Extreme Java When vanilla Java is not enough

8Jan/082

Blackmagic with NetBeans and OpenOffice

This one is one of the weirdest (and useful) things I ever seen in 16 years of my life as a developer (I'm 26, BTW)... OpenOffice is a very powerful Office Automation solution... NetBeans Plaform is a very powerful application platform... Can you imagine what you get when you mix both together? Yup, this is possible. With NB and OOo installed, you just need to create a NB Module with following JARs from OOo:

  • juh.jar
  • jurt.jar
  • officebean.jar
  • ridl.jar
  • unoil.jar

I created another module with a single TopComponent, and add this snippet:

private OOoBean oo;
 
@Override
public void componentOpened() {
  add(oo = new OOoBean());
  oo.loadFromURL("private:factory/swriter", null);
  oo.aquireSystemWindow();
}

But, this will NOT work... If you try to run it, an exception will be thrown, because OOo libs (.DLL/.SO) will not be found. They only exists in OOo install folder, and are automagically found by OOo classes - only if they aren't moved from the "classes" folder in OOo installation.

The workaround is a couple of classes in OOo SDK and The Ultimate Blackmagic(TM) - patent pending:

  1. Grab odk / source / com / sun / star / lib / loader from OOo's CVS and add it to integration module.
  2. Add unowinreg.dll to Windows Path (if you are on Linux, skip this step).
  3. We need to add "officebean" to classpath. Here lies OOoBean, and is optional if you are only using UNO interfaces. Other JARs are correctly listed by UnoInfo. Alter Loader.java and add this after line 205 (after "UnoInfo" call):
    vec.add(new File(fClassesDir, "officebean.jar").toURL());
  4. Now, the ugliest part of the evil potion: create a Facade. Using OOoBean directly will lead to some ugly ClassLoader conflicts. I've no time to fix this, but the following works:
    public static Container buildOOoBean() {
      return (Container) Loader.getCustomLoader().
        loadClass("com.sun.star.comp.beans.OOoBean").
        newInstance();
     
    }
    public static void showOOoBean(Container oo) {
      Class c = oo.getClass().
        getClassLoader().
        loadClass("com.sun.star.beans.PropertyValue");
     
      Class ca = Array.newInstance(c, 0).getClass();
      Method m = oo.getClass().
       getMethod("loadFromURL", String.class, ca);
     
      m.invoke(oo, "private:factory/swriter", null);
      oo.getClass().
        getMethod("aquireSystemWindow").invoke(oo);
    }
  5. Back to the TC, I use "buildOOoBean" in ComponentOpened and "showOOoBean" AFTER the component is shown (does not work otherwise).

This level of indirection is mandatory, because client module's ClassLoader is different than integration module's. If I do "OOoBean oo = new OOoBean()", the declaration and instantiation will try to use the JARs bundled. Since they don't lie on OOo install folder, the libraries will not be found. If I use "oo = (OOoBean) Loader.getCustomLoader().getClass("...").newInstance()", the "OOoBean" class from declaration will NOT be the same as the class instantiated. If you ever worked with JavaEE 4 and JSF/Struts/etc, you know that same classes from different ClassLoaders throws ClassCastException.

Yes, it is the purest evilness, but works (with some bugs):

Screenshot of OpenOffice and NetBeans

OOo works really well with Java, but NetBeans ClassLoader is "self-contained" (i.e. your bundled application must include EVERYTHING you use). This is a very nice architecture, but does not help if you if you need to interface with external applications.

Comments (2) Trackbacks (1)
  1. Thanks a lot for the tip.
    On my PC it works on OOo2.4 but not with OOo3.0.
    Could you pleas give it a try?

    Thanks a lot

  2. Hi Eduardo, i see your page http://extremejava.blogspot.com/2008/01/blackmagic-with-netbeans-and-openoffice.html
    I have a problem with open file .odt in java code.
    my problem is this. I created the java classes using itext to create a document library. Rtf, or. Odt. I integrated classes in Oralce form and everything works. I created a file. Odt application server on a folder and now only remains for me to open the file. The roads are two:
    1. Directly from the server, you can?
    2. From the client using the API or openoffice launching the executable with cmd?


Leave a comment

(required)


*