2017年5月27日土曜日

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

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

Main body START

UNOコンポーネントを作る

-Hypothesizer

それでは、UNOコンポーネントを作ろう。我々のUNOコンポーネントは'thebiasplanet.uno.hiunoextensionsunoextension.HiUnoExtensionsImplementation'だから、プロジェクトディレクトリの下にJavaのソースファイル、'source/java/thebiasplanet/uno/hiunoextensionsunoextension/HiUnoExtensionsImplementation.java'を作り、以下をこのファイルに書く。

// # Change the package name
package thebiasplanet.uno.hiunoextensionsunoextension;

import java.util.Set;
import java.util.HashSet;
import java.util.Map;
import com.sun.star.lib.uno.helper.WeakBase;
import com.sun.star.lang.XServiceInfo;
import com.sun.star.lang.XInitialization;
import com.sun.star.uno.XComponentContext;
// # Add necessary classes and interfaces START
import com.sun.star.lang.IllegalArgumentException;
// # Add necessary classes and interfaces END

// # Change the class name
public class HiUnoExtensionsImplementation
  extends WeakBase
  implements XServiceInfo, XInitialization,
  // # Specify the UNO interface to implement
  XHiUnoExtensions {
 private static final Set <String> SERVICE_NAMES_SET = new HashSet <String> ();
 private static final Class thisClass = new Object () { }.getClass ().getEnclosingClass ();
 static {
  // # Add service names START
  SERVICE_NAMES_SET.add ("thebiasplanet.uno.hiunoextensionsunoextension.HiUnoExtensions");
  // # Add service names END
 }
 static final String [] SERVICE_NAMES_ARRAY = SERVICE_NAMES_SET.toArray (new String [SERVICE_NAMES_SET.size ()]);
 private XComponentContext componentContext = null;
 // # Add member variables START
 private String message = null;
 // # Add member variables END
 
 static void setThisClassToServicesProvider (Map <String, Object []> p_implementationClassNameToImplementationClassAndServiceNamesArrayMap) {
  p_implementationClassNameToImplementationClassAndServiceNamesArrayMap.put (thisClass.getName (), new Object [] {thisClass, SERVICE_NAMES_ARRAY});
 }
 
 // # Change the class name
 public HiUnoExtensionsImplementation (XComponentContext p_componentContext)
   throws IllegalArgumentException {
  componentContext = p_componentContext;
 }
 
 public final void initialize (java.lang.Object [] p_arguments)
   throws com.sun.star.uno.Exception {
  // # Write the initialization START
  if (p_arguments != null && p_arguments.length == 1) {
   if (p_arguments[0] instanceof String) {
    message = (String) p_arguments[0];
    if (message == null) {
     throw new IllegalArgumentException ("The first argument can't be null.");
    }
   }
   else {
    throw new IllegalArgumentException("The first argument must be a String instance.");
   }
  }
  else {
   throw new IllegalArgumentException("The number of arguments must be 1.");
  }
  // # Write the initialization END
 }
 
 // # Add methods of the implemented UNO interface START
 public String sayHi (String p_name)
   throws IllegalArgumentException {
  if (p_name == null) {
   throw new IllegalArgumentException ("The first argument can't be null.");
  }
  return String.format ("%s, %s!", message, p_name);
 }
 // # Add methods of the implemented UNO interface END
 
 // # Add other member methods START
 // # Add other member methods END
 
 public String getImplementationName () {
  return thisClass.getName ();
 }
 
 public final boolean supportsService (String p_serviceName) {
  return SERVICE_NAMES_SET.contains (p_serviceName);
 }
 
 public final String [] getSupportedServiceNames () {
  return SERVICE_NAMES_ARRAY;
 }
}
-Rebutter

ふーむ、 . . .

-Hypothesizer

このクラスは、'com.sun.star.lib.uno.helper.WeakBase'を継承するが、これは、'com.sun.star.lang.XTypeProvider'と'com.sun.star.uno.XWeak'を実装したUNOのヘルパークラスだ。

'com.sun.star.lang.XTypeProvider'は、我々のUNOコンポーネントがLibreOffice Basicマクロからアクセスされるならば実装しておく必要がある。LibreOffice Basicマクロは、UNOコンポーネントがどのUNOインターフェースを実装しているかを、'com.sun.star.lang.XTypeProvider'を通して知らなければならない。

-Rebutter

Javaプログラムでは必要ないのに、LibreOffice Basicマクロは何故、それらを知らなければならないのか?

-Hypothesizer

UNOプロキシはUNOインターフェースに対して作られることを思い出してくれ。Javaでは、別のUNOインターフェースに対するUNOプロキシが欲しい場合、そのUNOインターフェースを指定することでそのUNOプロキシを明示的に得る。LibreOffice Basicマクロでは、このプロセスはLibreOffice Basicランタイムによって処理されるが、LibreOffice Basicランタイムは、どのUNOインターフェースを問い合わせるべきかを'com.sun.star.lang.XTypeProvider'を通して知る。

-Rebutter

それでは、LibreOffice Basicマクロでは、 UNOインターフェース毎にUNOプロキシを明示的に取得しなくてもよいわけだ。

-Hypothesizer

そうだ。

'com.sun.star.uno.XWeak'は、実のところ、我々には特に実装する必要がない。このヘルパークラスを使うのは、このヘルパークラスが'com.sun.star.lang.XTypeProvider'を実装しており、'com.sun.star.lang.XTypeProvider'だけを実装しているヘルパークラスがないからだ。

-Rebutter

'com.sun.star.uno.XWeak'の役割は何だ?

-Hypothesizer

UNOコンポーネントが'com.sun.star.uno.XWeak'を実装したら、このUNOコンポーネントを弱い参照で参照できるようになる。弱い参照は、あるオブジェクトへの参照であるが、そのオブジェクトがガーベッジコレクトされるのを妨げない参照だ。

-Rebutter

すると、我々のUNOコンポーネントのインスタンスが弱い参照で参照されているが普通の(強い)参照で参照されていない場合、そのインスタンスはそのうちガーベッジコレクトされるわけだ。

-Hypothesizer

そう。

また、我々のUNOコンポーネントは、'com.sun.star.lang.XServiceInfo'、'com.sun.star.lang.XInitialization'、'thebiasplanet.uno.hiunoextensionsunoextension.XHiUnoExtensions'も実装する。

我々のUNOコンポーネントが'com.sun.star.lang.XServiceInfo'を実装するのは、UNOサービスとして登録されるからだ。そうでなければ、'com.sun.star.lang.XServiceInfo'を実装する必要はない。

メソッド、'getImplementationName'、'supportsService'、'getSupportedServiceNames'は、このインターフェースのメソッドだ。

メソッド、'getImplementationName'は、UNOコンポーネントクラスのフルネームを戻す。

メソッド、'supportsService'は、1つのStringインスタンスを受け取り、このStringインスタンスが、このUNOコンポーネントが登録されるUNO サービス名の1つと同値であるかを判断する。

メソッド、'getSupportedServiceNames'は、このUNOコンポーネントが登録されるUNOサービス名の配列を戻す。

-Rebutter

UNOコンポーネントは、複数のUNOのサービス名で登録できるようだ。それは有用なのだろうか?

-Hypothesizer

私には分からない。とにかく、メカニズム上、1つのUNOコンポーネントを複数のUNOサービス名で登録できるようになっている。

-Rebutter

なるほど。

-Hypothesizer

'com.sun.star.lang.XInitialization'については、我々のUNOコンポーネントがUNOサービスマネージャーを通してインスタンス化される時、このインターフェースによって、我々はそうしたインスタンスの初期化をカスタマイズできる。

メソッド、'initialize'がこのインターフェースのメソッドだ。我々のUNOコンポーネントがUNOサービスマネージャーを通してインスタンス化される時、このUNOコンポーネントのJavaコンストラクタが、コンポーネントコンテキストを引数として呼び出される。次に、'initialize'メソッドが、パラメータの配列を引数として呼ばれる。

-Rebutter

ははあ。

-Hypothesizer

そして、もちろん、我々のUNOコンポーネントはインターフェース、'thebiasplanet.uno.hiunoextensionsunoextension.XHiUnoExtensions'を実装する。

-Rebutter

勿論。

-Hypothesizer

スタティックファイナルなメンバー、'SERVICE_NAMES_SET'、'thisClass'、'SERVICE_NAMES_ARRAY'は、このUNOコンポーネントがUNOサービスとして登録されるために必要な情報を格納している。この情報は、これらのメンバーとして格納されている必要は特になく、先に述べたインターフェースが適切に実装されればそれでよい。

-Rebutter

'SERVICE_NAMES_SET'に追加するUNOサービス名を変更すればよいだけなわけだ。

-Hypothesizer

そう。

メンバー、'componentContext'は、コンポーネントコンテキストを格納している。コンポーネントコンテキストは、UNOオブジェクトに取っておく必要は必ずしもないが、多くの場合、ここに取っておくと役に立つ。コンポーネントコンテキストからグローバルUNOサービスマネージャーを取得できる。そこで、我々は、Javaコンストラクタの引数で渡されたコンポーネントコンテキストをそこに保存するのをデフォルトとする。

-Rebutter

いいだろう。

-Hypothesizer

メンバー、'message'は、このUNOコンポーネント独自のメンバーだ。他のUNOコンポーネントでは、それぞれ必要なメンバーで置き換える。

-Rebutter

なるほど。

-Hypothesizer

スタティックメソッド、'setThisClassToServicesProvider'は、このUNOコンポーネントの情報を'グローバルUNOサービス'プロバイダーに提供するメソッドだ。この情報は、このメソッドで提供する必要はなく、'グローバルUNOサービス'プロバイダーが知るべきことを知れればそれでよい。

-Rebutter

オーケー。

-Hypothesizer

そして、メソッド、'sayHi'は、インターフェース、'thebiasplanet.uno.hiunoextensionsunoextension.XHiUnoExtensions'のメソッドだ。

-Rebutter

そこが、我々のUNOコンポーネント独自のアルゴリズムを記述する場所なわけだ。

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

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