EJBの仕様では、EJBの実行中に発生する例外として以下の2種類を定義しています。
アプリケーション例外
クライアントに通知される例外です。以下の例外がアプリケーション例外です。
java.lang.Exceptionのサブクラス (ただし、java.rmi.RemoteExceptionとそのサブクラスは除く)
java.lang.RuntimeExceptionのサブクラスをアプリケーション例外として使う場合は、以下のどちらかの方法でアプリケーション例外であることを明示的に指定します。
@ApplicationExceptionアノテーションを例外クラスに付加
デプロイメント記述のapplication-exceptionタグで例外クラスを指定
システム例外
EJBコンテナが受け取る例外です。この例外が発生するとEJBのオブジェクトは削除されます。以下の例外がシステム例外です。
java.lang.RuntimeExceptionのサブクラス (ただし、アプリケーション例外として指定されているものを除く)
java.rmi.RemoteExceptionのサブクラス
ビジネスクラスで発生した例外は上記の分類にしたがって以下のとおり処理されます。
アプリケーション例外の場合、クライアントに通知されます。
システム例外の場合、EJBコンテナに通知されます。セションBeanのオブジェクトは削除されます。
ただし、ビジネスクラスがPostprocessorインタフェースを実装している場合は、例外はhandleExceptionメソッドで処理されます。handleExceptionメソッドが例外を発生させた場合は、上記の処理にしたがいます。handleExceptionメソッドについては、4.2 エラー処理を参照してください。
注意
システム例外のクライアントへの通知機能はEJB 3.0に準拠したセションBeanでは提供されません。詳細は、27.4 GlassFishで提供されない機能を参照してください。
以下は、ビジネスクラスの処理で発生する例外に応じて、アプリケーション例外とシステム例外を発生させる例です。アプリケーション独自の例外クラスとして、MyApplicationException(アプリケーション例外)とMySystemException(システム例外)を定義しています。
import com.fujitsu.uji.DispatchContext; import com.fujitsu.uji.ext.Call; import com.fujitsu.uji.ext.CallFactory; import com.fujitsu.uji.ext.UjiCreateException; import com.fujitsu.uji.ext.UjiTargetException; public Object doSomething(DispatchContext context, MyDataBean dataBean) throws MyApplicationException { ... CallFactory factory = context.getCallFactory(); try { Call call = factory.createCall("SomeSessionBean"); MyDataBean response = (MyDataBean)call.invoke(dataBean, "update"); ... } catch (UjiCreateException e) { // この例では、UjiCreateExceptionが発生した場合は // EJBコンテナに通知します。 throw new MySystemException("System exception", e); } catch (UjiTargetException e) { // この例では、UjiTargetExceptionが発生した場合は // クライアントに通知します。 throw new MyApplicationException("Application exception", e); } ... }
MyApplicationException(アプリケーション例外)とMySystemException(システム例外)は、それぞれExceptionとRuntimeExceptionを継承して作成します。
public class MyApplicationException extends Exception { public MyApplicationException(String message, Throwable cause) { super(message, cause); } }
public class MySystemException extends RuntimeException { public MySystemException(String message, Throwable cause) { super(message, cause); } }
アプリケーションクラス、セションクラス、ビジネスクラスのライフサイクルは以下のようになります。
クラス | インスタンスが作成されるタイミング | インスタンスの有効期間 | 備考 |
---|---|---|---|
ビジネスクラス(initメソッドがtrueを返す場合) | セションBeanオブジェクト作成後、クライアントからの呼び出しを受けてビジネスクラスが初めて呼び出される時 | セションBeanオブジェクトがEJBコンテナから削除されるまで | |
ビジネスクラス(initメソッドがfalseを返す場合) | クライアントからの呼び出しを受けてビジネスクラス呼び出される時 | クライアントからの呼び出しが終了するまで | クライアントからの呼び出しがあるたびにインスタンスが作成されます。 |
セションクラス | セションBeanオブジェクトが作成された時 (セションBeanのPostConstructメソッドが呼び出されたとき) | セションBeanオブジェクトがEJBコンテナから削除されるまで | |
アプリケーションクラス | 同一のJavaVM内で最初にセションBeanのオブジェクトが作成された時 (同一のJavaVM内で最初にセションBeanのPostConstructメソッドが呼び出された時) | 全てのセションBeanインスタンスがEJBコンテナから削除されるまで | 同一のJavaVMに存在する複数のセションBeanオブジェクトで1個のインスタンスが共有されます。 |
ステートフルセションBeanの場合、クライアントとセションBeanが1対1に対応します。したがって、ビジネスクラスが2回以上呼び出される場合、その呼び出し元は同一のクライアントです。 一方、ステートレスセションBeanの場合、クライアントとセションBeanは1対1で対応づけられていません。そのため、ビジネスクラスが2回以上呼び出される場合、その呼び出し元が同じクライアントであるとは限りません。
Apcoordinatorで作成したセションBeanのビジネスメソッドはsimpleExecです。EJBの仕様では、トランザクション属性などのようにセションBeanのビジネスメソッドごとに指定可能な設定項目があります。 simpleExecとは異なる設定のビジネスメソッドが必要な場合は、次のようにアプリケーションを作成してください。
セションBeanクラスにユーザ定義のビジネスメソッドを追加します。
追加したビジネスメソッドと同じ名前、引数、throws節、返却値のメソッドをビジネスインタフェースに追加します。
デプロイメント記述やアノテーションを使って、追加したビジネスメソッドとsimpleExecに異なる設定をします。
クライアントからセションBeanを呼び出すときはビジネスメソッド名を明示的に指定します。
ビジネスメソッドを追加したセションBeanクラスは次のように作成します。
package ejboffice.ejb; import javax.ejb.Stateful; import com.fujitsu.uji.ejb.bean.UjiSimpleStatefulBean; @Stateful public class OfficeBean extends UjiSimpleStatefulBean implements Office { ... public Object[] mySimpleExec(Object dataBean, String verb, Object syncData) throws Exception { return simpleExec(dataBean, verb, syncData); } }
これは、ビジネスメソッドmySimpleExecを追加した例です。メソッドの引数の型、返り値の型、throws節は上記の例と同じにします。また、上記の例と同様にsimpleExecを呼び出してその返却値を返します。simpleExecメソッドはUjiSimpleStatefulBeanクラスとUjiSimpleStatelessBeanクラスに定義されています。
クライアントからユーザ定義のビジネスメソッドを呼び出す時には次のようにメソッド名を指定します。
セションBeanの呼び出しにEJBCallFactoryクラスを使用する場合
UjiSessionCallクラスのinvokeメソッドの代わりにinvokeMethodメソッドを使用します。その第1引数にビジネスメソッド名を指定します。
import com.fujitsu.uji.ejb.UjiSessionCall; ... UjiSessionCall call = ...; call.invokeMethod("mySimpleExec", dataBean, verb);
セションBeanの呼び出しにリモート共通インタフェースを使用する場合
CallインタフェースをUjiSessionCallクラスにキャストして、前項と同じ方法で呼び出します。
import com.fujitsu.uji.ext.Call; import com.fujitsu.uji.ejb.UjiSessionCall; ... Call call = ...; ((UjiSessionCall)call).invokeMethod("mySimpleExec", dataBean, verb);
なお、セションBeanの基本的な呼び出し方法については、27.3 EJBの呼び出しを参照してください。
UjiSimpleStatelessBeanクラスとUjiSimpleStatefulBeanクラスは、ライフサイクルコールバックメソッドを実装済みです。アプリケーション独自の処理を実行する目的でライフサイクルコールバックメソッドをオーバーライドした場合は、スーパークラスのライフサイクルコールバックメソッドを必ず呼び出してください。セションBeanクラスに新規にメソッドを追加すると、スーパークラスで実装済みのメソッドと重複するため、ライフサイクルコールバックメソッドとして使用することはできません。
UjiSimpleStatelessBeanクラスとUjiSimpleStatefulBeanクラスが実装しているライフサイクルコールバックメソッドについてはAPIリファレンスを参照してください。
インターセプタはクラスに設定する方法とメソッドに設定する方法があります。クラスに対してインターセプタを設定すると、ビジネスメソッドを含むすべてのセションBeanのメソッドにインターセプタが設定されます。ビジネスメソッドに限定してインターセプタを利用する場合は、以下のとおりインターセプタを設定してください。
ビジネスインタフェースを使ってセションBeanが呼び出された場合にインターセプタを呼び出したい場合は、simpleExecメソッドにインターセプタを設定してください。ユーザ定義のビジネスメソッドを追加した場合は、追加したビジネスメソッドにインターセプタを設定してください。
ホームインタフェースとリモートインタフェースを使ってセションBeanが呼び出された場合にインターセプタを呼び出したい場合は、execメソッドにインターセプタを設定してください。
simpleExecメソッドとexecメソッドはUjiSimpleStatelessBeanクラスとUjiSimpleStatefulBeanクラスに実装されています。詳細はAPIリファレンスを参照してください。