J2EE Design Patterns: CMP-to-BMP Pattern

J2EE Design Patterns: CMP-to-BMP Pattern

Vendor Specific: weblogic-ejb-jar.xml:

We define the vendor-specific information first in the weblogic-ejb-jar.xml. Here we tell the server where to place the home stub in JNDI, and where to look for the CMP mapping.



Persistence Mapping Info:


<persistence-type>

  <type-identifier>WebLogic_CMP_RDBMS</type-identifier>

  <type-version>6.0</type-version>

  <type-storage>META-INF/weblogic-cmp-rdbms-jar.xml</type-storage>

</persistence-type>

Local JNDI Name:

<local-jndi-name>InventoryHome</local-jndi-name>

Vendor Specific: weblogic-cmp-rdbms-jar.xml

Datasource name:

(This datasource has to be created in the server configuration!)

<data-source-name>InventoryDB</data-source-name>

Table name:

<table-name>inventory</table-name>

Field mapping:

<field-map>

  <cmp-field>stock</cmp-field>

  <dbms-column>stock</dbms-column>

</field-map>

<field-map>

  <cmp-field>item</cmp-field>

  <dbms-column>item</dbms-column>

</field-map>

<field-map>

  <cmp-field>price</cmp-field>

  <dbms-column>price</dbms-column>

</field-map>

Now we have everything that we need. The container will take the abstract class and the deployment information to get everything working.

For some reason, we may want to take this CMP bean and migrate it to BMP. A few reasons why we would want to do this are:

  • Portability: Currently, it only works on WebLogic 6.1, and we don't want to learn all of the other tools. This is common if we want to sell this DB component -- it should run on any server.
  • Performance: If we wanted to fine tune the SQL that we use (e.g. use stored procedures, join across tables, etc.)
  • Alternate data sources: If we wanted to access a different data source, instead of a RDBMS.

Migrating the Bean to Use BMP

Here is where the pattern kicks in. We can migrate to BMP by "becoming the persistence manager." We saw that the persistence manager extends the abstract class that we created, where it implements the abstract methods and "does its stuff." We can do the same thing! The design will end up looking like Figure 2:

Diagram.
Figure 2. BMP design.

BMP Entity Bean

Let's walk through the bean class that will become the BMP bean.

Extend the abstract CMP bean class:

public class InventoryBeanBMP extends InventoryBean {

Create fields that hold the mapping:

public String item;

public float  price;

public int    stock;

Override the ejb*() methods:

To override the EJB methods, we need to remember what our responsibility is for each method in the BMP world.

EJB Method Responsibility
ejbLoad() Load the data from the database (SELECT)
ejbStore() Update the data back to the database (UPDATE)
ejbRemove() Delete the data from the database (DELETE)
ejbCreate() Insert a new row (INSERT)
ejbFindByPrimaryKey(primary key) Make sure the primary key exists
ejbFindAllPrices() Return a collection of primary keys for each item

Most of the methods look the same, so let's look at one of them (you can see the rest in the code download):

public String ejbCreate(String item, float price, int stock) throws CreateException {

   // insert row into database

   this.item  = item;

   this.price = price;

   this.stock = stock;



   // Insert database record

   try {

     Connection connection = getConnection();

     PreparedStatement statement = connection.prepareStatement

      ("INSERT INTO inventory (item, price, stock) VALUES (?, ?, ?)");

     statement.setString(1, item);

     statement.setFloat(2, price);

     statement.setInt(3, stock);

     if (statement.executeUpdate() != 1) {

      statement.close();

      connection.close();

      throw new CreateException("Could not create: " + item);

     }

     statement.close();

     connection.close();

     return item;

   }

   catch(SQLException e) {

     throw new EJBException("Could not create: " + item, e);

   }

}

Implement get and set methods:

public String getItem() {

   return this.item;

}

public void setItem(String item) {

   this.item = item;

}



public float getPrice() {

   return this.price;

}

public void setPrice(float price) {

   this.price = price;

}



public int getStock() {

   return this.stock;

}

public void setStock(int stock) {

   this.stock = stock;

}

Helper function to get a JDBC connection:

private Connection getConnection() throws SQLException {

   DataSource ds = null;



   try {

      Context ctx = new InitialContext();

      ds = (DataSource) ctx.lookup ("java:comp/env/jdbc/InventoryDB") ;

   } catch (NamingException exp) {

      exp.printStackTrace() ;

   }



   return (ds == null) ? null : ds.getConnection();

}

EJB Deployment Descriptors:

Standard ejb-jar.xml

Change settings from CMP:

The class points to the BMP class, not the abstract class, and we let the container know that we are managing the persistence:

<ejb-class>InventoryBeanBMP</ejb-class>

<persistence-type>Bean</persistence-type>

Add reference to JDBC data source: (used in getConnection() method above)

<resource-ref>

  <res-ref-name>jdbc/InventoryDB</res-ref-name>

  <res-type>javax.sql.DataSource</res-type>

  <res-auth>Container</res-auth>

</resource-ref>

Vendor Specific: weblogic-ejb-jar.xml

We don't have to do much with the vendor-specific files, as we did in the CMP version. We just need to point to the local JNDI name (same as before), and point the datasource to the real location, which is configured in the app server.

<reference-descriptor>

  <resource-description>

    <res-ref-name>jdbc/InventoryDB</res-ref-name>

    <jndi-name>inventoryDB</jndi-name>

  </resource-description>

</reference-descriptor>

And there we have it. We have reused the abstract class, overridden it to do the BMP implementation that we need, and then tweaked the deployment descriptors.

Conclusion

We have investigated a pattern that allows us to switch between CMP and BMP implementations in a nice clean manner. Our BMP implementation simply extends the CMP abstract bean class, and does the work! Notice that we could put in some logic in the get/set methods to make sure that we didn't do anything in ejbStore(), or did a tuned query. I still recommend that CMP beans be used when possible, and BMP used as a last resort.

Notes on Running the Sample Application

You can download the code for this sample pattern. There are two code sets, BMP and CMP (under directories of that name). A sample build script is provided (build.cmd) for compiling and deploying to BEA WebLogic 6.1. You may need to change a few directory paths in that script to get it working. To test the application, run the client via javac PricerClient. Check out the README.txt file for more information (setting up database table, etc.).

Dion Almaer is a Principal Technologist for The Middleware Company, and Chief Architect of TheServerSide.Com J2EE Community.


Return to ONJava.com.

Prev  [1] [2] 

Close    To Top
  • Prev Article-Java:
  • Next Article-Java:
  • Now: Tutorial for Web and Software Design > Java > Java Basic > Java Content
    Photoshop Tutorial
     

    Special Effect

      3D Effect
      Photoshop Articles
    Programming Tutorial
     

    C/C++ Tutorial

      Visual Basic
      C# Tutorial
    Database Tutorial
     

    MySQL Tutorial

      MS SQL Tutorial
      Oracle Tutorial
    Geek Tutorial
     

    Blogging Tutorial

      RSS Tutorial
      Podcasting Tutorial
    Graphic Design Tutorial
      Coreldraw Tutorial
      Illustrator Tutorial
      3D Tutorials
    Webmaster Articles
     

    Domain Service

      Web Hosting
      Site Promotion
    Java Tutorial/ Articles
     

    Java Servlets

      JavaEE Tutorial
     

    JavaBeans Tutorial

    XML Tutorial/ Articles
     

    XML Style

      AJAX Tutorial
      XML Mobile
    Flash Tutorial/ Articles
     

    Flash Video

      Action Script
      Flash Articles
    OS Tutorial/ Articles
      Linux Tutorial
      Symbian Tutorial
      MacOS Tutorial
    Personal Tech
      Hardware Tutorial
      Software Tutorial
      Online Auction