<このシリーズの、前の記事 | このシリーズの目次 | このシリーズの、次の記事>
項目6に進んで、UNO旧スタイルサービスを作るために、2つのUNOインターフェース、'thebiasplanet.uno.hiunoextensionsunoextension.XScolder'と'thebiasplanet.uno.hiunoextensionsunoextension.XPraiser'を作る。
UNO旧スタイルサービスというのは、複数のUNOインターフェースを実装するUNOコンポーネントのUNOサービスのことだな?
厳密に言えば、UNO新スタイルサービスも、'com.sun.star.lang.XServiceInfo'を含め複数のUNOインターフェースを実装している。UNO旧スタイルサービスでは、そのUNO旧スタイルサービスのユーザーが直接使うように意図されているUNOインターフェースが複数実装されている。
なるほど。
UNOデータタイププロジェクトで、'source'ディレクトリ配下に、UNOIDLファイル、'unoIdl/thebiasplanet/uno/heyunoextensionsunoextension/XScolder.idl'と'unoIdl/thebiasplanet/uno/heyunoextensionsunoextension/XPraiser.idl'を作成し、以下を書く。
// # Change the defined variable name START
#ifndef __thebiasplanet_uno_hiunoextensionsunoextension_XScolder_idl__
#define __thebiasplanet_uno_hiunoextensionsunoextension_XScolder_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 heyunoextensionsunoextension {
// # Change the interface name and the parent interface
interface XScolder: com::sun::star::uno::XInterface
{
// # Add methods START
string scold ( [in] string p_name)
raises (com::sun::star::lang::IllegalArgumentException);
// # Add methods END
};
}; }; };
#endif
// # Change the defined variable name START
#ifndef __thebiasplanet_uno_hiunoextensionsunoextension_XPraiser_idl__
#define __thebiasplanet_uno_hiunoextensionsunoextension_XPraiser_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 heyunoextensionsunoextension {
// # Change the interface name and the parent interface
interface XPraiser: com::sun::star::uno::XInterface
{
// # Add methods START
string praise ( [in] string p_name)
raises (com::sun::star::lang::IllegalArgumentException);
// # Add methods END
};
}; }; };
#endif
ははあ。
次に、UNO拡張機能プロジェクトで、UNOコンポーネントのJavaソースファイル、'java/thebiasplanet/uno/heyunoextensionsunoextension/ScolderPraiserUnoComponent.java'を作成し、そこに以下を書く。
// # Change the package name
package thebiasplanet.uno.heyunoextensionsunoextension;
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 java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import com.sun.star.lang.IllegalArgumentException;
import thebiasplanet.coreutilities.messaging.Publisher;
// # Add necessary classes and interfaces END
// # Change the class name
public class ScolderPraiserUnoComponent
extends WeakBase
implements XServiceInfo, XInitialization,
// # Specify the UNO interface to implement
XScolder, XPraiser {
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.heyunoextensionsunoextension.ScolderPraiserService");
// # 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_unoComponentClassNameToUnoComponentClassAndServiceNamesArrayMap) {
p_unoComponentClassNameToUnoComponentClassAndServiceNamesArrayMap.put (thisClass.getName (), new Object [] {thisClass, SERVICE_NAMES_ARRAY});
}
// # Change the class name
public ScolderPraiserUnoComponent (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.format ("%s (%d %s)", (String) p_arguments[0], System.identityHashCode (this), DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss").format (LocalDateTime.now()));
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 scold (String p_name)
throws IllegalArgumentException {
if (p_name == null) {
throw new IllegalArgumentException ("The first argument can't be null.");
}
return String.format ("Don't do that! %s, %s!", message, p_name);
}
public String praise (String p_name)
throws IllegalArgumentException {
if (p_name == null) {
throw new IllegalArgumentException ("The first argument can't be null.");
}
return Publisher.getMessage (String.format ("Wonderful! %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;
}
}
ふむ、先ほどの2つのUNOインターフェースを実装している。
次に、このUNO新スタイルサービスを'グローバルUNOサービス'プロバイダーである'thebiasplanet.uno.heyunoextensionsunoextension.HeyUnoExtensionsUnoExtensionGlobalServicesProvider'に追加する。スタティックブロックに以下を追加する。
ScolderPraiserUnoComponent.setThisClassToServicesProvider (UNO_COMPONENT_CLASS_NAME_TO_UNO_COMPONENT_CLASS_AND_SERVICE_NAMES_ARRAY_MAP);
オーケー。
次に、この第3のUNOコンポーネントを設定するために、UNOコンポーネント設定ファイルに以下のコードを追加する。
<implementation name="thebiasplanet.uno.heyunoextensionsunoextension.ScolderPraiserUnoComponent">
<!-- # Add service names -->
<service name="thebiasplanet.uno.heyunoextensionsunoextension.ScolderPraiserService"/>
</implementation>
オーケー。
このUNO旧スタイルサービスの'グローバルUNOサービス'インスタンスファクトリを作る。
UNOデータタイププロジェクトで、'source'ディレクトリ配下に、UNOIDLファイル、'unoIdl/thebiasplanet/uno/heyunoextensionsunoextension/ScolderPraiserService.idl'を作り、そこに以下を書く。
// # Change the defined variable name START
#ifndef __thebiasplanet_uno_heyunoextensionsunoextension_ScolderPraiserService_idl__
#define __thebiasplanet_uno_heyunoextensionsunoextension_ScolderPraiserService_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
service ScolderPraiserService: XScolder {
// # Add constructors START
create1 ( [in] string p_message)
raises (com::sun::star::lang::IllegalArgumentException);
// # Add constructors END
};
}; }; };
#endif
ふむ、先ほどの2つのUNOインターフェースの内の1つ、'thebiasplanet.uno.hiunoextensionsunoextension.XScolder'を指定した。
そう。これが、全てのファクトリメソッドの戻りタイプを決定する。ファクトリメソッド毎に戻りタイプを指定することはできない。
ははあ。すると、ファクトリメソッド群の戻りタイプとして使うUNOインターフェースを1つ選択しさえすれば、UNO旧スタイルサービスの'グローバルUNOサービス'インスタンスファクトリを作れるわけだ。
そのとおりだ。
これで、UNOデータタイププロジェクトをビルドし、UNO拡張機能をビルドおよび登録できる。
ビルド・登録が正常に行なわれた。
'グローバルUNOサービス'インスタンスファクトリによってUNO旧スタイルサービスのインスタンスを生成できることをテストするために、先程のLibreOffice Basic Subの最後に以下のコードを追加する。
Dim l_scolderPraiserService1 As Variant
l_scolderPraiserService1 = thebiasplanet.uno.heyunoextensionsunoextension.ScolderPraiserService.create1 ("Well")
Msgbox (l_scolderPraiserService1.scold ("guys"))
Msgbox (l_scolderPraiserService1.praise ("guys"))
Subは、予期通りに動作した。
こうして、我々は、UNO旧スタイルサービスを作成し、このUNO旧スタイルサービスの'グローバルUNOサービス'インスタンスファクトリを作成し、この'グローバルUNOサービス'インスタンスファクトリによってUNO旧スタイルサービスのインスタンスを生成する方法を実証した。
項目7に進もう。別の言語環境内のUNOオブジェクトへのUNOプロキシを持っている時、同じUNOオブジェクトの別のUNOインターフェースのUNOプロキシを得るためには、'UnoRuntime.queryInterface'メソッドを使わなければならない。しかし、我々のコードの言語環境内のUNOオブジェクトへの参照を得る時、この参照は、UNOプロキシへのものではなく、オリジナルのUNOオブジェクトへのものだ。そのため、その参照を別のUNOインターフェースに、'UnoRuntime.queryInterface'メソッドを使うことなくただキャストできる。
それは理に適っているようだ。
UNOデータタイププロジェクトで、UNOIDLファイル、'unoIdl/thebiasplanet/uno/heyunoextensionsunoextension/XHeyUnoExtensions.idl'を変更し、メソッド、'getInnerPraiser'を以下のように追加する。
XPraiser getInnerPraiser ( [in] string p_message)
raises (com::sun::star::lang::IllegalArgumentException);
このメソッドは、前述した旧スタイルUNOサービスのインスタンスを生成し、このインスタンスをタイプ、'thebiasplanet.uno.heyunoextensionsunoextension.XPraiser'で戻す。
なるほど。
次に、UNO拡張機能プロジェクトで、UNOコンポーネント、'thebiasplanet.uno.heyunoextensionsunoextension.HeyUnoExtensionsUnoComponent'にこのメソッドを以下のように実装する。
public XPraiser getInnerPraiser (String p_message)
throws IllegalArgumentException {
XScolder l_innerScolderPraiser1 = null;
XPraiser l_innerScolderPraiser2 = null;
try {
l_innerScolderPraiser1 = ScolderPraiserService.create1 (componentContext, p_message);
l_innerScolderPraiser2 = (XPraiser) l_innerScolderPraiser1;
}
catch (IllegalArgumentException l_exception) {
throw l_exception;
}
return l_innerScolderPraiser2;
}
この旧スタイルUNOサービスのグローバルUNOサービス'インスタンスファクトリは旧スタイルUNOサービスのインスタンスをタイプ、'thebiasplanet.uno.heyunoextensionsunoextension.XScolder'で戻し、このインスタンスがJavaのキャストによって、UNOインターフェース、'thebiasplanet.uno.heyunoextensionsunoextension.XPraiser'に直接キャストされている。
そう。
UNOデータタイププロジェクトをビルドし、UNO拡張機能をビルドおよび登録しよう。
テストするために、先ほどのLibreOffice Basic Subの最後の以下のコードを追加する。
Dim l_scolderPraiserService2 As Variant
l_scolderPraiserService2 = l_heyUnoExtensionsService.getInnerPraiser ("Well")
Msgbox (l_scolderPraiserService2.scold ("guys"))
Msgbox (l_scolderPraiserService2.praise ("guys"))
ははあ、正常に動作する。
こうして、我々は、Java内で生成されたUNOオブジェクトインスタンスを、'UnoRuntime.queryInterface'メソッドを使わずに、UNOインターフェースに直接キャストできることを実証した。