Chapter 14. Migrating to EJB 3

This chapter covers

  • Migrating session beans and MDBs
  • Migrating CMP entity beans
  • Migrating JDBC DAO and O/R frameworks

In today’s IT world, migration has become an integral part of the application development lifecycle. Software products and technology change every few years, requiring the migration of applications from one platform (or one version) to another. From a budget standpoint, migration is certainly less expensive than rebuilding applications, and thus easier to justify to management. IT shops normally migrate their applications to increase their longevity and improve maintainability. Countless applications have been written using EJB 2 and many of these applications will be migrated to use EJB 3. Many customers who have built their persistence tier using JDBC, JDO, or O/R frameworks like Hibernate or TopLink will be migrating to the EJB 3 JPA, since it is the new industry-standard persistence API for the Java platform. Some companies may only be able to justify migrating a portion of their applications to EJB 3, leaving others living in an EJB 2 world. This will introduce a new wave of interoperability issues.

In this chapter we look at the compatibility, interoperability, and migration issues that will surface as you migrate to EJB 3. You may be under the gun to migrate your applications to EJB 3; this may even be the first chapter you’re reading in this book. Be advised that you should not consider this chapter the sole reference for all migration issues, although we’ll try to address the more common scenarios that you’re likely to encounter.

This chapter assumes some familiarity with EJB 2. Once more, we’ll use the ActionBazaar application to illustrate migration to EJB 3. Forget for a while that you built ActionBazaar using EJB 3, and pretend that it was originally developed using varieties of EJB 2 technologies such as session beans and CMP entity beans.

14.1. Backward compatibility and interoperability with EJB 2

Up to this point in the book we have focused almost exclusively on EJB 3. If you’ve used EJB 2 you realize that there have been drastic changes between the two versions. You may be wondering what will happen to your application when you deploy to a container that supports EJB 3. You might also be wondering what will happen if you have two EJB 2 applications that interact with each other when you migrate one of them to EJB 3. Let us put your mind at ease.

The EJB 3 specification requires that all complying containers support EJB 2. This should help relieve any concern as far as upgrading from your existing application server to one that is EJB 3 compliant. However, it seems likely that you will need to do something to make your old apps work in the shiny new EJB 3 app server, and you’ll want to make some changes that allow them to talk to newly minted EJB 3 apps. In this section we’ll explore what it will take to package applications and invoke components that contain EJBs from both versions.

14.1.1. Packaging EJB 2 and EJB 3 together

Unless you’re in the enviable situation of conducting green-field development with EJB 3, there is a chance your EJB 3 application will need to peacefully coexist with your EJB 2 applications and components, and vice versa. More than that, you’ll probably want them to work together, interoperating with each other.

Now there are several possibilities for using EJB 2 and EJB 3 together. Maybe you have decided to migrate a selected group of application components to EJB 3, while leaving some components in earlier versions as a part of an incremental migration. Another common case is where a newly developed EJB 3 application wants to leverage an existing EJB 2 component. Yet another instance could be that the developers decide to migrate the persistence tier of ActionBazaar built using CMP 2 to use the EJB 3 JPA, leaving all the session beans and MDBs implemented in EJB 2. A less likely but possible case is that you decide to move the business logic tier of your applications to EJB 3, and leave the persistence tier built with CMP 2 untouched. EJB 3 supports all these scenarios and makes the EJB 3 JPA available for use with session beans and MDBs built using EJB 2.

The first EJB 3 migration item to be aware of is that if you want to package both EJB 2–style beans and EJB 3 beans and JPA entities in the same EJB module, then you must set the version attribute of the ejb-jar module to 3.0 as follows:

If you specify a version other than 3.0 (e.g., 2.1), then the EJB container will assume the EJB module is an older version and won’t scan for annotations. This means it won’t detect EJB 3 beans, or detect the persistence unit containing entities packaged in the EJB module. Make sure that version is either set to 3.0 or not specified at all.

14.1.2. Invoking EJB 2 from EJB 3

You can invoke EJB 2 session or entity beans from EJB 3 session beans or MDBs. You can even use dependency injection to invoke an EJB 2 bean. To illustrate the latter, assume that you have an EJB 2 bean (ChargeCredit) that charges a credit card. Use the @EJB annotation to inject an instance of a home object for ChargeCredit in an EJB 3 POJO like this:

@Stateful
public PlaceOrderBean implements PlaceOrder {
..
@EJB
public ChargeCreditHome creditHome;
..
void chargeCreditCard(){
...
ChargeCredit chargeCredit
= creditHome.create();
String confirmationNo
= chargeCredit.add(billingInfo, amount);
..
}

ChargeCredit and ChargeCreditHome are the remote and home interfaces, respectively, of ChargeCreditEJB. Use the create method to get a reference to the remote interface, and then invoke the desired business method (in this case add) on the bean. As you can see from this example, EJB 3 supports the EJB 2 concepts, and the programming model is straightforward.

If, instead of calling an EJB 2 session bean you’d like to invoke an EJB 2 CMP entity bean from EJB 3, you’d follow a similar approach to the previous example. Assume that ActionBazaar used EJB 2 CMP entity beans for its persistence tier. The specific case we’ll discuss is one in which the PlaceBid EJB persists the Bid bean as follows:

@Stateless
public PlaceBidBean implements PlaceBid {
...
@EJB
public BidLocalHome bidLocalHome;
...
BidLocal bidLocal = bidLocalHome.create(BidDTO);
...
}

In this example, we create a bean instance (BidDTO) by using a data transfer object (DTO). We’ll discuss the DTO design pattern in section 14.3, but essentially the DTO is used to transfer business object state, not necessarily behavior, across application tiers. Recall that creating an entity bean instance will ask the container to persist the bean instance in the database.

That covers calling EJB 2 from EJB 3, but what about the other way around? Read the next section to solve this mind-numbing mystery... actually, there’s nothing mind-numbing about it—it’s almost as simple as what we just covered. Go ahead—see for yourself.

14.1.3. Using EJB 3 from EJB 2

You can use both EJB 3 session beans and the EJB 3 JPA from EJB 2 applications. Although there were some discussions in the EJB 3 Expert Group on adding support for dependency injection for EJB 2–style beans, the EJB 3 spec does not require support for injection with EJB 2 (although some vendors may decide to provide it). If your server does not support EJB 2 dependency injection, you must use good old-fashioned JNDI lookup to access EJB 3 session beans and the EJB 3 EntityManager from EJB 2 beans. This is shown in figure 14.1.

Figure 14.1. It is possible to use EJB 3 beans as well as the JPA EntityManager in EJB 2 by looking them up from the JNDI context.

The method is similar to using EJB 3 beans or JPA using JNDI lookup (which we discussed in chapter 12).

Using EJB 3 session beans from EJB 2

Pretend for a moment that the PlaceBid EJB is an EJB 2 session bean that invokes CheckCredit in a partner application, KabadiBazaar, but that CheckCredit is an EJB 3 session bean. You must have an ejb-ref or ejb-local-ref element in the ejb-jar.xml to establish the reference to the CheckCredit EJB as follows:

<session>
<ejb-name>PlaceBidBean</ejb-name>
<home>actionbazaar.buslogic.PlaceBidHome</home>
<remote>actionbazaar.buslogic.PlaceBid</remote>
<ejb-class>actionbazaar.buslogic.PlaceBidBean</ejb-class>
<session-type>stateless</session-type>
...
<ejb-local-ref>
<ejb-ref-name>ejb/CheckCredit</ejb-ref-name>
<ejb-ref-type>Session</ejb-ref-type>
<local>kabadibazaar.buslogic.CheckCredit</local>
<ejb-link>kabadibazaar-ejb.jar#CheckCreditBean</ejb-link>
</ejb-local-ref>
</session>

The only difference between the standard deployment descriptor and this one is that the ejb-local-ref element does not have a local-home element. This is because the EJB 3 session bean does not require a home interface. In your application you can use JNDI to look up remote beans with ref-name as follows:

The JNDI lookup is identical whether you’re using EJB 2 or EJB 3.

Using the EJB 3 JPA from EJB 2

You can use either a container- or an application-managed EntityManager in your EJB 2 beans. Assume that ActionBazaar migrated only the persistence tier to JPA. To use the container-managed EntityManager from an EJB 2 bean, you’d define the persistence-context-ref for the EJB 2 bean as follows:

<session>
<ejb-name>PlaceBidBean</ejb-name>
...
<persistence-context-ref>
<persistence-context-ref-name>
ActionBazaarEntityManager
</persistence-context-ref-name>
<persistence-unit-name>actionBazaar</persistence-unit-name>
</persistence-context-ref>
</session>

Next, you would look up an instance of a container-managed EntityManager via JNDI as follows:

Context context = new InitialContext();
EntityManager entityManager = (EntityManager)
context.lookup("java:comp/env/ActionBazaarEntityManager");
...
entityManager.persist(bid);

Notice that this JNDI lookup appears to be like all the others in the book. The only special thing you would have to do is to package a persistence.xml that describes the persistence unit and set version="3.0" in the ejb-jar.xml. It’s starting to look familiar, isn’t it? Using EJB 3 from EJB 2 boils down to

  • Making some modifications to your deployment descriptors
  • Working a little JNDI magic to get object references (if your server doesn’t support dependency injection for EJB 2)

That’s all there is to it! It’s so simple that this concludes our discussion on backward compatibility and interoperability of EJB applications.


Note

The EJB specification requires that an EJB container be interoperable with CORBA applications using RMI-IIOP. While this is possible, we don’t think this is commonly used so we won’t discuss it in this chapter. If your application requires interoperability with CORBA, we suggest you explore this on your own by referring to the EJB 3 Core Contracts specification.


The new way to achieve interoperability with heterogeneous systems is web services. In chapter 15 we discuss exposing EJB 3 stateless session beans as web services and invoking web services from EJB 3 applications. But that’s a whole chapter away, and we’re not through talking about migration yet. Let’s see; we’ve talked a bit about swapping bean invocations between EJB 2 and EJB 3—what do you say we explore how to migrate session beans next?

14.2. Migrating session beans

If you’re using EJB 2 session beans (which will be supported for a while by many major vendors), why you would migrate to EJB 3? Here area few reasons that come to mind:

  • You may be releasing a new version of your application and you want to take advantage of new EJB 3 features such as interceptors and dependency injection.
  • Migrating beans to use EJB 3 will simplify your code and improve maintainability of your application. Because EJB 3 is POJO based, you can also simplify your unit tests.
  • Migrating your applications will renew your applications for a few more years.

Migrating session beans to EJB 3 is quite easy because it is as simple as

  • Pruning the existing EJB code to make it a POJO
  • Defining at least one business interface
  • Using annotations instead of a deployment descriptor
  • Replacing redundant JNDI code with dependency injection

The remainder of this section further breaks down the details involved in migrating session beans from EJB 2 to EJB 3.

14.2.1. Converting interface and bean classes

An EJB 2 session bean has at least one component interface (local or remote), one home interface, and one bean class. The component and home interfaces extend the EJB-specific interfaces, while the bean class implements the javax.ejb.SessionBean interface. After you migrate your bean to EJB 3, it is a POJO and the bean class implements its business interfaces. Table 14.1 summarizes the changes between EJB 2.1 and EJB 3.

Table 14.1. EJB 2 required many interfaces that needed to extend EJB-specific interfaces. EJB 3 makes the home interface optional.

Components of a Session Bean

EJB 2

EJB 3

Remote or local component interface

Extends either EJBObject or EJBLocalObject

Business interface (POJI).

Home interface

Extends EJBHome or EJBLocalHome

Optional for maintaining EJB 2 client view. Candidate for removal.

Bean class

Implements javax.ejb. SessionBean

Implements business interface.

Given that the home interface is optional, you can consider it deprecated. We recommend you begin the process of making the shift away from the home interface in both your thinking as well as your code. More on removing the home interface in the sections ahead...

Interfaces

If you need to migrate your component interfaces, we’ve got just the recipe; you’ll have to make the following changes:

  • Your component interface (remote or local) becomes a regular business interface. In other words, it does not extend one of the EJB interfaces.
  • Your business methods don’t have to throw unnecessary exceptions such as RemoteException.

Figure 14.2 summarizes these differences.

Figure 14.2. The changes necessary to migrate EJB 2 business interfaces to EJB 3. You do not have to extend EJB-specific interfaces or throw RMI or EJB exceptions in the methods.

Let’s walk through this modification with an example. Consider the following remote interface of the PlaceBid EJB using EJB 2:

public interface PlaceBid extends EJBObject {
public Long addBid(String userId, Long itemId, Double bidPrice)
throws RemoteException,
CreateException,
FinderException,
NamingException;
}

The addBid method throws CreateException and FinderException because the bean class uses CMP 2 entity beans and throws NamingException because it uses JNDI.

After migration to EJB 3, the remote interface will look like this:

@Remote
public interface PlaceBid {
public Long addBid(String userId, Long itemId, Double bidPrice);
}

Ah, that’s better, isn’t it? This code assumes that we have migrated the EJB 2 CMP entity beans to use the EJB 3 JPA and are no longer required to throw FinderException and CreateException. In addition, we’ve defined the interface as a remote business interface with the annotation @Remote.

Unless you need the home interface (also known as adapted home) for backward compatibility with EJB 2 clients, you probably won’t need it, so seriously consider removing it. We’ll explain how to use the home interface with the EJB 3 session bean, if for some reason you’re unable to migrate a client application that is dependent on your EJB.

If you decide to use a deployment descriptor, then you must remove the home or local-home element and not have a home interface; otherwise, your EJB module will fail to deploy. The container should generate deployment errors if you forget to do this, and will identify the line number in the deployment descriptor.

The bean class

Migration of a session bean class is just as straightforward as component interfaces. Here are some changes you’ll need to make:

  • Your bean class doesn’t have to implement the javax.ejb.SessionBean interface. Just make the bean a POJO and have it implement the business interface.
  • You don’t have to implement unnecessary lifecycle methods. Furthermore, can use any method name you want for your lifecycle methods, and you can use annotations to mark which methods are lifecycle methods. Table 14.2 provides a list of EJB 2 methods with bean types and corresponding annotations that you can use in EJB 3.
    Table 14.2. EJB 2 required implementation of several lifecycle methods. If you implemented any of your application’s business logic in any of these methods, then you can use the corresponding methods in EJB 3 to migrate that business logic.

    Bean Type

    EJB 2 Methods

    EJB 3 Methods

    Stateless, Stateful

    ejbCreate

    Constructor

    Stateless, Stateful

    ejbPostCreate

    Method annotated with @PostConstruct

    Stateful

    ejbPassivate

    Method annotated with @PrePassivate

    Stateful

    ejbActivate

    Method annotated with @PostActivate

    Stateless, Stateful

    ejbRemove

    Method annotated with @PreDestroy

    Stateful

    remove method in home interface

    Method annotated with @Remove

    Stateful

    create method in home interface

    Method annotated with @Init if the EJB 3 bean has a home interface

    Stateless

    ejbTimeout

    Method annotated with @Timeout

Figure 14.3 summarizes these migration steps.

Figure 14.3. The changes necessary to migrate EJB 2.x bean classes to EJB 3. You don’t have to implement EJB specific interfaces in EJB 3, and you don’t have to implement all required lifecycle methods, as in EJB 2.

The business methods remain unchanged unless you’re using other resources or EJBs. The code becomes simplified because you can use injection. This gives you the ability to remove the JNDI code. If you are migrating EJB 2 CMP entity beans and you have a session bean that uses the CMP entity beans, you have to migrate your session bean methods to use the EntityManager API. We’ll discuss migration of entity beans to the EJB 3 JPA in section 14.3.

You can also opt to change the security and transactions settings to use metadata annotations. We’ll cover those in a later section.

14.2.2. Resource usage

Your EJB applications may be using JNDI lookup to find resources such as DataSources or JMS objects, and services such as EJBs or web services. Now that dependency injection is so readily available, you can use it instead of JNDI to find these resources. However, you have to remember the limitations of EJB 3 dependency injection.

If you’re using a DataSource, the differences between EJB 2 and EJB 3 are shown in table 14.3.

Table 14.3. The use of DataSource in EJB 2 was very complex and has been simplified in EJB 3 by using dependency injection.

EJB 2

EJB 3

Define resource-ref in ejb-jar.xml Lookup resource

Can use dependency injection

 

@Resource(name = "ActionBazaarDS")

Context ctx = new InitialContext();

DataSource ds = (DataSource) ctx.lookup("java:comp/env/ActionBazaarDS");

private DataSource ds;

Connection conn = ds.getConnection();

Connection conn = ds.getConnection();

If you’re using a JMS resource, the differences between EJB 2 and EJB 3 are shown in table 14.4.

Table 14.4. The use of JMS objects in EJB 2 was also very complex and has been simplified in EJB 3 by using dependency injection.

EJB 2.x

EJB3

Define resource-ref in ejb-jar.xml Lookup resource

@Resource(name = "jms/QueueConnectionFactory")

private QueueConnectionFactory qcf;

Context ctx = new InitialContext();

 

QueueConnectionFactory qcf = (QueueConnectionFactory) ctx.lookup("java:comp/env/jms/Queue ConnectionFactory");

QueueConnection conn = qcf.createQueueConnection();

QueueConnection conn = qcf.createQueueConnection();

 

Our comparison on how resources are declared and found between EJB 2 and EJB 3 is intended to underscore how much more straightforward dependency injection is compared to JNDI (no casting required), and how much easier it is for developers to maintain.

14.2.3. Transactions and security settings

EJB 2 doesn’t define any default transaction and security settings for EJBs. You have to specify the definitions yourself for each and every bean method in a session bean. If you don’t, you’ll see different behaviors in different EJB containers.

As discussed in chapter 6, EJB 3 defines CMT as the default transaction management type for a bean, and REQUIRED as the default transaction attribute for bean methods. Therefore, you can simplify your transaction settings in your deployment descriptors by only specifying those that need a transaction attribute other than REQUIRED. Optionally, you can use annotations to define transaction settings. The same holds true for security settings. You can leave the security settings as is in the deployment descriptor, or use the security annotations discussed in chapter 6.

14.2.4. Client applications

Session beans are server-side components that encapsulate business logic and may be accessed either by remote or local clients. The client for an EJB could be another EJB in the same container, a separate container, a web module, or an application client. When you migrate any session bean to EJB 3, the clients will be impacted. This is mostly due to the fact that home interfaces are no longer needed. All client applications will have to be modified to use the EJB 3 client view. The ejb-ref or ejb-local-ref element in the client application’s descriptor will also need to be modified to remove the home element, and the client code will have to be updated to look up the business interface instead of the home interface.

The old EJB 2 client code for the PlaceBid session bean would look like this:

Context context = new InitialContext();
PlaceBidHome placeBidHome =
(PlaceBidHome) PortableRemoteObject.narrow(
context.lookup("java:comp/env/PlaceBid"), PlaceBidHome.class);

PlaceBid placeBid = placeBidHome.create();
newBidId = placeBid.addBid(userId, itemId, bidPrice);

The migrated client code for the PlaceBid EJB will look like this if you continue to use JNDI:

Context context = new InitialContext();
PlaceBid placeBid = (PlaceBid)context.lookup("java:comp/env/PlaceBid");
Long newBidId = placeBid.addBid(userId, itemId, bidPrice);

If your client is a managed class and uses the Java EE 5 API, you can migrate the client to use dependency injection and further simplify the client code:

@EJB private PlaceBid placeBid;

Long newBidId = placeBid.addBid(userId, itemId, bidPrice);

So the original EJB 2 lookup took around eight lines of code. The EJB 3 refactoring reduced this to two lines of code, regardless of whether you use JNDI or dependency injection—in this case. Of course, your mileage may vary but we think you’ll immediately see some benefits to migrating this code to the new programming model available in EJB 3.

Maintaining backward compatibility with EJB 2 clients

There may be various cases when you cannot afford to migrate your client applications, but you want to move your session beans to EJB 3. This will primarily be an issue when you have a remote interface for a session bean that is used by separate applications, some of which you don’t have control over. Or perhaps you’re an independent software vendor (ISV) that sells packaged applications and customers may be using your EJB in their EJB 2 applications.

To demonstrate this, imagine that many ActionBazaar Gold customers use rich client applications that remotely access EJBs such as PlaceBid. Now that PlaceBid has been migrated to EJB 3 (POJOs, regular interface, etc.), the rich client applications will break unless you update them. In this release of ActionBazaar you aren’t making any client-side changes because you don’t want to distribute a newer version of client applications to your customers. At the same time you don’t want your client applications to break. Client applications of EJB 2 session beans use the create method on the home interface to create an EJB object instance. You can add a home interface and expose a create method in the home interface as follows:

import javax.rmi.RemoteException;
import javax.ejb.*;

public interface PlaceBidHome extends EJBHome {
public PlaceBid create() throws CreateException, RemoteException;
}

Then use the @RemoteHome annotation on the bean class to mark this as a remote home interface as follows:

@Stateless(name = "PlaceBid")
@RemoteHome(PlaceBidHome.class)
public class PlaceBidBean implements PlaceBid {
}

If you want to maintain backward compatibility with local EJB 2 clients, then you can use the @LocalHome annotation. You must remember that you can’t use the @javax.ejb.LocalHome and @javax.ejb.RemoteHome annotations in the home interfaces but only in the bean classes.

This concludes our discussion on migrating session beans. There’s not much to it, is there? Let’s now move to a discussion on migrating MDBs before we jump into more complex migration tasks involving CMP entity beans.

14.3. Migrating message-driven beans

MDBs have been simple Java classes since their introduction in EJB 2, and do not require remote or home interfaces, or unnecessary lifecycle methods. Not many changes to MDBs transpired in EJB 3, so migration of MDBs to EJB 3 is an easy task.

Unlike EJB 2, EJB 3 doesn’t require that your MDB class implement the javax.ejb.MessgeDrivenBean interface, and the deployment descriptor is now optional. You may prefer to use the @MessageDriven and @ActivationConfigProperty annotations instead of the complementary deployment descriptors to activate configuration properties. You can migrate your lifecycle methods to custom methods and annotate them with the @PostConstruct and @PreDestroy annotations. Optionally you can change this such that resources and services use dependency injection instead of JNDI lookup. These migration steps are similar to what we discussed for session beans in section 14.2.2.

This is all that’s involved to update your MDBs for EJB 3! Piece of cake! Simple as pie! OK, now we’re getting hungry...

The story for entity beans is not so bright; this is one of the areas that was completely overhauled for EJB 3. Are you ready to dive into the EJB 3 migration waters for EJB 2 entity beans? You go right ahead to the next section; we’ll meet you there.

14.4. Migrating CMP 2 entity beans to the EJB 3 JPA

Migrating CMP entity beans to the EJB 3 JPA is the most complex and involved migration task we’ll discuss. It requires careful planning and a thorough understanding of your application.

You now know that there are significant differences between CMP entity beans and EJB 3 entities. CMP entity beans are coarse-grained data objects, whereas EJB 3 entities are lightweight domain objects that represent fine-grained data. EJB 3 entities are regular Java classes and lack some features that CMP 2 entity beans provide, such as remoteness, declarative security, and transactions. We agree with the point of view that imposing those features was a bad idea in the first place. However, you’ll have to implement workarounds if you used those features. If you avoided them by using best practices and design patterns, then you are probably in good shape and your overall migration process will be smoother than it would be otherwise.

EJB 2 provided the ability to access an entity bean remotely by using remote interfaces, but design experts recommended against this. As you’ll recall from chapter 12, we recommend you use a session façade as a shield to front entity beans, and use DTOs to transfer data between clients and the server. If you’ve followed these guidelines, it will simplify your migration efforts. Another benefit of using the DAO design pattern is that it may enable you to migrate the persistence tier easily without much impact on the business logic tier.


Signpost up ahead: dead end for BMP entity beans

EJB 2 supported entity beans with bean-managed persistence (BMP), where the code was developed using an API such as JDBC for persisting bean instances. BMP was quite popular initially because CMP implementations from most application servers were not stable. It was also useful when applications required nonrelational data.

However, there are some inherent issues with BMP, such as N+1 problems. Unfortunately, there is no clear migration path for BMP entity beans to EJB 3. This translates into what seems like a dead end for BMP entity beans. As EJB 3 requires support for EJB 2, BMP entity beans will be supported in EJB 3 containers.

If you’re using BMP entity beans with a relational database, we recommend you consider migrating these to use the EJB 3 JPA. Otherwise, you may have a huge support issue lurking in your code base!


14.4.1. Redesign your domain model

You should seriously consider redesigning your domain model when migrating your CMP applications to EJB 3. CMP entity beans lacked support for OO features such as inheritance and polymorphism. Entity beans were mere representations of fragments of your database schema. Thus, in the OO purist’s lingua franca, your domain model was probably anemic; let’s see what we can do about that!

During your migration to EJB 3 JPA, you probably want to consider refactoring your entities to take advantage of the object-oriented features supported by the EJB 3 JPA. For example, assume that when ActionBazaar was built using CMP 2 it had an entity bean named UserBean that was a representation of the USERS table. Listing 14.1 shows the source code for this UserBean entity bean class.

Listing 14.1. User CMP entity bean using EJB 2

While migrating the application, we looked at the ActionBazaar system and found that there could be different kind of users, such as Bidder, Seller, or Admin. Therefore, rather than migrating the entity bean to EJB 3, we used inheritance and a single-table-per-entity hierarchy, as shown in listing 14.2.

Listing 14.2. Remodeled User entity with inheritance

Figure 14.4 shows the results of the entity refactoring.

Figure 14.4. While migrating EJB 2 entity beans to EJB 3, it is likely you’ll want to refactor to take advantage of features like OO inheritance support. In our example, the UserBean entity bean can be refactored into a User POJO entity superclass and Bidder, Seller, and so forth entity POJO subclasses.

Note that remodeling the entities did not require any changes in the database because we used a single-table-per-entity strategy, and we used the existing USER_TYPE column as the discriminator.

You should carefully plan and execute such a refactoring; it requires more work and testing of your applications than just migrating your CMP entity beans to entity classes as is. But the payoff in maintenance costs can be more than worth that extra work if done correctly.

In the next few sections, we’ll focus on strategies that allow you to migrate entity beans to a JPA entity without doing any redesign.

14.4.2. Using DTOs as entities

The DTO is a commonly used design pattern. The specific benefit with respect to entity beans is that it allows the transfer of data back and forth between remote clients and entity beans in EJB 2. There are two types of DTOs: fine grained and coarse grained. The fine-grained DTO often has a one-to-one mapping between an entity bean and a DTO. The coarse-grained DTO represents data from multiple entity beans and is also known as the View object. In reality, a fine-grained DTO looks like a real domain object, just without any behavior; only the state of the object is represented.

Chapter 9 explained that this use of a DTO is no longer required because entities themselves are POJOs that can be transferred between clients and servers. If you used the DTO design pattern and are looking to migrate your entity beans to EJB 3 without spending any effort on remodeling, then you should consider making each DTO a candidate for an EJB 3 entity class.

Assume that ActionBazaar used the DTO design pattern. Listing 14.3 shows a sample of a fine-grained DTO named UserDTO that maps to a UserBean entity bean.

Listing 14.3. A DTO for the UserBean CMP

Reviewing UserDTO in listing 14.3, it looks more like an entity. It’s a POJO; it has a constructor , fields , and properties required for the persistent attributes defined. It even has a relationship defined to another DTO that you can use as a basis for relationships between entities. It’s worth considering making this class an entity rather than migrating the abstract entity bean class in listing 14.1 to an entity. You can make the DTO an entity by simply annotating it as an entity with the @Entity annotation, and defining the O/R mapping from your vendor-specific deployment descriptor to either metadata annotations or orm.xml. Following is the UserDTO (renamed to User) converted to an entity with a few JPA annotations:

@Entity
@Table(name = "USERS")
public class User implements Serializable {
@Id
@Column(name = "USER_ID")
private String userId;
private Date birthDate;

...
}

You have to make sure that you have defined all persistence fields in the entity class by cross-checking the persistence fields defined in the deployment descriptor with your entity bean. You’ll also need to migrate the ORM metadata from the vendor-specific deployment descriptor, to either mapping annotations in the entity class or to a mapping file. After you migrate the finder methods and select methods to named queries, you’re almost done!

The last step is to recall that your entity beans may have some business logic in the business methods. You have to migrate any business methods from the entity bean to the entity class, or to a session bean façade, as we describe next.

14.4.3. Entity bean classes and interfaces

If your applications have not used DTOs, then we’re afraid you’re in for a lot of monotonous work as you migrate your entity beans to entities. We hope it’s evident from listing 14.1 that since the entity bean class and all methods are abstract, you’ll have to convert the bean class to a concrete class with a constructor and define persistence fields as well as the obligatory getter/setter methods. The first step in migration will be similar to creating a DTO for your entity bean and annotating it with @Entity.

Persistence fields are actually defined in the EJB deployment descriptor. Migrating all the fields to your bean class and creating the appropriate fields and getter/setter methods in the entity class is required since we’re relying on dependency injection to help us out at runtime. You should be able to find some development tools and utilities to help automate these mechanical steps.

Converting interfaces

EJB 2 entity beans required two interfaces: a component (remote or local) interface and a home interface. EJB 3 entities don’t require any framework interfaces, so you can entirely eliminate the interfaces from your entities if you like, or convert your component interface to a business interface for the entity.

Optionally, you can use your component interface as the basis for migrating to an entity. Listing 14.4 shows the local interface for the UserBean entity bean. A quick glance informs us that it will be easy to migrate this interface to an EJB 3 entity. The interface has all get/set methods for the persistence fields and the relationships .

Listing 14.4. Local interface for the UserBean CMP

If you haven’t used a DTO, we recommend you start with the local interface as the basis for creating your entity class.

The home interface in the entity bean serves as the factory method to create, remove, and query bean instances. You can remove the home interface and migrate your finder methods to named queries, as we discuss later in the section. The create and remove methods are replaced with EntityManager operations. Optionally, you can migrate the home interface to be used as a session façade that exposes all factory methods such as create and remove to minimize the impact on client applications. We’ll discuss this in section 14.4.4.

Identifying the primary key

Like the persistence fields, the primary key for CMP 2 is defined in the deployment descriptor. For example, the primary key for the UserBean entity bean is defined in the deployment descriptor as follows:

...
<prim-key-class>java.lang.String</prim-key-class>
<reentrant>false</reentrant>
<cmp-version>2.x</cmp-version>
<abstract-schema-name>User</abstract-schema-name>
<cmp-field>
<field-name>userId</field-name>
</cmp-field>
...
<primkey-field>userId</primkey-field>
...

You identify the primary key of the entity class in EJB 3 using the @Id annotation:

@Id
private String userId;

CMP 2 did not support the automatic generation of primary key values; this required the use of workarounds such as the Sequence Generator pattern, or vendor-specific extensions to either database sequence or table sequence generators. If you happened to use such features, then you must migrate them to one of the primary key–generation strategies that we discussed in chapter 8.

Creating O/R mapping

The ORM metadata such as table and column mapping for EJB 2 entity beans is defined in the vendor-specific deployment descriptor. Move those mappings to entity classes by using the @Table and @Column annotations, as discussed in chapter 8. Optionally, you can move them to an OR mapping file, as discussed in chapter 11.

Lifecycle methods

EJB 2 required you to implement a lot of lifecycle methods—a lot. These methods are template methods and are rarely used. It’s possible that you may have implemented some business logic in these methods. You can migrate the business logic for the lifecycle methods to the entity listener callback methods discussed in chapter 9. Table 14.5 summarizes the methods that you can migrate from EJB 2 lifecycle methods to entity callback methods in EJB 3.

Table 14.5. EJB 2 required implementations of many lifecycle methods. EJB 3 allows you to define lifecycle callback methods. This table lists the corresponding methods for EJB 3 JPA that you can use to migrate an entity bean’s lifecycle methods.

EJB 2 Lifecycle Method

Migrated EJB 3 JPA Entity

ejbCreate

Constructors in the entity class.

ejbPostCreate

A method annotated with @PostPersist.

ejbRemove

A method annotated with @PreRemove.

setEntityContext, unSetEntityContext

EntityContext is not supported in EJB3 JPA. Candidate for removal.

ejbActivate, ejbLoad

A method annotated with @PostLoad as per the application requirement.

ejbPassivate

Candidate for removal.

ejbStore

A method annotated with either @PrePersist or @PreUpdate depending on the application requirement.

If you’re like us, you welcome the move away from all these required lifecycle methods. It’s long overdue!

Finding an alternative to EntityContext

The EJB 2 entity bean provided environment information with the javax.ejb.EntityContext object. EJB 3 entities are no longer components and therefore do not have contexts of their own. This means there is no EntityContext equivalent in EJB 3. You have to migrate the use of EntityContext to one of the appropriate alternatives. One of the most commonly used methods in the EntityContext is the getPrimaryKey method. You can create a business method to expose the primary key of the entity to the caller. As outlined in table 14.3, the setEntityContext and unSetEntityContext methods are now candidates for removal because they are no longer supported.

Business methods

It’s quite possible that you may have business methods in your entity classes that are using JNDI to find other entity beans. Perhaps you are using the ejbSelect method of another entity bean (e.g., ItemBean) in a business method of UserBean. You could migrate this code to the entity class by using a named query of the entity class. This would require grabbing an instance of the EntityManager using JNDI. However, we recommend against the approach of using JNDI code within your entity classes because it will limit its usability to relying on the container. This boils down to a scenario where you cannot test or use it outside the container. We suggest that you take this opportunity to migrate such code to the service layer (i.e., the session façade).

Finder and select methods

If you’ve used CMP entity beans in EJB 2, you know that finder and select methods are defined in the home interface for the entity bean as shown here:

public interface UserLocalHome extends EJBLocalHome {
User create() throws CreateException;
User create(String userId, String firstName, String lastName,
String userType) throws CreateException;

User findByPrimaryKey(String primaryKey) throws FinderException;

Collection findAll() throws FinderException;

Collection findByFirstName(String name) throws FinderException;
}

Notice the two custom finders. The query for the finder methods (findAll and findByFirstName) are defined in the ejb-jar.xml using EJBQL as defined here:

<query>
<query-method>
<method-name>findById</method-name>
<method-params/>
</query-method>
<ejb-ql>select object(o) from User o WHERE o.id = ?1</ejb-ql>
</query>

<query>
<query-method>
<method-name>findByFirstName</method-name>
<method-params>
<method-param>java.lang.String</method-param>
</method-params>
</query-method>
<ejb-ql>
SELECT OBJECT(u) FROM User u WHERE u.firstName LIKE ?1
</ejb-ql>
</query>

The finder methods and select methods in the bean class can be converted to named queries in the User entity class like so:

@Entity
@NamedQueries({
@NamedQuery(
name = "findUserById",
query = "SELECT u FROM User u where u.id=?1"
),
@NamedQuery(
name = "findUserByFirstName",
query = "SELECT u FROM User u WHERE u.firstName LIKE ?1"
)})

public class User implements Serializable {
...
}

While migrating the finder methods to named queries, we have changed the name of the named queries to unique names (findUserById from findById), because named queries are scoped for the persistence units. This is unlike finder methods that can be invoked only on an entity bean instance. You will notice that we have used the simplified syntax of a JPQL query. Optionally, you can migrate your query to an ad hoc or dynamic query in your session façade, but we recommend against that due to the performance reasons we discussed in chapter 13.

Container-managed relationships

In EJB 2.1, relationships are defined in deployment descriptors. Listing 14.5 shows the descriptor elements that define a unidirectional, one-to-one relationship between the User and ContactDetail entity beans, and a one-to-many relationship between the User and Bid entity beans.

Listing 14.5. Container-managed relationship defined in the deployment descriptor

The relationships need to be migrated to the entity class using the appropriate association annotations such as @OneToOne or @OneToMany. Note that we have used Java Generics and changed the association field to a Set from Collection type and such change will require appropriate changes in the client code. The simplified code looks like this:

@Entity
public class User {
@Id
protected String userId;
protected String email;
@OneToOne
protected ContactDetail contactDetail;
@OneToMany(mappedBy = "bidder")
protected Set<Bid> bids;
...
}

@Entity
public class ContactDetail {
@Id
protected Long contactId;
...
}
@Entity
public class Bid implements Serializable {
@ManyToOne
protected User bidder;
...
}

In EJB 2, entity beans supported the concept of container-managed relationships. The container was automatically updating the reverse side of relationships when one side was updated. When migrating your relationships to EJB 3, you have to be aware that you are now responsible for managing both sides of your relationships. For example, if you had the following method in the User entity to update a relationship:

public addBid(Bid bid) {
getBids.add(bid);
}

you’d have to change this code to add the back pointer (i.e., set the relationship from Bid to User) as follows:

public void addBid(Bid bid) {
getBids().add(bid);
bid.setUser(this);
}

As you can see, there’s not a lot of code involved, but the burden of keeping things bidirectional falls squarely on your shoulders now.

Transactions and security settings

CMP entity beans provided the ability to specify transactions and security settings for bean methods. In practice, these were rarely used in favor of the more popular session façade approach. EJB 3 entities don’t provide such facilities, which means that you need to move security and transaction settings to your session façades.

14.4.4. Client applications

In EJB 3, we use the EntityManager API to perform entity operations such as persisting, finding, and removing entities. In EJB 2 the home interface acted as a factory interface to provide methods to create, remove, and find entity bean instances. Clients used these methods to persist, remove, and query bean instances. In the new EJB 3 world, client applications should be modified to use the EntityManager API.

Let’s say we have an EJB 2 newUser method in the BazaarAdminBean that is a session façade used to create an instance of a User entity bean as follows:

public void newUser(UserDTO user) throws
CreateException,
FinderException,
NamingException {

User userLocal = getUserLocalHome().create(
user.getUserId(),
user.getFirstName(),
user.getLastName(),
user.getUserType());
...
}

Our example code uses a DTO named UserDTO. After migration, the client code (where User is an entity) will look much simpler:

public void newUser(User user) {
getEntityManager().persist(user);
}

Similarly, you can migrate other operations, such as removal, or queries to use the EntityManager API. You have to remove the client code to handle exceptions such as CreateException and FinderException that were previously required to be handled in CMP entity beans but are no longer imposed.

Translating entity home to a session façade

It’s fairly effortless to migrate the home interface to a session façade by moving all factory methods such as create, remove, and find to this façade. We first create a UserLocalHome interface:

public interface UserLocalHome {
User create(String userId, String firstName, String lastName,
String userType) throws CreateException;

User findByPrimaryKey(String primaryKey) throws FinderException;

Collection findAll() throws FinderException;

Collection findByFirstName(String name) throws FinderException;
}

This interface is exactly the same as before except it does not extend EJBLocalHome. The session bean implements the UserLocalHome interface and implements all factory methods using the EntityManager API as follows:

@Stateless
public class UserLocalHomeBean implements UserLocalHome {
@PersistenceContext EntityManager em;
User create(String userId, String firstName, String lastName,
String userType) throws CreateException
{
User user = new User(userId, firstName, lastName, userType);

try
{
em.persist(user);
}
catch (Exception e)
{
throw new CreateException(e.getMessage());
}

returnuser;
}

User findByPrimaryKey(String primaryKey) throws FinderException
{
try
{
return (User)em.find(User.class, primaryKey);
}
catch (Exception e)
{
throw new FinderException(e.getMessage());
}
}
}

This code throws the EJB 2–specific exceptions that may be expected by clients. You can use this session bean façade to mimic the home interface, thereby reducing the number of changes required on the client side.

This concludes our discussion on migrating applications using CMP entity beans to the EJB 3 JPA. As we told you at the start of this section, migrating your CMP beans to JPA is the most involved of the tasks you’re likely to undertake when upgrading to EJB 3. Revising your domain model, using DTOs and session facades, and the required API changes will all help you achieve your migration goal. Your EJB 2 applications may already use DTOs and session facades, in which case much of this is familiar to you. Either way, we’ve provided a roadmap that will lead you down the migration trail.

At this point, we know exactly what you’re thinking—OK, what you’re probably thinking. What about all that JDBC code? You guys got any tips for converting it to JPA? It just so happens we do, and if you mosey on over to the next section you can see what these tips are.

14.5. Migrating JDBC DAOs to use the EJB 3 JPA

Almost every Java developer in the universe has used JDBC to persist data to a database. If your code also uses the DAO pattern, then migrating to the EJB 3 JPA may be a relatively painless process.

Migration from JDBC requires three major tasks:

  1. Identify your entities.
  2. Change the DAO implementation classes to use the EntityManager API to perform entity operations instead of using JDBC.
  3. Migrate your SQL queries to use JPQL and the EntityManager API.

These steps are summarized in figure 14.5.

Figure 14.5. The changes necessary to migrate JDBC DAOs to the EJB 3 JPA

The next three sections break down each of these steps, and we provide examples to illustrate exactly what you need to do.

14.5.1. Identifying entities

This is the most challenging task in the migration process and requires a good understanding of your application. The good news is that applications using DAOs don’t have any impact on the business logic tier of the application, and the migration effort is limited only in the persistence tier. If you followed the DAO design pattern religiously, you most likely created value or transfer objects (similar to DTOs) that are used by the business tier to retrieve or update data from the database. A careful look reveals that these transfer objects resemble entities. A little analysis is all that is required to understand the relationship between these transfer objects, allowing them to safely be converted to entities.

Suppose that ActionBazaar initially used JDBC DAOs for persistence and the transfer object BidTO looked similar to listing 14.6.

Listing 14.6. Bid transfer object used with a DAO

If you look at the code for BidTO carefully, it looks surprisingly similar to the Bid entity that we discussed in chapter 2. It even has references to the associated transfer objects. The only difference is that it does not have JPA annotations. You can use JPA annotations to convert your transfer objects to entities. The steps are similar to those we listed in section 14.4.2 when we discussed considering DTOs to be entities. Next you’ll see how to make the switch to the EntityManager.

14.5.2. Reworking a DAO implementation class to use the EntityManager API

The database-specific implementation class has JDBC code to persist the value or transfer object to the database. Assume that the BidDAOImpl class uses JDBC to persist and retrieve data. The next step in the process is for you to migrate the JDBC code to use the EntityManager API.

  1. Replace the code that opens and closes JDBC connections to obtain an instance of an EntityManager. For example, your BidDAOImpl class has a method that returns a database connection. You can change that method to return an EntityManager instance.
  2. Replace your SQL INSERT/UPDATE/DELETE statements to use the EntityManager API. For instance, one of BidDAOImpl’s methods has an INSERT statement that creates an instance of Bid in the database, as seen here:
    private final static String INSERT_BID_QUERY_STR =
    "INSERT INTO BIDS " +
    "(BID_ID,BIDDER_ID,ITEM_ID,BID_STATUS,BID_PRICE) " +
    "VALUES (?, ?, ?, ?, ?)";

    private void insertBid(BidTO bid) {
    ...
    stmt = dbConnection.prepareStatement(INSERT_BID_QUERY_STR);

    stmt.setLong(1, bid.getBidId());
    stmt.setString(2, bid.getBidder().getUserId().trim());
    stmt.setLong(3, bid.getItem().getId());
    stmt.setString(4, bid.getStatus().trim());
    stmt.setDouble(5, bid.getBidPrice());
    }

After migrating the JDBC code to use the EntityManager API, the migrated code will look like this:

private void insertBid(Bid bid) {
...
em.persist(bid);
}

Wow! Can you believe that? Similarly, you can use the em.remove and em.merge methods to migrate the JDBC code for remove or update operations. Next we’ll explain how you can migrate your SQL SELECT statements to use JPQL.

14.5.3. Swapping SQL queries for JPQL

Although it may be a little difficult to let go, you have to remember that there are no equivalents for ResultSet and Rowset in the EJB 3 JPA. Most typical applications use SQL statements to retrieve data and construct transfer objects, which are returned to the client instead of returning a ResultSet. Not following the DAO and Transfer Object design patterns will mean additional work for you.

Listing 14.7 shows a method in the BidDAOImpl class that returns a list of BidTOs by retrieving a ResultSet from the database.

Listing 14.7. Method that returns a list of transfer objects to the client

The method in listing 14.7 constructs a list of transfer objects of type BidTO by executing a JDBC SQL statement and returns them to the client. Assuming you have created an entity named Bid that corresponds to the BidTO transfer object, you can easily migrate this method to use JPQL and the EntityManager API. You can use a dynamic query in the getBids method as follows:

public List getBids(Long itemId) {
Item item = (Item)em.find(Item.class, itemId);
Query query =
em.createQuery("SELECT b FROM Bid b WHERE b.item = ?1");
Query.setParameter(1, item);
return query.getResultList();
}

However, we recommend using a named query instead of a dynamic query, and moving the JPQL statement to the Bid entity as a named query like this:

@Entity
@NamedQuery(
name = "findBidsByItem",
query = "SELECT b FROM Bid b WHERE b.item = ?1")

public class Bid implements Serializable {
...
}

Use the named query in the getBids method of the BidDAOImpl class:

public List getBids(Long itemId) {
Item item = (Item)em.find(Item.class, itemId);
Query query = em.createNamedQuery("findBidsByItem");
Query.setParameter(1, item);

return query.getResultList();
}

If you look at the migrated methods (insertBid in section 14.5.2 and getBids) and compare them with the original methods in BidDAOImpl, they should look much simpler. You can follow our guidelines to migrate all your JDBC DAO code to use the EJB 3 Persistence API with very little impact on the business tier of your applications. Don’t you just love it?

Next we tackle migrating applications that currently use O/R frameworks over to our new friend, the EJB 3 JPA.

14.6. Helping O/R frameworks to use the EJB 3 JPA

EJB 3 persistence is the result of a lot of hard work between individuals; vendors of major O/R mapping solutions such as Hibernate, TopLink, and JDO, and countless others. If you’ve ever used any of these frameworks, you know that the EJB 3 JPA looks an awful lot like your favorite O/R framework, which will make it easier for you to migrate to EJB 3 from an existing O/R solution. Covering detailed migration steps from each of these persistence solutions is out of the scope of this book. However, we will provide some generic steps for migrating applications that utilize O/R frameworks to convert to the EJB 3 JPA.

The EJB 3 JPA is now the standard API to build the persistence tier for applications. Each of the persistence providers will provide some mechanisms to facilitate migration to EJB 3. Check your vendor documentation for tools or utilities to ease the migration process.

If you are using an O/R framework, it is assumed that you’ll migrate an existing domain model to the EJB 3 JPA. Migration of applications using proprietary O/R solutions will involve three or four major steps:

1.  

Migrate proprietary mapping metadata to use the EJB 3 JPA O/R mapping annotations or orm.xml. Check your vendor’s documentation to see if they provide any tools to assist in this effort.

2.  

Migrate vendor-specific APIs (e.g., Hibernate’s Session API to perform CRUD operations) to use the EntityManager API. Table 14.6 shows what the migrated code will look like when you migrate from two popular frameworks.

Table 14.6. Comparison of application code to persist an instance of an entity with two popular O/R frameworks

Hibernate (from this)

Session sess = sessions.openSession();
Transaction tx = sess.beginTransaction();
sess.save(category);
tx.commit();
sess.close();

TopLink (or from this)

UnitOfWork uow = session.acquireUnitOfWork();
uow.registerObject(category);
uow.commit();

EJB 3 (to this)

ut.begin();
em.persist(category);
ut.commit();

3.  

You have to migrate both dynamic and named queries from any vendor-specific query language to use JPQL. For instance, if you are using JDO for O/R mapping and you have the following code using JDO QL:

Query query = pm.newQuery("SELECT FROM " +
"actionbazaar.buslogic.User WHERE firstName == :firstName");

List<User> people = (List<User>)
query.execute(firstName);

you will need to revise it to this:

Query query = em.createQuery(
"SELECT u FROM User u WHERE u.firstName = :firstName");
query.setParameter("firstName", firstName);

List<User> = (List<User>)query.getResultList();

4.  

This is an optional step depending on how many advanced features you are already using. If you’ve used any vendor-specific features such as caching, you’ll need to configure those features as properties in persistence.xml, or potentially as queryHints in your JPQL.

Your conversion efforts should take into account the fact that many persistence providers have been around for years and provide numerous features not supported in the EJB 3 JPA. Your application may be working with some features from a persistence provider that may not have an equivalent in the EJB 3 JPA. It is anticipated that most EJB 3 persistence providers will allow mixing such features with the EJB 3 JPA. You’ll have to decide whether continuing to use these vendor-specific features is worth more than remaining in compliance with the specification.

This brings to a close our discussion on migrating O/R frameworks to EJB 3 JPA. Next we’ll take a quick look at some overall project-level approaches targeted at easing the course of migration.

14.7. Approaches to migration

Like any software development project, migrating your applications to use EJB 3 may be quite challenging. A thorough understanding of your applications and knowledge of EJB 3 is required. If you’re migrating EJB 2 applications to EJB 3, you have to understand that other applications may have a dependency on your application. Making the jump to EJB 3 may break the dependent applications, because the client view of EJBs has changed.

14.7.1. Strategies

Depending on the size of your applications, and the number of applications you plan on upgrading, the strategy you choose could have a big impact on your success. You may go for either a phased approach or an all-at-once approach, depending on your comfort level with your code base and the availability of resources. An incremental approach may be better suited for most applications if you aren’t comfortable with the technology. It allows you to validate the technology, gives you firsthand experience through trial and error, and has minimal impact on the complete application.

Our advice is that you consider an agile approach to migration, and properly test your application after migrating only a small portion. Testing as you go along will give you confidence that you are on the right track, and let you know fairly quickly if you’ve gone off the rails. Of course, there are situations where it may not be practical to follow an incremental migration strategy. Only you know the capabilities of your team, your corporate culture, and the unique pressure associated with keeping your applications in a production-ready state.

14.7.2. Manual vs. automated

It is evident from our earlier discussions in this chapter that migration is mostly a mechanical and boring chore, and finding the right resources for such a task may be challenging. We certainly expect that many development tools will emerge promising to automate 100 percent of the migration workload. However, we recommend that you not rely completely on such tools. Tools can certainly simplify the migration process, but will require some degree of guidance so that your knowledge of your applications is taken into consideration during the process.

Tools can ease your task in converting classes to use EJB 3, but the resulting application may not be foolproof due to the scores of changes in the programming model between EJB 2 CMP entity beans and the EJB 3 JPA. We suggest you try migrating a part of your application with the tool and then examine the entire application to determine whether it behaves as expected. In many cases, you’ll want to change your domain model. In such situations your intervention will most likely be required because you are the only one who can make these decisions.

14.8. Summary

This chapter examined the major issues related to interoperability, compatibility, and migration to EJB 3. The EJB 3 specification requires backward compatibility with EJB 2. You learned how you can mix-and-match EJB 2 and EJB 3 components in the same applications, as well as convert applications completely over to EJB 3. We provided guidelines for migrating each EJB 2 component to EJB 3.

Migration of session beans and MDBs to EJB 3 is easy but still requires you to carefully plan the process because client applications may break due to changes in the client view of EJBs between EJB 2 and EJB 3. Migration of CMP entity beans is the most difficult task, but you can simplify the migration if you use design patterns such as DTO, Session Façade, and DAO.

This chapter also explained how to convert JDBC DAOs to use the EJB 3 JPA. Finally, you saw that the migration from using existing O/R mapping frameworks to using the EJB 3 JPA is a very straightforward task. With these guidelines and a good knowledge of your applications, you will have no problem migrating your applications to use EJB 3.

In the next chapter, you’ll learn how to expose EJBs as web services, and how to invoke web services from EJB applications.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset