Extended Persistence Context in Stateful Session Beans

by Mahesh Kannan

The Java Persistence Architecture, a part of the Enterprise JavaBeans 3.0 (EJB 3.0) specification, simplified the development of EJB applications using data persistence. A major simplification was the introduction of the EntityManager interface for accessing a database and creating, removing, or updating entities within a transaction. Entities are objects that represent data in a database. They are persistent in the sense that they exist even after the application that created them ends. To foster entity persistence an entity manager interacts with the persistence context, which the Java Persistence Architecture defines as:

A set of managed entity instances in which for any persistent entity identity there is a unique entity instance. Within the persistence context, the entity instances and their lifecycle are managed by the entity manager.

The Java Persistence Architecture also states that a container-managed persistence context, that is, a persistence context whose life cycle is managed automatically by the container, may be defined to have either a lifetime that is scoped to a single transaction or an extended lifetime that spans multiple transactions. The lifetime scope depends on the type specified in the PersistenceContextType class when an entity manager is created.

In the case of a container-managed persistence context that is scoped to a single transaction, the persistence context ends when an associated transaction commits or is rolled back through the Java Transaction API (JTA). By comparison, a container-managed persistence context that has an extended lifetime begins when a stateful session bean is created and ends only when the stateful session bean is removed from the container. The extended persistence context is said to be bound to the stateful session bean. Note that only stateful session beans can have a container-managed, extended entity manager.

One of the important distinctions between a transaction-scoped persistence context and that of an extended persistence context is the state of the entities after a transaction completes. In the case of a transaction-scoped persistence context, the entities become detached, that is, they are no longer managed. In the case of an extended persistence context, the entities remain managed. In other words, all operations, such as persist, that are done outside of a transaction are queued and committed when the persistence context is attached to a transaction (and when it commits). This makes an extended persistence context ideal for modeling a conversation with a user that spans many interactions. You can accomplish the same thing with a bean-managed transaction that spans the entire user conversation. You start this transaction with the UserTransaction.begin() method. However, this alternate approach is more complicated than taking advantage of an extended persistence context.

This Tech Tip illustrates an application that uses a stateful session bean and an entity manager with an extended persistence context. The application handles travel reservations -- it allows a user to book airplane flight and rental car reservations for a trip. A sample 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).

A Trip Reservation Application

The application for this tip presents a simple web page that allows a user to make trip reservations.

Trip Reservation Page
 

A trip reservation involves booking airline or car reservations for the trip. A user makes a trip reservation by specifying a departure and destination location, selecting the dates for the trip, and then choosing an airline or a car. The user then selects the Book It button to confirm the booking of a rental car or airplane flight, respectively. The user can make multiple bookings for the trip. The user then confirms his or her selections by clicking the Confirm button.

If you examine the source code for the application, you'll notice that a servlet, ControllerServlet, presents the reservation web page. The servlet uses a stateful session bean, BookingControllerLocalBean, to maintain the conversational state of the application. The stateful session bean uses a container-managed extended persistence context to manage the entities. Note that the default transaction attribute for all methods other than confirmBooking() in the application is NOT_SUPPORTED.

The following code in BookingControllerLocalBean injects a container-managed extended persistence scope:

   @PersistenceContext(type=PersistenceContextType.EXTENDED)
   private EntityManager em;

Beginning a Trip Reservation

The servlet begins the trip reservation process by calling the startBooking() method in BookingControllerLocalBean. Here's the call in the servlet to the method:

   bookingController = (BookingControllerLocal) (new InitialContext()).lookup("java:comp/env/ejb/BookingController");
   session.setAttribute("bc", bookingController);
   tripId = bookingController.startBooking();

And here is the startBooking() method in BookingControllerLocalBean:

   public Trip startBooking() {
       this.trip = new Trip();  // Create a new Trip
       em.persist(trip);

       return trip(); //Return the Trip which is an Entity
    }

Again note that because this application uses an extended persistence context, the entity Trip remains managed even though the methods are called without a transaction.

Handling Flight and Car Reservations

When the user requests a flight or a car reservation, the servlet calls the doBooking(Booking b) method in BookingControllerLocalBean. This method calls the em.persist method to make the entity persistent. The method then adds the Booking entity to the Trip entity as follows:

 trip.getBookings().add(b);
        b.setTrip(trip);

Note that the doBooking() method is not called within a transaction. Because of that, the entities are not flushed to the database, but rather remain managed by the entity manager. This makes it possible to modify the Booking object even after the doBooking() method is called. By comparison, if this application used a transaction-scoped entity manager , it would have to call em.merge() at the beginning of the next transaction to again have the entity manager manage the entity. However, because the application uses an entity manager with extended persistence scope the entities remain managed even after a transaction commits.

Here is the complete code for the doCarBooking() method:

   public void doBooking(Booking b) {
       em.persist(b);

       trip.getBookings().add(b);
       b.setTrip(trip);
   }

Displaying the State of a Trip Reservation

The servlet displays all the Booking entities in a trip by calling the bean's getAllBooking() method in BookingControllerLocalBean. This method does not fetch data from the database. Instead it fetches the collection of Booking entities within the Trip entity.

Here is the code for the getAllBooking() method. .

   public List<Booking>getAllBookings() {
       return trip.getBookings();
    }

Completing the Trip Reservation

When the user clicks the Confirm button, the servlet calls the confirmTrip() method in BookingControllerLocalBean. This method doesn't do anything:

   @TransactionAttribute(TransactionAttributeType.REQUIRED)
   public void confirmTrip() {
      em.flush();
   }

However, because the method executes within a transaction, the container automatically associates the extended persistence manager with the transaction. When the method completes, the container commits the transaction and the entity manager flushes the entity's state to the database.

Running the Sample Code

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

  1. Download the sample package and extract its contents. You should see an enterprise archive named techtip3.ear.

  2. If you haven't already done so, download and install GlassFish v2. Start GlassFish v2 by entering the following command on a command line:
       <glassfish_install_dir>/bin/asadmin start-domain
    

    Where <glassfish_install_dir> is the directory in which you installed GlassFish v2.

  3. Start the Java DB database server that is packaged with GlassFish v2 by entering the following command on a command line:
       <glassfish_install_dir>/bin/asadmin start-database
    

    Where <glassfish_install_dir> is the directory in which you installed GlassFish v2.

  4. Deploy techtip3.ear in GlassFish v2. You can do this various ways. One way is to enter the following command on a command line:
       <glassfish_install_dir>/bin/asadmin deploy techtip3.ear
    
  5. Open your browser to the following URL: http://localhost:8080/techtip3-war/TripController. You should see the trip reservation web page.

Summary

This tip showed an example that uses a container-managed entity manager with an extended persistence context to a handle a long conversation that spans multiple interactions with a user. The example also showed that intermediate user interactions do not have to be handled within a transaction, and how this type of entity manager is flushed when the transaction completes.

About the Author

Mahesh Kannan is member of the EJB container team. He has been involved with Java EE development for the last 7 years.

----------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Try GlassFish

Connect and Participate With GlassFish
Try GlassFish for a chance to win an iPhone. This sweepstakes ends on March 23, 2008. Submit your entry today.


Comments:

Hello, imagine you were trying to do the same thing in a fat java client talking to an EJB server, but this time talking to a stateless session bean.

Is the following how you would do it

Client Code:
trip=bookingController.startBooking();
....
booking=new Booking();
booking.addTrip(trip);
...
booking=bookingController.addBooking(trip,booking);
trip.getBookings().add(b);

Server Code:
public Trip startBooking() {
this.trip = new Trip();
em.persist(trip);
return trip;
}

public Booking addBooking(Trip trip, Booking b) {
em.persist(booking);
trip.addBooking(booking);
trip = em.merge(trip);
return booking;
}

Its seems like hard work keeping the two in sync. But I still love JPA.

-Cormac

Posted by Cormac on February 19, 2008 at 04:52 AM PST #

Great entry. It nicely describes the purpose of the extended persistence context and how it differs from the transaction-scoped persistence context. I think a lot of people are still confused about how a switch to an extended persistence changes the dynamic of their session bean.

This entry also sets the stage nicely for Seam, which makes management of the persistence context and fear of exceptions related to intermixing extended and transaction-scoped persistence contexts something you no longer have to worry about.

Posted by Dan Allen on May 01, 2008 at 04:17 PM PDT #

Where do I get this techtip3.ear? I can't see the link anywhere...

Posted by veggen on March 30, 2009 at 11:31 PM PDT #

@veggen: The techtip.ear file is in the sample package (ttfeb2008eem.zip)

Posted by Edward Ort on March 31, 2009 at 01:36 AM PDT #

nice article!
i've problem about stateful sessionbean.
is there is some way to share the same sessionbean in different servlet?
i mean, if i have two servlets can i use the same instance of sessionbean for those servlets? how? should i pass the sessionbean reference to the servlet's session so i can reuse it in other part of application? or there is other option to do?

Posted by simaremare on November 18, 2009 at 12:53 PM PST #

Post a Comment:
Comments are closed for this entry.
About

edort

Search

Archives
« April 2014
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today