目次 | |

8. 実体のクライアントビュー

備考:実体エンタプライズBeansのコンテナサポートは,EJB1.0ではオプション機能とする。 実体エンタプライズBeansのコンテナサポートは,EJB2.0では必須となる。

8.では,実体EJBオブジェクトのクライアントのビューを示す。実体EJBオブジェクトのクライアントのビューは, 実際のところは,エンタプライズBeanをインストールするエンタプライズBeanのコンテナによって満足される契約であって, エンタプライズBean自体が提供する業務メソッドだけをもつ。

エンタプライズBeansのクライアントビューは,コンテナが実装するクラスによって提供されるが, コンテナ自体はクライアントには透過的とする。

8.1 概観

クライアントにとって,実体エンタプライズBeanは永続的オブジェクトであって, (例えばデータベースなどの)永続的記憶域に記憶される実体のオブジェクトビュー, 又は既存のエンタプライズアプリケーションが実装する実体を表現する。

クライアントは,実体Beanの遠隔インタフェースを通じて,実体エンタープライスBeanにアクセスする。 遠隔インタフェースを実装するオブジェクトを,EJBオブジェクトと呼ぶ。EJBオブジェクトは, 遠隔Javaプログラム言語オブジェクトであって,遠隔オブジェクト呼出し[3]のための標準JavaAPIを通じて, クライアントからアクセスできる。

EJBオブジェクトは,生成されて破壊されるまで,コンテナの中に生存する。コンテナは,クライアントには透過的に, セキュリティ,並行性,トランザクション,永続性及びコンテナで生存するEJBオブジェクトのためのそれ以外のサービスを 提供する。コンテナはクライアントには透過的とする。すなわち,クライアントが, コンテナを操作するために使用できるAPIは存在しない。

複数のクライアントが,並行的に実体オブジェクトにアクセスできる。実体Beanがインストールされているコンテナは, トランザクションを使用して実体の状態へのアクセスを適切に同期化する。

各実体オブジェクトは,識別性をもち,一般に,実体オブジェクトが生成されたコンテナのクラッシュ及び再始動でも生き残る。 オブジェクト識別性は,コンテナによって実装される。

EJBオブジェクトのクライアントのビューは,位置非依存とする。EJBオブジェクトと同じJVMで実行しているクライアントは, 計算機が同じか異なるかにかかわらず,異なるJVMで実行するクライアントと同じAPIを使用する。

コンテナには複数のEJBクラスをインストールできる。一つのコンテナにインストールされた各EJBクラスに対して, コンテナはエンタプライズBeanのホームインタフェースを実装する。ホームインタフェースによって,クライアントは, 与えられたエンタプライズBeanの実体EJBオブジェクトの生成,参照及び除去が可能となる。 クライアントは,JNDIを通じてエンタプライズBeanのホームインタフェースを参照できる。 すなわち,エンタプライズBeanのホームインタフェースをJNDI名前空間で使用可能とするのは,コンテナの責任とする。

EJBオブジェクトのクライアントのビューは,エンタプライズBean及びそのコンテナの実装に関係なく,同じとする。 これによって,クライアントアプリケーションは,エンタプライズBeanが配置されるかもしれないすべてのコンテナ実装に渡り, 確実に移植できる。

8.2 EJBコンテナ

EJBコンテナ(短縮してコンテナとも呼ぶ。)は,エンタプライズBeansの“コンテナ”として機能するシステムとする。 コンテナは,データベースの中にレコードが存在し,ファイルシステムの中にファイル又はディレクトリが存在するのと同じに, エンタプライズBeanオブジェクトが生存する場所とする。

複数のEJBクラスを,一つのコンテナにインストール可能とする。コンテナの中にインストールされた EJBクラスのそれぞれに対して,一つのホームインタフェースをコンテナが提供する。ホームインタフェースによって, クライアントは,対応するEJBクラスのEJBオブジェクトの生成,参照及び除去が可能となる。コンテナは, エンタプライズBeansのホームインタフェース(これは,Bean提供者が定義し,コンテナ提供者が実装する。)を, クライアントのJNDI名前空間で利用可能とする。

EJBサーバは,一つ以上のEJBコンテナを保持してよい。コンテナは,クライアントには透過的とする。 すなわち,コンテナを操作するクライアントAPIは存在しないし,クライアントが,あるエンタプライズBean のインストールされているコンテナを知る方法は存在しない。

8.2.1 エンタプライズBeanのホームインタフェースの位置決め

クライアントは,JNDIを使用してエンタプライズBeanのホームインタフェースを位置決めする。 例えば,AccountエンタプライズBeanのホームインタフェースは,次のコードの断片を使用して位置決めできる。
        Context initialContext = new InitialContext();
        AccountHome accountHome = javax.rmi.PortableRemoteObject.narrow(
                initialContext.lookup("applications/bank/accounts"),
                AccountHome.class);
クライアントのJNDI名前空間は,一つのネットワーク上の複数の計算機上に位置する複数のEJBコンテナにインストールされた EJBクラスのホームインタフェースを含む構成となってもよい。一般には,EJBコンテナの実際の位置は, クライアントには透過的とする。

8.2.2 コンテナの提供物

図8.1は,実体コンテナがクライアントに提供するビューを例示する。
 
8.1
図8.1 実体コンテナがクライアントに提供するビューの例

8.3 エンタプライズBeanのホームインタフェース

コンテナは,コンテナにインストールされた各エンタプライズBeanのホームインタフェースの実装を提供する。 コンテナは,コンテナにインストールされたすべてのエンタプライズBeanのホームインタフェースを, JNDIを通じてクライアントにアクセス可能とする。エンタプライズBeanのホームインタフェースの実装クラスを, EJBホームと呼ぶ。

実体Beanのホームインタフェースによって,クライアントは次のことが可能になる。

エンタプライズBeanのホームインタフェースは,インタフェースjavax.ejb.EJBHomeを拡張し, Javaプログラム言語遠隔インタフェースの標準規則に従わなければならない。

8.3.1 メソッドcreate()

実体Beanのホームインタフェースは,ゼロ以上のメソッドcreate()を, EJBオブジェクトの各生成方法ごとに一つ定義できる。メソッドcreate()の実引数は,通常, 生成するEJBオブジェクトの状態を初期化するために使用する。

メソッドcreate()の返却値の型は,エンタプライズBeanの遠隔インタフェースとする。

すべてのメソッドcreate()のthrows節は,java.rmi.RemoteException及び javax.ejb.CreateExceptionを含まなければならない。付加的なアプリケーションレベルの例外も含んでもよい。

次のホームインタフェースは,二つの可能なメソッドcreate()の例を示す。

        public interface AccountHome extends javax.ejb.EJBHome{
                public Account create(String firstName, String lastName,
                        double initialBalance)
                                throws RemoteException, CreateException;
                public Account create(String accountNumber,
                        double initialBalance)
                                throws RemoteException, CreateException,
                                        LowInitialBalanceException;
                ...
        }
次の例は,クライアントが新しいEJBオブジェクト生成する方法を示す。
        AccountHome accountHome = ...;
        Account account = accountHome.create("John", "Smith", 500.00);

8.3.2 メソッドfinder()

実体Beanのホームインタフェースは,一つ以上のメソッドfinder()を,EJBオブジェクト又は特定の型の EJBオブジェクトの集まりを参照する各方法ごとに一つ定義する。各メソッドfinder()の名前は, findLargeAccounts()などとして接頭辞“find”で始めなければならない。実体Bean実装は, 要求した実体オブジェクトを位置決めするために,メソッドfinder()の実引数を使用する。 メソッドfinder()の返却値の型は,エンタプライズBeanの遠隔インタフェース 又はEJBオブジェクトの集まりを表現する型でなければならない。

備考:メソッドfindByPrimaryKey(primaryKey)は,すべての実体Beanに対して必須とする。

すべてのメソッドfinder()のthrows節は,java.rmi.RemoteExceptionを含まなければならない。 通常は,throws節もjavax.ejb.FinderExceptionを含む。

すべての実体Beanのホームインタフェースは,メソッドfindByPrimary(primaryKey)を含み,それによって, クライアントは,1次キー(primaryKey)を使用し実体Beanを位置決めできる。メソッドの名前は,常に, findByPrimaryKeyとする。すなわち,エンタプライズBeanの1次キー型の実引数を一つもち,返却値の型は, エンタプライズBeanの遠隔インタフェースとする。

メソッドfindByPrimaryKey()の例を次に示す。

        public interface AccountHome extends javax.ejb.EJBHome{
                ...
                public Account findByPrimaryKey(String AccountNumber)
                        throws RemoteException, FinderException;
        }
メソッドfindByPrimaryKey()をクライアントが使用する例を次に示す。
        AccountHome = ...;
        Account account = accountHome.findByPrimaryKey("100-3450-3333");

8.3.3 メソッドremove()

インタフェースjavax.ejb.EJBHomeは,クライアントがEJBオブジェクトを除去できるメソッドをいくつか定義する。
        public interface EJBHome extends Remote{
                void remove(Handle handle) throws RemoteException,
                        RemoveException;
                void remove(Object primaryKey) throws RemoteException,
                        RemoveException;
        }

8.4 実体EJBオブジェクトライフサイクル

8.4では,クライアントの視点から,EJBオブジェクトのライフサイクルを示す。

図8.2は,実体EJBオブジェクトのライフサイクルに関するクライアントの視点を示す (図中の用語referencedは,クライアントプログラムが,EJBオブジェクトへの参照をもつことを意味する。)。
 

8.2
図8.2 クライアントから見た実体EJBオブジェクトライフサイクル

EJBオブジェクトは,生成するまで存在しない。生成するまでは,識別性をもたない。生成後に,識別性をもつ。 クライアントは,コンテナが実装するエンタプライズBeanのホームインタフェースを使用して,EJBオブジェクトを生成する。 クライアントがEJBオブジェクトを生成する場合,クライアントは,新たに生成されたEJBオブジェクトへの参照を得る。

既存データを備えた環境では,EJBオブジェクトは,コンテナ及びEJBオブジェクトの配置前に“存在する”かもしれない。 さらに,実体EJBオブジェクトは,ホームインタフェースのメソッドcreate()呼出し以外の機構 (例えば,データベースレコードを入力するなど)によって,その環境で“生成される”かもしれないが, メソッドfinderを通じてコンテナのクライアントによってアクセス可能となるかもしれない。 同様に,EJBオブジェクトは,remove()操作以外の方法(データベースレコードの削除など)を使用して, 直接に削除されるかもしれない。図8.2中の“直接挿入”変換及び“直接削除”変換は, これらの直接的なデータベース操作を示す。

クライアントは,既存のEJBオブジェクトへの参照を,次の方法のいずれかで獲得できる。

オブジェクトへの参照をもつクライアントは,次のいずれをも実行できる。 存在しないオブジェクトへの参照は,すべて無効とする。存在しないオブジェクト上で呼出しを行おうとすると,必ず, java.rmi.NoSuchObjectExceptionが投げられる。

実体EJBオブジェクトは,すべて永続オブジェクトと考える。実体EJBオブジェクトの寿命は, そのオブジェクトを実行するJava仮想計算機プロセスの寿命によって制限されない。Java仮想計算機がクラッシュすると, 現在のトランザクションはロールバックされるかもしれないが,以前に生成されたEJB実体オブジェクトを破壊したり, クライアントが保持する参照を無効にはしない。

複数のクライアントは,並行的に,同じEJBオブジェクトにアクセスできる。トランザクションは, クライアントの作業を互いに孤立させるために使用する。

8.5 1 次キー及びオブジェクト識別性

すべての実体EJBオブジェクトは,そのホーム内で一意の識別性をもつ。コンテナ内のオブジェクトの識別性は, EJBオブジェクトのホーム及び1次キーによって決定される。二つのEJBオブジェクトが同じホーム及び同じ1次キーをもつ場合, その二つは同一と考える。

エンタプライズJavaBeansによって,1次キーオブジェクトをクラスjava.io.Serializableとすることができる。 1次キークラスは,エンタプライズBeanクラスに固有とする。つまり,各エンタプライズBeanクラスは, その1次キーに対して異なるクラスをもってよい。

EJBオブジェクトへの参照を保持するクライアントは,参照上のメソッドgetPrimaryKey()を呼び出すことによって, そのホーム内でのオブジェクトの識別性を決定できる。

クライアントは,二つのEJBオブジェクトの参照が,同じ実体を参照しているかどうかを, 次のメソッドのいずれかによって試験できる。

次のコードは,メソッドisIdentical()を使用して, 二つのオブジェクト参照が同じ実体EJBオブジェクトを参照しているかどうかを試験する例を示す。
        Account acc1 = ...;
        Account acc2 = ...;
        if(acct1.isIdentical(acc2)) {
                acc1 and acc2 are the same EJB objects
        }else {
                acc2 and acc2 are different EJB object 
        }
実体EJBオブジェクトの1次キーを知る場合クライアントは,コンテナが実装するホームインタフェースのメソッド findByPrimaryKey(key)を呼び出すことによって,そのオブジェクトへの参照を獲得できる。

エンタプライズJavaBeansは,EJBオブジェクト参照に対する“オブジェクト等価性”を規定していないことに注意。 Javaプログラム言語のメソッドObject.equals(Object obj)を使用して,二つのオブジェクトの参照を比較した結果は, 規定しない。同じオブジェクトを表現する二つのオブジェクト参照におけるメソッドObject.hashCode()を実行して, 同じ結果を得るとは保証しない。そこで,クライアントは,常にメソッドisIdentical()を使用して, 二つのオブジェクト参照が同じEJBオブジェクトを参照するかどうかを決定したほうがよい。

8.6 エンタプライズBeanの遠隔インタフェース

クライアントは,エンタプライズBeanの遠隔インタフェースを通じて,実体Beanにアクセスする。 エンタプライズBeanの遠隔インタフェースは,インタフェースjavax.ejb.EJBObjetを拡張しなければならない。 遠隔インタフェースは,クライアントが呼出し可能な業務メソッドを定義する。

実体Beanの遠隔インタフェースの定義例を次に示す。

        public interface Account extends javax.ejb.EJBObject{
                void debit(double amount)
                        throws java.rmi.RemoteException,
                                InsufficientBalanceException;
                void credit(double amount)
                        throws java.rmi.RemoteException;
                double getBalance()
                        throws java.rmi.RemoteException;
        }
インタフェースjavax.ejb.EJBObjectは, クライアントにEJBオブジェクトの参照上で次の操作を可能とさせるメソッドを定義する。 インタフェースjavax.ejb.EJBObjectで定義されるメソッドの実装は,コンテナが提供する。業務メソッドは, エンタプライズBeanクラスに委託される。

EJBオブジェクトは,インタフェースjavax.ejb.EnterpriseBeanで導入されるエンタプライズBeanのメソッドを, クライアントに対して開示しないことに注意すること。これらのインタフェースは, クライアントのために意図したものではない。コンテナが,EJBインスタンスを管理するために使用する。

8.7 エンタプライズBeanのハンドル

ハンドルは,EJBオブジェクトを識別するオブジェクトとする。EJBオブジェクトへの参照をもつクライアントは, 参照上でメソッドgetHandle()を呼び出すことによって,オブジェクトのハンドルを獲得できる。

ハンドルのクラスは,インタフェースjava.io.Serializableを実装しなければならないので,クライアントは, それを直列化してもよい。クライアントは,場合によっては異なるプロセスで,後に直列化されたハンドルを使用し, ハンドルで識別されるEJBオブジェクトへの参照を再び獲得する。

長期にわたり存在する実体を記憶するコンテナは,通常,クライアントが(多年にわたる場合もある)長い間ハンドルを記憶できる ハンドルの実装を提供する。このハンドルは,コンテナが使用する技術の一部(例えば,ORBサーバ,DBMSサーバなど)が, クライアントがハンドルを記憶している間に,更新又は置換されても,利用可能となる。

ハンドルの使用例を,次に示す。

        //A client obtains a handle of an account EJB object and
        //stores the handle in stable storage.
        //
        ObjectOutputStream stream = ...;
        Account account = ...;
        Handle handle = account.getHandle();
        stream.writeObject(handle);

        //A client can read the handle from stable storage, and use the
        //handle to ressurect an object reference to the
        //account EJB object.
        //
        ObjectInputStream stream = ...;
        Handle handle = (Handle) stream.readObject(handle);
        Account account = (Account)handle.getEJBObject();
        account.debit(100.00);

目次 | |