BT

Facilitating the Spread of Knowledge and Innovation in Professional Software Development

Write for InfoQ

Topics

Choose your language

InfoQ Homepage News Java EE6: EJB3.1 Is a Compelling Evolution

Java EE6: EJB3.1 Is a Compelling Evolution

Leia em Português

This item in japanese

The Enterprise Java Bean 3.0 (EJB 3) specification marked a very important way-point in the long march of Java in the enterprise. The specification was built very apparently with input from the community. It represented a much more consistent services paradigm, one that was more POJO-friendly and generally less complicated. The level of indirection afforded by Java 5's annotations made the paradigm more powerful while requiring less of the developer. The willingness to forsake bad legacy decisions for different, new solutions, made the framework interesting to people who might have previously shunned EJB. EJB Entity Beans disappeared, replaced with JPA Entities. The handful (or more) of Java classes and interfaces required for your average bean in EJB 2.1 or before became 2+ Java classes or interfaces. Convention-over-configuration based defaults were put into place to make it more straightforward to get up and running. EJB 3.0 was a revolution.

If EJB 3.0 was a revolution, EJB 3.1 is a very capable, welcome evolution. EJB 3.1 features a raft of features that feel like they should have been available in EJB 3.0. One can forgive the cautious pace of the specification - better to get 80% right than to freeze an imperfect model into the glacial evolution of a specification. Its arrival isn't unwelcome, of course. It is also telling that - even with all these new features - the EJB 3.1 specification and all the backwards compatibility and additions that if offers - is 626 pages, 14 pages shorter than the EJB 2.1 specification from almost a decade ago!

We will review some of these features in this post, and address their use.

New Features in EJB 3.1

Some of the biggest changes in EJB 3.1 are not additions to the platform, but reductions in the required ceremony in using the platform. Some increase the surface area of the user-facing APIs to introduce more flexibility. Some simply bring more flexibility.

Singletons

A singleton is a new type of session bean that provides one extra guarantee: the bean will only be created once per running JVM. There are many use cases that are better served with this feature: caching, for example. Another is the ability to guarantee a shared view on a resource that the application server doesn't already provide. Simple storage for valuable data that needn't be persisted but that might be too expensive to recreate is another option. Let's look at a (contrived) example. We'll assume that the User entity has already been created elsewhere (perhaps using the JPA 2.0).

@javax.ejb.Singleton 
public class ChatRoom { 

   private java.util.Map<User,Collection<String>> userComments; 

   @PostConstruct 
   public void setup (){ 
     userComments = new java.util.concurrent.ConcurrentHashMap<User,Collection<String>>(); 
     /* ...*/
   }
   public void join(User usr){ /* ...*/ }
   public void disconnect(User usr){  /* ...*/ }
   public void say(String msg){ /* ...*/  }
}

All clients can update the same mutable state by simple acquiring a reference to the ChatRoom instance. Clients are guaranteed access to the same instance upon acquisition. As this is a session bean, it offers the same guarantees as any other session bean: this bean is fully thread safe.

@javax.ejb.EJB 
private  ChatRoom  chatRoom ; 

 /* ... */

chatRoom.join(myUser) ;
chatRoom.say( "Hello, world!");
chatRoom.disconnect();

Singletons are designed for concurrent access. The specification gives the developer sophisticated control over concurrency control. You may use the container to force certain types of access in a declarative way. This behavior is the default. You may explicityly declare as using container-managed concurrency by annotating it with @javax.ejb.ConcurrencyManagement(CONTAINER). If you want to exert more control over the bean, use @javax.ejb.ConcurrencyManagement(BEAN). Container-managed concurrency lets you stipulate the type of access at the method-level or class-level. You might by default stipulate that all business methods are to be serialized by using @javax.ejb.Lock(WRITE) at the class level and then optimize for the case where a method is effectively "read-only," with no state-modifying side-effects. You would annotate that read-only method with @Lock(READ). All access on a method annotated with @Lock(WRITE) is serialized, and blocks client access until completion, or a timeout occurs. You may exercise control over the length of a timeout using the @AccessTimeout annotation, which takes a value of java.util.concurrent.TimeUnit. Thus, we might be able to rework the code in the first implementation of the ChatRoom to take advantage of this concurrency control.

@javax.ejb.Singleton 
@javax.ejb.Lock(WRITE)
public class ChatRoom { 

   private java.util.Map<User,Collection<String>> userComments; 

   @PostConstruct 
   public void setup (){ 
     userComments = new java.util.concurrent.ConcurrentHashMap<User,Collection<String>>(); 
     /* ...*/
   }
   public void join(User usr){ /* ...*/ }
   public void disconnect(User usr){  /* ...*/ }
   public void say(String msg){ /* ...*/  }

   @javax.ejb.Lock(READ)
   public int getCountOfActiveUsers(){ /* ... run through the map and count ... */ } 
}

Naturally, such a ChatRoom will ultimately die a memory starved death as the number of users and posts overwhelms the application server's memory. Some sort of expiration mechanism is in order. For the sake of demonstration, let's imagine a periodic garbage collector that runs through the ChatRoom posts and LRU destroys (or, perhaps using JPA and the EntityManager. persists and then destroys) old chat data.

The EJB Timer

EJB has had a Timer mechanism since EJB 2.1. However, it's always worked in terms of millisecond intervals and been fairly tedious to set up. The situation was a bit improved with EJB 3.0, but the fact remained that timers were still essentially procedurally declared and interval-based. If you want to set something up at the beginning of the week, for example, then you faced challenges. EJB 3.1 improves things by providing a declarative, flexible timer service that pulls the rug out from under various other schedulers like Quartz or Flux. For most simple scheduling needs, including CRON-like scheduling, EJB 3.1 is a fine solution. Let's revisit our ChatRoom. We want to schedule a bean to go through and garbage collect old data.

@javax.ejb.Singleton 
public class ChatRoom {

   private java.util.Map<User,Collection<String>> userComments;
        
   @javax.ejb.Schedule(minute="1", hour="*") 
   public void cleanOutOldDataFromChatLogs() { 
      /** ... not reprinting all the existing code ... */
   }
}

We've written a method that will go through and run a quick check on the data and - as necessary - expunge old /irrelevant chat logs so that we can keep things manageable. Here, we're using a declarative model to ensure that the method runs every hour. We could, of course, still inject the TimerService from EJB 3.0.

No-Interface Views

In EJB 3.0 beans were required to support at least one interface (a local or remote business interface) that would be used as the view of the bean to the clients of that bean. While indirection via interfaces is a very powerful technique, it sometimes just complicates things. In EJB 3.1 you may write a bean that has no interfaces. The client view is then the public methods as exposed by the class.

@javax.ejb.Stateless 
public class Calculator { 

  public float add ( float a , float b) { 
    return a + b; 
  } 

  public float subtract (float a , float b){ 
    return a - b ; 
  }

} 

Clients of this bean may simply accquire as usual with injection and invoke it:

@javax.ejb.EJB 
private Calculator calculator; 

...
float result = calculator.add( 10 , 10 ) ;
...

Asynchronous Services

The simple way to handle scaling issues is... to simply not handle them (until capacity is available)! This approach is most famously characterized by the SEDA (staged event driven architecture) pattern, wherein bottlenecks are avoided by queuing work. This lets submissions of work being queued and the client proceed. If a component downstream takes a long time, and the system is under load, this pattern ensures that the slow component doesn't bring the system to its knees.

Another approach to scaling is to not block client invocations on one-way message exchanges. Another approach still is to simply work asynchronously, letting execution on the client proceed until a result comes back. All of these approaches are embodied in the new asynchronous support for services in EJB 3.1. A bean class, or individual methods, may be annotated with the @javax.ejb.Asynchronous annotation to tell the container that clients should not block on the result of the invocation. This lets the client proceed instantaneously, and - in theory - it would enable a container to buffer the work until it's better able to perform it.

If a bean class, or a business interfaces, is annotated with @Asynchronous, then all methods on the bean are deferred. Otherwise, only methods that are annotated with @Asynchronous are deferred. Asynchronous methods may return void, or an instance of java.util.concurrent.Future<V>. The client may consult the instance of Future<V> for the result at any time later, but the result of the invocation proceeds instantly in the client thread, and doesn't block. This way, if the EJB takes an hour or two, then it doesn't matter - the client is unaffected. Conceptually this is the same as calling a service with the sole job of sending the request to a JMS queue.

The instance of Future<V> may be used to cancel the job, or wait for the result. A client's transactional context is not propagated to the asynchronous method. REQUIRED, then, is effectively REQUIRES_NEW for the asynchronous method.

Let's take a look at an example: we want to build a service that talks to several other web services and aggregates the results. We want the results, but we can't leave the client request (a web page, perhaps?) hanging. Such a service might look as follows:

@javax.ejb.Stateless
public CarHotelAndAirLineBookingServiceBean implements CarHotelAndAirLineBookingService  {
  @javax.ejb.Asynchronous  
  public Future<BookingConfirmation> bookCarHotelAndAirLine( Car rental, Hotel hotel, AirLine airLine) { 
    /**  ...  */
   } 
 } 

In the client - a JSF action - we might invoke such a service as follows:

@Named 
public BookingAction { 

        @javax.ejb.EJB  private  CarHotelAndAirLineBookingServiceBean bookingService; 

        private Future<BookingConfirmation> confirmation;

        public String makeRequest(){ 

                Hotel hotelSelection = ... ;
                Car rentalSelection = ... ;
                AirLine airLineSelection = ... ; 

                confirmation = bookingService.bookCarHotelAndAirLine(
                    rentalSelection, hotelSelection, airLineSelection ) ; 
                return "showConfirmationPending";
        }

        public Future<BookingConfirmation> getConfirmation(){ /* ... */ }

        /* ... */
}

Simplified Deployment

EJB 3.1 also marks the first version of the specification to provide a dramatically simpler deployment paradigm with support for deployment inside a in .WAR file. A class with a component-defining annotation becomes an enterprise bean component when packaged within WEB-INF/classes or as a .jar in WEB-INF/lib. Enterprise beans may also be defined using a WEB-INF/ejb-jar.xml file. Beans packaged in a .WAR share a single namespace, and become part of the .WAR's environment. Packaging a .jar in WEB-INF/lib is thus semantically equivalent to putting the classes in WEB-INF/classes.

Another novel feature of the new specification is EJB Lite. For many applications, EJB technology is more than is required. EJB Lite provides a more streamlined subset centered around the use of session-bean components. It provides a way to use EJB components in an embeddable fashion, too, which simplifies unit tests. EJB Lite supports stateless, stateful and singleton session beans. Beans may have a local-, or no-interface view. They may work with interceptors, and use container services like transactions and security.

EJB 3.1 is a powerful tool in the developers toolkit, and is clearly being evolved into something that'll meet the 80% use cases of most applications. The future looks good for the specification. This is also the first release of the specification to target certain specification features for future removal using the Java SE pruning mechanism. Aspects of the specification that have been marked for possible future removal include pre-3.0 support for older forms of container-managed and bean-managed persistence, the EJB 2.1 client view of entity beans, EJB QL (the query language from EJB 2.1), and JAX-RPC based web service support (both endpoints and client views; they were added in J2EE 1.4)

Clearly, EJB 3.1 is a compelling, backwards-compatible upgrade, and represents a fine next step from the work started in JSR 220 (EJB 3.0) more than 5 years ago.

Rate this Article

Adoption
Style

BT