G |
Entity Beans |
|
Get |
Get |
Example: The Rock Survey, Take 2 |
Now that we've actually created a database, and have some knowledge of entity beans and transactions, it's time to add data handling capability to the Rock Survey application. The first go 'round (see Example: The Rock Survey, Take 1) handled the user view and tracked the survey through the pages of the Web component, but never actually stored anything at the end of the survey. This portion of Take 2 will add a BMP entity bean (SurveyNamesBean) to deal with data for the SurveyNames table. It will also expand the persist() method in RockSurveyBean to include a transaction manager, and control adding and updating names and name counts.
The primary key for the SurveyNames table (see Table 3 in The Rock Survey Database) consists of two Strings (SQL type VARCHAR). You may recall from Entity Beans Overview that a primary key consisting of more than one element requires a custom primary key class. The SurveyNamesKey class represents the primary key for SurveyNames. The class consists of the two composite key Strings, a no-arg and a two argument constructor, getXXX methods for the data, and equals() and hashCode() methods. The class is used by the SurveyNamesBean create() and findByPrimaryKey() methods.
The SurveyNamesBean class performs access and maintenance operations against the SurveyNames table. SurveyNamesBean is an entity bean with BMP, and it implements all of the life cycle methods discussed in The Entity Bean Life Cycle and Entity Beans with Bean-Managed Persistence. In addition, it has getter methods for the Type, LastName, and Total columns. There is also an incrementTotal() method, which adds 1 to the current count. The class uses the same technique of connecting to the database as the CreateRSTables class (see Creating and Resetting the Rock Survey Tables), and uses standard SQL for access and updates. As recommended for EJB 2.0 components, the class exposes its methods with local home and component interfaces, as shown below:
// the local home interface for SurveyNamesBean
import javax.ejb.*;
public interface SurveyNamesLocalHome extends EJBLocalHome
{
public SurveyNamesLocal create( SurveyNamesKey snkIn )
throws CreateException;
public SurveyNamesLocal findByPrimaryKey(
SurveyNamesKey snkIn )
throws FinderException;
// no home business methods
} // end interface SurveyNamesLocalHome
// the local component interface for SurveyNamesBean
import javax.ejb.*;
public interface SurveyNamesLocal extends EJBLocalObject
{
public String getLastName();
public String getType();
public int getTotal();
public void incrementTotal();
} //end interface SurveyNamesLocal
SurveyNamesBean is managed by a new version of RockSurveyBean named RockSurvey2Bean. The primary additions are instance variables for the SessionContext and a javax.transaction.UserTransaction, along with variables to access SurveyNamesBean. The persist() method now actually does something, being expanded to handle the creation and updating of SurveyNames data. As you might imagine, there are many details in the code, but the following snippets show the essence of the new operations.
persist() uses the now familiar JNDI lookup with the local interface version to get the SurveyNamesBean home interface:
...
ic = new InitialContext();
snlHome =
(SurveyNamesLocalHome)ic.lookup(
"java:comp/env/ejb/SurveyNamesBean" );
...
The code then obtains a UserTransaction (ut is a UserTransaction and sc is a SessionContext) and begins a new transaction:
ut = sc.getUserTransaction();
...
ut.begin(); // begin transaction
The specification mandates that entity beans use container-managed transactions, but by using the Required transaction attribute, the entity bean insert and update operations will join in the transaction initiated by the session bean.
Because the same last names will often be entered into the survey, especially over time, the application takes the approach of first attempting to find existing data for the given last name, using findByPrimaryKey(). If the search is successful, the existing count is incremented; if the finder fails, then new data is created with an initial count of one. The snk variable in the code below is a reference to a SurveyNamesKey instance; snl is a SurveyNamesLocal reference:
...
try
{
snl = snlHome.findByPrimaryKey( snk );
bWasSuccessful = true;
snl.incrementTotal();
System.out.println("snl find successful." );
}
catch( ObjectNotFoundException onfe )
{ // create if not found
System.out.println("trying create." );
try
{
snl = snlHome.create( snk );
...
If the find or create was successful, the transaction is committed; if not, the transaction is rolled back:
if( bWasSuccessful )
{
bWasSuccessful = doCommit();
}
else { doRollback(); }
return bWasSuccessful;
From the Web component's view, nothing has changed. As we'll see in the next panel, deployment descriptor entries map RockSurvey2Bean to the java:comp/env/ejb/RockSurveyBean lookup. Even the same remote home and component interfaces are used, without change, again being mapped with deployment descriptor entries. Therefore, the JSPs, constants classes, and the RockSurveyRemote home and component interfaces from Example: The Rock Survey, Take 1 are reused in Take 2.
From the end user perspective, the only difference is a pause while the data is persisted after she presses the Done button.
|
|