読者です 読者をやめる 読者になる 読者になる

動的呼び出しクライアント その3 −通信成功−

S2Axis

RPC方式の通信処理

Axis2では、SOAP通信処理をするために、サーバ側では MessageReceiver、クライアント側では ServiceClient というものを利用します。

ドキュメントに載っていないので分からなかったけど、Axis2にもRPC方式の通信方法が用意されているようですね。

    • org.apache.axis2.rpc.receivers.RPCInOnlyMessageReceiver
      • RPC方式で非同期通信を行うためのメッセージ・レシーバー
    • org.apache.axis2.rpc.receivers.RPCMessageReceiver
      • RPC方式で同期通信を行うためのメッセージ・レシーバー
    • org.apache.axis2.rpc.client.RPCServiceClient
      • RPC方式で通信するためのクライアント

axis2-codegen-0.95.jar に含まれるクラスなのですが、WSDLからJavaソースを自動生成のための jar だと思ってS2Axis2の開発環境から外していたために、そんなクラスがあるのに気付かなかったョ(-_-)

上記のクラスのソースを見てみると、OMElement でSOAPメッセージを送受信する部分をラップしているだけのようですね。同じ処理を、自前で半分ぐらい作ってしまいました・・・ハァ。

サーバ

さて、気を取り直して、サーバから見直しです。

デフォルトではメッセージ・レシーバーとして RawXMLINOutMessageReceiver(OMElementを送受信するためのもの)が利用されます。これを、サービスをデプロイする際に、 RPCMessageReceiver が利用されるように指定します。メッセージ・レシーバーはメソッド単位で指定できるのですが、今回はサービスとして公開するメソッド全てに指定しています。

    AxisService service;

    // サービスを生成

    MessageReceiver receiver = new RPCMessageReceiver();
        
    Iterator ite = service.getOperations();
    while(ite.hasNext() == true) {
        AxisOperation ope = (AxisOperation)ite.next();
        ope.setMessageReceiver(receiver);
    }

AxisRpcConnector

リモートのサービスを呼び出す Connector は以下のような感じになります。

public class AxisRpcConnector extends TargetSpecificURLBasedConnector {

    protected AxisService service;

    public void setService(AxisService service) {
        this.service = service;
    }

    protected Object invoke(URL url, Method method, Object args)
            throws Throwable {

        EndpointReference targetEPR = new EndpointReference(url.toString());

        Options options = new Options();
        options.setTo(targetEPR);

        OMElement request = createRequest(url, method, args);

        ServiceClient client = new ServiceClient();
        client.setOptions(options);
        OMElement response = client.sendReceive(request);

        Object returnTypes = new Object { method.getReturnType() };
        Object returnValue = BeanUtil.deserialize(response, returnTypes);

        Object result;
        if (returnValue != null && returnValue.length == 1) {
            result = returnValue[0];
        }
        else {
            result = returnValue;
        }

        return result;
    }

    private OMElement createRequest(URL url, Method method, Object[] args) {
        OMFactory fac = OMAbstractFactory.getOMFactory();

        OMNamespace omNs = fac.createOMNamespace(SchemaGenerator.SCHEMA_TARGET_NAMESPACE,
                                                 SchemaGenerator.SCHEMA_NAMESPACE_PRFIX);

        QName qName = new QName(method.getName());
        OMElement request = BeanUtil.getOMElement(qName, args, null);
        request.setNamespace(omNs);
        return request;
    }

}

RPCServiceClient を使って通信しようとしたら、ネームスペースが設定されていないという原因でエラーになるため、結局、使用できませんでした。まあ、RPCServiceClient でも上と同じような処理を行っているので、問題ないでしょう。

サービス/クライアント

長くなってきましたが、ここからが実際にS2Axis2を利用するところです。
サービス/クライアントとして、OMElementを使用しないクラスを用意します。

  • Echoサービス(インタフェース )
public interface Echo {
    String echo(int id, String message);
}
  • Echoサービス(実装クラス)
public class EchoImpl implements Echo {
    
    public String echo(int id, String message) {
        return "[id = " + id + "] " + message;
    }
}
  • Echoクライアント
    public void test() {
        Echo echo = (Echo) getComponent(Echo.class);

        int    id = 1;
        String msg = "test message";

        String expect = "[id = " + id + "] " + msg;
        String result = echo.echo(id, msg);
        
        assertEquals(expect, result);
        
        System.out.println(result);
    }

diconファイルは、その2で書いた内容とほぼ変わりません。

サーバ起動後、テストクラスであるEchoクライアントを実行すると・・・結果は以下のようになり、無事メッセージが返ってきました。S2Axis2での通信が成功です!!

[id = 1] test message