EJB Interfaces are Optional
The very first change the expert
group covered was removing the last remaining obstacle to making EJBs look just like POJOs in
their simplest form by making Session Bean business interfaces optional. 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: @Stateless public class PlaceBidBean { @PersistenceContext private EntityManager entityManager; public void placeBid (Bid bid) { entityManager.persist(bid); } }
To keep things interesting, let's add a few more features to this
bargain-basement bean: @Stateless @WebService public class PlaceBidBean { @PersistenceContext private EntityManager entityManager; @WebMethod public void placeBid (Bid bid) { entityManager.persist(bid); } }
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.
|
The Singleton Beans are Here
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. 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 @Singleton public class DiscountRateBean { @PersistenceContext private EntityManager entityManager; private Rate rate; @PostConstruct private void init() { rate = entityManager.find(Rate.class, 1); } @PreDestroy private void destroy() { entityManager.merge(rate); } public void setRate(Rate rate) { this.rate = rate; } public Rate getRate() { return rate; } }
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: @Singleton public class DiscountRateBean { @PersistenceContext private EntityManager entityManager; private Rate rate; @PostConstruct private void init() { rate = entityManager.find(Rate.class, 1); } @PreDestroy private void destroy() { entityManager.merge(rate); } @ConcurrencyAttribute(READ_WRITE_LOCK) public void setRate(Rate rate) { this.rate = rate; } @ConcurrencyAttribute(READ_LOCK) public Rate getRate() { return rate; } }
For those who are familiar with
Doug Lea's work, the READ_LOCK and READ_WRITE_LOCK terminology comes from java.util.concurrent. There are some application shared
data that are just read-only. Any locking is really unnecessary in such
cases. In such a case, you can create an unsynchronized Singleton like this: @Singleton @ConcurrencyAttribute(NO_LOCK) // READ_LOCK would also work... public class DiscountRateBean { @PersistenceContext private EntityManager entityManager; private Rate rate; @PostConstruct private void init() { rate = entityManager.find(Rate.class, 1); } public Rate getRate() { return rate; } }
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: @Singleton @ConcurrencyManagement(BEAN) public class DiscountRateBean { @PersistenceContext private EntityManager entityManager; private Rate rate; @PostConstruct private void init() { rate = entityManager.find(Rate.class, 1); } @PreDestroy private void destroy() { entityManager.merge(rate); } public synchronized void setRate(Rate rate) { this.rate = rate; } public synchronized Rate getRate() { return rate; } }
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). |
More EJB 3.1 Features 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: 1.
Support for direct use of EJBs
in the servlet container, including simplified
packaging options. The current thought is to allow EJBs
in the WEB-INF/classes directory while allowing ejb-jar.xml
to reside in the WEB-INF directory, just like the web.xml
file. In a similar vein, you would be able to place an EJB jar into the
WEB-INF/lib directory. 2.
EJB Timer Service enhancements to support cron-like scheduling, deployment-time timer creation, and
Stateful Session Bean timed objects. 3.
Support for stateful web
services via Stateful Session Bean web service
endpoints. In addition to
these, there are a handful of features that are currently not on the JSR
agenda but could be really great: 1. Further
simplification of JMS, JavaMail and database
injected resources. For example, you should be able to inject MessageSenders, not just Queues and ConnectionFactory
references. Gavin King is a major proponent of this enhancement. 2.
A Service Provider Interface (SPI) for EJB. This
will make a number of innovative third-party integrations possible such as iBATIS, Spring, Acegi, Quartz or even Groovy Beans. Bill Burke, Mike
Keith and I strongly support this feature. 3.
The ability to add EJB support to a lightweight servlet container like Tomcat. This would be similar to
what is already available in the open source world in the form of Embedded JBoss, OpenEJB and EasyBeans. I haven't brought this feature up to the group
yet, but will if you think it is good. 4.
The ability to use local transactions in addition to
JTA in EJB. I think this would be very useful for smaller web applications
that really don't need JTA. 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 |
Besides managing
HTTP interactions, most web applications have significant requirements in the
areas of transaction management, security and persistence. Such requirements
can be readily addressed by technologies that have been part of the Java EE
platform for quite some time, such as the Enterprise JavaBeans (EJB) 3.x
technology and the Java Persistence API, but that are rarely supported by
“plain” servlet containers. By
incorporating many of these APIs, the Web Profile aims at raising the bar for
what should be considered a basic stack for the development of web
applications using the Java platform. Targeting
“modern” web applications then implies offering a reasonably
complete stack, composed of standard APIs, and capable out-of-the-box of
addressing the needs of a large class of web applications. Furthermore, this
stack should be easy to grow, so as to address any remaining developer needs. |
The following technologies are required components
of the Web Profile: •Servlet 3.0 •JavaServer Pages (JSP) 2.2 •Expression
Language (EL) 2.2 •Debugging
Support for Other Languages (JSR-45) 1.0 •Standard
Tag Library for JavaServer Pages (JSTL) 1.2 •JavaServer Faces (JSF) 2.0 •Common
Annotations for Java Platform (JSR-250) 1.1 •Enterprise JavaBeans (EJB) 3.1 Lite •Java Transaction
API (JTA) 1.1 •Java Persistence API (JPA) 2.0 •Bean Validation 1.0 •Managed
Beans 1.0 •Interceptors
1.1 •JSR-299
1.0 •JSR-330
1.0 |
EE.2.7.4RMI-IIOP The RMI-IIOP subsystem is composed of APIs that
allow for the use of RMI-style programming that is independent of the
underlying protocol, as well as an implementation of those APIs that supports
both the Java SE native RMI protocol (JRMP) and the CORBA IIOP protocol. Java
EE applications can use RMI-IIOP, with IIOP protocol support, to access CORBA
services that are compatible with the RMI programming restrictions (see the
RMI-IIOP spec for details). Such CORBA services would typically be defined by
components that live outside of a Java EE product, usually in a legacy
system. Only Java EE application clients are required to be able to define
their own CORBA services directly, using the RMI-IIOP APIs. Typically such
CORBA objects would be used for callbacks when accessing other CORBA objects. Java EE
applications are required to use the RMI-IIOP APIs, specifically the narrow
method of javax.rmi.PortableRemoteObject, when accessing Enterprise JavaBeans components, as described in the
EJB specification. This allows enterprise beans to be protocol independent.
Note that the most common use of the narrow method is not needed when using dependency injection instead of JNDI
lookups; the container will perform the narrow for the application before injecting the object reference. Java EE
products must be capable of exporting enterprise beans using the IIOP
protocol, and accessing enterprise beans using the IIOP protocol, as specified
in the EJB specification. The ability to use the IIOP protocol is required to
enable interoperability between Java EE products,
however a Java EE product may also use other protocols. |