Important: Read the disclaimer before reading this article.
Enterprise JavaBeansTM (EJBs) are designed to help significantly reduce development time for enterprise applications. As a quick review, there are two types of EJBs: session beans that provide business logic, and entity beans that encapsulate business data. Session beans are analogous to database stored procedures, and entity beans are analogous to database result sets. EJBs provide built-in features for remote access, scalability, security, and transactions. These built-in features do not come without cost. A simple stored procedure, one that does a single SQL statement, is one small source file. A simple session EJB that performs the same task requires more than 10 class files. It is easy to misuse EJBs and therefore end up with an application that is difficult to maintain and performs poorly.
JavaTM 2 Enterprise Edition (J2EE) uses entity EJBs to provide a layer of abstraction to the underlying relational database system. However, the interface of entity EJBs complicates the process of simply using SQL statement for database applications. Especially in bottom-up development projects and in legacy database development, design is database-oriented, which means it makes sense for architects to think in terms of SQL calls rather than EJB factories and objects.
I propose a design pattern that generalizes the use of entity EJBs to simplify EJB development. The design pattern retains the intuitive SQL interface, yet delivers the reusability and built-in distributed transaction support of EJBs. Many common cases can be handled. Because it is generalized, it can be used for automatic code generation. Given a database table, the bottom-up approach can generate code from Container-Managed Persistence (CMP) entity beans, session beans, up to a Java Server Page (JSP) or even a Web service.
The generic entity EJB wrapper
The generic SQL entity EJB wrapper is a helper class that manipulates entity EJB factories and interfaces to achieve the goal as to execute certain SQL statements by providing an intuitive SQL interface.
Figure 1 illustrates a typical EJB facade pattern. The EJB session facade pattern provides a stable, high-level gateway to the server-side components. The model layer consists of the relational database and a collection of entity EJBs. Each entity bean is an abstraction of a row of data; the relational database is responsible for persistent storage. The business layer consists of a session EJB, which is a client to the entity bean. Any method defined in the session bean is a transaction. The method in the session bean is where you implement the business logic.
Figure 1. EJB programming modelFigure 1. EJB programming model

The functions inside the entity bean are called through the home and remote interfaces of the bean, which involves extensive use of the following packages:
javax.ejb.* java.rmi.* javax.naming.* |
The home interface of an entity bean lets a client create new entity bean instances, look up existing entity beans, and remove entity bean instances. The remote interface of an entity bean allows a client to invoke the business methods of the bean such as the setter and getter. All of these are translated to JDBC calls by the container. To ensure correct use of the EJB and to ensure efficient resultant SQL statements, you may want to refer to the best practices articles in IBM Developer Domain [Ref.1].
Figure 2 shows how the generic SQL EJB wrapper can simplify these tasks. With the helper class, database development becomes more intuitive and generic. This class is basically doing a reciprocal mapping of functions. The EJB container maps SQL JDBC calls to a complex matrix of methods inside the entity beans, and the SQL EJB helper class maps the methods back to SQL wrappers.
Figure 2. EJB programming model using the SQL EJB wrapper

In the business method inside the session bean, get a handle to a generic SQL EJB wrapper and call the desired SQL methods provided by the wrapper. The SQL EJB helper methods will manipulate the entity bean interfaces to execute the desired SQL statements. Furthermore, the SQL EJB wrapper can also leverage the entity bean local interface when both the facade bean and the entity beans are in the same machine. All best practices can be encapsulated into the wrapper. These are all transparent to the business logic developers.
Usage example 1: Application development
In this section, I compare how you can develop a single transaction using the current technology to how you can perform the same task using the generic entity bean wrapper.
Consider the steps involved in developing a single transaction in the Application Developer configuration of WebSphere® Studio:
- Use the Enterprise Bean wizard to generate the entity beans.
- Use the Enterprise Bean wizard to generate a facade session bean.
- Implement the EJB helper code.
- Develop the transaction logic.
With the current technology, Websphere Studio can easily generate a layer of entity bean objects and an empty facade session bean as listed in Steps 1 and 2 above. WebSphere Studio can retrieve the database schema by simply going through DB2® Universal DatabaseTM (UDB) JDBC metadata support.
Step 3 is the development of the EJB helper code. Listing 1 is the helper code extracted from the WebSphere Performance Benchmark Sample [Ref. 2]. This is where you as a developer code the routines to handle the EJB context, home lookup and caching. This would also involve intensive exception handling and inline documentation.
Listing 1. The EJB helper code
public class TradeStaticContext
{
private static boolean verbose = true;
static InitialContext _initContext = null;
static QuoteHome _marketHome = null;
public static QuoteHome getQuoteHome()
{
if (_initContext == null)
{ setContext(); }
return _marketHome;
}
private static synchronized void setContext()
{
InitialContext localContext = null;
//Trade 2.037 - Fixes startup race condition -
//if _initContext has been set, another thread got here first
//and has already setup the EJB Homes
if (_initContext != null)
return;
if (verbose)
{
System.out.println( "TradeStaticContext.setContext: Setting context" );
}
try
{
localContext = new InitialContext();
}
catch (Exception me)
{
System.out.println(
"TradeStaticContext.setContext: Get InitialContext failed!!");
me.printStackTrace();
}
try
{
Object obj = null;
//#x2026
obj = localContext.lookup("java:comp/env/ejb/Quote");
_marketHome =
(QuoteHome) javax.rmi.PortableRemoteObject.narrow(obj, QuoteHome.class);
// Trade 2.037: Set _initContext after all EJB Homes have been setup to avoid
race condition
_initContext = localContext;
}
catch (Exception me)
{
System.out.println("TradeStaticContext.setContext: Lookup Homes failed!");
me.printStackTrace();
_initContext = null;
}
//#x2026
if (_marketHome == null)
{
System.out.println(
"TradeStaticContext.setContext: Exception creating QuoteHome");
_initContext = null;
}
}
} |
Step 4 is where you implement transaction logic. The body of the transaction is put inside the session bean. Some helper functions are called to facilitate the coding, as shown in Listing 2.
Listing 2. Transaction logic inside the session bean
public class TradeBean implements SessionBean
{
public QuoteObject getQuote(String symbol)
throws RemoteException, TradeException
{
//#x2026
Quote quote = findQuote(symbol);
}
private Quote findQuote(String symbol)
throws RemoteException, TradeException
{
//#x2026
QuoteHome qhome = TradeStaticContext.getQuoteHome();
retval = qhome.findByPrimaryKey(new QuoteKey(symbol));
}
}
|
Very clearly, a simple transaction (a single SELECT statement to the underlying database) is a nontrivial task in the EJB programming model.
Generic EJB wrapper technology
Consider the same tasks with the help of generic SQL entity EJB wrapper:
- Use the Enterprise Bean wizard to generate the entity beans.
- Develop (or generate) the generic SQL entity EJB wrapper code.
- Use the Enterprise Bean wizard to generate a facade session bean.
- Fill in the business logic inside the facade session bean.
Very similarly, Websphere Studio can easily generate a layer of entity bean objects and an empty fa#x437ade session bean as listed in Steps 1 and 3 above. WebSphere Studio can retrieve the database schema by simply going through DB2 JDBC metadata support.
One possible way to execute Step 2 is to develop an Eclipse plug-in that generates the generic SQL entity EJB wrapper code based on best practices and lessons learned. (Sample code will be provided in a followup article.) This can greatly improve your productivity. With a generic SQL entity EJB wrapper, just a few mouse clicks will enable you to generate a J2EE application that is ready for the Universal Test Client (UTC), including the Select, Insert, Delete, and Update default methods for any table. Developers can now customize the code and define their own business methods.
In Step 4, business transactions can be put into the body of the facade session bean. In Listing 3, a getQuote transaction is added.
Listing 3. getQuote transaction added to facade session bean
public class RegistryFacadeBean implements SessionBean
{
// Add user defined business methods here
public QuoteData getQuote(String symbol)
{
QuoteWrapper wQuote = new QuoteCMPWrapper();
Vector vQuote = wQuote.
Select( symbol, null, null );
if( vQuote.size() == 0 )
return null;
else
return ( QuoteData ) vQuote.get( 0 );
}
}
|
When working from the bottom up, getQuote is more naturally implemented as a SELECT. To do this, simply obtain a handle to the generated model helper (that is, the entity bean wrapper) and call the Select() method.
In this implementation, the Select() method is more than just a wrapper. It is a SELECT template, which supports different possible combination of "=" Boolean predicates. For example, the statement: Select( symbol, null, null )
Will be turned into the following EJBQL:
Select object(q) from Quote q where q.symbol=?l |
If you changed this to:
Select( symbol, price, null ) |
The following is executed:
Select object(q) from Quote q where q.symbol=?l and q.price=?2 |
And so on.
The IBM® AccessBean also shields the client program from the complexities of managing enterprise bean lifecycles. It would be interesting to see how AccessBeans and the SQL wrapper interface can work together to make bottom-up EJB development easier.
Usage example 2: Generating EJB Web pages
WebSphere Studio has an excellent Database Web Pages wizard. Given a SQL statement, the wizard can generate the HTML and JSP code that can access the database through JDBC. If you want to do this in EJBs instead of JDBC, you may want to leverage the generic entity EJB wrapper. This section describes how end-to-end EJB Web pages can possibly be generated as sample code using the generic SQL entity EJB wrapper.
This is bottom-up code generation, and the database is the starting point. The example below illustrates how end-to-end bottom-up code is generated starting from a DB2 database table using the generic SQL entity EJB wrapper. Consider the following table definition as a starting point of our code generation example.
Column Type Type name schema name ------------------------------ --------- ------------ USERID SYSIBM VARCHAR PASSWORD SYSIBM VARCHAR STATUS SYSIBM INTEGER |
An entity bean is generated using the Enterprise Bean Wizard for the table shown above. An entity bean is an abstraction of a row of data. The table columns are mapped to the container-managed fields.
Listing 4. Generating an entity bean
public class RegistryBean implements EntityBean
{
// Container managed fields
public java.lang.String userid;
public java.lang.String password;
public java.lang.Integer status;
//...
}
|
Generic SQL entity EJB wrapper
A SQL entity EJB wrapper is generated by the Eclipse plug-in that we mentioned in Usage Example 1 for the entity bean. The wrapper implements the Select, Insert, Delete, and Update method interfaces.
Listing 5. The SQL entity EJB
public interface RegistryWrapper
{
public Vector Select( RegistryData dRegistry );
public Vector SelectForUpdate( RegistryData dRegistry );
public void Insert( RegistryData dRegistry );
public void Delete();
public void Update( RegistryData dRegistry );
}
|
The RegistryData class is a data class. In our case, it is used as placeholders for the SQL predicates and for the result sets passed to and from the session bean and entity beans.
The Enterprise Bean Wizard can generate a facade session bean for the entity bean for the entity bean. The session bean is where you implement business methods. The Select, Insert, Delete, and Update business methods are generated by default. The entity bean wrapper is called within the relational database business methods.
Listing 6. The facade bean for the entity bean
public class RegistryFacadeBean implements SessionBean
{
public Vector Select( RegistryData dRegistry ) {
RegistryWrapper wRegistry
= new RegistryCMPWrapper();
return wRegistry.Select( dRegistry );
}
public Vector SelectForUpdate( RegistryData dRegistry )
{ /*...*/ }
public void Insert( RegistryData dRegistry ) { /*...*/ }
public void Delete() { /*...*/ }
public void Update( RegistryData dRegistry ) { /*...*/ }
// Add user defined business methods here
}
|
In the example in Listing 6, the generated Select() business method is completed by simply calling the Select() method in the Registry entity bean wrapper. The implementation of the Insert, Delete, Update business methods are similar.
The SQL methods in the facade session bean can then be promoted to the controller layer and/or the presentation layer for testing purpose. This is not limited to servlets and JSPs. There is nothing preventing the methods from being promoted to clients like J2EE applications, Java Applets, and Web services.
The generic SQL entity EJB wrapper not only simplifies bottom-up EJB database development, but also allows end-to-end code generation in many situations. As shown in the examples, the generalization provides an opportunity to use generated code, and the encapsulation greatly enhances the productivity of bottom-up EJB programming and legacy database development. This implementation can be used by WebSphere and DB2 UDB. A coming article will talk about the practical usage of the design pattern in details.
This article contains sample code. IBM grants you ("Licensee") a non-exclusive, royalty free, license to use this sample code. However, the sample code is provided as-is and without any warranties, whether EXPRESS OR IMPLIED, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. IBM AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE THAT RESULT FROM YOUR USE OF THE SOFTWARE. IN NO EVENT WILL IBM OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE SOFTWARE, EVEN IF IBM HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
IBM may have patents or pending patent applications covering subject matter described in this document. The furnishing of this document does not give you any license to these patents.
The author would like to thank Peter Shum, Matthew Huras, and Grant Hutchison for their valuable input and suggestions.
- [1] Harvey W. Gunther, WebSphere Application Server: Best Practices for Performance and Scalability, at http://www.ibm.com/software/webservers/appserv/ws_bestpractices.pdf
- [2] Tony Lau, Yongli An, Getting Started with WebSphere Performance Benchmark Sample, at http://www.ibm.com/dmdd/library/techarticle/0205an/0205an.html
Appendix A - Generated SQL EJB wrapper interface for the Registry bean with Inline documentation
/** * The Select() method maps to the Registry EJB finder method. Initial * context is obtained and Home interface is looked up if necessary. The * parameters are used as the predicates in the where clause. Any reference to * null will be taken away from the clause. For example, a call to * * Select( null, null, 1 ) * * translates to the SQL statement * * select * from Registry where status = 1 */ public Vector Select(java.lang.String userid, java.lang.String password, java.lang.Integer status); /** * Same as above except parameters are passed in form of RegistryData * wrapper. */ public Vector Select(RegistryData data); /** * The Insert() method maps to the Registry EJB create method. Initial * context is obtained and Home interface is looked up if necessary. The * parameters are the data to be inserted to the underlying table. */ public void Insert(java.lang.String userid, java.lang.String password, java.lang.Integer status) throws javax.ejb.CreateException, java.rmi.RemoteException; /** * Same as above except parameters are passed in form of RegistryData * wrapper. */ public void Insert(RegistryData data) throws javax.ejb.CreateException, java.rmi.RemoteException; /** * The Delete() method maps to the Registry EJB remove method. Initial * context is obtained and Home interface is looked up if necessary. The * Select() method must be called beforehand with resultset not null */ public void Delete(); /** * The Update() method maps to the Registry EJB setter methods. Initial * context is obtained and Home/Remote interface is looked up if necessary. The * parameters contain the updated data for the current row(s). The * Select() method must be called beforehand with resultset not null */ public void Update(java.lang.String userid, java.lang.String password, java.lang.Integer status); /** * Same as above except parameters are passed in form of RegistryData * wrapper. */ public void Update(RegistryData data); |
IBM, DB2, DB2 Universal Database and WebSphere are trademarks or registered trademarks of IBM Corporation in the United States, other countries, or both.
Java and all Java-based trademarks and logos are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States, other countries, or both.
Other company, product, and service names may be trademarks or service marks of others.
IBM copyright and trademark information
- [1] Harvey W. Gunther, WebSphere Application Server: Best Practices for Performance and Scalability, at
http://www.ibm.com/software/webservers/appserv/ws_bestpractices.pdf
- [2] Tony Lau, Yongli An, Getting Started with WebSphere Performance Benchmark Sample, at
http://www.ibm.com/dmdd/library/techarticle/0205an/0205an.html
Tony Lau is an IBM certified Systems Expert. He earned his Bachelor Degree of Applied Science in computer engineering from the University of Waterloo. He is an active member in UW Alumni. His current focus is DB2 performance for WebSphere and ebusiness applications. You can reach him at tktlau at ca.ibm.com.




