S2EJB3

S2Remotingを見てみました。Connectorを作ればいいということですね。必ずしも必要ないのですがRemotingInterceptorを継承したInterceptorも作ってみました。

まずConnector。
Ejb3Connector:JNDIからEJBをlookupしてリフレクションで呼び出す。

import java.lang.reflect.Method;
import javax.naming.InitialContext;
import org.seasar.framework.beans.BeanDesc;
import org.seasar.framework.beans.factory.BeanDescFactory;
import org.seasar.framework.util.InitialContextUtil;
import org.seasar.remoting.common.connector.Connector;

public class Ejb3Connector implements Connector {

  private final InitialContext initialContext;

  public Ejb3Connector(InitialContext initialContext) {
    this.initialContext = initialContext;
  }

  public Object invoke(String name, Method method, Object[] args)
      throws Exception {
    Object ejb = InitialContextUtil.lookup(initialContext, name);
    BeanDesc beanDesc = BeanDescFactory.getBeanDesc(ejb.getClass());
    return beanDesc.invoke(ejb, method.getName(), args);
  }
}


次にInterceptor。
Ejb3Interceptor:RemotingInterceptorを継承している。クラス名にprefixやsuffixをつけてJNDI名をつくることができます。

import org.aopalliance.intercept.MethodInvocation;
import org.seasar.framework.container.ComponentDef;
import org.seasar.remoting.common.interceptor.RemotingInterceptor;

public class Ejb3Interceptor extends RemotingInterceptor {

  private String prefix = "";

  private String suffix = "";

  public void setPrefix(String prefix) {
    this.prefix = prefix;
  }

  public void setSuffix(String suffix) {
    this.suffix = suffix;
  }

  @Override
  protected String getRemoteName(MethodInvocation invocation) {
    if (remoteName != null) {
      return getJndiName(remoteName);
    }
    final ComponentDef componentDef = getComponentDef(invocation);
    final Class componentClass = componentDef.getComponentClass();
    return getJndiName(componentClass.getName());
  }

  private String getJndiName(String name) {
    return prefix + name + suffix;
  }
}


diconファイル:太字のところが注目ポイント。この設定の場合、remoteEjb3インターセプタはクラス名 + RemoteのJNDI名でEJBにアクセスします。クラス名がそのままJNDI名のときはejb3インターセプタが使えます。Ejb3Interceptorを使わないでorg.seasar.remoting.common.interceptor.RemotingInterceptorを使う場合の例は一番下にコメントアウトしてあります、JNDI名がクラス名と無関係の場合はこんなカンジで名前を教えてあげる必要がある。

<?xml version="1.0" encoding="Shift_JIS"?>
<!DOCTYPE components PUBLIC "-//SEASAR2.1//DTD S2Container//EN" 
  "http://www.seasar.org/dtd/components21.dtd">
<components>
  
  <component name="ejb3"
    class="org.seasar.remoting.ejb3.interceptor.Ejb3Interceptor"/>
  
  <component name="remoteEjb3"
    class="org.seasar.remoting.ejb3.interceptor.Ejb3Interceptor">
    <property name="suffix">"Remote"</property>
  </component>
  
  <component name="localEjb3"
    class="org.seasar.remoting.ejb3.interceptor.Ejb3Interceptor">
    <property name="suffix">"Local"</property>
  </component>
  
  <component class="org.seasar.remoting.ejb3.connector.Ejb3Connector">
    <arg>initialContext</arg>
  </component>
  
  <component name="initialContext" class="javax.naming.InitialContext"/>
  
  <component class="study.ejb.Calculator">
    <aspect>remoteEjb3</aspect>
  </component>
    
  <!--    
  <component class="study.ejb.Calculator">
    <aspect>
      <component 
       class="org.seasar.remoting.common.interceptor.RemotingInterceptor">
        <property name="remoteName">"study.ejb.CalculatorRemote"</property>
      </component>
    </aspect>
  </component>
  -->
  
</components>

これでコードではEJBをつかっていることを意識することなくEJBをDIして使用できるはずです。ローカルかリモートかも気にする必要なし。

ところでステートフルのときとか、ステートレスBeanをキャッシュするとか何にも考えてないです。