Saturday 13 December 2008

OpenOffice (3.0) / UNO API

Recently a project needed some reporting enhancements (spreadsheet charts) for which Apache POI didn't provide the necessary support. So, after some exploration, I decided on using OpenOffice with it's API, in this particular instance it was OpenOffice 3.0m9 (latest at the tine of writing) and the UNO Java API.

www.openoffice.org

OpenOffice provides some very powerful tools, including Spreadsheets, Documents, PDF etc along compatibility with MS Office. In addition, OpenOffice is quite powerful at convertion document types and between versions. For example a MS word document could be loaded and then saved as a PDF.

OpenOffice - www.openoffice.org
Forum - http://user.services.openoffice.org/en/forum/
Wiki - http://wiki.services.openoffice.org/wiki/Main_Page (including good developer section)
FAQ - http://wiki.services.openoffice.org/wiki/Uno/FAQ

The OpenOffice suite comes with an SDK and the UNO API, supporting various languages, including Java.

SDK download - http://download.openoffice.org/3.0.0/sdk.html

The SDK/API is based on UNO (Unified Network Objects) which is an alternative/competator to COM, like CORBA etc, and allows the remote (out of process) communication and control of OpenOffice - "UNO is a component model that offers inter-operability between different programming languages, different objects models, different machine architectures, and different processes; either in a LAN or via the Internet."

Another acronym is URE - "Each component lives in a Uno Runtime Environment (URE). A URE is identified by the implementation language (e.g., C++, Java, Perl, ...) and the current process."

See here for more details: http://udk.openoffice.org/common/man/uno.html

When using OpenOffice on the server side to provide reports (in my case, as part of a web application), various SDK jars are needed along with a means to find the OpenOffice installation.

The Java jars needed are:
  • juh.jar
  • jurt.jar
  • ridl.jar
  • jut.jar
  • unoil.jar

I chose to include them in my web application WAR file.
This can create problems, because the classpath to the jars will not be where OpenOffice is installed, to work around this the Java classes from the SDK can be loaded and bootstrapped in the class loaded, but this is tricky when using a web app container. For convienience I made use of the useful bootstrapconnector.jar utility library. This library can connect to OpenOffice regardless of the location of the jars, it just needs a path to an OpenOffice installation, which I set as an ENV variable called UNO_PATH.

BootstrapSocketConnector - http://user.services.openoffice.org/en/forum/viewtopic.php?f=44&t=2520

I also made use of the OpenOffice plugin for Netbeans 6.5 to get a quick start developing the code, before moving to the production solution.


Some things to watch out for:

One problem I stumbled into. Installing OpenOffice for the first time on a remote Linux (CentOS) machine over a terminal, when I came to run the web application the program appears to hang. Some investigation with ps showed that soffice was being started, but that I was getting many instances, all apparently hung. I replicated the setup on a different Linux installation, this time one with a desktop / display manager. It was then obvious what was happening, the first time OpenOffice is launched, it prompts the user with a registration wizard! Oops.

So the solution to this is simple, pass an option when launching the OpenOffice process, this can be achieved conveniently using the bootstrapsocketconnect with something like the following:

// Create OOo server with additional -nofirststartwizard option
List oooOptions = OOoServer.getDefaultOOoOptions();
oooOptions.add("-nofirststartwizard");
OOoServer oooServer = new OOoServer(OOO_EXEC_FOLDER, oooOptions);

// Connect to OOo
BootstrapSocketConnector bootstrapSocketConnector = new BootstrapSocketConnector(oooServer);
XComponentContext remoteContext = bootstrapSocketConnector.connect();


.

No comments: