This is the README file for the JavaScript LiveConnect
Version 3 ("LC3") implementation.
Table of Contents
Introduction
New features
Compatibility
Limitations/Bugs/To-Do
Build conventions
Naming and coding conventions
The LiveConnect API
Sample LiveConnect shell interactions
Introduction
 LiveConnect is a library that 
permits JavaScript and Java virtual machines to interoperate. Specifically, 
it enables JavaScript to access Java fields, invoke Java methods and enables Java 
to access JavaScript object properties and evaluate arbitrary JavaScript. 
LiveConnect was originally an integrated feature of both the Netscape Navigator 
browser and Netscape's server-side JavaScript. Now, it is a standalone library 
that can be embedded within other projects, such as the Mozilla browser. More 
information on LiveConnect can be found by searching 
the index on Netscape's DevEdge site.  This README assumes basic familiarity 
with JSRef, 
the reference implementation of JavaScript, and with the LiveConnect technology. 
The JSRef project/makefiles (located in another directory) build a library 
  or DLL containing the JavaScript runtime (compiler, interpreter, decompiler, 
  garbage collector, atom manager, standard classes).  The LiveConnect project/makefiles 
  build a library that links with both JSRef and any Java Virtual Machine (JVM) 
  that implements the Java Native Interface (JNI), as specified by JavaSoft.  
  It then compiles a small "shell" example program and links that with the library 
  to make an interpreter that can be used interactively and with test scripts.  
  See the sample shell interactions. 
Scott Furman, 10/31/98
New features
The following features were not available in the versions of LiveConnect that 
were integrated with Netscape Navigator versions 4.x and earlier.  For information 
on LiveConnect version 1, which was used in Navigator versions 3 and 4, and Enterprise 
Server 3, see Netscape's 
DevEdge site or any number of 3rd-party publications.) 
 LiveConnect version 3 (8/31/99)
  -  In previous versions of LiveConnect, when more than one overloaded Java 
    method was compatible with the types of arguments in an invocation from JS, 
    the choice of Java method was made arbitrarily, by using the first one enumerated 
    by the Java reflection APIs.  Unfortunately, the ordering of methods 
    when enumerating is not governed by any specification, so differences between 
    JVM vendors could lead to inconsistencies in LiveConnect behavior.  Now, 
    a JVM-independent 
    set of rules is used to choose among a set of overloaded methods.   
    Informally, the method with Java parameter types that most  closely match 
    the JavaScript types is chosen.
 
 
-  The weak correspondence between the JS language typing system and Java's 
    may result in ambiguity and/or shadowing when resolving among overloaded Java 
    methods, even when using LC3's improved method overload resolution algorithm 
    (see above).  For example, JS's number type can map to a Java method 
    argument that has any floating-point or integral types: byte, char, short, 
    int, long, float, double.   If necessary, it is now possible to 
    bypass the method overload resolution process and explicitly specify the method 
    to be invoked:
  
    
  
    myPrintMethod = java.io.PrintStream["print(double)"]; 
    myPrintMethod(13); 
  
  -  Static methods can now be invoked using either the class name or a reference 
    to an instance of the class.  (Older versions of LiveConnect allow only 
    the former.)
 
 
-  It is no longer necessary to convert Java Strings to JS strings before 
    using them as the receivers of JS string methods, which is typically done 
    by appending an empty string to the Java string, e.g. 
     
           s = new java.lang.String("foo") // s contains 
        a Java string
 s = s + "";                     
        // s is now a JS string
 m = s.match(/o?/)
 
 
The explicit conversion to a JS string is no longer required because java.lang.String 
    objects are treated as a special case that "inherit" all the methods of JS 
    strings, i.e. so that the second statement in the example above is now superfluous.
    
  
-  Similarly, JavaArray objects "inherit" the methods of JS's Array.prototype, 
    so it is possible to apply many, though not all, of the JS array utility methods 
    such as reverse() and join() to JavaArray objects.
 
 
-  There is now support for the instanceof and in operators.  
    These operators are currently proposed for inclusion in the ECMA-2 standard.
 
 
-  LiveConnect has been extended to take advantage of JavaScript exceptions, 
    a language feature that debuted in JavaScript 1.4.  Now, when JavaScript 
    calls into Java, any Java exceptions are converted to JS exceptions which 
    can be caught using JS try-catch statements.  Similarly, JS exceptions 
    are propagated to Java wrapped in an instance of netscape.javascript.JSException.
 
 
- JavaScript Array objects can now be passed to Java methods that expect a 
    Java array as an argument. 
 LiveConnect will create a new Java array of the appropriate type with a length 
    equal to that of the JS Array object. Each element of the Java array is filled 
    in by converting the corresponding element of the JS array, including undefined 
    elements, to an equivalent Java value. Note: Since the contents of the JS 
    array are copied, side-effects made by the invoked Java method to the Java 
    array will not be reflected in the JS array argument.
LiveConnect version 2 (7/31/98)
   The Java methods of java.lang.Object are now invokeable methods 
    of JavaArray objects, matching the behavior 
    of arrays when accessed from Java.  (Java arrays are a subclass 
    of java.lang.Object.) For example, Java's getClass() and hashCode() 
    methods can now be called on JavaArray objects.  (In prior versions 
    of LiveConnect, the methods of java.lang.Object were only inherited 
    by non-array Java objects.)
  Note that this change has caused the string representation of JavaArray objects 
    to change.  Previously, the JavaArray toString() method always printed 
    "[object JavaArray]" for all JavaArray's.  
    Now, the Java java.lang.Object.toString() method is called to convert 
    JavaArray objects to strings, just as with other, non-array Java objects that 
    are accessible via LiveConnect. java.lang.Object.toString()is defined 
    in the Java Language Specification to return the value of the following 
    expression: 
  
getClass().getName() + '@' + Integer.toHexString(hashCode())
    
     
  
 A one-character string is now an acceptable match for an argument to a 
    Java method of type char.  (In earlier versions of LiveConnect, 
    the only acceptable match for a char had to be a JavaScript value 
    that was convertible to a number.)  For example, the following is now 
    possible:
  c = new java.lang.Character("F")
    
     
A JavaClass object is now an acceptable match for an argument to a Java
method of type java.lang.Class.  For example, you can now write:
java.lang.reflect.Array.newInstance(java.lang.String,
3)
instead of the more verbose:
  
jls = java.lang.Class.forName("java.lang.String") 
    
    java.lang.reflect.Array.newInstance(jls, 3) 
  
     
Compatibility
Unlike this standalone/component release, all previous versions of LiveConnect 
appeared only as an integrated feature of Netscape Navigator or the Enterprise 
Server.  The variants of LiveConnect that appeared in Navigator versions 
3.x and 4.x all behave much the same, modulo bugs.  For brevity we refer 
to this classic version of LiveConnect as "LC1" (LiveConnect version 1) and this 
most recent release as "LC3".  With a few exceptions LC3 provides a superset 
of LC1 features. (There was an intermediate LiveConnect release known as "LC2" 
in 7/98, but it was not used in any products.) 
  -  As in LC1, JavaScript objects appear to Java as instances of netscape.javascript.JSObject.  
    In LC1, two JSObject's could be tested for equality, i.e. to see if 
    they refer to the same instance, by using the `==' operator.  Instead, 
    developers must now use the equals()method of netscape.javascript.JSObject 
    for comparison, a method that overrides java.lang.Object.equals().  
    Note that using equals() instead of `==' will work the same in all 
    versions of LiveConnect, including LC3
[It is not possible to replicate the identity behavior of the `==' operator 
    that LC1 provides without the use of "weak" references, i.e. references that 
    do not contribute to making a Java object reachable for purposes of garbage 
    collection, but which nonetheless allow reference to an object as long as 
    it is reachable by other means.  The use of weak references is not portable, 
    however.  It is not part of the JNI or JDK 1.1 and it is not provided 
    on all JVMs.  The JDK1.2 release includes standard support for weak references.]
    
      
  
-  It's possible that, in a set of overloaded Java methods, more than one 
    method is compatible with the types of the actual arguments in a call from 
    JavaScript to Java via LiveConnect.  LC1 and LC2 resolved these ambiguities 
    in a simplistic manner, by simply invoking whatever method was enumerated 
    first by the JVM.  The enumeration order of reflected methods using java.lang.reflect  
    is not specified by Sun and may differ among vendor's JVMs, i.e. enumeration 
    could be in order of classfile appearance, hashtable order, etc.  Hence, 
    the Java method chosen when there is more than one compatible method may vary 
    depending on the JVM.  With the Netscape and Sun JVMs, it is possible 
    to change the behavior of an LC1/LC2 program by changing the order that Java 
    methods appear in a source file, thus changing the method enumeration order.
In LC3, a new method overload resolution algorithm is used.  Informally, 
    the method with Java parameter types that most  closely match the JavaScript 
    types is chosen.  You can read all the gorey details in the spec.
    
      
  
-  There are several minor changes in error handling to make LiveConnect more 
    conformant to ECMAScript.  These include, for example, making any attempt 
    to delete JavaObject, JavaClass or JavaPackage properties fail silently, rather 
    than causing an error.  Also, some error messages have been changed to 
    be more informative.  These changes should generally be backward-compatible 
    with LC1 because few programs that use LiveConnect will depend on the exact 
    behavior of LiveConnect when handling errors.
 Limitations/Bugs/To-Do
  -  The efficiency of calling Java methods leaves something to be desired, 
    due to the convoluted nature of implementing native methods for JS.  
    JS_CloneFunctionObject() is called for every Java method invocation and the 
    inability to store private data in a JSFunction object requires that the method 
    table be searched twice instead of once for every invocation.
 
 
-  When Java objects are referenced from JS, they are entered into a hash 
    table, so as to ensure that the same JS Object wrapper is used every time 
    a particular Java object is reflected into JS.  In this way, the behavior 
    of the JS '==' and '===' operators are preserved.  Unfortunately, the 
    hash table may grow quite large (objects are only removed from the hash table 
    when finalized).  In thread-safe systems, the hash table must be locked 
    when accessed, leading to slow performance. One alternate solution would be 
    to make it possible to overload JS's equality-test operators, so that the 
    hash table would no longer be required.
 
 
-  Initially, JavaClassDescriptor objectswere reference-counted to permit 
    free'ing of unused descriptors.  However, it's relatively common to develop 
    cycles in the graph of JavaClassDescriptors, which leads to unused JavaClassDescriptors 
    that have non-zero reference counts. For that reason, JavaClassDescriptors 
    are not free'ed until JSJ_Shutdown().  Luckily, the amount of memory 
    used by JavaClassDescriptors tends to be relatively small.
 
 
-  The LiveConnect API is designed to allow multiple JVMs to be used simultaneously 
    in the same executable (although each JSContext is limited to interaction 
    with at most one JVM).  However, the API is not fully implemented.  
    For example, many global variables will need to become members of the JSJavaVM 
    struct so that they are stored on a per-JVM basis.
 
 
-  Java and JavaScript use independent garbage collection systems. A reference 
    between the two worlds must, therefore, take the form of a GC root. It's possible 
    to create uncollectable objects when cyclic graphs cross the boundary between 
    JS and Java, e.g. a JS object that refers to a Java object that refers back 
    to the original JS object. There is no simple solution to this dual-GC problem. 
    Luckily, such cyclic object graphs are extremely rare. 
Build conventions
The following directions are for building the standalone version of LiveConnect. 
  To build the version that's used in the Mozilla browser, see the Mozilla 
  build documentation.
On all platforms, you must update your JVM's CLASSPATH to point to 
  the js/src/liveconnect/classes subdirectory.  If you do not, LiveConnect 
  will still operate but with the limitation that JS objects may not be passed 
  as arguments of Java methods and it will not be possible to call from Java into 
  JavaScript, i.e. the netscape.javascript.JSObject class will be inaccessible.  
  Another downside of operating without these classes is that Java error messages 
  will not include a Java stack trace, when one is available.  If your CLASSPATH 
  is set improperly, you will see a message like, "initialization error: Can't 
  load class netscape/javascript/JSObject" when starting a LiveConnect debug 
  build. 
By default, all platforms build a version of LiveConnect that is not 
  threadsafe.  If you require thread-safety, you must also populate the mozilla/dist 
  directory with NSPR 
  headers and libraries.  (NSPR implements a portable threading library, 
  among other things.  The source is downloadable via CVS 
  from mozilla/nsprpub.)  
  Next, you must define JS_THREADSAFE when building LiveConnect, either 
  on the command-line (gmake/nmake) or in a universal header file.  Note 
  that JSRef must also be built with JS_THREADSAFE. 
One important note about building on Windows: There are two independent build 
  systems (in addition to the Mozilla browser build system). One of them uses 
  the IDE project files and the other uses gmake and makefiles. The former will 
  be preferred by most for debugging and the latter is more complete, since it 
  builds the necessary Java classes in addition to compiling the LiveConnect C 
  code.
Windows
- 
Build the JS runtime and interpreter, js32.dll, by using the 
normal
JSRef build procedure.
-  Set the JDK environment variable to point to the top-level JDK directory, 
      e.g. D:\jdk1.1.5.  This is used to establish paths for header 
      file inclusion, linking and execution.  If you are not using Sun's 
      JVM, the project files may require manual tweaking to set these paths correctly.
-  Use MSVC 5 or MSVC 6 with the LiveConnectShell.dsw project file.  
      NOTE: makefile.win is an nmake file used only for 
      building the JS-engine in the Mozilla browser.  Don't attempt to use 
      it to build the standalone JS-engine.
- 
The output files (DLLs and executables) are placed in either the js\src\liveconnect\Debug
or the js\src\liveconnect\Release directory.
- 
The LiveConnect-enabled shell is named lcshell.exe and appears
in the output directory.
- 
You must have the JVM DLL in your PATH environment
variable in order to run.  If you are using the Sun JDK, the DLL appears
in the JDK's bin directory, e.g. D:\jdk1.1.5\bin\javai_g.dll.
- 
Use any Java compiler to compile the java source files in the js\src\liveconnect\classes\netscape\javascript
directory.
-  Update your JVM's CLASSPATH to point to the js\src\liveconnect\classes 
      subdirectory.  (See above)
 
 
Mac OS
- 
Using CodeWarrior Pro 3 is recommended, though the project files will probably
also work with CodeWarrior Pro 4.
- 
Install Apple's JVM, MRJ 2.0 (or later), and the MRJ
SDK v2.0.1ea4.  Note: You do not need to install MRJ if you are
running a recent version of MacOS 8, since it is shipped with the OS.
- 
Copy the folders CIncludes & Libraries from the SDK's
Interfaces&Libraries directory to js:src:liveconnect:macbuild:JavaSession.
- 
Build the LiveConnect test application, LiveConnectShell, with
js:src:liveconnect:macbuild:LiveConnectShell.mcp.
- 
Build liveconnect.jar with js:src:liveconnect:macbuild:LiveConnect.mcp.
- 
Make an alias to liveconnect.jar and place it in "{SystemFolder}Extensions:MRJ
Libraries:MRJClasses".
 
 
Unix (also works on Windows)
    -  Use 'gmake -f Makefile.ref' to build. 
      To compile optimized code, pass BUILD_OPT=1 on the gmake command 
      line or preset it in the environment or Makefile.ref.  NOTE: 
      Do not attempt to use Makefile to build.  This file is used 
      only for building LiveConnect in the Mozilla browser.
-  Each platform on which LiveConnect is built must 
      have a *.mk configuration file in the js/src/liveconnect/config 
      directory.  The configuration file specifies the JVM headers/libraries 
      used and allows for customization of command-line options.  To date, 
      the build system has been tested on Solaris, AIX, HP/UX, OSF, IRIX, x86 
      Linux and Windows NT. Most platforms will work with either the vendor compiler 
      or gcc.
- Update your JVM's CLASSPATH to point to 
      the js/src/liveconnect/classes subdirectory.  (See above)
Naming and coding conventions:
- 
Public function names begin with JSJ_ followed by capitalized "intercaps", 
e.g. JSJ_ConnectToJavaVM.
- 
Extern but library-private function names use a jsj_ prefix and mixed case,
e.g. jsj_LookupSymbol.
- 
Most static function names have unprefixed, underscore-separated names:
get_char.
- 
But static native methods of JS objects have intercaps names, e.g., JavaObject_getProperty().
- 
And library-private and static data use underscores, not intercaps (but
library-private data do use a js_ prefix).
- 
Scalar type names are lowercase and js-prefixed: jsdouble.
- 
Aggregate type names are JS-prefixed and mixed-case: JSObject.
- 
Macros are generally ALL_CAPS and underscored, to call out potential side
effects, multiple uses of a formal argument, etc.
- 
Four spaces of indentation per statement nesting level.  The files
are space-filled, so adjusting of your tab setting should be unnecessary.
- 
I don't bow down to the ancient "80 columns per line" gods, since most
of us are not using vt100's to read source code.  My rule of thumb
is to use no more than 95 columns per line, but exceptions are made to
format tables or table-like code.
- 
DLL entry points have their return type expanded within a JS_EXPORT_API() 
macro call, to get the right Windows secret type qualifiers in the right
places for both 16- and 32-bit builds.
The LiveConnect API
All public LiveConnect entry points and callbacks are documented in 
jsjava.h,
the header file that exports those functions.
 
File walk-through
 
| jsjava.h | LiveConnect's only public header file.  Defines all public API
entry points, callbacks and types. | 
| jsj_private.h | LiveConnect internal header file for intra-module sharing of functions
and types. | 
| jsj.c | Public LiveConnect API entry points and initialization code. Handling
of multiple threads and multiple JVMs. | 
| jsj_array.c | Read and write elements of a Java array, performing needed conversions
to/from JS types. | 
| jsj_class.c | Construct and manipulate JavaClassDescriptor structs, which are the
native representation for Java classes.  JavaClassDescriptors are
used to describe the methods and fields of a class, including their type
signatures, and include a reference to the peer java.lang.Class
object.  Since each Java object has a class, there is a JavaClassDescriptor
associated with the JavaScript reflection of each Java Object. | 
| jsj_convert.c | Convert between Java and JavaScript values of all types, which may
require calling routines in other files to wrap JS objects as Java objects
and vice-versa. | 
| jsj_field.c | Reflect Java fields as properties of JavaObject objects and implement
getter/setter access to those fields. | 
| jsj_JavaArray.c | Implementation of the JavaScript JavaArray class.  Instances of
JavaArray are used to reflect Java arrays. | 
| jsj_JavaClass.c | Implementation of the JavaScript JavaClass class.   Instances
of JavaClass are used to reflect Java classes. | 
| jsj_JavaObject.c | Implementation of the JavaScript JavaObject class.   Instances
of JavaObject are used to reflect Java objects, except for Java arrays,
although some of the code in this file is used by the JavaArray code. | 
| jsj_JavaMember.c | Implementation of the JavaScript JavaMember class.  JavaMember's
are a strange beast required only to handle the special case of a public
field and a public method that appear in the same Java class and which
have the same name. | 
| jsj_JavaPackage.c | Implementation of the JavaScript JavaPackage class.   Instances
of JavaPackage are used to reflect Java packages.  The JS properties
of a JavaPackage are either nested JavaPackage objects or a JavaClass object. | 
| jsj_JSObject.c | Implementation of the native methods for the  netscape.javascript.JSObject
Java class, which are used for calling into JavaScript from Java. 
It also contains the code that wraps JS objects as instances of  netscape.javascript.JSObject
and
the code that handles propagation of exceptions both into and out of Java. | 
| jsj_method.c | Reflect Java methods as properties of JavaObject objects and make it
possible to invoke those methods.  Includes overloaded method resolution
and argument/return-value conversion code. | 
| jsj_utils.c | Low-level utility code for reporting errors, etc. | 
Sample LiveConnect shell interactions
Java packages, classes and constructors
js> java
[JavaPackage java]
js> awt = java.awt
[JavaPackage java.awt]
js> Rectangle = awt.Rectangle
[JavaClass java.awt.Rectangle]
Java instance fields and methods
js> r = new java.awt.Rectangle(34, 23)
java.awt.Rectangle[x=0,y=0,width=34,height=23]
js> r.width - r.height
11
js> r.x = 7; r.y = 4
4
js> r
java.awt.Rectangle[x=7,y=4,width=34,height=23]
js> r.grow(3)
There is no Java method java.awt.Rectangle.grow that matches JavaScript
argument types (number).
Candidate methods with the same name are:
   void grow(int, int)
js> r.grow(3, 3)
js> r
java.awt.Rectangle[x=4,y=1,width=40,height=29]
Java arrays
js> s = new java.lang.String("mastiff")
mastiff
js> c = s.toCharArray()
[C@298e9b
js> c[0] = "b"; c[4] = "a"; c[5] = "r"; c[6] = "d"
d
js> s2 = new java.lang.String(c)
bastard
Java static fields and methods
js> java.lang.reflect.Modifier.ABSTRACT
1024
js> java.lang.Math.sin(3) + 2
2.1411200080598674
Explicit resolution of overloaded Java methods
js> x = "23"
23
js> java.lang.Math.abs(x)
The choice of static Java method java.lang.Math.abs matching JavaScript
argument types (string) is ambiguous.
Candidate methods are:
   long abs(long)
   float abs(float)
   double abs(double)
   int abs(int)
js> abs = java.lang.Math["abs(int)"]
function abs(int)() {
    [native code]
}
js> abs(x)
23
Public Method/field enumeration
js> out = java.lang.System.out
java.io.PrintStream@2980f5
js> for (m in out) print(m)
println
print
checkError
close
flush
write
wait
notifyAll
notify
toString
equals
hashCode
getClass
js> for (m in java.lang.String) print(m)
copyValueOf
valueOf
'instanceof' and 'in' operators
js> s = new java.lang.String("foop")
foop
js> s instanceof java.lang.Class
false
js> s instanceof java.lang.Object
true
js> "valueOf" in s
true
js> "NoSuchThing" in s
false
Applying JavaScript string methods to Java strings
js> s = new java.lang.String("The rain in Spain falls mainly on my
head.")
The rain in Spain falls mainly on my head.
js> s.match(/Spain.*my/)
Spain falls mainly on my
Applying JavaScript array methods to Java arrays
js> s = new java.lang.String("JavaScript")
JavaScript
js> c = s.toCharArray()
[C@298aef
js> c.reverse()
[C@298aef
js> new java.lang.String(c)
tpircSavaJ