DevX HomePage

Creating Container-managed Entity Beans with JBoss

Entity JavaBeans that use container-managed persistence (CMP) are convenient, because they require so little custom code to achieve automatic persistence. But that convenience carries a price: beans using CMP are also ferociously complex to configure, and often difficult to debug. In this article, you will see how to create, configure, and deploy entity beans that use CMP and JBoss.
n Entity Bean is an Enterprise JavaBean (EJB) that represents a persistent object in a relational database. JBoss provides two methods of entity bean persistence, Bean Managed Persistence (BMP) and Container-Managed Persistence (CMP). With BMP, the entity bean developer must implement all the persistence logic. With CMP, the application server manages entity bean persistence; the developer provides interfaces and configuration.

Applications that use entity beans—particularly entity beans that use CMP— quickly become complex. Therefore, to describe the configuration process in detail without getting bogged down by code complexity, I designed the sample application for this article, JBlog, to be functional and illustrative, yet simple. I also wanted a timely example, which led to the idea of blogging. JBlog is a small blogger application that uses CMP entity beans to persist blog content.

What You Need
To build and run the sample JBlog application, you need JBoss 3.2.1, Java 2 SDK 1.4, Java 2 EE SDK 1.3, Ant 1.5, and JUnit 3.8.1.

JBlog's interface consists of two Web pages, one for viewing a blog and one for posting new entries. The interface uses two entity beans: Story for blog entries and Author for content authors. In the rest of this article, you'll see how to construct, configure, and persist those entity beans.

An entity bean using CMP has several interfaces, explained in the following sections. You don't have to implement all the interfaces for every CMP entity bean.

The Home Interface (optional)
External clients use an entity bean's home interface to create, remove, and find instances of the entity bean. You don't need to create a home interface if external clients will not use the bean directly. The home interface defines the following methods:

Both the entity beans in JBlog have home interfaces. To see the full code, look at the StoryHome.java and AuthorHome.java files in the JBlog source directory. The main page (index.jsp) uses the AuthorHome interface to find the author "bigt."

   // Create AuthorHome.
   AuthorHome authorHome = (AuthorHome) PortableRemoteObject.narrow(
      ctx.lookup("ejb/JBlog/Author"), AuthorHome.class);
   
   // Find author.
   Author author = authorHome.findByPrimaryKey("bigt");




The Remote Interface (optional)
External clients interact with an entity bean via its remote interface, which defines the entity bean's public business methods. If the entity bean will not be used by external clients, you don't need to create a remote interface.

Both of the entity beans in JBlog have remote interfaces. To see the code for them, look at Story.java and Author.java in the JBlog source directory. The main page uses Author to get an author's stories and Story to display a story.

   // Get an author's stories
   
   // Create AuthorHome and StoryHome.
   AuthorHome authorHome = (AuthorHome) PortableRemoteObject.narrow(
      ctx.lookup("ejb/JBlog/Author"), AuthorHome.class);
   StoryHome storyHome = (StoryHome) PortableRemoteObject.narrow(
      ctx.lookup("ejb/JBlog/Story"), StoryHome.class);
   
   // Find author and get stories.
   Author author = authorHome.findByPrimaryKey("bigt");
   Collection stories = author.getStoryKeys();
   <%
      // Display stories.
      for (Iterator i = stories.iterator(); i.hasNext(); ) {
         Integer key = (Integer) i.next();
         Story story = storyHome.findByPrimaryKey(key);
   %>
   <p>
   <font size="+2"><%= story.getTitle() %></font><br>
   <b>Posted <%= story.getPubDate() %></b><br>
   <%= story.getText() %>
   </p>
   ...
The posting page (post.jsp) uses Author to assign an author to a new story.

   // Assign author to new story
   
   // Find author.
   Author author = authorHome.findByPrimaryKey("bigt");
         
   // Create story.
   Story story = storyHome.create(request.getParameter("title"), 
      request.getParameter("text"), author);
The Local Home Interface (required)
Local clients—other components running in the same container as the entity bean—use the local home interface to create, remote, and find instances of an entity bean. Like the home interface, the local home interface defines create, remove, finder methods, and home methods. Additionally, the local home interface may define select methods, which are local query methods. You must create a local home interface for a CMP entity bean.

To see the code for the local home interfaces of JBlog's entity beans, look at the files AuthorLocalHome.java and StoryLocalHome.java in the JBlog source directory. These interfaces are referenced in the EJB jar descriptor and the JBoss CMP descriptor and are used by JBoss.

The Local Interface (required)
Local clients interact with an entity bean via its local interface, which defines the local business methods of the entity bean. You must create a local interface for a CMP entity bean.

To see the code for the local interfaces of JBlog's entity beans, look at the AuthorLocal.java and StoryLocal.java files in the JBlog source directory. These interfaces are referenced in the EJB jar descriptor and the JBoss CMP descriptor and are used by JBoss. Additionally, AuthorBean uses the StoryLocal interface to get a list of the primary keys of the author's stories.

   // Get primary keys of author's stories
   public Collection getStoryKeys() {
      Vector keys = new Vector();
      Collection stories = getStories();  // List of StoryLocal instances
   
      for (Iterator i = stories.iterator(); i.hasNext(); ) {
         StoryLocal storyLocal = (StoryLocal) i.next();
         keys.add(0, storyLocal.getPrimaryKey());
      }
   
      return keys;
   }
Similarly, StoryBean uses the AuthorLocal interface to assign an author to a story.

   // Assign author (local) to story
   // This method is called by the container after entity bean is created.
   public void ejbPostCreate(String title, String text, AuthorLocal author) {
      setAuthor(author);
   }





The Entity Bean Class
The entity bean class contains the entity bean logic. However, with CMP, the entity class is abstract, because many of the methods are defined in the class but implemented by the container. The entity bean class defines the following methods:

   public abstract void setName(String name)
   public abstract String getName()
To see the code for the entity bean classes in JBlog, look at AuthorBean.java and StoryBean.java in the JBlog source directory. AuthorBean and StoryBean are referenced in the EJB jar descriptor and the JBoss CMP descriptor.

The EJB Jar Descriptor
The EJB jar descriptor file, ejb-jar.xml, specifies deployment information for the EJBs in an EJB jar. For each entity bean, the descriptor must contain one <entity> child element in the <enterprise-beans> element. The <entity> element contains the following child elements:

EJB-QL is beyond the scope of this article. For more information on EJB-QL, see the EJB 2.0 specification.

JBlog's EJB jar descriptor contains two <entity> elements, one for Author (see Listing 1) and one for Story (see Listing 2).




Specifying Bean Relationships in the EJB Jar Descriptor File
With CMP 2.0, you can define relationships between entity beans in the EJB jar descriptor file rather than the entity bean code. Note, though, that you can define such relationships only for local interfaces. For each relationship, the EJB jar descriptor must contain one <ejb-relation> child element in the <relationships> element.

The <ejb-relation> element contains the following elements:

In turn, each <ejb-relationship-role> element contains elements that describe the relationship itself:

JBlog's EJB jar descriptor contains one element for the relationship Author-Story.

   // The Author-Story relation as specified in 
   // the EJB jar descriptor
   
   <ejb-relation>
      <ejb-relation-name>Author-Story</ejb-relation-name>
   
      <ejb-relationship-role> 
         <ejb-relationship-role-name>
            author-stories
         </ejb-relationship-role-name>
   
         <multiplicity>One</multiplicity> 
   
         <relationship-role-source>
            <ejb-name>Author</ejb-name> 
         </relationship-role-source> 
               
         <cmr-field>
         <cmr-field-name>stories</cmr-field-name> 
            <cmr-field-type>java.util.Collection</cmr-field-type> 
         </cmr-field>
      </ejb-relationship-role> 
   
      <ejb-relationship-role> 
         <ejb-relationship-role-name>
             stories-author
         </ejb-relationship-role-name>
               
         <multiplicity>Many</multiplicity> 
         <cascade-delete/>
               
         <relationship-role-source>   
            <ejb-name>Story</ejb-name> 
         </relationship-role-source> 
             
         <cmr-field>
            <cmr-field-name>author</cmr-field-name>
         </cmr-field> 
      </ejb-relationship-role> 
   </ejb-relation>





The JBoss CMP Descriptor File
The JBoss CMP descriptor file, jbosscmp-jdbc.xml, contains database and relationship mapping information for the entity beans in an EJB jar. For each entity defined in the EJB jar descriptor, the JBoss CMP descriptor must contain one <entity> child element in the <enterprise-beans> element. The <entity> element contains:

For each container managed field in the entity bean, the <entity> element must contain one <cmp-field>, which includes:

JBlog's JBoss CMP descriptor contains two <entity> elements, one for Author and one for Story.

   // Author entity element in JBoss CMP descriptor
   
   <entity>
      <ejb-name>Author</ejb-name>
      <table-name>author</table-name>
   
      <cmp-field>
         <field-name>username</field-name>
         <not-null/>
      </cmp-field>
      <cmp-field>
         <field-name>password</field-name>
         <not-null/>
      </cmp-field>
      <cmp-field>
         <field-name>name</field-name>
      </cmp-field>
   </entity>
   
   // Listing 10: Story entity element in JBoss CMP descriptor
   
   <entity>
      <ejb-name>Story</ejb-name>
      <table-name>story</table-name>
   
      <cmp-field>
         <field-name>storyId</field-name>
         <column-name>story_id</column-name>
         <not-null/>
      </cmp-field>
      <cmp-field>
         <field-name>pubDate</field-name>
         <column-name>pub_date</column-name>
         <not-null/>
      </cmp-field>
      <cmp-field>
         <field-name>title</field-name>
         <not-null/>
      </cmp-field>
      <cmp-field>
         <field-name>text</field-name>
         <not-null/>
      </cmp-field>
      <cmp-field>
         <field-name>username</field-name>
      </cmp-field>
   </entity>





Specifying Bean Relationships in the JBoss CMP Descriptor File
For each relationship defined in the EJB jar descriptor, the JBoss CMP descriptor must contain one <ejb-relation> child element in the <relationships> element. Each <ejb-relation> element can contain the following child elements:

Each <ejb-relationship-role> element contains:

JBlog's JBoss CMP descriptor contains one <ejb-relation> element for the relationship Author-Story.

   // The Author-Story relation element in JBoss CMP descriptor
   
   <ejb-relation>
      <ejb-relation-name>Author-Story</ejb-relation-name>
      <foreign-key-mapping/>
   
      <ejb-relationship-role> 
         <ejb-relationship-role-name>author-stories</ejb-relationship-role-name>
         <key-fields>
            <key-field>
               <!-- Note: Field in Author. -->
               <field-name>username</field-name>
               <!-- Note: Column in Story table. -->
               <column-name>username</column-name>
            </key-field>
         </key-fields>
      </ejb-relationship-role> 
   
      <ejb-relationship-role> 
         <ejb-relationship-role-name>stories-author</ejb-relationship-role-name>
         <key-fields/>
      </ejb-relationship-role> 
   </ejb-relation>
As you can see from the code and configuration file sections listed in this article, entity beans that use CMP don't require much code; however, to achieve that code simplicity, bean configuration is extremely complex (far too complex, in my opinion). To compound the problem, because so much of the substance of a bean lies in the configuration files rather than the code, many errors are undetectable until deployment or runtime; therefore, you can lose many hours searching through the JBoss server log for clues to the cause of the errors. When developing your own entity beans using CMP and JBoss, keep in mind that everything depends on correct configuration.

Thornton Rose is a contract developer with over twelve years of experience in a variety of programming languages, tools, and methodologies. He lives in Atlanta, GA, and is currently working at BellSouth as a technical lead. Visit his web site, or reach him via e-mail .


DevX is a division of Jupitermedia Corporation
© Copyright 2007 Jupitermedia Corporation. All Rights Reserved. Legal Notices