RemoteProxy

http://d.hatena.ne.jp/aufheben/20050820J2EE勉強会の内容がまとまっています。id:aufhebenさんはきっとひがさんの隣に座ってらしたかたですね。
ひがさんがおっしゃってたRemoteProxyってEJBのビジネスインタフェースに依存しないようにするということなんでしょうか?クライアント側は設定ファイルでRemoteインタフェースとLocalインタフェースどちらでアクセスするかを切り替えられるからうれしい?
僕の理解を書いてみました。

ビジネスインタフェースとセッションBean : セッションBeanはRemoteとLocalの両方のインタフェースを持つとする

public interface Calculator {
  int add(int x, int y);
  int subtract(int x, int y);
}
@Local
public interface CalculatorLocal extends Calculator {
}
@Remote
public interface CalculatorRemote extends Calculator {
}
@Stateless
public class CalculatorBean implements CalculatorRemote、CalculatorLocal {
  public int add(int x, int y) {
    return x + y;
  }
  public int subtract(int x, int y) {
    return x - y;
  }
}


クライアント側で使うインタフェースとmainを持つクライアント

public interface Calc {
  int add(int x, int y);
  int subtract(int x, int y);
}
public class Client {

  private Calc calc;

  public void setCalculator(Calc calc) {
    this.calc = calc;
  }

  public int add(int x, int y) {
    return calc.add(x, y);
  }

  public static void main(String[] args) throws Exception {
    S2Container container = S2ContainerFactory.create("study/seasar/my.dicon");
    Client client = (Client) container.getComponent(Client.class);
    System.out.println(client.add(10,1));
  }
}

Seasar2の設定ファイルとインターセプタ

<?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="initialContext" class="javax.naming.InitialContext"/>
  
  <component name="ejb3" class="study.seasar.Ejb3Interceptor">
    <arg>initialContext</arg>
    <arg>"study.ejb.CalculatorRemote"</arg>
  </component>
  
  <component class="study.seasar.Calc">
    <aspect>ejb3</aspect>
  </component>
  
  <component class="study.seasar.Client"/>
  
</components>
public class Ejb3Interceptor extends AbstractInterceptor {
  private InitialContext ctx;
  private String jndiName;
  private Map methodNameMap = new HashMap();
  
  public Ejb3Interceptor(InitialContext ctx, String jndiName) {
    this.ctx = ctx;
    this.jndiName = jndiName;
  }
  
  public void addMethodNameMap(String methodName, String targetMethodName) {
    methodNameMap.put(methodName, targetMethodName);
  }

  public Object invoke(MethodInvocation invocation) throws Throwable {
    Object ejb = ctx.lookup(jndiName);
    BeanDesc beanDesc = BeanDescFactory.getBeanDesc(ejb.getClass());
    Method method = invocation.getMethod();
    String methodName = method.getName();
    if (methodNameMap.containsKey(methodName)) {
      methodName = (String) methodNameMap.get(methodName);
    }
    if (!MethodUtil.isAbstract(method)) {
      return invocation.proceed();
    } else if (beanDesc.hasMethod(methodName)) {
      return beanDesc.invoke(ejb, methodName, invocation.getArguments());
    } else {
      throw new MethodNotFoundRuntimeException(
          getTargetClass(invocation), methodName, invocation
              .getArguments());
    }
  }
}


Clientクラスのmainを実行してEJBを意識することなく呼び出せました。
呼び出しのフローは Client -> Calc -> (Ejb3Interceptor) -> Calculator。
クライアント側にCalcインタフェースを用意しましたがClientが直接Calculatorを参照して、Calculatorにインターセプタを引っ掛ければよかったかも?