OpenEJB simplifies Enterprise JavaBeans development The Enterprise JavaBeans development cycle—build, deploy, and test—is time consuming, partly because EJB components run inside an EJB container, which, in turn, depends on various resources like datasources and a JNDI (Java Naming and Directory Interface) provider. The traditional development cycle can vary anywhere from a few minutes to 30 minutes, depending on your application’s complexity, the number of beans, and the EJB container’s features. Some EJB containers provide hot-deployment such that any change in the application results in an automatic redeployment. Based on my experience, hot-deployment does not always function properly as a cache cleaner—server restart and redeployment is often needed.Another challenge with EJB development is using the EJB container’s debugger tool. Since the test and the container system run in different JVMs, you must set up a remote debugging environment, which itself may become complex.Unit testing (with JUnit) EJB components is also not easy. Firstly, the beans must be deployed to the container, which itself is time-consuming. Secondly, you have two options with JUnit tests that are both complex and time-consuming: The tests run within the container, which requires the tests to be deployed to the containerThe tests run in different JVMs and act as a client against a remote EJB containerTo address the above challenges, the J2EE community has come up with several good solutions to shorten the EJB development cycle. However, many challenges remain, mostly because of the numerous technologies (EJB, Servlet/JavaServer Pages, Java Message Service, and Java Database Connectivity) a J2EE application relies on. In addition, many competing and complementary solutions are available, and it’s difficult to know which one to choose.As for EJB development, there are varying solutions. One solution is to test the application when it is deployed to an EJB container. Another solution is to test the application on a simulated (mock) EJB container. In the latter solution, when other EJB components or resources (e.g., a datasource) are needed, an external EJB container is called. Nevertheless, these solutions have their complexities and shortcomings.In this article, I introduce you to a combination of tools that significantly simplify and shorten the EJB development cycle. To give you an idea of the time saved, only three seconds pass from the time some code has changed until the time the test results appear on the screen, using a laptop with a 2.2 GHz Mobile Intel Pentium 4 Processor. This article is based on my experience with an on-going development project. The project consists of roughly 300 Java classes and 10 EJB components. Throughout the article, I refer to the tools used in the project: XStream, OpenEJB, Eclipse, and Oracle OC4J.Macroscopic viewInstead of running your test inside a container, run the container inside your test. In this article, we use a lightweight embeddable EJB container inside our tests, as shown in Figure 1.The figure on the left shows traditional EJB development, where the application and the test are deployed to a running EJB container. The figure on the right shows that the application and the EJB container can start and terminate inside the test. Most EJB containers have a footprint too large to be embedded in an application. However, OpenEJB was designed to be embedded and has a small footprint. I found OpenEJB to be a perfect choice for EJB development.As an embedded EJB container, OpenEJB starts in a just a couple of seconds (on a laptop with a 2.2 GHz Mobile Intel Pentium 4 Processor). When running, OpenEJB is like any other full-featured EJB container.But what if your project has already chosen a particular EJB container? Can you still benefit from OpenEJB? Can your tests be carried both in OpenEJB and your choice of EJB container? If yes, do you have to make many adjustments? How much effort is required to embed OpenEJB? As an answer to the above questions, let me assert that it takes only a few minutes to set up OpenEJB, and your tests can run unmodified both on OpenEJB and your choice of EJB container. ToolsLet’s first review the tools we need:Mandatory tools: J2SE: For compiling and running the testsOpenEJB (0.9.2): As the embedded containerJUnit: For writing and automating testsOptional tools: XStream: For mocking (simulating) input dataEclipse: For the IDEA J2EE server: Your choice of application server for production purposesIn the development project I participate in, we use Eclipse as the IDE and Oracle OC4J as the EJB container for production. Furthermore, we use XStream to persist Java objects to XML files. These XML files are used for simulating input data for our tests.Getting startedBelow is a summary of the steps you should take in testing your EJB components: As input data, feed your tests with XML files (mocks). This will save you from typing the same input over and over. Here, I recommend using XStream, a tiny but a powerful library that maps XML to and from Java. Instead of XML, you could use hard-coded Java objects as input, but this would pollute your code—not to mention how much time it would take to create and maintain such code. This step is optional.Figure 2. A JUnit test can be fed with hard-coded Java objects, or XStream can dynamically create Java objects from XML and feed the JUnit testWrite your tests with JUnit or some other unit-test framework. JUnit benefits from a large developer community, and the tool has many extensions.Install OpenEJB (I detail those steps later).Deploy your application jar files to OpenEJB only once. This step does not need to be repeated as long as you do not add or remove EJB components or modify the configuration (see below). The deployment process typically takes a couple of minutes.When you modify a piece of code, you can run the tests with an embedded OpenEJB container. You will probably repeat this step often.When you are satisfied with the quality of the code in Step 5, run the same tests on the application server you have chosen for production. The purpose of this step is to discover possible incompatibilities between OpenEJB and your production application server.The following sequence diagram illustrates how the JUnit test gets a reference to a bean by embedding OpenEJB as the EJB container.Create XML-mocks (optional)To speed up testing, we can use XStream to create XML-mocks as input data for the tests. To use XStream, make sure the following jar files are in your classpath: xpp3-1.1.3.4d_b4_min.jar xstream-1.0.2.jar The following statements create an XML representation of any Java object: XStream xstream = new XStream(); String xml = xstream.toXML(someJavaObject)); Let’s see how we can use the above code to generate input data for your tests. Suppose you want to test the following code: public class CarReservation(){ public boolean reserveCar(Car car){ // Do something with the car } } The reserveCar() method takes a car as parameter. Now, the question is how to create the Car object? Of course, one method would hard-code the car object. Another method would capture a snapshot of a Car object and reuse the snapshot as input for the tests. In our solution, we use the latter method. Suppose your application contains the following code: public void getCarInformationFromUser(Request request){ Car car = request.getCar(); } You could modify that code to the following to get a snapshot of the Car object: public void getCarInformationFromUser(Request request){ Car car = request.getCar(); XStream xstream = new XStream(); System.out.println("car=" + xstream.toXML(car)); } If you run your application once, you can copy the XML representation of the Car object from the standard output and save it to a file.Now you can test the reserveCar() method with the XML-mocks you just created: public void testReserveCar(){ /* * Read the XML string from a file */ String xml = SomeFileReader.getCarXML(); XStream xstream = new XStream(); Car mockCar = (Car) xstream.fromXML(xml); /* * Continue the test */ CarReservation reservation = new CarReservation(); boolean ok = reservation.reserveCar(mockCar); assertTrue(ok);} You may decide to standardize the way objects convert to XML by creating an interface and letting your classes (or preferably superclasses) implement it: public interface XMLStylate { /** * @return a string that contains the XML * representation of an object */ String toXML(); } Your CarReservation class can be extended with the following method: public class CarReservation() implements XMLStylate{ public boolean reserveCar(Car car){ // Do something with the car } public String toXML(){ XStream xstream = new XStream(); return xstream.toXML(this); } } As you can see, the CarReservation provides a standard way of converting itself to XML. For quality assurance, a piece of code must be tested under various scenarios, with each scenario having a set of input data. XML combined with XStream greatly simplifies the latter task.Write your JUnit testsYour EJB tests will look like code that is run within an EJB container, with no framework-specific code. Let’s write a simple test for our Car Reservation application: public class CarEjbTest extends TestCase { private Context context; private Car mockCar; public final static String CAR_HOME = "ejb/car/Car"; protected void setUp() throws Exception { super.setUp(); context = new InitialContext(); /* * You have to write some file reader that reads * the XML representing the car object */ String xml = SomeFileReader.getCarXML(); mockCar = (Car) (new XStrem()).fromXML(xml); } protected void tearDown() throws Exception { super.tearDown(); } public void testCar() throws Exception { try { /* * Get the reference to home object */ Object objref = context.lookup(CAR_HOME); CarReservationHome carReservationHome = (CarReservationHome) PortableRemoteObject.narrow(objref, CarReservationHome.class); CarReservation carReservation = carReservationHome.create(); boolean ok = reservation.reserveCar(mockCar); assertTrue(ok); } catch (NamingException e) { e.printStackTrace(); } catch (RemoteException e) { e.printStackTrace(); } } } Interestingly, the above test can be run both inside and outside an EJB container, with the following alternatives: Test calls EJB components that are deployed and run as part of an embedded OpenEJB containerTest makes remote calls to EJB components deployed to an EJB containerTest runs in an EJB container and makes local calls to EJB componentsInstall OpenEJBOpenEJB can be installed as either a standalone server or an embedded container:Download OpenEJB.Unzip it to a folder, say to c:javaopenejb.Create a new configuration from scratch: Remove the old configuration move conf conf.bak.Create an empty folder called conf, mkdir conf.In the recently created conf folder, create the following files: openejb.conflogging.confmyapp.cmp.global-database.xmlmyapp.cmp.local-database.xmlmyapp.cmp.or-mapping.xmlEdit openejb.conf and make sure that it correctly references myapp.cmp.global-database.xml, myapp.cmp.local-database.xml, and myapp.cmp.or-mapping.xml. Note that the path is calculated from c:javaopenejb. For example, the path to myapp.cmp.global-database.xml would be conf/myapp.cmp.global-database.xml in openejb.conf. In all the above files, you must define various container-managed persistence and bean-managed persistence containers. Furthermore, you must define connectors for various datasources.Add your jar file to the OpenEJB configuration. In openejb.conf, add a reference to your jar file. For example: <Deployments jar="C:devmyappdeploymyapp-ejb.jar"/>.Make the necessary modifications in each of the above files.Deploy to OpenEJBDeploy your application jar file only once to OpenEJB. OpenEJB will add a file called openejb-jar.xml to your jar file. The openejb-jar.xml file contains configuration information specific to OpenEJB. If you add or remove EJB beans, you must deploy again.Here is the syntax for deploying a jar file: openejb deploy -a -c C:devmyappdeploymyapp-ejb.jar Now, you need to back up openejb-jar.xml. You will find it under the application jar file’s META-INF folder. Simply go to the command prompt and run the following to extract the files: jar xvf C:devmyappdeploymyapp-ejb.jar Note: You must ensure that openejb-jar.xml is added to the application jar file every time you make a new build. For example, if you use Ant, make sure Ant always includes openejb-jar.xml.Use the same naming convention in the application, the test, and openejb-jar.xml. Doing so ensures that the same application and the same test will run unmodified in both OpenEJB and your production application server. For example, in the above test, we used the following convention: public final static String CAR_HOME = "ejb/car/Car"; Therefore, we must make sure that the configuration in openejb-jar.xml looks like this: <ejb-deployment ejb-name="TheCar" deployment-id="ejb/car/Car" container-id="Default Stateless Container"> </ejb-deployment> Run the test with embedded OpenEJBHere comes the magic. To run your tests, you just need to add the following command line arguments to your JUnit tests: -Djava.naming.factory.initial=org.openejb.client.LocalInitialContextFactory -Djava.naming.provider.url=ormi://localhost:4201 -Dopenejb.home=c:javaopenejbopenejb-0.9.2 -Dopenejb.configuration=c:javaopenejbopenejb-0.9.2confopenejb.conf -Dopenejb.loader=embed -Dopenejb.localcopy=true If you have configured OpenEJB with a username and password, the following arguments must also be added: -Djava.naming.security.principal=adminusername -Djava.naming.security.credentials=password Let’s walk through the above arguments.The following two arguments tell the JVM to use OpenEJB as the JNDI provider: -Djava.naming.factory.initial=org.openejb.client.LocalInitialContextFactory -Djava.naming.provider.url=ormi://localhost:4201 In fact, the first time your application asks for a JNDI resource, LocalInitialContextFactory initializes and starts an instance of OpenEJB. OpenEJB then deploys and starts the jar files specified in openejb.conf.The following two arguments give the location of both OpenEJB’s home and the configuration file: -Dopenejb.home=c:javaopenejbopenejb-0.9.2 -Dopenejb.configuration=c:javaopenejbopenejb-0.9.2confopenejb.conf As you can see, only the absolute path is used; otherwise, OpenEJB does not initialize properly.Finally, the following lines ensure OpenEJB starts in the embedded mode: -Dopenejb.loader=embed -Dopenejb.localcopy=true Here is how CarEjbTest runs with embedded OpenEJB in Eclipse:Debug the test with embedded OpenEJBOut of the box, it is difficult to use an IDE debugger with an EJB container. However, with OpenEJB in embedded mode, things are simple. Simply choose “debug” instead of “run” with the above VM arguments. Remember that OpenEJB, EJB components, and JUnit tests all start in the same JVM and the debugger sees them as one big Java application.Run the test on the remote production serverAbout 90 percent of the time, you will develop and test using an embedded OpenEJB container, since doing so is fast and easy. When you feel that a component is ready for integration testing, the application is deployed to the application server chosen for production. To run the tests on the remote production server, see your EJB container’s documentation. With Oracle OC4J, running the tests is simple:Start OC4JDeploy your application to OC4JRun the test with the following command line arguments: -Djava.naming.factory.initial= com.evermind.server.ApplicationClientInitialContextFactory -Djava.naming.provider.url=ormi://localhost:23791/myapplication -Djava.naming.security.principal=admin -Djava.naming.security.credentials=password The above command line arguments specify that OC4J is the JNDI provider. Furthermore, it tells OC4J to expose the resources within the application myapplication.OC4J provides two different classes as the JNDI provider:com.evermind.server.ApplicationClientInitialContextFactorycom.evermind.server.rmi.RMIInitialContextFactoryFor a discussion about which class to choose, see the chapter on JNDI from the Oracle9iAS Containers for J2EE Services Guide.Here is how CarEjbTest is run for OC4J in Eclipse:DiscussionOpenEJB’s boot time is just a few seconds. You may recall that in the project I work on, we have 300 classes and 10 EJB components. In embedded mode, OpenEJB runs within the test’s JVM. On our laptop, it takes almost three seconds for OpenEJB and the tests to start. There is no need to redeploy or empty the cache when the same test runs repeatedly.To save even more time, you can use XStream to generate input data in XML for the tests. When testing, XStream simply saves you from punching the same input data repeatedly.Frequently testing EJB components usually proves time-consuming. Several frameworks try to reduce the time it takes to test EJB components, but these frameworks often require you to learn framework-specific features. As illustrated in this article, using OpenEJB as an embedded container not only significantly reduces the time it takes to test EJB components, but also build and deploy them as well.Thanks to David Blevins and Fredrik Harloff for reviewing and commenting on this article.Nader Aeinehchi works as chief architect at EDB Business Partner, one of Scandinavia’s largest IT companies. He has been extensively working with Java since 1996. He holds a MS in physics. Web DevelopmentApp TestingSecurityJava