Javascript <=> Java interop
 
I would be glad for comments on my j2j.class applet. It uses JSObject
and MAYSCRIPT applet flag for either way communication between
Javascript and Java. For the testing purposes it is minimalistic:
Javascript function calls applet public method and applet in turn
calls the callback Javascript function. All relevant comments are in
Java source. Compiled class if needed at http:\\javascript.myplus.org/
j2j.class
HTML page:
<!DOCTYPE html>
<html>
<head>
<title>Test</title>
<meta http-equiv="Content-Type"
 content="text/html; charset=iso-8859-1">
<script>
function test() {
 var japp = document.getElementById('J2J');
 japp.callJava(['echo', 'foo']);
}
function echo() {
 window.alert('Java applet says: "Here!"');
}
</script>
</head>
<body>
<p><applet id="J2J" width="12" height="12" code="j2j.class" mayscript>
 <param name="bgcolor" value="#FF0000">
 <dfn style="color:red"
  title="Java applet is not launched">Java</dfn>
</applet></p>
<p><button type="button" onclick="test()">Test</button></p>
</body>
</html>
Java j2j.class source:
/********************************************
 * Java <=> JavaScript interoperability
 *
 * This applet needs to be run on a HTML page
 * with <applet> tag properly set in order to
 * be fully functional.
 *
 * This applet is  written to be  compatible
 * with any  Java platform  down to JDK 1.1,
 * so no Swing extensions are used.
 *
 * Programmed by  VK [schools_ring@yahoo.com]
 *
 ********************************************/
import java.awt.*;
import java.applet.*;
import netscape.javascript.*;
/* LiveConnect package will be used to communicate between
 * Java applet and JavaScript/DOM methods on the HTML page.
 * Remember that the JVM used at the development  time has
 * nothing to do with the JVM used by browsers to run your
 * applet.  Respectively if you decide  to recompile  this
 * applet using JCreator,  NetBeans or any other  IDE tool
 * you'll get a package loading error. To make it work you
 * have to  add LiveConnect package to your classpath.
 * Depending on what JMV plugin you already have installed,
 * there are several places to choose from:
 * 1. Sun Java plug-in
 *    Add to your classpath plugin.jar which is located in
 *    the /lib subdirectory of the installed plugin, e.g.:
 *    C:\Program Files\Java\jre1.6.0_07\lib\plugin.jar
 *    Note: Sun plug-ins prior JRE 1.4.2 have this package
 *    named jaws.jar so look for it instead if you have an
 *    ancient JRE plug-in installed and nothing else.
 * 2. Microsoft JVM (MJVM)
 *    Add to your classpath  plugin.jar which is harder to
 *    locate because the MJVM installer places packages in
 *    randomly named folders as a security mesure.  Search
 *    in \%Systemroot%\Java sub-folders  for the .cab file
 *    containing plugin.jar and add it to the classpath.
 * 3. Netscape 3.x - 4.x JVM
 *    Add to your classpath java40.jar which is located in
 *    \java\classes subdirectory inside the Netscape setup
 *    directory.
 *
 * It is absolutely irrelevant from where the package comes
 * from and even if it contains anything usable at all.
 * At runtime  on a HTML page  applets will use the package
 * from the available plug-in that runs the applet. And for
 * Java IDE you  cannot test and work with JSObject anyway,
 * it will give you an Error.  So all this buzz  from above
 * is only to  pacify the compiler  so you could get .class
 * from your .java source. The testing has to be done after
 * that from a HTML page.
 *
 * For curious ones:
 * internally netscape.javascript.*  subclasses and extends
 * sun.plugin.javascript.*  package members  located in the
 * same .jar archive.
 *
 * MAYSCRIPT !
 * Do not  forget to add  mayscript  flag attribute to your
 * applet tag:  <applet ...  mayscript>
 * By default LiveConnect is disabled and an attempt to use
 * JSObject will be ignored (loopholed) or  it will raise a
 * security exception.
 * To have LiveConnect enabled for an applet, set mayscript
 * flag on.
 * Do  not use <object> and do  not use pseudo-XHTML syntax
 * like  mayscript="true".  Use the  universally  supported
 * <applet> tag and mayscript attribute without any value.
 *
 * SIZE does matter !
 * Java applets have security restriction for their minimum
 * size: 10px X 10px.  In the past there were discrepancies
 * between browsers to treat it as "no lesser than 10px" or
 * "starting from 10px and lesser". To be on the safe side,
 * use 11px or 12px for WIDTH and HEIGHT. So it can be like
 *
 * <applet width="12" height="12" code="j2j.class" mayscript>
 *  <param name="bgcolor" value="#C0C0C0">
 *  <dfn style="color:red"
 *   title="Java applet is not launched">Java</dfn>
 * </applet>
 */
public class j2j extends Applet {
 // String to return on getAppletInfo() call:
 final String appletInfo = "j2j v.1.2";
 // If bgcolor parameter is missing or invalid then
 // applet canvas will be painted in this color:
 Color defaultBgColor = Color.WHITE;
 // Applet may fail to instantiate  JSObject or the
 // communication may be blocked,  yet it should be
 // still running  at least  for the reason to  not
 // make a black  or gray  spot on your  HTML page.
 // mayScript flag  (set to true if JSObject is OK)
 // is  used  to check  before  LiveConnect-related
 // operations:
 boolean mayScript = false;
 // [window] host object reference holder:
 JSObject Win;
 // [document] object reference holder:
 JSObject Doc;
 public void init() {
  setBgColor();
    }
 public void start() {
 // While [window] object is available immediately,
 // DOM object may not be available on init() stage
 // so it is more reliable  to obtain the necessary
 // references on start() stage.
  getJSObjects();
 }
 public void stop() {
  /* NOP */
 }
 public void destroy() {
 // Release references, most importantly DOM refs.
  Win = null;
  Doc = null;
 }
 synchronized Object callJavaScript(String method,
                                    Object[] args) {
 if (mayScript) {
  Win.call(method, args);
 }
 return null;
}
 public synchronized boolean callJava(Object[] Args) {
  String method;
  Object[] args;
  int i;
  if (mayScript && Args.length >= 1) {
   method = (String)Args[0];
   // honnestly hate this:
   args = new Object[Args.length-1];
   for (i = 1; i < Args.length; i++) {
    args[i-1] = Args[i];
   }
   // end of hate
   callJavaScript(method, args);
   return true;
  }
  else {
   return false;
  }
 }
 void setBgColor() {
  String bgColor;
  int r, g, b;
  Color c;
  bgColor = this.getParameter("bgcolor");
  if (bgColor == null) {
   this.setBackground(defaultBgColor);
  }
  else {
   if ( bgColor.startsWith("#") && bgColor.length() == 7 ) {
    try {
     r = Integer.parseInt(bgColor.substring(1,3), 16);
     g = Integer.parseInt(bgColor.substring(3,5), 16);
     b = Integer.parseInt(bgColor.substring(5,7), 16);
     c = new Color(r, g, b);
     this.setBackground(c);
    }
    catch (Exception e) {
     this.setBackground(defaultBgColor);
    }
   }
   else {
    this.setBackground(defaultBgColor);
   }
  }
 }
 void getJSObjects() {
  String errorMessage = "";
  try {
   Win = JSObject.getWindow(this);
   Doc = (JSObject)Win.getMember("document");
  }
  catch (Exception e) {
   errorMessage = "JSObject interop is disabled: " +
   "possibly \"mayscript\" flag is not set.";
  }
  catch (Error err) {
   errorMessage = "You cannot operate with JSObject " +
   "if your applet is running stay-alone: run it in " +
   "a browser as a component of a HTML page.";
  }
  finally {
   if (errorMessage.equals("")) {
    mayScript = true;
   }
   else {
    System.err.println(errorMessage);
   }
  }
 }
 public String getAppletInfo() {
  return appletInfo;
 }
}
end of Java source