この章ではコンテナ管理の永続性を持つEJB 2.0エンティティBeanの実装方法を説明します。
この章の内容は次のとおりです。
詳細は次のトピックを参照してください。
コンテナ管理の永続性を持つEJB 2.0エンティティBeanの実装プロセスは、次のステップで構成されています。
Beanのホーム・インタフェースを作成します。ホーム・インタフェースは、クライアントによるエンティティBeanの作成、検索または削除を可能にするメソッドを定義します。詳細は「エンティティBeanホーム・インタフェースの実装」を参照してください。
Beanのコンポーネント(リモート)・インタフェースを作成します。コンポーネント・インタフェースはクライアントが起動できるメソッドを宣言します。詳細は「エンティティBeanコンポーネント・インタフェースの実装」を参照してください。
Beanの主キーを定義します。主キーは各エンティティBeanインスタンスを識別する、シリアライズ可能クラスです。詳細は「主キーの構成」を参照してください。
Beanを実装します。詳細は「エンティティBeanクラスの実装」を参照してください。
Beanのデプロイメント・ディスクリプタを作成します。これは、XML要素を使用するBeanのプロパティを指定するファイルです。ユーザーはコンテナが管理するBean内のデータを特定します(永続フィールドの詳細は「コンテナ管理の永続フィールドの構成」を参照)。これらのフィールドが他のオブジェクトとの関連を示す場合は、「コンテナ管理の関連フィールドの構成」を参照してください。
構成対象のEJBコンテナ・サービスもすべてデプロイメント・ディスクリプタで明示されています。データ・ソースおよびJTAの詳細は、『Oracle Containers for J2EEサービス・ガイド』を参照してください。セキュリティの詳細は、『Oracle Containers for J2EEセキュリティ・ガイド』を参照してください。
永続データがデータベースに保存される場合、またはデータベースからリストアされる場合に、コンテナで提供されるデフォルトを使用しないときは、Bean用の正しい表が存在することを確認する必要があります。デフォルト・シナリオでは、デプロイメント・ディスクリプタおよびデータ・ソース情報に基づいて、コンテナがユーザーのデータに対する表および列を作成します。
Bean、コンポーネント・インタフェース、ホーム・インタフェース、およびデプロイメント・ディスクリプタを含むEJB JARファイルを作成します。作成したら、application.xmlファイルを構成し、EARファイルを作成して、エンティティBeanをOC4Jにデプロイします。詳細は第2章「Orion CMPアプリケーション開発の理解」を参照してください。
コンテナ管理の永続性を持つEJB 2.0エンティティBeanの構成の詳細は、「コンテナ管理の永続性を持つEJB 2.0エンティティBeanの構成」を参照してください。
ホーム・インタフェースは、クライアントがビジネス・メソッドをリクエストできる、Bean参照の取得に主に使用されます。ホーム・インタフェースのタイプを次に示します。
javax.ejb.EJBHomeを拡張するリモート・ホーム・インタフェース。このホーム・インタフェース・タイプは、リモート・クライアント・ビューを提供するBeanに用意されています。
javax.ejb.EJBLocalHomeを拡張するローカル・ホーム・インタフェース。このホーム・インタフェース・タイプは、ローカル・クライアント・ビューを提供するBeanに用意されています。
|
注意: エンティティBeanがコンテナ管理関連のターゲットの場合は、このBeanにローカル・インタフェースが必要です。 |
クライアントは標準のJNDI APIによってBeanのホーム・インタフェースを特定できます。
ホーム・インタフェースには、クライアントがBeanインスタンスを作成するために起動できるcreateメソッドが含まれます。エンティティBeanは、それぞれパラメータが定義されたゼロ以上のcreateメソッドを保持できます。
エンティティBeanは、1つ以上のfinderメソッド(最低でも1つのfindByPrimaryKeyメソッドを含む)を定義する必要があります。オプションで、Beanに対して他のfinderメソッド(find<NAME>と名付けられる)を定義できます。
作成および取得メソッドの他に、ホーム・インタフェース内でビジネス・メソッドを提供できます。これらのメソッドは特定のエンティティ・オブジェクトのデータにアクセスできません。これらのメソッドの目的は、単一のエンティティBeanインスタンスに関連していない情報を取得する手段を提供することです。クライアントがホーム・インタフェースのビジネス・メソッドを起動すると、リクエストにサービスを提供するためエンティティBeanがプールから削除されます。このように、このメソッドはBeanに関連する一般情報における操作の実行に使用できます。
例4-1 エンティティBeanホーム・インタフェースの実装
ホーム・インタフェースでは、createおよびfindByPrimaryKeyメソッドを定義するだけでなく、javax.ejb.EJBHomeインタフェースを拡張する必要があります。
例4-1は、リモート・インタフェースを作成するためのメソッドを提供するローカル・ホーム・インタフェースの実装を示しています。また、従業員番号で特定の従業員を探すためと、すべての従業員を探すための、2つのfinderメソッドも提供されています。calculateSalaryメソッドは、すべての従業員の給与の合計を計算するホーム・インタフェースのビジネス・メソッドです。このメソッドは特定の従業員の情報にはアクセスしませんが、すべての従業員のデータベースに対してSQL問合せを実行します。
package employee;
import javax.ejb.*;
import java.rmi.*;
public interface EmployeeLocalHome extends EJBLocalHome {
public EmployeeLocal create(Integer empNumber) throws CreateException;
// Find an existing employee
public EmployeeLocal findByPrimaryKey (Integer empNumber)
throws FinderException;
// Find all employees
public Collection findAll() throws FinderException;
// Calculate the salaries of all employees
public float calculateSalary() throws Exception;
}
このインタフェースに対する実装を作成するのはEJBコンテナです。
デプロイメント・ディスクリプタのホーム・インタフェースの宣言を次に示します。
<local-home>employee.EmployeeLocalHome</local-home>
EJBオブジェクトはBeanのコンポーネント・インタフェースからアクセス可能です。コンポーネント・インタフェース(リモート・インタフェースとも呼ばれる)はクライアントがコールするビジネス・メソッドを定義します。ビジネス・メソッドはエンティティBeanコードで実装されます。コンポーネント・インタフェースのタイプを次に示します。
javax.ejb.EJBObjectを拡張するコンポーネント・インタフェース。EJBObjectインタフェースは、クライアントがEJBオブジェクトのIDにアクセスして、このオブジェクトに対する永続ハンドルを作成することを可能にする操作を定義します。
javax.ejb.EJBLocalObjectを拡張するコンポーネント・インタフェース。EJBLocalObjectインタフェースは、クライアントがこのオブジェクトのIDにアクセスすることを可能にする操作を定義します。
例4-2 エンティティBeanコンポーネント・インタフェースの実装
employeeエンティティBeanの例では、従業員情報の取得および更新のためのメソッドを含むローカル・コンポーネント・インタフェースを公開します。
package employee;
import javax.ejb.*;
public interface EmployeeLocal extends EJBLocalObject {
public Integer getEmpNumber();
public void setEmpNumber(Integer empNumber);
public String getEmpName();
public void setEmpName(String empName);
public Float getSalary();
public void setSalary(Float salary);
}
コンポーネント・インタフェースに対する実装を作成するのはEJBコンテナです。
デプロイメント・ディスクリプタのコンポーネント・インタフェースの宣言を次に示します。
<local>employee.EmployeeLocal</local>
エンティティBeanクラスは次の基準に従う必要があります。
クラスは直接的または間接的にjavax.ejb.EntityBeanインタフェースを実装します。
クラスはpublicとして定義され、abstractとなります。
クラスは引数をとらないpublicなコンストラクタを定義します。
クラスはfinalize()メソッドを定義しません。
クラスはエンティティBeanのコンポーネント・インタフェースを実装する場合がありますが、必須ではありません(「エンティティBeanコンポーネント・インタフェースの実装」を参照)。
エンティティBeanクラスは次のメソッドを実装します。
ホーム・インタフェースで宣言されるメソッドに対するターゲット・メソッド(「エンティティBeanホーム・インタフェースの実装」を参照)。これには、次のメソッドが含まれます。
ホーム・インタフェースで定義され、関連付けられているcreateメソッドに一致するパラメータを持つejbCreateおよびejbPostCreateメソッド。
ホーム・インタフェースで定義されたejbFindByPrimaryKeyおよびejbFindAll以外のfinderメソッド。コンテナはejbFindByPrimaryKeyおよびejbFindAllのメソッドの実装を生成します。
Bean実装でejbHome接頭辞を持つホーム・インタフェースのビジネス・メソッド。たとえば、calculateSalaryメソッドはejbHomeCalculateSalaryメソッドで実装されます。
コンポーネント・インタフェースで宣言されるビジネス・ロジック・メソッド。
javax.ejb.EntityBeanインタフェースから継承されたメソッド(ejbActivate、ejbPassivateなど)。
ほとんどのターゲット・メソッドおよびデータ・オブジェクトを管理するのはコンテナです。エンティティBeanのコールバック・メソッドの詳細は「コールバック・メソッド」を参照してください。
例4-3 エンティティBeanクラスの実装
例4-3はエンティティBeanクラスの実装を示しています。
package employee;
import javax.ejb.*;
import java.rmi.*;
public abstract class EmployeeBean implements EntityBean {
private EntityContext ctx;
// Each persistent field has a getter and a setter
public abstract Integer getEmpNumber();
public abstract void setEmpNumber(Integer empNumber);
public abstract String getEmpName();
public abstract void setEmpName(String empName);
public abstract Float getSalary();
public abstract void setSalary(Float salary);
public void EmployeeBean() {
// Constructor. Do not initialize anything in this method.
// All initialization should be performed in the ejbCreate method.
// The passivate() method may destroy these attributes when pooling
}
public float ejbHomeCalculateSalary() throws Exception {
Collection c = null;
try {
c = ((EmployeeLocalHome)this.ctx.getEJBLocalHome()).findAll();
Iterator i = c.iterator();
float totalSalary = 0;
while (i.hasNext()) {
EmployeeLocal e = (EmployeeLocal)i.next();
totalSalary = totalSalary + e.getSalary().floatValue();
}
catch (FinderException e) {
System.out.println("Got finder Exception " + e.getMessage());
throw new Exception(e.getMessage());
}
}
public EmployeePK ejbCreate(Integer empNumber, String empName, Float salary)
throws CreateException {
setEmpNumber(empNumber);
setEmpName(empName);
setSalary(salary);
return new EmployeePK(empNumber);
}
public void ejbPostCreate(Integer empNumber, String empName, Float salary)
throws CreateException {
// Called just after bean created; container takes care of implementation
}
public void ejbStore() {
// Called when bean persisted; container takes care of implementation
}
public void ejbLoad() {
// Called when bean loaded; container takes care of implementation
}
public void ejbRemove() throws RemoveException {
// Called when bean removed; container takes care of implementation
}
public void ejbActivate() {
// Called when bean activated; container takes care of implementation.
// If you need resources, retrieve them here
}
public void ejbPassivate() {
// Called when bean deactivated; container takes care of implementation.
// If you set resources in ejbActivate, remove them here
}
public void setEntityContext(EntityContext ctx) {
this.ctx = ctx;
}
public void unsetEntityContext() {
this.ctx = null;
}
}
デプロイメント・ディスクリプタのエンティティBeanクラスは次の行で定義します。
<ejb-class>employee.EmployeeBean</ejb-class>
エンティティBeanに対するデプロイメント・ディスクリプタの例を次に示します。
<enterprise-beans>
<entity>
<display-name>Employee</display-name>
<ejb-name>EmployeeBean</ejb-name>
<local-home>employee.EmployeeLocalHome</local-home>
<local>employee.EmployeeLocal</local>
<ejb-class>employee.EmployeeBean</ejb-class>
<persistence-type>Container</persistence-type>
<prim-key-class>java.lang.Integer</prim-key-class>
<reentrant>False</reentrant>
<cmp-version>2.x</cmp-version>
<abstract-schema-name>Employee</abstract-schema-name>
<cmp-field><field-name>empNumber</field-name></cmp-field>
<cmp-field><field-name>empName</field-name></cmp-field>
<cmp-field><field-name>salary</field-name></cmp-field>
<primkey-field>empNumber</primkey-field>
</entity>
...
</enterprise-beans>