LibreOffice5(7)既存インターフェイスを継承してPythonスクリプトをUNOコンポーネント化する例:その2

2015-11-29

旧ブログ

t f B! P L

前の関連記事:LibreOffice5(6)既存インターフェイスを継承してPythonスクリプトをUNOコンポーネント化する例:その1


前回やったcom.sun.star.task.XJobExecutorインターフェイスを継承して実装する方法は文字列を引数に渡してメニュー項目によって処理の場合分けができるメリットがありました。今回はcom.sun.star.lang.XMainインターフェイスを継承している例です。

com.sun.star.lang.XMainインターフェイスを継承してUNOコンポーネント化している例


例 Examplesのswritercomp.py, swritercompclient.py

最初ダウンロードしたときは動かなかったのですがPyCharmで読み込んでフォーマットを整えたら動きました。

swritercomp.pyのタブのコードがおかしかったようです。

com.sun.star.lang.XMainインターフェイスを継承して実装しています。

swritercomp.pyの最後をみると実装名はorg.openoffice.comp.pyuno.swriter、サービス名はorg.openoffice.demo.SWriterであることがわかります。

動かしてみた方法です。

まずswritercomp.pyとswritercompclient.pyをマイマクロフォルダに置きました。

LibreOffice5を起動してツール→拡張機能マネージャーでswritercomp.pyを登録しました。

LibreOffice5をソケット通信可能な状態で起動しました。(起動方法の設定はlinuxBean14.04(83)LibreOfiice5.0.2のインストール参照。)

swritercompclient.pyを実行します。

私の場合はPyCharmから実行しました。

インタープリタは/opt/libreoffice5.0/program/pythonを指定したプロジェクトでの実行です。

するとWriterのドキュメントが開いて文字や表が表示されました。

swritercompclient.pyはLibreOfficeとポート番号2002でソケット通信を確立してコンポーネントコンテクストを得てそれでorg.openoffice.demo.SWriterをインスタンス化しています。

これでswritercomp.pyのSWriterCompクラスがインスタンス化されたことになり、そのあとcom.sun.star.lang.XMainインターフェイスのrun()メソッドを実行しています。

run()メソッドの引数には文字列のタプルを渡します。

swritercompclient.pyの最終行のpyComp.run( (), )はpyComp.run(tuple())と書き換えても動きました。

com.sun.star.lang.XMainインターフェイスを実装する意義について調べようとしましたがPythonに関してとくに有用な情報は収集できませんでした。

Pythonでインターフェイスを実装している例が他にToolPanelPocというのがあったのですが、これはmakeでできあがったtoolpanel.oxtを拡張機能マネージャーに登録してもreadmeに書いてあるようなメニューの項目は出現せず、LibreOffice5.0.2.2やWindowsの4.2.6.2では何も変化はありませんでした。

以下はPython以外のcom.sun.star.lang.XMainインターフェイスを実装する例についてやってみましたがcom.sun.star.lang.XMainインターフェイスを実装する意義についてPythonに関する情報は得られませんでした。

com.sun.star.lang.XMainインターフェイスを実装するC++の例


このXMainインターフェイスについてはわざわざデベロッパーガイドでThe UNO Executable - Apache OpenOffice Wikiの項目で解説してあります。

実行可能なUNOコンポーネントのためのインターフェイス、みたいな感じで書いてあります。

まずはSDKに付属の例を探してみます。

/opt/libreoffice5.0/sdk/examplesフォルダを「XMain」で検索してみると/opt/libreoffice5.0/sdk/examples/cpp/remoteclient/remoteclient.cxxが引っかかってきました。

これはC++ examplesのRemote clientのソースです。
mkdir -p /home/pq/libreoffice5.0_sdk/LINUXexample.out/slo/remoteclientsample
gcc -c -fpic -fvisibility=hidden -O -I. -I/home/pq/libreoffice5.0_sdk/LINUXexample.out/inc -I/home/pq/libreoffice5.0_sdk/LINUXexample.out/inc/examples -I../../../include -I/home/pq/libreoffice5.0_sdk/LINUXexample.out/inc/remoteclientsample -DUNX -DGCC -DLINUX -DCPPU_ENV=gcc3 -DHAVE_GCC_VISIBILITY_FEATURE -o/home/pq/libreoffice5.0_sdk/LINUXexample.out/slo/remoteclientsample/remoteclient.o remoteclient.cxx
mkdir -p /home/pq/libreoffice5.0_sdk/LINUXexample.out/lib
g++ -shared -Wl,-z,origin '-Wl,-rpath,$ORIGIN' -L"/home/pq/libreoffice5.0_sdk/LINUXexample.out/lib" -L"/opt/libreoffice5.0/sdk/lib" -L"/opt/libreoffice5.0/sdk/../program" -o /home/pq/libreoffice5.0_sdk/LINUXexample.out/lib/remoteclientsample.uno.so /home/pq/libreoffice5.0_sdk/LINUXexample.out/slo/remoteclientsample/remoteclient.o \
 -luno_cppuhelpergcc3 -luno_cppu -luno_sal 
--------------------------------------------------------------------------------
The remoteclient C++ component can be used by using the uno binary. Use the
the follwong command to start the example. The run target starts a remote
server and connect with the client to this server.
-
make remoteclient.run
-
NOTE: The example uses the "uno" tool to prepare a working UNO environment.
      The example component is made available via -env:URE_MORE_SERVICES=...
      Please check the generated "/home/pq/libreoffice5.0_sdk/LINUXexample.out/lib/remoteclientsample.rdb " to see how you can specify your own components in such an environment
      and how to use the passive UNO registration.
--------------------------------------------------------------------------------
linuxBean14.04(83)LibreOfiice5.0.2のインストールで一括Makeしたログをみてみるとこのようになっていたのでとりあえず実行してみることにしました。

C++ examplesにはまずポート番号2083のソケット通信できるようにLibreOfficeを起動しておく必要がある、と書いてあるのですが、この例は起動していると逆にうまくうごきませんでした。

linuxBean14.04(83)LibreOfiice5.0.2のインストールで作成したsetsdkenvランチャでTerminalを起動します。

cd /opt/libreoffice5.0/sdk/examples/cpp/remoteclient
make remoteclient.run

これでRemote clientの例が動きます。
pq@HP6730b1:/opt/libreoffice5.0/sdk/examples/DevelopersGuide$ cd /opt/libreoffice5.0/sdk/examples/cpp/remoteclient
pq@HP6730b1:/opt/libreoffice5.0/sdk/examples/cpp/remoteclient$ make remoteclient.run
Start the remote server process ...
-
uno -env:URE_MORE_SERVICES=file:///home/pq/libreoffice5.0_sdk/LINUXexample.out/lib/remoteclientsample.rdb  --singleaccept -s com.sun.star.io.Pipe \
 -u "uno:socket,host=localhost,port=2083;urp;MyPipe" &
waiting on the server process ...
sleep 5

> accepting socket,host=localhost,port=2083...-
... remote server process runs ...
-
Start remote client process ...
-
uno -env:URE_MORE_SERVICES=file:///home/pq/libreoffice5.0_sdk/LINUXexample.out/lib/remoteclientsample.rdb  -s com.sun.star.bridge.example.RemoteClientSample \
  -- "uno:socket,host=localhost,port=2083;urp;MyPipe"
Connecting ....
connection established.got the remote initial object
got inputstream and outputstream from remote process
pipe test worked perfect
-
ちゃんと動いているようです。
uno -env:URE_MORE_SERVICES=file:///home/pq/libreoffice5.0_sdk/LINUXexample.out/lib/remoteclientsample.rdb  --singleaccept -s com.sun.star.io.Pipe -u "uno:socket,host=localhost,port=2083;urp;MyPipe"
まずこれでcom.sun.star.io.Pipeサービスを提供できるようにサーバー起動しています。
uno -env:URE_MORE_SERVICES=file:///home/pq/libreoffice5.0_sdk/LINUXexample.out/lib/remoteclientsample.rdb  -s com.sun.star.bridge.example.RemoteClientSample -- "uno:socket,host=localhost,port=2083;urp;MyPipe"
次に同じrdbファイルと同じソケットを指定してcom.sun.star.bridge.example.RemoteClientSampleサービスを起動してサーバーと接続しています。

remoteclientsample.rdbはMakefileの中で作られたxmlファイルなのでエディタで中身をみることができます。
<?xml version="1.0" encoding="UTF-8"?>
<components xmlns="http://openoffice.org/2010/uno-components">
  <component loader="com.sun.star.loader.SharedLibrary" uri="remoteclientsample.uno.so">
    <implementation name="com.sun.star.comp.product.example.RemoteClientSample">
      <service name="com.sun.star.bridge.example.RemoteClientSample"/>
    </implementation>
  </component>
</components>
3行目のuriででてくるremoteclientsample.uno.soが、remoteclient.cxxをコンパイルしたものです。

このファイルの内容はよくみたらLibreOffice(67)Writing UNO componentsのThumbs Exampleその3ででてきた.componentsファイルそのものですね。

実装名com.sun.star.comp.product.example.RemoteClientSampleとサービス名com.sun.star.bridge.example.RemoteClientSampleもIDLファイルの定義なしにremoteclient.cxxで定義されたクライアント側のもののようです。

com.sun.star.lang.XMainインターフェイスを実装するJavaの例


Standalone Use Case - Apache OpenOffice WikiにJavaの例がありますがSDKの例には入っていませんでした。

とりあえずStandalone Use Caseの例をコンパイルしてみます。

Eclipseを起動。

File→New→Java Project。

Project nameをTheUNOExecutbleにしてあとはデフォルトのままFinish。

Package ExplorerのTheUNOExecutableプロジェクト内のsrcを右クリックしてNew→Class。

NameにUnoExeMainと入力してFinish。

UnoExeMain.javaファイルにStandalone Use Caseの例をコピペしました。

エラーがでていますが、これはTheUNOExecutbleプロジェクトを右クリック→Build Path→Add External Archivesから/opt/libreoffice5.0/program/classes/juh.jarを選択したところその他のjarファイルも追加されてエラーが消えました。

linuxBean14.04(51)Eclipse4.5のインストールと静的コールグラフ生成のときと同様にして5つのjarファイルを追加しようと思っていのが自動的に必要なjarファイルが追加されたので驚きました。(こんな機能ありましたっけ?)


とりあえずEclipseのメニューからRun→RunとすしてJava Applicationとして実行を選択するとConsoleに数字がたくさん出力されました、、、意味がわかりません。

これ以上Eclipseでの操作方法がわからないのでEclipseを終了してファイルマネージャでUnoExeMain.javaがある~/workspace/TheUNOExecutable/srcフォルダを開きます。

jarファイルに含めるmanifestファイルを作成します。
RegistrationClassName: UnoExeMain
Leafpadにこれを入力しManifestというファイル名で保存しました。
(ChromeからこれをコピペしたManifestファイルはjarのマニフェストファイルになぜか反映されませんでした。それに気づかずちょっと時間を食いました。)

ファイルマネージャのメニューのツール→現在のフォルダで端末を開く。

Standalone Use Caseに書いてあるとおりjavac UnoExeMainとすると「エラー: クラス名'UnoExeMain'が受け入れられるのは、注釈処理が明示的にリクエストされた場合のみです」といわれます。

ちょっと調べてjavac UnoExeMain.javaでやり直すとパッケージ不足のエラーが多発します。

そうですよね~。こんなのうまくいくわけないと思っていたのですよ。

ということでLibreOffice(67)Writing UNO componentsのThumbs Exampleその3を参考にやり直します、、、と思ったらライブラリのパスが4.3とは異なっていることに気がついたのでlinuxBean14.04(83)LibreOfiice5.0.2のインストールで一括MakeしたログのDevelopersGuide_Components_Thumbs.logからjavacの部分を抜き出して改変しました、、、これもclasspathがなぜか二重になっていて全くの正解ではないですね。
2015.12.4追記。二重になっているのは/opt/libreoffice5.0/sdkに加えて/opt/libreofficedev5.0/sdkのパスも入っているからでした。原因はあちこちのパスの設定が/opt/libreofficedev5.0になっているのが原因なのですが、とりあえず見つけ次第直しているような状態です。~/libreoffice5.0_sdk/LINUXexample.outフォルダを削除してmake_all.shをやり直すと直りました。)

LibreOffice(22)FirstStepsのMakefileで使うJDKのコマンドも参考にしました。
"/usr/bin/javac"  -classpath "/opt/libreoffice5.0/program/classes/juh.jar:/opt/libreoffice5.0/program/classes/jurt.jar:/opt/libreoffice5.0/program/classes/ridl.jar:/opt/libreoffice5.0/program/classes/unoloader.jar:/opt/libreoffice5.0/program/classes/unoil.jar"  UnoExeMain.java
これでUnoExeMain.classができました。
"/usr/bin/jar" cvfm UnoExeMain.jar Manifest UnoExeMain.class
これでUnoExeMain.jarで完成しました。

LibreOfficeを起動してツール→拡張機能マネージャー。

「追加」。「UNO Java Component」を選択してUnoExeMain.jarを登録しました。


結局このあとあれこれ頑張ってみましたが動かすことはできませんでした。

とりあえず作ったUnoExeMain.rdbファイル。
<?xml version="1.0" encoding="UTF-8"?>
<components xmlns="http://openoffice.org/2010/uno-components">
  <component loader="com.sun.star.loader.Java2" uri="UnoExeMain.jar">
    <implementation name="UnoExeMain">
      <service name="MyMain"/>
    </implementation>
  </component>
</components>
作り直したmanifestファイル。
UNO-Type-Path: UnoExeMain.jar
RegistrationClassName: UnoExeMain
/opt/libreoffice5.0/program/uno -env:URE_MORE_SERVICES=UnoExeMain.rdb -s MyMain

UnoExeMain.jarとUnoExeMain.rdbを置いたフォルダでこのコマンドを実行してみました。
pq@HP6730b1:~/.config/libreoffice/4/user/Scripts/java$ /opt/libreoffice5.0/program/uno -env:URE_MORE_SERVICES=file:///home/pq/.config/libreoffice/4/user/Scripts/java/UnoExeMain.rdb -s MyMain
> error: [jni_uno bridge error] UNO calling Java method activate: non-UNO exception occurred: java.lang.NoClassDefFoundError: com/sun/star/lang/XMain
java stack trace:
java.lang.NoClassDefFoundError: com/sun/star/lang/XMain
 at java.lang.ClassLoader.defineClass1(Native Method)
 at java.lang.ClassLoader.defineClass(ClassLoader.java:800)
 at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
 at java.net.URLClassLoader.defineClass(URLClassLoader.java:449)
 at java.net.URLClassLoader.access$100(URLClassLoader.java:71)
 at java.net.URLClassLoader$1.run(URLClassLoader.java:361)
 at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
 at java.security.AccessController.doPrivileged(Native Method)
 at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
 at java.lang.ClassLoader.loadClass(ClassLoader.java:425)
 at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
 at java.lang.ClassLoader.loadClass(ClassLoader.java:412)
 at java.lang.ClassLoader.loadClass(ClassLoader.java:412)
 at java.lang.ClassLoader.loadClass(ClassLoader.java:412)
 at java.net.FactoryURLClassLoader.loadClass(URLClassLoader.java:793)
 at java.lang.ClassLoader.loadClass(ClassLoader.java:358)
 at com.sun.star.comp.loader.RegistrationClassFinder.find(RegistrationClassFinder.java:52)
 at com.sun.star.comp.loader.JavaLoader.activate(JavaLoader.java:269)
Caused by: java.lang.ClassNotFoundException: com.sun.star.lang.XMain
 at java.net.URLClassLoader$1.run(URLClassLoader.java:366)
 at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
 at java.security.AccessController.doPrivileged(Native Method)
 at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
 at java.lang.ClassLoader.loadClass(ClassLoader.java:425)
 at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
 at java.lang.ClassLoader.loadClass(ClassLoader.java:358)
 ... 18 more

> dying...
これはもうお手上げです。

参考にしたサイト


Python-UNO bridge
swritercomp.py, swritercompclient.py の例を実行してみました。

LibreOffice: Main Page
LibreOffice APIリファレンス。

Apache OpenOffice Developer's Guide - Apache OpenOffice Wiki
LibreOfficeのデベロッパーガイドでもあります。

LibreOffice 5.0 SDK - Development Tools
LibreOffice5.0の開発ツールの解説。

LibreOffice 4.5 SDK - Examples
LibreOffice SDK付属の例一覧。

次の関連記事:LibreOffice5(8)oxtファイルをzip圧縮するときは最初の階層に注意

ブログ検索 by Blogger

Translate

最近のコメント

Created by Calendar Gadget

QooQ