この記事では Crispy について説明します。Crispy の目標は、多種多様なトランスポート (RMI、EJB、JAX-RPC、XML-RPC など) に対するリモート呼び出しの単一エントリー・ポイントを提供することです。Crispy では、プロパティーを使用することでサービス・マネージャーを構成し、このサービス・マネージャーを使ってリモートの API を呼び出します。

Sachin Mahajan, Software Development, IBM

Sachin MahajanSachin Mahajan は技術的な業務や監督者としての業務を含め、ソフトウェア開発に 9 年を超える経験があります。現在は IBM が提供する SaaS である LotusLive の開発チームで業務を行っています。



2009年 5月 07日

はじめに

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 のドキュメントより引用)
Crispy (クライアントとサーバー) のコンポーネント (Crispy のドキュメントより引用)

下記の図 2 は、クライアント・コンポーネントとサーバー・コンポーネントの間の通信の様子を示しています。この図からわかるように、これはクライアントとサーバーとの間の典型的な通信です。メモリー上に表現された (パラメーターや結果などを含む) データは、サーバーへの送信に適したフォーマットに変換されます。これはマーシャリングと呼ばれます。逆の変換はサーバー上でメソッドの実行前に行われ、アンマーシャリングと呼ばれます。

図 2. Crispy のコンポーネント間での通信 (Crispy のドキュメントより引用)
Crispy のコンポーネント間での通信 (Crispy のドキュメントより引用)

クライアント・サイドでは、ServiceManager オブジェクトが動的または静的なプロキシーを作成してサーバーと通信し、プロキシー・オブジェクトのメソッドを呼び出します。サーバーへの呼び出しをマーシャリングする前に、パラメーターを変換するための、オプションとしての呼び出しが行われます。図 3 に示すように、このプロセスは net.sf.crispy.util.Converter.makeSimple を使って行われます。サーバーがリクエストを受信すると、アンマーシャリングが行われ、サーバーは変換されたオブジェクトを net.sf.crispy.util.Converter.makeComplex を使って返送します。

図 3. Crispy でのオブジェクトの変換 (Crispy のドキュメントより引用)
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」を読んでください。

コメント

developerWorks: サイン・イン

必須フィールドは(*)で示されます。


IBM ID が必要ですか?
IBM IDをお忘れですか?


パスワードをお忘れですか?
パスワードの変更

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


お客様が developerWorks に初めてサインインすると、お客様のプロフィールが作成されます。会社名を非表示とする選択を行わない限り、プロフィール内の情報(名前、国/地域や会社名)は公開され、投稿するコンテンツと一緒に表示されますが、いつでもこれらの情報を更新できます。

送信されたすべての情報は安全です。

ディスプレイ・ネームを選択してください



developerWorks に初めてサインインするとプロフィールが作成されますので、その際にディスプレイ・ネームを選択する必要があります。ディスプレイ・ネームは、お客様が developerWorks に投稿するコンテンツと一緒に表示されます。

ディスプレイ・ネームは、3文字から31文字の範囲で指定し、かつ developerWorks コミュニティーでユニークである必要があります。また、プライバシー上の理由でお客様の電子メール・アドレスは使用しないでください。

必須フィールドは(*)で示されます。

3文字から31文字の範囲で指定し

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


送信されたすべての情報は安全です。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=SOA and web services
ArticleID=395553
ArticleTitle=Crispy による Web サービス: 第 1 回: 入門
publish-date=05072009