RemoteProxy
http://d.hatena.ne.jp/aufheben/20050820。J2EE勉強会の内容がまとまっています。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にインターセプタを引っ掛ければよかったかも?