8.では,実体EJBオブジェクトのクライアントのビューを示す。実体EJBオブジェクトのクライアントのビューは, 実際のところは,エンタプライズBeanをインストールするエンタプライズBeanのコンテナによって満足される契約であって, エンタプライズBean自体が提供する業務メソッドだけをもつ。
エンタプライズBeansのクライアントビューは,コンテナが実装するクラスによって提供されるが, コンテナ自体はクライアントには透過的とする。
クライアントは,実体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が配置されるかもしれないすべてのコンテナ実装に渡り, 確実に移植できる。
複数のEJBクラスを,一つのコンテナにインストール可能とする。コンテナの中にインストールされた EJBクラスのそれぞれに対して,一つのホームインタフェースをコンテナが提供する。ホームインタフェースによって, クライアントは,対応するEJBクラスのEJBオブジェクトの生成,参照及び除去が可能となる。コンテナは, エンタプライズBeansのホームインタフェース(これは,Bean提供者が定義し,コンテナ提供者が実装する。)を, クライアントのJNDI名前空間で利用可能とする。
EJBサーバは,一つ以上のEJBコンテナを保持してよい。コンテナは,クライアントには透過的とする。 すなわち,コンテナを操作するクライアントAPIは存在しないし,クライアントが,あるエンタプライズBean のインストールされているコンテナを知る方法は存在しない。
Context initialContext = new InitialContext(); AccountHome accountHome = javax.rmi.PortableRemoteObject.narrow( initialContext.lookup("applications/bank/accounts"), AccountHome.class);クライアントのJNDI名前空間は,一つのネットワーク上の複数の計算機上に位置する複数のEJBコンテナにインストールされた EJBクラスのホームインタフェースを含む構成となってもよい。一般には,EJBコンテナの実際の位置は, クライアントには透過的とする。
![]() |
実体Beanのホームインタフェースによって,クライアントは次のことが可能になる。
メソッド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);
備考:メソッド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");
public interface EJBHome extends Remote{ void remove(Handle handle) throws RemoteException, RemoveException; void remove(Object primaryKey) throws RemoteException, RemoveException; }
図8.2は,実体EJBオブジェクトのライフサイクルに関するクライアントの視点を示す
(図中の用語referencedは,クライアントプログラムが,EJBオブジェクトへの参照をもつことを意味する。)。
![]() |
EJBオブジェクトは,生成するまで存在しない。生成するまでは,識別性をもたない。生成後に,識別性をもつ。 クライアントは,コンテナが実装するエンタプライズBeanのホームインタフェースを使用して,EJBオブジェクトを生成する。 クライアントがEJBオブジェクトを生成する場合,クライアントは,新たに生成されたEJBオブジェクトへの参照を得る。
既存データを備えた環境では,EJBオブジェクトは,コンテナ及びEJBオブジェクトの配置前に“存在する”かもしれない。 さらに,実体EJBオブジェクトは,ホームインタフェースのメソッドcreate()呼出し以外の機構 (例えば,データベースレコードを入力するなど)によって,その環境で“生成される”かもしれないが, メソッドfinderを通じてコンテナのクライアントによってアクセス可能となるかもしれない。 同様に,EJBオブジェクトは,remove()操作以外の方法(データベースレコードの削除など)を使用して, 直接に削除されるかもしれない。図8.2中の“直接挿入”変換及び“直接削除”変換は, これらの直接的なデータベース操作を示す。
クライアントは,既存のEJBオブジェクトへの参照を,次の方法のいずれかで獲得できる。
実体EJBオブジェクトは,すべて永続オブジェクトと考える。実体EJBオブジェクトの寿命は, そのオブジェクトを実行するJava仮想計算機プロセスの寿命によって制限されない。Java仮想計算機がクラッシュすると, 現在のトランザクションはロールバックされるかもしれないが,以前に生成されたEJB実体オブジェクトを破壊したり, クライアントが保持する参照を無効にはしない。
複数のクライアントは,並行的に,同じEJBオブジェクトにアクセスできる。トランザクションは, クライアントの作業を互いに孤立させるために使用する。
エンタプライズJavaBeansによって,1次キーオブジェクトをクラスjava.io.Serializableとすることができる。 1次キークラスは,エンタプライズBeanクラスに固有とする。つまり,各エンタプライズBeanクラスは, その1次キーに対して異なるクラスをもってよい。
EJBオブジェクトへの参照を保持するクライアントは,参照上のメソッドgetPrimaryKey()を呼び出すことによって, そのホーム内でのオブジェクトの識別性を決定できる。
クライアントは,二つの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オブジェクトを参照するかどうかを決定したほうがよい。
実体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オブジェクトの参照上で次の操作を可能とさせるメソッドを定義する。
EJBオブジェクトは,インタフェースjavax.ejb.EnterpriseBeanで導入されるエンタプライズBeanのメソッドを, クライアントに対して開示しないことに注意すること。これらのインタフェースは, クライアントのために意図したものではない。コンテナが,EJBインスタンスを管理するために使用する。
ハンドルのクラスは,インタフェース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);