Getting Started with Enterprise JavaBeans™

G

Entity Beans

Tutorial Home Section Home Previous Section Next

Get

Get

Example: The Rock Survey, Take 2 (continued)

     "SurveyBeanTable", created in The Rock Survey Database, contains exactly one row consisting of counter and total columns for the survey data. The last step for Take 2 of the Rock Survey application will add data management for the table. As you might expect from the way we went about things in Example: The Rock Survey, Take 2 and the preceding discussion, we will accomplish the task by adding another entity bean, this time using CMP, and expanding the persist() method in RockSurvey2Bean.

     You may ask yourself why any normal human would name a table "SurveyBeanTable" — unexpectedly, the double quotes are part of the name. The answer is that deploytool generated and named it (see the discussion about generating the default SQL in Final Deployment of the Rock Survey, Take 2). The developer has no real control over the datastore creation when using CMP; table naming and Object/Relational (O/R) mapping are not addressed by the specification, meaning that it is vendor proprietary. This state of affairs can become a major issue when dealing with existing databases and for data portability among vendor implementations. And yes, I cheated in The Rock Survey Database by using the container-generated SQL to ensure that the data was set up to match the container's expectations.

     The SurveyBean class manages "SurveyBeanTable" data, and, other than providing getters and setters for 19 column variables, is surprisingly small. That's because all of the persistence code (read JDBC/SQL here) is generated by the container. As we will see shortly, the reduction in code comes at the price of more complicated and complex deployment descriptors, along with some vendor dependent entries.

     The local home interface should look familiar:


// the local home interface for SurveyBean
import javax.ejb.*;

public interface SurveyLocalHome extends EJBLocalHome 
{
    
    public SurveyLocal create( String Type )
        throws CreateException;
    
    public SurveyLocal findByPrimaryKey (String Type)
        throws FinderException;
    
} // end interface SurveyLocalHome

     The local component interface is completely composed of getters and setters. These are all declared abstract in the SurveyBean code.


// the local component interface for SurveyBean
import javax.ejb.*;

public interface SurveyLocal extends EJBLocalObject 
{
  public String getType();
  public void setType( String TypeIn );
    
  public int getSF();
  public void setSF( int SFIn );
  ...    
  public double getPounds();
  public void setPounds( double PoundsIn );

} // end interface SurveyLocal

     In this case, RockSurvey2Bean, the managing session bean, does all of the editing and validation. At times, you may prefer to have these tasks centralized, probably in the entity bean itself. So how do you do that when the setter is abstract? The answer is to have another method to perform any tasks for a data element, and, if the element passes editing, have that method call the setter. A naming convention for the editing methods becomes very helpful for maintainable code in that situation. We do have one edit in the bean: in the ejbCreate() method, which in CMP is invoked before the actual insertion, the primary key String argument is checked to be sure that it is "ROCK". Again, there will only be one row in this table and the key will always be "ROCK". If the test fails, a CreateException is thrown.

     It should be mentioned that it is more typical to send the key and also arguments for all of the data to be inserted in the row to ejbCreate(). Here, because inserts should happen very infrequently — expected to be once in this table's lifetime — and because 19 arguments could become unwieldy to handle correctly, the code initially creates the row with just the key information. It then calls the setters using a RockSurvey2Bean method (setupSurveyData()) already written to handle data updates. The coding time and maintenance efficiencies gained by using this technique — in this case — are an acceptable tradeoff against any performance losses.

     In RockSurvey2Bean, instance variables for the SurveyBean local interfaces have been added, and the ejbPassivate() method now sets the interface variables for both of the entity beans and the UserTransaction reference to null. The persist() method tests for null values and resets the variables if appropriate.

     The new code related to SurveyBean should look familiar. The code first obtains the local home:


      if( slHome == null )
      {
        sMsg = "SurveyBean";
        ic = new InitialContext();
        slHome = 
          (SurveyLocalHome)ic.lookup( 
             "java:comp/env/ejb/SurveyBean" ); 
      }

     Since there will always be only one row in the "SurveyBeanTable" table, the "try the finder first, perform create upon failure" technique is even more appropriate than before. Here's the code:


    try
    {
      sl = slHome.findByPrimaryKey( "ROCK" );
      bWasSuccessful = true;

      setupSurveyData();
      System.out.println("sl find successful." );
    }
    catch( ObjectNotFoundException onfe )
    { // create if not found
      System.out.println("trying create." );
      try
      {  
        sl = slHome.create( "ROCK" ); 
        setupSurveyData();
        ...
      }  
      ...
    }  

     This code is performed in-line with the SurveyNamesBean management code and within the same transaction.

     The other addition to RockSurvey2Bean is the setupSurveyData() method, which breaks down the survey input data to the appropriate categories for updating the datastore. The method is invoked for both creates and updates.

     Again, externally, to both the Web component and the end user, there is no difference between Take 1 and Take 2 other than the time it takes to update the datastore.



Tutorial Home Section Home Previous Section Next