LibreOffice5(36)UNOコンポーネントのJavaの例:TestJavaComponent

UNOコポーネントのサービス名と実装サービス名の命名規則がよく理解できません。Component ArchitectureとかPossible Structures for Java Componentsが関係ありそうなので、Javaの例のTestJavaComponentをやることにしました。

前の関連記事:LibreOffice5(35)unoinsp.py:PyDevパッケージで管理する


TestJavaComponentをNetBeans8.0.2のデバッガにかける


SDKの例はlinuxBean14.04(132)LibreOfiice5.2のSDKの例をコンパイルするですべてコンパイル済です。

NetBeansはlinuxBean14.04(25)NetBeans8とLibreOffice5のインストールの8.0.2JavaSEを使います。

Product Version: NetBeans IDE 8.0.2 (Build 201411181905)
Java: 1.7.0_121; OpenJDK Client VM 24.121-b00

NetBean8.0.2はOpenJDK7で動かしています。

LibreOffice(24)NetBeans7でJavaのマクロを作成と同様にしてまず TestJavaComponentのNetBeansプロジェクトを作成します。

NetBeans8.0.2でファイル→新規プロジェクト。

Java→既存のソースを使用するJavaプロジェクト。

プロジェクト名はTestJavaComponentにしました。

 /opt/libreoffice5.2/sdk/examples/DevelopersGuide/Components/JavaComponent

ソースパッケージフォルダはこれを選択しました。

今回はマクロではないのでマイマクロフォルダには移動させていません。


 プロジェクトに含めるファイルは**javaでjavaファイルだけを選択しました。

 プロジェクトのプロパティから/opt/libreoffice5.2/program/classesにあるunoil.jar、ridl.jar、juh.jar、jurt.jarの4つのjarファイルを追加しました。

LibreOffice5.2からJREを起動する


LibreOffice(25)JavaのマクロをNetBeans7でデバッグすると同様にします。

LibreOfficeでツール→オプション。

詳細。

NetBeans8.0.2はOpenJDK7で動いているので、LibreOfficeのJava実行環境もバージョン1.7.0を選択してパラメーターを設定しておきます。

Writerを起動してツール→マクロ→マクロを実行。

LibreOfficeのマクロ→Hello World→org.libreoffice.example.java_scripts.HelloWorld.printHW、を選択して実行ボタンをクリックします。

WriterのドキュメントにHello World(in Java)と表示されたら、JREの起動は成功です。

NetBeansからデバッガをアタッチする


デバッグ→デバッガのアタッチ。

ホストlocalhost、ポート8000でOK。

出力:デバッガ・コンソールにlocalhost: 8000にアタッチしています、とでたらアタッチ成功です。

TestJavaComponentにブレークポイントを設定する


ざっくりソースを読んだ感じでTestJavaComponent.javaのmain関数の最初のコマンド行である74行目にブレークポイントを設定しました。

LibreOfficeからツール→拡張機能マネージャー。

追加ボタンをクリックしてJavaComponent.oxtを選択します。

~/libreoffice5.0_sdk/LINUXexample.outにあるはずです。

うーん、このブレークポイントはハズレですね。

拡張機能マネージャーに登録されるタイミングでブレークしたかったのですが、このブレークポイントはインスタンス化してから実行されるところのようです。

うーん、Pythonのunohelper.ImplementationHelper()に該当するところがどこかわからないですね。

とりあえずTestJavaComponent.javaのコメントに書いてある通りにcom.sun.star.test.SomethingBをインスタンス化してみます。

うーん、unoinsp.pyにかけてみるとTestComponentA.javaもTestComponentB.javaもgetSupportedServiceNames()メソッドの配列Stringの長さが0になっている、とエラーがでてきますね。

String[0]を[1]にしてコンパイルし直しました。

これでgetSupportedServiceNames()メソッドのエラーがでなくなりました。

とりあえずここまでやって理解したことはUNOコンポーネントとはoxtファイルの中に入れたuno.jarファイルを指すということです。

Component Architectureの図にある通りです。

LibreOffice(67)Writing UNO componentsのThumbs Exampleその3ですでに詳しく学習していましたね。

JavaComponent.oxtに含まれているJavaComponent.uno.jarは、Possible Structures for Java ComponentsのMultiple Implementations per Component Fileに該当します。

言語ローダーによって実装が変わる


oxtファイルの実装ファイルをみるとJavaではuno.jarファイル、C++ではuno.soファイル(Linux_x86)になっていてそれがUNOコンポーネントになっています。

Pythonではコンパイルされないのでpyファイルのままです。

UNOコンポーネントになっているファイルはuno.pyと命名したほうがよさそうですが、いくつかみたPytyonで作成された拡張機能をみてもそうなっているものはありませんでした。

Pythonモジュールは一つのファイルですが、Pythonパッケージは複数ファイルからなっていますし、ファイル名でインポートするときにuno.pyとつけるのはいまいちですね。

命名規則([Python] コーディング規約(PEP8)を学んで、Pythonらしいコードを書く - YoheiM .NET)に照らしてもuno.pyとつけるのはよくなさそうです。

TestCppComponent.cxxのC++の例では、Javaの例のTestServiceProvider.javaのようにサービスファクトリーを振り分けるコードが入っていません。

JavaComponent.oxtをインストールするとcom.sun.star.test.SomethingAやcom.sun.star.test.SomethingBといったサービス名やその実装名でPythonでもインスタンス化できます。

しかしC++の例のCppComponent.oxtをインストールしてもそのIDLで定義してあるmy_module.MyService1や実装名のmy_module.my_sc_implementation.MyService1でJupyter Notebookからインスタンス化しようとするとJupyter Notebookのカーネルがクラッシュしてインスタンス化できませんでした。

TestCppComponent.cxxのコードからは実行できたので、IDLの定義がおかしいわけでもないようです。

原因はよくわかりませんでした。

まあでもJavaの例をPythonに翻訳するにあたりそのまま変換する必要がないことがわかりました。

com.sun.star.task.Jobをサービス名にするUNOコンポーネント


UniversoLibreMexicoAC/easydev: Tool for easy develop macros in LibreOffice... with PythonCalendar for Calc — LibreOffice Extensions and Templates WebsiteOOoPython/Job - ...?といった拡張機能はUNOコンポーネントのサービス名をcom.sun.star.task.Jobにしています。

XJobインターフェイスの execute()メソッドを使うためです。

easydevCalendar for CalcはIDLでサービスやインターフェイスを追加しています。

実装サービス名でインスタンス化したときはこれらは区別されるので問題ないですが、サービス名のcom.sun.star.task.Jobでインスタンス化するとこれらはどう区別されるのか不思議です。

インスペクタで確認するとcom.sun.star.task.JobのインスタンスのIDLは拡張機能マネージャーの順番が後ろのものが出力されました。

拡張機能マネージャーはアルファベット順になっているので、easydevCalendar for Calcの両方がインストールされているの時はpycalendarという名前で登録されているCalendar for CalcのIDLの結果が表示されます。

このときcom.sun.star.task.Jobではインスタンス化されないeasydevも実装サービス名でインスタンス化できました。

そもそもeasydevではサービス名以外でcom.sun.star.task以下のモジュールを使っていないのでcom.sun.star.task.Jobをサービス名にする必要性がないと思います。

pycalendarはXJobExecutorを継承しています。

OOoPython/UNOComponent - ...?の例ではサービス名に関係なくXJobExecutorの trigger()メソッドを使っているのでpycalenderもまたサービス名をcom.sun.star.task.Jobにする必要性はないと思います。

ああ、pycalendarではIDLでサービスを定義していないので適当なサービス名がないからcom.sun.star.task.Jobにしている?、、、そんなことはなくサービス名はIDLを定義していなくても実装名と同じでよいはずです。

OOoPython/Job - ...?もまたcom.sun.star.task.Jobにする必要性はないようにみえますが、これはIDLを定義しているわけではないので、インスペクタでみてもcom.sun.star.task.Jobのインスタンスの属性の変化はありません。

結局サービス名も実装サービス名もLibreOffice固有のサービス名を上書きしないように命名しようと思います。

(2017.4.5追記。同名の実装サービス名をもつ拡張機能を追加しようとするとエラーがでてきて追加できません。


実装サービス名が異なるがサービス名が同じ拡張機能は登録できます。

その場合そのサービス名でインスタンス化すると後から追加された実装がインスタンス化されました。

実装サービス名の付け方のルールについてはXServiceInfo - Apache OpenOffice Wikiに解説がありました。)

参考にしたサイト


Component Architecture - Apache OpenOffice Wiki
UNO ComponentとはJavaではuno.jarファイル、Pythonではpyファイルを指すようです。

Possible Structures for Java Components - Apache OpenOffice Wiki
Javaの一つのコンポーネントに2つのサービスを含ませる例。

LibreOffice 5.3 SDK - Developer's Guide Examples
Writing UNO components examplesのTestJavaComponentの例をやりました。

[Python] コーディング規約(PEP8)を学んで、Pythonらしいコードを書く - YoheiM .NET
Pythonの命名規則の解説。

UniversoLibreMexicoAC/easydev: Tool for easy develop macros in LibreOffice... with Python
Pythonの拡張機能の例。IDLではold-style serviceを定義しています。

Calendar for Calc — LibreOffice Extensions and Templates 
Pythonの拡張機能の例。IDLではインターフェイスのみを定義しています。

OOoPython/Job - ...?
IDLを定義せずcom.sun.star.task.XJobのPython実装例。

OOoPython/UNOComponent - ...?
IDLを定義せずcom.sun.star.task.XJobExecutorのPython実装例。

次の関連記事:LibreOffice5(37)bootstrap()で起動したLibreOfficeをエラーなく終了させる

PR

0 件のコメント:

コメントを投稿