OpenOffice UNO

OpenOfficeはUNO(Universal Network Objects)を使用してAPIを実装している。

OpenOffice.org for Developersの[SDK]-[SDK Download (1.0.2 SDK should be used for OOo 1.0.3.x)]からOpenOffice SDK をダウンロードするとドキュメントが充実しているので、ある程度は理解できるようになるのではないだろうか。

まずは、[SDK]-[Developer’s Guide (part of SDK)]からたどれる、2 First Steps を読んでみると言うのもよさそう。

LinuxでOpenOfficeでUNOを起動オプションで使えるようにするには、次のようにコマンドをうつ。ただし、ユーザーインタフェース用画面を表示して動かしたい場合は -headless はいらない。

soffice -headless \
“-accept=socket,host=localhost,port=8100;urp;StarOffice.ServiceManager” &

設定ファイルを書き変える方法は1.0.2と1.1.xでは設定方法が違うので注意が必要。ここでは1.1.xでの対応方法を書いておく。

$OfficePath/share/registry/data/org/openoffice/Setup.xcu をエディタで開いて編集する。<node oor:name=”Office”/>というエレメントのボディ部に、次のpropエレメントを追加する。

<prop oor:name=”ooSetupConnectionURL” oor:type=”xs:string”>
<value>socket,host=localhost,port=8100;urp;</value>
</prop>

この設定により、OpenOffice.orgを起動すると、8100ポートでソケット経由のUNOリモートプロトコル(urp)通信ができるようになる。

ネットワークインストールをしてあり、個人単位でこの設定をしたい場合には、$OfficePath/user/registry/data/org/openoffice/Setup.xcuにここで示したpropエレメントを追加する。

あとはsofficeをコマンド実行すればよい。動作確認はnetstatコマンドなどで8100ポートが開いているかみればいい。

$ soffice &
$ netstat -a | grep 8100
tcp 0 0 localhost.localdom:8100 *:* LISTEN

OpenOffice.org SDK のサンプルをちょっとだけさわって、Impressの新規ファイルを開いて閉じる処理をuseConnection3メソッドとして追加してみた。

import com.sun.star.beans.PropertyValue;
import com.sun.star.lang.XComponent;
import com.sun.star.sheet.XSpreadsheetDocument;
import com.sun.star.sheet.XSpreadsheets;
import com.sun.star.sheet.XSpreadsheet;
import com.sun.star.sheet.XSpreadsheetView;
import com.sun.star.table.XCell;
import com.sun.star.frame.XModel;
import com.sun.star.frame.XController;
import com.sun.star.frame.XComponentLoader;
import com.sun.star.bridge.XUnoUrlResolver;
import com.sun.star.uno.UnoRuntime;
import com.sun.star.uno.XComponentContext;
import com.sun.star.lang.XMultiComponentFactory;
import com.sun.star.beans.XPropertySet;

public class FirstConnection extends java.lang.Object {
    private XComponentContext xRemoteContext = null;
    private XMultiComponentFactory xRemoteServiceManager = null;

    public static void main(String[] args) {
        FirstConnection firstConnection1 = new FirstConnection();
        try {
            firstConnection1.useConnection();
            firstConnection1.useConnection3();
        } catch (java.lang.Exception e) {
            e.printStackTrace();
        } finally {
            System.exit(0);
        }
    }

    protected void useConnection3() throws java.lang.Exception {
    try {
        xRemoteServiceManager = this.getRemoteServiceManager("uno:socket,host=localhost,port=8100;urp;StarOffice.ServiceManager");
        // get the Desktop, we need its XComponentLoader interface to load a new document
        Object desktop = xRemoteServiceManager.createInstanceWithContext("com.sun.star.frame.Desktop", xRemoteContext);
        // query the XComponentLoader interface from the desktop
        XComponentLoader xComponentLoader = (XComponentLoader)UnoRuntime.queryInterface(XComponentLoader.class, desktop);
        // create empty array of PropertyValue structs, needed for loadComponentFromURL
        // Preparing properties for loading the document
        //PropertyValue[] loadProps = new PropertyValue[1];
            PropertyValue[] loadProps = new PropertyValue[0];
        // Setting the flag for hidding the open document
        //loadProps[ 0 ] = new PropertyValue();
        //loadProps[ 0 ].Name = "Hidden";
        //loadProps[ 0 ].Value = new Boolean(true);
        // load new impress file
        XComponent xImpressComponent = xComponentLoader.loadComponentFromURL("private:factory/simpress", "_blank", 0, loadProps);
        xImpressComponent.dispose();
    }
    catch( com.sun.star.lang.DisposedException e ) {
        xRemoteContext = null;
        throw e;
    }          
    }

    protected void useConnection2() throws java.lang.Exception {
    try {
        xRemoteServiceManager = this.getRemoteServiceManager("uno:socket,host=localhost,port=8100;urp;StarOffice.ServiceManager");
        // get the Desktop, we need its XComponentLoader interface to load a new document
        Object desktop = xRemoteServiceManager.createInstanceWithContext("com.sun.star.frame.Desktop", xRemoteContext);
        // query the XComponentLoader interface from the desktop
        XComponentLoader xComponentLoader = (XComponentLoader)UnoRuntime.queryInterface(XComponentLoader.class, desktop);
        // create empty array of PropertyValue structs, needed for loadComponentFromURL
        PropertyValue[] loadProps = new PropertyValue[0];
        // load new calc file
        XComponent xSpreadsheetComponent = xComponentLoader.loadComponentFromURL("private:factory/scalc", "_blank", 0, loadProps);
        // query its XSpreadsheetDocument interface, we want to use getSheets()
        XSpreadsheetDocument xSpreadsheetDocument = (XSpreadsheetDocument)UnoRuntime.queryInterface(XSpreadsheetDocument.class, xSpreadsheetComponent);
        // use getSheets to get spreadsheets container
        XSpreadsheets xSpreadsheets = xSpreadsheetDocument.getSheets();
        //insert new sheet at position 0 and get it by name, then query its XSpreadsheet interface
        xSpreadsheets.insertNewByName("MySheet", (short)0);
        Object sheet = xSpreadsheets.getByName("MySheet");
        XSpreadsheet xSpreadsheet = (XSpreadsheet)UnoRuntime.queryInterface(XSpreadsheet.class, sheet);
        // use XSpreadsheet interface to get the cell A1 at position 0,0 and enter 21 as value
        XCell xCell = xSpreadsheet.getCellByPosition(0, 0);
        xCell.setValue(21);
        // enter another value into the cell A2 at position 0,1
        xCell = xSpreadsheet.getCellByPosition(0, 1);
        xCell.setValue(21);
        // sum up the two cells
        xCell = xSpreadsheet.getCellByPosition(0, 2);
        xCell.setFormula("=sum(A1:A2)");
        // we want to access the cell property CellStyle, so query the cell’s XPropertySet interface
        XPropertySet xCellProps = (XPropertySet)UnoRuntime.queryInterface(XPropertySet.class, xCell);
        // assign the cell style "Result" to our formula, which is available out of the box
        xCellProps.setPropertyValue("CellStyle", "Result");
        // we want to make our new sheet the current sheet, so we need to ask the model
        // for the controller: first query the XModel interface from our spreadsheet component
        XModel xSpreadsheetModel = (XModel)UnoRuntime.queryInterface(XModel.class, xSpreadsheetComponent);

        // then get the current controller from the model
        XController xSpreadsheetController = xSpreadsheetModel.getCurrentController();
        // get the XSpreadsheetView interface from the controller, we want to call its method
        // setActiveSheet
        XSpreadsheetView xSpreadsheetView = (XSpreadsheetView)UnoRuntime.queryInterface(XSpreadsheetView.class, xSpreadsheetController);
        // make our newly inserted sheet the active sheet using setActiveSheet
        xSpreadsheetView.setActiveSheet(xSpreadsheet);    
    }
    catch( com.sun.star.lang.DisposedException e ) { //works from Patch 1
        xRemoteContext = null;
        throw e;
    }          
    }

    protected void useConnection() throws java.lang.Exception {
    String service = "uno:socket,host=localhost,port=8100;urp;StarOffice.ServiceManager";
        try {
            xRemoteServiceManager = this.getRemoteServiceManager(service);
            String available = (null != xRemoteServiceManager ? "available" : "not available");
            System.out.println("remote ServiceManager is " + available);
            //
            // do something with the service manager…
            //
        } catch (com.sun.star.connection.NoConnectException e) {
        System.err.println("No process listening on the resource");
        e.printStackTrace();
        throw e;
        } catch (com.sun.star.lang.DisposedException e) { //works from Patch 1
            xRemoteContext = null;
            throw e;
        }          
    }

    protected XMultiComponentFactory getRemoteServiceManager(String unoUrl)
        throws java.lang.Exception 
    {
        if (xRemoteContext == null) {
            // First step: create local component context, get local servicemanager and
            // ask it to create a UnoUrlResolver object with an XUnoUrlResolver interface
            XComponentContext xLocalContext =
                com.sun.star.comp.helper.Bootstrap.createInitialComponentContext(null);
            XMultiComponentFactory xLocalServiceManager = xLocalContext.getServiceManager();
            Object urlResolver  = xLocalServiceManager.createInstanceWithContext("com.sun.star.bridge.UnoUrlResolver", xLocalContext );
            // query XUnoUrlResolver interface from urlResolver object
            XUnoUrlResolver xUnoUrlResolver = (XUnoUrlResolver) UnoRuntime.queryInterface(XUnoUrlResolver.class, urlResolver);
            // Second step: use xUrlResolver interface to import the remote StarOffice.ServiceManager,
            // retrieve its property DefaultContext and get the remote servicemanager
            Object initialObject = xUnoUrlResolver.resolve(unoUrl);
            XPropertySet xPropertySet = (XPropertySet)UnoRuntime.queryInterface(XPropertySet.class, initialObject);
            Object context = xPropertySet.getPropertyValue("DefaultContext");            
            xRemoteContext = (XComponentContext)UnoRuntime.queryInterface(XComponentContext.class, context);
        }
        return xRemoteContext.getServiceManager();
    }
}

同じカテゴリの記事: Open Source