<< Asterisk IMAP store for Voicemail | Home | Attach Sources to your Maven Artifacts! >>

Using OpenOffice.org from Java Applications

A UNO Quickstart

OpenOffice.org is quite nice as a free and open source office suite that works on Linux and Windows and I use it quite a lot.

Besides its use as a desktop application it is not widely recognized that it can also be used as a backend document processing system by your Java application. Use cases are numerous: an invocice generating webapp in your intranet, prefilled document templates with content from a database or just an online inventory of your documents wiht support for on demand conversion to Microsoft Office formats or PDF.

The key to make your Java applications talk to OpenOffice is called UNO. UNO stands for Universal Network Objects and is the remoting system used by OpenOffice. It's a bit like CORBA.

First to enable remoting you must start OpenOffice with the -accept option:

/usr/bin/ooffice -accept="socket,host=0,port=8200,tcpNoDelay=1;urp;" -nologo
Parameter Description
host Hostname or IP number of the resource to listen on/connect. May be localhost. In an acceptor string, this may be 0 ('host=0'), which means, that it accepts on all available network interfaces.
port TCP/IP port number to listen on/connect to.
tcpNoDelay Corresponds to the socket option tcpNoDelay. For a UNO connection, this parameter should be set to 1 (this is NOT the default ― it must be added explicitly). If the default is used (0), it may come to 200 ms delays at certain call combinations.

Source: Professional UNO

You can also add the -headless option which allows using the application without user interface.

There is not much introducory documentation besides the heavy-weight Developers Guide and a blog entry from 2005.

You need a few jars that you can either download as part of the SDK from the OpenOffice.org website. If you are using Maven you can instead just add the following dependencies to your pom.xml:

<dependency>
<groupId>org.openoffice</groupId>
<artifactId>juh</artifactId>
<version>2.1.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.openoffice</groupId>
<artifactId>jurt</artifactId>
<version>2.1.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.openoffice</groupId>
<artifactId>ridl</artifactId>
<version>2.1.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.openoffice</groupId>
<artifactId>unoil</artifactId>
<version>2.1.0</version>
<scope>compile</scope>
</dependency>

You need some boilerplate code to connect to OpenOffice:

Object x;
Object defaultContext;
Object desktop;

XComponentContext componentContext = Bootstrap.createInitialComponentContext(null);
x = componentContext.getServiceManager().createInstanceWithContext("com.sun.star.connection.Connector", componentContext);
XConnector connector = (XConnector) UnoRuntime.queryInterface(XConnector.class, x);
XConnection connection = connector.connect(getConnectionString());

x = componentContext.getServiceManager().createInstanceWithContext("com.sun.star.bridge.BridgeFactory", componentContext);
XBridgeFactory bridgeFactory = (XBridgeFactory) UnoRuntime.queryInterface(XBridgeFactory.class, x);
bridge = bridgeFactory.createBridge("", "urp", connection, null);

x = bridge.getInstance("StarOffice.ServiceManager");
XMultiComponentFactory multiComponentFactory = (XMultiComponentFactory) UnoRuntime.queryInterface(XMultiComponentFactory.class, x);

XPropertySet properySet = (XPropertySet) UnoRuntime.queryInterface(XPropertySet.class, multiComponentFactory);
defaultContext = properySet.getPropertyValue("DefaultContext");
componentContext = (XComponentContext) UnoRuntime.queryInterface(XComponentContext.class, defaultContext);
multiComponentFactory = componentContext.getServiceManager();

desktop = multiComponentFactory.createInstanceWithContext("com.sun.star.frame.Desktop", componentContext);
componentLoader = (XComponentLoader) UnoRuntime.queryInterface(XComponentLoader.class, desktop);
multiServiceFactory = (XMultiServiceFactory) UnoRuntime.queryInterface(XMultiServiceFactory.class, multiComponentFactory);

Now you have a XComponentLoader that you can use to load additional resources like a document:

// Load the document, which will be displayed.
XComponent xComponent = openOfficeConnection.getComponentLoader().loadComponentFromURL(
"test.odt", "_blank", 0, new PropertyValue[0]);
// Get the textdocument
XTextDocument aTextDocument = (XTextDocument) UnoRuntime.queryInterface(XTextDocument.class, xComponent);

If you didn't run OpenOffice in headless mode you'll see the document on your screen now. Let's have a look at some simple operations on that document:

XTextDocument xtd = (XTextDocument) UnoRuntime.queryInterface(XTextDocument.class, xComponent);
XDocumentInfoSupplier xdis = (XDocumentInfoSupplier) UnoRuntime.queryInterface(XDocumentInfoSupplier.class, xtd);
XDocumentInfo xdi = xdis.getDocumentInfo();
XPropertySet xps = (XPropertySet) UnoRuntime.queryInterface(XPropertySet.class, xdi);
XPropertySetInfo xpsi = xps.getPropertySetInfo();

XFastPropertySet xfps = (XFastPropertySet) UnoRuntime.queryInterface(XFastPropertySet.class, xps);

for (Property property : xpsi.getProperties())
{
String name = property.Name;
Object value = xfps.getFastPropertyValue(property.Handle);

System.out.println(name + ": " + value);
}

This code snippet prints the meta information of the document (what you get if you choose File/Properties...) to stdout.

Of course you can do much more, querying for tables in the document, changing or adding text, saving the document to different formats like Microsoft Word or PDF. Have a look at the javadocs and the IDL reference at http://api.openoffice.org/ and play with it.



Re: Using OpenOffice.org from Java Applications

This is a nice how-to. I would like to do it as a Service on the back-end. I thought using Servlets, but the problem starts to compile it properly, that the back-end application is able to work with the *.jars.

Do you have an example (via ANT) how to compile it properly?

Thanks,
D.

Re: Using OpenOffice.org from Java Applications

Which problems do you encounter when compiling your application?
I am using the OpenOffice.org jars in a web environment and it works well. I am sorry I don't have any ant scripts as I am using maven to build my projects but it should work much the same way with ant I suppose.

Re: Using OpenOffice.org from Java Applications

Hi, I agree, nice how-to.  One minor issue, I tried the -headless option running on OpenOffice 2.3 on Windows XP and it had no effect.  That is to say that the document still popped up on my screen.  Any comments?

Re: Using OpenOffice.org from Java Applications

And I like your banner photo!  Where is it?

Re: Using OpenOffice.org from Java Applications

I am not sure how that works on Windows, I am using it on my Linux servers this way.
The picture has been taken near my home in Cologne, Germany.

Re: Using OpenOffice.org from Java Applications

Is "UNI" a typo (1st sentence of 3rd paragraph)?

Re: Using OpenOffice.org from Java Applications

Yes, should be UNO of course. I've fixed it.
Thanks.

Re: Using OpenOffice.org from Java Applications

If there aren't binary images involved, wouldn't it be much more simple and light-weight to just generate the component XML files according to the schema/DDLs and zip up as required by the .xsc spec?  If this won't work for some reason, please say so.  I'd rather not spend my time on fruitless work.

I don't know why OOO doesn't provide a lighter weight API for integrators.  Loading a separate remoting engine is a pretty large concession just to support their file format.  Compare to how lightweight Jexcel is for .xls and Itext for .pdf.

Jdom is so easy to use that I'm considering using the strategy above to create .xsc docs, then use UNO to convert to .xls.  Trade-off between efficient performance with Jexcel lib vs. easy coding to just do the conversion with UNI.

Re: Using OpenOffice.org from Java Applications

I agree that remoting OpenOffice just to generate simple ODF files might not be the best solution. It becomes interesting when you want to use more advanced document processing features of OpenOffice.
There is a project that aims at implementing a pure Java library to work with OpenOffice document: odf4j
I didn't have a look at it yet, but it might be worth a look before starting from scratch.

Re: Using OpenOffice.org from Java Applications

I doubt if even the public interface of odf4j will be stabilized in 2008.  They're still designing basic usage.

Re: Using OpenOffice.org from Java Applications

I am using openoffice 2.3 from java in windows platform, successfully converted word to pdf from java but failed while did from web application alerting with UI language cannot be recognized.

Add a comment Send a TrackBack