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.

Tagged as: 2 Comments
4Jan/080

Asynchronous Node children in NetBeans Platform

5 minutes playing with the new NetBeans 6 platform and I found a very useful feature. In previous post, I download URL. Using that code, I want to create a list of POJOs (that will be represented by a list of Nodes). In old NB5 days, I had to create a Thread and a lot of syncronization code to make the download run in background. In NetBeans 6 is easy as 1, 2, 3:

  1. Subclass ChildFactory (from Nodes API), implementing createKeys and createNodeFromKey
  2. Create an AbstractNode passing Children.create(MyChildFactory)
  3. Compile, run and enjoy!
4Jan/080

HTTP POST download with Java’s URL class

This is easy, but I always forget the recipe. I need to download and process a file using a POST request. The code is:

URL url = new URL(FORM_URL);
URLConnection conn = url.openConnection();
conn.setDoOutput(true);
 
OutputStreamWriter out = new OutputStreamWriter(conn.getOutputStream());
out.write("field=value&field=value&...");
out.flush();
 
InputStreamReader isr = new InputStreamReader(conn.getInputStream());
BufferedReader in = new BufferedReader(isr);
String line;
 
while ((line = in.readLine()) != null) {
    // do something
}
 
out.close();
in.close();

The only catch is to use URLEncoder.encode to translate keys and values to the x-form-url-encoded style.

Tagged as: , , , No Comments