2018年11月25日日曜日

10: 'やあ、GUI Java UNOクライアントたち'サンプル

<このシリーズの前の記事 | このシリーズの目次 | このシリーズの次の記事>

あなたのプログラムをLibreOffice/OpenOfficeインスタンス(または任意のUNOサーバー)に接続し、切断を検知する。

話題


About: UNO (Universal Network Objects)
About: LibreOffice
About: Apache OpenOffice
About: Javaプログラミング言語

この記事の目次


開始コンテキスト



ターゲットコンテキスト



  • 読者は、GUI JavaプログラムをLibreOfficeまたはApache OpenOfficeのインスタンスに接続し、切断を(もしあれば)検知する方法を知る。
ト書き
Hypothesizer 7、Objector 10A、Objector 10Bがコンピューターの前にいる。


オリエンテーション


Hypothesizer 7
この記事では、GUI Java UNOクライアントサンプルを取得、ビルド、実行、理解します。

実は、コンソールJava UNOクライアントサンプルについての過去の記事があり、その過去記事が説明したことはこの記事は省略します

Objector 10A
その過去記事は何を説明したのだ?

Hypothesizer 7
サー、JavaプログラムをLibreOfficeまたはApache OpenOfficeのインスタンスに接続する方法を説明いたしました。

Objector 10A
プログラムをLibreOfficeやApache OpenOfficeのインスタンスに接続することになど興味はなく、プログラムにオフィスドキュメントファイルを読み書きさせたいのだ。

Hypothesizer 7
実のところ、あなたが興味をお持ちか否かにかかわらず、プログラムをLibreOfficeまたはApache OpenOfficeのインスタンスに接続しなければなりません、ある過去の記事で説明されているとおり。

Objector 10A
...それでは、私がプログラムをLibreOfficeかApache OpenOfficeのインスタンスに接続するよう、君は要求するのかね?

Hypothesizer 7
私が個人的に要求しているのではなく、UNOが要求しているのです。

Objector 10A
どちらにしろ、UNOクライアントがGUIプログラムであることが、コンソールプログラムであることと、UNO上どう違うのか、私には理解できない。GUIプログラムであるかコンソールプログラムであるかは、単にJavaプログラミングの問題だと思うが。

Hypothesizer 7
GUIプログラムは比較的長い間動作し続けるよう意図されているので、その中のUNOコネクションは途中で切断されるかもしれません。

Objector 10A
コンソールプログラムの中のUNOコネクションだって途中で切断されるかもしれない...

Hypothesizer 7
確かに。しかし、コンソールプログラムへのパラメータ群はコマンド引数として渡されるため、そのコンソールプログラムがUNO切断のために途中終了したら、そのコマンドを再度実行すればよいだけです。他方で、GUIプログラムへあなたが苦労して行なったインプットは、そのGUIプログラムが途中終了すれば失われるでしょう。

Objector 10A
君が持っている'コンソールプログラム'の観念には偏りがあるようだな。インプットをインタラクティブに受けるコンソールプログラムだってある。

Hypothesizer 7
ああ、仰っしゃるとおりです。しかしながら、この記事の話題はUNO切断をイベントとして検知することでして、UNOクライアントは、そのイベントを受け取ることができる必要があります。厳密に言えば、問題は、プログラムがGUIプログラムか否かではなくて、プログラムがイベントドリブンか否かです。

Objector 10A
UNO切断をイベントとして検知する必要性が理解できないな。UNO切断は、次のUNO操作を試みた時にどのみち検出されるだろう。

Hypothesizer 7
問題は、切断の後、インプットが失われることなく、ユーザーが操作を続けられるかどうかです。

Objector 10A
なぜ続けられないんだ?プログラムは新たなコネクションを確立すればよいだけであって、ユーザーは操作を続けられるだろう?

Hypothesizer 7
状態は必ずしもそんなに簡単に再構成できないでしょう?

Objector 10A
「状態」とはどういう意味だ?

Hypothesizer 7
例えば、切断は、あなたのプログラムがLibreOfficeまたはApache OpenOfficeのインスタンス内に、あるドキュメントをオープンして、そのドキュメントへのUNOプロキシを取得した後に、そのインスタンスの途中終了によって引き起こされたかもしれず、ユーザーが操作を続けられるようにするには、あなたのプログラムは、その状態を再構成しなければなりません。

Objector 10A
ふーむ、それでは、切断がイベントとして検知されようがされまいが、インプットはどのみち失われるだろう。

Hypothesizer 7
'オール・オア・ナッシング'ではないのです。検知がより早ければ、害がより少なくなります。ユーザーは、切断の通知を即座に受けなければ、無駄になる運命のインプットを長い間続けることになるかもしれません。

Objector 10A
うーん...

Objector 10B
あなたの'開始コンテキスト'は一体全体何なの?

Hypothesizer 7
マダム、'開始コンテキスト'は、この記事を理解するための前提条件です。どの技術ドキュメントにもあります、明示的に述べられているか否かにかかわらず(そして、実際上可能な限りより明示的に述べられるべきだと私は強く信じます)。

Objector 10B
多過ぎると言ってるのよ!

Hypothesizer 7
「多過ぎる」と仰っしゃられましても、必要なものは必要なわけでして、私は正直に明らかにしただけです...

Objector 10B
そんな要求を読者にする人はいないわよ、あなたを除いてはね!

Hypothesizer 7
...申し上げたとおり、どの技術ドキュメントにも前提知識があり(新生児向けでない限り)、もしも、ある著者がその前提知識を明かさなかったとしたら、その方は、怠慢であったか、不正直であったということになるでしょう。


本体


1: GUI Java UNOクライアントサンプルを取得してビルドする


Hypothesizer 7
ここに、GUI Java UNOクライアントサンプルがあります。

'hiGuiJavaUnoClients'がサンプルプログラムのプロジェクトディレクトリです。他2つのディレクトリは様々なプロジェクトから共通に使われるプロジェクトのものであり、それらプロジェクトは、サンプルプロジェクトをビルドする際に自動的にビルドされます。

サンプルプロジェクトをビルドする方法はある過去の記事に記載されており、開発環境を構築する方法は、2つの過去記事(Linux用はこちらで Windows用はこちら)に記載されています。

ト書き
Hypothesizer 7は、ターミナルをオープンし、サンプルプロジェクトをビルドする。


2: サンプルプログラムを実行する


Hypothesizer 7
サンプルプログラムを実行する前に、LibreOfficeまたはApache OpenOfficeのインスタンスを、クライアントからのコネクションを受け付ける状態で開始しておかなければなりません(その方法は、過去の記事で知ることができます)。

ト書き
Hypothesizer 7は、LibreOfficeのインスタンスをポート番号'2002'で開始する。

Hypothesizer 7
サンプルプログラムは、カレントディレクトリをサンプルプロジェクトディレクトリに位置させ、以下のようにして実行できます。

@bash or cmd ソースコード
gradle i_executeJarTask -Pc_mainClassName="theBiasPlanet.hiGuiJavaUnoClients.programs.HiGuiJavaUnoClients" -Pc_commandLineArguments="execution/Properties.xml"

Objector 10A
そこに指定されているXMLファイルは何だ?

Hypothesizer 7
それは、設定ファイルで、サンプルプログラムはそこからいくつかのデフォルト値と、JavaFXのスタイルシートのパスを取得します。

ト書き
Hypothesizer 7は、カレントディレクトリをサンプルプロジェクトディレクトリに位置させて、上記コマンドをターミナルで実行する。

Objector 10A
何だそれは?

Hypothesizer 7
それは、そこのURLで指定されたUNOサーバーに接続でき、そのUNOサーバーにそこのパスで指定されたファイルをオープンさせられ、そのUNOサーバーから切断でき、UNO切断があれば検知するJavaFXプログラムです。

Objector 10A
「UNO切断があれば検知」して、それでどうする?密かに検知されても、本当に検知していると信じることはできない。

Hypothesizer 7
プログラム上で目に見えるステータスを変更します。接続中は、'Connect'/'Disconnect'/'Open'ボタンが無効/有効/有効に、非接続中は、それらが有効/無効/無効になります。

Objector 10A
それでは、接続されているLibreOfficeインスタンスをシャットダウンすると、...

Hypothesizer 7
サンプルプログラムはすぐにステータスを変更するはずです、このように。

ト書き
Hypothesizer 7は、サンプルプログラムをLibreOfficeインスタンスに接続し、その後、LibreOfficeウィンドウをクローズする、が、サンプルプログラムはステータスを変更しない。

Objector 10A
何も検知しないじゃないか!

Hypothesizer 7
...えーと、LibreOfficeインスタンスは、ウィンドウをクローズされただけでは終了しなかったようです。

ト書き
Hypothesizer 7は、LibreOfficeプロセスをkillし、サンプルプログラムはステータスを変更する。

Objector 10A
ああ。


3: サンプルプログラムを理解する



3-1: プロジェクト群構造を理解する


Hypothesizer 7
3つのプロジェクト、'coreUtilitiesToBeDisclosed'、'unoUtilitiesToBeDisclosed'、'hiGuiJavaUnoClients'があります。'coreUtilitiesToBeDisclosed'には、あらゆる種類のプロジェクトで共用されるように想定されているユーティリティコードが含まれています。'unoUtilitiesToBeDisclosed'には、UNOプログラムのプロジェクト群で共用されるように想定されているユーティリティコードが含まれています。'hiGuiJavaUnoClientsがサンプルプロジェクトです。


3-2: UNO切断イベントに対するリスナーを登録する


Hypothesizer 7
'オリエンテーション'で申し上げたとおり、コンソールJava UNOクライアントサンプルを扱った前記事で説明されていることを私は繰り返しません。この記事で説明されるのは、切断イベントに対するリスナーを登録する方法です。

UNO切断イベントリスナークラスは、'com.sun.star.lang.XEventListener'インターフェースの実装として作成し、'disposing'メソッドを実装します。

'disposing'メソッドは、1つの引数を持ち、'com.sun.star.lang.EventObject'型のイベントオブジェクトを受け取ります。

Objector 10A
そのイベントオブジェクトからは具体的に何を得られるのか?

Hypothesizer 7
'Source'という名前のメンバー変数があり、これは、UNOブリッジを格納しています。

Objector 10A
ふーむ、それは、そのリスナーが複数のコネクションに登録されているケースのためらしいな。

Hypothesizer 7
そうだろうと思います。

Objector 10A
他にどんなメンバーがある?

Hypothesizer 7
実のところ、他にはありません。

Objector 10A
はあ?...そういうイベントは普通、切断の原因をもってるだろうが?

Hypothesizer 7
普通持っているということには同意ですが、これはなぜか持っていません。

Objector 10A
...

Hypothesizer 7
とにかく、そのリスナークラスのインスタンスが、UNOブリッジUNOオブジェクトに、UNOブリッジUNOコンポーネントに実装されている'com.sun.star.lang.XComponent' UNOインターフェースの'addEventListener'メソッドによって登録されます。

Objector 10B
それで、サンプルでは、どれがリスナークラスで、そのインスタンスはどこで登録されているの?

Hypothesizer 7
実は、'theBiasPlanet.unoUtilities.connectionsHandling.UnoConnection'がリスナークラスであり、これが、ブリッジを受け取るコンストラクター内で、自身のインスタンスを登録します。

Objector 10B
はあ?UNOコネクションが切断イベントを受け取るというのはよく分からないわ。普通は、何かのウィンドウが切断イベントを受け取るでしょう...

Hypothesizer 7
実際には、'theBiasPlanet.unoUtilities.connectionsHandling.UnoConnection'は、そうしたウィンドウ群へのプロキシとして、切断イベントを受け取ります。'theBiasPlanet.unoUtilities.connectionsHandling.UnoConnectionEventsListener'のインスタンス群が'theBiasPlanet.unoUtilities.connectionsHandling.UnoConnection'のインスタンスに登録され、後者インスタンスが、切断イベントを受け取った後、前者インスタンス群を呼び出します。

Objector 10B
...なんでそんなプロキシが有益なの?そんなの無益に思えるし、あなたは全く無益なトリックを自慢しているのよ...

Hypothesizer 7
...マダム、そうしている目的は、リスナー群が、UNO切断イベントだけでなくUNO接続イベントをも受け取り、イベントオブジェクトにおいてUNOブリッジでなく'theBiasPlanet.unoUtilities.connectionsHandling.UnoConnection'インスタンスを受け取るようにするということです。

Objector 10B
...UNO接続イベントを受け取ったり、 'theBiasPlanet.unoUtilities.connectionsHandling.UnoConnection' インスタンスを受け取ったりして、何がいいわけ?

Hypothesizer 7
各リスナーは、UNO操作を行なうために、UNOブリッジではなく、UNOオブジェクト群コンテキストを必要とします。

Objector 10B
それで?UNOオブジェクト群コンテキストUNOブリッジから取得できないの?

Hypothesizer 7
確かにできます、しかし、各リスナーは、UNOオブジェクト群コンテキストへの参照をUNOコネクションが確立された時に取得する必要があり、UNOブリッジから開始して、各リスナーがその参照をUNOサーバーから取得しなければなりません。その参照が既に'theBiasPlanet.unoUtilities.connectionsHandling.UnoConnection'インスタンス内に格納されており、getterメソッドで取得できるにもかかわらずです。

Objector 10A
それでは、'theBiasPlanet.hiGuiJavaUnoClients.displaysHandling.HiGuiJavaUnoClientsMainScene'がリスナーなのか、結局のところ?

Hypothesizer 7
はい、'theBiasPlanet.unoUtilities.displaysHandling.UnoConnectionBaseScene'が'theBiasPlanet.unoUtilities.connectionsHandling.UnoConnectionEventsListener'をインプリメントしており(抽象クラスなので、本当に実装しているわけではない)、それが、 'theBiasPlanet.unoUtilities.displaysHandling.UnoConnectionConnectorScene'によって継承され、さらに、'theBiasPlanet.hiGuiJavaUnoClients.displaysHandling.HiGuiJavaUnoClientsMainScene'によって継承されています。

Objector 10B
なんでそんなクラス階層が必要なのか理解できないわ(なんで'theBiasPlanet.hiGuiJavaUnoClients.displaysHandling.HiGuiJavaUnoClientsMainScene'が'theBiasPlanet.unoUtilities.connectionsHandling.UnoConnectionEventsListener'を直接実装しないわけ?)。あなたは自慢したくてそんな不必要なクラスを導入しているだけなのよ。

Hypothesizer 7
...いくつか目的があります。'theBiasPlanet.unoUtilities.displaysHandling.UnoConnectionBaseScene'は、'theBiasPlanet.unoUtilities.displaysHandling.UnoConnectionConnectorScene' (UNO クライアントのベースシーン)と 'theBiasPlanet.unoUtilities.displaysHandling.UnoConnectionAcceptorScene'(UNO サーバーのベースシーン)の共通ロジックを格納するためのものであり、'theBiasPlanet.unoUtilities.displaysHandling.UnoConnectionConnectorScene'は、様々なUNOクライアントシーン('theBiasPlanet.hiGuiJavaUnoClients.displaysHandling.HiGuiJavaUnoClientsMainScene'はその1つです)の共通ロジックを格納するためのものです。

Objector 10B
あなたは自慢したいだけ!自慢したいだけ!自慢したいだけ!

Hypothesizer 7
...インターフェース、'theBiasPlanet.unoUtilities.connectionsHandling.UnoConnectionEventsListener'には2つのメソッド、'connected'、'disconnected'があり、それらを各リスナーは実装するように想定されています(そのインターフェースは'theBiasPlanet.unoUtilities.displaysHandling.UnoConnectionConnectorScene'が既に実装済みなので、厳密に言えば、'theBiasPlanet.unoUtilities.displaysHandling.UnoConnectionConnectorScene'の子孫はそれを実装する必要がありませんが、子孫はたいてい、それらのメソッド内で追加でやることがあるでしょう)。


4: 結びとその先


Hypothesizer 7
これで、UNO切断に対してGUI Java UNOクライアントに適切にアクションを起こさせることができるようになりました。

あなたはJavaプログラマーではありませんか?将来の記事群にて、私たちはいくつかの他のプログラミング言語(C++およびC#)でいくつかUNOクライアントを作成します。

また、将来の記事群にて、私たちはいくつかUNOサーバーも作成します。


参考資料


<このシリーズの前の記事 | このシリーズの目次 | このシリーズの次の記事>