Skip to main content

Implementing an SQL EJB Wrapper as a Model Helper using an Access Bean

Tony Lau, Certified Systems Expert, IBM, Software Group
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
Peter He, Software Developer, IBM, Software Group
Peter He is a Software Developer with the DB2 Integration Team at IBM Toronto Lab. Peter has been working extensively with DB2 and WebSphere technologies and is the architect of the IBM Video Central software based on Web Services architecture. He holds a Ph.D. from York University and is a DB2 Certified Solutions Expert.

Summary:  This article provides a sample implementation of the wrapper described in a previous article on using a generic SQL entity EJB wrapper to simplify EJB development. The article also describes performance implications.

Date:  14 Aug 2003
Level:  Introductory
Activity:  268 views

© 2003 International Business Machines Corporation. All rights reserved.

Important: Please read the disclaimer before reading this article.

Introduction

The introductory article Using a Generic SQL Entity EJB Wrapper to Simplify EJB development proposed a coding technique for simplifying bottom-up EJB development. In this follow-up article, we provide a sample implementation of the wrapper and describe how the wrapper works with the existing IBM® infrastructures.

IBM architects recommend that programmers use a model helper to simplify the use of entity EJBs[1]. A model helper lets you use entity beans like a regular JavaTM Bean. WebSphere® Studio supports the implementation of a model helper by providing an Access Bean infrastructure. An Access Bean consists of an EJB factory and a data class. The factory is responsible for the EJB life-cycling. The data class provides the data storage and access methods for cacheable enterprise bean properties. This saves lots of work in terms of managing the EJB interfaces.

In this article, we describe a sample implementation of the SQL EJB Wrapper as a model helper leveraging Access Bean technology. We'll also point out the performance implications to the underlying database management system (DBMS).


Setting up the sample

Install the prerequisite software.

  1. Install DB2 UDB v8.1.2
  2. Install Websphere Studio Enterprise Edition v5

Create the sample database

To create the sample database:

  1. Download TradeDB.bat from downloads.
  2. Open a DB2 Command Window.
  3. In the DB2 Command Window just opened, run TradeDb.bat.

Import the application

To import the application to the Enterprise Developer configuration of WebSphere Studio, use the steps below:

  1. Download EjbWraper.ear from the downloads section below.
  2. Launch WebSphere Studio.
  3. In WebSphere Studio,click File->Import to open an Import window.
  4. In the Import window, select the EAR file, and then click Next.
  5. In the second Import window, browse EjbWraper.ear for the Ear File field and enter EjbWraper for the Project Name field, and then click Finish.
  6. Import Query.ear from the <WSED5>\runtimes\ee_v5\lib directory.

Configure the classpath

Now add the required packages to the classpath:

  1. Bring up the J2EE perspective.
  2. Right click on the TradeEJB project and select Properties.
  3. In the Properties for TradeEJB window, select the Libaries tag in the Java Build Path panel.
  4. Select Add External JARs and add query.jar and qryclient.jar under the <WSED5>\runtimes\ee_v5\lib directory.

Create the test server

To create a test server for the sample code:

  1. Open the Server perspective.
  2. In the Server Configurations panel, right click on Servers and select New->Server and Server Configurations.
  3. In the Create a New Server and Server Configuration window (Figure 1), enter EjbWrapTestServer into the Server name field and select EE Test Environment, and then click Finish.
    Figure 1. Creating a test server
    Figure 1. Creating a test server
  4. In the Server Configuration panel, right click on Servers->EjbWrapTestServer and select Add->EjbWrapper and do the same for the Query.ear project.
  5. In the Server Configuration panel, right click on Servers->EjbWrapTestServer and select Open to open the server configuration.
  6. Select the Security tag and add a Trade JAAS Authentication Entries for the Trade user (Figure 2).
    Figure 2. Adding authentication entries
    Figure 2. Adding authentication entries
  7. Select the Data source tag, and add a V5 datasource with JNDI name jdbc/Trade and database name TradeDB. Set the component-managed authentication alias and container-managed authentication alias to EjbWraper (Figures 3 and 4).
    Figure 3. Adding a datasource
    Figure 3. Adding a datasource

    Figure 4. Adding a datasource, con't
    Figure 4. Adding a datasource, con't

Test the code

To test the code, run the Tradedb session bean, which contains some test functions for the wrapper code on the test server:

  1. Open the Server perspective.
  2. In the Server view, making sure that the Server State is "Server is synchronized." Right click on the EjbWraperTestServer, and select Start. This will start the test server.
  3. Open the J2EE perspective.
  4. In the J2EE Hierarchy view, right click on the Tradedb Session bean and select Run on Server. This will start the Universal Test Client (Figure 5).
    Figure 5. Universal Test Client
    Figure 5. Universal Test Client
  5. In the References panel, expand the Tradedb->TradedbHome and use the create() method to create a reference to Tradedb.
  6. Invoke any of the test functions included in the sample code.
    Figure 6. Invoking a test function from the test client
    Figure 6. Invoking a test function from the test client

At this point, the sample code is up and running. Let's look at the source code.


The model class

The model class is our EJB helper class. Listing 1 shows the class member and the methods in the TradeaccountbeanModel class.

Listing 1. The model class

 
public class TradeaccountbeanModel
{ 
	private Vector beanInterface = new Vector();
 
	public Vector Select(String userid, Double balance, Integer transactions)  
		throws javax.ejb.FinderException
	{ /*... */ } 
 
	public void Insert(String userid, Double balance, Integer transactions) 
		throws javax.ejb.CreateException
	{ /*... */ } 
  
	public void Delete() throws javax.ejb.RemoveException
	{ /*... */ }
 
	public void Update(String userid, Double balance, Integer transactions)
	{ /*... */ }
 
} 

The TradeaccountbeanModel class consists of a beanInterface class member and Select(), Insert(), Delete(), and Update() methods.

The Select(), Insert(), Delete(), and Update() methods are described in the introductory article. You can add user-defined functions to the model helper if you like.

The beanInterface class member is a collection of bean references as a result of a query. This is intended to cache the bean references for further manipulation.

We'll describe the implementation of each SQL method in the upcoming sections.


Insert method

A call to the bean creation method results in an insert to the underlying database. Consider Listing 2 for a typical implementation of insert.

Listing 2. A typical implementation of insert

 
public void Insert(String userid, Double balance, Integer transactions) 
	throws javax.ejb.CreateException
{
	TradeaccountbeanFactory factory = new TradeaccountbeanFactory();
	try
	{
		 Tradeaccountbean bean = factory.create(userid);
		 bean.setUserid(userid);
		 bean.setTransactions(transactions);
 
		 beanInterface.add( bean );
	}
	catch (java.rmi.RemoteException re)
	{
	}
}

EJB factory is an access bean that simplifies the creating or finding of an enterprise bean instance. In our example above, the TradeaccountbeanFactory is used to create an instance of Tradeaccountbean entity bean with the corresponding primary key. The default setter methods in the entity bean are used to initialize the container-managed persistent (CMP) fields userid and transactions of the bean. However, this implementation does not only result in one insert statement but also has the side effect of two additional update statements.

Consider Listing 3 for an example of more efficient implementation of insert.

Listing 3. A more efficient insert

 
public void Insert(String userid, Double balance, Integer transactions) 
	throws javax.ejb.CreateException 
{ 
	TradeaccountbeanFactory factory = new TradeaccountbeanFactory(); 
 
	try 
	{ 
		beanInterface.add(factory.create(userid, balance, transactions)); 
		System.out.println("Insert"); 
	} 
	catch (java.rmi.RemoteException re) 
	{ 
		throw new EJBException(re); 
	} 
} 


In this implementation, we use an EJB factory create method that passes in all the CMP fields in one shot. Only a single insert statement is generated as desired.

To be able to use the create method above, you must add the corresponding signature with all the CMP fields in the home class. See Listing 4 for an example.

Listing 4. Add an ejbCreate() to TradeaccountbeanBean.java

 public sample.TradeaccountbeanKey ejbCreate( 
	java.lang.String userid, 
	java.lang.Double balance, 
	java.lang.Integer transactions) 
	throws javax.ejb.CreateException 
{ 
	setUserid(userid); 
	setBalance(balance); 
	setTransactions(transactions); 
	return null; 
} 


Then you must promote this method to the home class as shown in Listing 5.

Listing 5. Add a create() to TradeaccountbeanHome.java

 
public sample.Tradeaccountbean create( 
	java.lang.String userid, 
	Double balance, 
	Integer transactions) 
	throws javax.ejb.CreateException, java.rmi.RemoteException; 



Select method

The Select() described in the coding technique is a select filter template. It generates a frequently used SELECT-WHERE-AND query. Consider Listing 6 for an implementation of select.

Listing 6. A traditional implementation of select

public Vector Select(String userid, Double balance, Integer transactions) 
	throws javax.ejb.FinderException 
{ 
	Enumeration bean = null; 
	Vector queryResult = new Vector(); 
 
	try 
	{ 
		bean = findByWhereClause(userid, balance, transactions); 
		while ( e.hasMoreElements() ) 
{ 
			beanInterface.add(bean); 
			queryResult.add(bean.getTradeaccountbeanData()); 
		} 
       } 
	catch (java.rmi.RemoteException re) 
	{ 
	} 
	return queryResult; 
 
} 


One way to implement a select filter is to dynamically compose a JDBC statement based on the parameters passed in by the client. This result set will provides the actual data values. To obtain references to the beans, we can issue a findByPrimaryKey() default EJB finder for each individual bean. If you look at the source code provided, this is exactly what the findByWhereClause() method above is doing. This way, any call to the Select() method will result in N+1 selects to the database for each call, where N is the size of the result set.

For applications that we do not know the query search criteria (such as a select filter) until application runtime, we may want to use IBM Dynamic Query Services (DQS) [1]. See Listing 7 for a more efficient implementation of select leveraging the advantages of DQS.

Listing 7. A DQS implementation of select

 
public Vector Select(String userid, Double balance, Integer transactions) 
	throws javax.ejb.FinderException 
{ 
	String query = "SELECT OBJECT(a) FROM Tradeaccountbean a "; 
	Vector queryResult = new Vector(); 
	 
	//Generate the EJBQL query 
	try 
	{	 
		int count = 0; 
		Object[] parms = new Object[3];  
		 
		if (userid != null || balance != null || transactions != null) 
		{ 
			int markPos = 0; 
			 
			query = query + " WHERE "; 
			 
			if (userid != null) 
			{ 
				query += "a.userid = ?1"; 
				parms[count] = new String (userid); 
				count++; 
			} 
				 
			if (balance != null) 
			{ 
				if (count == 0) 
				{ 
					query += "a.balance = ?1"; 
				} 
				else 
				{ 
					markPos = count + 1; 
					query += " AND a.balance = ?" + markPos; 
				} 
					 
				parms[count] = balance; 
				count++; 
			} 
				 
			if (transactions != null) 
			{ 
				if (count == 0) 
				{ 
					query += "a.transactions = ?1"; 
				} 
				else 
				{ 
					markPos = count + 1; 
					query += " AND a.transactions = ?" + markPos; 
				} 
		 
				parms[count] = transactions; 
				count++; 
			} 
		} 
				 
		System.out.println("Query: " + query); 
			 
		Query qb = QueryBeanFactory.getQuery();		 
		QueryIterator it; 
			 
		Object[] newParms; 
			 
		if (count == 0) 
			newParms = null; 
		else 
		{ 
			newParms = new Object[count]; 
			for (int i = 0; i < count; i++) 
				newParms[i] = parms[i]; 
		} 
				 
		//Query Database 
		it = qb.executeQuery(query, newParms, null, 0, 1000); 
			 
		qb.remove(); 
			 
		//Get the query result			 
		while (it.hasNext()) 
		{ 
			IQueryTuple t = (IQueryTuple) it.next(); 
			Tradeaccountbean accountbean = (Tradeaccountbean)t.getObject(1); 
			beanInterface.add(accountbean); 
			queryResult.add(accountbean.getTradeAccountBeanData()); 
		} 
			 
		return queryResult; 
			 
	} 
	catch (Exception e) 
	{ 
		e.printStackTrace(); 
		throw new EJBException (e); 
	}						 
 
} 

The dynamic query API is actually a Query stateless session bean. Before we can execute a query, we have to obtain a reference to the Query session bean either through JNDI or factory. As shown in the code above, a Query bean is obtained from the QueryBeanFactory.

A dynamic query is passed in as a String and the input parameters are passed in the form of an array of java.lang.Object values. So, the query and the parameters can be dynamically composed based on the search criteria provided by the Select() method client.

Calling the next() method of the QueryIterator returns an instance of IQueryTuple, which contains the actual data values and object references. For our purpose, we store the object references for later use and returns the data classes from the object as the query result.

This implementation of Select() template will be translated to a single select statement to the underlying database. Very clearly, DQS provides high flexibility of implementing the Select() filter. For more information on DQS, please refer to the WebSphere InfoCenter [4].


Delete method

The following is an implementation of a delete.

Listing 8. An implementation of delete

 
public void Delete() throws javax.ejb.RemoveException 
{ 
 
	System.out.println("Delete"); 
 
	try 
	{ 
		for (int i = 0; i < beanInterface.size(); i++) 
			 ((Tradeaccountbean) beanInterface.get(i)).remove(); 
	} 
	catch (java.rmi.RemoteException re) 
	{ 
		throw new EJBException(re); 
	} 
} 


Code the beans resulted from the previous select are removed by calling the remove() method in the bean interfaces one-by-one.


Update method

In EJB programming model, update is relatively transparent to the programmer. Any change to the CMP fields will result in update statements to the database. Consider Listing 9 for a typical implementation of update.

Listing 9. A typical implementation of update

 
public void Update(String userid, Double balance, Integer transaction) 
{ 
	Tradeaccountbean b = null; 
	try 
	{ 
		for (int i = 0; i < beanInterface.size(); i++) 
		{ 
			b.setBalance(balance); 
			b.setTransactions(transaction);			 
		} 
	} 
	catch (java.rmi.RemoteException re) 
	{ 
	} 
} 

What we need to do is to call the default setter methods provided by WebSphere Studio. Note that each call to the setter is an individual update. In the example above, we will have two update statements, one for updating the balance and one for updating the transaction.

Consider Listing 10 for a more efficient implementation of update.

Listing 10. A more efficient implementation of update

 
public void Update(String userid, Double balance, Integer transaction) 
{ 
 
	Tradeaccountbean b = null; 
	TradeaccountbeanData d = null; 
	try 
	{ 
		for (int i = 0; i < beanInterface.size(); i++) 
		{ 
			// Get data class of each bean 
			b = ((Tradeaccountbean) beanInterface.get(i)); 
			d = b.getTradeaccountbeanData(); 
			// Update each data class 
			d.setBalance(balance); 
			d.setTransactions(transaction); 
			b.syncTradeaccountbeanData(d); 
		} 
 
	} 
	catch (java.rmi.RemoteException re) 
	{ 
		throw new EJBException(re); 
	} 
 
} 

A data class access bean provides the data storage and access methods for cacheable enterprise bean properties. The syncXXXData() method causes any changes you have made to the data class to be written back to the enterprise bean. In our example, we update the balance and transaction through the setter of the TradeaccountbeanData data class. The syncTradeaccountbeanData() method is called to synchronize the change. Only one update statement is issued.


Conclusion

This article described a sample implementation of a SQL EJB Wrapper. The SQL wrapper supports the concept of model helper. The wrapper also works very well with Access Bean in WebSphere Studio. One important aspect of implementing wrappers is to ensure that the wrappers are leveraging best practices for EJB performance. In this article, we also go through the best practices in terms of database access.


Disclaimer

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.

IBM certified Systems Expert



Downloads

NameSizeDownload method
TradeDB.bat3 KB HTTP
EjbWraper.ear2 KB

Information about download methods


Resources

About the authors

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

Peter He is a Software Developer with the DB2 Integration Team at IBM Toronto Lab. Peter has been working extensively with DB2 and WebSphere technologies and is the architect of the IBM Video Central software based on Web Services architecture. He holds a Ph.D. from York University and is a DB2 Certified Solutions Expert.

Comments (Undergoing maintenance)



Trademarks  |  My developerWorks terms and conditions

Help: Update or add to My dW interests

What's this?

This little timesaver lets you update your My developerWorks profile with just one click! The general subject of this content (AIX and UNIX, Information Management, Lotus, Rational, Tivoli, WebSphere, Java, Linux, Open source, SOA and Web services, Web development, or XML) will be added to the interests section of your profile, if it's not there already. You only need to be logged in to My developerWorks.

And what's the point of adding your interests to your profile? That's how you find other users with the same interests as yours, and see what they're reading and contributing to the community. Your interests also help us recommend relevant developerWorks content to you.

View your My developerWorks profile

Return from help

Help: Remove from My dW interests

What's this?

Removing this interest does not alter your profile, but rather removes this piece of content from a list of all content for which you've indicated interest. In a future enhancement to My developerWorks, you'll be able to see a record of that content.

View your My developerWorks profile

Return from help

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Information Management, WebSphere
ArticleID=14396
ArticleTitle=Implementing an SQL EJB Wrapper as a Model Helper using an Access Bean
publish-date=08142003
author1-email=
author1-email-cc=
author2-email=
author2-email-cc=

My developerWorks community

Tags

Help
Use the search field to find all types of content in My developerWorks with that tag.

Use the slider bar to see more or fewer tags.

Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere).

My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).

Use the search field to find all types of content in My developerWorks with that tag. Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere). My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).

Special offers