2017年7月8日土曜日

22: 第2のサンプルUNO拡張機能(LibreOffice拡張機能またはApache OpenOffice拡張機能)を別の構造で開発する、パート4

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

Main body START

UNO旧スタイルサービスのシングルトンファクトリを作る実験をする

-Hypothesizer

UNO旧スタイルサービスのシングルトンファクトリは作れないと参考文書は主張しているが、実際には作れる。

-Rebutter

ははあ。

-Hypothesizer

UNOデータタイププロジェクトで、UNOIDLファイル、'unoIdl/thebiasplanet/uno/heyunoextensionsunoextension/ScolderPraiserServiceSingleton.idl'を作り、そこに以下を書く。

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

// # Change the interface idl
#include "thebiasplanet/uno/heyunoextensionsunoextension/XScolder.idl"

// # Change the module name
module thebiasplanet { module uno { module heyunoextensionsunoextension {
 // # Change the service name and the interface name
 singleton ScolderPraiserServiceSingleton: XScolder;
}; }; };

#endif
-Rebutter

これがシングルトンファクトリなのか?

-Hypothesizer

そう。

-Rebutter

これがUNO旧スタイルサービスとどうやって関連付けられるのか?

-Hypothesizer

実のところ、シングルトンファクトリは、コンポーネントコンテキストからインスタンスをただ取り出すだけであり、コンポーネントコンテキスト内のプロパティ名が'/singletons/thebiasplanet.uno.heyunoextensionsunoextension.ScolderPraiserServiceSingleton'になる。

-Rebutter

うむ?それでは、シングルトンファクトリの名称がプロパティの名称に反映されるわけだ。. . . では、避けられない次の質問は、「そのプロパティに望みのインスタンスをどうやってセットするのか?」だ。

-Hypothesizer

実のところ、どのようにそれをするように想定されているのかの記述を参考文書に見つけられなかった。だから、自分流にやった。

コンポーネントコンテキストは読み取り専用のはずであり、また、追加のプロパティを指定してコンポーネントコンテキストの新たなインスタンスを生成する方法が私には見つけられなかった。そこで、コンポーネントコンテキストクラスのサブクラスを作った。

-Rebutter

ほう。

-Hypothesizer

UNOユーティリティプロジェクトで、Javaソースファイル、'java/thebiasplanet/unoutilities/connectionshandling/UnoComponentContext.java'を作り、そこに以下を書く。

package thebiasplanet.unoutilities.connectionshandling;

import java.util.Map;
import com.sun.star.uno.XComponentContext;
import com.sun.star.lang.XMultiComponentFactory;

public class UnoComponentContext implements XComponentContext {
 private XComponentContext originalComponentContext = null;
 private Map <String, Object> extraNameValueMap = null;
 
 public UnoComponentContext (XComponentContext p_originalComponentContext, Map <String, Object> p_extraNameValueMap) throws com.sun.star.uno.Exception {
  if (p_originalComponentContext == null) {
   throw new com.sun.star.uno.Exception ("Original component context is required.");
  }
  originalComponentContext = p_originalComponentContext;
  extraNameValueMap = p_extraNameValueMap;
 }
 
 @Override
 public final Object getValueByName (String p_name) {
  if (extraNameValueMap != null && extraNameValueMap.containsKey (p_name)) {
   return extraNameValueMap.get (p_name);
  }
  return originalComponentContext.getValueByName (p_name);
 }
 
 @Override
 public final XMultiComponentFactory getServiceManager () {
  return originalComponentContext.getServiceManager ();
 }
 
 public final boolean isFromTheSameOrigin (UnoComponentContext p_unoComponentContext) {
  if ((p_unoComponentContext ==  null) || (extraNameValueMap.get ("identification") == null)) {
   return false;
  }
  if (extraNameValueMap.get ("identification").equals (p_unoComponentContext.getValueByName ("identification"))) {
   return true;
  }
  else {
   return false;
  }
 }
}
-Rebutter

ふーむ、これで、追加のプロパティを指定してコンポーネントコンテキストのインスタンスを生成できるようになった。

-Hypothesizer

我々は、UNOコンポーネント、'thebiasplanet.uno.heyunoextensionsunoextension.HeyUnoExtensionsUnoComponent'のインスタンスが生成された時に、カスタマイズしたコンポーネントコンテキストインスタンスを生成し、このコンポーネントコンテキストインスタンスを渡し回す。

-Rebutter

すると、このコンポーネントコンテキストが使われる場合にのみシングルトンなわけだ。

-Hypothesizer

そのとおり。このコンポーネントコンテキストインスタンスを渡し回すために、UNOインターフェース、'thebiasplanet.uno.heyunoextensionsunoextension.XHeyUnoExtensions'に、このコンポーネントコンテキストを取り出すメソッドを以下のように追加する。

  com::sun::star::uno::XComponentContext getComponentContext ();
-Rebutter

ふーむ。

-Hypothesizer

また、同じUNOインターフェースに、シングルトンを戻すメソッド、'getSingletonInnerPraiser'も以下のように追加しよう。

  XPraiser getSingletonInnerPraiser ();
-Rebutter

オーケー。

-Hypothesizer

次に、UNO拡張機能プロジェクトで、UNOコンポーネント、'thebiasplanet.uno.heyunoextensionsunoextension.HeyUnoExtensionsUnoComponent'のコンストラクタを以下のように変更する。

  componentContextExtraNameValueMap = new HashMap <String, Object> ();
  try {
   componentContext = new UnoComponentContext (p_componentContext, componentContextExtraNameValueMap);
  }
  catch (com.sun.star.uno.Exception l_exception) {
  }
  componentContextExtraNameValueMap.put ("/singletons/thebiasplanet.uno.heyunoextensionsunoextension.ScolderPraiserServiceSingleton", ScolderPraiserService.create1 (componentContext, "Well"));
-Rebutter

カスタマイズしたコンポーネントコンテキストインスタンスを生成し、このインスタンスをUNOオブジェクト内に保持する。

-Hypothesizer

そして、UNOコンポーネント、'thebiasplanet.uno.heyunoextensionsunoextension.HeyUnoExtensionsUnoComponent'にメソッド、'getComponentContext'を以下のように追加する。

 public XComponentContext getComponentContext (){
  return componentContext;
 }
-Rebutter

ははあ。

-Hypothesizer

また、UNOコンポーネント、'thebiasplanet.uno.heyunoextensionsunoextension.HeyUnoExtensionsUnoComponent'に、メソッド、'getSingletonInnerPraiser'も、以下のように追加する。

 public XPraiser getSingletonInnerPraiser ()
   throws IllegalArgumentException {
  XScolder l_singletonInnerScolderPraiser1 = null;
  XPraiser l_singletonInnerScolderPraiser2 = null;
  try {
   l_singletonInnerScolderPraiser1 = ScolderPraiserServiceSingleton.get (componentContext);
   l_singletonInnerScolderPraiser2 = (XPraiser) l_singletonInnerScolderPraiser1;
  }
  catch (IllegalArgumentException l_exception) {
   throw l_exception;
  }
  return l_singletonInnerScolderPraiser2;
 }
-Rebutter

シングルトンは、メソッド、'get'で得られるわけだ。

-Hypothesizer

3つのプロジェクト、UNOデータタイププロジェクト、UNOユーティリティプロジェクト、UNO拡張機能プロジェクトをビルドし、先ほどのLibreOffice Basic Subの最後に以下のコードを追加する。

 Dim l_scolderPraiserServiceSingleton1 As Variant
 Dim l_scolderPraiserServiceSingleton2 As Variant
 Dim l_scolderPraiserServiceSingleton3 As Variant
 l_scolderPraiserServiceSingleton1 = l_heyUnoExtensionsService.getSingletonInnerPraiser ()
 Msgbox (l_scolderPraiserServiceSingleton1.scold ("guys"))
 Msgbox (l_scolderPraiserServiceSingleton1.praise ("guys"))
 l_scolderPraiserServiceSingleton2 = l_heyUnoExtensionsService.getSingletonInnerPraiser ()
 Msgbox (l_scolderPraiserServiceSingleton2.scold ("guys"))
 Msgbox (l_scolderPraiserServiceSingleton2.praise ("guys"))
 Dim l_componentContext As Variant
 l_componentContext = l_heyUnoExtensionsService.getComponentContext () l_scolderPraiserServiceSingleton3 = thebiasplanet.uno.heyunoextensionsunoextension.ScolderPraiserServiceSingleton.get (l_componentContext)
 Msgbox (l_scolderPraiserServiceSingleton3.scold ("guys"))
 Msgbox (l_scolderPraiserServiceSingleton3.praise ("guys"))
 Dim l_scolderPraiserService3 As Variant
 l_scolderPraiserService3 = GetProcessServiceManager ().createInstanceWithArgumentsAndContext ("thebiasplanet.uno.heyunoextensionsunoextension.ScolderPraiserService", l_args (), l_componentContext)
 Msgbox (l_scolderPraiserService3.scold ("guys"))
 Msgbox (l_scolderPraiserService3.praise ("guys"))

シングルトンを3度得ることに注意してくれ。メソッド、'scold'および'praise'の戻りには、UNOオブジェクトのアイデンティティハッシュコード('System.identityHashCode' によって得た)が含まれるので、本当にシングルトンを得ているのかどうかを判別できる。

-Rebutter

ふーむ、メッセージ中の丸括弧内の番号がアイデンティティハッシュコードだ。. . . マクロSubを実行すると、3回のメッセージのアイデンティティハッシュコードが同じだ。

-Hypothesizer

'l_scolderPraiserServiceSingleton1'と'l_scolderPraiserServiceSingleton2'はメソッド、'getSingletonInnerPraiser'から得て、'l_scolderPraiserServiceSingleton3'はシングルトンファクトリから直接得た。しかし、それらがどのように得られたにしろ、それらは同じオブジェクトだ。

また、'l_scolderPraiserService3'についてのコードは、比較のために追加した。'l_scolderPraiserService3'は、グローバルUNOオブジェクトサービスマネージャーから得たものであり、アイデンティティハッシュコードから分かるとおり、シングルトンではない。

-Rebutter

なるほど。

-Hypothesizer

このようにして、我々は、UNO旧スタイルサービスのシングルトンファクトリを作る方法を実証した。

Main body END

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