This blog is now hosted on my own server:
http://extremejava.tpk.com.br
2008-02-08
2008-01-08
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:
I created another module with a single TopComponent, and add this snippet:
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:
Yes, it is the purest evilness, but works (with some bugs):
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.
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.
- 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() {
try {
add(oo = new OOoBean());
oo.loadFromURL("private:factory/swriter", null);
oo.aquireSystemWindow();
} catch (Exception ex) {
Exceptions.printStackTrace(ex);
}
}
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:
- Grab odk / source / com / sun / star / lib / loader from OOo's CVS and add it to integration module.
- Add unowinreg.dll to Windows Path (if you are on Linux, skip this step).
- Alter Loader.java and add this after line 205 (after "UnoInfo" call):
vec.add(new File(fClassesDir, "officebean.jar").toURL());
This part of the magick adds "officebean" to classpath. Here lies OOoBean, and is optional if you are only using UNO interfaces. Other JARs are correctly listed by UnoInfo. - 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);
} - Back to the TC, I use "buildOOoBean" in ComponentOpened and "showOOoBean" AFTER the component is shown (does not work otherwise).
Yes, it is the purest evilness, but works (with some bugs):
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.
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.
2008-01-04
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:
- Subclass ChildFactory (from Nodes API), implementing createKeys and createNodeFromKey
- Create an AbstractNode passing Children.create(MyChildFactory)
- Compile, run and enjoy!
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:
The only catch is to use URLEncoder.encode to translate keys and values to the x-form-url-encoded style.
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();
BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
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.
Subscribe to:
Posts (Atom)