Implementing the Container Callback Methods

   

Implementing the Container Callback Methods

No matter which persistence method an entity bean uses, it has to implement the EntityBean interface. This means that you're still required to implement the same callback methods when you use CMP as you do for BMP. The difference is in what you're responsible for doing within these methods. An exception to this comment applies to finder methods, which aren't implemented at all within a CMP bean class. This is because the container is completely responsible for their implementation. You'll see later in the "Deploying an Entity Bean Using CMP" section how queries are defined for finder methods.

A common restriction to remember as the various callback methods are discussed is that you can't declare your implementations for any of them as static or final . This is because the container must be able to extend your bean class and override these methods.

Tip

As you'll see throughout this section, many of the callback methods can be declared with do-nothing or common implementations when you're using CMP. It's a good idea to implement an abstract class that provides default implementations for these methods. You can then extend all your CMP entity bean classes from it. The AbstractEntity class introduced previously in Chapter 5 is an example of how this can be done.


Assigning an EntityContext

The container assigns an EntityContext object to an entity instance when it's first created. Just like in BMP, you're responsible for implementing the following two methods to accept that assignment from the container:

 public void setEntityContext(EntityContext ctx) throws EJBException,    RemoteException;  public void unsetEntityContext() throws EJBException, RemoteException; 

Because of the point within a bean instance's life cycle that these methods are called, you can use them to allocate and deallocate resources that are used by all instances of the bean class. You can't allocate resources that are specific to a single entity object identity here because an instance can be reused without setEntityContext ever being called again by the container. Most of the time you won't need to do anything special in these methods and you can provide simple implementations like those shown in the following code:

 public abstract class EnglishAuctionCMPBean implements EntityBean {   ...    EntityContext ctx;    ...    public void setEntityContext(EntityContext ctx) {     this.ctx = ctx;    }    public void unsetEntityContext() {     ctx = null;    }    ...  } 

Creation and Removal

For any entity bean you declare, you have to implement an ejbCreate method for each cre ate method declared in the bean's home interface. Your ejbCreate method has to perform the database insert for a new entity for BMP, but that's not the case with CMP. The container performs the database insert for you, but it calls your ejbCreate method first to give you the chance to initialize the instance. Listing 7.1 shows an example CMP implementation of an ejbCreate method.

Listing 7.1 ejbCreateWithData “A CMP ejbCreate Method Initializes an Entity Before It's Inserted
 public Integer ejbCreateWithData(String name, String description)   throws CreateException {   // throw an application exception if the name isn't valid    if ((name == null)  (name.trim().length() == 0)) {     throw new CreateException("Cannot create an auction without a name");    }    // initialize the entity object before it's inserted by the container    setNameField(name);    setDescriptionField(description);     // always return null from ejbCreate for CMP    return null;  } 

Notice that this implementation of ejbCreateWithData returns a null . BMP ejbCreate methods have to return the primary key value assigned to a new entity object, but CMP implementations always return null and leave the primary key assignment to the container. After the container calls your ejbCreate method, the container saves the entity (or at least assigns its primary key) and your ejbPostCreate method is called. As with BMP, this method is where you perform any initialization that depends on the primary key of the entity object being assigned. This is also the only point during the creation process that you can assign objects to a CMR field relationship. Unless you establish relationships when an entity object is first created, an implementation of this method that does nothing is all you usually need:

 public void ejbPostCreateWithData(String name, String description)   throws CreateException { } 

In the case of AuctionBidBean , it needs to define relationships to the owning auction and bidder when it's created:

 public void ejbPostCreate(EnglishAuction newAuction, Bidder newBidder,   Timestamp newDateTimeSubmitted, Double newAmount, String newTransactionId) {   // CMR fields can only be set in ejbPostCreate    setAuction(newAuction);    setBidder(newBidder);  } 

The life cycle for an entity includes a callback method for removal as well as creation. When a client calls a remove method on an entity, the container calls your ejbRemove method before deleting the corresponding data from the database. You can throw a RemoveException to veto a deletion, but you're not responsible for making the delete call on the database. The purpose of calling ejbRemove is to allow you to free up any resources held by the instance. After ejbRemove returns, the container removes the referenced entity object from any managed relationships and deletes it from the data store. The container might wait until the end of the current transaction to perform this delete, but the entity is removed immediately as far as the application can tell.

Before returning to the client that invoked the remove operation, the container deletes any related entities that you've identified as requiring a cascade deletion. Just like the initial entity object being removed, any related entities that are deleted this way are removed from any relationships after their ejbRemove method has been executed. This process continues recursively until the cascade deletion is complete.

In the simple implementation of the auction example, no processing needs to be done in ejbRemove , and the version inherited from AbstractEntity is all that's needed. A more robust bean class might want to reject deletion depending on the current state of the auction. For example, you might want to throw an exception if an attempt is made to delete an open auction without first canceling it.

Primary Key Generation

Several options for generating primary key values were introduced in Chapter 6. These included using native sequencing provided by the database or generating a globally unique string each time a key value is needed. For the BMP auction classes, a simple approach of accessing a sequence table in the database during a call to ejbCreate was used. No matter which approach you use to generate a key for a BMP entity, you're responsible for returning it from ejbCreate . All this changes when you move to CMP. An ejbCreate method for a CMP entity does any required initialization of its fields (other than those related to the primary key) and returns null . The container then is responsible for assigning the primary key before calling the corresponding ejbPostCreate . This is why you have to wait until ejbPostCreate to assign related objects to a new entity.

Because you don't directly assign the primary key and you don't interact with the data store yourself, you're limited in your choices for primary key generation with CMP. In short, you're dependent on the options offered to you by the CMP implementation you use. These options typically include using a particular database vendor's native sequencing capability or using a sequence table that the container interacts with directly. For the auction example, this is demonstrated using WebLogic's sequence table option. As you'll see when the deployment descriptors for the example are covered, the only change required to the BMP sequence tables is to the column name used in the table. WebLogic requires the column in a sequence table to be named SEQUENCE .

Loading and Storing

Whenever the container retrieves an entity object's state from the database, it follows that operation with a call to ejbLoad on the instance. This method is the appropriate place to update any transient instance fields declared by the class that depend on an entity's persistent fields. After ejbLoad , an entity's instance fields are expected to be in a consistent state. Before writing an entity's state to the database, the container calls ejbStore on the instance. This method should transfer any transient data that's used to determine the value of persistent fields to those fields. This would be necessary if you were to work with an entity within an application using fields that aren't the ones actually persisted . The persistent fields might be optimized for storage and not as easy to work with as an alternate version you hold in one or more transient fields.

The uses of ejbLoad and ejbStore described here are not needed very often. In most entity bean classes that you develop, you'll only need do-nothing implementations of these methods.

Passivation and Activation

When the container is preparing to move an entity instance into the ready state, it calls its ejbActivate method before calling ejbLoad . The purpose of the ejbActivate method is to allow you to obtain any resources that are needed by the instance. Whenever the container decides it needs to passivate an entity object, it calls the instance's ejbStore method and then ejbPassivate . You should release any resource references obtained in ejbActivate when ejbPassivate is called. An entity bean instance isn't associated with an entity object's state when activation and passivation are taking place. Because of this, you're not allowed to call any of the instance's CMP or CMR get or set methods within either ejbActivate or ejbPassivate .

Implementing Home Methods

You're restricted in what you can do within a home method because it isn't associated with a particular entity object identity when it's executed. This means that you can't access any instance fields or methods of the class within a home method. For a CMP bean, this means that you can't call a CMP or CMR get or set method as part of a home method.

The EnglishAuctionHome interface includes a declaration for a single home method:

 public Collection getItemsBeingAuctioned(); 

You can implement this method with the following:

 public Collection ejbHomeGetItemsBeingAuctioned() {   try {     return ejbSelectAuctionedItems();    }    catch (FinderException e) {     return null;    }  } 

Here, the home method returns a collection of Item local interface references that correspond to all the items currently assigned to auctions. The implementation details are delegated to a select method. Select methods are a feature unique to CMP beans that you'll see defined in the next section.

To remind yourself of the rules associated with implementing these methods, see "Home Methods," p. 137 .

Declaring Select Methods

A select method allows you to query the database for information about an entity or any of its related entity objects within the framework provided by the container. For example, a customer entity bean could make use of a select method to locate the orders associated with a customer that are above a certain price. Select methods are similar to finder methods in that they are implemented by the container and not the bean provider. Where they differ is that you can't expose a select method in a bean's home or component interface ”these methods are only for a bean class to use internally. The only code that you write for a select method is an abstract method declaration in the bean class. Using the same pattern applied to the other bean implementation methods, select methods must be declared with a name that begins with ejbSelect . For example, the following is a valid select method declaration:

 public abstract Collection ejbSelectHighPriceOrders(double minOrderAmount)    throws FinderException; 

As shown in this example, a select method must be declared as public and abstract and it must include FinderException in its throws clause, along with any other application exceptions you want to throw. A select method can return values corresponding to any CMP or CMR field declared for the bean. You can declare a select method to return a single value, but you have to be certain that only a single value will ever be returned if you do. Usually, you'll declare a select method to return either Collection or Set . If you're returning entity bean references from a select method, you need to declare the select method to return the local reference type of the entity or a collection of them.

The select method that was referenced by the implementation of the ejbHomeGetItemsBeingAuctioned home method is declared as

 public abstract Collection ejbSelectAuctionedItems() throws FinderException; 

The abstract declaration for a select method allows you to use it within the bean class. This declaration is all you need to provide in your code. The next section describes how you define the actual query for a select.



Special Edition Using Enterprise JavaBeans 2.0
Special Edition Using Enterprise JavaBeans 2.0
ISBN: 0789725673
EAN: 2147483647
Year: 2000
Pages: 223

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net