Interface-based programming is clearly a useful technique in writing loosely-coupled, unit-testable applications. That is precisely why both EJB 2.1 and Spring promote the idea of component interfaces. In fact, at least one interface is required even for EJB 3.0 Session Beans (this is not a requirement for EJB 3.0 Message Driven Beans).
The trouble is that component interfaces are just a needless abstraction in a lot of circumstances. I can't remember the times I silently cursed under my breath as I carried out the mechanical task of writing interfaces just because the framework needed it or the architect sitting in some ivory tower mandated it. A lot of times, just a regular Java object is really all you need for your foreseeable needs, especially if you don't really do much unit testing and loose-coupling is just not enough of a concern for the application.
EJB 3.1 allows you to do just that. Now you do not need any interfaces for Session Beans, just like JPA Entities and Message Driven Beans. All you have to do is annotate a POJO with the @Stateless or @Stateful to get a fully functional EJB. Take a look at the example below modified from the Session Bean chapter in EJB 3 in Action:
In the above example, we are using JAX-WS 2.0 to expose the simple little placeBid method as a web service. We're also using JPA to persist a Bid entity. PlaceBidBean has the full range of Stateless Session Bean functionality available behind-the-scenes including pooling, thread-safety, component life-cycle, interceptors, security and declarative transactions. For example, as you might have guessed if you are familiar with EJB 3.0, the placeBid method is wrapped in a container-managed JTA transaction by default. RMI-based remoting will also be supported for these beans, although the exact semantics hasn't been solidified yet.
Besides making it easy to get going with simple bean classes, dropping the interface requirements also makes using EJB 3.1 beans in WebBeans easy. Gavin King is leading the WebBeans JSR (JSR 299), largely inspired by the lessons in JBoss Seam. WebBeans is expected to make JSF, JPA and EJB 3.1 virtually seamless (no pun intended) and make Java EE 6 truly feel like a fully integrated stack.
EJB 3.1 Singleton Beans are the middleware equivalent of the GOF Singleton pattern. In the Java EE context, they are primarily used to store application-wide shared data.
Think about all the times you needed to cache some data in memory so you didn't have to do the same old database lookups over and over again from different parts of the application. Neither Stateless Session Beans nor Stateful Session Beans meet this need. While Stateful Session Beans can maintain a session cache, it can't really be shared amongst the application tier components very easily.
There are various ways of solving this problem now. The simplest way is to use static fields or GOF Singleton pattern POJOs. More complex strategies that can work across an application cluster include using the Servlet container's application scope, JBoss Cache, OSCache, JCS and SwarmCache. Commercial solutions include Tangosol Coherence and Terracotta. While these solutions do work a majority of the time, they have a lot of weaknesses. Some are not thread-safe out of the box (static fields, Singleton POJOs), some are not transactional (Singleton POJOs, the Servlet application scope, OSCache, JCS, SwarmCache), none are remoteable and none have any security mechanisms. Other than the simplest solutions, all of them require the use of non-standard, third-party code. Enter EJB 3.1 Singletons.
The container is guaranteed to maintain a single shared instance of an EJB 3.1 Singleton. This means that Singletons can cache state across the application tier. Because it is an EJB, Singletons have all the middleware services you might expect--declarative transaction management, security, remoting, concurrency management, dependency injection, component life-cycle callbacks, interceptors and so on. Like all other EJBs, Singletons are simply annotated POJOs. Here is a simple example:
The example is using JPA and bean life-cycle callbacks to load data on startup and save the data when the bean is destroyed (usually when the application is being shut-down). Any bean calling getRate and setRate is guaranteed access to the shared data stored in a single instance of DiscountRateBean. You'll notice an interesting problem--any updates will be lost if the container does not get a chance to call the pre-destroy callback. We'll see how to minimize this problem using cron-like timers in a future article.
By default, all Singleton methods are made thread-safe and transactional. This means that all multithreaded access to the bean is serialized and all methods are assumed to have a REQUIRED transaction attribute (do you think that these are sensible defaults? If not, why?). You can change transactional behavior using the @TransactionManagement and @TransactionAttribute annotations just like you would do for a Stateful or Stateless Session Bean. If you've ever done this sort of thing for a relatively large scale application, you know having both the getRate and setRate methods serialized can be a serious performance bottleneck. In reality, you simply need a read-lock on the getRate method while a read-write lock should be placed on the setRate method. You can do this by using the @ConcurrencyAttribute like so:
One alternative to @ConcurrencyAttribute(READ_LOCK), @ConcurrencyAttribute(READ_WRITE_LOCK) and @ConcurrencyAttribute(NO_LOCK) being forwarded is @ConcurrencyReadLock, @ConcurrencyReadWriteLock and @ConcurrencyNoLock. To keep consistency with these low-level annotations, @TransactionAttribute would be broken up into @TransactionRequired, @RequiresNewTranscation, @TransactionNotSupported and so on. Some folks have pointed out that this mode of thinking begins to get into "annotation bloat" and adds a new source of complexity. This annotation granularity is also not consistent with Spring and C#.NET declarative transactions. Supporters of this model point out that it is easier to type than @ConcurrencyAttribute(READ_WRITE_LOCK), etc. What do you think?
It may also be entirely possible that you want to manage Singleton concurrency yourself and want the container to be uninvolved other than providing middleware services. This is supported through what is being called bean managed concurrency (a similar idea to bean managed transactions). Here is an example:
Notice this time we are managing concurrency ourselves using the synchronized keyword. Since the container will not interfere, you are free to use whatever concurrency management mechanism you like, including but not limited to using the full power of the java.util.concurrent package. For now, the new concurrency management features are limited to EJB 3.1 Singletons, but they could be expanded to cover other bean types.
Singletons will also give you control over lazy/eager loading as well as explicit Singleton dependency management to address load ordering. We won't discuss those features here although you are welcome to comment on that too. Although the specification does not cover clustering support, it is very likely that most vendors will make Singletons cluster-safe (just like Stateful Session Beans).
The two features discussed here are just the tip of the iceberg. There are a number of other very interesting features listed on the JSR agenda. Here are some of the most interesting ones:
In addition to these, there are a handful of features that are currently not on the JSR agenda but could be really great:
A feature forwarded by Adam Bien, the standardization of JNDI mapping, is also particularly interesting as it will go a long way to enhancing portability across containers. What are your thoughts on this last list? Are the features useful? Should they be pushed harder? Are they more useful than what is on the current agenda?
As you might be able to see, the expert group is trying hard to add useful features to EJB 3.1. We can only go so far on our own though... we need your feedback to tell us if we are on the right track or if we should be pursuing other paths. You can send your feedback directly to the JCP at [email protected]. Feel free to CC me at [email protected] so I am in the loop. In the coming months, I'll try to present more features to you as we discuss them on the expert group. Until then, wish us good luck!