3. J2EE Tutorial

3.1. Prerequisites for the OpenJPA J2EE Tutorial
3.2. J2EE Installation Types
3.3. Installing the J2EE Sample Application
3.3.1. Compiling and Building The Sample Application
3.3.2. Deploying Sample To JBoss
3.3.3. Deploying Sample To WebLogic 9
3.4. Using The Sample Application
3.5. Sample Architecture
3.6. Code Notes and J2EE Tips

By deploying OpenJPA into a J2EE environment, you can maintain the simplicity and performance of OpenJPA, while leveraging J2EE technologies such as container managed transactions (JTA/JTS), enterprise objects with remote invocation (EJB), and managed deployment of multi-tiered applications via an application server. This tutorial will demonstrate how to deploy OpenJPA-based J2EE applications and showcase some basic enterprise JPA design techniques. The tutorial's sample application models a basic garage catalog system. While the application is relatively trivial, the code has been constructed to illustrate simple patterns and solutions to common problems when using OpenJPA in an enterprise environment.

3.1. Prerequisites for the OpenJPA J2EE Tutorial

This tutorial assumes that you have installed OpenJPA and setup your classpath according to the installation instructions appropriate for your platform. In addition, this tutorial requires that you have installed and configured a J2EE-compliant application server, such as WebLogic or JBoss, running on JDK 1.5. If you use a different application server not listed here, this tutorial may be adaptable to your application server with small changes; refer to your application server's documentation for any specific classpath and deployment descriptor requirements.

This tutorial assumes a reasonable level of experience with OpenJPA and JPA. We provide a number of other tutorials for basic concepts, including enhancement, schema mapping, and configuration. This tutorial also assumes a basic level of experience with J2EE components, including session beans, JNDI, JSP, and EAR/WAR/JAR packaging. Sun and/or your application server company may provide tutorials to get familiar with these components.

In addition, this tutorial uses Ant to build the deployment archives. While this is the preferred way of building a deployment of the tutorial, one can easily build the appropriate JAR, WAR, and EAR files by hand, although that is outside the scope of this document.

3.2. J2EE Installation Types

Every application server has a different installation process for installing J2EE components. OpenJPA can be installed in a number of ways, which may or may not be appropriate to your application server. While this document focuses mainly upon using OpenJPA as a JCA resource, there are other ways to use OpenJPA in a J2EE environment.

  • JPA: J2EE 5 allows for the automatic injection of EntityManager instances into the J2EE context.

  • JCA: OpenJPA implements the JCA 1.0 spec, and the openjpa-persistence.rar file that comes in the jca/persistence directory of the distribution can be installed as any other JCA connection resource. This is the preferred way to integrate OpenJPA into a pre-J2EE 5 environment. It allows for simple installation (usually involving uploading or copying openjpa-persistence.rar into the application server's deployment directory), and guided configuration on many appservers.

  • Manual Binding into JNDI: Your application may require some needs in initializing OpenJPA that go beyond the JPA and JCA specifications. In this case, you can manually instantiate OpenJPA and place it into the JNDI tree. This process, however, is not seamless and can require a fair bit of custom application server code to bind an instance of org.apache.openjpa.persistence.EntityManagerFactoryImpl into JNDI.

3.3. Installing the J2EE Sample Application

Installing the sample application involves first compiling and building a deployment archive (.ear) file. This file then needs to be deployed into your application server.

3.3.1. Compiling and Building The Sample Application

Navigate to the samples/persistence/j2ee directory of your OpenJPA installation.

Ensure that the JNDI name in the setSessionContext() method in ejb/CarBean.java matches your JCA installation. This defaults to java:/openjpa-ejb, but the actual value will depend on the configuration of your JCA deploy and your application server's JNDI context. E.g. the default name for a WebLogic 9 install would be simply openjpa-ejb.

Compile the source files in place both in this base directory as well as the nested ejb and jsp directories:

javac *.java  ejb/*.java jsp/*.java

Enhance the Car class.

openjpac -p persistence.xml Car.java

Run the mapping tool; make sure that your META-INF/persistence.xml file includes the same connection information (e.g. Driver, URL, etc.) as your JCA installation. You should update your JCA configuration to include samples.persistence.j2ee.Car in the MetaDataFactory property:

<config-property name="MetaDataFactory">Types=samples.persistence.j2ee.Car</config-property/>
mappingtool -p persistence.xml Car.java

Build an J2EE application archive by running Ant against the build.xml. This will create openjpa-persistence-j2ee-sample.ear. This ear can now be deployed to your appserver. Be sure to add the class samples.j2ee.Car to the openjpa.PersistentClasses OpenJPA configuration property. This will automatically register the Entity.

ant -f build.xml

3.3.2. Deploying Sample To JBoss

Place the ear file in the deploy directory of your JBoss installation. You can use the above hints to view the JNDI tree to see if samples.j2ee.ejb.CarHome was deployed to JNDI.

3.3.3. Deploying Sample To WebLogic 9

Place the ear file in the autodeploy directory of your WebLogic domain. Production mode (see your startWebLogic.sh/cmd file) should be set to false to enable auto-deployment. If the application was installed correctly, you should see openjpa-persistence-j2ee-sample listed in the Deployments section of the admin console. In addition you should find CarHome listed in the JNDI tree under AdminServer->samples->j2ee->ejb . Ensure that you have added the class samples.j2ee.Car to the openjpa.PersistentClasses OpenJPA configuration property in the META-INF/ra.xml file.

3.4. Using The Sample Application

The sample application installs itself into the web layer at the context root of sample. By browsing to http://yourserver:yourport/openjpa-persistence-j2ee-sample , you should be presented with a simple list page with no cars. You can edit, add, delete car instances. In addition, you can query on the underlying Car instances by passing in an JPQL query into the marked form (such as select car from Car car where car.model="Some Model").

3.5. Sample Architecture

The garage application is a simple enterprise application that demonstrates some of the basic concepts necessary when using OpenJPA in the enterprise layer.

The core model wraps a stateless session bean facade around an entity. Using a session bean provides both a remote interface for various clients as well as providing a transactional context in which to work (and thus avoiding any explicit transactional code).

This session bean uses the JPA's detachment capabilities to provide an automatic Data Transfer Object mechanism for the primary communication between the application server and the (possibly remote) client. The Car instance will be used as the primary object upon which the client will work.

  • samples/persistence/j2ee/Car.java: The core of the sample application. This is the entity class that OpenJPA will use to persist the application data. Instances of this class will also fill the role of data transfer object (DTO) for EJB clients. To accomplish this, Car implements java.io.Serializable so that remote clients can access cars as parameters and return values from the EJB.

  • samples/persistence/j2ee/jsp/SampleUtilities.java: This is a simple facade to aggregate some common J2EE behavior into some static methods. By placing all of the functionality into a single facade class, we can reduce code maintenance of our JSPs.

  • samples/persistence/j2ee/ejb/Car*.java: The source for the CarEJB session bean. Clients can use the CarHome and CarRemote interfaces to find, manipulate, and persist changes to Car transfer object instances. By using J2EE transactional features, the implementation code in CarBean.java can be focused almost entirely upon business and persistence logic without worrying about transactions.

  • samples/persistence/j2ee/jsp/*.jsp: The web presentation client. These JSPs are not aware of the JPA; they simply use the CarEJB session bean and the Car transfer object to do all the work.

  • samples/persistence/j2ee/resources/*: Files required to deploy to the various appservers, including J2EE deployment descriptors, WAR/ EJB/ EAR descriptors, as well as appserver specific files.

  • samples/persistence/j2ee/build.xml: A simple Ant build file to help in creating a J2EE EAR file.

3.6. Code Notes and J2EE Tips

  1. Entity classes are excellent candidates for the Data Transfer Object Pattern. This pattern attempts to reduce network load, as well as group business logic into concise units. For example, CarBean.edit allows you to ensure that all values are correct before committing a transaction, instead of sequentially calling getters and setters on the session facade. This is especially true when using RMI such as from a Swing based application connecting to an application server.

    CarEJB works as a session bean facade to demarcate transactions, provide finder methods, and encapsulate complex business logic at the server level.

  2. EntityManager.close() should be called at the end of every EJB method. In addition to ensuring that your code will not attempt to access a closed EntityManager, it allows OpenJPA to free up unused resources. Since an EntityManager is created for every transaction, this can increase the scalability of your application.

  3. You should not use EntityManager.getTransaction() when using JTA to manage your transactions. Instead, OpenJPA will integrate with JTA to automatically govern transactions based on your EJB transaction configuration.

  4. While serialization of entity instances is relatively straightforward, there are several things to keep in mind:

    • While "default fetch group" values will always be returned to the client upon serialization, lazily loaded fields will not as the EntityManager will have been closed before those fields attempt to serialize. You can either access those fields before serialization, configure the fetch type of the relationships, or configure your JPQL queries to eagerly fetch data.

  5. It is not necessarily required that you use EJBs and container-managed transactions to demarcate transactions, although that is probably the most common method. In EJBs using bean managed transactions, you can control transactions through the javax.transaction.UserTransaction interface. Furthermore, outside of session beans you can control the JPA layer's transaction via the javax.persistence.EntityTransaction interface.

  6. EntityManagers are allocated on a per-Transaction basis. Calling getEntityManager from the same EntityManagerFactory within the same EJB method call will always return the same entity manager, although the user-visible object may be proxied, so might not compare equal using the == operator.