JPA Tutorials
OpenJPA Tutorials These tutorials provide step-by-step examples of how to use various facets of the OpenJPA system. They assume a general knowledge of JPA and Java. For more information on these subjects, see the following URLs: Sun's Java site JPA Overview Document Links to JPA
Tutorial Requirements These tutorials require that JDK 1.5 or greater be installed on your computer, and that java and javac are in your PATH when you open a command shell.
OpenJPA Tutorial In this tutorial you will become familiar with the basic tools and development processes under OpenJPA by creating a simple JPA application.
The Pet Shop Imagine that you have decided to create a software toolkit to be used by pet shop operators. This toolkit must provide a number of solutions to common problems encountered at pet shops. Industry analysts indicate that the three most desired features are inventory maintenance, inventory growth simulation, and behavioral analysis. Not one to question the sage advice of experts, you choose to attack these three problems first. According to the aforementioned experts, most pet shops focus on three types of animals only: dogs, rabbits, and snakes. This ontology suggests the following class hierarchy: Animal ^ | +--------------------+ | | | Dog Rabbit Snake
Included Files We have provided an implementation of Animal and Dog classes, plus some helper classes and files to create the initial schema and populate the database with some sample dogs. Let's take a closer look at these classes. tutorial.persistence.AnimalMaintenance: Provides some utility methods for examining and manipulating the animals stored in the database. We will fill in method definitions in . tutorial.persistence.Animal: This is the superclass of all animals that this pet store software can handle. tutorial.persistence.Dog: Contains data and methods specific to dogs. tutorial.persistence.Rabbit: Contains data and methods specific to rabbits. It will be used in . tutorial.persistence.Snake: Contains data and methods specific to snakes. It will be used in . ../../META-INF/persistence.xml: This XML file contains OpenJPA-specific and standard JPA configuration settings. It is important to load all persistent entity classes at startup so that OpenJPA can match database discriminator values to entity classes. Often this happens automatically. Some parts of this tutorial, however, do require that all entity classes be loaded explicitly. The JPA standard includes persistent class listings in its XML configuration format. Add the following lines to ../../META-INF/persistence.xml between the <provider> and the <properties> elements: <class>tutorial.persistence.Animal</class> <class>tutorial.persistence.Dog</class> solutions : The solutions directory contains the complete solutions to this tutorial, including finished versions of the .java files listed above.
Important Utilities java: Runs main methods in specified Java classes. javac: Compiles .java files into .class files that can be executed by java . org.apache.openjpa.enhance.PCEnhancer org.apache.openjpa.enhance.PCEnhancer: Runs the OpenJPA enhancer against the specified classes. More information is available in of the Reference Guide. org.apache.openjpa.jdbc.meta.MappingTool org.apache.openjpa.jdbc.meta.MappingTool: A utility that can be used to create and maintain the object-relational mappings and schema of all persistent classes in a JDBC-compliant datastore. This functionality allows the underlying mappings and schema to be easily kept up-to-date with the Java classes in the system. See of the Reference Guide for more information.
Getting Started Let's compile the initial classes and see them in action. To do so, we must compile the .java files, as we would with any Java project, and then optionally pass the resulting classes through the OpenJPA enhancer. CLASSPATH Be sure that your CLASSPATH is set correctly. Note that your OpenJPA install directory should be in the CLASSPATH, as the tutorial classes are located in the tutorial/persistence directory under your OpenJPA install directory, and are in the tutorial.persistence package. Make sure you are in the tutorial/persistence directory. All examples throughout the tutorial assume that you are in this directory. Examine Animal.java, Dog.java, and SeedDatabase.java These files are good examples of the simplicity JPA engenders. As noted earlier, persisting an object or manipulating an object's persistent data requires almost no JPA-specific code. For a very simple example of creating persistent objects, please see the seed method of SeedDatabase.java . Note the objects are created with normal Java constructors. The files Animal.java and Dog.java are also good examples of how JPA allows you to manipulate persistent data without writing any specific JPA code, by providing simple annotations. Let's take a look at the Animal.java file. Notice that the class is a Plain Old Java Object (POJO), with several annotations describing how the class is mapped into a relational database. First, let's examine the class level annotations: @Entity(name="Animal") @Table(name="JPA_TUT_ANIMAL") @Inheritance(strategy=InheritanceType.SINGLE_TABLE) @DiscriminatorColumn(name="SPECIES", length=100) public abstract class Animal { ... } The annotations serve to map the class into the database. For more information on these and other annotations, see and . @Entity: This annotation indicates that instances of this class may be persistent entities. The value of the name attribute is the entity name, and is used in queries, etc. @Table: This annotation is used to map the entity to a primary table. The value of the name attribute specifies the name of the relational table to use as the primary table. @Inheritance: When multiple classes in an inheritance hierarchy are persistent entity types, it is important to describe how the inheritance hierarchy is mapped. Setting the value of the strategy attribute to InheritanceType.SINGLE_TABLE indicates that the primary table for all subclasses shall be the same table as for the superclass. @DiscriminatorColumn: With a SINGLE_TABLE inheritance mapping strategy, instances of multiple classes will be stored in the same table. This annotation describes a column in that table that is used to determine the type of an instance whose data is stored in a particular row. The name attribute is the name of the column, and the length attribute indicates the size of the column. By default, the unqualified class name for the instance is stored in the discriminator column. To store a different value for a type, use the @DiscriminatorValue annotation. Let's take a look at our class' field annotations. We have chosen to use field access for our entities, meaning the persistence implementation will get and set persistent state directly through our class' declared fields. We could have chosen to use property access , in which the implementation accesses persistent state through our JavaBean getter and setter methods. In that case, we would have annotated our getter methods rather than our fields. @Id @GeneratedValue @Column(name="ID") private long id; @Basic @Column(name="ANIMAL_NAME") private String name = null; @Basic @Column(name="COST") private float price = 0f; The annotations serve to map the fields into the database. For more information on these and other annotations, see . @Id: This annotation indicates that the field is to be mapped to a primary key column in the database. @GeneratedValue: Indicates that the implementation will generate a value for the field automatically. @Column: This annotation describes the column to which the field will be mapped. The name attribute specifies the name of the column. @Basic: This annotation indicates that the field is simply mapped into a column. There are other annotations that indicate entity relationships and other more complex mappings. Compile the .java files. javac *.java You can use any Java compiler instead of javac. Enhance the persistent classes. (Optional) java org.apache.openjpa.enhance.PCEnhancer Animal.java Dog.java This step runs the OpenJPA enhancer on the Animal.java and Dog.java files mentioned above. See of the Reference Guide for more information on the enhancer, including alternatives to enhancement. The -p flag points the enhancer to your persistence.xml configuration file. All OpenJPA tools look for default configuration in a resource called openjpa.xml or META-INF/openjpa.xml. Thus you can avoid passing the -p argument to tools by using this configuration file name in place of persistence.xml. See in the Reference Guide for details on OpenJPA configuration.
Configuring the Datastore Now that we've compiled the source files, we're ready to set up the database. Hypersonic SQL, a pure Java relational database, is included in the OpenJPA distribution. We have included this database because it is simple to set up and has a small memory footprint; however, you can use this tutorial with any of the relational databases that we support. You can also write your own plugin for any database that we do not support. For the sake of simplicity, this tutorial only describes how to set up connectivity to a Hypersonic SQL database. For more information on how to connect to a different database or how to add support for other databases, see of the Reference Guide. org.apache.openjpa.jdbc.meta.MappingTool Create the object-relational mappings and database schema. java org.apache.openjpa.jdbc.meta.MappingTool Animal.java Dog.java This command propagates the necessary schema for the specified classes to the database configured in persistence.xml. If you are using the default Hypersonic SQL setup, the first time you run the mapping tool Hypersonic will create tutorial_database.properties and tutorial_database.script database files in your current directory. To delete the database, just delete these files. By default, JPA uses object-relational mapping information stored in annotations in your source files. of the JPA Overview will help you understand mapping annotations. Additionally, of the Reference Guide describes your other mapping options in detail. If you are curious, you can view the schema OpenJPA created for the tutorial classes with OpenJPA's schema tool: java org.apache.openjpa.jdbc.schema.SchemaTool -a reflect -f tmp.schema This will create a tmp.schema file with an XML representation of the database schema. The XML should be self explanatory; see of the Reference Guide for details. You may delete the tmp.schema file before proceeding. Populate the database with sample data. java tutorial.persistence.SeedDatabase Congratulations! You have now created an JPA-accessible persistent store, and seeded it with some sample data.
Inventory Maintenance The most important element of a successful pet store product, say the experts, is an inventory maintenance mechanism. So, let's work on the Animal and Dog classes a bit to permit user interaction with the database. This chapter should familiarize you with some of the basics of the JPA specification and the mechanics of compiling and enhancing persistent classes. You will also become familiar with the mapping tool for propagating the persistent schema into the database. First, let's add some code to AnimalMaintenance.java that allows us to examine the animals currently in the database. Add code to AnimalMaintenance.java. Modify the getAnimals method of AnimalMaintenance.java to look like this: /** * Return a list of animals that match the specified query filter. * * @param filter the JPQL filter to apply to the query * @param cls the class of animal to query on * @param em the EntityManager to obtain the query from */ public static List getAnimals(String filter, EntityManager em) { // Execute a query for the specified filter. Query query = em.createQuery(filter); return query.getResultList(); } Compile AnimalMaintenance.java. javac AnimalMaintenance.java Take a look at the animals in the database. java tutorial.persistence.AnimalMaintenance list Animal Notice that list optionally takes a query filter. Let's explore the database some more, this time using filters: java tutorial.persistence.AnimalMaintenance list "select a from Animal a where a.name = 'Binney'" java tutorial.persistence.AnimalMaintenance list "select a from Animal a where a.price <= 50" The Java Persistence Query Language (JPQL) is designed to look and behave much like an object oriented SQL dialect. The name and price fields identified in the above queries map to the member fields of those names in tutorial.persistence.Animal. More details on JPQL syntax is available in of the JPA Overview. Great! Now that we can see the contents of the database, let's add some code that lets us add and remove animals.
Persisting Objects As new dogs are born or acquired, the store owner will need to add new records to the inventory database. In this section, we'll write the code to handle additions through the tutorial.persistence.AnimalMaintenance class. This section will familiarize you with the mechanism for storing persistent instances in a JPA entity manager. We will create a new dog, obtain a Transaction from a EntityManager, and, within the transaction, make the new dog object persistent. tutorial.persistence.AnimalMaintenance provides a reflection-based facility for creating any type of animal, provided that the animal has a two-argument constructor whose first argument corresponds to the name of the animal and whose second argument is an implementation-specific primitive. This reflection-based system is in place to keep this tutorial short and remove repetitive creation mechanisms. It is not a required part of the JPA specification. Add the following code to AnimalMaintenance.java. Modify the persistObject method of AnimalMaintenance.java to look like this: /** * Performs the actual JPA work of putting <code>object</code> * into the data store. * * @param object the object to persist in the data store */ public static void persistObject(EntityManager em, Object object) { // Mark the beginning of the unit of work boundary. em.getTransaction().begin(); em.persist(object); // Mark the end of the unit of work boundary, // and record all inserts in the database. em.getTransaction().commit(); System.out.println("Added " + object); } In the above code, we pass in an EntityManager. EntityManagers may be either container managed or application managed. In this tutorial, because we're operating outside a container, we're using application managed EntityManager s. In managed environments, EntityManagers are typically container managed, and thus injected or looked up via JNDI. Application managed EntityManagers can be used in both managed and unmanaged environments, and are created by an EntityManagerFactory . An EntityManagerFactory can be obtained from the javax.persistence.Persistence class. This class provides some convenience methods for obtaining an EntityManagerFactory . Recompile AnimalMaintenance.java. javac AnimalMaintenance.java You now have a mechanism for adding new dogs to the database. Go ahead and add some by running java tutorial.persistence.AnimalMaintenance add Dog <name> <price> For example: java tutorial.persistence.AnimalMaintenance add Dog Fluffy 35 You can view the contents of the database with: java tutorial.persistence.AnimalMaintenance list Dog
Deleting Objects What if someone decides to buy one of the dogs? The store owner will need to remove that animal from the database, since it is no longer in the inventory. This section demonstrates how to remove data from the datastore. Add the following code to AnimalMaintenance.java. Modify the deleteObjects method of AnimalMaintenance.java to look like this: /** * Performs the actual JPA work of removing * <code>objects</code> from the datastore. * * @param objects the objects to persist in the datastore * @param em the EntityManager to delete with */ public static void deleteObjects(Collection objects, EntityManager em) { // Mark the beginning of the unit of work boundary. em.getTransaction().begin(); // This method removes the objects in 'objects' from the data store. for (Object ob : objects) { System.out.println("Removed animal: " + ob); em.remove(ob); } // Mark the end of the unit of work boundary, and record all // deletes in the database. em.getTransaction().commit(); } Recompile AnimalMaintenance.java. javac AnimalMaintenance.java Remove some animals from the database. java tutorial.persistence.AnimalMaintenance remove <query> Where <query> is a query string like those used for listing animals above. All right. We now have a basic pet shop inventory management system. From this base, we will add some of the more advanced features suggested by our industry experts.
Inventory Growth Now that we have the basic pet store framework in place, let's add support for the next pet in our list: the rabbit. The rabbit is a bit different than the dog; pet stores sell them all for the same price, but gender is critically important since rabbits reproduce rather easily and quickly. Let's put together a class representing a rabbit. In this chapter, you will see some more queries and write a bidirectional relation between objects. Provided with this tutorial is a file called Rabbit.java which contains a sample Rabbit implementation. Examine Rabbit.java. The Rabbit class above contains a bidirectional relationship between parents and children. From the Java side of things, a bidirectional relationship is simply a pair of fields that are conceptually linked. There is no special Java work necessary to express bidirectionality. However, you must identify the relationship as bidirectional using JPA annotations so the mapping tool can create the most efficient schema. Insert this snippet of code immediately before the children field declaration in the Rabbit.java file. @ManyToMany @JoinTable(name="RABBIT_CHILDREN", joinColumns=@JoinColumn(name="PARENT_ID"), inverseJoinColumns=@JoinColumn(name="CHILD_ID")) The @ManyToMany annotation indicates that children is one side of a many-to-many relation. @JoinTable describes how this relation maps to a database join table. The annotation's joinColumns name the join table's foreign key columns linking to the owning instance (the parent). In this case, column RABBIT_CHILDREN.PARENT_ID is a foreign key to the parent's ID primary key column. Similarly, the inverseJoinColumns attribute denotes the foreign key columns linking to the collection elements (the children). For more details on the @JoinTable annotation, see of the JPA Overview. Now we'll map the other side of this bidirectional relation, the parents field. Insert the following snippet of code immediately before the parents field declaration in the Rabbit.java file. The mappedBy attribute identifies the name of the owning side of the relation. @ManyToMany(mappedBy="children") Compile Rabbit.java. javac Rabbit.java Enhance the Rabbit class. (Optional) java org.apache.openjpa.enhance.PCEnhancer Rabbit.java Refresh the object-relational mappings and database schema. java org.apache.openjpa.jdbc.meta.MappingTool Rabbit.java Now that we have a Rabbit class, let's get some preliminary rabbit data into the database. Add a <class> entry for Rabbit to ../../META-INF/persistence.xml. <class>tutorial.persistence.Rabbit</class> Create some rabbits. Run the following commands a few times to add some male and female rabbits to the database: java tutorial.persistence.AnimalMaintenance add Rabbit <name> false java tutorial.persistence.AnimalMaintenance add Rabbit <name> true Now run some breeding iterations. java tutorial.persistence.Rabbit breed 2 Look at your new rabbits. java tutorial.persistence.AnimalMaintenance list Rabbit java tutorial.persistence.AnimalMaintenance details "select r from Rabbit r where r.name = '<name>'"
Behavioral Analysis Often, pet stores sell snakes as well as rabbits and dogs. Pet stores are primarily concerned with a snake's length; much like rabbits, pet store operators usually sell them all for a flat rate. This chapter demonstrates more queries, schema manipulation, and additional relation types. Provided with this tutorial is a file called Snake.java which contains a sample Snake implementation. Let's get it compiled and loaded: Examine and compile Snake.java. javac Snake.java Enhance the class. (Optional) java org.apache.openjpa.enhance.PCEnhancer Snake.java Refresh the mappings and database. As we have created a new persistent class, we must map it to the database and change the schema to match. So run the mapping tool: java org.apache.openjpa.jdbc.meta.MappingTool Snake.java Add a <class> entry for Snake to ../../META-INF/persistence.xml. <class>tutorial.persistence.Snake</class> Once you have compiled everything, add a few snakes to the database using: java tutorial.persistence.AnimalMaintenance add Snake "name" <length> Where <length> is the length in feet for the new snake. To see the new snakes in the database, run: java tutorial.persistence.AnimalMaintenance list Snake Unfortunately for the massively developing rabbit population, snakes often eat rabbits. Any good inventory system should be able to capture this behavior. So, let's add some code to Snake.java to support the snake's eating behavior. First, let's modify Snake.java to contain a list of eaten rabbits. Add the following code snippets to Snake.java. // This list will be persisted into the database as // a one-to-many relation. @OneToMany(mappedBy="eater") private Set<Rabbit> giTract = new HashSet<Rabbit> (); Note that we specified a mappedBy attribute in this example. This is because the relation is bidirectional; that is, the rabbit has knowledge of which snake ate it. We could have left out the eater field and instead created a standard unidirectional relation. In fact, in a bidirectional many-to-one relation, the many side must always be the owner. For more information on types of relations, see of the JPA Overview. Modify the toString(boolean) method to output the giTract list. public String toString(boolean detailed) { StringBuffer buf = new StringBuffer(1024); buf.append("Snake ").append(getName()); if (detailed) { buf.append(" (").append(length).append(" feet long) sells for "); buf.append(getPrice()).append(" dollars."); buf.append(" Its gastrointestinal tract contains:\n"); for (Rabbit rabbit : giTract) buf.append("\t").append(rabbit).append("\n"); } else buf.append("; ate " + giTract.size() + " rabbits."); return buf.toString(); } Add the following methods. /** * Kills the specified rabbit and eats it. */ public void eat(Rabbit dinner) { // Consume the rabbit. dinner.kill(); dinner.setEater(this); giTract.add(dinner); System.out.println("Snake " + getName() + " ate rabbit " + dinner.getName() + "."); } /** * Locates the specified snake and tells it to eat a rabbit. */ public static void eat(EntityManager em, String filter) { em.getTransaction().begin(); // Find the desired snake(s) in the data store. Query query = em.createQuery(filter); List<Snake> results = query.getResultList(); if (results.isEmpty()) { System.out.println("No snakes matching '" + filter + "' found"); return; } Query uneatenQuery = em.createQuery ("select r from Rabbit r where r.isDead = false"); Random random = new Random(); for (Snake snake : results) { // Run a query for a rabbit whose 'isDead' field indicates // that it is alive. List<Rabbit> menu = uneatenQuery.getResultList(); if (menu.isEmpty()) { System.out.println("No live rabbits in DB."); break; } // Select a random rabbit from the list. Rabbit dinner = menu.get(random.nextInt(menu.size())); // Perform the eating. System.out.println(snake + " is eating:"); snake.eat(dinner); } em.getTransaction().commit(); } public static void main(String[] args) { if (args.length == 2 && args[0].equals("eat")) { EntityManagerFactory emf = Persistence. createEntityManagerFactory(null); EntityManager em = emf.createEntityManager(); eat(em, args[1]); em.close(); emf.close(); return; } // If we get here, something went wrong. System.out.println("Usage:"); System.out.println(" java tutorial.persistence.Snake eat " + "\"snakequery\""); } Add an eater field to Rabbit.java, and a getter and setter. @ManyToOne @JoinColumn(name="EATER_ID") private Snake eater; ... public Snake getEater() { return eater; } public void setEater(Snake snake) { eater = snake; } The @ManyToOne annotation indicates that this is the many side of the bidirectional relation. The many side must always be the owner in this type of relation. The @JoinColumn describes the foreign key that joins the rabbit table to the snake table. The rabbit table has an EATER_ID column that is a foreign key to the ID primary key column of the snake table. Compile Snake.java and Rabbit.java and optionally enhance the classes. javac Snake.java Rabbit.java java org.apache.openjpa.enhance.PCEnhancer Snake.java Rabbit.java Refresh the mappings and database. java org.apache.openjpa.jdbc.meta.MappingTool Snake.java Rabbit.java Now, experiment with the following commands: java tutorial.persistence.Snake eat "select s from Snake s where s.name = '<name>'" java tutorial.persistence.AnimalMaintenance details "select s from Snake s where s.name = '<name>'"
Complex Queries Imagine that one of the snakes in the database was named Killer. To find out which rabbits Killer ate, we could run either of the following two queries: java tutorial.persistence.AnimalMaintenance details "select s from Snake s where s.name = 'Killer'" java tutorial.persistence.AnimalMaintenance list "select r from Rabbit r where r.eater.name = 'Killer'" The first query is snake-centric - the query runs against the Snake class, looking for all snakes named Killer and providing a detailed listing of them. The second is rabbit-centric - it examines the rabbits in the database for instances whose eater is named Killer. This second query demonstrates that the simple Java 'dot' syntax is used when traversing a to-one field in a query. It is also possible to traverse collection fields. Imagine that there was a rabbit called Roger in the datastore and that one of the snakes ate it. In order to determine who ate Roger Rabbit, you could run a query like this: java tutorial.persistence.AnimalMaintenance details "select s from Snake s inner join s.giTract r where r.name = 'Roger'"
Extra Features Congratulations! You are now the proud author of a pet store inventory suite. Now that you have all the major features of the pet store software implemented, it's time to add some extra features. You're on your own; think of some features that you think a pet store should have, or just explore the features of JPA. Here are a couple of suggestions to get you started: Animal pricing. Modify Animal to contain an inventory cost and a resale price. Calculate the real dollar amount eaten by the snakes (the sum of the inventory costs of all the consumed rabbits), and the cost assuming that all the eaten rabbits would have been sold had they been alive. Ignore the fact that the rabbits, had they lived, would have created more rabbits, and the implications of the reduced food costs due to the not-quite-as-hungry snakes and the smaller number of rabbits. Dog categorization. Modify Dog to have a relation to a new class called Breed, which contains a name identifying the breed of the dog and a description of the breed. Put together an admin tool for breeds and for associating dogs and breeds.
J2EE Tutorial 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.
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.
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. 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.
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.
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. (Optional) java org.apache.openjpa.enhance.PCEnhancer 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/> java org.apache.openjpa.jdbc.meta.MappingTool 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
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.
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.
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" ).
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.
Code Notes and J2EE Tips 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 OpenJPA 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, OpenJPA 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. 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.