Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Mastering Enterprise JavaBeans™ and the Java 2 Platform, Enterprise Edition - Roman E

..pdf
Скачиваний:
41
Добавлен:
24.05.2014
Размер:
6.28 Mб
Скачать

Writing Bean-Managed Persistent Entity Beans 219

* 4) Release the DB Connection */

try {

if (pstmt != null) pstmt.close();

}

catch (Exception e) { } try {

if (conn != null) conn.close();

}

catch (Exception e) { }

}

}

/**

*Called by Container. Releases held resources for

*passivation.

*/

public void ejbPassivate() throws RemoteException { System.out.println("ejbPassivate () called.");

}

/**

*Called by the container. Updates the in-memory entity

*bean object to reflect the current value stored in

*the database.

*/

public void ejbLoad() throws RemoteException { System.out.println("ejbLoad() called.");

/*

*Again, query the Entity Context to get the current

*Primary Key, so we know which instance to load.

*/

AccountPK pk = (AccountPK) ctx.getPrimaryKey();

String id = pk.accountID;

PreparedStatement pstmt = null;

Connection conn = null;

try { /*

* 1) Acquire a new DB Connection */

conn = getConnection();

/*

*2) Get account from the DB, querying

*by account ID

*/

Source 8.4 AccountBean.java (continues).

Go back to the first page for a quick link to buy this book online!

220 M A S T E R I N G E N T E R P R I S E J A V A B E A N S

pstmt = conn.prepareStatement("select ownerName, balance from accounts where id = ?");

pstmt.setString(1, id);

ResultSet rs = pstmt.executeQuery(); rs.next();

ownerName = rs.getString("ownerName"); balance = rs.getDouble("balance");

}

catch (SQLException ex) {

throw new RemoteException("Account " + pk + " failed to load from database", ex);

}

finally { /*

* 3) Release the DB Connection */

try {

if (pstmt != null) pstmt.close();

}

catch (Exception e) { } try {

if (conn != null) conn.close();

}

catch (Exception e) { }

}

}

/**

*Called from the Container. Updates the database

*to reflect the current values of this in-memory

*entity bean instance.

*/

public void ejbStore() throws RemoteException { System.out.println("ejbStore() called.");

PreparedStatement pstmt = null;

Connection conn = null;

try { /*

* 1) Acquire a new DB Connection */

conn = getConnection();

/*

* 2) Store account in DB */

pstmt = conn.prepareStatement(

"update accounts set ownerName = ?, balance = ? where id = ?");

Source 8.4 AccountBean.java (continues).

Go back to the first page for a quick link to buy this book online!

Writing Bean-Managed Persistent Entity Beans 221

pstmt.setString(1, ownerName); pstmt.setDouble(2, balance); pstmt.setString(3, accountID); pstmt.executeUpdate();

}

catch (SQLException ex) {

throw new RemoteException("Account " + accountID + " failed to save to database", ex);

}

finally { /*

* 3) Release the DB Connection */

try {

if (pstmt != null) pstmt.close();

}

catch (Exception e) { } try {

if (conn != null) conn.close();

}

catch (Exception e) { }

}

}

/**

*Called by the container. Associates this bean

*instance with a particular context. We can query

*the bean properties that customize the bean here.

*/

public void setEntityContext(EntityContext ctx) throws RemoteException { System.out.println("setEntityContext called");

this.ctx = ctx;

env = ctx.getEnvironment();

}

/**

*Called by Container. Disassociates this bean

*instance with a particular context environment.

*/

public void unsetEntityContext() throws RemoteException { System.out.println("unsetEntityContext called"); this.ctx = null;

this.env = null;

}

/**

* Called after ejbCreate(). Now, the Bean can retrieve

Source 8.4 AccountBean.java (continues).

Go back to the first page for a quick link to buy this book online!

222 M A S T E R I N G E N T E R P R I S E J A V A B E A N S

*its EJBObject from its context, and pass it as

*a 'this' argument.

*/

public void ejbPostCreate(String accountID, String ownerName) throws RemoteException {

}

/**

*This is the initialization method that corresponds to the

*create() method in the Home Interface.

*

*When the client calls the Home Object's create() method,

*the Home Object then calls this ejbCreate() method.

*

* @return The primary key for this account */

public AccountPK ejbCreate(String accountID, String ownerName) throws CreateException, RemoteException {

PreparedStatement pstmt = null;

Connection conn = null;

try {

System.out.println("ejbCreate() called."); this.accountID = accountID; this.ownerName = ownerName;

this.balance = 0;

/*

* Acquire DB connection */

conn = getConnection();

/*

* Insert the account into the database */

pstmt = conn.prepareStatement("insert into accounts (id, ownerName, balance) values (?, ?, ?)");

pstmt.setString(1, accountID); pstmt.setString(2, ownerName); pstmt.setDouble(3, balance); pstmt.executeUpdate();

/*

* Generate the Primary Key and return it */

return new AccountPK(accountID);

}

catch (Exception e) {

Source 8.4 AccountBean.java (continues).

Go back to the first page for a quick link to buy this book online!

Writing Bean-Managed Persistent Entity Beans 223

throw new CreateException(e.toString());

}

finally { /*

* Release DB Connection for other beans */

try { pstmt.close();

}

catch (Exception e) { } try {

conn.close();

}

catch (Exception e) { }

}

}

/**

* Finds a Account by its primary Key */

public AccountPK ejbFindByPrimaryKey(AccountPK key) throws FinderException, RemoteException {

PreparedStatement pstmt = null;

Connection conn = null;

try {

System.out.println("ejbFindByPrimaryKey(" + key + ") called");

/*

* Acquire DB connection */

conn = getConnection();

/*

* Find the Entity in the DB

*/

pstmt = conn.prepareStatement("select id from accounts where id = ?"); pstmt.setString(1, key.toString());

ResultSet rs = pstmt.executeQuery(); rs.next();

/*

* No errors occurred, so return the Primary Key */

return key;

}

catch (Exception e) {

throw new FinderException(e.toString());

}

Source 8.4 AccountBean.java (continues).

Go back to the first page for a quick link to buy this book online!

224 M A S T E R I N G E N T E R P R I S E J A V A B E A N S

finally { /*

* Release DB Connection for other beans */

try { pstmt.close();

}

catch (Exception e) { } try {

conn.close();

}

catch (Exception e) { }

}

}

/**

* Finds a Account by its Name */

public Enumeration ejbFindByOwnerName(String name) throws FinderException, RemoteException {

PreparedStatement pstmt = null;

Connection conn = null;

Vector v = new Vector();

try {

System.out.println("ejbFindByOwnerName(" + name + ") called");

/*

* Acquire DB connection */

conn = getConnection();

/*

* Find the primary keys in the DB */

pstmt = conn.prepareStatement(

"select id from accounts where ownerName = ?"); pstmt.setString(1, name);

ResultSet rs = pstmt.executeQuery();

/*

* Insert every primary key found into a vector */

while (rs.next()) {

String id = rs.getString("id"); v.addElement(new AccountPK(id));

}

Source 8.4 AccountBean.java (continues).

Go back to the first page for a quick link to buy this book online!

Writing Bean-Managed Persistent Entity Beans 225

/*

* Return an enumeration of found primary keys */

return v.elements();

}

catch (Exception e) {

throw new FinderException(e.toString());

}

finally { /*

* Release DB Connection for other beans */

try { pstmt.close();

}

catch (Exception e) { } try {

conn.close();

}

catch (Exception e) { }

}

}

public static final String JDBC_URL = "JDBC_URL";

/**

*Gets current connection to the connection pool.

*Note: In the future, once vendors have adopted JDBC 2.0,

*the preferred method for retrieving a JDBC Connection is

*through JNDI.

*

*Assumes that environment properties contain a property

*named "user" and "password" if authentication is desired.

*These environment properties are retrieved from the

*EntityContext object during setEntityContext().

*

 

* @return

Connection

* @exception

java.sql.SQLException

*

 

*/

public Connection getConnection() throws SQLException { String jdbcURL = (String) env.get(JDBC_URL);

//For debugging...

//String drivers = (String) env.get("jdbc.drivers");

//System.out.println(jdbcURL + ", " + drivers);

//DriverManager.setLogStream(System.out);

Source 8.4 AccountBean.java (continues).

Go back to the first page for a quick link to buy this book online!

226 M A S T E R I N G E N T E R P R I S E J A V A B E A N S

return DriverManager.getConnection(jdbcURL, env);

}

}

Source 8.4 AccountBean.java (continued).

application-specific environment properties that ship with our bean, as we’ll see very shortly. We also specify the particular database to connect to via a property we call JDBC_URL. This property is passed to the DriverManager as well, so it knows with which database to hook up.

In our bank account example, we retrieve our JDBC connections via the JDBC call DriverManager.getConnection(). We also close each connection after every method call. This allows our EJB container to pool JDBC connections. When the connection is not in use, another bean can use our connection.

Although this works with BEA WebLogic server, it is not a standard, portable way for connection pooling. WebLogic performs pooling directly beneath the JDBC 1.0 driver shell, but other EJB vendors may require different mechanisms for pooling database connections. Connection pooling is unfortunately not specified by JDBC 1.0, which means that any enterprise beans that use JDBC 1.0 are not very portable.

There is a light at the end of the tunnel. The new JDBC 2.0 specification, which has been finalized, supports a portable mechanism of database connection pooling. Already vendors are beginning to support JDBC 2.0, and by the time you read this, most every serious relational database vendor should have a JDBC 2.0 driver. The Java 2 Platform, Enterprise Edition (J2EE) specification mandates support of JDBC 2.0 as well, which is good news for anyone writing to J2EE and the EJB 1.1 specification. Furthermore, EJB 1.1 specifies a portable way to retrieve a JDBC driver through the Java Naming and Directory Interface (JNDI), which we detail in Appendix D.

Our finder methods use JDBC to perform SELECT statements on the relational database to query for bank account records. We create a new primary key class for the data we find, and we return the primary key to the container. The container will then instantiate EJB objects that match each primary key, so that the clients can start working with the data.

To create a new bank account, the client calls create() on the home object, which calls our ejbCreate() and ejbPostCreate() methods. Notice that we insert some data into the database using JDBC in ejbCreate(). We also assign our member variables the data passed in from the client. We don’t need to use ejbPostCreate() for anything. Our entity bean is now associated with some specific database data and is associated with a client-specific EJB object.

Go back to the first page for a quick link to buy this book online!

Writing Bean-Managed Persistent Entity Beans 227

Notice that we don’t hold any bean-independent resources, so our setEntityContext() and unsetEntityContext() methods are fairly bare-boned. We also don’t hold any bean-specific resources, so our ejbPassivate() and ejbActivate() methods are empty.

When the container synchronizes our bean with the database, the ejbLoad() and ejbStore() methods perform JDBC persistence, thus keeping everyone’s data in synch. Notice that ejbLoad() acquires the primary key via a getPrimaryKey() call to the Entity Context. This is how it figures out what data to load.

JDBC can be very tough to debug due to incompatibilities between databases. It’s much easier to debug JDBC if you log what JDBC is doing behind the scenes. To do this, see the commented code in the getConnection() method of AccountBean.java. Simply uncomment those lines to enable logging.

AccountException.java

Our custom exception class is AccountException.java, displayed in Source 8.5. It simply delegates to the parent java.lang.Exception class. It’s still useful to define our own custom exception class, however, so that we can distinguish between a problem with our bank account component, and a problem with another part of a deployed system.

package com.wiley.compBooks.roman.entity.account;

/**

* Exceptions thrown by Accounts */

public class AccountException extends Exception {

public AccountException() { super();

}

public AccountException(Exception e) { super(e.toString());

}

public AccountException(String s) { super(s);

}

}

Source 8.5 AccountException.java.

Go back to the first page for a quick link to buy this book online!

228 M A S T E R I N G E N T E R P R I S E J A V A B E A N S

Client.java

Our last Java file is a simple test client to exercise our bean’s methods. It’s shown in Source 8.6.

The client code is fairly self-explanatory. We perform some bank account operations in the try block. We have a finally clause to make sure our bank account is properly deleted afterward, regardless of any exceptions that may have been thrown.

package com.wiley.compBooks.roman.entity.account;

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

import java.util.Enumeration;

/**

* Sample client code that manipulates a Bank Account Entity Bean. */

public class Client {

public static void main(String[] args) {

Account account = null;

try { /*

*Get a reference to the Account Home Object - the

*factory for Account EJB Objects

*/

Context ctx = new InitialContext(System.getProperties());

AccountHome home =

(AccountHome) ctx.lookup("AccountHome");

/*

* Use the factory to create the Account EJB Object */

home.create("123-456-7890", "John Smith");

/*

* Find an account */

Enumeration e = home.findByOwnerName("John Smith"); if (e != null) {

account = (Account) e.nextElement();

}

Source 8.6 Client.java (continues).

Go back to the first page for a quick link to buy this book online!