By deploying Kodo into a J2EE environment, you can maintain the simplicity and performance of Kodo, 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 Kodo-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 Kodo in an enterprise environment.
This tutorial assumes that you have installed Kodo 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 Kodo 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.
Every application server has a different installation process for installing J2EE components. Kodo 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 Kodo as a JCA resource, there are other ways to use Kodo in a J2EE environment.
JPA
: J2EE 5 allows for the
automatic injection of
EntityManager
instances
into the J2EE context.
JCA
: Kodo implements the
JCA 1.0 spec, and the kodo-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 Kodo into a
pre-J2EE 5 environment. It allows for simple installation
(usually involving uploading or copying kodo-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 Kodo that go beyond the
JPA and JCA specifications. In this case, you can
manually instantiate Kodo 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.
Section 8.1.3, “Kodo JPA JCA Deployment” goes over the steps to install Kodo on your application server of choice via the Java Connector Architecture (JCA). If your application server does not support JCA, see Section 8.1.5, “Non-JCA Application Server Deployment” and Section 8.1.1, “Standalone Deployment” for other installation options.
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.
Navigate to the samples/persistence/j2ee
directory of your Kodo installation.
Ensure that the JNDI name in the setSessionContext() method in
ejb/CarBean.java matches your JCA installation. This defaults to
java:/kodo-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 kodo-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.
kodoc -p persistence.xml Car.java
Run the mapping tool; make sure that your <a
href="META-INF/persistence.xml" target="_top">META-INF/persistence.xml</a>
file includes the same connection information (e.g. Driver, URL, etc.)
as your JCA installation, although note that when you deploy via JCA,
the configuration information used at runtime will be the information
provided in the JCA configuration file, not the persistence.xml file.
You should update your JCA configuration to include samples.persistence.j2ee.Car
in the Types
parameter of the of 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
kodo-persistence-j2ee-sample.ear
. This ear
can now be deployed to your appserver. Be sure to add the class
samples.persistence.j2ee.Car
to the
kodo.MetaDataFactory
Kodo configuration
property. This will automatically register the Entity.
ant -f build.xml
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.persistence.j2ee.ejb.CarHome
was
deployed to JNDI.
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 kodo-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
Types
parameter of the
kodo.MetaDataFactory
Kodo configuration
property in the META-INF/ra.xml
file.
The sample application installs itself into the web layer at the
context root of sample. By browsing to
http://yourserver:yourport/kodo-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"
).
The garage application is a simple enterprise application that demonstrates some of the basic concepts necessary when using Kodo 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 Kodo 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.
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.
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 Kodo to free up unused resources.
Since an EntityManager
is created
for every transaction, this can increase the scalability
of your application.
You should not use
EntityManager.getTransaction()
when using JTA
to manage your transactions. Instead, Kodo will integrate with
JTA to automatically govern transactions based on your EJB
transaction configuration.
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.
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.
EntityManager
s 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.