Sun Java Solaris Communities My SDN Account Join SDN
 
Enterprise Java Technologies Tech Tips

EJB 3.0 Compatibility and Migration, and Using an EJB Session Bean as a Model Facade

 
In this issue

Welcome to the Enterprise Java Technologies Tech Tips for February 24, 2007. Here you'll get tips on using enterprise Java technologies and APIs, such as those in Java Platform, Enterprise Edition (Java EE).

This issue covers:

These tips were developed using the Java EE 5 SDK. You can download the SDK from the Java EE Downloads page .

You can download the sample archive for the tip EJB 3.0 - EJB 2.x Interoperability.

You can download the sample archive for the tip Using an EJB Session Bean as a Model Facade.

Any use of this code and/or information below is subject to the license terms.

 
EJB 3.0 Compatibility and Migration
By Ken Saks  

The Enterprise JavaBeans (EJB) 3.0 specification introduced a new, vastly simpler, API for implementing and accessing session beans. Many developers have questions about how applications written to this new API can interact with legacy EJB applications, or how legacy applications can interact with the new API.

It would be impractical to require developers to entirely rewrite all existing EJB applications in order to take advantage of any of the new capabilities. In some cases, developers plan to upgrade their applications, but would prefer to do it using a phased approach. In other cases they prefer to write new EJB 3.0 applications, but would still like to take advantage of their existing application's services. The EJB 3.0 specification makes both of these strategies possible. This tip explains how.

A sample application package accompanies the tip. The code examples in the tip are taken from the source code of the sample (which is included in the package). The sample uses the Java EE 5 SDK. You can download the Java EE 5 SDK from the Java EE Downloads page

EJB 3.0-to-EJB 2.x Compatibility

Let's first look at an example of an application written to the simplified EJB 3.0 API calling a legacy EJB application. In the source code for the sample that accompanies this tip you'll find an EJB 3.0 stateless session bean named MigrationBean. The bean invokes a remote EJB 2.x stateless session bean named EJB2xBean. MigrationBean could either be an entirely new bean or an existing bean that was recoded to use the EJB 3.0 API. For simplicity both beans in this example are packaged in the same archive, but that is not required. Here are the EJB 2.x home and remote interfaces for EJB2xBean:


   public interface EJB2xHome extends EJBHome {

       public EJB2xRemote create()
           throws CreateException, RemoteException;
   }

   public interface EJB2xRemote extends EJBObject {

       public void foo() throws RemoteException;

   }
   
Here is the first part of the MigrationBean class:

   @Stateless
   public class MigrationBean implements MigrationRemote {

       // Inject a reference to the Home interface 
       // of the EJB 2.x bean.
       @EJB private EJB2xHome ejb2xHome;

       private EJB2xRemote ejb2x;   

MigrationBean uses the @EJB annotation to inject a reference to EJB2xHome. The @EJB annotation was introduced as part of the EJB 3.0 specification. However, it was designed to be used with the older-style EJB 2.x home view in addition to the EJB 3.0 business interface view. Whenever the EJB container instantiates MigrationBean, it injects a reference to EJB2xHome in the ejb2xHome data member.

An important benefit of using the @EJB annotation with a 2.x home interface is that it frees you from having to use PortableRemoteObject.narrow(). The PortableRemoteObject.narrow() method is used to cast to the correct type the Object returned when you lookup the home interface. In EJB 3.0 the injected home reference can be used without any special casting.

The MigrationBean class defines a @PostConstruct method that uses the home reference to create an EJB2xRemote reference. The class then stores the result in another data member.

    @PostConstruct
    private void initialization() {
        try {
            ejb2x = ejb2xHome.create();
        } catch(Exception e) {
            throw new EJBException(e);
        }
    }
    
In the last part of the class, MigrationBean invokes the EJB2x business method within its own business method.

    public void bar() {

      try {
          // Call operation on legacy EJB.
          ejb2x.foo();
      } catch(Exception e) {
          throw new EJBException(e);

      }
    }    

All standard EJB services such as security and transaction propagation work as expected between the two beans.

Note that using an @EJB annotation to access EJB 2.x beans is not limited to EJB components. You can use the same approach to access a legacy bean from other types of components in a Java EE 5 application, such as a servlet or an application client. Also, even though this example used a remote EJB 2.x bean, you can use the approach to access a local EJB 2.x bean as well.

EJB 2.x-to-EJB 3.0 Compatibility

In the first example, you saw how an EJB component written using the new EJB 3.0 API could be a client of a legacy EJB component. Now let's look at the reverse case. Here you'll see how a legacy component that is coded using the EJB 2.x client API can access a session bean that is implemented using the EJB 3.0 simplified API. The idea here is to use the new EJB without making any changes to the existing EJB client code.

In this second example, a stateful session bean named AdaptedBean is implemented using the simplified EJB 3.0 API. The bean exposes a 2.x remote home interface to a standalone Java client. Here are the home and remote interfaces for AdaptedBean:

   public interface AdaptedHome extends EJBHome {

       public AdaptedRemote create(String id)
           throws CreateException, RemoteException;
   }

   public interface AdaptedRemote extends EJBObject {

       public String getId() throws RemoteException;
   }
   
Here is the AdaptedBean class :

   @Stateful
   @RemoteHome(AdaptedHome.class)
   public class AdaptedBean {

       private String myId = "unknown";

       @Init
       public void create(String id) {
           myId = id;
       }

       public String getId() {
           return myId;
       }

   }   

Notice that the bean class is implemented using the POJO-like simplifications of EJB 3.0. However, it uses the @RemoteHome annotation to exposes an EJB 2.x style remote home interface. This annotation tells the EJB container that the bean has a home interface named AdaptedHome and a remote interface named AdaptedRemote. You don't need a separate annotation to specify the AdaptedRemote interface. That's because the container can derive it from the signature of the AdaptedHome's create() method. If the bean exposed a local home interface, it would use the @LocalHome annotation instead.

The other important annotation in the class is @Init. The EJB 2.x view always defines a create method, so you must define a method on the bean class to handle the create operation. The @Init annotation tells the EJB container which method that is. The method can have any name, but its method parameters must match the create method in the corresponding home interface.

Here is the standalone client code for accessing AdaptedBean:

   try {

        InitialContext ic = new InitialContext();
        Object o = ic.lookup(AdaptedHome.class.getName());

        AdaptedHome adaptedHome = (AdaptedHome)
            PortableRemoteObject.narrow(o, AdaptedHome.class);

        AdaptedRemote adapted = adaptedHome.create("duke");

        System.out.println("Adapted id = " + adapted.getId());

   } catch(Exception e) { ... }
   

Notice that the client code uses the standard EJB 2.x client programming model. It does not need to know that the target bean is implemented with EJB 3.0.

Running the Sample Code

A sample package accompanies this tip. To install and run the sample:

  1. If you haven't already done so, download the Java EE 5 SDK from the Java EE Downloads Page. Also be sure to have an installed version of the Java Platform Standard Edition (Java SE) 5 SDK.

  2. Download the sample package for the tip and extract its contents. You should now see the newly extracted directory as <sample_install_dir>/ttfeb2007ejbmigration, where <sample_install_dir> is the directory where you installed the sample package. For example, if you extracted the contents to C:\ on a Windows machine, then your newly created directory should be at C:\ttfeb2007ejbmigration. Below this directory you should see two subdirectories: Migration and Adapted.

  3. To build and run the EJB 3.0-to-EJB 2.x compatibility example, change to the Migration directory. To build and run the EJB 2.x-to-EJB 3.0 compatibility example, change to the Adapted directory. Then set the javaee.home location attribute in the build.xml file in the selected directory to the directory in which you installed the Java EE 5 application server.

  4. Start the application server by entering the following command:

       <appserv_install>/bin/asadmin start-domain domain1
          
    where <appsrv_install> is where you installed the Java EE 5 application server.

  5. Enter the command:

        ant all

    This builds the sample application then deploys and executes it.

    You should see the following in the output for the EJB 3.0-to-EJB 2.x compatibility example :

            runappclient:
              [exec] Successfully called EJB 3.0 bean

    You should see the following in the output for the EJB 2.x-to-EJB 3.0 compatibility example:

            runjavaclient:
              [java] Adapted id = duke

    The application is then automatically undeployed and its build resources erased.

Summary

The EJB 3.0 specification greatly simplifies the session bean API. But it does so with the understanding that there is a large investment in EJB applications built with earlier versions of the specification. For this reason, a goal of EJB 3.0 is to ensure smooth interoperability between new and existing applications. If you are a developer using EJB 3.0, you have a lot flexibility in deciding whether to migrate legacy applications to the new API or to take advantage of those legacy applications from new components.

About the Author

Ken Saks is the lead architect for the EJB 3.0 container in the Java EE 5 SDK. He has been a member of the Enterprise Java group at Sun Microsystems since 1999.

Using an EJB Session Bean as a Model Facade
By Sean Brydon and Yutaka Yoshida  

The November 18, 2006 Tech Tip Using a Model Facade discussed some of the things that can lead to complexity when you use the Java Persistence API to manage persistence in the domain model of your Java EE 5 applications. The tip showed how a Model Facade (or simply a "Facade") can reduce that complexity.

As an example, the tip showed a servlet interacting with a Facade that is implemented as a web tier component. In this tip you'll see how a Facade can be implemented as an Enterprise JavaBeans (EJB) technology session bean.

Why Use a Session Bean as a Model Facade?

Implementing a Facade as a web component is a good approach if you want to have a web-only architecture and you don't want to use an EJB container. However there are distinct advantages to using an EJB container. For example, an EJB container provides services such as support for container-managed transactions. You can leverage that support if you implement a Facade as a session bean. In that case, the EJB container manages the transactions freeing you from having to include code to manage the transactions.

An Example Facade

In this example a servlet interacts with a Facade that is implemented as a session bean. If you're familiar with EJB 3.0 technology, you know that a session bean requires a business interface that provides the client view of the bean. It's the business interface that the servlet uses to access the Facade.

Here's what the business interface for the Facade in the example looks like:

   import java.util.List;

   import com.sun.javaee.blueprints.sessionfacade.InvalidItemException;
   import com.sun.javaee.blueprints.sessionfacade.model.Item;

   public interface CatalogFacade {
       public void addItem(Item item)throws InvalidItemException;
       public Item getItem(int itemID);
       public List<Item> getAllItems();
   }

You can find the source code for the business interface as well as for the other code examples in this tip in the sample application package that accompanies the tip.

Notice that interface is quite simple. However, despite this simplicity, the interface contains all the information that the client servlet needs to access the model tier of this web application. Also notice that like any EJB 3.0 business interface it does not need to import EJB package-specific classes. This simplicity is a key benefit of using a Facade. All the client web components that need to access model tier objects go through the Facade. The Facade encapsulates any details about the Java Persistence APIs or Java Transaction APIs that might be involved in managing the persistence objects.

Now let's look at the Facade.

   @Stateless
   public class CatalogFacadeBean implements CatalogFacade {  
   
     @PersistenceContext(unitName="CatalogPu")
     private EntityManager em;
   
     public void addItem(Item item) throws 
             InvalidItemException {
       if(item.getName().length() == 0)
         throw new InvalidItemException("The item" +
           " name cannot be empty." +
           " Please specify a name for the item. ");
       em.persist(item);
     }
   
     public Item getItem(int itemID) {
       Item item =  em.find(Item.class,itemID);
       return item;
     }
   
     public List<Item> getAllItems() {
       List<Item> items = em.createQuery(
               "SELECT OBJECT(i) FROM Item i").getResultList();  
       return items;
     }
   }

There are a number of things to notice in the Facade:

  • It is stateless. The @Stateless annotation marks CatalogFacadeBean as a stateless session bean. If you need to maintain session state between client web requests, you can use a stateful session bean for the Facade or store the state somewhere else, such as in an HttpSession on the web tier. In general, stateless session beans are more commonly used to implement a Facade in Java EE 5 applications.

  • It is local. A stateless session bean can be either a local or remote object. In this example, there is no need for remote access or RMI-IIOP access, so the session bean is local. Stateless session beans are local by default so there is no need to specify an annotation that it is local.

  • It uses container-managed transactions. There is no code in CatalogFacadeBean to demarcate transactions. The session bean uses the container-managed transaction services of the EJB container. If instead of using container-managed transaction services, the session bean used application-managed transactions, you would need to include calls to Java Transaction APIs to mark the boundaries of each transaction.

  • It relies on default transaction behavior. By default, each method of the Facade executes in a transaction that is managed by the container. You could also get this behavior by specifying the @TransactionAttribute annotation with the value "REQUIRED" or you can specify the behavior in a deployment descriptor.

  • It takes advantage of container-managed entity managers, where the EJB container manages the lifecycle of the entity managers. The @PersistenceContext annotation tells the EJB container to inject an EntityManager object into the session bean. If the bean used application-managed entity managers, you would need to include code that creates and destroys entity managers.

  • It returns Java Persistence objects. The Facade does not return a data transfer object or a value object that is a copy of the Java Persistence objects. One of the features of the Java Persistence API is that Java Persistence objects can be managed by the container and can also be used as plain old Java objects (POJOs), and in fact, those objects are used as POJOs by the Facade's clients. In some cases, a web component client might need to be more loosely-coupled from the domain model. In that case it can choose to use different objects than the POJOs that represent the model tier. However, in this example the Item POJO is sufficient to be used in the web tier. This makes the programming model relatively simple.

  • Throws an application exception. The session bean throws an InvalidItemException with an appropriate corrective action prompt if the user does not specify a name for an item. InvalidItemException is an example of an application exception, which is different from a system exception. In EJBs, an application exception is defined by the application developer and is considered part of the application business logic.

  • Uses generics. The method declaration public List<Item> getAllItems uses generics to specify List as a collection of type Item. Generics provide a way for you to communicate the type of a collection so that it can be checked by the Java compiler. Generics also makes method declarations easier to read and understand.

Using the Facade

Now let's look at the servlet that uses the example Facade:

   public class CatalogServlet extends HttpServlet {
     
     @EJB private CatalogFacade cf;  
     
     ...      
   
     public void doGet(HttpServletRequest request, 
         HttpServletResponse response) throws 
         ServletException, IOException {
       ...       
       
       if ("additem.do".equals(selectedURL))  {
             //get values from request and place 
             // them into new Item
             String desc = request.getParameter("item_desc");
             String name = request.getParameter("item_name");
             ...
             Item item = new Item();
             item.setName(name);
             item.setDescription(desc);
             ...
             //use facade to add new Item to database
             cf.addItem(item);
         ...         
       }
       ...
   }

Notice that the servlet uses dependency injection, through the @EJB annotation, to lookup and obtain the Facade. Notice also that the Facade is stored as a field, cf, so that it can be shared and used by other client requests.

By using the Facade, the servlet is shielded from the details of the entities and from any persistence operations required to access the entities.

Using the Session Bean Facade With Java Server Faces Technology

In the sample code provided with this tip, a servlet accesses Java Persistence objects in the model tier through a Facade. However you could also use a JavaServer Faces technology (often referred to as JSF) component as the web component. In this approach, each JSF page would typically access a JSF-managed bean (also called a backing bean). The managed bean would then access the session bean Facade using the session bean's interface. This is the expected programming model for Java EE 5 applications using JSF and EJB 3.0.

The following diagram illustrates this approach.

JSFwithFacade3

Running the Sample Code

A sample package accompanies this tip that includes a Model Facade implemented as a session bean. To install and run the sample:

  1. If you haven't already done so, download the Java EE 5 SDK from the Java EE Downloads Page. Also be sure to have an installed version of the Java Platform Standard Edition (Java SE) 5 SDK.

  2. Download the sample package for the tip and extract its contents. You should now see the newly extracted directory as <sample_install_dir>/ttfeb2007beanfacade, where <sample_install_dir> is the directory where you installed the sample package. For example, if you extracted the contents to C:\ on a Windows machine, then your newly created directory should be at C:\ttfeb2007beanfacade. The TechTipEJBSessionfacade directory below ttfeb2007beanfacade contains the source files and other support files for the sample.

  3. Edit the build.properties file in the bp-project subdirectory of the TechTip-EJBsessionfacade directory and set properties appropriately for your environment. For example, set javaee.home to point to your Java EE 5 installation directory.

  4. Start the derby database by entering the following command:

       <appsrv_install>/bin/asadmin start-database

    where <appsrv_install> is where you installed the Java EE 5 application server.

  5. Start the application server by entering the following command:

       <appsrv_install>/bin/asadmin start-domain domain1

  6. Change to the TechTip-EJBsessionfacade directory and enter the command:

       ant setup

    This sets up the database resources.

  7. Enter the command:

       ant run

    This builds the sample application then deploys and launches it at http://localhost:8080/bp-sessionfacade.

    The application is the Java Persistence sample application taken from the Java BluePrints Solutions Catalog

EJBFacadePage

Click on the links in the displayed page to retrieve or add items in a catalog. If you examine the source for the application, you'll see that it uses an EJB session bean as a model facade for operations on the persistent entities in the catalog.

When you're finished with the application you can remove it by entering the following commands:

   ant clean - to clean up the application workspace.
   ant undeploy - toun deploy the application from the application server
   ant unsetup - to clean up database resources from the application server

Summary

If you are building a Java EE 5 web application that uses the Java Persistence API, consider refactoring your code by introducing a Model Facade.

For additional information about Facades and the Java Persistence API see:

About the Authors

Sean Brydon is an engineer with Sun Microsystems where he is the technical lead for the Java BluePrints program. He has been involved with the Java BluePrints since its inception. He is an author of the Addison-Wesley Java-series books, "Designing Enterprise Applications with the Java 2 Platform, Enterprise Edition," and "Designing Web Services with the J2EE 1.4 Platform." He is a regular speaker on enterprise application design. Sean has also been involved in designing and developing the Java Pet Store 2.0 reference application and the Java BluePrints Solutions Catalog.

Yutaka Yoshida was a Servlet 2.4 specification lead, and is currently working in the Java BluePrints project. He has been involved in designing and developing the Java Adventure Builder reference application, the Java BluePrints Solutions Catalog, and the Java Pet Store 2.0 reference application.

Developer Assistance

Need programming advice on Java EE? Try Developer Expert Assistance

 
2007 JavaOne Conference Registration is Live

Register today for the JavaOne conference and save $200. The program is new and expanded. Check the 2007 JavaOne Conference page for details.

 
Rate and Review
Tell us what you think of the content of this page.
Excellent   Good   Fair   Poor  
Comments:
Your email address (no reply is possible without an address):
Sun Privacy Policy

Note: We are not able to respond to all submitted comments.