碧クライアント - 機能リファレンス

機能リファレンスについて

midoriClientで使われている機能の説明をします。


サンプルプログラムについて


このページで使われているサンプルプログラムは、ダウンロードページのmidoriClientTutorial.zipに含まれています。
なお、サンプルプログラムで呼び出している「CalcService」は、midoriフレームワークのチュートリアルプロジェクトであるmidoriTutorial.zipに含まれているものです。
サンプルプログラムでは、GAE上に動作確認用のテストサーバーとしてあらかじめ公開されているものを呼び出しています。

RPCClient

midoriClientを使ってRPCを行う際に、最も基本となるクラスがRPCClientです。
RPCClientは、指定されたURL、メソッド名に対してRPCを行って、戻り値をJavaのオブジェクトとして取得するシンプルなクラスです。
複数サーバーの呼び出しや、エラー時のリトライなどといった複雑な処理は出来ませんので、そういった処理が必要となる場合は、後述のRPCClientCaller(RPCClientCaller)を使用して下さい。


RPCClientの基本的な使い方


midoriClientTutorialのclient.tutorial.SimpleRPCClientSampleクラスを例にして、RPCClientの基本的な使い方について説明します。


client.tutorial.SimpleRPCClientSample
package client.tutorial;

import jp.fores.midori.client.RPCClient;
import jp.fores.midori.client.handler.BasicRPCHandler;
import jp.fores.midori.client.handler.RPCHandler;
import jp.fores.midori.client.serializer.JsonRPCSerializer;
import jp.fores.midori.client.serializer.RPCSerializer;

/**
 * 最も基本的なRPCClientの使い方のサンプルクラス。<br>
 * 動作確認用のサーバー(http://midori-rpc.appspot.com/)のCalcServiceに対してJSON-RPCを行います。<br>
 */
public class SimpleRPCClientSample {
	//==========================================================
	//メソッド

	//_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
	//クラスメソッド

	/**
	 * メインメソッドです。
	 *
	 * @param args コマンドライン引数
	 * @throws Exception 例外
	 */
	public static void main(String[] args) throws Exception {
		//==========================================================
		//呼び出し先のURL
		String url = "http://midori-rpc.appspot.com/rpc/calcService.json";


		//==========================================================
		//RPCClientの準備

		//RPC形式に応じたシリアライザのインスタンスを生成
		//(JSON-RPCなので、JsonRPCSerializerを使う)
		RPCSerializer serializer = new JsonRPCSerializer();

		//使用するライブラリに応じたハンドラのインスタンスを生成
		//(Java標準ライブラリを使いたいので、BasicRPCHandlerを使う)
		RPCHandler handler = new BasicRPCHandler();

		//シリアライザとハンドラを元にして、RPCClientのインスタンスを生成
		RPCClient rpcClient = new RPCClient(serializer, handler);


		//==========================================================
		//RPCの実行

		//RPCで「addition」メソッドを呼び出す
		//(123, 345は「addition」メソッドに渡す引数)
		Object result = rpcClient.remoteCall(url, "addition", 123, 345);

		//結果の出力
		System.out.println(result);
	}
}
									

RPCClientのインスタンスを生成するには、後述のシリアライザとハンドラを指定する必要があります。
RPCClientでRPCを実際に行うのが、remoteCall()メソッドです。
remoteCall()メソッドには、戻り値の型指定を行わないものと、行うものの二種類があり、それぞれのシグネチャは以下の通りです。

/**
 * リモートプロシージャコール(RPC)を行います。
 *
 * @param url URL
 * @param methodName メソッド名
 * @param args メソッドに渡す引数(可変引数)
 * @return リモートプロシージャコールの戻り値のオブジェクト(戻り値が存在しない場合はnull)
 * @throws Exception 例外
 */
public Object remoteCall(String url, String methodName, Object... args;

/**
 * 戻り値の型指定でリモートプロシージャコール(RPC)を行います。
 *
 * @param <T> 戻り値の型
 * @param returnClass 戻り値の型のクラスオブジェクト
 * @param url URL
 * @param methodName メソッド名
 * @param args メソッドに渡す引数(可変引数)
 * @return リモートプロシージャコールの戻り値のオブジェクト(戻り値が存在しない場合はnull)
 * @throws Exception 例外
 */
public <T> T remoteCall(Class<T> returnClass, String url,
		String methodName, Object... args) throws Exception;
										

戻り値の型指定の機能は、JSON-RPCで通信を行う場合に特に有用です。
JSON-RPCで戻り値の型指定を行わない場合は、戻り値がDTOだった場合の型はjava.util.LinkedHashMapとなってしまいますが、型指定を行うと適切なDTOに変換してくれます。


シリアライザ(RPCSerializer)


シリアライザは、RPC形式に応じたシリアライズ・デシリアライズ処理を行うための仕組みです。
RPC形式に応じて、使用するシリアライザクラスを切り替えて使います。
なお、RPC形式がJavaやHessianで、かつ引数や戻り値の型がDTOのメソッドを呼び出す場合は、クライアント側にもサーバー側と同じDTOクラスが必要となるので注意して下さい。

標準でサポートされているシリアライザは以下の通りです。

クラス名 説明
jp.fores.midori.client.serializer.JavaRPCSerializer Javaシリアライズ用のシリアライザ。
Javaのjava.io.Serializableの仕組みを使ったmidoriフレームワーク独自規格のバイナリ通信。
midoriフレームワークが使われているサーバーをJavaから呼び出す場合には、効率が良い。
このプラグインを使うためには、RPC対象となるメソッドの引数・戻り値ともにjava.io.Serializableインターフェースを実装している必要がある。
jp.fores.midori.client.serializer.JsonRPCSerializer JSON-RPC用のシリアライザ。
対応しているサーバーが多い。
戻り値の型指定を行わない場合は、戻り値がDTOだった場合の型はjava.util.LinkedHashMapとなる。
jp.fores.midori.client.serializer.HessianRPCSerializer Hessian用のシリアライザ。
メソッドのオーバーロードには対応していないので注意。
また、Androidからは使用できないので注意。


ハンドラ(RPCHandler)


ハンドラは、RPCを行う際に使用する通信処理を切り替えるための仕組みです。
標準でサポートされているハンドラは以下の通りです。

クラス名 説明
jp.fores.midori.client.handler.BasicRPCHandler ハンドラの最も基本的な実装クラス。
Java標準のjava.net.HttpURLConnectionクラスを使って処理を行う。
処理効率はそれほど良くないが、通信用のライブラリを別途用意する必要がないというメリットがある。
jp.fores.midori.client.handler.HttpClientRPCHandler HttpClientを使った実装クラス。
Apache HttpComponentsのorg.apache.http.client.HttpClientクラスを使って処理を行う。
jp.fores.midori.client.handler.HttpCoreRPCHandler HttpCoreを使った実装クラス。
Apache HttpComponentsのorg.apache.http.protocol.HttpRequestExecutorクラスを使って処理を行う。
jp.fores.midori.client.handler.HttpCoreNioRPCHandler HttpCore-NIOを使った実装クラス。
Apache HttpComponentsのorg.apache.http.nio.reactor.ConnectingIOReactorクラスを使って処理を行う。


RPCClientのオプション


RPCClientはそのままの設定でも使えますが、オプションを変更することできめ細かい設定が可能です。
オプションは全てRPCClientクラスのpublicフィールドとして公開されています。
RPCClientのオプション一覧を以下に示します。

フィールド名 デフォルト値 説明
requestGZip false リクエスト送信時にgzip圧縮を行うかどうかのフラグ。
サーバー側が対応していないと、エラーになってしまう可能性があるので注意して下さい。
また、midoriフレームワークでは対応しているが、それ以外では対応しているサーバーが少ないので注意して下さい。
この機能を有効にすることにより、通信量を軽減することができますが、反面gzipの圧縮・展開処理のためクライアント・サーバー側ともにCPU使用量は増えるので注意して下さい。
responseGZip false レスポンスでgzip圧縮を受け入れるかどうかのフラグ。
サーバー側が対応していないと、エラーになってしまう可能性があるので注意して下さい。
この機能を有効にすることにより、通信量を軽減することができますが、反面gzipの圧縮・展開処理のためクライアント・サーバー側ともにCPU使用量は増えるので注意して下さい。
isGAE false GAE用かどうかのフラグ。
呼び出し先のサーバー側がGAEの場合は、trueを指定して下さい。
connectTimeout 200 接続タイムアウト時間(単位=ミリ秒)。
0以下の値を指定すると、タイムアウトしなくなります。
readTimeout 0 読み取りタイムアウト時間(単位=ミリ秒)。
0以下の値を指定すると、タイムアウトしなくなります。
requestMethod POST リクエストメソッド。
POST以外の値(GETやPUT, DELETE)を指定する場合に変更して下さい。
ただし、RPCの仕様上、POST以外は受け付けないサーバーが大半なので注意して下さい。


RPCClientの少し複雑な使い方のサンプル


midoriClientTutorialのclient.tutorial.ComplexRPCClientSampleクラスは、今まで説明してきた機能を使った少し複雑なサンプルプログラムです。


client.tutorial.ComplexRPCClientSample
package client.tutorial;

import jp.fores.midori.client.RPCClient;
import jp.fores.midori.client.handler.BasicRPCHandler;
import jp.fores.midori.client.handler.RPCHandler;
import jp.fores.midori.client.serializer.JsonRPCSerializer;
import jp.fores.midori.client.serializer.RPCSerializer;
import tutorial.dto.CalcResultDto;

/**
 * RPCClientの少し複雑な使い方のサンプルクラス。<br>
 * 動作確認用のサーバー(http://midori-rpc.appspot.com/)のCalcServiceに対してRPCを行います。<br>
 */
public class ComplexRPCClientSample {
	//==========================================================
	//メソッド

	//_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
	//クラスメソッド

	/**
	 * メインメソッドです。
	 *
	 * @param args コマンドライン引数
	 * @throws Exception 例外
	 */
	public static void main(String[] args) throws Exception {
		//==========================================================
		//呼び出し先のURL
		//(midoriフレームワークでは、通信方式に応じて拡張子が変わるので注意)

		String url = "http://midori-rpc.appspot.com/rpc/calcService.json";
		//String url = "http://midori-rpc.appspot.com/rpc/calcService.java";
		//String url = "http://midori-rpc.appspot.com/rpc/calcService.hessian";


		//==========================================================
		//RPCClientの準備

		//_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
		//シリアライザ

		//RPC形式に応じたシリアライザのインスタンスを生成
		RPCSerializer serializer = new JsonRPCSerializer();
		//RPCSerializer serializer = new JavaRPCSerializer();
		//RPCSerializer serializer = new HessianRPCSerializer();


		//_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
		//ハンドラ

		//使用するライブラリに応じたハンドラのインスタンスを生成
		RPCHandler handler = new BasicRPCHandler();
		//RPCHandler handler = new HttpClientRPCHandler();
		//RPCHandler handler = new HttpCoreRPCHandler();
		//RPCHandler handler = new HttpCoreNioRPCHandler();


		//_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
		//RPCClient

		//シリアライザとハンドラを元にして、RPCClientのインスタンスを生成
		RPCClient rpcClient = new RPCClient(serializer, handler);

		//リクエスト送信時にgzip圧縮を行うかどうかのフラグ
		rpcClient.requestGZip = true;

		//レスポンスでgzip圧縮を受け入れるかどうかのフラグ
		rpcClient.responseGZip = true;

		//GAE用かどうかのフラグ
		rpcClient.isGAE = true;

		//接続タイムアウト時間(単位=ミリ秒)
		rpcClient.connectTimeout = 3000;

		//読み取りタイムアウト時間(単位=ミリ秒)
		rpcClient.readTimeout = 10000;

		//リクエストメソッド
		rpcClient.requestMethod = "PUT";


		//==========================================================
		//RPCの実行

		//RPCで「operation」メソッドを呼び出す
		//(戻り値の型指定を行う)
		//(64, 4は「operation」メソッドに渡す引数)
		CalcResultDto result = rpcClient.remoteCall(CalcResultDto.class, url, "operation", 64, 4);

		//結果の出力
		System.out.println("足し算=" + result.addition + ", 引き算="
				+ result.subtraction + ", かけ算=" + result.multiplication
				+ ", 割り算=" + result.division);
	}
}
									

RPCClientCaller

RPCClientCallerは、RPCClientをラッピングして、複数のサーバーに対してRPCを行うための仕組みです。
基本的なRPCClientCallerとしては、複数のサーバーに対して順番にRPCを行うSequenceRPCClientCallerと、並列にRPCを行うParallelRPCClientCallerの二種類があります。
さらにRPCClientCaller自体の機能を拡張するためのラッピングクラスとして、繰り返し機能を付与するRepeatRPCClientCallerと、タイムアウト機能を付与するTimeoutRPCClientCallerがあります。
RPCClientCallerを使用する場合、サーバーは必ずしも複数存在しなければならないわけではなく、単一サーバーの呼び出しの場合にも使用できます。

標準でサポートされているRPCClientCallerは以下の通りです。

クラス名 説明
jp.fores.midori.client.caller.SequenceRPCClientCaller 複数のサーバーに対して順番にRPCを行う実装クラス。
シングルスレッドで1つ1つのサーバーに対して順番に処理を行います。
エラーが返ってきた場合や、タイムアウトになった場合は次のサーバーに処理が移ります。
jp.fores.midori.client.caller.ParallelRPCClientCaller 複数のサーバーに対して並列にRPCを行う実装クラス。
マルチスレッドを使って処理を行います。
同等の機能を持つサーバーが複数存在し、処理効率よりも処理速度を重視する場合にお勧めです。
更新系の処理を呼び出す場合は、複数のサーバーでそれぞれ更新処理が行われることになるので、副作用に注意して下さい。

オプション
・並列実行するスレッド数
jp.fores.midori.client.caller.RepeatRPCClientCaller 複数のサーバーに対して繰り返し回数指定付きでRPCを行うようにするための、RPCClientCallerのラッパークラス。
他のRPCClientCallerに繰り返し機能を付与するためのクラスなので、このクラスは単独では使用できません。
あくまでも繰り返し処理を行うのはエラー時だけなので、RPC呼び出しに成功した時点で処理を抜けます。
TimeoutRPCClientCallerと組み合わせて使用することもできます。

オプション
・繰り返し回数(0以下の値が指定された場合は成功するまで繰り返す)
・リトライまでの待ち時間
・リトライまでの待ち時間を倍々にしていく方式を使用するかどうかのフラグ(true=倍々にしていく, false=そのまま)
・リトライまでの最大待ち時間
jp.fores.midori.client.caller.TimeoutRPCClientCaller 複数のサーバーに対してタイムアウト指定付きでRPCを行うようにするための、RPCClientCallerのラッパークラス。
他のRPCClientCallerにタイムアウト機能を付与するためのクラスなので、このクラスは単独では使用できません。
RepeatRPCClientCallerと組み合わせて使用することもできます。

オプション
・タイムアウト時間


RPCClientCallerの基本的な使い方


midoriClientTutorialのclient.tutorial.SimpleRPCClientCallerSampleクラスを例にして、RPCClientCallerの基本的な使い方について説明します。


client.tutorial.SimpleRPCClientCallerSample
package client.tutorial;

import jp.fores.midori.client.RPCClient;
import jp.fores.midori.client.caller.GeneralURLListGetter;
import jp.fores.midori.client.caller.RPCClientCaller;
import jp.fores.midori.client.caller.SequenceRPCClientCaller;
import jp.fores.midori.client.caller.URLListGetter;
import jp.fores.midori.client.handler.BasicRPCHandler;
import jp.fores.midori.client.handler.RPCHandler;
import jp.fores.midori.client.serializer.JsonRPCSerializer;
import jp.fores.midori.client.serializer.RPCSerializer;

/**
 * 最も基本的なRPCClientCallerの使い方のサンプルクラス。<br>
 * 動作確認用の3つのサーバー(http://1.latest.midori-rpc.appspot.com/, http://2.latest.midori-rpc.appspot.com/, 
 * http://3.latest.midori-rpc.appspot.com/)のCalcServiceに対してJSON-RPCを行います。<br>
 */
public class SimpleRPCClientCallerSample {
	//==========================================================
	//メソッド

	//_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
	//クラスメソッド

	/**
	 * メインメソッドです。
	 *
	 * @param args コマンドライン引数
	 * @throws Exception 例外
	 */
	public static void main(String[] args) throws Exception {
		//==========================================================
		//呼び出し先のURL
		//(複数存在するので配列)
		String[] urlArray = new String[] {
				"http://1.latest.midori-rpc.appspot.com/rpc/calcService.json",
				"http://2.latest.midori-rpc.appspot.com/rpc/calcService.json",
				"http://3.latest.midori-rpc.appspot.com/rpc/calcService.json" };

		//呼び出し先のURLに応じたURLListGetterのインスタンスを生成
		URLListGetter urlListGetter = new GeneralURLListGetter(urlArray);


		//==========================================================
		//RPCClientの準備

		//RPC形式に応じたシリアライザのインスタンスを生成
		//(JSON-RPCなので、JsonRPCSerializerを使う)
		RPCSerializer serializer = new JsonRPCSerializer();

		//使用するライブラリに応じたハンドラのインスタンスを生成
		//(Java標準ライブラリを使いたいので、BasicRPCHandlerを使う)
		RPCHandler handler = new BasicRPCHandler();

		//シリアライザとハンドラを元にして、RPCClientのインスタンスを生成
		RPCClient rpcClient = new RPCClient(serializer, handler);


		//==========================================================
		//RPCClientCallerの準備

		//複数のサーバーに対して順番にRPCを行うRPCClientCallerの実装クラスのインスタンスを生成
		RPCClientCaller caller = new SequenceRPCClientCaller(rpcClient);


		//==========================================================
		//RPCの実行

		//RPCで「addition」メソッドを呼び出す
		//(123, 345は「addition」メソッドに渡す引数)
		Object result = caller.remoteCall(urlListGetter, "addition", 123, 345);

		//結果の出力
		System.out.println(result);
	}
}
									

RPCClientCallerでRPCを実際に行うのが、remoteCall()メソッドです。
remoteCall()メソッドには、戻り値の型指定を行わないものと、行うものの二種類があり、それぞれのシグネチャは以下の通りです。

/**
 * 複数のサーバーに対してリモートプロシージャコール(RPC)を行います。
 *
 * @param urlListGetter サーバーのURLのリストを返すインターフェース
 * @param methodName メソッド名
 * @param args メソッドに渡す引数(可変引数)
 * @return リモートプロシージャコールの戻り値のオブジェクト(戻り値が存在しない場合はnull)
 * @throws Exception 例外
 */
public Object remoteCall(URLListGetter urlListGetter, String methodName,
		Object... args) throws Exception;

/**
 * 複数のサーバーに対して戻り値の型指定でリモートプロシージャコール(RPC)を行います。
 *
 * @param <T> 戻り値の型
 * @param returnClass 戻り値の型のクラスオブジェクト
 * @param urlListGetter サーバーのURLのリストを返すインターフェース
 * @param methodName メソッド名
 * @param args メソッドに渡す引数(可変引数)
 * @return リモートプロシージャコールの戻り値のオブジェクト(戻り値が存在しない場合はnull)
 * @throws Exception 例外
 */
public <T> T remoteCall(Class<T> returnClass, URLListGetter urlListGetter,
		String methodName, Object... args) throws Exception;
										

RPCClientCallerのremoteCall()メソッドは、RPCClientのものと非常によく似ていますが、URLを指定する方法が単純なStringではなく、URLListGetterという点だけが異なります。


URLListGetter


URLListGetterは、RPCClientCallerを使って複数のサーバーに対してRPCを行う際に、対象のURLを指定するための仕組みです。
標準でサポートされているURLListGetterは以下の通りです。

クラス名 説明
jp.fores.midori.client.caller.GeneralURLListGetter URLListGetterの汎用実装クラス。
対象のURLを、単一のURL、URLのリスト、URLの配列の3種類の方法で指定できます。


RepeatRPCClientCallerとTimeoutRPCClientCallerの組み合わせ


RepeatRPCClientCallerとTimeoutRPCClientCallerは同時に使用することもできますが、使用する順番によって挙動が変化します。
RepeatRPCClientCallerをTimeoutRPCClientCallerでラッピングした場合は、RPC処理全体のタイムアウト時間を指定することになります。
逆に、TimeoutRPCClientCallerをRepeatRPCClientCallerでラッピングした場合は、タイムアウト付きのRPC自体を複数回繰り返すことになります。

効果的な組み合わせ方法の一例としては、RepeatRPCClientCallerの繰り返し回数に-1(成功するまで無限に繰り返す)を設定したものを、TimeoutRPCClientCallerでラッピングするという方法があります。
この場合、処理が成功するかタイムアウトになるまでRPCを繰り返し行う設定となります。


RPCClientCallerの少し複雑な使い方のサンプル


midoriClientTutorialのclient.tutorial.ComplexRPCClientCallerSampleクラスは、複数のRPCClientCallerを組み合わせた少し複雑なサンプルプログラムです。


client.tutorial.ComplexRPCClientCallerSample
package client.tutorial;

import jp.fores.midori.client.RPCClient;
import jp.fores.midori.client.caller.GeneralURLListGetter;
import jp.fores.midori.client.caller.ParallelRPCClientCaller;
import jp.fores.midori.client.caller.RPCClientCaller;
import jp.fores.midori.client.caller.RepeatRPCClientCaller;
import jp.fores.midori.client.caller.TimeoutRPCClientCaller;
import jp.fores.midori.client.caller.URLListGetter;
import jp.fores.midori.client.handler.BasicRPCHandler;
import jp.fores.midori.client.handler.RPCHandler;
import jp.fores.midori.client.serializer.JsonRPCSerializer;
import jp.fores.midori.client.serializer.RPCSerializer;
import tutorial.dto.CalcResultDto;

/**
 * RPCClientCallerの少し複雑な使い方のサンプルクラス。<br>
 * 動作確認用の3つのサーバー(http://1.latest.midori-rpc.appspot.com/, http://2.latest.midori-rpc.appspot.com/, 
 * http://3.latest.midori-rpc.appspot.com/)のCalcServiceに対してJSON-RPCを行います。<br>
 */
public class ComplexRPCClientCallerSample {
	//==========================================================
	//メソッド

	//_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
	//クラスメソッド

	/**
	 * メインメソッドです。
	 *
	 * @param args コマンドライン引数
	 * @throws Exception 例外
	 */
	public static void main(String[] args) throws Exception {
		//==========================================================
		//呼び出し先のURL
		//(複数存在するので配列)
		String[] urlArray = new String[] {
				"http://1.latest.midori-rpc.appspot.com/rpc/calcService.json",
				"http://2.latest.midori-rpc.appspot.com/rpc/calcService.json",
				"http://3.latest.midori-rpc.appspot.com/rpc/calcService.json" };

		//呼び出し先のURLに応じたURLListGetterのインスタンスを生成
		URLListGetter urlListGetter = new GeneralURLListGetter(urlArray);


		//==========================================================
		//RPCClientの準備

		//RPC形式に応じたシリアライザのインスタンスを生成
		//(JSON-RPCなので、JsonRPCSerializerを使う)
		RPCSerializer serializer = new JsonRPCSerializer();

		//使用するライブラリに応じたハンドラのインスタンスを生成
		//(Java標準ライブラリを使いたいので、BasicRPCHandlerを使う)
		RPCHandler handler = new BasicRPCHandler();

		//シリアライザとハンドラを元にして、RPCClientのインスタンスを生成
		RPCClient rpcClient = new RPCClient(serializer, handler);


		//==========================================================
		//RPCClientCallerの準備

		//複数のサーバーに対して並列にRPCを行うRPCClientCallerの実装クラスのインスタンスを生成
		RPCClientCaller caller = new ParallelRPCClientCaller(rpcClient);

		//並列ではなく、順番にRPCを行う場合はこちら
		//RPCClientCaller caller = new SequenceRPCClientCaller(rpcClient);

		//繰り返し回数指定付きでRPCを行えるようにするために、RepeatRPCClientCallerでラッピングする
		//(成功するまで、無限に繰り返したいので-1を指定する)
		caller = new RepeatRPCClientCaller(caller, -1);

		//さらに、タイムアウト指定付きでRPCを行えるようにするために、TimeoutRPCClientCallerでラッピングする
		//(全体のタイムアウト時間として、10000ミリ秒(10秒)を指定する)
		caller = new TimeoutRPCClientCaller(caller, 10000);


		//==========================================================
		//RPCの実行

		//RPCで「operation」メソッドを呼び出す
		//(戻り値の型指定を行う)
		//(64, 4は「operation」メソッドに渡す引数)
		CalcResultDto result = caller.remoteCall(CalcResultDto.class, urlListGetter, 
									"operation", 64, 4);

		//結果の出力
		System.out.println("足し算=" + result.addition + ", 引き算="
				+ result.subtraction + ", かけ算=" + result.multiplication
				+ ", 割り算=" + result.division);
	}
}
									

プロキシ

RPC対象のクラスに対するインターフェース定義が存在する場合は、プロキシインスタンスを使った呼び出しを行うことができます。
プロキシインスタンスを使う場合、通常のremoteCall()メソッドを使う場合に比べて、次のようなメリットがあります。

  • RPC呼び出しが、あたかも通常のクラス呼び出しのように行える。
  • メソッド名や引数、戻り値の型が間違っている場合には、コンパイルエラーで知らせてくれる。
  • 戻り値の型補正を自動で行ってくれる。

プロキシインスタンスは、RPCProxyFactory.createProxy()メソッドを使って作成します。
createProxy()メソッドには、RPCClientを引数にとるものと、RPCClientCallerを引数にとるものの二種類があり、それぞれのシグネチャは以下の通りです。
/**
 * 対象のインターフェースに対応する、リモートプロシージャーコール(RPC)を行うプロキシインスタンスを作成します。
 *
 * @param <T> 対象のインターフェースの型
 * @param targetInterface 対象のインターフェースのクラスオブジェクト
 * @param url URL
 * @param rpcClient リモートプロシージャーコールを行うクライアントクラス
 * @return 作成したプロキシインスタンス
 * @throws IllegalArgumentException 指定されたクラスオブジェクトがインターフェースを表していない場合
 */
public static <T> T createProxy(Class<T> targetInterface, String url,
		RPCClient rpcClient) throws IllegalArgumentException;

/**
 * 対象のインターフェースに対応する、複数のサーバーに対してリモートプロシージャーコール(RPC)を行うプロキシインスタンスを作成します。
 *
 * @param <T> 対象のインターフェースの型
 * @param targetInterface 対象のインターフェースのクラスオブジェクト
 * @param urlListGetter サーバーのURLのリストを返すインターフェース
 * @param caller 複数のサーバーに対してリモートプロシージャーコールを行うインターフェース
 * @return 作成したプロキシインスタンス
 * @throws IllegalArgumentException 指定されたクラスオブジェクトがインターフェースを表していない場合
 */
public static <T> T createProxy(Class<T> targetInterface,
		URLListGetter urlListGetter, RPCClientCaller caller)
		throws IllegalArgumentException;
										


プロキシインスタンス経由でのRPCClientの使い方


midoriClientTutorialのclient.tutorial.RPCClientProxySampleクラスは、プロキシインスタンス経由でのRPCClientの使い方のサンプルプログラムです。


client.tutorial.RPCClientProxySample
package client.tutorial;

import jp.fores.midori.client.RPCClient;
import jp.fores.midori.client.handler.BasicRPCHandler;
import jp.fores.midori.client.handler.RPCHandler;
import jp.fores.midori.client.proxy.RPCProxyFactory;
import jp.fores.midori.client.serializer.JsonRPCSerializer;
import jp.fores.midori.client.serializer.RPCSerializer;
import tutorial.CalcServiceInterface;
import tutorial.dto.CalcResultDto;

/**
 * プロキシインスタンス経由でのRPCClientの使い方のサンプルクラス。<br>
 * 動作確認用のサーバー(http://midori-rpc.appspot.com/)のCalcServiceに対してJSON-RPCを行います。<br>
 */
public class RPCClientProxySample {
	//==========================================================
	//メソッド

	//_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
	//クラスメソッド

	/**
	 * メインメソッドです。
	 *
	 * @param args コマンドライン引数
	 * @throws Exception 例外
	 */
	public static void main(String[] args) throws Exception {
		//==========================================================
		//呼び出し先のURL
		String url = "http://midori-rpc.appspot.com/rpc/calcService.json";


		//==========================================================
		//RPCClientの準備

		//RPC形式に応じたシリアライザのインスタンスを生成
		//(JSON-RPCなので、JsonRPCSerializerを使う)
		RPCSerializer serializer = new JsonRPCSerializer();

		//使用するライブラリに応じたハンドラのインスタンスを生成
		//(Java標準ライブラリを使いたいので、BasicRPCHandlerを使う)
		RPCHandler handler = new BasicRPCHandler();

		//シリアライザとハンドラを元にして、RPCClientのインスタンスを生成
		RPCClient rpcClient = new RPCClient(serializer, handler);


		//==========================================================
		//プロキシインスタンスの作成
		//(ここで、CalcServiceInterfaceはRPC対象の「CalcService」と同じシグネチャを持つインターフェース)
		CalcServiceInterface proxy = RPCProxyFactory.createProxy(CalcServiceInterface.class, url, 
										rpcClient);


		//==========================================================
		//RPCの実行

		//プロキシインスタンスの「operation」メソッドを呼び出す
		CalcResultDto result = proxy.operation(64, 4);

		//結果の出力
		System.out.println("足し算=" + result.addition + ", 引き算="
				+ result.subtraction + ", かけ算=" + result.multiplication
				+ ", 割り算=" + result.division);
	}
}
									

プロキシインスタンス経由でのRPCClientCallerの使い方


midoriClientTutorialのclient.tutorial.RPCClientCallerProxySampleクラスは、プロキシインスタンス経由でのRPCClientCallerの使い方のサンプルプログラムです。


client.tutorial.RPCClientCallerProxySample
package client.tutorial;

import jp.fores.midori.client.RPCClient;
import jp.fores.midori.client.caller.GeneralURLListGetter;
import jp.fores.midori.client.caller.ParallelRPCClientCaller;
import jp.fores.midori.client.caller.RPCClientCaller;
import jp.fores.midori.client.caller.RepeatRPCClientCaller;
import jp.fores.midori.client.caller.TimeoutRPCClientCaller;
import jp.fores.midori.client.caller.URLListGetter;
import jp.fores.midori.client.handler.BasicRPCHandler;
import jp.fores.midori.client.handler.RPCHandler;
import jp.fores.midori.client.proxy.RPCProxyFactory;
import jp.fores.midori.client.serializer.JsonRPCSerializer;
import jp.fores.midori.client.serializer.RPCSerializer;
import tutorial.CalcServiceInterface;
import tutorial.dto.CalcResultDto;

/**
 * プロキシインスタンス経由でのRPCClientCallerの使い方のサンプルクラス。<br>
 * 動作確認用の3つのサーバー(http://1.latest.midori-rpc.appspot.com/, http://2.latest.midori-rpc.appspot.com/, 
 * http://3.latest.midori-rpc.appspot.com/)のCalcServiceに対してJSON-RPCを行います。<br>
 */
public class RPCClientCallerProxySample {
	//==========================================================
	//メソッド

	//_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
	//クラスメソッド

	/**
	 * メインメソッドです。
	 *
	 * @param args コマンドライン引数
	 * @throws Exception 例外
	 */
	public static void main(String[] args) throws Exception {
		//==========================================================
		//呼び出し先のURL
		//(複数存在するので配列)
		String[] urlArray = new String[] {
				"http://1.latest.midori-rpc.appspot.com/rpc/calcService.json",
				"http://2.latest.midori-rpc.appspot.com/rpc/calcService.json",
				"http://3.latest.midori-rpc.appspot.com/rpc/calcService.json" };

		//呼び出し先のURLに応じたURLListGetterのインスタンスを生成
		URLListGetter urlListGetter = new GeneralURLListGetter(urlArray);


		//==========================================================
		//RPCClientの準備

		//RPC形式に応じたシリアライザのインスタンスを生成
		//(JSON-RPCなので、JsonRPCSerializerを使う)
		RPCSerializer serializer = new JsonRPCSerializer();

		//使用するライブラリに応じたハンドラのインスタンスを生成
		//(Java標準ライブラリを使いたいので、BasicRPCHandlerを使う)
		RPCHandler handler = new BasicRPCHandler();

		//シリアライザとハンドラを元にして、RPCClientのインスタンスを生成
		RPCClient rpcClient = new RPCClient(serializer, handler);


		//==========================================================
		//RPCClientCallerの準備

		//複数のサーバーに対して並列にRPCを行うRPCClientCallerの実装クラスのインスタンスを生成
		RPCClientCaller caller = new ParallelRPCClientCaller(rpcClient);

		//並列ではなく、順番にRPCを行う場合はこちら
		//RPCClientCaller caller = new SequenceRPCClientCaller(rpcClient);

		//繰り返し回数指定付きでRPCを行えるようにするために、RepeatRPCClientCallerでラッピングする
		//(成功するまで、無限に繰り返したいので-1を指定する)
		caller = new RepeatRPCClientCaller(caller, -1);

		//さらに、タイムアウト指定付きでRPCを行えるようにするために、TimeoutRPCClientCallerでラッピングする
		//(全体のタイムアウト時間として、10000ミリ秒(10秒)を指定する)
		caller = new TimeoutRPCClientCaller(caller, 10000);


		//==========================================================
		//プロキシインスタンスの作成
		//(ここで、CalcServiceInterfaceはRPC対象の「CalcService」と同じシグネチャを持つインターフェース)
		CalcServiceInterface proxy = RPCProxyFactory.createProxy(CalcServiceInterface.class, 
										urlListGetter, caller);


		//==========================================================
		//RPCの実行

		//プロキシインスタンスの「operation」メソッドを呼び出す
		CalcResultDto result = proxy.operation(64, 4);

		//結果の出力
		System.out.println("足し算=" + result.addition + ", 引き算="
				+ result.subtraction + ", かけ算=" + result.multiplication
				+ ", 割り算=" + result.division);
	}
}