EJB仕様ではEJBの実行中に発生する例外として、以下の2種類を定義しています。
アプリケーション例外: クライアントに通知される例外です。以下の全ての条件を満たす例外がアプリケーション例外です。
java.lang.Exceptionのサブクラスである。
java.lang.RuntimeExceptionのサブクラスではない。
java.rmi.RemoteExceptionのサブクラスではない。
システム例外: 処理を継続できなくなるような回復不能な例外を表します。この例外はEJBコンテナが受け取り、例外を発生したEJBのオブジェクトは削除されます。以下のすべての条件を満たす例外がシステム例外です。
アプリケーション例外でない。
java.rmi.RemoteExceptionのサブクラスではない。
ビジネスクラスで発生した例外も基本的に上記の分類に従って処理されます。
アプリケーション例外の場合、クライアントに通知されます。
システム例外の場合、EJBコンテナに通知されます。その結果、セションBeanのオブジェクトは削除されます。
ただし、ビジネスクラスがPostprocessorインターフェイスを実装している場合は、例外はhandleExceptionメソッドで処理されます。handleExceptionメソッドが例外を発生した場合は、上記の処理に従います。handleExceptionメソッドについては、“4.2 エラー処理”を参照してください。
デバッグの目的で、セションBean内で発生したシステム例外をクライアントに通知する場合は、初期化パラメータuji.informSystemExceptionを“client”に設定してください。この設定により、システム例外はコンテナではなくクライアントに通知されます。また、システム例外が発生してもセションBeanオブジェクトは削除されません。運用時はuji.informSystemExceptionを“container”に設定して、通常どおりシステム例外がEJBコンテナに通知されるように設定してください。
エンタープライズBean環境(デプロイメント記述の<env-entry>で定義された値)はEJBDispatchContextのgetEnvironmentメソッドで取得できます。 以下は、ビジネスクラスのメソッドでエンタープライズBean環境を取得する例です。
import com.fujitsu.uji.ejb.bean.EJBDispatchContext; ... public Object search(DispatchContext context, HashMap data) { // エンタープライズBean環境java:comp/env/initialCountの値を取得します。 Integer i = (Integer)((EJBDispatchContext) context).getEnvironment("initialCount"); ... }
EJBDispatchContextのメソッドを利用するには、ビジネスクラスのメソッドの第1引数に与えられるDispatchContextをEJBDispatchContextにキャストします。
getEnvironmentメソッドの引数にはエントリの名前からjava:comp/env/を除いた部分を指定します。上記の例ではjava:comp/env/initialCountの値が取得されます。 指定された名前が未定義の場合はnullが返ります。
ポイント
一般的なEJBと同様にIniticalContextを使ってエンタープライズBean環境を取得することも可能です。ただし、getEnvironmentメソッドを使用した場合には、ローカル呼び出し機能で呼び出された場合でもエンタープライズBean環境が取得できます。
EJBコンテナはjavax.ejb.SessionContextインターフェイスを実装したオブジェクトをセションBeanに与えます。このSessionContextを取得するには、EJBSessionProfileのgetEJBContextメソッドを使用します。このメソッドをビジネスクラスで呼び出す例を示します。
import com.fujitsu.uji.ejb.bean.EJBSessionProfile; import javax.ejb.SessionContext; public Object search(DispatchContext context, HashMap data) { EJBSessionProfile sp = (EJBSessionProfile)context.getSessionProfile(); SessionContext sessionContext = (SessionContext)sp.getEJBContext(); }
getEJBContextメソッドの返り値の型はSessionContextのスーパーインターフェイスであるEJBContextです。これをSessionContextにキャストして使用します。
EJBSessionProfileのメソッドを利用するには、DispatchContextのgetSessionProfileでセションクラスを取得し、それをEJBSessionProfileにキャストします。
アプリケーションクラス、セションクラス、ビジネスクラスのライフサイクルは以下のようになります。
クラス | インスタンスが作成されるタイミング | インスタンスの有効期間 | 備考 |
---|---|---|---|
ビジネスクラス(initメソッドがtrueを返す場合) | セションBeanオブジェクト作成後、クライアントからの呼び出しを受けてビジネスクラスが初めて呼び出される時 | セションBeanオブジェクトがEJBコンテナから削除されるまで | |
ビジネスクラス(initメソッドがfalseを返す場合) | クライアントからの呼び出しを受けてビジネスクラス呼び出される時 | クライアントからの呼び出しが終了するまで | クライアントからの呼び出しがあるたびにインスタンスが作成されます。 |
セションクラス | セションBeanオブジェクトが作成された時(セションBeanのejbCreateメソッドが呼び出されたとき) | セションBeanオブジェクトがEJBコンテナから削除されるまで | |
アプリケーションクラス | 同一のJVM内で最初にセションBeanのオブジェクトが作成された時(同一のJVM内で最初にセションBeanのejbCreateメソッドが呼び出された時) | 全てのセションBeanインスタンスがEJBコンテナから削除されるまで | 同一のJVMに存在する複数のセションBeanオブジェクトで1個のインスタンスが共有されます。 |
ステートフルセションBeanの場合、クライアントとセションBeanが1対1に対応します。したがって、ビジネスクラスが2回以上呼び出される場合、その呼び出し元は同一のクライアントです。 一方、ステートレスセションBeanの場合、クライアントとセションBeanは1対1で対応づけられていません。そのため、ビジネスクラスが2回以上呼び出される場合、その呼び出し元が同じクライアントであるとは限りません。
Apcoordinatorで作成したセションBeanはビジネスメソッドを1個だけ持ち、そのメソッド名はexecです。 execとはトランザクション属性などが異なるビジネスメソッドが必要な場合は、次のようにしてください。
セションBeanクラスにユーザー定義のビジネスメソッドを追加する。
追加したビジネスメソッドをリモートインターフェイスにも追加する。
デプロイメント記述で、execメソッドとユーザー定義ビジネスメソッドにそれぞれ別のトランザクション属性を割り当てる。
クライアントからセションBeanを呼び出すときはメソッド名を指定し、呼び出すメソッドを区別する。
ビジネスメソッドを追加したセションBeanクラスは次のように作成します。
import com.fujitsu.uji.ejb.bean.UjiSessionBean; import java.lang.reflect.InvocationTargetException; public class OfficeEJB extends UjiSessionBean { public Object[] myExec(Object dataBean, String verb, Object syncData) throws InvocationTargetException { return exec(dataBean,verb,syncData); } }
これは、ビジネスメソッドmyExecを追加した例です。メソッドの引数の型、返り値の型、throws節は上記例と同じにしてください。また、上記例と同様にexecを呼び出してその返り値を返すように作成してください。execメソッドはUjiSessionBeanクラスに定義されています。
クライアントからユーザー定義のビジネスメソッドを呼び出す時には次のようにメソッド名を指定してください。
セションBeanの呼び出しにEJBCallFactoryを使用する場合: UjiSessionCallクラスのinvokeメソッドの代わりにinvokeMethodメソッドを使用します。その第1引数にメソッド名を指定します。
UjiSessionCall call=...; call.invokeMethod("myExec",dataBean,verb);
セションBeanの呼び出しにリモート共通インターフェイスを使用する場合: CallインターフェイスをUjiSessionCallクラスにキャストして、前項と同じ方法で呼び出します。
Call call=...; ((UjiSessionCall)call).invokeMethod("myExec",dataBean,verb);
なお、セションBeanの基本的な呼び出し方法については、“EJBの呼び出し”を参照してください。