金曜日 7 07, 2006
金曜日 7 07, 2006
前回のエントリの最後にふれたように、セッション・ビーンをリモートからもローカルからも呼び出せるようにするためには、リモート用とローカル用の2つのビジネス・インタフェースを用意する必要があります。
@Stateless
@Remote(CalcRemote.class) @Local(CalcLocal.class)
public class CalcImpl implements CalcRemote, CalcLocal {...}
ローカル用の一部のメソッドをリモート用には公開したくない場合は別ですが、ほとんどの場合、リモート用とローカル用には同じビジネス・メソッドのセットを定義したいと考えるでしょう。上記のように、同じメソッドのセットをもつ2つのインタフェースを用意しなければならないとすると、以下のようなデメリットが生じます。
ローカルとリモートでインタフェース・クラスを共有できない仕様は、J2EE 1.4(EJB 2.1)のときも仕様上不可避の問題でしたが、J2EE 1.4でのEJB開発ではほとんどの場合XDocletが使用されていたと思います。XDocletはEJB実装からEJBインタフェースを自動生成できるため、EJB実装とEJBインタフェースの同期はそれほど問題にはなりませんでした。EJB 3.0ではビジネス・インタフェースがせっかくPOJI(Plain Old Java Interface)になったのですから、なんとか1つにまとめたいものです。
ローカルとリモートで1つのインタフェースを使用できないのは、EJBクライアント側でルックアップする(あるいは、インジェクションする)EJBのメタ情報を宣言するためのアノーテーション@EJBの仕様上の問題です。@EJBはデプロイメント記述子のリモート用<ejb-ref>とローカル用<ejb-local-ref>の両方にマッピングされるように仕様化されました。@EJBアノーテーションそのものには、ローカルかリモートかを明示するメンバがなく、@EJB.beanInterface要素のインタフェースクラスが@Remoteと@Localのどちらでアノーテーションされているかの情報に頼らざるをえなくなっています(@EJB.beanInterface要素が省略された場合、アノーテーションされている変数の型から決定します)。もし、EJB参照のためのアノーテーションが@EJBRefと@EJBLocalRefの2つが用意されていたか、@EJBにローカル/リモートが明示できるメンバ要素が含まれていれば、おそらく1つのビジネス・インタフェースをローカル/リモートで共通化することが可能だったのではないかと思います。
しかし、現状のEJB 3.0仕様のままでもこの問題を解決する方法が、A Java Programmer's Blog: Remote or Local interface? に紹介されています。これはなかなか良いアイデアです。つまり、リモート用とローカル用にはインタフェースクラスを用意するものの、それらで定義するメソッドは両方の親インタフェースに全て定義してしまえば良いというものです。そのままでは、インタフェース・クラスが3つに増えてしまいますが、インナー・クラス表現を使ってJavaのクラスファイルとしては1つにまとめてしまえるわけです。
package com.example;
public interface Calc {
public int add(int i, int j);
@javax.ejb.Remote
public interface Remote extends Calc {
}
@javax.ejb.Local
public interface Local extends Calc {
}
}
package com.example;
import javax.ejb.Stateless;
@Stateless
public class CalcImpl implements Calc.Local, Calc.Remote {
public int add(int i, int j) {
return i + j;
}
}
クライアント側でローカル/リモートのどちらのEJB参照を要求するかを明示するには、Calcのサブインタフェースを明示すれば良いわけです。@EJBでインジェクションする場合は以下のように記述すればよいことになります。
@EJB(beanInterface=Calc.Remote.class) Calc calc1; // リモート参照 @EJB(beanInterface=Calc.Local.class) Calc calc2; // ローカル参照
ローカル/リモートどちらを選んでも、EJB参照の型はCalcに統一でき、ソースコードも増えません。ローカル呼出しからリモート呼出しに切替える場合であっても、変更はアノーテーションの部分だけで、ソースのロジックを見直す必要はありません。また、ローカルだけに公開したいメソッドを追加したい場合でもCalc.Localインタフェースにそのメソッドを追加すれば対応できます。
[1] 例えば、NetBeans 5.xでは、ソースコードのエディタ・ペインで実装クラスのメソッド名で右クリックし、コンテキストメニューからRefactor > Rename...またはRefactor > Change Method Parameters...を選ぶことで、複数インタフェースでメソッドが重複している場合でも同期的に変更が適用できます。
cool
Posted by wow gold on 11月月 03日, 2008年 at 10:44 午前 JST #