HomeDigital EditionSys-Con RadioSearch Java Cd
Advanced Java AWT Book Reviews/Excerpts Client Server Corba Editorials Embedded Java Enterprise Java IDE's Industry Watch Integration Interviews Java Applet Java & Databases Java & Web Services Java Fundamentals Java Native Interface Java Servlets Java Beans J2ME Libraries .NET Object Orientation Observations/IMHO Product Reviews Scalability & Performance Security Server Side Source Code Straight Talking Swing Threads Using Java with others Wireless XML

As the EJB 2.0 specification has entered its final stage, many companies are in the process of building server-side J2EE applications. The final draft of the specification has made container-managed persistence (CMP) of entity beans complete and more powerful.

Significant changes that were made to the specification in the area of entity beans include:

  • Local entity beans are lightweight entity beans that exist only locally, inside the EJB container, and therefore don't need to be marshaled.
  • EJB QL helps create specialized queries declaratively.
  • Declarative entity bean relationships have been added.
  • Dependent object classes were removed from the latest draft in favor of local entity beans.
These features are essential for real-life applications. Another exciting development is that the latest version of BEA WebLogic application server supports the draft specification in all of the preceding features. In this article I will go through an example application to demonstrate local entity beans and entity bean relationships; namely, a many-to-many relationship. I'll also create deployment descriptors for BEA WebLogic Application Server 6.1 and write a build-script to generate a deployable archive.

Remote entity beans encapsulate coarse-grained persistent objects, whereas local entity beans target fine-grained persistent objects. Local entity beans differ from remote entity beans in this manner:

  • The bean interface extends javax. ejb.EJBLocalObject; the home interface extends javax.ejb.EJBLocalHome.
  • The bean is never transmitted over the network. Thus its methods will not throw a java.rmi.RemoteException.
  • The bean is collocated in the same JVM and its method parameters are passed by reference.
Although the last item exposes the implementation details about the object, this optimization is well deserved. Indeed, it's only logical that some objects are never accessed remotely and therefore shouldn't incur the overhead associated with the remote call. Often the local entity bean may be accessed through a facade session bean. In this case the remote clients will pass value objects to the facade session bean. This bean will then perform business logic that may involve other session beans and entity beans. The facade bean will call the local entity beans when the data needs to be persisted. (More about this later.)

Another important feature of CMP is declarative entity bean relationships. The specification allows a declaration of the following things about a relationship:

  • Cardinality: One-to-one, one-to-many, and many-to-many relationships are supported.
  • Direction: Unidirectional and bidirectional relationships are supported.
  • Cascade deletes: If a relationship is marked for cascade delete, the dependent entity beans are removed when the main entity bean is removed.
You still have to provide abstract get and set methods in the bean class to reflect cardinality and direction. For example, if an Order bean has many Order Line Items, then you must provide abstract getLineItems and setLineItems methods in the Order class to specify a unidirectional, one-to-many relationship.

How It's Done
Let's write a small application that utilizes local entity beans and relationships. My example will run on BEA WebLogic 6.1 Server and an Oracle database. I'll have two entity beans - User and Group. User can belong to multiple groups and a Group can have multiple users. Both beans are local entity beans and have two session facade beans: UserManager and GroupManager. I also want to navigate in both directions. Thus our entity beans have a many-to-many, bidirectional relationship. Additionally, I'll have two value objects that are sent to clients by the facade beans: UserValueObject and Group- ValueObjects. The value objects allow clients to cache and use objects multiple times without remote calls. Figure 1 illustrates the classes.

In Figure 1 the entity beans' interfaces extend javax.ejb.EJBLocalObject and the entity beans' home interfaces extend the javax.ejb.EJBLocalHome interface. Another important aspect is that the value object must implement the java.io.Serializable interface for it to be sent over the network.

Figure 1
Figure  1:

The entity beans have abstract get and set methods for all fields that need to be persisted. The business logic to create, update, and delete the entity beans resides in the facade session beans. Here's how the User Manager bean creates a User in the createUser method:

InitialContext ctx = new InitialContext();
UserBeanHome home = (UserBeanHome)ctx.lookup("User");
UserBean bean = home.create(user.getUserName());
The Group Manager bean is responsible for adding and removing Users from Groups. Adding a User to a Group is as simple as adding a user bean to a collection. This is done in the addUserToGroup method. I had to declare this method to require a transaction in the ejb-jar.file because the collection must be retrieved and altered in the same transaction.

UserBean userBean = userHome.findByPrimaryKey(userName);
GroupBean groupBean = home.findByPrimaryKey(groupName);
Collection users = groupBean.getUsers();
users.add(userBean);
Once I have the classes, I can write the deployment descriptors. First I write ejb-jar.xml the same as for any EJB container. Listing 1 describes a Group-User relationship.

Ejb-jar.xml descriptor declares the entity beans and relationships, whereas the actual mapping-to-storage mechanism is done in the EJB container-specific deployment descriptors. BEA WebLogic 6.1 uses two files for that purpose. The first file, weblogic-ejb-jar.xml, specifies a persistence descriptor as a part of the Weblogic-enterprise-bean element. It also specifies the name of the second descriptor file where the field mapping is done. Listing 2 shows the complete Weblogic enterprise bean element.

I specify how the fields are mapped to the table columns in the other WebLogic descriptor, weblogic-cmp-rdbms-jar.xml. I also specify how the Group-User relationship is mapped to the database through a USER_GROUP table. Listing 3 shows the relationship portion.

Once I've written the deployment descriptors and implemented the beans, I write a build script to build my application. Since EJB applications have a lot of different pieces to them, it's a good idea to create a build script as soon as the skeleton of the project is in place. I use a utility Ant to do all my builds. Ant can create directories, move files, compile, jar, and deploy your J2EE application. It can even create database schema and run unit tests for you.

Another good thing about Ant is that the scripts are written in XML, which seems quite natural since we spent all this time with XML writing the deployment descriptors. WebLogic Server 6.1 comes with a number of examples that have Ant build scripts and can serve as templates. Listing 4 shows the fragment of the Ant script that calls the WebLogic ejb compiler to create a final deployable .jar file for our beans.

Finally, I copy the output .jar file to the WebLogic applications directory and run the Java client. The client creates the UserManager session bean and calls UserManager to create a User, passing a User value object (see Listing 5). Groups are created in a similar way. After a Group is created, I can add a User to it with just one call.

groupManager.addUserToGroup("alex", "testgroup");

Under the hood, the container inserts a row in the table USER_GROUP that points to tables SYSUSER and SYSGROUP connecting them.

When testing my applications on WebLogic 6.1 I used a utility P6Spy available from Provision6 (www.provision6.com/) to analyze the SQL generated by the container. P6Spy driver is configured to log all SQL statements before they get to the real JDBC driver.

One thing I'd see from the SQL log is that for every get method called on an entity bean, the container generates a SELECT statement. To improve that you can use different concurrent strategy flags in the WebLogic descriptor. For example, if you set concurrency strategy to be Exclusive, then the SELECT statement is issued only once, the first time the bean is loaded. The assumption here is that all updates are going through the bean, so the bean doesn't have to be synchronized with the database for every get method. (See WebLogic documentation for more on other concurrent strategy flags and entity bean optimization.)

Similarly, for every set method on the entity bean, the container issues an UPDATE statement. The reason is that every set method is performed in a new transaction, and at the end of each transaction the container commits the data to storage. Again, we can improve that if all set methods are called in the same transaction. Since they're called inside the facade session bean, we can mark the bean to require a transaction in the ejb-jar.xml deployment descriptor. Further optimizations are possible as required by a specific application.

Entity beans separate business logic from persistence code. Local entity beans cover the area of fine-grained objects making necessary syntactical changes to optimize performance. Declarative relationships take another step to abstract object developers from the database schema.

These features of CMP have the potential to increase the productivity of the enterprise application developers. The situation will further improve once EJB container vendors create or improve graphical tools to write deployment descriptors for CMP and relationships. For now the example deployment descriptors given in this article can help you get started.

For More Information
1. EJB 2 Proposed Final Draft 2: http://java.sun.com/products/ejb/docs.html
2. BEA Weblogic Server Release 6.1 Documentation: http://e-docs.bea.com/wls/docs61/index.html
3. Jakarta Ant Project: http://jakarta.apache.org/ant/
4. P6Spy Driver: www.provision6.com/index.htm

Author Bio
Alex Pestrikov, a programmer for more than five years, has spent the last three years working on Java projects. He currently writes J2EE applications for the Middleware Lab, government of Ontario, Canada. Alex holds a degree in finance and computer science from the University of Bridgeport (Connecticut), and is a master's candidate in computer science. [email protected]

	



Listing 1: ejb-jar.xml

<relationships> 
   <ejb-relation> 
     <ejb-relation-name>Group-User</ejb-relation-name> 
       <ejb-relationship-role> 
         <ejb-relationship-role-name> 
           group-has-users 
          </ejb-relationship-role-name> 
          <multiplicity>many</multiplicity> 
          <relationship-role-source> 
            <ejb-name>Group</ejb-name>
          </relationship-role-source> 
          <cmr-field> 

    <!-- method to retrieve users 
    is java.util.Collection getUsers() --> 

          <cmr-field-name>users</cmr-field-name> 

    <!-- you can specify java.util.Set or java.util.
    Collection if multiplicity is many. 
    You do not have to provide this element if multiplicity is one --> 

          <cmr-field-type>java.util.Collection</cmr-field-type> 
          </cmr-field> 
          </ejb-relationship-role> 

       <ejb-relationship-role>
         <ejb-relationship-role-name> 
           user-belongs-to-group 
         </ejb-relationship-role-name> 
         <multiplicity>many</multiplicity> 
         <relationship-role-source> 
         <ejb-name>User</ejb-name> 
         </relationship-role-source> 
           <cmr-field> 
             <cmr-field-name>groups</cmr-field-name> 
             <cmr-field-type> 
               java.util.Collection 
             </cmr-field-type> 
           </cmr-field> 
       </ejb-relationship-role> 
   </ejb-relation> 
</relationships> 


 2: weblogic-ejb-jar.xml

<weblogic-enterprise-bean> 
   <ejb-name>User</ejb-name>
     <entity-descriptor> 
       <persistence> 
          <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> 
          <persistence-use> 
            <type-identifier> 
                WebLogic_CMP_RDBMS 
             </type-identifier> 
             <type-version>6.0</type-version> 
          </persistence-use> 
       </persistence> 
    </entity-descriptor> 
    <local-jndi-name>User</local-jndi-name> 
</weblogic-enterprise-bean> 


Listing 3: weblogic-cmp-rdbms-jar.xml 

<weblogic-rdbms-relation> 
    <relation-name>Group-User</relation-name> 
     <table-name>USER_GROUP</table-name> 
     <weblogic-relationship-role> 
        <relationship-role-name> 
           group-has-users 
        </relationship-role-name> 
        <column-map> 

          <!-- column from USER_GROUP table> 
          <foreign-key-column> 
             GROUPNAME 
          </foreign-key-column> 

          <!-- column from SYSUSER table>
          <key-column>GROUPNAME</key-column> 
        </column-map> 
     </weblogic-relationship-role> 
     <weblogic-relationship-role> 
        <relationship-role-name> 
            user-belongs-to-group 
        </relationship-role-name> 
        <column-map> 

          <!-- column from USER_GROUP table --> 
          <foreign-key-column> 
              USERNAME 
          </foreign-key-column> 

          <!-- column from SYSGROUP table --> 
          <key-column>USERNAME</key-column> 
        </column-map> 
     </weblogic-relationship-role> 
</weblogic-rdbms-relation> 


Listing 4: Ant build script 

  <!-- Run ejbc to create the deployable jar file --> 
   <target name="ejbc" depends="jar_ejb"> 
     <java classname="weblogic.ejbc" fork="yes"> 
       <sysproperty key="weblogic.home" value="${WL_HOME}"/> 
       <arg line="-compiler javac ${dist}/user_in.jar ./user_out.jar"/> 
       <classpath> 
         <pathelement path="${WL_HOME}/lib/weblogic.jar"/> 
       </classpath> 
     </java> 
   </target> 


Listing 5: Client 

InitialContext ic = new InitialContext();
Object objRef = ic.lookup( "UserManager" ); 
UserManagerHome home = (UserManagerHome) 
PortableRemoteObject.narrow( objRef, UserManagerHome.class ); 
UserManager userManager = home.create(); 

User user = new UserValueObject(); 
user.setUserName("alex"); 
user.setUserType("regular"); 
user.setUserEmail("[email protected]"); 
userManager.createUser(user);

  
 

All Rights Reserved
Copyright ©  2004 SYS-CON Media, Inc.
  E-mail: [email protected]

Java and Java-based marks are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries. SYS-CON Publications, Inc. is independent of Sun Microsystems, Inc.