S2Remoting実装トライアル(その3)

引き続き、RmiAdaptorの実装クラスにトライ。

5. RmiAdaptorImpl

またまた、ひがさんのblogから引用します。

Adaptorは、自分が登録されているコンテナから指定されたコンポーネントを 取得し、seasar.beans.BeanDesc経由でメソッドを実行します。

後は実行した結果が、Adaptor->Connector->ConnectorAdvice->クライアント 経由で戻ります。


BeanDescとはなんぞや?というわけでソースを見てみると、、、ありました。
今はorg.seasar.framework.beans.BeanDescにパッケージが変更になっているようです。

詳細まで読んではいませんが、invokeメソッドは正体不明のClassオブジェクトに対して、
そのクラスが持つであろうメソッド名称と引数を渡すと、メソッドが実行できるという仕組みのようです。
う〜む。素晴らしい。

ちなみに、メソッドの引数や戻り値がプリミティブな場合はどうすれば良いのだろう?
まぁ、それはちょっと置いて、まずは先に進みます。


自分が登録されているコンテナから指定されたコンポーネントを取得するには、
S2Containerオブジェクトが必要になります。

しかし、ひがさんのサーバ側ダイコン定義にはそのような定義がない。。。



おっ、ドキュメントを見ると、自動セッターインジェクションなるものがありますね!
これを利用してみます。

package sample.seasar.remoting.impl;

import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;

import org.seasar.framework.beans.BeanDesc;
import org.seasar.framework.beans.factory.BeanDescFactory;
import org.seasar.framework.container.S2Container;

import sample.seasar.remoting.RmiAdaptor;

/**
 * @author murata
 */
public class RmiAdaptorImpl extends UnicastRemoteObject implements RmiAdaptor
{
  private S2Container container;

  /**
   * @throws RemoteException
   */
  public RmiAdaptorImpl() throws RemoteException
  {
    super();
  }

  /**
   * @param container
   *          The container to set.
   */
  public void setContainer(S2Container container)
  {
    this.container = container;
  }

  /*
   * (non-Javadoc)
   * 
   * @see org.seasar.remoting.RmiAdaptor#invoke(java.lang.String,
   *      java.lang.String, java.lang.Object[])
   */
  public Object invoke(String targetName, String methodName, Object[] args)
      throws RemoteException
  {
    Object targetObj = this.container.getComponent(targetName);

    BeanDesc beanDesc = BeanDescFactory.getBeanDesc(targetObj.getClass());

    return beanDesc.invoke(targetObj, methodName, args);
  }
}

これで一先ずS2Remotingのサンプル実装が完了です。
う〜む。インタフェース2つ、クラスが3つで計5ファイルですね。

次は、examples&diconファイルです。

6. Hello, HelloImpl

これはひがさんのblogにあるものそのままです。

package examples.remoting;

/**
 * @author murata
 */
public interface Hello
{
  public String say();
}
package examples.remoting;

/**
 * @author murata
 */
public class HelloImpl implements Hello
{
  public String say()
  {
    return "Hello";
  }
}

続いて、diconファイル。

7. server.dicon, client.dicon

まずはサーバ側のdiconファイル(server.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="traceInterceptor"
    class="org.seasar.framework.aop.interceptors.TraceInterceptor"/>
  <component name="hello" class="examples.remoting.HelloImpl">
    <aspect>traceInterceptor</aspect>
  </component>
  <component class="sample.seasar.remoting.impl.RmiAdaptorImpl">
    <aspect>traceInterceptor</aspect>
  </component>
</components>

そして、クライアント側のdiconファイル(client.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="traceInterceptor"
    class="org.seasar.framework.aop.interceptors.TraceInterceptor"/>
  <component name="rmiConnector" class="sample.seasar.remoting.impl.RmiConnectorImpl">
    <initMethod name="addURL">
       <arg>'rmi://localhost/RmiAdaptor'</arg>
    </initMethod>
    <aspect>traceInterceptor</aspect>
  </component>
  <component class="examples.remoting.Hello">
    <aspect>traceInterceptor</aspect>
    <aspect>
      <component class="sample.seasar.remoting.interceptor.S2RemotingInterceptor">
        <property name="connector">rmiConnector</property>
        <property name="componentName">'hello'</property>
      </component>
    </aspect>
  </component>
</components>

あとは、Mainクラスの作成です。

8. ServerMian

package examples.remoting;

import java.rmi.Naming;
import java.rmi.RMISecurityManager;

import org.seasar.framework.container.S2Container;
import org.seasar.framework.container.factory.S2ContainerFactory;

import sample.seasar.remoting.RmiAdaptor;

/**
 * @author murata
 */
public class ServerMain
{
  public static void main(String[] args)
  {
    S2Container container = S2ContainerFactory
        .create("examples/remoting/server.dicon");
    RmiAdaptor adaptor = (RmiAdaptor) container
        .getComponent(sample.seasar.remoting.impl.RmiAdaptorImpl.class);

    try
    {
      if (System.getSecurityManager() == null)
      {
        System.setSecurityManager(new RMISecurityManager());
      }

      Naming.rebind("//localhost/RmiAdaptor", adaptor);
      System.out.println("Naming.rebind() ---> rmiregistry");
    }
    catch (Exception e)
    {
      e.printStackTrace();
    }
  }
}

9. ClientMain

package examples.remoting;

import org.seasar.framework.container.S2Container;
import org.seasar.framework.container.factory.S2ContainerFactory;

/**
 * @author murata
 */
public class ClientMain
{
  public static void main(String[] args)
  {
    S2Container container = S2ContainerFactory
        .create("examples/remoting/client.dicon");
    Hello hello = (Hello) container.getComponent(examples.remoting.Hello.class);

    System.out.println(hello.say());
  }
}

10. rmicの実行

忘れてました。rmicを実行する必要がありますね。

>rmic org.seasar.remoting.impl.RmiAdaptorImpl

これでスケルトンとスタブが生成できました。

11. いよいよ実行!

まずはrmiregistryの起動。

>rmiregistry

そしてサーバ側(ServerMain)の起動。
ServerMainを起動するにはVMオプションとして以下を設定します。

-Djava.security.policy=file:/C:\eclipse\workspace\s2remoting\bin\java.policy -Djava.rmi.server.codebase=file:/C:\eclipse\workspace\s2remoting\bin\

policyファイルは同じみの内容。

grant {
    permission java.security.AllPermission;
};

すると、サーバ側のコンソールの出力は以下の通り。

Naming.rebind() ---> rmiregistry

そしてクライアント側(ClientMain)の起動。
ClientMainを起動するVMオプションとしては以下を設定します。

-Djava.security.policy=file:/C:\eclipse\workspace\s2remoting\bin\java.policy

クライアント側のコンソール出力は以下の通り。

BEGIN examples.remoting.Hello#say()
BEGIN sample.seasar.remoting.impl.RmiConnectorImpl#invoke(hello, say, [Ljava.lang.Object;@14a55f2)
END sample.seasar.remoting.impl.RmiConnectorImpl#invoke(hello, say, [Ljava.lang.Object;@14a55f2) : Hello
END examples.remoting.Hello#say() : Hello
Hello

この時のサーバ側のコンソールは以下のようになります。

Naming.rebind() ---> rmiregistry
BEGIN sample.seasar.remoting.impl.RmiAdaptorImpl#invoke(hello, say, [Ljava.lang.Object;@3020ad)
BEGIN examples.remoting.HelloImpl#say()
END examples.remoting.HelloImpl#say() : Hello
END sample.seasar.remoting.impl.RmiAdaptorImpl#invoke(hello, say, [Ljava.lang.Object;@3020ad) : Hello

動いてますね!!!