S2Axis 開発記 プロトタイプその3 動的起動クライアント
入門ばっかりやってないで開発もしろ!! という声が聞こえた気がするのでちょっとだけ準備を進めてみる.
サーバ側はプロトタイプが動いているので,次はクライアントですね.
依頼主であるはぶさんとこではクライアントは .NET らしいのですが,一応 S2Axis としては両方揃っていないとね♪
そのクライアントサイドですが,プログラミングスタイルとしては二通りあるようです.
一つは任意のサービスの任意のメソッドを自由に呼び出す方法.CORBA の DII (Dynamic Invocation Interface) に相当するものですね.これを動的起動と呼びましょう.
もう一つは WSDL から生成したスタブ (Proxy) を使う方法.こちらは静的起動と呼びましょう.
Amazon みたいな外部の Web サービスを利用する場合は静的起動を使うことが多いでしょうか.一方,システム内部のサービスを利用する場合は動的起動の方が多いかも.ま,いずれはどっちも揃えないとね♪
Axis のドキュメントでは,最初に動的起動から説明されています.そこで,まずは動的起動から学習します.
「Axis ユーザガイド」には,とても簡単なサンプルが掲載されています.
public class TestClient { public static void main(String [] args) { try { String endpoint = "http://nagoya.apache.org:5049/axis/services/echo"; Service service = new Service(); Call call = (Call) service.createCall(); call.setTargetEndpointAddress( new java.net.URL(endpoint) ); call.setOperationName(new QName("http://soapinterop.org/", "echoString") ); String ret = (String) call.invoke( new Object[] { "Hello!" } ); System.out.println("Sent 'Hello!', got '" + ret + "'"); } catch (Exception e) { System.err.println(e.toString()); } } }
これだけで Web サービスを呼び出せちゃうんですね.
キーになるのは
Call
というクラス.
こいつに呼び出したい Web サービスのエンドポイント (URL) およびメソッド名を設定して,
-
invoke(Object[])
を呼び出せばいいだけみたい.
後,Web サービスによってはレスポンスメッセージに戻り値の型を設定してくれない場合があるらしいので,
-
setReturnClass(Class)
で希望の戻り値の型を指定した方がよさげだとか.
マジでこれだけ? 楽勝かもぉ〜.
これ,S2Dao みたいに Java の interface
に対する Interceptor を作るとよさげ.
使い方のイメージは
<component class="SomeInterface"> <aspect> <component class="org.seasar.axis.client.DynamicInvocationInterceptor"> <arg>service</arg> <arg>"http://〜"</arg> </component> </aspect> </component>
みたいな.
で,Interceptor ではメソッド名と引数が取れるから,それを Call
に渡してあげれば OK のはず.
クライアントサイドは実装クラスの直接呼び出しとWeb サービスの呼び出しを .dicon ファイルだけで切り替えられます.
本当は準備編として書き始めたのですが,すぐにでも出来そうなのでプロトタイプ編に変更!!
...
うーみゅ,意外と躓いたなぁ.
なんかですね,サンプル通りだとコンパイル通らないよ?
Service#createCall()
が返すのは Axis の Call
じゃなくて,JAX-RPC の Call
なんですけど...
JAX-RPC の Call
には,setReturnCalass(Class)
がないんですけど...
どうやら,Axis の Call
は JAX-RPC の Call
にキャストできるようなので,それで凌ぎました.
というわけで,Interceptor はこんな感じ.
package org.seasar.axis.client; import java.lang.reflect.Method; import java.net.URL; import javax.xml.namespace.QName; import org.aopalliance.intercept.MethodInvocation; import org.apache.axis.client.Call; import org.apache.axis.client.Service; import org.seasar.framework.aop.interceptors.AbstractInterceptor; public class DynamicInvocationInterceptor extends AbstractInterceptor { final private Service service; final private URL url; public DynamicInvocationInterceptor(final Service service, final URL url) { this.service = service; this.url = url; } public Object invoke(final MethodInvocation invocation) throws Throwable { final Method method = invocation.getMethod(); final Call call = (Call) service.createCall(); call.setTargetEndpointAddress(url); call.setOperationName(new QName("http://soapinterop.org/", method .getName())); call.setReturnClass(method.getReturnType()); return call.invoke(invocation.getArguments()); } }
ということで,お試し.
まずはサービスのインタフェース.
package foo; public interface Hello { String say(); }
サービスとか格好良く呼んだところで所詮この程度.(^^;
その実装クラス.
package foo; public class HelloImpl implements Hello { private String message; public HelloImpl(String message) { this.message = message; } public String say() { return message; } }
そしてクライアントの実行用クラス.
package foo; import org.seasar.framework.container.S2Container; import org.seasar.framework.container.factory.SingletonS2ContainerFactory; public class Client { public static void main(String[] args) { SingletonS2ContainerFactory.init(); S2Container container = SingletonS2ContainerFactory.getContainer(); Hello hello = (Hello) container.getComponent(Hello.class); System.out.println(hello.say()); } }
そして app.dicon
.まずはローカルで動かしてみます.
<?xml version="1.0" encoding="Shift_JIS"?> <!DOCTYPE components PUBLIC "-//SEASAR//DTD S2Container//EN" "http://www.seasar.org/dtd/components.dtd" > <components> <component name="hello" class="foo.HelloImpl"> <arg>"Hello, World"</arg> </component> </components>
こいつを実行!!
Hello, World
まぁ,当たり前に動きました.
次に,この app.dicon
をサーバに配置します.
そして,クライアントの app.dicon
を次のように変更します.
<?xml version="1.0" encoding="Shift_JIS"?> <!DOCTYPE components PUBLIC "-//SEASAR//DTD S2Container//EN" "http://www.seasar.org/dtd/components.dtd" > <components> <component name="service" class="org.apache.axis.client.Service"/> <component class="foo.Hello"> <aspect> <component class="org.seasar.axis.client.DynamicInvocationInterceptor"> <arg>service</arg> <arg>new java.net.URL("http://localhost:8080/axis/services/hello")</arg> </component> </aspect> </component> </components>
そしてクライアント用のクラスを実行!!!!
Hello, World
\(^o^)/