# JavaXPCOM

Ajax, Development, Java, XUL @ 29 April 2006

After poking around for some hours (then days) trying to find some useful information on how to use JavaXPCOM (which is a bridge between XPCOM and Java, formally known as Javaconnect) I stumbled across a few things as well as hacking together some understanding myself and through C++ examples of XPCOM usage.

We decided a while back to adopt an XML based protocol wherever possible, and moreover, RDF where appropriate. When communicating with a central server, this would use HTTP, so it seemed logical to use the same on the localhost. So, XUL uses AJAX, basically, to do asynchronous calls over HTTP to localhost, and retreives XML which is then passed into objects representing the returned resources. This way, we dont need to heavily integrate Java and XUL using XPCOM, and we allow other applications to be able to place nicely with the API over a well-known protocol and format. Anyway, this means that the only work JavaXPCOM needs to do is:

  • Start XPCOM using a XULRunner installation
  • Start an XUL window and pass control over to it
  • Be able to call javascript/xul events from java (to open windows, etc)

So to start with, we need to find an XULRunner install. As it stands, we will distribute a version with the installer, but JavaXPCOM contains code to easily find installed versions as well (this is actually documented on the JavaXPCOM site).

  1. Set the path the XULRunner directory, here we are doing it explicitly:
    File grePath = new File(new File(".").getAbsolutePath(), "platform/win32/xulrunner");
  2. Next create an instance of the LocationProvider
    LocationProvider locProvider = new LocationProvider(grePath);
  3. Initialize JavaXPCOM embedding:
    Mozilla.getInstance().initEmbedding(grePath, grePath, locProvider);
  4. Now we need to start an XUL application, so we get an instance of the XPCOM service manager
    nsIServiceManager serviceManager = moz.getServiceManager();
  5. Now we need to get the @mozilla.org/toolkit/app-startup;1 service:
    nsIAppStartup appStartup = (nsIAppStartup)serviceManager.getServiceByContractID("@mozilla.org/toolkit/app-startup;1", nsIAppStartup.NS_IAPPSTARTUP_IID);
  6. Get the nsIWindowWatcher interface to the above
    nsIWindowCreator windowCreator = (nsIWindowCreator)appStartup.queryInterface(nsIWindowCreator.NS_IWINDOWCREATOR_IID);
  7. Get the window watcher service
    nsIWindowWatcher windowWatcher = (nsIWindowWatcher)serviceManager.getServiceByContractID("@mozilla.org/embedcomp/window-watcher;1", nsIWindowWatcher.NS_IWINDOWWATCHER_IID);
  8. Set the window creator (from step 6)
    windowWatcher.setWindowCreator(windowCreator);
  9. Create the root XUL window:
    nsIDOMWindow win = windowWatcher.openWindow(null, "chrome://your-app/content/window.xul", "mywindow", "chrome,resizable,centerscreen", null);
  10. Set this as the active window
    windowWatcher.setActiveWindow(win);
  11. Hand over the application to xpcom/xul, this will block:
    appStartup.run();

Now, the LocationProvider is responsible for providing path(s) and file(s) that XPCOM needs. I have implemented a version that when the ‘ChromeML’ location is asked for returns an array of File’s, the first of which points to my own applications chrome folder, and the second of which is the xulrunner’s own chrome folder. This seems to work, but there are several issues:

  1. I do not seem to be able to open XUL windows (or in anyway interact with xpcom/xul) from another thread. Since this run() method on nsIAppStartup blocks, this is a bit annoying. I presume there is a way to run this loop manually, or hook into it so we can queue up requests from other threads to be invoked on the xpcom thread.

Ok, thats only one major issue for now, but I’m sure I will think of others.
If anyone has any ideas how these problems can be solved, or how one may circumvent them, I’m all ears. Also, I know that this area is so bleeding edge it hurts, so it would be nice to talk to some other people doing the same things!

4 Responses to “JavaXPCOM”

  1. Brian Says:

    Hi, did you solve the “from another thread” issue? i am in the same boat and cannot solve it as yet.

  2. mica Says:

    Try to execute appStartup.run(); in a new thread, maybe with:

    new Thread(){
    public void run(){
    appStartup.run();
    }
    }.start();

  3. Sam Says:

    Hi Ray,

    I’m having a little difficulty getting your example to work, and I wwonder if you could clarify a couple points.

    You use “chrome://your-app/content/window.xul” to point to your .xul file. Is this a relative path? And are you changing chrome.manifest or anything like that?

    Likewise, I assume the two files that LocationProvider is passing are supposed to be absolute paths to the chrome directories, right? Are we including the chrome directories themselves in the pathnames? Did you change LocationProvider in any other way (from the example at http://developer.mozilla.org/en/docs/JavaXPCOM:Embedding_Mozilla_in_a_Java_Application_using_JavaXPCOM)?

    I’m trying to implement your example, and I either get some error on the “nsIDOMWindow win = windowWatcher.openWindow…” line, or it accepts the path (even if the path is junk) and doesn’t do anything with it. If you were to explain in further detail how you got the program to work, I’d appreciate it greatly.

    Thanks!
    Sam

  4. TheReallyBest Says:

    X-Rumer is the BEST!!!

    http://upload.wikimedia.org/wikipedia/en/thumb/6/6b/XRumer_screenshot.gif/200px-XRumer_screenshot.gif

    ;)

Leave a Reply