Java EJB EJB Design Guidelines

EJB Design Guidelines


This material is from the book JBuilder Developer’s Guide , written by Saleem Siddiqui, Michael Landy, and Jeff Swisher, published by Sams Publishing.

© Copyright Sams Publishing. All rights reserved.


Using entity beans is a practice that many users of application servers
do not want to venture into. Part of this is due to the lack of understanding;
the other part is due to the lack of capabilities in earlier versions
of the EJB specification. As we look at entity beans, keep in mind two
important considerations when designing the architecture:

  • Using local interfaces versus remote interfaces

  • Container managed persistence versus bean managed persistence

Use the Local Interface

When accessing data remotely, the result of the data has to be moved
from one location to another, thus, data has to be serialized. This
process of serialization is expensive. In other words, the latency of
serializing data, sending it over the wire, and rematerializing the
data on the client can be time consuming. With the introduction of EJB
2.0 specification, the capability to call and communicate to an entity
bean with a local interface was defined.

Inspiration

The inspiration of local interfaces is specifically to address the
performance issues related to serializing data. With the use of session
façades or the use of value objects, the need for network ubiquity
and serializing data has become less important. Without the need for
serialized data, an alternative was needed. This alternative is to pass
data by reference rather than value. In other words, instead of copying/
serializing the data, a reference to the data is passed.

Inner Workings

The inner workings of this change in the design are rather simple.
If the entity bean runs within the same process, you can access the
entity bean using its local interface and pass all data by reference
rather than value. There is a drawback to using this method of communication:
You lose the concept of network ubiquity. In other words, the client
needs to know the location of the bean you want to use, but you gain
what was lost in higher performance throughput.

Use CMP Before BMP

When I first started to use J2EE servers, the idea of letting the container
manage all the persistence for me seemed unsettling. So I found myself
developing persistence code. The process was neither desirable nor ultimately
a good, efficient process for developing large-scale applications. I
was developing huge portions of code that did nothing other than save,
read, and remove instances of data. They were virtually identical except
for the details of the SQL statements and member attributes.

Inspiration

With the changes in the EJB specification from 1.1 to 2.0, container
managed persistence became all the more important and powerful. Without
these necessary changes to the specifications, many developers found
that most uses of CMP were limited to simple persistence.

Inner Workings

Container managed persistence supports most of the persistence requirements
that any enterprise application needs. Using the container for accomplishing
these tasks is not only quicker to develop, but the performance is usually
better. If those two reasons are not enough, container managed persistence
is by far the most portable of the components within the J2EE architecture.

In Practice

The ChalkTalk application needs the capability to read and save data
to the database structure. We have read and written data to the database
using JDBC; now it is time to accomplish the same task using entity
beans. The process of building the beans is rather simple; most of our
work will be executed in the session facade.

Building the Persistence Layer

The creation of the persistence layer using JBuilder depends on the
appropriate data structure being completed. In Chapter 15, "Database
Connectivity," we created the necessary data store for our application.
We will now create the entity beans to manage this persistence. The
following steps are used to build the necessary entity beans:

  1. Import a schema from our data source in the EJB module containing
    our session beans. This is accomplished by right-clicking on the
    data source node when we are in the EJB Designer and selecting Import
    Schema from Datasource.

  2. Set the following database parameters:

    • Driver: com.borland.datastore.jdbc.DataStoreDriver

    • URL: jdbc:borland:dslocal:C:JBDGdbChalkTalk.jds

    • Username: leave blank

    • Password: leave blank

  3. Right-click on each table and create a CMP 2.0 entity bean for
    each table. For example, right click on the table Room and create
    a CMP 2.0 bean.

  4. Define relationships.

Configuring an Entity Bean

Typically each entity bean that has been created requires more finder
methods than just a findByPrimaryKey. Our Room entity
bean is a perfect example.

  1. Right-click on our Room entity bean. Add a finder method.

  2. Configure the following properties for the finder method:

    • Name: findAll

    • Return type: java.util.Collection

    • Input parameters: leave empty

    • Home interfaces: Local Home

    • Query: SELECT OBJECT(o) FROM RoomSchema AS o

  3. Compile and save.

Creating an EJB Connection Factory

This factory supplies caching to both local and remote interfaces.
Although this connection factory differentiates between local and remote
interfaces, you have the capability to make this interface ubiquitous.
The following steps build your EJB connection factory:

  1. Create a new class within your project, calling it EJBConnectionFactory.

  2. Move the newly created class to the package com.sams.chalktalk.beans.

  3. Add the following code to implement the connection to both local
    and remote beans in addition to placing them into a cache when the
    connection has been established:

  4. package com.sams.chalktalk.beans;
    
    import javax.naming.*;
    import java.util.*;
    import javax.ejb.*;
    
    class EJBHomeFactory {
    
     private static EJBHomeFactory instance = null;
     private Context initialContext;
     private Map ejbHomes;
    
     private EJBHomeFactory() throws NamingException {
      initialContext = new InitialContext();
      ejbHomes = Collections.synchronizedMap(new HashMap());
     }
    
     public static EJBHomeFactory getInstance() throws NamingException {
      if(instance == null) {
       instance = new EJBHomeFactory();
      }
      return instance;
     }
    
     public EJBLocalHome lookupByLocalEJBReference(String ejbReferenceComponent)
      throws NamingException {
    
      java.lang.Object home = ejbHomes.get(ejbReferenceComponent);
      if(home == null) {
       home = initialContext.lookup("java:comp/env/ejb/" + 
                      ejbReferenceComponent);
       ejbHomes.put(ejbReferenceComponent, home);
      }
      return (EJBLocalHome) home;
     }
    
     public EJBHome lookupByRemoteEJBReference(String ejbReferenceComponent, 
       Class homeClass)
      throws NamingException {
    
      java.lang.Object home = ejbHomes.get(ejbReferenceComponent);
      if(home == null) {
       java.lang.Object obj =
        initialContext.lookup("java:comp/env/ejb/" + ejbReferenceComponent);
       home = javax.rmi.PortableRemoteObject.narrow(obj, homeClass);
       ejbHomes.put(ejbReferenceComponent, home);
      }
      return (EJBHome) home;
     }
    }
  5. Compile and save your project.

Creating a Manager Bean

A manager bean surfaces the business logic and ultimately interfaces
to the persistence utilizing the entity beans. These manager beans will
then be attached to the session facade to consolidate the middle-tier
access. The following steps are required to create one of the manager
beans:

  1. Create a new class, naming the class RoomManager and placing
    the new class in the package com.sams.chalktalk.beans.

  2. The following code surfaces the required business logic. The requirements
    of the manager class are used to implement all the appropriate business
    logic, such as checking to make sure that a room has a capacity.

  3. package com.sams.chalktalk.beans;
    
    import javax.naming.*;
    import javax.ejb.*;
    import java.util.*;
    
    class RoomManager {
     //Add a home factory for caching the home interfaces
     private EJBHomeFactory homeFactory;
     private static RoomManager instance = null;
     
     //Use the RoomValueFactory to create
     private RoomValueFactory roomValueFactory;
    
     private RoomManager() throws NamingException {
      homeFactory = EJBHomeFactory.getInstance();
     }
    
     public static RoomManager getInstance() throws NamingException {
      if(instance == null) {
       instance = new RoomManager();
      }
      return instance;
     }
    
     public String createRoom(RoomValue roomValue)
       throws FinderException, NamingException {
    
      try {
       RoomHome roomHome =
         (RoomHome) homeFactory.lookupByLocalEJBReference("Room");
       Room room = roomHome.create(roomValue.getLocation(),roomValue. getCapacity()
    ,roomValue.getName(),roomValue.getKey());
       return room.getName();
      }
      catch(Exception e) {
       throw new EJBException(e);
      }
     }
    
     public void updateRoom(RoomValue roomValue)
       throws FinderException, NamingException {
    
      try {
       Room room = roomValueFactory.findRoom(roomValue.getKey());
       room.setCapacity(roomValue.getCapacity());
      }
      catch(Exception e) {
       throw new EJBException(e);
      }
     }
    
     public void removeRoom(Short key)
       throws FinderException, NamingException {
    
      try {
       Room room = roomValueFactory.findRoom(key);
       room.remove();
      }
      catch(Exception e) {
       throw new EJBException(e);
      }
     }
    
     public void removeAllRooms()
       throws FinderException, NamingException {
    
      try {
       Collection rooms = roomValueFactory.findAllRooms();
       Iterator iterator = rooms.iterator();
       Room room = null;
       while(iterator.hasNext()) {
        room = (Room) iterator.next();
        room.remove();
       }
      }
      catch(Exception e) {
       throw new EJBException(e);
      }
     }
    }

Attaching the Session Facade

Our session facade wraps multiple manager beans together into one session
bean. In other words, we will access all functionality for our ChalkTalk
system utilizing this one session bean. The following steps are required
to attach the facade to our manager bean:

  1. Define a private member for each type of bean manager you want
    to use. For example, the following code defines one for our RoomManager:

  2.  private RoomManager roomManager;
  3. Create an instance of our manager bean within ejbCreate().
    The following demonstrates the implementation using our RoomManager:

  4.  public void ejbCreate() throws CreateException {
      try {
       roomManager = RoomManager.getInstance();
      }
      catch (NamingException ex) {
       //pass exception to the container
       throw new EJBException(ex);
      }
  5. Attach the manager bean call to be called from the corresponding
    session bean method. If the client calls the createRoom
    method of the session bean, it then needs to pass the information
    to the manager class. The following code demonstrates such an implementation:

  6.  public void createRoom(RoomValue room) {
      try {
       roomManager.createRoom(room);
      }
      catch (Exception ex) {
        throw new EJBException(ex);
      }
     }
  7. Compile and save your project.

Testing the Implementation

It is time to test the client we created. The easiest way to test the
session facade is to build a client dedicated to testing the interface.
The following steps build a test client to exercise this facade:

  1. Select File, New from the JBuilder menu.

  2. Within the Object Gallery, under the Enterprise tab, select the
    EJB Test Client.

  3. Specify the following parameters to build our test client:

    • EJB name: ChalkTalkFacade

    • Package: com.sams.chalktalk.client

    • Class name: ChalkTalkFacadeTestClient

    • Generate Method for Testing Remote Interface Calls with Arguments:
      Checked

    • Generate Logging Messages: Checked

    • Generate Main Functions: Checked

    • Generate Header Comments: Checked

  4. Add the following code to the main method to test your
    session bean interface:

  5.   //create a Remote interface
      client.create();
    
      //Add a room
      client.addRoom(new RoomData(5,"Small Room",5,"2nd Floor"));
    
      //Add with invalid capacity
      client.addRoom(new RoomData(3,"Error Room",0,"3rd Floor"));
  6. Save, compile, and run your test application.

Summary

Using entity beans is a question for design, experience, need, and
implemented technology. Entity beans are designed to handle all the
persistence requirements for most enterprise applications. Entity beans,
like session beans, are designed to be distributed objects with the
following characteristics:

  • Entity beans provide persistence.

  • Entity beans are transactional.

  • Entity beans are multiuser.

  • Entity beans are long-lived.

  • Entity beans survive the life of the container.

The introduction of more advanced container managed persistence and
the other important features added to the EJB specification has made
building and ultimately managing an application much more efficient.

Reflections

  • Should I use container managed or bean managed persistence?

  • Should I design for use with local or remote interfaces?

  • Should entity beans be used to encapsulate nontraditional data
    access?

About the Authors

Saleem Siddiqui is a technical architect and trainer with Dunn Solutions Group. He is also a Sun Certified Developer and a Borland Certified JBuilder Instructor. At Dunn, he provides consulting services and business application development.

Michael Landy is Director of Business Applications for Dunn Solutions Group directing the strategic solutions for clients.

Jeff Swisher is a technical manager for the Dunn Solutions Group business applications. He works as a programmer, trainer, architect, and instructional designer. He is a Sun Certified Java Developer and a Borland Certified Instructor in JBuilder.

Source of this material

This material is from Chapter 23: Developing Entity Beans from the book JBuilder Developer’s Guide (ISBN: 0-672-32427-X) written by Saleem Siddiqui, Michael Landy, and Jeff Swisher, published by Sams Publishing.

To access the full Table of Contents for the book.


Other Chapters from Sams Publishing:

Web Services and Flows (WSFL)

Overview of JXTA

Introduction to EJBs

Processing Speech with Java

The Java Database Control in BEA Weblogic

Databases and Tomcat

Working with JAX-RPC

Understanding Servlets


Latest Posts

Related Stories