July 23, 2008

BEA 買収後の Oracle のミドルウェア戦略

少し前に某 ML で得た情報ですが・・・

今月初めに、BEA 買収後の Oracle のミドルウェアの統合方針が発表されています。

http://www.oracle.com/products/middleware/docs/oracle-middleware-strategy-briefing-072008.pdf

JavaEE アプリケーションサーバは、OC4J を捨てて WebLogic Server へ統合される模様です。
しかし(というか、もちろん)ORM フレームワークは Toplink です。

WebLogic Server は、Pitchfork という Spring Framework ベースの DI/AOP コンテナを内包しており、事実上 Oracle のアプリケーションサーバは Oracle ADF + Spring + Toplink という構成になりそうです。

商用 JavaEE アプリケーションサーバ製品は、IBM と Oracle の2強時代になりそうですね。

統合開発環境は、従来通り Eclipse Pack と JDeveloper の2本立て。BEA Workshop の機能は Eclipse Pack の一部として取り込まれていくようです。

Beehive は消えゆく運命に・・・


February 27, 2008

EJB3でのホームインタフェースの作成

どのWebサイトや雑誌記事を見ても「EJB3ではホームインタフェース不要」と、書いてありますが・・・

Stateful SessionBeanのセッション管理をアプリケーションで制御したい場合にはホームインタフェースが必要になる場面も多いと思います。

具体的な例のひとつは、アプリケーションで一旦セッションを破棄して新規にセッションを開始したい場合です。

@EJBアノテーションはコンテナがフィールドを初期化する時にしか動作しないため、EJBのビジネスインタフェース型のフィールドを定義して、@EJBアノテーションを付与する方法では、このようなシチュエーションに対応できません。


EJB3でホームインタフェースを利用する場合は、次のように実装します。

ホームインタフェースを作成する。

  • javax.ejb.EJBLocalHome(リモート呼び出しを行う場合は javax.ejb.EJBHome)インタフェースを継承して作成する。
  • 1つ以上のcreate()メソッドを定義する。戻り値の型は次の手順で作成するビジネスインタフェースの型、引数は任意(と言ってもSerializableな型)、javax.ejb.CreateException をthrowするように実装する。
  • create()メソッドは引数の数と型が異なるものをいくつでもオーバーロード可。

package study.ejb3.model.service;

import javax.ejb.CreateException;
import javax.ejb.EJBLocalHome;

/**
 * ホームインタフェース。
 * javax.ejb.EJBLocalHome または javax.ejb.EJBHome を継承して作成する。
 * 1つ以上の create() メソッドを定義する。戻り値の型は ビジネスインタフェースの型。
 * create() メソッドは javax.ejb.CreateException をthrowするように定義する。
 * create() メソッドは引数の数と型が異なるものをいくつでもオーバーロード可。
 */
public interface HogeServiceHome extends EJBLocalHome {

    /**
     * create() メソッド
     */
    public HogeService create() throws CreateException;

}


ビジネスインタフェースを作成する。
  • 通常のEJB3ビジネスインタフェースとは違い、ホームインタフェースを併用する場合は javax.ejb.EJBLocalObject(リモート呼び出しを行う場合は javax.ejb.EJBObject)インタフェースを継承して作成する。
  • 任意のビジネスメソッドを定義する。ただし、引数と戻り値は Serializableな型であること。これは通常のEJB3スタイルと同様。
  • また、後述するBean実装クラスで@Removeアノテーションを付けたメソッドをクライアントから呼び出せるようにするため、同メソッドを定義する。


package study.ejb3.model.service;

import java.rmi.RemoteException;

import javax.ejb.EJBLocalObject;

/**
 * ビジネスインタフェース.
 * javax.ejb.EJBLocalObjectまたはjavax.ejb.EJBObjectを継承して作成する。
 * 任意のビジネスメソッドを定義する。戻り値と引数はSerializableな型であること。
 *
 */
public interface HogeService extends EJBLocalObject {

    /**
     * ビジネスメソッド
     */
    public String businessMethod() throws RemoteException;

    /**
     * Bean実装クラスで@Removeアノテーションを付けるメソッド
     */
    public void destroy() throws RemoteException;

}


Bean実装クラスを作成する。
  • 通常のEJB3スタイルとは異なり、ビジネスインタフェースをimplementsしない。
  • create() メソッドの引数の数と型に対応したメソッドを実装し、@Initアノテーションを付ける。メソッド名は任意。アクセス修飾子は public、戻り値の型は void 。
  • 任意の名前のメソッドを実装し、@Remove アノテーションを付ける。アクセス修飾子は public、戻り値の型は void。
  • ビジネスインタフェースに定義したビジネスメソッドを実装する。javax.ejb.EJBException をthrowするように実装する。
  • クラス宣言部に @Stateful アノテーションを付ける。これは通常の EJB3スタイルと同様。
  • クラス宣言部に@LocalHome(リモート呼び出しを行う場合は@RemoteHome)アノテーションを付ける。引数に、ホームインタフェースのクラスオブジェクトを指定する。
  • クラス宣言部に@Local(リモート呼び出しを行う場合は@Remote)アノテーションを付ける。引数に、ビジネスインタフェースのクラスオブジェクトを指定する。
  • 上記2つの設定により、ホームインタフェース、ビジネスインタフェース、Bean実装クラスの3つが関連付けられる。従来のEJB2.xではデプロイメントディスクリプタ(配備記述子)ejb-jar.xmlで設定した内容。


package study.ejb3.model.service;

import javax.ejb.EJBException;
import javax.ejb.Init;
import javax.ejb.Local;
import javax.ejb.LocalHome;
import javax.ejb.Remove;
import javax.ejb.Stateful;

/**
 * Bean実装クラス。
 * 通常のEJB3スタイルとは異なり、ビジネスインタフェースをimplementsしない。
 * @Local(または@Remove)アノテーションで
 *                          関連づくビジネスインタフェースを指定する。
 * @LocalHome(または@RemoveHome)アノテーションで
 *                          関連づくホームインタフェースを指定する。
 */
@Stateful(name = "HogeService")
@Local(HogeService.class)          // ビジネスインタフェースのクラスオブジェクトを指定
@LocalHome(HogeServiceHome.class) // ホームインタフェースのクラスオブジェクトを指定
public class HogeServiceBean {

    /**
     * ビジネスメソッド
     */
    public String businessMethod() throws EJBException {
        return "Hello! Business Method!";
    }

    /**
     * ホームオブジェクトのcreate()メソッドが呼ばれたとき
     * (新規セッション開始時)に呼ばれる
     */
    @Init
    public void init() {
        System.out.println("init() が呼ばれた");
    }

    /**
     * クライアントからこのメソッドが呼ばれるとセッションが破棄される
     */
    @Remove
    public void destroy() {
        System.out.println("destroy() が呼ばれた");
    }

}


EJBクライアント(EJB呼び出し側)の実装。
  • EJBビジネスインタフェース型ではなく、ホームインタフェース型のフィールドを定義し、@EJBアノテーションを付ける。EJBオブジェクトと同様、ホームオブジェクトも@EJBでインジェクション可能。


@EJB
private HogeServiceHome home;


  • ホームオブジェクトの create() メソッドを呼び出すと、EJBオブジェクトを取得可能。同時に新規にセッションが開始される。


// セッションを開始。
HogeService service = home.create();


  • EJBオブジェクトの、@Remove が付いたメソッドを呼び出すとセッション破棄。


// セッションを破棄
service.destroy();


  • 新規にセッションを開始したい場合(EJBオブジェクトを新規に取得したい)は、再度ホームオブジェクトの create() メソッドを呼び出せばOK。


// セッションを改めて新規に開始。
service = home.create();


@EJBアノテーションはフィールド初期化時にしか動作しないため、ホームインタフェースを使わないと新規にセッションを開始したい場合(EJBオブジェクトを新規に取得したい)は、JNDIルックアップするコードを書かないといけないことになります。



・・・なんだか、EJB2.xとEJB3のスタイルが混在した、えらく中途半端なコードになってしまいますね(^^;

February 23, 2008

JBoss4.2.xにおける@EJBアノテーション

JBoss4.2はServlet2.5/EJB3にデフォルトで対応しているので、Webコンテナ上で動作するコンポーネントで @EJB アノテーションが当然使えると思っていました。

JNDIルックアップのコードを書かなくても、EJBのビジネスインタフェース型のフィールドに「@EJB」とアノテーションをつけておけば、フィールド初期化時にコンテナが裏でコッソリEJBオブジェクトのインスタンスを取得してフィールドにセットしてくれるという機能です。アノテーションによるDI(Dependency Injection)ってやつですね。

@EJB
private HogeService;

こう書いておけば、コンテナがこのフィールドを初期化する際に、HogeServiceインタフェースを実装したEJBオブジェクトをJNDIサービスより取得してフィールドにセットしてくれます。

しかし、結論から言うとJBoss4.2ではWebコンテナ上でのこの動作はサポートされていません。
JBossの公式文書に下記のような記述がありました。

Java EE 5 allows you to inject EJB3 bean instances directly into the web application via annotations without explicit JNDI lookup. This behavior is not yet supported in JBoss AS 4.2.
http://viewvc.jboss.org/cgi-bin/viewvc.cgi/jbossas/projects/docs/trunk/Server_Configuration_Guide/ja-JP/EJB3.po?revision=65669&pathrev=68449

JBoss4.2.xはEJB3 (JSR-220) 対応のEJBコンテナを実装し、Servlet2.5 (JSR-154) 対応のWebコンテナを実装していますが、Common Annotations (JSR-250) は完全に実装されていないようです。

結局、ServletコンテナからEJBを利用するには従来のEJB2.x時代のようにJNDIルックアップするコードを書かなくてはいけません。


・・・道理で、Web上にもWebコンテナから@EJBでEJBオブジェクトをインジェクションするサンプルが見つからないわけです。

これで1日ぐらいハマりました。

今度のセミナーではCommon Annotations (JSR-250) が動作する JBoss5.0.0Beta4を使うことにします・・・


それにしても、JBossの情報って少ないですね。利用者が減っているのでしょうか?少なくともネット上の情報を探す限りでは、積極的にブログ等へ情報をアップするエッジの効いたエンジニアの利用が減っている感じがします。
JavaEE5完全対応のアプリケーションサーバを正式リリースできていないのはJBossだけですしね。OSSのJavaEEアプリサーバでは、最近はGlassfishの勢いが目立ちます。GlassfishはNetBeansにも標準でバンドルされるようになったし。

※ところが、JBoss5.0.0Beta4はJMSがうまく動かなかったり、セキュリティロールがうまく動かなかったりでした。具体的には、QueueのJNDIサービスへの登録時に例外が発生してデプロイできません。セキュリティロールは、@RollsAllowedで指定していないロールでもメソッドの実行が許可されてしまいました。まあ、βなのでこんなもんですね・・・