2017年7月1日土曜日

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

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

Main body START

UNO旧スタイルサービスを作る

-Hypothesizer

項目6に進んで、UNO旧スタイルサービスを作るために、2つのUNOインターフェース、'thebiasplanet.uno.hiunoextensionsunoextension.XScolder'と'thebiasplanet.uno.hiunoextensionsunoextension.XPraiser'を作る。

-Rebutter

UNO旧スタイルサービスというのは、複数のUNOインターフェースを実装するUNOコンポーネントのUNOサービスのことだな?

-Hypothesizer

厳密に言えば、UNO新スタイルサービスも、'com.sun.star.lang.XServiceInfo'を含め複数のUNOインターフェースを実装している。UNO旧スタイルサービスでは、そのUNO旧スタイルサービスのユーザーが直接使うように意図されているUNOインターフェースが複数実装されている。

-Rebutter

なるほど。

-Hypothesizer

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
-Rebutter

ははあ。

-Hypothesizer

次に、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;
 }
}
-Rebutter

ふむ、先ほどの2つのUNOインターフェースを実装している。

-Hypothesizer

次に、このUNO新スタイルサービスを'グローバルUNOサービス'プロバイダーである'thebiasplanet.uno.heyunoextensionsunoextension.HeyUnoExtensionsUnoExtensionGlobalServicesProvider'に追加する。スタティックブロックに以下を追加する。

  ScolderPraiserUnoComponent.setThisClassToServicesProvider (UNO_COMPONENT_CLASS_NAME_TO_UNO_COMPONENT_CLASS_AND_SERVICE_NAMES_ARRAY_MAP);
-Rebutter

オーケー。

-Hypothesizer

次に、この第3のUNOコンポーネントを設定するために、UNOコンポーネント設定ファイルに以下のコードを追加する。

  <implementation name="thebiasplanet.uno.heyunoextensionsunoextension.ScolderPraiserUnoComponent">
   <!-- # Add service names -->
   <service name="thebiasplanet.uno.heyunoextensionsunoextension.ScolderPraiserService"/>
  </implementation>
-Rebutter

オーケー。

UNO旧スタイルサービスの'グローバルUNOサービス'インスタンスファクトリを作る

-Hypothesizer

この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
-Rebutter

ふむ、先ほどの2つのUNOインターフェースの内の1つ、'thebiasplanet.uno.hiunoextensionsunoextension.XScolder'を指定した。

-Hypothesizer

そう。これが、全てのファクトリメソッドの戻りタイプを決定する。ファクトリメソッド毎に戻りタイプを指定することはできない。

-Rebutter

ははあ。すると、ファクトリメソッド群の戻りタイプとして使うUNOインターフェースを1つ選択しさえすれば、UNO旧スタイルサービスの'グローバルUNOサービス'インスタンスファクトリを作れるわけだ。

-Hypothesizer

そのとおりだ。

-Hypothesizer

これで、UNOデータタイププロジェクトをビルドし、UNO拡張機能をビルドおよび登録できる。

-Rebutter

ビルド・登録が正常に行なわれた。

'グローバルUNOサービス'インスタンスファクトリによってUNO旧スタイルサービスのインスタンスを生成する実験をする

-Hypothesizer

'グローバル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"))
-Rebutter

Subは、予期通りに動作した。

-Hypothesizer

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

Java内で生成されたUNOオブジェクトインスタンスを、'UnoRuntime.queryInterface'メソッドを使わずに、UNOインターフェースに直接キャストする実験をする

-Hypothesizer

項目7に進もう。別の言語環境内のUNOオブジェクトへのUNOプロキシを持っている時、同じUNOオブジェクトの別のUNOインターフェースのUNOプロキシを得るためには、'UnoRuntime.queryInterface'メソッドを使わなければならない。しかし、我々のコードの言語環境内のUNOオブジェクトへの参照を得る時、この参照は、UNOプロキシへのものではなく、オリジナルのUNOオブジェクトへのものだ。そのため、その参照を別のUNOインターフェースに、'UnoRuntime.queryInterface'メソッドを使うことなくただキャストできる。

-Rebutter

それは理に適っているようだ。

-Hypothesizer

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'で戻す。

-Rebutter

なるほど。

-Hypothesizer

次に、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;
 }
-Rebutter

この旧スタイルUNOサービスのグローバルUNOサービス'インスタンスファクトリは旧スタイルUNOサービスのインスタンスをタイプ、'thebiasplanet.uno.heyunoextensionsunoextension.XScolder'で戻し、このインスタンスがJavaのキャストによって、UNOインターフェース、'thebiasplanet.uno.heyunoextensionsunoextension.XPraiser'に直接キャストされている。

-Hypothesizer

そう。

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"))
-Rebutter

ははあ、正常に動作する。

-Hypothesizer

こうして、我々は、Java内で生成されたUNOオブジェクトインスタンスを、'UnoRuntime.queryInterface'メソッドを使わずに、UNOインターフェースに直接キャストできることを実証した。

Main body END

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