2.4. J2EE Tutorial

2.4.1. Prerequisites for the Kodo J2EE Tutorial
2.4.2. J2EE Installation Types
2.4.3. Installing Kodo
2.4.4. Installing the J2EE Sample Application
2.4.4.1. Compiling and Building The Sample Application
2.4.4.2. Deploying Sample To JBoss
2.4.4.3. Deploying Sample To WebLogic 6.1 to 7.x
2.4.4.4. Deploying Sample To WebLogic 8.1
2.4.4.5. Deploying Sample To SunONE / Sun JES
2.4.4.6. Deploying Sample To JRun
2.4.4.7. Deploying Sample To WebSphere
2.4.4.8. Deploying Sample To Borland Enterprise Server 5.2
2.4.5. Using The Sample Application
2.4.6. Sample Architecture
2.4.7. Code Notes and J2EE Tips

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 JDO design techniques. The tutorial's sample application attempts to model 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.

2.4.1. Prerequisites for the Kodo J2EE Tutorial

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 JBoss, WebSphere, WebLogic, Borland Enterprise Server, JRun, or SunONE / Sun JES. If you use a different application server, 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 JDO. We provide a number of other tutorials for basic Kodo and JDO concepts, including enhancement, schema mapping, and configuration. This tutorial also assumes a basic level of experience with J2EE components, including EJB, 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.

2.4.2. J2EE Installation Types

Every application server has a different installation process for installing J2EE components. Kodo can be installed in a number of ways, each of 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.

  • JCA: Kodo implements the JCA 1.0 spec, and the kodo-jdo.rar file that comes in the jca directory of the distribution can be installed as any other JCA connection resource. This is the preferred way to integrate Kodo into a J2EE environment. It allows for simple installation (usually involving uploading or copying kodo-jdo.rar into the application server), guided configuration on many appservers, as well as dynamic reloading for upgrading Kodo to a newer version. The drawback is that older application servers have flaky or non- existent JCA support as the spec is relatively new.

  • PersistenceManagerFactoryImpl: This remains the most compatible way to integrate Kodo into a J2EE environment, though this is not seamless and can require a fair bit of custom application server code to manually bind an instance of PersistenceManagerFactoryImpl into the JNDI tree. This is somewhat offset by avoiding JCA configuration issues as well as being able to tailor the binding and start-up process.

2.4.3. Installing Kodo

Section 8.1.4, “Kodo JDO 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.

2.4.4. 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.

2.4.4.1. Compiling and Building The Sample Application

Navigate to the samples/jdo/j2ee directory of your Kodo installation. Compile the source files in place both in this base directory as well as the nested ejb directory:

javac *.java  ejb/*.java

Enhance the Car class.

kodoc -p jdo.properties package.jdo

Run the mapping tool; make sure that your META-INF/jdo.properties file includes the same connection information (e.g. Driver, URL, etc.) as your installation:

mappingtool -p jdo.properties package.jdo

Configure options in samples.properties to match your JCA installation, most notably the JNDI name to which you have bound Kodo (it defaults to kodo).

[Warning]Warning

This step (editing samples.properties) is very important as this value can be quite different for each appserver and each configuration.

Be sure that the setting you put for pmf.jndi matches not only your configured setting but also what your application server may prefix the configured name with.

JBoss, for example, will prefix the JNDI name with java:/ and Borland Enterprise Server looks at the serial:// context. Refer to your JNDI tree and the documentation for your application server for further details.

Build an J2EE application archive by running Ant against the build.xml. This will create samplej2ee.ear. This ear can now be deployed to your appserver.

ant -f build.xml

2.4.4.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.jdo.j2ee.ejb.CarHome was deployed to JNDI.

2.4.4.3. Deploying Sample To WebLogic 6.1 to 7.x

Place the ear file in the applications 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 sample-ejb listed in the Deployments/EJB section of the admin console. In addition you should find CarHome listed in the JNDI tree under myserver->samples->j2ee->ejb .

2.4.4.4. Deploying Sample To WebLogic 8.1

Create a new directory named samplej2ee.ear in the applications directory of your WebLogic domain. Extract the EAR file (without copying the EAR file) to this new directory:

applications> mkdir samplej2ee.ear
applications> cd samplej2ee.ear
samplej2ee.ear> jar -xvf /path/to/samplej2ee.ear

Deploy the application by using the admin console (Deployments -> Applications -> Deploy a new Application. Select samplej2ee.ear and deploy to the proper server targets. If you have installed the application correctly, you should find CarHome listed in the JNDI tree under myserver->samples->j2ee->ejb .

2.4.4.5. Deploying Sample To SunONE / Sun JES

Browse to the admin console in your web browser. Select Applications/ Enterprise Applications from the left navigation panel. Select Deploy... and in the following screen upload the samplej2ee.ear file to the server. Apply your changes by selecting the link in the upper right portion of the page. You should now see samplej2ee listed in the Enterprise Applications folder of the navigation panel.

2.4.4.6. Deploying Sample To JRun

Browse to the admin console in your web browser. Select J2EE Components from the left navigation panel. Select Add under the Enterprise Applications heading. Select the samplej2ee.ear file and hit Deploy. You should now see Sample-KodoJ2EE listed in the top-level folder of the navigation panel. Select it, and then select the sample-ejb.jar#CarEJB component under Enterprise JavaBeans section, then change the JNDI Name for the bean from the default value to samples.jdo.j2ee.ejb.CarHome and hit Apply.

If the Kodo resource adapter and the sample EAR are both configured correctly, you should now be able to access your sample application at JRun's deploy URL (e.g., http://localhost:8100/sample/).

2.4.4.7. Deploying Sample To WebSphere

Browse to the admin console in your web browser. Select Applications / Install New Application from the left navigation panel. Select the path to your samplej2ee.ear file and press Next.

On the following screen, leave the options at the default and select Next. On the following screen (Install New Application->Step 1 ), ensure that the Deploy EJBs option is checked. Leave other options at their defaults.

Move on to Step 2. On this screen enter samples.jdo.j2ee.ejb.CarHome as the JNDI name for the Car EJB. Continue through the remaining steps leaving options at the defaults. Select Finish and ensure that the application is deployed correctly.

Save the changes to the domain configuration by either selecting the Save link that appears after the installation is complete or by selecting Save from the top menu.

To verify your installation, select Applications / Enterprise Applications from the left navigation panel. Sample-KodoJ2EE should be listed in the list. If the application has not started already, select the checkbox next to Sample-KodoJ2EE and select Start.

2.4.4.8. Deploying Sample To Borland Enterprise Server 5.2

Deploy the EAR file using iastool or the console. Note that you may have to include the JDO library in your stub generation process. Also be sure that you have followed the JCA instructions for BES as well as editing the samples.properties to point to serial://kodo JNDI location. You should be able to see the CarEJB located in JNDI located at the home classname.

2.4.5. 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/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 PersistenceCapable instance by passing in a JDOQL query into the marked form (such as model=="Some Model").

2.4.6. Sample Architecture

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 a persistence capable instance. 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 Data Transfer Object pattern to provide the primary communication between the application server and the (remote) client. The Car instance will be used as the primary object upon which the client will work.

This model can be easily adapted to using entity beans. See our sample ejb directory and JDOEntityBean for more details on how to using JDO to power your entity beans.

  • samples/jdo/j2ee/Car.java: The core of the sample application. This is the persistence capable 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/jdo/j2ee/package.jdo: The JDO metadata file for the package. Note that some appservers have a problem with the way we include an internal DTD. If you see a lot of illegal/malformed character exceptions, uncomment out the DTD declaration in this file.

  • samples/jdo/j2ee/SampleUtilities.java: This is a simple facade to aggregate some core JDO functionality into some static methods. By placing all of the functionality into a single facade class, we can reduce code maintenance, as well as having the added advantage of being able to access Kodo from other portions of the application such as a servlet or JSP (though this functionality is not demonstrated in this sample). In addition, some simple utility functions such as JNDI helper methods are also in this class.

  • samples/jdo/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/jdo/j2ee/jsp/*.jsp: The web presentation client. These JSPs are not aware of JDO; they simply use the CarEJB session bean and the Car transfer object to do all the work.

  • samples/jdo/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/jdo/j2ee/build.xml: A simple Ant build file to help in creating a J2EE EAR file.

  • samples/jdo/j2ee/samples.properties: A simple .properties file to tailor the sample application to your particular appserver and installation.

2.4.7. Code Notes and J2EE Tips

  1. Persistence capable instances 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. Persistent instances using datastore identity lose all identity upon serialization (which happens when they are returned from an EJB method). While there are numerous ways to solve this problem, the sample uses the clientId field of Car to store the stringified datastore id. Note that this field is not persistent. This field ensures that the client and EJB always share the same identity for a given car instance.

    [Note]Note

    Note that this situation is slightly different for application identity. While persistent instances under application-identity still lose their id instance, recreating it from the server side is trivial as the fields on which it is based are still available.

    Other ways of solving this problem include:

    • Transmitting the object id first or otherwise storing identity with the client:

      Object oid = dogRemote.findByQuery ("// some query");
      Dog dog = dogRemote.getDogForOid (oid);
      // changes happen to dog
      dogRemote.save (oid, dog);
      
    • Wrapper objects that store the persistent instance, object id instance, as well as potentially other application-specific data:

      public class DogTransferObject
      {
          private Dog dog;
          private Object oid;
          private String authentication; // some application specific client data
      }
      
  3. PersistenceManager.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 PersistenceManager, it allows the JDO implementation to free up unused resources. Since a PersistenceManager is created for every transaction, this can increase the scalability of your application.

  4. You should not use PersistenceManager.currentTransaction or any javax.jdo.Transaction methods. Instead, use the JTA transactional API. SampleUtilities includes a helper method to obtain a UserTransaction instance from JNDI (see your application server's documentation on the proper JNDI lookup).

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

    • Collections and iterators returned from Query instances become closed and inaccessible upon method close. If the client is receiving the results of a Query, such as in CarBean.query, the results should be transferred to another fresh collection instance before being returned from the server.

    • While "default fetch group" values will always be returned to the client upon serialization, lazily loaded fields will not as the PersistenceManager will have been closed before those fields attempt to serialize. One can either simply access those fields before serialization, or one can use the persistence mangaer's retrieve and retrieveAll methods to make sure object state is loaded. Note that these methods are not recursive. If you need to go through multiple relations, you must call retrieve at each relational depth. This is an intentional limitation in the specification to prevent the entire object graph from being serialized and/or retrieved.

  6. 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 either the javax.jdo.Transaction or the javax.transaction.UserTransaction. Furthermore, outside of EJBs you can access the JDO layer with either transactional API.

  7. The Kodo distribution includes source code for some convenient base classes that encapsulate much of the code that is laid out in this example for clarity. JDOBean, JDOSessionBean, and JDOEntityBean include most of the functionality of SampleUtilities, and handle common EJB interface methods such as setEntityContext. To use these classes, we recommend placing Kodo's jars into the system classpath and not into the ear. Ear deployment can cause classloader problems due to the multiple locations that these classes could be loaded from.

  8. PersistenceManagers are allocated on a per-Transaction basis. Calling getPersistenceManager from the same PersistenceManagerFactory within the same EJB method call will always return the same instance.

    SamplesUtilities.getPersistenceManager () 
        == SampleUtilities.getPersistenceManager (); // will always be true
    

 

Skip navigation bar   Back to Top