LibreOffice Developer's Guide: Chapter 16 - JavaBean for Office Components

    From The Document Foundation Wiki

    This chapter describes the OOoBean component, a generic Java Bean wrapper for LibreOffice components. It is assumed that the reader is familiar with the Java Beans technology. Additional information about Java Beans can be found at https://docs.oracle.com/javase/tutorial/javabeans/.

    With the OOoBean, a developer can easily write Java applications, harnessing the power of LibreOffice. It encapsulates a connection to a locally running LibreOffice process, and hides the complexity of establishing and maintaining that connection from the developer.

    It also allows embedding of LibreOffice documents within the Java environment. It provides a Java AWT window into which the backend LibreOffice process draws its visual representation. This window can then be plugged into the UI hierarchy of the hosting Java application. The embedded document is controlled from the Java environment, since the OOoBean allows developers to access the complete LibreOffice API from their Java environment giving them full control over the embedded document, its appearance and behavior.

    Using the OOoBean

    The Java class OOoBean can be instantiated directly, or application classes can be derived from this class. If a real Java Bean is to be created, which for example can be used in Java Bean UI builders, it has to be subclassed. The application class then might use the UNO bootstrapping mechanism to find the OOoBean, LibreOffice and its API classes. This mechanism is not built into OOoBean itself because it can not be used to find itself. And once the OOoBean class has been found, you intrinsically also find the LibreOffice installation and the API classes.

    A standard LibreOffice is a prerequisite. The LibreOffice executable, as well as the UNO libraries and runtime, is found using the Java Class Loader. Moving or copying the needed class files will not result in a working OOoBean.

    Warning.svg

    Warning:
    Since the Office Bean uses a native peer to render LibreOffice documents, Swing components, such as drop-down menus or list boxes appear behind it, or they are not displayed at all. One way to avoid this is by exclusively employing AWT components when using the Office Bean. Another, but only partial, solution is to tell Java Swing to create heavy weight windows for popup menus: JPopupMenu.setDefaultLightWeightPopupEnabled.


    Warning.svg

    Warning:
    Currently the Office Bean is not available for Mac (see issue 54172 for more details).


    The OOoBean by Example

    The OOoBeanViewer is a Java application that displays LibreOffice documents in a Java AWT applet, which allows for the control of some toolboxes, the menu bar and the status bar, as well as storing and loading the document content to/from an internal buffer.

    The OOoBean Viewer

    The OOoBeanViewer utilizes the class OOoBean directly without subclassing it:

    public class OOoBeanViewer extends java.applet.Applet
    {
        ...
        private OOoBean aBean;
        ...
    
        public void init()
        {
            aBean = new OOoBean();
        }
    
        ...
        {
            add( aBean );
        }
    }

    Initially, the OOoBean component does not contain a document. A document can be created with the loadFromURL method:

    private void createBlankDoc(String url, String desc)
    {
        //Create a blank document
        try
        {
            aBean.loadFromURL( url, null );
            ....
        }
        catch ( com.sun.star.comp.beans.SystemWindowException aExc )
        {
            // this exception will be thrown when no system window parent can be found
            ...
        }
        catch ( com.sun.star.comp.beans.NoConnectionException aExc )
        {
            // this exception is thrown
            // when no connection to a [PRODUCTNAME] instance can be established
            ...
        }
        catch ( Exception aExc )
        {
            ...
        }
    }

    Some tool windows of the document window within the Java Bean can be controlled directly by the OOoBean API. For example, to toggle visibility of the menu bar:

    aBean.setMenuBarVisible( !aBean.isMenuBarVisible() );

    The examples above provide an overview of how the OOoBean API is used to create Java Beans that can be used in Java applications and applets. For concrete Java Beans, you usually subclass OOoBean and create appropriate BeanInfo classes for integrating within an IDE (Integrated Development Environment), such as the Bean Development Kit or Forte for Java. Developers can use the examples as a guideline when using the OOoBean API to write new beans, or use or extend the example beans.

    API Overview

    The OOoBean offers methods that can be applied to all LibreOffice document types.

    Methods of com.sun.star.comp.beans.OOoBean
    OOoBean() constructor - creates an OOoBean with an implicit connection
    OOoBean(OfficeConnection) constructor - creates an OOoBean with an explicit connection
    setOOoStartTimeOut(...) void - sets the timeout for methods which start LibreOffice
    setOOoCallTimeOut(...) void - sets the timeout for other methods
    SetOOoCheckCycle(...) void - sets repeat period for cyclic LibreOffice alive check
    setOOoConnection(...) void - sets an explicit connection to a LibreOffice instance
    startOOoConnection(...) void - starts a connection with an explicit connection URL
    isOOoConnected() boolean - returns whether the OOoBean is connected to a LibreOffice
    stopOOoConnection() void - stops the current connection to LibreOffice
    getOOoConnection() OfficeConnection - returns the current connection to LibreOffice
    getMultiServiceFactory() XMultiServiceFactory -- returns the service factory of the connected LibreOffice
    getOOoDesktop() XDesktop - returns the desktop object of the connected LibreOffice
    clearDocument() void -- resets the Bean to an empty document
    clear() void - removes the document from the Bean
    aquireSystemWindow() void - has to be called when the Bean has a parent component which has a valid system window
    releaseSystemWindow() void -- has to be called before the parent component loses its system window, e.g. before it is removed from its parent component
    loadFromURL() void -- loads a document into the Bean
    loadFromStream() void -- loads a document from a Java stream int o the Bean
    loadFromByteArray() void -- loads a document from a byte array into the Bean
    storeToURL() void - stores the document in the Bean to an URL
    storeToStream() void - stores the document in the Bean to a stream
    storeToByteArray() void - stores the document in the Bean to a byte array
    getFrame() Frame -- returns a wrapper for Frame
    getController() Controller -- returns a wrapper for Controller
    getDocument() Document -- returns a wrapper for OfficeDocument
    setAllBarsVisible() void - sets visibility of all tool bars, known by this Bean
    set...BarVisible() void - sets visibility of a specific tool bar
    is...BarVisible() boolean - returns visibility of a specific tool bar

    Configuring the Office Bean

    The OfficeBean

    The fundamental framework of the Office Bean is contained in the officebean.jar archive file that depends on a local library officebean.dll or libofficebean.so, depending on the platform. The interaction between the backend LibreOffice process, officebean local library, Office Bean and the Java environment is shown in the illustration below.

    The Office Bean allows the developer to connect to and communicate with the LibreOffice process through a named pipe. It also starts up a LibreOffice instance if it cannot connect to a running office. This is implemented in the Office Bean local library. The Office Bean depends on three configuration settings to make this work. It has to find the local library, needs the location of the LibreOffice executable, and the bean and office must know the pipe name to use.

    Default Configuration

    The Office Bean uses default values for all the configuration settings, if none are provided:

    • Since OpenOffice.org 1.1.0 the officebean.jar is located in the <OfficePath>/program/classes directory.
    • It looks for the local library (Windows: officebean.dll, Unix: libofficebean.so) relative to the officebean.jar in the <OfficePath>/program directory. The local library depends on the following shared libraries:
      1. The library sal3 (Windows: sal3.dll, Unix: libsal3.so) is located in the <OfficePath>/program folder. It maybe necessary to add the <OfficePath>/program folder to the PATH environment variable if the bean cannot find sal3.
      2. The library jawt.dll is needed in Windows. If the bean cannot find it, check the Java Runtime Environment binaries (<JRE>/bin) in your PATH environment variable.
    • It expects the LibreOffice installation in the default install location for the current platform. The soffice executable is in the program folder of a standard installation.
    • The pipe name is created using the value of the user.name Java property. The name of the pipe is created by appending "_office" to the name of the currently logged on user, for example, if the user.name is "JohnDoe", the name of the pipe is "JohnDoe_office".

    Based on these default values, the Office Bean tries to connect to an office. The office must run in listening mode. That is, it must have been started with the -accept command line option. If there is no running office, then it attempts to start one. The exact parameters used by the bean are:

     # WINDOWS
     soffice.exe -bean -accept=pipe,name=<user.name>_Office;urp;StarOffice.NamingService
    
     # UNIX
     soffice -bean "-accept=pipe,name=<user.name>_Office;urp;StarOffice.NamingService"
    
    Warning.svg

    Warning:
    There is a limitation in the communication process with the Office Bean and older versions of LibreOffice. If a LibreOffice process is already running that was not started with the proper -accept=pipe option, the Office Bean does not connect to it. Since OpenOffice.org 1.1.0 this limitation is obsolete.


    In case an office document is displayed outside of the Java frame, then the office has probably been started with wrong or no arguments. Providing the proper command-line arguments is necessary, so that the LibreOffice process can open a correctly named pipe, through which it communicates with the Java application. Only if this pipe can be established, the office will display the document in the Java window.

    You can avoid providing the command-line options by editing the file <OfficePath>\user\config\registry\instance\org\openoffice\Setup.xml. Within the <Office/> element, the developer adds an <ooSetupConnectionURL/> element with settings for a named pipe. The following example shows a user-specific Setup.xml that configures a named pipe for a user named JohnDoe:

    <?xml version="1.0" encoding="UTF-8"?>
    <Setup state="modified" cfg:package="org.openoffice"
    xmlns="http://openoffice.org/2000/registry/components/Setup"
    xmlns:cfg="http://openoffice.org/2000/registry/instance"
    xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance">
    <Office>
    <ooSetupConnectionURL cfg:type="string">
        pipe,name=JohnDoe_Office;urp;StarOffice.NamingService
    </ooSetupConnectionURL>
        <Factories cfg:element-type="Factory">
        <Factory cfg:name="com.sun.star.text.TextDocument">
            <ooSetupFactoryWindowAttributes cfg:type="string">
            193,17,1231,1076;1;
            </ooSetupFactoryWindowAttributes>
        </Factory>
        </Factories>
    </Office>
    </Setup>

    With this user-specific Setup.xml file, the office opens a named pipe JohnDoe_Office whenever it starts up. It does not matter if the user double clicks a document, runs the Quickstarter, or starts a new, empty document from a LibreOffice template.

    Customized Configuration

    Besides these default values, the Office Bean can be configured to use other parameters. There are three possibilities:

    • starting the connection with an explicit UNO URL including path and pipe name parameters
    • creating the connection manually and handing this object to the OOoBean
    • creating the OOoBean with such a manually created connection object.

    The first method that a developer uses to configure the Office Bean is through the UNO URL passed in the setUnoUrl() call. The syntax of the UNO URL is as follows:

     url := 'uno:localoffice'[','<params>]';urp;StarOffice.NamingService'
     params := <path>[','<pipe>]
     path := 'path='<pathv>
     pipe := 'pipe='<pipev>
     pathv := platform_specific_path_to_the_local_office_distribution
     pipev := local_office_connection_pipe_name
    

    Here is an example of how to use setUnoUrl() in code:

    OfficeConnection officeConnection = new LocalOfficeConnection();
    officeConnection.setUnoUrl(
    “uno:localoffice,path=/home/user/staroffice6.0/program;urp;StarOffice.NamingService”);
    aBean = new OOoBean( officeConnection );

    Warning.svg

    Warning:
    In OpenOffice.org 1.1.0 the properties mechanism was removed and cannot be used any longer. The following section about the Office Bean properties and the officebean.properties file are only valid for older OpenOffice.org versions. Since OpenOffice.org 1.1.0 the Office Bean uses an implicit find mechanism over the classpath for the office and the local Office Bean library so that no properties file is necessary.


    Internal Architecture

    These details are not needed for developers utilizing the OOoBean class. This information is directed to developers who want to adapt the OOoBean mechanisms to other technologies, e.g. to implement access to a remote LibreOffice instance.

    Internally, the OOoBean consists of three major parts which are all included in the officebean.jar file. The classes LocalOfficeWindow and LocalOfficeConnection implement a fundamental framework that makes it possible to connect to the office and display the document window of a local LibreOffice installation in an AWT or Swing frame.

    The Internal Office Bean API

    The Office Bean API is exported in two Java interfaces, com.sun.star.comp.beans.OfficeConnection and com.sun.star.comp.beans.OfficeWindow.

    Note pin.svg

    Note:
    These interfaces are Java interfaces in the com.sun.star.comp.beans package, they are not UNO interfaces.

    Note pin.svg

    Note:
    Prior to OpenOffice.org 2.0.0 all Office Bean classes were in the com.sun.star.bean package. As of OpenOffice.org 2.0.0 the classes are contained in the com.sun.star.comp.bean package. The classes of the com.sun.star.bean package are still contained in the officebean.jar but they are deprecated. Further development and bug fixing will occur only in the com.sun.star.comp.bean package.

    An implementation of com.sun.star.comp.beans.OfficeConnection is provided in the class com.sun.star.comp.beans.LocalOfficeConnection. The class com.sun.star.comp.beans.LocalOfficeWindow implements com.sun.star.comp.beans.OfficeWindow. The relationship between the Office Bean interfaces and their implementation classes is shown in the illustration below.

    The OfficeBean structure

    The following sections describe the Office Bean interfaces OfficeConnection and OfficeWindow. Refer to the section Using the OOoBean for an explanation of how the implementation classes are used.

    OfficeConnection Interface

    The com.sun.star.comp.beans.OfficeConnection interface contains the methods used to configure, initiate,and manage the connection to LibreOffice. These methods are:

    public void setUnoUrl(String URL) throws java.net.MalformedURLException
    public com.sun.star.uno.XComponentContext getComponentContext()
    public OfficeWindow createOfficeWindow(Container container)
    public void setContainerFactory(ContainerFactory containerFactory)

    The client uses setUnoUrl() to specify to the Office Bean how it connects to the LibreOffice process. See the section Configuring the Office Bean for a description of the syntax of the URL. A java.net.MalformedURLException is thrown by the concrete implementation if the client passes a badly formed URL as an argument.

    The method getComponentContext() gets an object that implements the com.sun.star.uno.XComponentContext interface from the Office Bean. This object is then used to obtain objects implementing the full LibreOffice API from the backend LibreOffice process.

    A call to createOfficeWindow() requests a new OfficeWindow from the OfficeConnection. The client obtains the java.awt.Component from the OfficeWindow to plug into its UI. See the getAWTComponent() method below on how to obtain the Component from the OfficeWindow. The client provides java.awt.Container that indicates to the implementation what kind of OfficeWindow it is to create.

    The method setContainerFactory() specifies to the Office Bean the factory object it uses to create Java AWT windows to display popup windows in the Java environment. This factory object implements the com.sun.star.comp.beans.ContainerFactory interface. See below for a definition of the ContainerFactory interface.

    If the client does not implement its own ContainerFactory interface, the Office Bean uses its own default ContainerFactory creating instances of java.awt.Canvas.

    OfficeWindow Interface

    The com.sun.star.comp.beans.OfficeWindow interface encapsulates the relationship between the AWT window that the client plugs into its UI, and the com.sun.star.awt.XWindowPeer object, which the LibreOffice process uses to draw into the window. It provides two public methods:

    public java.awt.Component getAWTComponent()
    public com.sun.star.awt.XWindowPeer getUNOWindowPeer()

    The client uses getAWTComponent() to obtain the Component window associated with an OfficeWindow. This Component is then added to the clients UI hierarchy.

    The method getUNOWindowPeer() obtains the UNO com.sun.star.awt.XWindowPeer object associated with an OfficeWindow.

    ContainerFactory Interface

    The interface com.sun.star.comp.beans.ContainerFactory defines a factory class that the client implements if it needs to control how popup windows generated by the backend LibreOffice process are presented within the Java environment. The factory has only one method:

    public java.awt.Container createContainer()

    It returns a java.awt.Container.

    Note pin.svg

    Note:
    For more background on handling popup windows generated by LibreOffice, and possible threading issues to consider, see Java Window Integration.

    LocalOfficeConnection and LocalOfficeWindow

    The class LocalOfficeConnection implements a connection to a locally running LibreOffice process that is an implementation of the interface OfficeConnection. Its method createOfficeWindow() creates an instance of the class LocalOfficeWindow, that is an implementation of the interface OfficeWindow.

    Where LocalOfficeConnection keeps a single connection to the LibreOffice process, there are multiple, shared LocalOfficeWindow instances for multiple beans. The LocalOfficeWindow implements the embedding of the local LibreOffice document window into a java.awt.Container.

    Heckert GNU white.svg

    Content on this page is licensed under the Public Documentation License (PDL).