Sun Java System Application Server Platform Edition 9 Upgrade and Migration Guide

Chapter 5 Migrating EJB

Although the EJB 1.1 and EJB 2.0 specification will continue to be supported in Sun Java System Application Server 9, the use of the EJB 3.0 architecture is recommended to leverage its enhanced capabilities.

To migrate a number of modifications are required, including within the source code of components.

You can use the Migration Tool to migrate from EJB 1.1 to EJB 2.0. The Migration Tool will only perform EJB 1.1 to EJB 2.0 conversions if you selected the "Migrate CMPs from EJB 1.1 to 2.0 specs." option. You should choose the this option only if all source files (.java files) and the deployment descriptors (ejb-jar.xml and sun-j2ee-ri.xml files) are available in the input source code. This migration requires and modifies all of these files to affect this migration effectively. If, after verification, the Migration Tool is satisfied that a CMP EJB 1.1 enterprise bean can be migrated to EJB 2.0, it will make the appropriate changes.

The modifications required to migrate from EJB 2.0 to EJB 3.0 are related to the differences between EJB 2.0 and EJB 2.0. These differences are described in the following topics.

Metadata Annotations

An annotation consists of the @ sign preceding the annotation type, followed by a parenthesized list of element-value pairs. The EJB 3.0 Specification defines a variety of annotation types such as those that specify a bean's type (@Stateless, @Stateful, @MessageDriven, @Entity), whether a bean is remotely or locally accessible (@Remote, @Local), transaction attributes (@TransactionAttribute), and security and method permissions (@MethodPermissions, @Unchecked, @SecurityRoles).

Annotations for the EJB 3.0 annotation types generate interfaces required by the class as well as references to objects in the environment. In many cases, defaults can be used instead of explicit metadata annotation elements. In these cases, a developer doesn't have to completely specify a metadata annotation to obtain the same result as if the annotation was fully specified. For example, by default, an entity bean (annotated by @Entity) has a default entity type of CMP, indicating that it has container-managed persistence. These defaults can make annotating enterprise beans very simple. In fact, in many cases, defaults are assumed when an annotation is not specified. In those cases, the defaults represent the most common specifications. For example, container-managed transaction demarcation (where the container, as opposed to the bean, manages the commitment or rollback of a unit of work to a database) is assumed for an enterprise bean if no annotation is specified. These defaults illustrate the "coding by exception" approach that guides EJB 3.0 technology. The intent is to simplify things for developers by forcing them to code things only where defaults are not adequate.

EJB Query Language

EJB 3.0 has made enhancements to EJB QL to provide additional functionality. Addition of projection, explicit inner and outer join operations, bulk update and delete, subqueries, and group-by. Addition of a dynamic query capability and support for native SQL queries.

The EJB 2.0 specification introduces a query language called EJB Query Language, or EJB QL to correct many of these inconsistencies and shortcomings. EJB QL is based on SQL92. It defines query methods, in the form of both finder and select methods, specifically for entity beans with container-managed persistence. EJB QL’s principal advantage over SQL is its portability across EJB containers and its ability to navigate entity bean relationships.

The EJB 1.1 specification left the manner and language for forming and expressing queries for finder methods to each individual application server. While many application server vendors let developers form queries using SQL, others use their own proprietary language specific to their particular application server product. This mixture of query implementations causes inconsistencies between application servers.

Local Interfaces

Under the EJB 3.0 API, the business interface of an enterprise bean is a plain Java interface, not an EJBObject or EJBLocalObject interface. However, usage of the earlier EJBObject and EJBLocalObjectinterface types continues to be supported under EJB 3.0.

With EJB 2.0, session beans and entity beans can expose their methods to clients through two types of interfaces: a remote interface and a local interface. The 2.0 remote interface is identical to the remote interface used in the 1.1 architecture, whereby, the bean inherits from RMI, exposes its methods across the network tier, and has the same capability to interact with distributed clients.

However, the local interfaces for session and entity beans provide support for lightweight access from EJBs that are local clients; that is, clients co-located in the same EJB container. The EJB 2.0 specification further requires that EJBs that use local interfaces be within the same application. That is, the deployment descriptors for an application’s EJBs using local interfaces must be contained within one ejb-jar file.

In the EJB 1.1 architecture, session and entity beans have one type of interface, a remote interface, through which they can be accessed by clients and other application components. The remote interface is designed such that a bean instance has remote capabilities; the bean inherits from RMI and can interact with distributed clients across the network.

The local interface is a standard Java interface. It does not inherit from RMI. An enterprise bean uses the local interface to expose its methods to other beans that reside within the same container. By using a local interface, a bean may be more tightly coupled with its clients and may be directly accessed without the overhead of a remote method call.

In addition, local interfaces permit values to be passed between beans with pass by reference semantics. Because you are now passing a reference to an object, rather than the object itself, this reduces the overhead incurred when passing objects with large amounts of data, resulting in a performance gain.

EJB 3.0 Entity Model

To create the session bean, a developer only needs to code a bean class and annotate it with appropriate metadata. A session bean need not home interface, remote interface, or deployment descriptor to code. All that is required in addition to the bean class is a business interface, and that can be generated by default. The bean class is coded as a plain old Java object (POJO) rather than a class that implements an interface such as javax.ejb.SessionBean. Because the bean class does not implement an interface such as javax.ejb.SessionBean, a developer no longer has to implement methods such as ejbRemove, ejbActivate, or ejbPassivate in the bean class. However a developer can implement any or all of these callbacks if they are needed. If the bean class implements one of these callbacks, the EJB container calls it just as it does for EJB 2.1 technology.

The new Java Persistence API in EJB 3.0 defines a new single model for implementing persistence in the Java platform. In EJB 3.0 technology, an entity bean class is a concrete class. It's no longer an abstract class.

The EJB 2.0 specification uses the CMP model. It expanded the existing CMP to allow multiple entity beans to have relationships among themselves. This is referred to as Container-Managed Relationships (CMR). The container manages the relationships and the referential integrity of the relationships.According to the EJB 2.0 specification, the implementation class for an entity bean that uses CMP is now defined as an abstract class.

The EJB 1.1 specification presented a more limited CMP model. The EJB 1.1 architecture limited CMP to data access that is independent of the database or resource manager type. It allowed you to expose only an entity bean’s instance state through its remote interface; there is no means to expose bean relationships. The EJB 1.1 version of CMP depends on mapping the instance variables of an entity bean class to the data items representing their state in the database or resource manager. The CMP instance fields are specified in the deployment descriptor, and when the bean is deployed, the deployer uses tools to generate code that implements the mapping of the instance fields to the data items.

The following topics are discussed in this section:

Defining Persistent Fields

In EJB 3.0, get and set methods are concrete, not abstract. In addition, these methods can include logic, something that was not possible previously. This is useful for actions such as validating fields. Another improvement is that access to the persistence fields is not limited to the get and set methods. The persistence fields are also accessible through a bean class's business methods. One restriction however is that in EJB 3.0 technology, only methods within the class can access persistence fields -- in other words, you cannot expose the instance variables outside of the class.

The EJB 2.0 specification lets you designate an entity bean’s instance variables as CMP fields or CMR fields. You define these fields in the deployment descriptor. CMP fields are marked with the element cmp-field, while container-managed relationship fields are marked with the element cmr-field.

Dependency Injection

Previous versions of the EJB architecture forced the developer into complying with the requirements of the EJB container in terms of providing classes and implementing interfaces. By comparison, In EJB 3.0, dependency injection reflects the fact that the bean tells the EJB container what it needs, and then container satisfies those needs.

Message-Driven Beans

EJB 3.0 enhances message-driven beans with support for interceptors.

Message-driven beans were a new feature introduced by the EJB 2.0 architecture. Message-driven beans are transaction-aware components that process asynchronous messages delivered through the Java Message Service (JMS).

Migrating EJB Client Applications

Existing EJB 2.1 and earlier applications are supported to run unchanged in EJB 3.0 containers. All EJB 3.0 implementations support EJB 1.1, EJB 2.0, and EJB 2.1 deployment descriptors for applications written to earlier versions.

Clients written to the new EJB 3.0 API

A client written to the EJB 3.0 API may be a client of a component written to the EJB 2.1 or earlier API. Such clients may access components written to the EJB 3.0 APIs and components written to the earlier EJB APIs within the same transaction. Such clients access components written to the earlier EJB APIs using the EJB 2.1 client view home and component interfaces. The EJB annotation may be used for the injection of home interfaces into components that are clients of beans written to the earlier EJB client view.

Declaring EJBs in the JNDI Context

In Application Server 9, EJBs are systematically mapped to the JNDI sub-context ejb/. If you attribute the JNDI name Account to an EJB, the Application Server 9 automatically creates the reference ejb/Account in the global JNDI context. The clients of this EJB therefore have to look up ejb/Account to retrieve the corresponding home interface.

Let us examine the code for a servlet method deployed in Sun ONE Application Server 6.x.

The servlet presented here calls on a stateful session bean, BankTeller, mapped to the root of the JNDI context. The method whose code you are considering is responsible for retrieving the home interface of the EJB, to enable a BankTeller object to be instantiated, and a remote interface for this object to be retrieved, so that you can make business method calls to this component.

/**
   * Look up the BankTellerHome interface using JNDI.
   */
private BankTellerHome lookupBankTellerHome(Context ctx)
      throws NamingException
{
    try
    {
      Object home = (BankTellerHome) ctx.lookup("ejb/BankTeller");
      return (BankTellerHome) PortableRemoteObject.narrow(home, 
	              BankTellerHome.class);
    }
    catch (NamingException ne)
    {
      log("lookupBankTellerHome: unable to lookup BankTellerHome" +
          "with JNDI name ’BankTeller’: " + ne.getMessage() );
      throw ne;
    }
}

As the code already uses ejb/BankTeller as an argument for the lookup, there is no need for modifying the code to be deployed on Application Server 9.

Using EJB JNDI References

This section summarizes the considerations when using EJB JNDI references. Where noted, the consideration details are specific to a particular source application server platform.

Placing EJB References in the JNDI Context

It is only necessary to modify the name of the EJB references in the JNDI context mentioned above (moving these references from the JNDI context root to the sub-context ejb/) when the EJBs are mapped to the root of the JNDI context in the existing WebLogic application.

If these EJBs are already mapped to the JNDI sub-context ejb/ in the existing application, no modification is required.

However, when configuring the JNDI names of EJBs in the deployment descriptor within the Sun Java Studio IDE, it is important to avoid including the prefix ejb/ in the JNDI name of an EJB. Remember that these EJB references are automatically placed in the JNDI ejb/ sub-context with Application Server 9. So, if an EJB is given to the JNDI name BankTeller in its deployment descriptor, the reference to this EJB will be translated by Application Server 9 into ejb/BankTeller, and this is the JNDI name that client components of this EJB must use when carrying out a lookup.

Global JNDI context versus local JNDI context

Using the global JNDI context to obtain EJB references is a perfectly valid, feasible approach with Application Server 9. Nonetheless, it is preferable to stay as close as possible to the Java EE specification, and retrieve EJB references through the local JNDI context of EJB client applications. When using the local JNDI context, you must first declare EJB resource references in the deployment descriptor of the client part (web.xml for a Web application, ejb-jar.xml for an EJB component).

Migrating CMP Entity EJBs

With the introduction of EJB 3.0, you can use JDO (in addition to CMP 2.0), which is an architecture that provides a standard way to transparently persist plain Java objects.

EJB 2.x and EJB 3.0 uses CMP 2.0. In order to migrate a CMP 1.1 bean to CMP 2.0, we first need to verify if a particular bean can be migrated. The steps to perform this verification are as follows.

ProcedureTo Verify if a Bean Can be Migrated

  1. From the ejb-jar.xml file, go to the <cmp-fields> names and check if the optional tag <prim-key-field> is present in the ejb-jar.xml file and has an indicated value. If it does, go to next step.

    Look for the <prim-key-class> field name in the ejb-jar.xml, get the class name and get the public instance variables declared in the class. Now see if the signature (name and case) of these variables matches with the <cmp-field> names above. Segregate the ones that are found. In these segregated fields, check if some of them start with an upper case letter. If any of them do, then migration cannot be performed.

  2. Look into the bean class source code and obtain the java types of all the <cmp-field> variables.

  3. Change all the <cmp-field> names to lowercase and construct accessors from them. For example if the original field name is Name and its java type is String, the accessor method signature will be:

    Public void setName(String name)Public String getName()

  4. Compare these accessor method signatures with the method signatures in the bean class. If there is an exact match found, migration is not possible.

  5. Get the custom finder methods signatures and their corresponding SQLs. Check if there is a ”Join’ or ”Outer join’ or an ”OrderBy’ in the SQL, if yes, we cannot migrate, as EJB QL does not support ”joins’, ”Outer join’ and ”OrderBy’.

  6. Any CMP 1.1 finder, which used java.util.Enumeration, must now use java.util.Collection. Change your code to reflect this. CMP 2.0 finders cannot return java.util.Enumeration.

    Migrating the Bean Class explains how to perform the actual migration process.

Migrating the Bean Class

This section describes the steps required to migrate the bean class to Sun Java System Application Server 9.

ProcedureTo Migrate the Bean Class

  1. Prepend the bean class declaration with the keyword abstract.

    For example if the bean class declaration was:

    Public class CabinBean implements EntityBean // before modification

    Change it to:

    abstract Public class CabinBean implements EntityBean // after 
    modification
  2. Prefix the accessors with the keyword abstract.

  3. Insert all the accessors after modification into the source(.java) file of the bean class at class level.

  4. Comment out all the cmp fields in the source file of the bean class.

  5. Construct protected instance variable declarations from the cmp-field names in lowercase and insert them at the class level.

  6. Read up all the ejbCreate() method bodies (there could be more than one ejbCreate).

    Look for the pattern ”<cmp-field>=some value or local variable’, and replace it with the expression ”abstract mutator method name (same value or local variable)’.

    For example, if the ejbCreate body before migration is:

    public MyPK ejbCreate(int id, String name) {
       this.id = 10*id;
       Name = name;   //1
       return null;
    }

    Change it to:

    public MyPK ejbCreate(int id, String name) {
       setId(10*id);
       setName(name);   //1
       return null;
    }

    Note that the method signature of the abstract accessor in //1 is as per the Camel Case convention mandated by the EJB 2.0 specification. Also, the keyword ”this’ may or may not be present in the original source, but it must be removed from the modified source file.

  7. Initialize all the protected variables declared in the ejbPostCreate()methods in step 5.

    The protected variables will be equal in number with the ejbCreate() methods. This initialization will be done by inserting the initialization code in the following manner:

    protected String name;  //from step 5
    protected int id;  //from step 5
    public void ejbPostCreate(int id, String name) {
       name = getName();    /*abstract accessor*/ //inserted in this step
       id  = getId();        /*abstract accessor*/ //inserted in this step
    }
  8. Inside the ejbLoad method, set the protected variables to the beans’ database state.

    To do so, insert the following lines of code:

    public void ejbLoad() {
       name = getName();    // inserted in this step
       id = getId();        // inserted in this step
       ...                  // existing code
    }
  9. Similarly, update the beans’ state inside ejbStore()so that its database state gets updated.

    But remember, you are not allowed to update the setters that correspond to the primary key outside the ejbCreate(), so do not include them inside this method. Insert the following lines of code:

    public void ejbStore() {
        setName(name);       //inserted in this step
        setId(id);           //Do not insert this if it is a part 
                               of the primary key
        ...                  //already present code
    }
  10. Replace all occurrences of any <cmp-field> variable names with the equivalent protected variable name (as declared in step 5).

    If you do not migrate the bean, at the minimum you need to insert the <cmp-version>1.x</cmp-version> tag inside the ejb-jar.xml file at the appropriate place, so that the unmigrated bean still works on Sun Java System Application Server 9.

Migration of ejb-jar.xml

To migrate the file ejb-jar.xml to Sun Java System Application Server 9, perform the following steps:

ProcedureTo Migrate the EJB Deployment Descriptor

To migrate the EJB deployment descriptor file, ejb-jar.xml, edit the file and make the following changes.

  1. Convert all <cmp-fields> to lowercase.

  2. Insert the tag <abstract-schema-name> after the <reentrant> tag.

    The schema name will be the name of the bean as in the < ejb-name> tag, prefixed with “ias_”.

  3. Insert the following tags after the <primkey-field> tag:

    <security-identity>
       <use-caller-identity/>
    </security-identity>
  4. Use the SQL obtained above to construct the EJB QL from SQL.

  5. Insert the <query> tag and all its nested child tags with all the required information just after the <security-identity> tag.

Custom Finder Methods

The custom finder methods are the findBy... methods (other than the default findByPrimaryKey method), which can be defined in the home interface of an entity bean. Since the EJB 1.1 specification does not stipulate a standard for defining the logic of these finder methods, EJB server vendors are free to choose their implementations. As a result, the procedures used to define the methods vary considerably between the different implementations chosen by vendors.

Sun ONE Application Server 6.x uses standard SQL to specify the finder logic.

Information concerning the definition of this finder method is stored in the enterprise bean’s persistence descriptor (Account-ias-cmp.xml) as follows:

<bean-property>
  <property>
    <name>findOrderedAccountsForCustomerSQL</name>
    <type>java.lang.String</type>
    <value>
       SELECT BRANCH_CODE,ACC_NO FROM ACCOUNT where CUST_NO = ?
    </value>
    <delimiter>,</delimiter>
  </property>
</bean-property>
<bean-property>
  <property>
    <name>findOrderedAccountsForCustomerParms</name>
    <type>java.lang.Vector</type>
    <value>CustNo</value>
    <delimiter>,</delimiter>
  </property>
</bean-property>

Each findXXX finder method therefore has two corresponding entries in the deployment descriptor (SQL code for the query, and the associated parameters).

In Sun Java System Application Server 9 the custom finder method logic is also declarative, but is based on the EJB query language EJB QL.

The EJB-QL language cannot be used on its own. It has to be specified inside the file ejb-jar.xml, in the <ejb-ql> tag. This tag is inside the <query> tag, which defines a query (finder or select method) inside an EJB. The EJB container can transform each query into the implementation of the finder or select method. Here’s an example of an <ejb-ql> tag:

<ejb-jar>   
  <enterprise-beans>     
    <entity>
      <ejb-name>hotelEJB</ejb-name>       
      ...       
      <abstract-schema-name>TMBankSchemaName</abstract-schema-name>       
      <cmp-field>
      ...       
      <query>         
        <query-method>           
          <method-name>findByCity</method-name> 
            <method-params>             
              <method-param>java.lang.String</method-param> 
            </method-params>         
        </query-method>         
        <ejb-ql>           
          <![CDATA[SELECT OBJECT(t) FROM TMBankSchemaName 
                                    AS t WHERE t.city = ?1]]>
        </ejb-ql>       
      </query>     
    </entity>   
    ...   
  </enterprise-beans> ... 
</ejb-jar>

DTD Changes during EJB Migration

Migrating EJBs from Application Server 6.x to Application Server 9 is done without making any changes to the EJB code. However, the following DTD changes are required.

Session Beans


Note –

To avoid changing JNDI names throughout the application, declare the JNDI name of the EJB as ejb/<ejb-name> inside the <jndi-name> tag.


Entity Beans

Message Driven Beans

Application Server provides seamless Message Driven Support through the tight integration of Sun Java System Message Queue with the Application Server, providing a native, built-in JMS Service.

This installation provides Application Server with a JMS messaging system that supports any number of Application Server instances. Each server instance, by default, has an associated built-in JMS Service that supports all JMS clients running in the instance.

Both container-managed and bean-managed transactions, as defined in the Enterprise JavaBeans Specification 2.0 and 3.0 are supported.

Message Driven Bean support in iPlanet Application Server was restricted to developers, and used many of the older proprietary APIs. Messaging services were provided by iPlanet Message Queue for Java 2.0. An LDAP directory was also required under iPlanet Application Server to configure the Queue Connection Factory object.

The QueueConnectionFactory, and other elements required to configure Message Driven Beans in Application Server are now specified in the ejb-jar.xml file.

For more information on the changes to deployment descriptors, see Migrating Deployment Descriptors For information on Message Driven Beans see Using Message-Driven Beans in Sun Java System Application Server Platform Edition 9 Developer’s Guide.