レベル: 中級 Sachin Mahajan, Software Development, IBM
2009年 5月 07日 この記事では Crispy について説明します。Crispy の目標は、多種多様なトランスポート (RMI、EJB、JAX-RPC、XML-RPC など) に対するリモート呼び出しの単一エントリー・ポイントを提供することです。Crispy では、プロパティーを使用することでサービス・マネージャーを構成し、このサービス・マネージャーを使ってリモートの API を呼び出します。
はじめに
Crispy は、Communication per Remote Invocation for different kinds of Services via ProxYs (プロキシーを介して多種多様なサービスを呼び出すための、リモート呼び出しによる通信) を表します。Crispy はリモート呼び出しのためのフレームワークであり、多種多様なトランスポート・プロトコル (RMI、EJB、JAX-RPC、XML-RPC など) をサポートしています。簡単に言えば、Crispy を使うためには、サービス・マネージャーを (プロパティー・ファイルを使って) 構成し、サポートされているリモート API を呼び出せばよいだけです。
まず、Crispy を構成するためのコード・サンプルを見てみましょう (リスト 1)。
リスト 1. Crispy を構成するためのコード・サンプル
Properties prop = new Properties();
prop.put(Property.REMOTE_URL_AND_PORT, serviceUrl);
prop.put(Property.EXECUTOR_CLASS, typeOfExecutor);
ServiceManager manager = new ServiceManager(prop);
LibraryService library = (LibraryService) manager.createService(LibraryService.class);
String author = library.findAuthor(myBook);
String isbn = library.findISBN(myBook);
…
|
上記のコードでは、properties オブジェクトを作成し、リモート URL と実行クラスのタイプを設定しています。実行クラスのタイプには、JAX RPC、JBoss Remoting、RMI executor、XML RPC、REST、http executor などがあります。プロパティーを構成したら、Crispy の ServiceManager のインスタンスを作成します。これで、この ServiceManager (Factory パターン) を使ってリモート・サービス・オブジェクト (この場合は OrderService) を作成することができます。
背景
Crispy について簡単に説明したので、今度は典型的なリモート呼び出しを Crispy を使わずに行う場合の例を見てみましょう。
リスト 2. Web サービス (JAX-RPC)
public static final String LIBRARY_SERVICE_ENDPOINT =
"http://myservicehost:9080/axis/services/LibraryService";
Service service = (Service) ServiceFactory.newInstance().createService(null);
Call call = service.createCall();
call.setTargetEndpointAddress("LIBRARY_SERVICE_ENDPOINT ");
call.setOperationName(new QName("findAuthor"));
QName paramXmlType = new QName(String.class.getName());
call.addParameter("arg0", paramXmlType, String.class, ParameterMode.IN);
call.setReturnType(new QName(String.class.getName()));
String result = (String) call.invoke(new String[] {”Alice in Wonderland”});
System.out.println("Author of Alice in Wonderland: " + result);
|
Web サービスを呼び出すために call オブジェクトが使われています。これを手動で設定することもでき、あるいは WSDL 文書を使うこともできます。ここでは、この call オブジェクトのオペレーション、パラメーター、戻り型を設定し、Web サービスを呼び出して、必要な結果を取得しています。
リスト 3. XML-RPC (Apache XML-RPC)
XmlRpcClient client = new XmlRpcClient("http://myservicehost:9090");
Vector param = new Vector();
param.add(”Alice in Wonderland”);
String result = (String)
client.execute("crispysample.LibraryService.findAuthor", param);
System.out.println("Author of Alice in Wonderland: " + result);
…
|
XML-RPC クライアントにとって、メインとなるアクセス・ポイントは XmlRpcClient です。execute メソッドと、param として渡されるパラメーターを使って、「calculateTip」というメソッドでリクエストが実行されます。
Crispy の登場
上記のコードは、リモート呼び出しを行う方法のうち、JAX-RPC による方法と XML-RPC による方法という 2 つの例を示したにすぎません。他にも、RMI、EJB、REST、http などを使ってリモート呼び出しを行うことができます。Crispy では、構成された ServiceManager を使うことによって、そうしたさまざまなリモート呼び出しをまとめて扱うことができます。ServiceManager を構成するためには Properties オブジェクトを使います。
リスト 4. JAX-RPC の場合
MiniAxisServer server = new MiniAxisServer();
try {
server.addService(LibraryService.class.getName(),
LibraryServiceImpl.class.getName());
server.start();
Properties properties = new Properties();
properties.put(Property.REMOTE_URL_AND_PORT, "LIBRARY_SERVICE_ENDPOINT");
properties.put(Property.EXECUTOR_CLASS, JaxRpcExecutor.class.getName());
} catch (Exception e) {
e.printStackTrace();
}
finally {
server.stop();
}
…
|
リスト 5. XML-RPC の場合
MiniXmlRpcServer server = new MiniXmlRpcServer();
try {
server.addService(LibraryService.class.getName(), LibraryServiceImpl.class.getName());
server.start();
Properties properties = new Properties();
properties.put(Property.REMOTE_URL_AND_PORT, " http://myservicehost:9090");
properties.put(Property.EXECUTOR_CLASS, XmlRpcExecutor.class.getName());
} catch (Exception e) {
e.printStackTrace();
}
finally {
server.stop();
}
…
|
ServiceManager が構成できると、ServiceManager をインスタンス化することができ、またリモート・メソッドを呼び出すことができます。下記はその一例です。
リスト 6. ServiceManager の例
ServiceManager manager = new ServiceManager(properties);
Library library = (LibraryService) manager.createService(LibraryService.class);
System.out.println("Author of Alice in Wonderland: " + result);
|
上記のコードから、Crispy を使うとリモート呼び出しが非常に容易になることがわかります。サービス・マネージャーを構成すると非常に便利で、リモート呼び出しとローカル呼び出しが同じように扱えるようになります。しかも、クライアントは呼び出し対象のリモート技術について詳しく知る必要がありません。
Crispy の実際
Crispy の内部動作
Crispy フレームワークは、クライアント (サービス・コンシューマー)、内部サービス・プロバイダー、そして外部サービス・プロバイダー、という 3 つのコンポーネントで構成されています。この 3 つのコンポーネントにはすべて通信ライブラリーが必要ですが、サーバー・コンポーネントのみにサービスの実装が必要になります。またクライアントにはサービス・インターフェースが必要です。
図 1. Crispy (クライアントとサーバー) のコンポーネント (Crispy のドキュメントより引用)
下記の図 2 は、クライアント・コンポーネントとサーバー・コンポーネントの間の通信の様子を示しています。この図からわかるように、これはクライアントとサーバーとの間の典型的な通信です。メモリー上に表現された (パラメーターや結果などを含む) データは、サーバーへの送信に適したフォーマットに変換されます。これはマーシャリングと呼ばれます。逆の変換はサーバー上でメソッドの実行前に行われ、アンマーシャリングと呼ばれます。
図 2. Crispy のコンポーネント間での通信 (Crispy のドキュメントより引用)
クライアント・サイドでは、ServiceManager オブジェクトが動的または静的なプロキシーを作成してサーバーと通信し、プロキシー・オブジェクトのメソッドを呼び出します。サーバーへの呼び出しをマーシャリングする前に、パラメーターを変換するための、オプションとしての呼び出しが行われます。図 3 に示すように、このプロセスは net.sf.crispy.util.Converter.makeSimple を使って行われます。サーバーがリクエストを受信すると、アンマーシャリングが行われ、サーバーは変換されたオブジェクトを net.sf.crispy.util.Converter.makeComplex を使って返送します。
図 3. Crispy でのオブジェクトの変換 (Crispy のドキュメントより引用)
先ほど触れたように、これはオプションのステップであり、オブジェクトを転送するために java.io.Serializable インターフェースを実装したくない場合には、このステップを呼び出すことができます。上記の図で示したように、複雑な Java オブジェクトは Java の HashTable (java.util.HashTable) オブジェクトに変換されます。この場合のキーは Java オブジェクトの属性名であり、値はその属性の値です。関係は Java の Vector オブジェクト (java.util.Vector) を使ってマッピングされます。
Crispy を同期型または非同期型で実行する
このフレームワークでは同期型または非同期型で実行するために、主にクライアントがそれに対応する呼び出しを行います。テストは、等価なサーバーが既に起動しているという前提で、MiniServer オブジェクト (net.sf.crispy.impl.MiniServer) を使って行います。下記は実行のタイプ (同期型または非同期型) を設定する方法の一例です。
リスト 7. MiniServer オブジェクト
MiniRmiServer server = new MiniRmiServer();
try {
server.addService(LibraryServiceImpl.LOOKUP_NAME,
LibraryServiceImpl.class.getName());
server.start();
Properties properties = new Properties();
properties.put(Property.REMOTE_URL_AND_PORT, "rmi://localhost:1098");
prop.put(Property.DYNAMIC_PROXY_CLASS, Property.VALUE_FOR_CGLIB_DYNAMIC_PROXY);
properties.put(Property.EXECUTOR_CLASS, RmiExecutor.class.getName());
//Register the interface implementation mapping
prop.put(LibraryService.class.getName(), LibraryServiceImpl.class.getName());
ServiceManager manager = new ServiceManager(prop);
LibraryService library = manager.createService(LibraryService.class);
System.out.println("Author of Alice in Wonderland: " +
library.findAuthor(“Alice in Wonderland”));
} catch (Exception e) {
e.printStackTrace();
}
finally {
server.stop();
}
...
|
上記の例では、デフォルトでは同期型で実行されます。一方、非同期型で実行するためには、ServiceManager オブジェクトによって AsynchronousCallback オブジェクト (net.sf.crispy.concurrent.AsynchronousCallback) の実装を登録する必要があります。この例では、登録されたコールバックと、非同期に実行するためのメソッド名、そして実行スレッドの最大数を使って LibraryService オブジェクトが作成されています。
リスト 8. LibraryService オブジェクト
Properties properties = new Properties();
properties.put(Property.REMOTE_URL_AND_PORT, "rmi://localhost:1098");
prop.put(Property.DYNAMIC_PROXY_CLASS, Property.VALUE_FOR_CGLIB_DYNAMIC_PROXY);
properties.put(Property.EXECUTOR_CLASS, RmiExecutor.class.getName());
//Register the interface implementation mapping
prop.put(LibraryService.class.getName(), LibraryServiceImpl.class.getName());
AsynchronousCallback callback = new AsynchronousCallbackForTests();
ServiceManager manager = new ServiceManager(prop);
LibraryService library = manager.createService
(LibraryService.class,callback,new String[]{“findAuthor”},INT_MAX_NO_THREADS);
...
|
謝辞
多忙なスケジュールの中でこの記事を校閲してくださり、また専門家としてのコメントをくださった、Crispy フレームワークの作成者である Mario Linke 氏に深く感謝いたします。
まとめ
この記事では、Crispy の内部動作について、さらにリモート呼び出しを行う上での Crispy の便利さと使いやすさについて説明しました。また JAX-RPC と XML-RPC を使ってリモート呼び出しを行う方法と、同期型で実行する場合と非同期型で実行する場合の両方について、Crispy を利用するための詳細をいくらかも説明しました。この記事は Crispy について説明する 2 回シリーズの記事の第 1 回です。次回の記事では、Crispy を使う RESTful アプリケーションの例について、また他のフレームワークを使って Crispy を拡張する方法について説明する予定です。
参考文献 - Crispy Sourceforge の Web サイトで Crispy についての資料を読んでください。
- SOA での Crispy の重要さを知るために、new to SOA を調べてみてください。SOA の紹介記事や、IT やビジネスにとっての SOA の重要性を理解するための記事が豊富に用意されています。
- JAX-RPC に関するヒントを紹介した記事として、「Web サービスのヒント: JAX-RPC と JAX-WS」を読んでください。
- XML-RPC を使った Web サービスを紹介した記事として、「PerlでXML-RPCを始めよう 第2回:XML-RPC Middleware」を読んでください。
著者について  | 
|  | Sachin Mahajan は技術的な業務や監督者としての業務を含め、ソフトウェア開発に 9 年を超える経験があります。現在は IBM が提供する SaaS である LotusLive の開発チームで業務を行っています。 |
記事の評価
|