EJB 3.1 – EJB New and Improved!
EJB 3.1 has launched! Read all about the new features and tweaks.
Join the DZone community and get the full member experience.
Join For FreeThe EJB 3.0 specification was a huge improvement from what we were used to in the early versions of EJB. Available as an early draft, EJB 3.1 has many more features and is even easier to use.
Let’s take a brief overview of a few interesting topics being considered in this new and improved version of EJB.
Optional Session Bean Business Interfaces:
Writing enterprise applications using EJB 2.1, EJB 3.0 or Spring always promoted the idea of writing component interfaces. In many cases, you could do with just a POJO without an interface. This new version of EJB allows you to write Session beans with no interfaces; just like you write your JPA entities and Message Driven beans. So, let’s see an example of how this can be accomplished:
package ejb31.samples.stateless.ws;import javax.ejb.Stateless;import javax.jws.WebMethod;import javax.jws.WebService;import ejb31.samples.entity.Customer;@Stateless@WebServicepublic class CustomerManager {@WebMethodpublic Customer getCustomer(){Customer customer = new Customer();customer.setFirstName("FirstName");customer.setLastName("LastName");return customer;}}
Global JNDI Names:
I remember blogging about the issues I had to face due to the portability issues caused by vendor-specific JNDI names. I had to work around a solution for testing on three different application servers: JBoss, Oracle and GlassFish. Each of these application servers has completely different naming convention for remote interfaces.
The GlassFish AS uses the fully qualified name of the remote business interface as default:
Object obj = initialContext.lookup("com.os.ent.CustomerManagerRemote");
JBoss on the other hand uses the application (EAR) name, followed by the EJB name and followed by a ‘/remote’ constant.
Object obj = initialContext.lookup("ejb3sampleapp/CustomerManager/remote");
Oracle uses the name specified in the @Stateless annotation.
Object obj = initialContext.lookup("CustomerManager");
In EJB 3.1, the global JNDI names would follow a standard pattern that is portable across all the different application servers:
java:global[/<application-name>]/<module-name>/<bean-name>#<interface-name>
Singleton Session Beans:
In all the earlier versions of EJB’s, we could use two session bean types: Stateless and Stateful. With EJB 3.1, we have the one which many of us felt a need for from time-to-time called the Singleton. Yes, Singletons are POJOs just like our Session beans, and the container is guaranteed to maintain a single shared instance of this Singleton. These Singletons are thread safe and also transactional. Like all other EJB’s, singletons have all the services such as security, remoting, dependency injection, web services, interceptors and so on.
package ejb31.samples.singleton;import java.util.ArrayList;import java.util.Collection;import java.util.HashMap;import java.util.Map;import javax.ejb.Singleton;@Singletonpublic class StateRegistryBean implements StateRegistry {private final Map<String, String> states = new HashMap<String, String>();public Collection<String> getStates() {return new ArrayList<String>(states.values());}public void removeState(String state) {states.remove(state);}public void setState(String name, String value) {states.put(name, value);}}
Calendar Based Timer Services:
One of the most important changes in EJB 3.1 is the ability to declaratively create cron-like schedules to trigger EJB methods. All that is needed is to annotate an EJB method with the @Schedule annotation to implement the timer.
For example the following schedule represents "Every Monday at 6:15": @Schedule(minute=”15”, hour=”6”, dayOfWeek=”Mon”) send a weekly newsletter to everyone in the list:
@StatelessPublic class NewsLetterBean{ @Schedule(minute=”15”, hour=”6”, dayOfWeek=”Mon”) Public void sendNewsLetter() { }}
Asynchronous Session beans:
In many enterprise applications I was involved, asynchronous processing was a must. And the only way to accomplish this was by using Message Driven Beans. Even though writing MDBs was very trivial, configuring all the necessary server resources like connection factories, topics and queues made it a little bit of a chore, especially since all I needed was an asynchronous method invocation.
With EJB 3.1 these issues are easily solved by a simple annotation placed on the Session Bean: @Asynchronous. Under normal circumstances, a Session bean method call blocks the client for the duration of that call. With this annotation in place, the container returns control to the client and executes the method on a separate thread.
The Session bean method call which is annotated with the @ Asynchronous annotation can return a java.util.Future object that allows the client to retrieve a result value, check for exceptions, or attempt to cancel an in-progress invocation.
EJB Lite:
A vast majority of clients I have worked with recently use EJB applications. Most of them use injection, JPA, stateless session beans and transactions, but not necessarily messaging, remoting or web services. EJB Lite is perfect for such applications. The best part of EJB Lite is that you can write your enterprise application with no XML at all, and knowing a very small number of basic annotations.
The following is a list of features proposed for EJB Lite:
• Stateless, Stateful, and Singleton session beans
• Only local EJB interfaces or no interfaces
• No support for asynchronous invocation
• Interceptors
• Declarative and programmatic security
• Declarative and programmatic transactions
• No support for Timers and scheduling
Easy packaging:
Even for the simplest web application, EJB 3.0 required that we have the components of the web application in a war file, EJB’s packaged in a jar file, and this war and jar in turn be packaged into an ear and deployed. This is very cumbersome, especially for new-comers to Java EE.
This isn’t the case anymore, all you would need to do is to drop all your EJB’s within the WEB-INF/classes directory and deploy these along with your web application.
If you have an ejb-jar.xml file, which again is optional, it would be placed within the WEB-INF directory just like the web.xml file.
EJB 3.1 Embeddable Container:
Testing EJBs was a herculean task all these years. It isn’t anymore with the timely and useful innovation of the embeddable container. The embeddable container allows you to use JPA and EJB 3.1 outside a container. There are already a number of open source embeddable EJB 3 containers that can run in any Java SE environment. To name a few: Open EJB, GlassFish, JBoss. For unit testing as well as running all the examples included in this article, I used Apache OpenEJB communities latest release of OpenEJB 3.1. OpenEJB is an embeddable, lightweight EJB 3.0 implementation with partial support of EJB 3.1.
Let’s take a look at how I was able to successfully test my Singleton Beans. The listing below shows the test class.
package org.ejb31.samples; import java.util.Properties; import javax.naming.Context; import javax.naming.InitialContext; import junit.framework.Assert; import org.junit.Test; import ejb31.samples.singleton.StateRegistry; public class StateRegistryTest { @Test public void testStates() throws Exception { Properties props = new Properties(); props.setProperty(Context.INITIAL_CONTEXT_FACTORY, "org.apache.openejb.client.LocalInitialContextFactory"); InitialContext context = new InitialContext(props); StateRegistry stateOne = (StateRegistry) context .lookup("StateRegistryBeanLocal"); StateRegistry stateTwo = (StateRegistry) context .lookup("StateRegistryBeanLocal"); stateOne.setState("MaryLand", "MD"); stateTwo.setState("Virginia", "VA"); Assert.assertEquals(2, stateTwo.getStates().size()); Assert.assertEquals(stateTwo.getState("MaryLand"), "MD"); Assert.assertEquals(stateOne.getState("Virginia"), "VA"); } }
In the above test class, the org.openejb.client.LocalInitialContextFactory used as the JNDI provider, will automatically embed OpenEJB into the testing VM. The same instance of OpenEJB is used for all the tests within that VM.
And below is the output from within the Eclipse IDE when you run the above test:
Apache OpenEJB 3.1 build: 20081009-03:31
http://openejb.apache.org/
INFO - openejb.home = C:\dev\ejb3.1\samples
INFO - openejb.base = C:\dev\ejb3.1\samples
INFO - Configuring Service(id=Default Security Service, type=SecurityService, provider-id=Default Security Service)
INFO - Configuring Service(id=Default Transaction Manager, type=TransactionManager, provider-id=Default Transaction Manager)
INFO - Found EjbModule in classpath: C:\dev\ejb3.1\samples\build
INFO - Beginning load: C:\dev\ejb3.1\samples\build
INFO - Configuring enterprise application: classpath.ear
INFO - Configuring Service(id=Default Singleton Container, type=Container, provider-id=Default Singleton Container)
INFO - Auto-creating a container for bean StateRegistryBean: Container(type=SINGLETON, id=Default Singleton Container)
INFO - Configuring Service(id=Default Stateless Container, type=Container, provider-id=Default Stateless Container)
INFO - Auto-creating a container for bean HelloBean: Container(type=STATELESS, id=Default Stateless Container)
INFO - Configuring PersistenceUnit(name=DemoPU)
INFO - Configuring Service(id=Default JDBC Database, type=Resource, provider-id=Default JDBC Database)
INFO - Auto-creating a Resource with id 'Default JDBC Database' of type 'DataSource for 'DemoPU'.
INFO - Configuring Service(id=Default Unmanaged JDBC Database, type=Resource, provider-id=Default Unmanaged JDBC Database)
INFO - Auto-creating a Resource with id 'Default Unmanaged JDBC Database' of type 'DataSource for 'DemoPU'.
INFO - Adjusting DemoPU <jta-data-source> to 'Default JDBC Database'
INFO - Adjusting DemoPU <non-jta-data-source> to 'Default Unmanaged JDBC Database'
INFO - Enterprise application "classpath.ear" loaded.
INFO - Assembling app: classpath.ear
INFO - PersistenceUnit(name=DemoPU, provider=org.apache.openjpa.persistence.PersistenceProviderImpl)
ERROR - JAVA AGENT NOT INSTALLED. The JPA Persistence Provider requested installation of a
ClassFileTransformer which requires a JavaAgent. See http://openejb.apache.org/3.0/javaagent.html
INFO - Jndi(name=StateRegistryBeanLocal) --> Ejb(deployment-id=StateRegistryBean)
INFO - Jndi(name=HelloBeanRemote) --> Ejb(deployment-id=HelloBean)
INFO - Created Ejb(deployment-id=HelloBean, ejb-name=HelloBean, container=Default Stateless Container)
INFO - Created Ejb(deployment-id=CustomerManager, ejb-name=CustomerManager, container=Default Stateless Container)
INFO - Created Ejb(deployment-id=StateRegistryBean, ejb-name=StateRegistryBean, container=Default Singleton Container)
INFO - Deployed Application(path=classpath.ear)
I haven't seen anything as easier than this to run tests against EJB's.
Conclusion:
I, like most developers, dreaded working with EJB 2.x. EJB 3 was a big step in the right direction. I myself was involved in writing a couple of enterprise applications in EJB 3.0, which I greatly enjoyed. With this latest, not yet released EJB 3.1 version, it took me less than an hour to explore all the examples shown in this article. I used OpenEJB 3.1 for this article and was even able to test some of the examples as shown above.
What are your thoughts about this upcoming version of EJB? Have you tried using EJB 3.1? The expert group in my opinion has done a tremendous job, what do you think?
You can also send your feedback directly to the expert group at jsr-318-comments@jcp.org. In case you like to know more about EJB 3.1, you can take a look at the EJB 3.1 public draft.
Opinions expressed by DZone contributors are their own.
Comments