ヘッダーをスキップ

Oracle Containers for J2EE Enterprise JavaBeans開発者ガイド
10g(10.1.3.1.0)

B31852-03
目次
目次
索引
索引

戻る 次へ

13 EJB 2.1エンティティBeanの実装

この章では、次のようなEJB 2.1エンティティBeanの実装方法を説明します。

詳細は、次を参照してください。

コンテナ管理の永続性を備えたEJB 2.1エンティティBeanの実装

表13-1に、コンテナ管理の永続性を備えたEJB 2.1エンティティBeanの重要な構成要素をまとめ、次の手順でこれらの構成要素の実装方法を説明します。一般的な実装は、「Javaの使用方法」を参照してください。詳細は、「コンテナ管理の永続性を備えたEJB 2.1エンティティBeanとは」を参照してください。

表13-1    コンテナ管理の永続性を備えたEJB 2.1エンティティBeanの構成要素 
構成要素  説明 

ホーム・インタフェース(リモートまたはローカル) 

リモート・ホーム・インタフェースのjavax.ejb.EJBHome、ローカル・ホーム・インタフェースのjavax.ejb.EJBLocalHomeを拡張し、引数を取らない1つのcreateファクトリ・メソッド、および1つのremoveメソッドを必要とします。 

コンポーネント・インタフェース(リモートまたはローカル) 

リモート・インタフェースの場合はjavax.ejb.EJBObjectを拡張し、ローカル・インタフェースの場合はjavax.ejb.EJBLocalObjectを拡張します。また、Bean実装で実装されるビジネス・ロジック・メソッドを定義します。 

Beanの実装 

EntityBeanを実装します。このクラスは、パブリックとして宣言する必要があり、パブリックで空のデフォルト・コンストラクタを含み、finalizeメソッドは使用しません。また、コンポーネント・インタフェースで定義されたメソッドを実装します。ホーム・インタフェースのcreateメソッドに一致する1つ以上のejbCreateメソッドが含まれている必要があります。ejbRemoveなどのコンテナ・サービス・メソッド用の空の実装を含めます。 

  1. Beanのホーム・インタフェースを作成します(「EJB 2.1ホーム・インタフェースの実装」を参照)。

    リモート・ホーム・インタフェースは、クライアントがBeanをインスタンス化するためにリモートで起動できるcreateおよびfinderメソッドを定義します。ローカル・ホーム・インタフェースは、Beanをインスタンス化するために同一JVM上のBeanがローカルで起動できるcreateおよびfinderメソッドを定義します。

    finderの詳細は、「finderメソッドについて」を参照してください。

    1. リモート・ホーム・インタフェースを作成するには、javax.ejb.EJBHomeを拡張します(「リモート・ホーム・インタフェースの実装」を参照)。

    2. ローカル・ホーム・インタフェースを作成するには、javax.ejb.EJBLocalHomeを拡張します(「ローカル・ホーム・インタフェースの実装」を参照)。

  2. Beanのコンポーネント・インタフェースを作成します(「EJB 2.1コンポーネント・インタフェースの実装」を参照)。

    リモート・コンポーネント・インタフェースは、クライアントがリモートで起動できるビジネス・メソッドを宣言します。ローカル・インタフェースは、同一JVM上のBeanがローカルで起動できるビジネス・メソッドを宣言します。

    1. リモート・コンポーネント・インタフェースを作成するには、javax.ejb.EJBObjectを拡張します(「リモート・コンポーネント・インタフェースの実装」を参照)。

    2. ローカル・コンポーネント・インタフェースを作成するには、javax.ejb.EJBLocalObjectを拡張します(「ローカル・コンポーネント・インタフェースの実装」を参照)。

  3. Beanの主キーを定義します(「コンテナ管理の永続性を備えたEJB 2.1エンティティBeanの主キーの構成」を参照)。

    主キーはシリアライズ可能なクラスで、各エンティティBeanインスタンスを識別します。単純なデータ型クラス(java.lang.Stringなど)を使用したり、複合クラス(主キーのコンポーネントとして複数のオブジェクトを持つクラスなど)を定義できます。

  4. 次のようにコンテナ管理の永続性を備えたエンティティBeanを実装します。

    1. ホーム・インタフェースで宣言されたgetterおよびsetterメソッドに対応する抽象getterおよびsetterメソッドを実装します。

      コンテナ管理の永続性を備えたエンティティBeanの場合、コンテナが実装を行うため、getterおよびsetterメソッドはpublic abstractです。

    2. ホームおよびコンポーネント・インタフェースで宣言したビジネス・メソッドを実装します(存在する場合)。これらの各メソッドのシグネチャは、BeanがRemoteExceptionをスローしない場合を除き、リモートまたはローカル・インタフェースのシグネチャに一致している必要があります。ローカル・インタフェースおよびリモート・インタフェースはBean実装を使用するため、Bean実装ではRemoteExceptionをスローできません。

      エンティティBeanの場合、これらのメソッドはセッションBeanに委任されることがあります(「セッションBeanとは」を参照)。

    3. ビジネス・ロジックに使用されるBeanまたはパッケージに対してプライベートであるメソッドを実装します。これには、パブリック・メソッドがリクエストされた作業の完了に使用するプライベート・メソッドも含まれます。

    4. ホーム・インタフェースで宣言された各createメソッドに対応するejbCreateメソッドを実装します。クライアントがcreateメソッドを起動すると、コンテナによって対応するejbCreateメソッドが起動されます。

      すべてのebjCreateメソッドの戻り型は、Beanの主キーの型です。

      コンテナ管理の永続性を備えたエンティティBeanの場合は、コンテナがデータベースに維持する値をクライアントが渡せるようにするcreateメソッドを提供します。

    5. javax.ejb.EntityBeanインタフェース・コンテナのコールバック・メソッドの空の実装を提供します。

      詳細は、「コンテナ管理の永続性を備えたEJB 2.1エンティティBeanのライフ・サイクル・コールバック・メソッドの構成」を参照してください。

    6. EntityContextのインスタンスを受け取る)setEntityContextメソッドおよびunsetEntityContextメソッドを実装します(「setEntityContextおよびunsetEntityContextメソッドの実装」を参照)。

    7. オプションで、エンティティBeanのビジネス・メソッドで使用する0個以上のpublic abstractのselectメソッド(「selectメソッドについて」を参照)を定義します。

  5. エンティティBeanの適切なデータベース・スキーマ(表と列)を作成します。

    コンテナ管理の永続性を備えたエンティティBeanの場合は、永続性属性をデータベースに格納する方法を指定するか、表の作成を管理するようにコンテナを構成できます。

    詳細は、次を参照してください。

  6. Bean実装と一致するように、またdata-sources.xmlファイルで定義されているデータソースを参照するようにejb-jar.xmlファイルを構成します(「デプロイXMLの使用方法」を参照)。

  7. エンティティBeanの構成を完了します(第14章「コンテナ管理の永続性を備えたEJB 2.1エンティティBeanの使用方法」を参照)。

Javaの使用方法

例13-1に、コンテナ管理の永続性を備えたEJB 2.1エンティティBeanの一般的な実装を示します。例13-2では対応するリモート・ホーム・インタフェースを示し、例13-3では対応するリモート・コンポーネント・インタフェースを示します。

例13-1    コンテナ管理の永続性を備えたEJB 2.1エンティティBeanの実装

package cmpapp;

import javax.ejb.*;
import java.rmi.*;

public abstract class EmployeeBean implements EntityBean {

    private EntityContext ctx;

    // container-managed persistent fields accessors
    public abstract Integer getEmpNo();
    public abstract void setEmpNo(Integer empNo);

    public abstract String getEmpName();
    public abstract void setEmpName(String empName);

    public abstract Float getSalary();
    public abstract void setSalary(Float salary);

    public void EmployeeBean() {
        // Empty constructor, don't initialize here but in the create().
        // passivate() may destroy these attributes in the case of pooling
    }

    public EmployeePK ejbCreate(Integer empNo, String empName, Float salary)
        throws CreateException {
        setEmpNo(empNo);
        setEmpName(empName);
        setSalary(salary);
        return new EmployeePK(empNo);
    }

    public void ejbPostCreate(Integer empNo, String empName, Float salary)
        throws CreateException {
        // when just after bean created
    }

    public void ejbStore() {
        // when bean persisted
    }

    public void ejbLoad() {
        // when bean loaded
    }

    public void ejbRemove() {
        // when bean removed
    }

    public void ejbActivate() {
        // when bean activated
    }

    public void ejbPassivate() {
        // when bean deactivated
    }

    public void setEntityContext(EntityContext ctx) {
        this.ctx = ctx;
    }

    public void unsetEntityContext() {
        this.ctx = null;
    }

}

例13-2    EJB 2.1 CMPリモート・ホーム・インタフェース

package cmpapp;

import java.rmi.*;
import java.util.*;
import javax.ejb.*;

public interface EmployeeHome extends EJBHome {
     public Employee create(Integer empNo, String empName, Float salary)
         throws CreateException, RemoteException;

     public Employee findByPrimaryKey(EmployeePK pk)
         throws FinderException, RemoteException;

     public Collection findByName(String empName)
         throws FinderException, RemoteException;

     public Collection findAll()
         throws FinderException, RemoteException;
}

例13-3    EJB 2.1 CMPリモート・コンポーネント・インタフェース

package cmpapp;

import javax.ejb.*;
import java.rmi.*;

public interface Employee extends EJBObject {
    // container-managed persistent fields accessors
    public Integer getEmpNo() throws RemoteException;
    public void setEmpNo(Integer empNo) throws RemoteException;

    public String getEmpName() throws RemoteException;
    public void setEmpName(String empName) throws RemoteException;

    public Float getSalary() throws RemoteException;
    public void setSalary(Float salary) throws RemoteException;
}

デプロイXMLの使用方法

例13-4に、例13-1に示したコンテナ管理の永続性を備えたエンティティBeanに対応するejb-jar.xmlファイルのentity要素を示します。

例13-4    コンテナ管理の永続性を備えたEJB 2.1エンティティBeanのejb-jar.xml

...
    <enterprise-beans>
        <entity>
            <description>no description</description>
            <display-name>EmployeeBean</display-name>
            <ejb-name>EmployeeBean</ejb-name>
            <home>cmpapp.EmployeeHome</home>
            <remote>cmpapp.Employee</remote>
            <ejb-class>cmpapp.EmployeeBean</ejb-class>
            <persistence-type>Container</persistence-type>
            <cmp-version>2.x</cmp-version>
            <abstract-schema-name>EmployeeBean</abstract-schema-name>
            <prim-key-class>cmpapp.EmployeePK</prim-key-class>
            <reentrant>False</reentrant>
            <cmp-field><field-name>empNo</field-name></cmp-field>
            <cmp-field><field-name>empName</field-name></cmp-field>
            <cmp-field><field-name>salary</field-name></cmp-field>
            <query>
                <description></description>
                <query-method>
                <method-name>findAll</method-name>
                <method-params/>
                </query-method>
                <ejb-ql>Select OBJECT(e) From EmployeeBean e</ejb-ql>
            </query>
            <query>
                <description></description>
                <query-method>
                <method-name>findByName</method-name>
                <method-params>
                <method-param>java.lang.String</method-param>
                </method-params>
                </query-method>
                <ejb-ql>Select OBJECT(e) From EmployeeBean e where e.empName = ?1</ejb-ql>
            </query>
        </entity>
    </enterprise-beans>
...

 

Bean管理の永続性を備えたEJB 2.1エンティティBeanの実装

表13-2に、Bean管理の永続性を備えたEJB 2.1エンティティBeanの重要な構成要素をまとめます。次の手順では、これらの構成要素の実装方法を説明します。一般的な実装は、「Javaの使用方法」を参照してください。詳細は、「Bean管理の永続性を備えたEJB 2.1エンティティBeanとは」を参照してください。

表13-2    Bean管理の永続性を備えたEJB 2.1エンティティBeanの構成要素 
構成要素  説明 

ホーム・インタフェース
(リモートまたはローカル) 

リモート・ホーム・インタフェースのjavax.ejb.EJBHome、ローカル・ホーム・インタフェースのjavax.ejb.EJBLocalHomeを拡張し、引数を取らない1つのcreateファクトリ・メソッド、および1つのremoveメソッドを必要とします。 

コンポーネント・インタフェース(リモートまたはローカル) 

リモート・インタフェースの場合はjavax.ejb.EJBObjectを拡張し、ローカル・インタフェースの場合はjavax.ejb.EJBLocalObjectを拡張します。また、Bean実装で実装されるビジネス・ロジック・メソッドを定義します。 

Beanの実装 

EntityBeanを実装します。このクラスは、パブリックとして宣言する必要があり、パブリックで空のデフォルト・コンストラクタを含み、finalizeメソッドは使用しません。また、コンポーネント・インタフェースで定義されたメソッドを実装します。ホーム・インタフェースのcreateメソッドに一致する1つ以上のejbCreateメソッドが含まれている必要があります。ejbStoreejbLoadejbRemoveなどのコンテナ・サービス・メソッド用の完全な実装を含めます。 

  1. Beanのホーム・インタフェースを作成します(「EJB 2.1ホーム・インタフェースの実装」を参照)。

    リモート・ホーム・インタフェースは、クライアントがBeanをインスタンス化するためにリモートで起動できるcreateメソッドを定義します。ローカル・ホーム・インタフェースは、Beanをインスタンス化するために同一JVM上のBeanがローカルで起動できるcreateメソッドを定義します。

    1. リモート・ホーム・インタフェースを作成するには、javax.ejb.EJBHomeを拡張します(「リモート・ホーム・インタフェースの実装」を参照)。

    2. ローカル・ホーム・インタフェースを作成するには、javax.ejb.EJBLocalHomeを拡張します(「ローカル・ホーム・インタフェースの実装」を参照)。

  2. Beanのコンポーネント・インタフェースを作成します(「EJB 2.1コンポーネント・インタフェースの実装」を参照)。

    リモート・コンポーネント・インタフェースは、クライアントがリモートで起動できるビジネス・メソッドを宣言します。ローカル・インタフェースは、同一JVM上のBeanがローカルで起動できるビジネス・メソッドを宣言します。

    1. リモート・コンポーネント・インタフェースを作成するには、javax.ejb.EJBObjectを拡張します(「リモート・コンポーネント・インタフェースの実装」を参照)。

    2. ローカル・コンポーネント・インタフェースを作成するには、javax.ejb.EJBLocalObjectを拡張します(「ローカル・コンポーネント・インタフェースの実装」を参照)。

  3. Beanの主キーを定義します(「Bean管理の永続性を備えたEJB 2.1エンティティBeanの主キーの構成」を参照)。

    主キーはシリアライズ可能なクラスで、各エンティティBeanインスタンスを識別します。単純なデータ型クラス(java.lang.Stringなど)を使用したり、複合クラス(主キーのコンポーネントとして複数のオブジェクトを持つクラスなど)を定義できます。

  4. 次のようにBean管理の永続性を備えたエンティティBeanを実装します。

    1. ホーム・インタフェースで宣言されたgetおよびsetメソッドに対応するgetおよびsetメソッドの完全な実装を提供します。

      Bean管理の永続性を備えたエンティティBeanの場合、ユーザーが実装を行うため、getterおよびsetterメソッドはpublicです。

    2. ホームおよびコンポーネント・インタフェースで宣言したビジネス・メソッドを実装します(存在する場合)。これらの各メソッドのシグネチャは、BeanがRemoteExceptionをスローしない場合を除き、リモートまたはローカル・インタフェースのシグネチャに一致している必要があります。ローカル・インタフェースおよびリモート・インタフェースはBean実装を使用するため、Bean実装ではRemoteExceptionをスローできません。

      エンティティBeanの場合、これらのメソッドはセッションBeanに委任されることがあります(「セッションBeanとは」を参照)。

    3. ビジネス・ロジックに使用されるBeanまたはパッケージに対してプライベートであるメソッドを実装します。これには、パブリック・メソッドがリクエストされた作業の完了に使用するプライベート・メソッドも含まれます。

    4. ホーム・インタフェースで宣言された各createメソッドに対応するejbCreateメソッドを実装します。クライアントがcreateメソッドを起動すると、コンテナによって対応するejbCreateメソッドが起動されます。

      すべてのebjCreateメソッドの戻り型は、Beanの主キーの型です。

      Bean管理の永続性を備えたエンティティBeanの場合は、コンテナがデータベースに維持する値をクライアントが渡せるようにするcreateメソッドを提供します。データベースのインスタンスを作成するためにデータベースと(通常は直接JDBCコールを通じて)対話する実装をユーザーが提供します。

      詳細は、「Bean管理の永続性を備えたEJB 2.1エンティティBeanのejbCreateメソッドの実装」を参照してください。

    5. javax.ejb.EntityBeanインタフェース・コンテナのコールバック・メソッドの完全な実装を提供します(「Bean管理の永続性を備えたEJB 2.1エンティティBeanのライフ・サイクル・コールバック・メソッドの構成」を参照)。

      Bean管理の永続性を備えたエンティティBeanの場合は、データベースの永続性を管理するためにデータベースと(通常は直接JDBCコールを通じて)対話するこれらの各メソッドの実装をユーザーが提供します。

    6. EntityContextのインスタンスを受け取るsetEntityContextメソッドおよびunsetEntityContextメソッドを実装します(「setEntityContextおよびunsetEntityContextメソッドの実装」を参照)。

    7. 必須のfindByPrimaryKey finderメソッドを実装し、オプションで他のfinderを実装します(「Bean管理の永続性を備えたEJB 2.1エンティティBeanの問合せの構成」を参照)。

  5. エンティティBeanの適切なデータベース・スキーマ(表と列)を作成します。

    Bean管理の永続性を備えたエンティティBeanの場合は、アプリケーションがBean管理の永続性を備えたエンティティBeanのインスタンスの作成を試行する前に、ユーザーが(data-sources.xmlファイルで定義されている)データベースにこのスキーマを作成します。

  6. Bean実装と一致するように、またdata-sources.xmlファイルで定義されているデータソースを参照するようにejb-jar.xmlファイルを構成します(「デプロイXMLの使用方法」を参照)。

  7. エンティティBeanの構成を完了します(第15章「Bean管理の永続性を備えたEJB 2.1エンティティBeanの使用方法」を参照)。

Javaの使用方法

例13-5に、Bean管理の永続性を備えたEJB 2.1エンティティBeanの一般的な実装を示します。例13-7では対応するホーム・インタフェースを示し、例13-6では対応するリモート・インタフェースを示します。

例13-5    Bean管理の永続性を備えたEJB 2.1エンティティBeanの実装

package bmpapp;

import java.util.*;
import java.rmi.*;
import java.sql.*;
import javax.sql.*;
import javax.naming.*;
import javax.ejb.*;

public class EmployeeBean implements EntityBean {

    public Integer empNo;

    public EntityContext ctx;
    private Connection conn = null;
    private PreparedStatement ps = null;
    private EmployeePK pk;
    private static final String dsName = "jdbc/OracleDS";

    private static final String insertStatement =
        "INSERT INTO EMP (EMPNO, ENAME, SAL) VALUES (?, ?, ?)";
    private static final String updateStatement =
        "UPDATE EMP SET ENAME=?, SAL=? WHERE EMPNO=?";
    private static final String deleteStatement =
        "DELETE FROM EMP WHERE EMPNO=?";
    private static final String findAllStatement =
        "SELECT EMPNO, ENAME, SAL FROM EMP";
    private static final String findByPKStatement =
        "SELECT EMPNO, ENAME, SAL FROM EMP WHERE EMPNO = ?";
    private static final String findByNameStatement =
        "SELECT EMPNO, ENAME, SAL FROM EMP WHERE ENAME = ?";
    // or you can define a variable specific to orion to implement finder-method:
    // or use <finder-method/> in orion-ejb-jar.xml
    public static final String findByNameQuery="full: " +
        "SELECT EMPNO, ENAME, SAL FROM EMP WHERE ENAME = $1";

    public EmployeeBean() {
        // Empty constructor, don't initialize here but in the create().
        // passivate() may destroy these attributes in the case of pooling
    }

    public EmployeePK ejbCreate(Integer empNo, String empName, Float salary)
        throws CreateException {
        try {
            pk = new EmployeePK(empNo, empName, salary);
            conn = getConnection(dsName);
            ps = conn.prepareStatement(insertStatement);
            ps.setInt(1, empNo.intValue());
            ps.setString(2, empName);
            ps.setFloat(3, salary.floatValue());
            ps.executeUpdate();
            return pk;
        }
        catch (SQLException e) {
            System.out.println("Caught an exception 1 " + e.getMessage() );
            throw new CreateException(e.getMessage());
        }
        catch (NamingException e) {
            System.out.println("Caught an exception 1 " + e.getMessage() );
            throw new EJBException(e.getMessage());
        }
        finally {
            try {
                ps.close();
                conn.close();
            } catch (SQLException e) {
                throw new EJBException(e.getMessage());
            }
        }
    }

    public void ejbPostCreate(Integer empNo, String empName, Float salary)
        throws CreateException {
    }

    public EmployeePK ejbFindByPrimaryKey(EmployeePK pk)
        throws FinderException {
        if (pk == null || pk.empNo == null) {
            throw new FinderException("Primary key cannot be null");
        }
        try {
            conn = getConnection(dsName);
            ps = conn.prepareStatement(findByPKStatement);
            ps.setInt(1, pk.empNo.intValue());
            ps.executeQuery();
            ResultSet rs = ps.getResultSet();
            if (rs.next()) {
                pk.empNo = new Integer(rs.getInt(1));
                pk.empName = new String(rs.getString(2));
                pk.salary = new Float(rs.getFloat(3));
            }
            else {
                throw new FinderException("Failed to select this PK");
            }
        }
        catch (SQLException e) {
            throw new FinderException(e.getMessage());
        }
        catch (NamingException e) {
            System.out.println("Caught an exception 1 " + e.getMessage() );
            throw new EJBException(e.getMessage());
        }
        finally {
            try {
                ps.close();
                conn.close();
            }
        catch (SQLException e) {
                throw new EJBException(e.getMessage());
            }
        }
        return pk;
    }

    public Collection ejbFindAll() throws FinderException {
        //System.out.println("EmployeeBean.ejbFindAll(): begin");
        Vector recs = new Vector();
        try {
            conn = getConnection(dsName);
            ps = conn.prepareStatement(findAllStatement);
            ps.executeQuery();
            ResultSet rs = ps.getResultSet();
            int i = 0;
            while (rs.next()) {
                pk = new EmployeePK();
                pk.empNo = new Integer(rs.getInt(1));
                pk.empName = new String(rs.getString(2));
                pk.salary = new Float(rs.getFloat(3));
                recs.add(pk);
            }
        }
        catch (SQLException e) {
            throw new FinderException(e.getMessage());
        }
        catch (NamingException e) {
            System.out.println("Caught an exception 1 " + e.getMessage() );
            throw new EJBException(e.getMessage());
        }
        finally {
            try {
                ps.close();
                conn.close();
            }
            catch (SQLException e) {
                throw new EJBException(e.getMessage());
            }
        }
        return recs;
    }

    public Collection ejbFindByName(String empName)
        throws FinderException {
        //System.out.println("EmployeeBean.ejbFindByName(): begin");
        if (empName == null) {
            throw new FinderException("Name cannot be null");
        }
        Vector recs = new Vector();
        try {
            conn = getConnection(dsName);
            ps = conn.prepareStatement(findByNameStatement);
            ps.setString(1, empName);
            ps.executeQuery();
            ResultSet rs = ps.getResultSet();
            int i = 0;
            while (rs.next()) {
                pk = new EmployeePK();
                pk.empNo = new Integer(rs.getInt(1));
                pk.empName = new String(rs.getString(2));
                pk.salary = new Float(rs.getFloat(3));
                recs.add(pk);
            }
        }
        catch (SQLException e) {
            throw new FinderException(e.getMessage());
        }
        catch (NamingException e) {
            System.out.println("Caught an exception 1 " + e.getMessage() );
            throw new EJBException(e.getMessage());
        }
        finally {
            try {
                ps.close();
                conn.close();
            }
            catch (SQLException e) {
                throw new EJBException(e.getMessage());
            }
        }
        return recs;
    }

    public void ejbLoad() throws EJBException {
        //Container invokes this method to instruct the instance to
        //synchronize its state by loading it from the underlying database
        //System.out.println("EmployeeBean.ejbLoad(): begin");
        try {
            pk = (EmployeePK) ctx.getPrimaryKey();
            ejbFindByPrimaryKey(pk);
        }
        catch (FinderException e) {
            throw new EJBException (e.getMessage());
        }
    }

    public void ejbStore() throws EJBException {
        //Container invokes this method to instruct the instance to
        //synchronize its state by storing it to the underlying database
        //System.out.println("EmployeeBean.ejbStore(): begin");
        try {
            pk = (EmployeePK) ctx.getPrimaryKey();
            conn = getConnection(dsName);
            ps = conn.prepareStatement(updateStatement);
            ps.setString(1, pk.empName);
            ps.setFloat(2, pk.salary.floatValue());
            ps.setInt(3, pk.empNo.intValue());
            if (ps.executeUpdate() != 1) {
                throw new EJBException("Failed to update record");
            }
        }
        catch (SQLException e) {
            throw new EJBException(e.getMessage());
        }
        catch (NamingException e) {
            System.out.println("Caught an exception 1 " + e.getMessage() );
            throw new EJBException(e.getMessage());
        }
        finally {
            try {
                ps.close();
                conn.close();
            }
            catch (SQLException e) {
                throw new EJBException(e.getMessage());
            }
        }
    }

    public void ejbRemove() throws RemoveException {
        //Container invokes this method befor it removes the EJB object
        //that is currently associated with the instance
        //System.out.println("EmployeeBean.ejbRemove(): begin");
        try {
            pk = (EmployeePK) ctx.getPrimaryKey();
            conn = getConnection(dsName);
            ps = conn.prepareStatement(deleteStatement);
            ps.setInt(1, pk.empNo.intValue());
            if (ps.executeUpdate() != 1) {
                throw new RemoveException("Failed to delete record");
            }
        }
        catch (SQLException e) {
            throw new RemoveException(e.getMessage());
        }
        catch (NamingException e) {
            System.out.println("Caught an exception 1 " + e.getMessage() );
            throw new EJBException(e.getMessage());
        }
        finally {
            try {
                ps.close();
                conn.close();
            }
            catch (SQLException e) {
                throw new EJBException(e.getMessage());
            }
        }
    }

    public void ejbActivate() {
        // Container invokes this method when the instance is taken out
        // of the pool of available instances to become associated with
        // a specific EJB object
        //System.out.println("EmployeeBean.ejbActivate(): begin");
    }

    public void ejbPassivate() {
        // Container invokes this method on an instance before the instance
        // becomes disassociated with a specific EJB object
        //System.out.println("EmployeeBean.ejbPassivate(): begin");
    }

    public void setEntityContext(EntityContext ctx) {
        //Set the associated entity context
        //System.out.println("EmployeeBean.setEntityContext(): begin");
        this.ctx = ctx;
    }

    public void unsetEntityContext() {
        //Unset the associated entity context
        //System.out.println("EmployeeBean.unsetEntityContext(): begin");
        this.ctx = null;
    }

    /**
     * methods inherited from EJBObject
     */
    public Integer getEmpNo() {
        pk = (EmployeePK) ctx.getPrimaryKey();
        return pk.empNo;
    }

    public String getEmpName() {
        pk = (EmployeePK) ctx.getPrimaryKey();
        return pk.empName;
    }

    public Float getSalary() {
        pk = (EmployeePK) ctx.getPrimaryKey();
        return pk.salary;
    }

    public void setEmpNo(Integer empNo) {
        pk = (EmployeePK) ctx.getPrimaryKey();
        pk.empNo = empNo;
    }

    public void setEmpName(String empName) {
        pk = (EmployeePK) ctx.getPrimaryKey();
        pk.empName = empName;
    }

    public void setSalary(Float salary) {
        pk = (EmployeePK) ctx.getPrimaryKey();
        pk.salary = salary;
    }

    public EJBHome getEJBHome() {
        return ctx.getEJBHome();
    }

    public Handle getHandle() throws RemoteException {
        return ctx.getEJBObject().getHandle();
    }

    public Object getPrimaryKey() throws RemoteException {
        return ctx.getEJBObject().getPrimaryKey();
    }

    public boolean isIdentical(EJBObject remote) throws RemoteException {
        return ctx.getEJBObject().isIdentical(remote);
    }

    public void remove() throws RemoveException, RemoteException{
        ctx.getEJBObject().remove();
    }

    /**
     * Private methods
     */
    private Connection getConnection(String dsName)
             throws SQLException, NamingException {
        DataSource ds = getDataSource(dsName);
        return ds.getConnection();
    }

    private DataSource getDataSource(String dsName) throws NamingException {
        DataSource ds = null;
        Context ic = new InitialContext();
        ds = (DataSource) ic.lookup(dsName);
        return ds;
    }
}

例13-6    EJB 2.1 BMPリモート・ホーム・インタフェース

package bmpapp;

import java.rmi.*;
import java.util.*;
import javax.ejb.*;

public interface EmployeeHome extends EJBHome {

    public Employee create(Integer empNo, String empName, Float salary)
        throws CreateException, RemoteException;

    public Employee findByPrimaryKey(EmployeePK pk)
        throws FinderException, RemoteException;

    public Collection findByName(String empName)
        throws FinderException, RemoteException;

    public Collection findAll()
        throws FinderException, RemoteException;
}

例13-7    EJB 2.1 BMPリモート・コンポーネント・インタフェース

package bmpapp;

import java.rmi.*;
import javax.ejb.*;

public interface Employee extends EJBObject {

    // getter remote methods
    public Integer getEmpNo() throws RemoteException;
    public String getEmpName() throws RemoteException;
    public Float getSalary() throws RemoteException;

    // setter remote methods
    public void setEmpNo(Integer empNo) throws RemoteException;
    public void setEmpName(String empName) throws RemoteException;
    public void setSalary(Float salary) throws RemoteException;
}

デプロイXMLの使用方法

例13-8に、例13-5に示したBean管理の永続性を備えたエンティティBeanに対応するejb-jar.xmlエンティティ要素を示します。

例13-8    Bean管理の永続性を備えたEJB 2.1エンティティBeanのejb-jar.xml

...
    <enterprise-beans>
        <entity>
            <description>no description</description>
            <display-name>EmployeeBean</display-name>
            <ejb-name>EmployeeBean</ejb-name>
            <home>bmpapp.EmployeeHome</home>
            <remote>bmpapp.Employee</remote>
            <ejb-class>bmpapp.EmployeeBean</ejb-class>
            <persistence-type>Bean</persistence-type>
            <prim-key-class>bmpapp.EmployeePK</prim-key-class>
            <reentrant>False</reentrant>
            <resource-ref>
                <res-ref-name>jdbc/OracleDS</res-ref-name>
                <res-type>javax.sql.DataSource</res-type>
                <res-auth>Application</res-auth>
            </resource-ref>
        </entity>
    </enterprise-beans>
...

例13-9に、例13-8で示したejb-jar.xmlファイルで使用したres-ref-namejdbc/OracleDS)を指定するdata-sources.xmlファイルのdata-source要素のejb-location属性を示します。

例13-9    Bean管理の永続性を備えたEJB 2.1エンティティBeanデータソースのdata-sources.xml

    <connection-pool name="Example Connection Pool">
        <!-- This is an example of a connection factory that emulates XA behavior. -->
        <connection-factory factory-class="oracle.jdbc.pool.OracleDataSource"
            user="scott"
            password="tiger"
            url="jdbc:oracle:thin:@//localhost:1521/oracle.regress.rdbms.dev.us.oracle.com">
        </connection-factory>
    </connection-pool>

    <managed-data-source name="OracleDS"
        connection-pool-name="Example Connection Pool"
        jndi-name="jdbc/OracleDS"/>

Bean管理の永続性を備えたEJB 2.1エンティティBeanのejbCreateメソッドの実装

ejbCreateメソッドは、主に主キーの作成を実行します。次のものが含まれます。

  1. 主キーの作成

  2. キーに対する永続データ表現の作成

  3. 一意の値へのキーの初期化および重複がないことの確認

  4. コンテナへのこのキーの返却

コンテナにより、キーがエンティティBeanの参照にマッピングされます。

次の例では、employeeの例のejbCreateメソッドを示します。このメソッドは、主キーであるempNoを初期化します。これは、本来なら、自動的に、次に使用可能な従業員番号である主キーを生成します。ただし、ここでは例を簡単にするために、このejbCreateメソッドはユーザーに一意の従業員番号を入力するよう求めます。


注意

単純化のために、この例ではサンプル内のtryブロックが省略されています。 


さらに、従業員の全データがこのメソッドで提供されるため、データはこのインスタンスのコンテキスト変数内に格納されます。初期化後、このキーがコンテナに返されます。

// The create methods takes care of generating a new empNo and returns
// its primary key to the container
public Integer ejbCreate (Integer empNo, String empName, Float salary) 
   throws CreateException {
  // in this implementation, the client gives the employee number,
  // so only need to assign it, not create it 
  this.empNo = empNo;
  this.empName = empName;
  this.salary = salary;
  
  // insert employee into database 
  conn = getConnection(dsName);
  ps = conn.prepareStatement("INSERT INTO EMPLOYEEBEAN (EmpNo, EmpName, SAL) 
       VALUES ( "+this.empNo.intValue()+", "+this.empName+","
       + this.salary.floatValue()+")");
  ps.executeUpdate();
  ps.close();

  // return the new primary key
  return (empNo);
}

このデプロイメント・ディスクリプタでは、<prim-key-class>要素内で、主キー・クラスのみ定義します。Beanがデータを保存するため、デプロイメント・ディスクリプタには、永続データの定義は存在しません。ただし、デプロイメント・ディスクリプタの<resource-ref>要素で、Beanが使用するデータベースを定義します。データベース構成の詳細は、「デプロイXMLの使用方法」を参照してください。

<enterprise-beans>
   <entity>
      <display-name>EmployeeBean</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>Bean</persistence-type>
      <prim-key-class>java.lang.Integer</prim-key-class>
      <reentrant>False</reentrant>
      <resource-ref>
            <res-ref-name>jdbc/OracleDS</res-ref-name>
            <res-type>javax.sql.DataSource</res-type>
            <res-auth>Application</res-auth>
      </resource-ref>
   </entity>
</enterprise-beans>

または、複数のデータ型に基づいた複合主キーを作成可能です。複合主キーは、次のように、そのクラス内で定義します。

package employee;

import java.io.*;
java.io.Serializable;

...

public class EmployeePK implements java.io.Serializable {
  public Integer empNo;
  public String empName;
  public Float salary;

  public EmployeePK(Integer empNo) {
    this.empNo = empNo;
    this.empName = null;
    this.salary = null;
  }

  public EmployeePK(Integer empNo, String empName, Float salary) {
    this.empNo = empNo;
    this.empName = empName;
    this.salary = salary;
  }
  
}

主キー・クラスの場合、クラスを<prim-key-class>要素で定義します。これは、単純な主キー定義と同じです。

<enterprise-beans>
   <entity>
      <display-name>EmployeeBean</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>Bean</persistence-type>
      <prim-key-class>employee.EmployeePK</prim-key-class>
      <reentrant>False</reentrant>
      <resource-ref>
            <res-ref-name>jdbc/OracleDS</res-ref-name>
            <res-type>javax.sql.DataSource</res-type>
            <res-auth>Application</res-auth>
      </resource-ref>
   </entity>
</enterprise-beans>

employeeの例では、ユーザーが従業員番号をBeanに対して指定する必要があります。別の手段としては、次に使用可能な従業員番号を計算し、この番号を従業員の名前および勤務地と組み合せて従業員番号を生成する方法があります。

複合主キー・クラスの定義後、次のように、ejbCreateメソッド内で主キーを作成します。

public EmployeePK ejbCreate(Integer empNo, String empName, Float salary)
    throws CreateException {
  pk = new EmployeePK(empNo, empName, salary);
  ...
}

ejbCreate(またはejbPostCreate)が処理する作業には、他に、Beanの存続期間中に必要なリソースの割当てがあります。この例では、すでに従業員情報が存在するため、ejbCreateは次の処理を実行します。

  1. データベースへの接続を取得します。この接続は、Beanの存続期間中オープンされています。データベース内の従業員情報の更新に使用されます。ejbPassivateおよびejbRemoveで解放し、ejbActivateで再割当てを行います。

  2. データベースの従業員情報を更新します。

これは、次のように実行されます。

public EmployeePK ejbCreate(Integer empNo, String empName, Float salary)
    throws CreateException {
  pk = new EmployeePK(empNo, empName, salary);
  conn = getConnection(dsName);
  ps = conn.prepareStatement("INSERT INTO EMPLOYEEBEAN (EmpNo, EmpName, SAL) 
      VALUES ( "+this.empNo.intValue()+", "+this.empName+","
      + this.salary.floatValue()+")");
  ps.executeUpdate();
  ps.close();
  return pk;
}

EJB 2.1ホーム・インタフェースの実装

ホーム・インタフェースは、クライアントがエンティティBeanインスタンスの作成または取得に使用するメソッドを指定するために使用します。

ホーム・インタフェースには、クライアントがBeanのインスタンスを作成するために起動するcreateメソッドが含まれている必要があります。エンティティBeanには、それぞれ定義されたパラメータを持つ0(ゼロ)以上のcreateメソッドを使用できます。各createメソッドにつき、対応するejbCreateメソッドをBean実装で定義します。

すべてのエンティティBeanで、1つ以上のfinderメソッドをホーム・インタフェースに定義する必要があります。そのうちの1つ以上はfindByPrimaryKeyメソッドである必要があります。オプションで、事前定義およびデフォルトのfinderを含む他のfinderメソッドを定義できます。これらには、find<name>のように名前を付けます。詳細は、「finderメソッドについて」を参照してください。

メソッドの作成および取得に加えて、ホーム・インタフェース内でホーム・インタフェースのビジネス・メソッドを提供できます。このメソッドの機能では、特定のエンティティ・オブジェクトのデータにアクセスできません。このメソッドは、単一のエンティティBeanインスタンスに関連がない情報を取得するために使用します。クライアントがホーム・インタフェースの任意のビジネス・メソッドを起動すると、エンティティBeanはプールから移動され、リクエストを処理します。したがって、このメソッドを使用すると、Beanに関連する一般的な情報に関する操作を実行できます。

たとえば、employeeアプリケーションでは、ローカル・ホーム・インタフェースにcreatefindByPrimaryKeyfindAllおよびcalcSalaryメソッドを提供できます。calcSalaryメソッドは、全従業員の給与合計を計算する、ホーム・インタフェースのビジネス・メソッドです。このメソッドは特定の従業員の情報にはアクセスしませんが、全従業員のデータベースに対してSQL問合せを実行します。

ホーム・インタフェースには次の2種類があります。

リモート・ホーム・インタフェースの実装

リモート・クライアントは、リモート・インタフェースを介してEJBを起動します。クライアントは、リモート・ホーム・インタフェースで宣言されたcreateメソッドを起動します。コンテナは、Bean実装内の、適切なパラメータ・シグネチャを持つejbCreateメソッドにクライアント・コールを渡します。リモート・ホーム・インタフェースを開発するための要件は次のとおりです。

例13-2に、例13-1のコンテナ管理の永続性を備えたEJB 2.1エンティティBeanに対応するリモート・ホーム・インタフェースを示します。例13-6に、例13-5のBean管理の永続性を備えたEJB 2.1エンティティBeanに対応するリモート・ホーム・インタフェースを示します。

ローカル・ホーム・インタフェースの実装

EJBは、同じコンテナに存在するクライアントからローカルでコールできます。したがって、同一JVM上のBean、JSPまたはサーブレットは、ローカル・ホーム・インタフェースで宣言されたcreateメソッドを起動します。コンテナは、Bean実装内の、適切なパラメータ・シグネチャを持つejbCreateメソッドにクライアント・コールを渡します。ローカル・ホーム・インタフェースを開発するための要件は、次のとおりです。

EJB 2.1コンポーネント・インタフェースの実装

コンポーネント・インタフェースでは、クライアントから起動可能なBeanのビジネス・メソッドを定義します。

エンティティBeanコンポーネント・インタフェースは、クライアントがそのメソッドを起動できるインタフェースです。コンポーネント・インタフェースは、エンティティBeanインスタンスのビジネス・ロジック・メソッドを定義します。

コンポーネント・インタフェースには次の2種類があります。

リモート・コンポーネント・インタフェースの実装

リモート・インタフェースでは、リモート・クライアントによって起動可能なビジネス・メソッドを定義します。リモート・コンポーネント・インタフェースを開発するための要件は、次のとおりです。

例13-3に、例13-1のコンテナ管理の永続性を備えたEJB 2.1エンティティBeanに対応するリモート・コンポーネント・インタフェースを示します。例13-7に、例13-5のBean管理の永続性を備えたEJB 2.1エンティティBeanに対応するリモート・コンポーネント・インタフェースを示します。

ローカル・コンポーネント・インタフェースの実装

ローカル・コンポーネント・インタフェースでは、ローカル(同一JVM上の)クライアントから起動可能なBeanのビジネス・メソッドを定義します。ローカル・コンポーネント・インタフェースを開発するための要件は、次のとおりです。

setEntityContextおよびunsetEntityContextメソッドの実装

エンティティBeanのインスタンスは、このメソッドを使用して、コンテキストへの参照を維持します。エンティティBeanには、コンテナによって維持され、Beanから使用可能なコンテキストが存在します。エンティティ・コンテキスト内のメソッドを使用して、セキュリティおよびトランザクションのロールなどのBeanに関する情報の取得が、Beanによって行われる場合があります。Beanに関してコンテキストから取得可能なすべての情報は、Sun社のEJB仕様を参照してください。

コンテナは、Beanをインスタンス化すると、setEntityContextメソッドを起動して、Beanからコンテキストを取得できるようにします。コンテナは、トランザクション・コンテキストからはこのメソッドをコールしません。この時点でBeanがコンテキストを保存しなかった場合、Beanは二度とコンテキストにアクセスできなくなります。


注意

インスタンスの存続期間中存在するリソースの割当ておよび破棄には、setEntityContextおよびunsetEntityContextメソッドも使用可能です。 


コンテナはこのメソッドをコールする際、EntityContextオブジェクトの参照をBeanに渡します。Beanは、この参照を後の使用のために格納できます。次の例では、Beanがコンテキストをthis.ctx変数に格納するところを示します。

このメソッドを使用して、Beanのコンテキストの参照を取得します。エンティティBeanには、コンテナによって維持され、Beanから使用可能なエンティティ・コンテキストが存在します。Beanは、エンティティ・コンテキスト内のメソッドを使用して、コンテナへのコールバック・リクエストを送信できます。

例13-10に、セッション・コンテキストをentityctx変数に格納するエンティティBeanを示します。

例13-10    setEntityContextおよびunsetEntityContextメソッドの実装

import javax.ejb.*;

public class MyBean implements EnityBean {
   EntityContext entityctx;

   public void setEntityContext(EntityContext ctx) {
      entityctx = ctx;   // entity context is stored in instance variable
   }

    public void unsetEntityContext() {
        entityctx = null;
    }

   // other methods in the bean
}

戻る 次へ
Oracle
Copyright © 2002, 2008 Oracle Corporation.

All Rights Reserved.
目次
目次
索引
索引