<このシリーズの、前の記事 | このシリーズの目次 | このシリーズの、次の記事>
UNO旧スタイルサービスのシングルトンファクトリは作れないと参考文書は主張しているが、実際には作れる。
ははあ。
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
これがシングルトンファクトリなのか?
そう。
これがUNO旧スタイルサービスとどうやって関連付けられるのか?
実のところ、シングルトンファクトリは、コンポーネントコンテキストからインスタンスをただ取り出すだけであり、コンポーネントコンテキスト内のプロパティ名が'/singletons/thebiasplanet.uno.heyunoextensionsunoextension.ScolderPraiserServiceSingleton'になる。
うむ?それでは、シングルトンファクトリの名称がプロパティの名称に反映されるわけだ。. . . では、避けられない次の質問は、「そのプロパティに望みのインスタンスをどうやってセットするのか?」だ。
実のところ、どのようにそれをするように想定されているのかの記述を参考文書に見つけられなかった。だから、自分流にやった。
コンポーネントコンテキストは読み取り専用のはずであり、また、追加のプロパティを指定してコンポーネントコンテキストの新たなインスタンスを生成する方法が私には見つけられなかった。そこで、コンポーネントコンテキストクラスのサブクラスを作った。
ほう。
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;
}
}
}
ふーむ、これで、追加のプロパティを指定してコンポーネントコンテキストのインスタンスを生成できるようになった。
我々は、UNOコンポーネント、'thebiasplanet.uno.heyunoextensionsunoextension.HeyUnoExtensionsUnoComponent'のインスタンスが生成された時に、カスタマイズしたコンポーネントコンテキストインスタンスを生成し、このコンポーネントコンテキストインスタンスを渡し回す。
すると、このコンポーネントコンテキストが使われる場合にのみシングルトンなわけだ。
そのとおり。このコンポーネントコンテキストインスタンスを渡し回すために、UNOインターフェース、'thebiasplanet.uno.heyunoextensionsunoextension.XHeyUnoExtensions'に、このコンポーネントコンテキストを取り出すメソッドを以下のように追加する。
com::sun::star::uno::XComponentContext getComponentContext ();
ふーむ。
また、同じUNOインターフェースに、シングルトンを戻すメソッド、'getSingletonInnerPraiser'も以下のように追加しよう。
XPraiser getSingletonInnerPraiser ();
オーケー。
次に、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"));
カスタマイズしたコンポーネントコンテキストインスタンスを生成し、このインスタンスをUNOオブジェクト内に保持する。
そして、UNOコンポーネント、'thebiasplanet.uno.heyunoextensionsunoextension.HeyUnoExtensionsUnoComponent'にメソッド、'getComponentContext'を以下のように追加する。
public XComponentContext getComponentContext (){
return componentContext;
}
ははあ。
また、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;
}
シングルトンは、メソッド、'get'で得られるわけだ。
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' によって得た)が含まれるので、本当にシングルトンを得ているのかどうかを判別できる。
ふーむ、メッセージ中の丸括弧内の番号がアイデンティティハッシュコードだ。. . . マクロSubを実行すると、3回のメッセージのアイデンティティハッシュコードが同じだ。
'l_scolderPraiserServiceSingleton1'と'l_scolderPraiserServiceSingleton2'はメソッド、'getSingletonInnerPraiser'から得て、'l_scolderPraiserServiceSingleton3'はシングルトンファクトリから直接得た。しかし、それらがどのように得られたにしろ、それらは同じオブジェクトだ。
また、'l_scolderPraiserService3'についてのコードは、比較のために追加した。'l_scolderPraiserService3'は、グローバルUNOオブジェクトサービスマネージャーから得たものであり、アイデンティティハッシュコードから分かるとおり、シングルトンではない。
なるほど。
このようにして、我々は、UNO旧スタイルサービスのシングルトンファクトリを作る方法を実証した。