BMP エンティティ bean では、フィールドやパーシスタンスロジックの getter メソッドや setter メソッドをコーディングします。
bean 実装で検出されたコールバックメソッドのパーシスタンスロジックを指定します。パーシスタンスロジックは、次に示すように、データを作成、取り出し、更新、保存または削除します。
EJB コンテナは、bean ライフサイクルのさまざまなポイントでこれらのメソッドを呼び出すことにより、データソースのパーシスタンスや一貫性を調整します。
メモ: EJB コンテナは、CMP bean にこれらのメソッドを自動的に実装します。詳細については、 「CMP エンティティ bean (1.1 仕様)」 および 「CMP エンティティ bean (2.0 仕様)」 を参照してください。
BMP エンティティ bean のホームインターフェイスは、1 つ以上の create
メソッド、1 つの findByPrimary
キーメソッド、およびオプションでカスタム finder メソッドを定義します。
次のコードは、BMP エンティティ bean のリモートホームインターフェイス、および各メソッドから返される例外を示しています。
package compass;
import java.rmi.RemoteException; import javax.ejb.CreateException; import javax.ejb.FinderException; public interface OrderHomeRemote extends javax.ejb.EJBHome { public OrderRemote create(String customerId, int tripId, String ccType, String ccNumber, String ccExpiration) throws CreateException, RemoteException; public OrderRemote findByPrimaryKey(Integer pk) throws FinderException, RemoteException; public java.util.Collection findByCustomer(String customerId) throws FinderException, RemoteException; }
BMP エンティティ bean のコンポーネントインターフェイスは、クライアントから呼び出されるビジネスメソッドを定義します。リモートコンポーネントインターフェイスで定義されるメソッドは、常に RemoteException
を投げる必要があり、また、すべてのコンポーネントインターフェイスのメソッドは、bean 実装内のビジネスメソッドから投げられた例外を投げる必要があります。
次のコードは、BMP エンティティ bean のコンポーネントインターフェイスを示しています。
package compass;
import java.rmi.RemoteException; public interface OrderRemote extends javax.ejb.EJBObject { public int getOrderId() throws RemoteException; public String getUserId() throws RemoteException; public void setUserId(String customerId) throws RemoteException; public int getTripId() throws RemoteException; public void setTripId(int tripId) throws RemoteException; public java.sql.Date getOrderDate() throws RemoteException; public String getCCType() throws RemoteException; public void setCCType(String ccType) throws RemoteException; public String getCCNumber() throws java.rmi.RemoteException; public void setCCNumber(String ccNumber) throws RemoteException; public String getCCExpiration() throws RemoteException; public void setCCExpiration(String ccType) throws RemoteException; }
次のコードは、BMP エンティティ bean の bean 実装を示しています。
package compass;
import java.sql.*; import javax.ejb.EJBException; import javax.ejb.CreateException; import javax.ejb.FinderException; import javax.ejb.RemoveException; public class OrderBean implements javax.ejb.EntityBean { public javax.ejb.EntityContext context; // これらのフィールドは、データベーステーブルの列に対応します。 public int orderId; public String userId; public int tripId; public String ccType; public String ccNumber; public String ccExpiration; public java.sql.Date orderDate; public int getOrderId() { // orderID はプライマリキーです。 return ((Integer) context.getPrimaryKey()).intValue(); } public String getUserId(){ return userId; } public void setUserId(String userId){ this.userId = userId; } public int getTripId(){ return tripId; } public void setTripId(int tripId){ this.tripId = tripId; } public java.sql.Date getOrderDate(){ return orderDate; } public String getCCType(){ return ccType; } public void setCCType(String ccType){ this.ccType = ccType; } public String getCCNumber(){ return ccNumber; } public void setCCNumber(String ccNumber){ this.ccNumber = ccNumber; } public String getCCExpiration(){ return ccExpiration; } public void setCCExpiration(String ccExpiration){ this.ccExpiration = ccExpiration; } // データベースに行を作成します。 public java.lang.Integer ejbCreate(String userId, int tripId, String ccType, String ccNumber, String ccExpiration) throws CreateException { // log() はこのクラスの最後で定義されます。 log("ejbCreate()"); this.userId = userId; this.tripId = tripId; this.ccType = ccType; this.ccNumber = ccNumber; this.ccExpiration = ccExpiration; Connection connection=null; PreparedStatement ps=null; Statement stmt=null; ResultSet rs=null; try { javax.naming.InitialContext ctx = new javax.naming.InitialContext(); javax.sql.DataSource ds = (javax.sql.DataSource) ctx.lookup("compass"); connection=ds.getConnection(); // 新規プライマリキーを自動生成します。 stmt = connection.createStatement(); stmt.executeUpdate("UPDATE sequence SET lastkey=lastkey+1 WHERE sequence_id='order'"); rs = stmt.executeQuery("SELECT lastkey FROM sequence WHERE s equence_id='order'"); rs.next(); orderId=rs.getInt(1); log("order:"+orderId); // 予約内容を挿入します。 ps = connection.prepareStatement("INSERT INTO orders (order_id, user_id, trip_id, cc_type, cc_number, cc_expiration) VALUES (?,?,?,?,?,?)"); ps.setInt(1, orderId); ps.setString(2, userId); ps.setInt(3, tripId); ps.setString(4, ccType); ps.setString(5, ccNumber); ps.setString(6, ccExpiration); if (ps.executeUpdate() == 1) { log("INSERT order succeeded"); } else { log("INSERT order failed"); throw new CreateException("INSERT order failed"); } return new Integer(orderId); } catch (Exception e) { log(e); throw new EJBException(e.getMessage()); } finally { try { rs.close(); ps.close(); connection.close(); } catch (SQLException e) { log(e); } } } public void ejbPostCreate(String userId, int tripId, String ccType, String ccNumber, String ccExpiration) { // 実装されていません。 } // データベースから行を取り出します。 public void ejbLoad(){ log("ejbLoad()"); orderId = ((Integer) context.getPrimaryKey()).intValue(); log("Primary key:"+orderId); Connection connection = null; PreparedStatement ps=null; ResultSet rs=null; try { javax.naming.InitialContext ctx = new javax.naming.InitialContext(); javax.sql.DataSource ds = (javax.sql.DataSource) ctx.lookup("compass"); connection=ds.getConnection(); ps = connection.prepareStatement("SELECT * FROM orders WHERE order_id=?"); ps.setInt(1, orderId); rs = ps.executeQuery(); if (rs.next()) { log("SELECT order succeeded"); userId = rs.getString("user_id"); tripId = rs.getInt("trip_id"); orderDate = rs.getDate("order_date"); ccType = rs.getString("cc_type"); ccNumber = rs.getString("cc_number"); ccExpiration = rs.getString("cc_expiration"); } else { log("SELECT order failed"); throw new EJBException("SELECT order failed"); } } catch (Exception e) { throw new EJBException(e.getMessage()); } finally { try { rs.close(); ps.close(); connection.close(); } catch (Exception e) { log(e); } } } // データベースに行を保管します。 public void ejbStore(){ log("ejbStore()"); Connection connection = null; PreparedStatement ps=null; try { javax.naming.InitialContext ctx = new javax.naming.InitialContext(); javax.sql.DataSource ds = (javax.sql.DataSource) ctx.lookup("compass"); connection=ds.getConnection(); ps = connection.prepareStatement("UPDATE orders SET user_id=?, trip_id=?, cc_type=?, cc_number=?, cc_expiration=?WHERE order_id=?"); ps.setString(1, userId); ps.setInt(2, tripId); ps.setString(3, ccType); ps.setString(4, ccNumber); ps.setString(5, ccExpiration); ps.setInt(6, orderId); if (ps.executeUpdate() == 1) { log("UPDATE order succeeded"); } else { log("UPDATE order failed"); throw new EJBException("UPDATE order failed"); } } catch (Exception e) { log(e); throw new EJBException(e.getMessage()); } finally { try { ps.close(); connection.close(); } catch (Exception e) { log(e); } } } // データベースから行を削除します。 public void ejbRemove() throws RemoveException { log("ejbRemove()"); Connection connection = null; PreparedStatement ps = null; try { javax.naming.InitialContext ctx = new javax.naming.InitialContext(); javax.sql.DataSource ds = (javax.sql.DataSource) ctx.lookup("compass"); connection=ds.getConnection(); ps = connection.prepareStatement("DELETE FROM orders WHERE order_id=?"); ps.setInt(1, orderId); if (ps.executeUpdate() == 1) { log("DELETE order succeeded"); } else { log("DELETE order failed"); throw new RemoveException("DELETE order failed"); } } catch (Exception e) { log(e); throw new EJBException(e.getMessage()); } finally { try { ps.close(); connection.close(); } catch (Exception e) { log(e); } } } public void ejbPassivate() { } public void ejbActivate() { } public void setEntityContext(javax.ejb.EntityContext context) { this.context = context; } public void unsetEntityContext() { this.context = null; } // 行を取り出してプライマリキーを返します。 // 戻り値のタイプが PK のクラスであることに注意します。 // CMP の場合、このメソッドは void を返します。 public Integer ejbFindByPrimaryKey(Integer pk) throws FinderException { log("ejbFindByPrimaryKey()"); orderId = pk.intValue(); Connection connection = null; PreparedStatement ps=null; ResultSet rs=null; try { javax.naming.InitialContext ctx = new javax.naming.InitialContext(); javax.sql.DataSource ds = (javax.sql.DataSource) ctx.lookup("compass"); connection=ds.getConnection(); ps = connection.prepareStatement("SELECT count(*) FROM orders WHERE order_id=?"); ps.setInt(1, orderId); rs = ps.executeQuery(); if (rs.next()) { throw new javax.ejb.ObjectNotFoundException("Invalid Primary Key"); } } catch (Exception e) { throw new EJBException(e.getMessage()); } finally { try { rs.close(); ps.close(); connection.close(); } catch (Exception e) { log(e); } } return pk; } // 顧客の予約内容を検索します。 public java.util.Collection ejbFindByCustomer(String userId) throws FinderException { log("ejbFindByCustomer():"+userId); Connection connection = null; PreparedStatement ps=null; ResultSet rs=null; java.util.Vector list = new java.util.Vector(); try { javax.naming.InitialContext ctx = new javax.naming.InitialContext(); javax.sql.DataSource ds = (javax.sql.DataSource) ctx.lookup("compass"); connection=ds.getConnection(); ps = connection.prepareStatement("SELECT order_id FROM orders WHERE user_id=? ORDER BY order_date desc"); ps.setString(1, userId); rs = ps.executeQuery(); while (rs.next()) { Integer pk = new Integer(rs.getInt(1)); list.addElement(pk); } } catch (Exception e) { throw new EJBException(e.getMessage()); } finally { try { rs.close(); ps.close(); connection.close(); } catch (Exception e) { log(e); } } return list; } private void log(Object message) { System.out.println("-> "+new java.util.Date()+" "+this+" "+message); } }
BMP エンティティ bean の基本的なデプロイメントディスクリプタには、entity
要素内に要素が含まれます。後で、アプリケーションアセンブラにより、assembly-descriptor
要素内に追加仕様が作成されます。
次のサンプルは、BMP エンティティ bean のデプロイメントディスクリプタ内の要素を示しています。
...
<entity> <ejb-name>Order</ejb-name> <home>compass.OrderHomeRemote</home> <remote>compass.OrderRemote</remote> <ejb-class>compass.OrderBean</ejb-class> <persistence-type>Bean</persistence-type> <prim-key-class>java.lang.Integer</prim-key-class> <reentrant>False</reentrant> <security-identity><use-caller-identity/></security-identity> </entity> </enterprise-beans> <assembly-descriptor> <container-transaction> <method> <ejb-name>Order</ejb-name> <method-name>*</method-name> </method> <trans-attribute>Required</trans-attribute> </container-transaction> </assembly-descriptor> ...
次の例は、BMP エンティティ bean の JRun EJB デプロイメントディスクリプタを示しています。
...
<entity> <ejb-name>Order</ejb-name> <jndi-name>Order</jndi-name> </entity> ...
次のステートレスセッション bean の例は、リモートの BMP エンティティ bean へのクライアントアクセスを示しています。
...
// 新規の予約内容を作成します。 try { Object obj = ctx.lookup("Order"); OrderHomeRemote home = (OrderHomeRemote)javax.rmi.PortableRemoteObject.narrow(obj, OrderHomeRemote.class); OrderRemote order = home.create(custId, tripId, ccType, ccNumber, ccExpiration); orderId = order.getOrderId(); log("Order created:"+orderId); } catch (Exception e) { log(e); } // トランザクションが引き続き有効かどうかをチェックします。 // 有効でない場合、例外を返してクライアントに通知します。 if (context.getRollbackOnly()) throw new javax.ejb.EJBException("Order failed"); return orderId; ...
フィールドを変更するエンティティ bean のビジネスメソッドの呼び出しの後では必ず、デフォルトで、EJB コンテナは ejbStore
メソッドを呼び出します。jrun-ejb-jar.xml の alwaysDirty
要素を true に設定することによって、フィールドの状態にかかわらず、 EJB コンテナ ejbStore
メソッドを呼び出すようにすることができます。