public abstract class Command implements Serializable {public abstract void execute throws CommandException;... catch ClassCastException e {e.printStackTrace; }} public Command executeCo
Trang 1public abstract class Command implements Serializable {
public abstract void execute() throws CommandException;
Trang 2public void CommandServer() {}
public Command executeCommand(Command aCommand) throwsCommandException
{
try{aCommand.execute();
}catch (CommandException e){
Trang 3public class EJBCommandTarget implements CommandTarget {
private CommandServerHome serverHome;
public EJBCommandTarget()
{
try
{
Context ctx = new InitialContext(System.getProperties());
Object obj = ctx.lookup(“CommandServer”);
Trang 4catch (ClassCastException e) {
e.printStackTrace();
}}
public Command executeCommand(Command aCommand)
throws CommandException
{
try {CommandServer aCommandServer = serverHome.create();
aCommand = aCommandServer.executeCommand(aCommand);
return aCommand;
}catch (Exception e){
throw new CommandException(e);
}}
private static EJBCommandTarget ejbTarget = new EJBCommandTarget();
//execute command, overwriting memory reference of the passed //in command to that of the new one
public static Command execute(Command aCommand)
//under different transaction configurations)
return ejbTarget.executeCommand(aCommand);
}
}
Trang 5Data Access Command Bean
The implementations of the abstract super classes BaseReadCommand and BaseUpdateCommand, as well as the InsertEmployeeCommand and QueryEmployeeByNameCommand classes are provided Note that the BaseReadCommand uses a RowSet to simplify its implementation RowSets are part of the JDBC 2.0 optional package, and joined core JDBC as of JDBC 3.0 The example here uses Sun’s free CachedRowSet implementation of the RowSet interface.
protected CachedRowSet rowSet = null;
private Connection con;
protected BaseReadCommand ( String jndiName, String statement )
Trang 6public void execute() throws DataCommandException
{
try{rowSet = new CachedRowSet();
rowSet.populate(pstmt.executeQuery());
rowSet.beforeFirst();
this.release();
} catch (SQLException e){
throw new DataCommandException(e.getMessage());
}}
public boolean next() throws DataCommandException
{
try{return rowSet.next();
} catch (SQLException e){
throw new DataCommandException(e.getMessage());
}}
private void release() throws SQLException
{
if (pstmt != null) pstmt.close();
if (con != null) con.close();
}}
* The Super class for any data command beans that Create, Update or
* Delete This class is reusable across projects, all proj specificdata
* (Datasource JDNI and SQl String) are left to the subclasses
*/
abstract class BaseUpdateCommand {
Trang 7protected PreparedStatement pstmt;
private Connection con;
protected BaseUpdateCommand ( String jndiName, String statement )
Trang 8* is the usecase specific Command bean that
* an application developer would write
} catch (SQLException e){
throw new DataCommandException(e.getMessage());
}}
public void setId(int id) throws DataCommandException
{
try{pstmt.setInt(1, id);
} catch (SQLException e){
throw new DataCommandException(e.getMessage());
}}
public void setName(String aName) throws DataCommandException{
try{pstmt.setString(2, aName);
} catch (SQLException e){
throw new DataCommandException(e.getMessage());
}
}
Trang 9static final String statement =
“select EMPLOYEEID, NAME, EMAIL from Employees where NAME = ?”;
static final String dataSourceJNDI = “bookPool”;
protected QueryEmployeeByNameCommand() throws DataCommandException
Trang 10throw new DataCommandException(e.getMessage());
}}
public void setName(String aName) throws DataCommandException
{
try{pstmt.setString(1, aName);
} catch (SQLException e){
throw new DataCommandException(e.getMessage());
}}
}
Dual Persistent Entity Bean
Included is the code example of the bank account entity bean inheritance tionship and deployment descriptors These classes can be compiled and then deployed in CMP or BMP by swapping the provided deployment descriptors.
rela-Account Deployment Descriptor for
Trang 12public interface Account extends EJBObject {
public double balance() throws RemoteException;
public double deposit(double amount) throws RemoteException;public double withdraw(double amount) throws
public interface AccountHome extends EJBHome {
public Account create(String accountId, double initialBalance)throws CreateException, RemoteException;
public Account findByPrimaryKey(String primaryKey)
throws FinderException, RemoteException;
public Collection findBigAccounts(double balanceGreaterThan)throws FinderException, RemoteException;
Trang 13Account CMP Bean Superclass
abstract public String getAccountId();
abstract public double getBalance();
abstract public void setAccountId(String val);
abstract public void setBalance(double val);
Trang 14public String ejbCreate(String accountId, double initialBalance)throws CreateException
public void ejbActivate() {}
public void ejbLoad() {}
public void ejbPassivate() {}
public void ejbPostCreate(String accountId,double initialBalance){}public void ejbRemove() throws RemoveException {}
public void ejbStore() {}
Trang 15private String accountId;
private double balance;
public String getAccountId()
Trang 16if (ps != null) ps.close();
if (con != null) con.close();
} catch (Exception e){
throw new EJBException(e);
}}}
public Collection ejbFindBigAccounts(double balanceGreaterThan){
Connection con = null;
PreparedStatement ps = null;
try{con = getConnection();
ps = con.prepareStatement(“select id from Accounts where
pk = rs.getString(1);
v.addElement(pk);
}return v;
} catch (SQLException e){
throw new EJBException(e);
} finally{
try{
if (ps != null) ps.close();
if (con != null) con.close();
} catch (Exception e){
throw new EJBException(e);
}}}
Trang 17throw new ObjectNotFoundException();
} catch (SQLException sqe)
Trang 18elsethrow new NoSuchEntityException();
} catch (SQLException sqe){
throw new EJBException(sqe);
} finally{
try{
if (ps != null) ps.close();
if (con != null) con.close();
} catch (Exception e){
System.out.println(“Error closing JDBC resourcest: “ +e);
throw new EJBException(e);
}}}
public void ejbPostCreate(String accountId, double initialBalance){
accountId = (String) ctx.getPrimaryKey();
ps = con.prepareStatement(“delete from Accounts where id =
?”);
ps.setString(1, accountId);
Trang 19throw new NoSuchEntityException();
} catch (SQLException sqe)
Trang 20return ds.getConnection();
} catch (NamingException e){
throw new EJBException(e);
}}
EJB Home Factory
Here we present an example of an EJB Home Factory
Simple EJB Home Factory
* EJB Home Factory, maintains a simple hashmap cache of EJBHomes
* For a production implementations, exceptions such as NamingException
* can be wrapped with a factory exception to futher simplify
* the client
*/
public class EJBHomeFactory
{
private Map ejbHomes;
private static EJBHomeFactory aFactorySingleton;
Trang 21* Returns the singleton instance of the EJBHomeFactory
* The sychronized keyword is intentionally left out the
* as I don’t think the potential to intialize the singleton
* twice at startup time (which is not a destructive event)
* is worth creating a sychronization bottleneck on this
* VERY frequently used class, for the lifetime of the
* client application
*
* Alternatively, you can sychronize this method, OR you can
* simply Intialize the hashMap and factory using static
* Lookup and cache an EJBHome object using a home class
* Assumes that the JNDI name of the EJB Home being looked for
* is the same as the fully qualified class name of the
* same EJB Home
* If EJB-REF tags are being used externally, then the classname
* of the EJB Home can be mapped to the actual JNDI name of the
* deployed bean transaprently at deployment time
* If EJB-REF tags are not used, then the EJB’s must be deployed
Trang 22anEJBHome = (EJBHome) PortableRemoteObject.narrow
(ctx.lookup (homeClass.getName()),homeClass);
this.ejbHomes.put(homeClass, anEJBHome);
}}catch (ClassCastException e){
throw new HomeFactoryException(e);
}catch (NamingException e){
throw new HomeFactoryException(e);
}
return anEJBHome;
}
/**
* Lookup and cache an EJBHome object
* This ‘alternate’ implementation delegates JNDI name knowledge
* to the client It is included here for example only
System.out.println(“finding HOME for first time”);anEJBHome = (EJBHome) PortableRemoteObject.narrow
Trang 23this.ejbHomes.put(homeClass, anEJBHome);
}}
The changed/extra code (over the stateless delegate example in Chapter 8)
is highlighted in bold The only major change in the SFSB version of the
Busi-ness Delegate is the use of a getEJB() method before every invocation of a ness method on an EJB This is done to ensure that the EJBObject still exists (was not lost in serialization), in order to recreate it from the handle in case of
busi-serialization Also, clients must remember to call remove on the delegate when
they are done with it, so that the SFSB can be removed.
public class ForumServicesDelegate implements Serializable
{
private transient TestSession sb;
private Handle remoteHandle;
public ForumServicesDelegate() throws DelegateException
Trang 24throw new DelegateException();
}}
//business method
public long addForum(long categoryPK, String forumTitle,
String summary) throws NoSuchCategoryException,DelegateException {
try{
return getEJB().sb.addForum
(categoryPK, forumTitle, summary);
} catch(CreateException e){
throw new DelegateException();
//log errors, etc} catch(RemoteException e){
throw new DelegateException();
//log errors, etc}
//if so, recreate session bean reference
sb = (ForumServices) PortableRemoteObject.narrow (remoteHandle.getEJBObject(),ForumServices.class); }
} catch (ClassCastException e) {
throw new DelegateException();
Trang 25//once the client is done with the
//stateful delegate, allow client to call
//remove, so we can tell the EJB server to
Included is a complete implementation of the Sequence Block pattern, based
on a submission by Jonathan Weedon from Borland Corporation The Sequence entity bean exposes only local interfaces (it is only called by the Sequence Session Bean) The Sequence Session Bean exposes both local and remote interfaces (should be called by local interfaces in production; remote is provided for testing purposes) Ejb-jar.xml descriptors are also included
Sequence Entity Bean Local Interface
Trang 26Sequence Entity Bean Local Home
abstract public int getIndex();
abstract public String getName();
abstract public void setIndex(int newIndex);
abstract public void setName(java.lang.String newName);
public void ejbActivate() {}
public void ejbLoad() {}
public void ejbPassivate() {}
public void ejbPostCreate(String name) {}
public void ejbRemove() {}
public void ejbStore() {}
public void setEntityContext(EntityContext unused) {}
public void unsetEntityContext() {}
Trang 27Sequence Session Remote Interface
package examples.sequencegenerator;
import java.rmi.*;
public interface SequenceSession extends javax.ejb.EJBObject {
public int getNextNumberInSequence(String name) throws
public interface SequenceSessionHome extends javax.ejb.EJBHome {
SequenceSession create() throws CreateException, RemoteException;
}
Sequence Session Local Interface
package examples.sequencegenerator;
public interface SequenceSessionLocal extends javax.ejb.EJBLocalObject {
public int getNextNumberInSequence(String name);
Trang 28private class Entry {
private int _retryCount;
private SequenceLocalHome _sequenceHome;
public int getNextNumberInSequence(String name)
// add an entry to the sequence tableentry = new Entry();
try{entry.sequence = _sequenceHome.findByPrimaryKey(name);}
catch (javax.ejb.FinderException e){
// if we couldn’t find it, then create it
entry.sequence = _sequenceHome.create(name);
}_entries.put(name, entry);
}
if (entry.last % _blockSize == 0){
for (int retry = 0; true; retry++){
try{entry.last = entry.sequence.getNextKeyAfterIncrementingBy(_blockSize);break;
}catch (javax.ejb.TransactionRolledbackLocalException e){
if (retry < _retryCount){
// we hit a concurrency exception, so //try again
continue;
Trang 29else{// we tried too many times, so fail
throw new javax.ejb.EJBException(e);
}}}}
public void ejbActivate() {}
public void ejbCreate() {}
public void ejbPassivate() {}
public void ejbRemove() {}
}
Sequence Session and Entity
EJB-JAR.xml
<?xml version=”1.0”?>
<!DOCTYPE ejb-jar PUBLIC ‘-//Sun Microsystems,
Inc.//DTD Enterprise JavaBeans 2.0//EN’
‘http://java.sun.com/dtd/ejb-jar_2_0.dtd’>