ONJava.com -- The Independent Source for Enterprise Java
oreilly.comSafari Books Online.Conferences.

advertisement

AddThis Social Bookmark Button

J2EE Design Patterns: CMP-to-BMP Pattern

by Dion Almaer
04/10/2002

EJB 2.0 finally gives us a Container-Managed Persistence (CMP) model to work with. Whenever possible, I like to use CMP beans in my EJB projects; however, for the odd thing, I need to change my entity to be bean-managed. I use the following pattern to allow me to go from a CMP model to a Bean-Managed Persistence (BMP) model in a clean way.

In this article, we will discuss:

  1. CMP 2.0: What has changed?
  2. The Inventory EJB application.
  3. Developing a CMP bean.
  4. Migrating the bean to use BMP.

CMP 2.0: What Has Changed?

When EJB first came out, it got a real hammering over CMP. When EJB 2.0 came out, along came a revamped CMP model, giving us features we really wanted like relationships and standardizing on a query language.

When it comes to writing a CMP bean, we do so in a very different way, compared to doing so with EJB 1.1. We create an abstract class, and instead of creating public fields for the managed variables, we create abstract getters and setters (like JavaBeans). This allows the vendor persistence manager to implement the accessors to the data in their own way.

This helps them put in logic that says things like:

  • Since they didn't call any set methods, don't do anything in ejbStore().
  • They only changed one field, so let's just SET that field in the UPDATE query.
  • Let's lazy-load some of the data, so that we only get it when the user asks for it via the get method.

Side Question: Why do we have to create abstract methods in this abstract class? Why can't the persistence manager just create the methods in the subclass?

Answer: We need to access these methods in the abstract class. For example, in ejbCreate(...), we go through the passed-in arguments and set*() them.

Inventory EJB Application

To show this entity pattern, we will look at a simple application that models an inventory system. The parts of the application are:

  • Inventory Entity Bean: This is our focus. It will map to a database table inventory, which holds the item name (primary key), price, and the number of items in stock.
  • Pricer Stateless Session Bean: This bean uses the inventory entity bean to get the price(s) of items. It uses local interfaces to access the entities (new in EJB 2.0)
  • Pricer Client: This command-line application runs methods on the session to test that this is all working.

One key point is that when we migrate the inventory entity bean from CMP to a BMP implementation, nothing else will change.

Let's look at implementing the inventory entity bean using CMP.

Developing a CMP Bean

The inventory CMP requires us to create an abstract class (compliant to the Entity spec), and XML descriptor files telling the mapping framework what to map. Figure 1 shows what these items look like.

Diagram.
Figure 1.

Abstract Entity Bean

The abstract entity has the following properties:

Implements javax.ejb.EntityBean.

abstract public class InventoryBean implements EntityBean {.

Implements methods declared in EntityBean interface:

public void setEntityContext(EntityContext context) {
   ctx = context;
}

public void unsetEntityContext() {
   ctx = null;
}

public void ejbActivate() {}

public void ejbPassivate() {}

public void ejbRemove() throws RemoveException {}

public void ejbStore() {}

public void ejbLoad() {}

Implements an ejbCreate() and an ejbPostCreate() method that corresponds to the create() method in the home interface (uses abstract set methods to set all incoming params):

public String ejbCreate(String item, float price, int stock) throws CreateException {
   setItem(item);
   setPrice(price);
   setStock(stock);
   return null;
}

public void ejbPostCreate(String item, float price, int stock) throws CreateException {}

Implements the abstract get and set methods:

public abstract String getItem();
public abstract void setItem(String item);

public abstract float getPrice();
public abstract void setPrice(float price);

public abstract int getStock();
public abstract void setStock(int stock);

Implements a helper method to get access to the entity context (this will be used in the BMP bean later):

public EntityContext getEntityContext() {
   return ctx;
}

EJB Deployment Descriptors

We have created a CMP-compliant entity bean class, and now it's time to create the deployment descriptors. First we create the "standard" ejb-jar.xml, and then we need to configure the vendor-specific information. We will show the WebLogic 6.1 deployment descriptors because we have to pick one.

Standard ejb-jar.xml

Configure basic entity information:

We configure the class names, using the "local" variants, which means that these are local entity beans. We tell the container that this entity is CMP via the persistence-type XML tag.

<entity>
  <ejb-name>InventoryBean</ejb-name>
  <local-home>InventoryHome</local-home>
  <local>Inventory>/local<
  <ejb-class>InventoryBean</ejb-class>
  <persistence-type>Container</persistence-type>
  <prim-key-class>java.lang.String</prim-key-class>
  <reentrant>False</reentrant>

Next, we tell the container which fields are to be managed, and that the item is the primary key:

  <cmp-field>
    <field-name>item</field-name>
  </cmp-field>
  <cmp-field>
    <field-name>price</field-name>
  </cmp-field>
  <cmp-field>
    <field-name>stock</field-name>
  </cmp-field>
  <primkey-field>item</primkey-field>

Finally, we configure the findAllPrices() method using EJB-QL:

  <query>
    <query-method>
      <method-name>findAllPrices</method-name>
      <method-params>
      </method-params>
    </query-method>
    <ejb-ql><![CDATA[WHERE 1=1]]></ejb-ql>
  </query>

Pages: 1, 2

Next Pagearrow