2017年5月20日土曜日

14: サンプルUNO拡張機能(LibreOffice拡張機能またはApache OpenOffice拡張機能)を理解する、パート1

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

Main body START

サンプルUNO拡張機能をよく理解する必要がある

-Hypothesizer

UNOの基本概念を学んだので、我々は、我々のサンプルUNO拡張機能の詳細を理解できるになった。サンプルUNO拡張機能をよく理解しておかないと、将来のUNOの拡張機能を開発する目的にサンプルを使えないだろう。

-Rebutter

それはそうだろう。

-Hypothesizer

作成過程を追体験することで、サンプルUNO拡張機能を理解することにしよう。

-Rebutter

分かった。

プロジェクトを作成する

-Hypothesizer

プロジェクトを作ろう。

共通Gradleビルドスクリプト群または共通Antビルドファイル群が格納されたディレクトリの下に、ディレクトリ、'hiUnoExtensionsUnoExtension'を作る。これが、プロジェクトのルートディレクトリだ。ディレクトリ名は任意だ。

-Rebutter

長い名前だな . . .

-Hypothesizer

ああ、この機会に言っておくが、私は、長い名前を使うことにほとんどためらいがない。それは、長い名前が好きだからではなく、省略があまり好きでないからだ。何かに名付けるときは省略は便利に思えるが、少し時間がたってだいぶそれについて忘れた後に見ると、わかりにくいことになりかねない。例えば、先ほどのものを'hiExtExt'と名付けたとして、'Ext'は何を意味するのだろうか?Extended?Exterior?External?Extinct?Extra?Extract?Extreme?Extinguisher?仮に'Extension'として正しく理解したとして、一体何の拡張機能なのか?Firefoxの拡張機能か?Eclipseの拡張機能か?Javaの拡張機能か?. . . もし誰かが、省略をそれぞれ、しばらく時間がたった後でも思い出せる優れた記憶力を持っているならば、省略すればよい。残念なことに、私の記憶力はお粗末なものであり、そのため、可能な限り、省略を避けなければならなくなっている。だから、私が付ける長い名前を気にする必要はない。短い名前が好きな人は自分で短くすればよい。

-Rebutter

いいだろう。

-Hypothesizer

次に、このプロジェクトのGradleビルドスクリプトまたはAntビルドファイルを作る。

Gradleビルドスクリプトの方は、以下のように書く。

// # Change the target name
ext.TARGET_NAME = "thebiasplanet.hiunoextensionsunoextension.uno"

apply ("from": "../commonBuild01.gradle")

// # Change the default task
defaultTasks ("registerUnoExtension")
ext ({
 // Add this if necessary
 //CHECKSTYLE = "ON"
 // Add this if necessary
 //JAR_DEPLOY_DIRECTORY_NAME = "?"
 // Add this if necessary
 //WAR_DEPLOY_DIRECTORY_NAME = "?"
 // # Change this if necessary
 INCLUDED_JAR_FILE_NAMES = ["../unoUtilitiesToDisclose/target/thebiasplanet.unoutilities.jar"]
 // # Change this if necessary
 OTHER_CLASSES_PATHS = [JAVA_FILES_BASE_DIRECTORY_NAME, CLASSES_BASE_DIRECTORY_NAME, LIBREOFFICE_CLASSES_BASE_DIRECTORY_NAME + "/unoil.jar", LIBREOFFICE_CLASSES_BASE_DIRECTORY_NAME + "/jurt.jar", LIBREOFFICE_CLASSES_BASE_DIRECTORY_NAME + "/ridl.jar", LIBREOFFICE_CLASSES_BASE_DIRECTORY_NAME + "/juh.jar"]
 REFERENCED_PROJECT_DIRECTORY_NAMES = ["../unoUtilitiesToDisclose"]
})

apply ("from": "../commonBuild02.gradle")

ターゲット名(ここでは、'thebiasplanet.hiunoextensionsunoextension.uno')とデフォルトタスク('registerUnoExtension')を指定する。そして、'INCLUDED_JAR_FILE_NAMES'配列に、UNOユーティリティプロジェクトのJarファイル名を含めるが、これによって、このJarファイルの中身が、このサンプルUNO拡張機能プロジェクトのJarファイルに含まれるようになる。

-Rebutter

ターゲット名は何に使用されるのか?

-Hypothesizer

UNOデータタイプ「マージされた」レジストリファイルの名前、Jarファイルの名前、UNO拡張機能ファイルの名前、UNOコンポーネント設定ファイルの名前に使われる。

-Rebutter

ふーむ、これらのファイルの説明は後で行なわれるのだろうな。

'INCLUDED_JAR_FILE_NAMES'配列にUNOユーティリティプロジェクトのJarファイル名を含めるというのは、UNOユーティリティプロジェクトのJarファイルが、このサンプルUNO拡張機能プロジェクトのJarファイル内に展開されるという意味か?

-Hypothesizer

そうだ。

-Rebutter

そうすると、他のUNO拡張機能を登録する際、UNOユーティリティプロジェクトのJarファイルの中身が重複してしまうと思うが。

-Hypothesizer

そう。実際には、それで特に問題は起きないが、正直なところ、美しくはない。複数のUNO拡張機能からJarファイルが共有されるようにできるが、それには、LibreOfficeの設定が必要になる。こうした設定は、将来の記事で行なうことにする。

-Rebutter

オーケー。

-Hypothesizer

ところで、'OTHER_CLASSES_PATHS'配列に含まれる、'LIBREOFFICE_CLASSES_BASE_DIRECTORY_NAME'ディレクトリ配下のJarファイル群に注目してくれ。これらのJarファイルは、UNOのライブラリだ。これらは、我々のJavaソースをコンパイルするのに必要だが、我々のJarファイルには含まれない。というのは、これらはデフォルトで実行時にロードされるからだ。

-Rebutter

なるほど。

-Hypothesizer

Antビルドファイルの方は、以下のように書く。

<?xml version="1.0" encoding="UTF-8"?>
<!-- # Change the project name and the default target -->
<project basedir="." name="thebiasplanet.hiunoextensionsunoextension.uno" default="registerUnoExtension">
 <import file="../commonBuild01.xml"/>
 
 <!-- Add this if necessary
 <property name="CHECKSTYLE" value="ON"/>
 -->
 
 <!-- Add this if necessary
 <property name="JAR_DEPLOY_DIRECTORY_NAME" value="?"/>
 -->
 
 <!-- Add this if necessary
 <property name="WAR_DEPLOY_DIRECTORY_NAME" value="?"/>
 -->
 
 <path id="INCLUDED_JAR_FILE_NAMES">
  <!-- # Add the pathelement if necessary
  <pathelement path="?"/>
  -->
  <pathelement path="../unoUtilitiesToDisclose/target/thebiasplanet.unoutilities.jar"/>
 </path>
 
 <path id="OTHER_CLASSES_PATHS">
  <!-- # Change the path if necessary -->
  <pathelement path="${JAVA_FILES_BASE_DIRECTORY_NAME}:${CLASSES_BASE_DIRECTORY_NAME}:${LIBREOFFICE_CLASSES_BASE_DIRECTORY_NAME}/unoil.jar:${LIBREOFFICE_CLASSES_BASE_DIRECTORY_NAME}/jurt.jar:${LIBREOFFICE_CLASSES_BASE_DIRECTORY_NAME}/ridl.jar:${LIBREOFFICE_CLASSES_BASE_DIRECTORY_NAME}/juh.jar"/>
 </path>
 
 <import file="../commonBuild02.xml"/>
</project>

プロジェクト名(ここでは、'thebiasplanet.hiunoextensionsunoextension.uno')とデフォルトターゲット('registerUnoExtension')を指定する。そして、'INCLUDED_JAR_FILE_NAMES'パスに、UNOユーティリティプロジェクトのJarファイル名を含めるが、これによって、このJarファイルの中身が、このサンプルUNO拡張機能プロジェクトのJarファイルに含まれるようになる。

ところで、'OTHER_CLASSES_PATHS'パスに含まれる、'LIBREOFFICE_CLASSES_BASE_DIRECTORY_NAME'ディレクトリ配下のJarファイル群に注目してくれ。Those Jar files are UNO libraries. これらは、我々のJavaソースをコンパイルするのに必要だが、我々のJarファイルには含まれない。というのは、これらはデフォルトで実行時にロードされるからだ。

-Rebutter

オーケー。

-Hypothesizer

次に、プロジェクトディレクトリの下に以下のディレクトリ構造を作る。

/source
 /java
 /resource
 /unoIdl
-Rebutter

分かった。

UNOインターフェースを作る

-Hypothesizer

特定のUNOインターフェースを実装するUNOコンポーネントを作りたいので、そのUNOインターフェースを作ろう。UNOコンポーネントが既存のUNOインターフェースのみを実装すればよいのであれば、これは必要ないが、多くの場合、独自のUNOインターフェースを作りたいということになるだろう。

我々のUNOインターフェースを'thebiasplanet.uno.hiunoextensionsunoextension.XHiUnoExtensions'と名付けるが、これは、'unoIdl'ディレクトリ配下にUNOIDLファイル、'thebiasplanet/uno/hiunoextensionsunoextension/XHiUnoExtensions.idl'を作ることを意味する。

そして、この'XHiUnoExtensions.idl'ファイルに以下を書く。

// # Change the defined variable name START
#ifndef __thebiasplanet_uno_hiunoextensionsunoextension_XHiUnoExtensions_idl__
#define __thebiasplanet_uno_hiunoextensionsunoextension_XHiUnoExtensions_idl__
// # Change the defined variable name END

#include <com/sun/star/uno/XInterface.idl>
// # Add necessary idls START
#include <com/sun/star/lang/IllegalArgumentException.idl>
// # Add necessary idls END

// # Change the module name
module thebiasplanet { module uno { module hiunoextensionsunoextension {
 // # Change the interface name and the parent interface
 interface XHiUnoExtensions: com::sun::star::uno::XInterface
 {
  // # Add methods START
  string sayHi( [in] string p_name)
    raises (com::sun::star::lang::IllegalArgumentException);
  // # Add methods END
 };
}; }; };

#endif
-Rebutter

ふーむ、 . . .

-Hypothesizer

'#ifndef' ~ '#endif'ブロックは、その中のコードが複数回実行されないようにするためのものだ。定義する名前は、他の定義名の間で一意であればなんでもよい。

'#include'命令において、インクルードされるファイルがシステムインクルードディレクトリ配下にある場合には<>を使い、インクルードされるファイルがユーザー独自のディレクトリ配下にある場合には""を使う。

'com::sun::star::uno::XInterface'は、我々のUNOインターフェースの基底UNOインターフェースだ。我々のUNOインターフェースは一つのUNOインターフェースしか継承しないが、複数のUNOインターフェースを継承することもできる。'::'という表記に気をつけてくれ。UNOIDLでは、モジュールは'::'で区切られる。

'sayHi'メソッドが、我々のUNOインターフェースのメソッドだ。もちろん、必要であれば、我々のUNOインターフェースに複数のメソッドを持たせることもできる。

'[in]'指定は、この引数がメソッドの中に渡され、メソッド内からのこの引数への変更はメソッドの外からは見えないことを意味する。

-Rebutter

それはわかるが、'[out]'と指定したらどうなるのか?Javaは'[out]'引数を取り扱えないと思うが。

-Hypothesizer

実をいうと、'[out]'か'[inout]'の引数は、Javaでは配列にマッピングされる。配列が'[out] string p_argument1'ならば、'String [] p_argument1'にマッピングされる。

-Rebutter

ああ、それでは、メソッド内で値を'p_argument1 [0]'に設定するわけだ。

-Hypothesizer

そうだ。

-Rebutter

データタイプ、'string'は、Javaでは'java.lang.String'にマッピングされるのだな?

-Hypothesizer

そうだ。データタイプのマッピングについては、参考文書のここを参照してくれ。

-Rebutter

おう、UNOの文字列にはnullが許されないのか。

-Hypothesizer

そのようだ。

UNOインターフェースのUNOコンポーネントがスローするかもしれない'RuntimeException'を除く例外は、'raises'句に宣言しなければならない。'RuntimeException'は、'com.sun.star.uno.RuntimeException'またはその子孫のインスタンスだ。

-Rebutter

なるほど。

Main body END

References

  • Apache OpenOffice Wiki. (2014/01/02). Apache OpenOffice Developer's Guide. Retrieved from https://wiki.openoffice.org/wiki/Documentation/DevGuide/OpenOffice.org_Developers_Guide

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