JS/CORBA Adapter

What is it?

The keywords here are:

  • distributed—multiple JavaScript engines execute on different machines
  • transparently—interaction with remote JavaScript objects is no different from interacting with local objects
  • arbitrary—*any* JavaScript object can participate in the interaction

Apart from building distributed systems of JavaScript objects, the JS/CORBA Adapter also provides an easy mechanism for other CORBA systems to access JavaScript objects—any JavaScript object can be ‘CORBA-enabled’ dynamically without the need to define any IDL, etc.

Where do I get it?

The project is hosted at SourceForge: http://www.sourceforge.net/projects/jscorba/ You will also need a copy of Rhino, a JavaScript engine written in Java which is part of the Mozilla project: http://www.mozilla.org/rhino/

How does it work?

The file Javascript.idl should give you a clue. It basically maps the Scriptable interface to a CORBA interface. Scriptable is implemented by all JavaScript objects and is the interface used by the JavaScript engine for all interactions with JavaScript objects. There is also a Function interface, which inherits from Scriptable and is used for things than can be ‘called’ and act as ‘constructors’. This too is mapped to a corresponding CORBA interface.

The job of the JS/CORBA Adapter is to ‘export’ local objects to CORBA by creating CORBA objects that implement the Scriptable CORBA interface, and to ‘import’ remote objects, by wrapping CORBA references to remote objects in locally created JavaScript proxy objects. Thus, a remote invocation traverses the following objects:

client JS engine ->
ScriptableClient ->
CORBA ref ->
client ORB--network--> server ORB ->
ScriptableServer ->
Javascript object ->
server JS engine

Exporting and importing can be done explicitly. This is primarily used for bootstrapping purposes.

How do I use it?

Follow the instructions in INSTALL.txt in order to build/install JS/CORBA Adapter. There are some examples in the ‘examples’ directory that should give you a pretty good idea how things work. Basically, a ‘typical’ scenario works along the following lines:

  • Create an ORB and POA with the right policies
  • Create an instance of the JS/CORBA Adapter. You can have more than one instance in which case you will get more than one “object identity space” (see above), i.e. you can create multiple CORBA wrappers for local JavaScript objects and multiple JavaScript wrappers for CORBA references to remote JavaScript objects. Not sure why anyone would want to do this, but you can :)
  • Create some local JavaScript objects and export them to the CORBA world using the ‘exportObj’ method on the JS/CORBA adapter.
  • Store the resulting object references in some naming/directory service or write the IORs to files.
  • Other JavaScript engines can now get a reference to the exported objects by following steps 1)+2) and then doing a naming/directory query (or reading the IOR files) followed by executing the ‘importObj’ method on their JS/CORBA adapter.
  • The other Javascript engines can now invoke methods on the imported objects. Arguments and results are automatically exported/imported.

The examples illustrate how to do all of this.

Garbage Collection

I bet you have been dying to ask how the Javascript engine knows when it is safe to destroy a local Javascript object that has been ‘exported’. The short answer is: it doesn’t. The long answer is: The exporting of an object (explicitly or implicitly) does not prevent it from being garbage-collected. Garbage-collecting may sound like a dangerous thing to do, but is actually not that bad – it means you can control what becomes garbage and what doesn’t by simply removing/keeping local pointers to the objects. The alternative would be to implement a proper distributed garbage collection (which is very hard, but I might still do it at some point), or to go for an ugly compromise, like in RMI.

You do need to be careful with implicitly exported objects, e.g. objects passed as arguments in calls to remote objects. For example, in

   remote.foo(compute());

the result of compute() might get gc-ed after the call return (NB: It will *not* get gc-ed before that) before the call returns unless it is referred to from somewhere else. If you cannot be sure that an argument is referred to from elsewhere, the safe thing to do is to assign it to a local variable that doesn’t go out of scope until any potential invocations on it have been completed, eg.

   {
   var tmp = compute();
   remote.foo(tmp);
   ...
   }

The JS/CORBA adapter provides a pair of functions, “root” and “unroot” that disable/enable garbage-collection of an object. These functions are particularly useful if the lifetime of an object is not defined by its scope, e.g.

   {
   var tmp = compute();
   root(tmp);
   remote.foo(tmp);
   }

   ....tmp survives scope exit...
   in a method on the tmp obj:

   {
   unroot(this);
   }

Note that ‘root’ can be called multiple times on the same object. The object is re-enabled for garbage-collection only after the same number of ‘unroot’ calls have been made. Both ‘root’ and ‘unroot’ operate on *local* objects only, i.e. they are *not* an attempt to provide a means of distributed reference counting.