XULRunner is a technology from Mozilla that allows to create cross-platform GUI applications just as easy as a websites.
Today I was trying to use my java libraries inside of a XUL application. This is basically to be able to load a jar file and call java functions with my javascript code.
It turns out that the only ( and the best ) way to accomplish this is by using
LiveConnect, a feature of java plugin that allows to 'talk' to java. LiveConnect among other things is responsible for communication with java applets.
With LiveConnect one can instanciate arbitrary java class and use it in javascript. Any java objects returned from method calls will be accessible in javascript as well as any javascript objects passed to java methods will be accessible in java. To achieve this effect LiveConnect does two-way wrapping of objects, i.e. it wraps java object with javascript and the other way around.
More precisely, to instanciate a JVM object simply do this:
var javaObject = new java.lang.String('Hello');
So to load classes from a library simply instanciate a classloader and then use it to instanciate the classes. Something like this:
function getAppPath(appName) {
var chromeRegistry = Components
.classes["@mozilla.org/chrome/chrome-registry;1"]
.getService(Components.interfaces.nsIChromeRegistry);
var uri =
Components.classes["@mozilla.org/network/standard-url;1"]
.createInstance(Components.interfaces.nsIURI);
uri.spec = "chrome://" + appName + "/content/";
var path = chromeRegistry.convertChromeURL(uri);
if (typeof(path) == "object") {
path = path.spec;
}
path = path.substring(0, path.indexOf("/chrome/") + 1);
return path;
};
var basePath = getAppPath('myapp');
var url = new java.net.URL(basePath + 'java/my.jar');
var cl = new java.net.URLClassLoader( [ url ] );
var aClass = java.lang.Class.forName("com.stan.XULDemo", true, cl);
var inst = aClass.newInstance();
// Calling 'sum' function from java
var a = inst.sum(2, 3);
alert(a); // Will alert '5'
// A function which we'll pass to java
// and have java call it later with a parameter
var callback = function(str) {
alert(str);
};
inst.callMeLater(callback, 'test');
The code of com.stan.XULDemo.java will be the following:
package com.stan;
public calss XULDemo {
public int sum(int a, int b) {
return a + b;
}
public void callMeLater(final JSObject func, final String text) {
new Thread() {
public void run() {
try {
Thread.sleep(5000); // Sleep 5 seconds
} catch(Exception e) { }
// We are passed a javascript Function Object
// which has method 'call' used to actually call the
// function. The first parameter is 'this',
// followed by a set
// of actual function parameters
func.call("call", new Object[] { null, text });
}
}.start();
}
}
This works out of the box with XULRunner.
Note. Currently there are troubles with LiveConnect 1.9 on Mac (jdk 1.6 u3) which I am looking at right now.