Java Tutorial/Trail: Java and Javascript

From Wikiversity
Jump to navigation Jump to search

Java and JavaScript[edit | edit source]

Java to JavaScript communication[edit | edit source]

The class netscape.javascript.JSObject found in the JRE directory in the "lib/plugin.jar" archive is the object that allows communication with the JavaScript engine. The content of the JAR is automatically available inside the Java environment of the web browser. The following code instantiates the JSObject:

public class MyApplet extends Applet {
    JSObject window = JSObject.getWindow (this);
}

JSObject[edit | edit source]

JSObject offers the following methods:

java.lang.Object call (java.lang.String methodName, java.lang.Object[] args) Calls a method on a JavaScript object.
java.lang.Object eval (java.lang.String s) Evaluates an expression string in JavaScript.
java.lang.Object getMember (java.lang.String name) Returns a named member of a JavaScript object.
java.lang.Object getSlot (int index) Returns an indexed member of a JavaScript object.
static JSObject getWindow (java.applet.Applet applet) Returns a JSObject for the window containing the applet.
void removeMember (java.lang.String name) Removes a named member of a JavaScript object.
void setMember (java.lang.String name, java.lang.Object value) Assigns a named member of a JavaScript object.
void setSlot (int index, java.lang.Object value) Assigns an indexed member of a JavaScript object.

JavaScript to Java communication[edit | edit source]

Calling Java methods from JavaScript is almost too easy, because the Java code exposes all public functions, not just methods intended for communication with the enclosing HTML page. If the applet or object tag has an id of "myApplet" the following code calls into the Java applet:

var myApplet = document.getElementById ("myApplet");
myApplet.publicMethod ();

It is even possible to call methods unrelated to the applet itself with the Packages keyword:

myApplet.Packages.java.lang.System.out.println ();

Example: Mozilla Persona for Applets[edit | edit source]

This example applet communicates with JavaScript to permit a login to the Mozilla Persona authentication system offered by Mozilla. Discerning readers will notice that the assertion returned by the authentication system could require some sort of verification, which should, for security reasons, not be implemented in the applet. One method of verification is the Remote Verification API.

MozillaPersonaUtil[edit | edit source]

package org.wikiversity.java_tutorial;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.ArrayList;

import netscape.javascript.JSException;
import netscape.javascript.JSObject;

public final class MozillaPersonaUtil
{
	/**
	 * onlogin ()<br>
	 * A user has logged in! Here you need to:<br>
	 * 1. Send the assertion to your backend for verification and to create a session.<br>
	 * 2. Update your UI.<br>
	 * <br>
	 * onlogout ()<br>
	 * A user has logged out! Here you need to:<br>
	 * Tear down the user's session by redirecting the user or making a call to your backend.<br>
	 *
	 * @author bernhard
	 */
	public static class WatchContext
	{
		String loggedInUser; // The email or null, undefined in case of doubt.
		String onlogin;      // function(assertion) { ... } (Mandatory)
		String onlogout;     // function() { ... } (Mandatory)
		
		public String toString ()
		{
			StringWriter sw = new StringWriter ();
			PrintWriter pw = new PrintWriter (sw);
			boolean comma = false;
			ArrayList<String> list = new ArrayList<String> (3);

			if (loggedInUser != null)
				list.add ("loggedInUser: '" + loggedInUser + "'");
			if (onlogin != null)
				list.add ("onlogin: " + onlogin);
			if (onlogout != null)
				list.add ("onlogout: " + onlogout);

			for (String parameter : list)
			{
				if (!comma)
					comma = true;
				else
					pw.println (',');
				pw.print (parameter);
			}	
			pw.println ();
			pw.flush ();
			return sw.toString ();
		}
	}

	public static class LoginContext 
	{
		String siteName;       // My Example Site
		String siteLogo;       // /logo.png (100x100 pixels)
		String termsOfService; // /tos.html
		String privacyPolicy;  // /privacy.html
		String returnTo;       // /welcome.html
		String onCancel;       // function() { alert('user refuses to share identity.'); }
		
		public String toString ()
		{
			StringWriter sw = new StringWriter ();
			PrintWriter pw = new PrintWriter (sw);
			boolean comma = false;
			ArrayList<String> list = new ArrayList<String> (6);
			
			if (siteName != null)
				list.add ("siteName: '" + siteName + "'");
			if (siteLogo != null)
				list.add ("siteLogo: '" + siteLogo + "'");
			if (termsOfService != null)
				list.add ("termsOfService: '" + termsOfService + "'");
			if (privacyPolicy != null)
				list.add ("privacyPolicy: '" + privacyPolicy + "'");
			if (returnTo != null)
				list.add ("returnTo: '" + returnTo + "'");
			if (onCancel != null)
				list.add ("oncancel: " + onCancel);
			
			for (String parameter : list)
			{
				if (!comma)
					comma = true;
				else
					pw.println (',');
				pw.print (parameter);
			}	
			pw.println ();
			pw.flush ();
			return sw.toString ();
		}
	}

	/**
	 * This method calls navigator.id.request ();
	 * @see https://developer.mozilla.org/en-US/docs/DOM/navigator.id.request
	 * @param window
	 * @param ctx
	 * @throws JSException
	 */
	public static void mozillaPersonaLoginRequest (JSObject window, LoginContext ctx)
		throws JSException
	{
		String javaScriptCode = "navigator.id.request ({ " + ctx + " });";
        	window.eval (javaScriptCode);
	}

	/**
	 * This method calls navigator.id.logout ();
	 * @see https://developer.mozilla.org/en-US/docs/DOM/navigator.id.logout
	 * @param window
	 * @throws JSException
	 */
	public static void mozillaPersonaLogoutRequest (JSObject window)
		throws JSException
	{
		String javaScriptCode = "navigator.id.logout ();";
        	window.eval (javaScriptCode);
	}

	/**
	 * This method calls navigator.id.watch ().
	 * @see https://developer.mozilla.org/en-US/docs/DOM/navigator.id.watch
	 * @param window
	 * @param ctx
	 * @throws JSException
	 */
	public static void mozillaPersonaWatch (JSObject window, WatchContext ctx)
		throws JSException
	{
		String javaScriptCode = "navigator.id.watch ({ " + ctx + " });";
        	window.eval (javaScriptCode);
	}
}

MozillaPersonaApplet[edit | edit source]

package org.wikiversity.java_tutorial;

import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.lang.reflect.Method;

import javax.swing.JApplet;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;

import netscape.javascript.JSObject;

import org.w3c.dom.html.HTMLDocument;

public final class MozillaPersonaTestApplet extends JApplet implements ActionListener
{
	private final static String PINFO[][] = {
		{ "debug", "boolean", "turn on debug information" }
	};

	@Override
	public String[][] getParameterInfo () {
		return PINFO;
	}

	@Override
	public void actionPerformed (ActionEvent e)
	{
		Object src = e.getSource ();
		if (src == login)
		{
			login ();
		}
		else if (src == logout)
		{
			logout ();
		}
	}
	
	private final static String version = "0.5";
	private JButton login, logout;
	private JTextArea textArea;

	@Override
	public void init ()
	{
		login  = new JButton ("login");
		login.addActionListener (this);
		logout = new JButton ("logout"); 
		logout.addActionListener (this);
		textArea = new JTextArea ();
		textArea.setLineWrap (true);
		textArea.setWrapStyleWord (false);
		textArea.setText ("[ Version " + version + " ]");

		JPanel panel = new JPanel ();
		panel.setLayout (new FlowLayout (FlowLayout.LEFT));
		panel.add (login);
		panel.add (logout);
		
		setLayout (new BorderLayout ());
		add (panel, BorderLayout.NORTH);
		add (textArea, BorderLayout.CENTER);
	}

	private boolean debug;

	public void callbackLogin (String assertion)
	{
		textArea.setText ("[callbackLogin] assertion=" + assertion);
	}

	public void callbackLogout ()
	{
		textArea.setText ("[callbackLogout]");
	}

	public void callbackCancel ()
	{
		textArea.setText ("[callbackCancel]");
	}	
	
	@Override
	public void start ()
	{
		debug = Boolean.parseBoolean (getParameter ("debug"));
		
		HTMLDocument document = getDocument ();
		JSObject window = JSObject.getWindow (this);

		MozillaPersonaUtil.WatchContext ctx = new MozillaPersonaUtil.WatchContext ();
		ctx.onlogin  = "function (assertion) { mozillaPersonaApplet.callbackLogin (assertion); }";
		ctx.onlogout = "function () { mozillaPersonaApplet.callbackLogout (); }";
		MozillaPersonaUtil.mozillaPersonaWatch (window, ctx);		
	}

	private void login ()
	{
		JSObject window = JSObject.getWindow (this);
		MozillaPersonaUtil.LoginContext ctx = new MozillaPersonaUtil.LoginContext ();
		ctx.siteName = "Wikiversity Java Tutorial";
		ctx.siteLogo = "/Wikiversity.png";
		ctx.privacyPolicy  = "/privacypolicy.html";
		ctx.termsOfService = "/compliance.html"; 
		ctx.returnTo = "/index.html";
		ctx.onCancel = "function () { mozillaPersonaApplet.callbackCancel (); }";
		MozillaPersonaUtil.mozillaPersonaLoginRequest (window, ctx);
	}

	private void logout ()
	{
		JSObject window = JSObject.getWindow (this);
		MozillaPersonaUtil.mozillaPersonaLogoutRequest (window);
	}
	
	private HTMLDocument getDocument ()
	{
		try {
			Class c = Class.forName ("com.sun.java.browser.plugin2.DOM");
			Method m = c.getMethod ("getDocument", new Class[] { java.applet.Applet.class });
			return (HTMLDocument) m.invoke (null, new Object[] { this });
		}
		catch (Exception e) {
			System.out.println ("New Java Plug-In not available");
			// In this case, you could fallback to the old bootstrapping
			// mechanism available in the com.sun.java.browser.plugin.dom package
			return null;
		}
	}
}

See also[edit | edit source]

External links[edit | edit source]