mirror of https://github.com/apache/openjpa.git
1549 lines
64 KiB
XML
1549 lines
64 KiB
XML
<?xml version="1.0" encoding="UTF-8"?>
|
|
<!--
|
|
Licensed to the Apache Software Foundation (ASF) under one
|
|
or more contributor license agreements. See the NOTICE file
|
|
distributed with this work for additional information
|
|
regarding copyright ownership. The ASF licenses this file
|
|
to you under the Apache License, Version 2.0 (the
|
|
"License"); you may not use this file except in compliance
|
|
with the License. You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing,
|
|
software distributed under the License is distributed on an
|
|
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
KIND, either express or implied. See the License for the
|
|
specific language governing permissions and limitations
|
|
under the License.
|
|
-->
|
|
<chapter id="jpa_tutorials">
|
|
<title>
|
|
JPA Tutorials
|
|
</title>
|
|
<section id="jpa_tutorials_intro">
|
|
<title>
|
|
OpenJPA Tutorials
|
|
</title>
|
|
<para>
|
|
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:
|
|
</para>
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para>
|
|
<ulink url="http://java.sun.com/">Sun's Java site</ulink>
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
<link linkend="jpa_overview_intro">JPA Overview Document</link>
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
<link linkend="jpa_resources">Links to JPA</link>
|
|
</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
<section id="jpa_tutorial_requirements">
|
|
<title>
|
|
Tutorial Requirements
|
|
</title>
|
|
<para>
|
|
These tutorials require that JDK 1.5 or greater be installed on your computer,
|
|
and that <literal>java</literal> and <literal>javac</literal> are in your
|
|
<literal>PATH</literal> when you open a command shell.
|
|
</para>
|
|
</section>
|
|
</section>
|
|
<section id="jpa_tutorial">
|
|
<title>
|
|
OpenJPA Tutorial
|
|
</title>
|
|
<para>
|
|
In this tutorial you will become familiar with the basic tools and development
|
|
processes under OpenJPA by creating a simple JPA application.
|
|
</para>
|
|
<section id="jpa_tutorial_chapter1">
|
|
<title>
|
|
The Pet Shop
|
|
</title>
|
|
<para>
|
|
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.
|
|
</para>
|
|
<para>
|
|
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:
|
|
</para>
|
|
<para>
|
|
<screen> Animal ^ | +--------------------+ | | | Dog Rabbit Snake</screen>
|
|
</para>
|
|
<section id="jpa_tutorial_files">
|
|
<title>
|
|
Included Files
|
|
</title>
|
|
<para>
|
|
We have provided an implementation of <classname>Animal</classname> and
|
|
<classname>Dog</classname> 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.
|
|
</para>
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para>
|
|
<ulink url="../../../tutorial/persistence/AnimalMaintenance.java"><classname>
|
|
tutorial.persistence.AnimalMaintenance</classname></ulink>: Provides some
|
|
utility methods for examining and manipulating the animals stored in the
|
|
database. We will fill in method definitions in
|
|
<xref linkend="jpa_tutorial_chapter3"/>.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
<ulink url="../../../tutorial/persistence/Animal.java"><classname>
|
|
tutorial.persistence.Animal</classname></ulink>: This is the superclass of all
|
|
animals that this pet store software can handle.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
<ulink url="../../../tutorial/persistence/Dog.java"><classname>
|
|
tutorial.persistence.Dog</classname></ulink>: Contains data and methods
|
|
specific to dogs.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
<ulink url="../../../tutorial/persistence/Rabbit.java"><classname>
|
|
tutorial.persistence.Rabbit</classname></ulink>: Contains data and methods
|
|
specific to rabbits. It will be used in <xref linkend="jpa_tutorial_chapter4"/>
|
|
.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
<ulink url="../../../tutorial/persistence/Snake.java"><classname>
|
|
tutorial.persistence.Snake</classname></ulink>: Contains data and methods
|
|
specific to snakes. It will be used in <xref linkend="jpa_tutorial_chapter5"/>
|
|
.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
<ulink url="../../../META-INF/persistence.xml"><filename>
|
|
../../META-INF/persistence.xml</filename></ulink>: This XML file contains
|
|
OpenJPA-specific and standard JPA configuration settings.
|
|
</para>
|
|
<para>
|
|
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 <filename>
|
|
../../META-INF/persistence.xml</filename> between the <literal><provider>
|
|
</literal> and the <literal><properties></literal> elements:
|
|
</para>
|
|
<programlisting>
|
|
<class>tutorial.persistence.Animal</class>
|
|
<class>tutorial.persistence.Dog</class>
|
|
</programlisting>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
<ulink url="../../../tutorial/persistence/solutions"><filename>solutions
|
|
</filename></ulink>: The solutions directory contains the complete solutions to
|
|
this tutorial, including finished versions of the <filename>.java</filename>
|
|
files listed above.
|
|
</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
</section>
|
|
<section id="jpa_tutorial_utilities">
|
|
<title>
|
|
Important Utilities
|
|
</title>
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para>
|
|
<command>java</command>: Runs main methods in specified Java classes.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
<command>javac</command>: Compiles <filename>.java</filename> files into
|
|
<filename>.class</filename> files that can be executed by <command>java
|
|
</command>.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
<indexterm>
|
|
<primary>
|
|
org.apache.openjpa.enhance.PCEnhancer
|
|
</primary>
|
|
</indexterm>
|
|
<command>org.apache.openjpa.enhance.PCEnhancer</command>:
|
|
Runs the OpenJPA enhancer against the specified
|
|
classes. More information is available in <xref linkend="ref_guide_pc_enhance"/>
|
|
of the Reference Guide.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
<indexterm>
|
|
<primary>
|
|
org.apache.openjpa.jdbc.meta.MappingTool
|
|
</primary>
|
|
</indexterm>
|
|
<command>org.apache.openjpa.jdbc.meta.MappingTool</command>:
|
|
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
|
|
<xref linkend="ref_guide_mapping"/> of the Reference Guide for more
|
|
information.
|
|
</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
</section>
|
|
</section>
|
|
<section id="jpa_tutorial_chapter2">
|
|
<title>
|
|
Getting Started
|
|
</title>
|
|
<para>
|
|
Let's compile the initial classes and see them in action. To do so, we must
|
|
compile the <filename>.java</filename> files, as we would with any Java project,
|
|
and then optionally pass the resulting classes through the OpenJPA enhancer.
|
|
</para>
|
|
<note>
|
|
<para>
|
|
<indexterm>
|
|
<primary>
|
|
CLASSPATH
|
|
</primary>
|
|
</indexterm>
|
|
Be sure that your <envar>CLASSPATH</envar> is set correctly. Note that your
|
|
OpenJPA install directory should be in the <envar>CLASSPATH</envar>, as the
|
|
tutorial classes are located in the <literal> tutorial/persistence</literal>
|
|
directory under your OpenJPA install directory, and are in the <literal>
|
|
tutorial.persistence</literal> package.
|
|
</para>
|
|
</note>
|
|
<orderedlist>
|
|
<listitem>
|
|
<para>
|
|
Make sure you are in the <filename> tutorial/persistence</filename> directory.
|
|
All examples throughout the tutorial assume that you are in this directory.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
Examine <filename>Animal.java</filename>, <filename>Dog.java</filename>, and
|
|
<filename>SeedDatabase.java</filename>
|
|
</para>
|
|
<para>
|
|
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 <literal>seed</literal> method of <filename>SeedDatabase.java
|
|
</filename>. Note the objects are created with normal Java constructors. The
|
|
files <filename>Animal.java</filename> and <filename>Dog.java</filename> are
|
|
also good examples of how JPA allows you to manipulate persistent data without
|
|
writing any specific JPA code, by providing simple annotations.
|
|
</para>
|
|
<para>
|
|
Let's take a look at the <filename>Animal.java</filename> 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:
|
|
</para>
|
|
<programlisting>
|
|
@Entity(name="Animal")
|
|
@Table(name="JPA_TUT_ANIMAL")
|
|
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
|
|
@DiscriminatorColumn(name="SPECIES", length=100)
|
|
public abstract class Animal
|
|
{
|
|
...
|
|
}
|
|
</programlisting>
|
|
<para>
|
|
The annotations serve to map the class into the database. For more information
|
|
on these and other annotations, see <xref linkend="jpa_overview_meta"/>
|
|
and <xref linkend="jpa_overview_mapping"/>.
|
|
</para>
|
|
<orderedlist>
|
|
<listitem>
|
|
<para>
|
|
<command>@Entity</command>: This annotation indicates that instances of this
|
|
class may be persistent entities. The value of the <command>name</command>
|
|
attribute is the entity name, and is used in queries, etc.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
<command>@Table</command>: This annotation is used to map the entity to a
|
|
primary table. The value of the <command>name</command> attribute specifies the
|
|
name of the relational table to use as the primary table.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
<command>@Inheritance</command>: 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 <command>strategy
|
|
</command> attribute to <command>InheritanceType.SINGLE_TABLE</command>
|
|
indicates that the primary table for all subclasses shall be the same table as
|
|
for the superclass.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
<command>@DiscriminatorColumn</command>: With a <command>SINGLE_TABLE</command>
|
|
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
|
|
<command>name</command> attribute is the name of the column, and the <command>
|
|
length</command> 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 <command>@DiscriminatorValue
|
|
</command> annotation.
|
|
</para>
|
|
</listitem>
|
|
</orderedlist>
|
|
<para>
|
|
Let's take a look at our class' field annotations. We have chosen to use
|
|
<emphasis>field access</emphasis> 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 <emphasis> property access
|
|
</emphasis>, 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.
|
|
</para>
|
|
<programlisting>
|
|
@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;
|
|
</programlisting>
|
|
<para>
|
|
The annotations serve to map the fields into the database. For more information
|
|
on these and other annotations, see <xref linkend="jpa_overview_meta"/>.
|
|
</para>
|
|
<orderedlist>
|
|
<listitem>
|
|
<para>
|
|
<command>@Id</command>: This annotation indicates that the field is to be
|
|
mapped to a primary key column in the database.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
<command>@GeneratedValue</command>: Indicates that the implementation will
|
|
generate a value for the field automatically.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
<command>@Column</command>: This annotation describes the column to which the
|
|
field will be mapped. The <command>name</command> attribute specifies the name
|
|
of the column.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
<command>@Basic</command>: 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.
|
|
</para>
|
|
</listitem>
|
|
</orderedlist>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
Compile the <filename>.java</filename> files.
|
|
</para>
|
|
<programlisting>
|
|
javac *.java
|
|
</programlisting>
|
|
<para>
|
|
You can use any Java compiler instead of <command>javac</command>.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
Enhance the persistent classes. (Optional)
|
|
</para>
|
|
<programlisting>
|
|
java org.apache.openjpa.enhance.PCEnhancer Animal.java Dog.java
|
|
</programlisting>
|
|
<para>
|
|
This step runs the OpenJPA enhancer on the <filename>Animal.java</filename> and
|
|
<filename>Dog.java</filename> files mentioned above. See
|
|
<xref linkend="ref_guide_pc_enhance"/> of the Reference Guide for more
|
|
information on the enhancer, including alternatives to enhancement.
|
|
</para>
|
|
<note>
|
|
<para>
|
|
The <literal>-p</literal> flag points the enhancer to your <filename>
|
|
persistence.xml</filename> configuration file. All OpenJPA tools look for
|
|
default configuration in a resource called <filename>openjpa.xml</filename> or
|
|
<filename>META-INF/openjpa.xml</filename>. Thus you can avoid passing the
|
|
<literal>-p</literal> argument to tools by using this configuration file name in
|
|
place of <filename>persistence.xml</filename>. See
|
|
<xref linkend="ref_guide_conf"/> in the Reference Guide for details on
|
|
OpenJPA configuration.
|
|
</para>
|
|
</note>
|
|
</listitem>
|
|
</orderedlist>
|
|
<section id="jpa_tutorial_chapter2_datastore">
|
|
<title>
|
|
Configuring the Datastore
|
|
</title>
|
|
<para>
|
|
Now that we've compiled the source files,
|
|
we're ready to set up the database. <ulink url="http://hsqldb.sourceforge.net">
|
|
Hypersonic SQL</ulink>, 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 <xref linkend="ref_guide_dbsetup"/> of
|
|
the Reference Guide.
|
|
</para>
|
|
<orderedlist>
|
|
<listitem>
|
|
<para>
|
|
<indexterm>
|
|
<primary>
|
|
org.apache.openjpa.jdbc.meta.MappingTool
|
|
</primary>
|
|
</indexterm>
|
|
Create the object-relational mappings and database schema.
|
|
</para>
|
|
<programlisting>
|
|
java org.apache.openjpa.jdbc.meta.MappingTool Animal.java Dog.java
|
|
</programlisting>
|
|
<para>
|
|
This command propagates the necessary schema for the specified classes to the
|
|
database configured in <filename>persistence.xml</filename>. If you are using
|
|
the default Hypersonic SQL setup, the first time you run the mapping tool
|
|
Hypersonic will create <filename>tutorial_database.properties</filename> and
|
|
<filename>tutorial_database.script</filename> database files in your current
|
|
directory. To delete the database, just delete these files.
|
|
</para>
|
|
<para>
|
|
By default, JPA uses object-relational mapping information stored in annotations
|
|
in your source files. <xref linkend="jpa_overview_mapping"/> of the JPA
|
|
Overview will help you understand mapping annotations. Additionally,
|
|
<xref linkend="ref_guide_mapping"/> of the Reference Guide describes your
|
|
other mapping options in detail.
|
|
</para>
|
|
<para>
|
|
</para>
|
|
<para>
|
|
If you are curious, you can view the schema OpenJPA created for the tutorial
|
|
classes with OpenJPA's schema tool:
|
|
</para>
|
|
<programlisting>
|
|
java org.apache.openjpa.jdbc.schema.SchemaTool -a reflect -f tmp.schema
|
|
</programlisting>
|
|
<para>
|
|
This will create a <filename>tmp.schema</filename> file with an XML
|
|
representation of the database schema. The XML should be self explanatory; see
|
|
<xref linkend="ref_guide_schema_xml"/> of the Reference Guide for details.
|
|
You may delete the <filename>tmp.schema</filename> file before proceeding.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
Populate the database with sample data.
|
|
</para>
|
|
<programlisting>
|
|
java tutorial.persistence.SeedDatabase
|
|
</programlisting>
|
|
</listitem>
|
|
</orderedlist>
|
|
<para>
|
|
Congratulations! You have now created an JPA-accessible persistent store, and
|
|
seeded it with some sample data.
|
|
</para>
|
|
</section>
|
|
</section>
|
|
<section id="jpa_tutorial_chapter3">
|
|
<title>
|
|
Inventory Maintenance
|
|
</title>
|
|
<para>
|
|
The most important element of a successful pet store product, say the experts,
|
|
is an inventory maintenance mechanism. So, let's work on the <classname>Animal
|
|
</classname> and <classname>Dog</classname> classes a bit to permit user
|
|
interaction with the database.
|
|
</para>
|
|
<para>
|
|
This chapter should familiarize you with some of the basics of the
|
|
<ulink url="../../ejb-3_0-pr-spec-persistence.pdf">JPA specification</ulink> 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.
|
|
</para>
|
|
<para>
|
|
First, let's add some code to <filename>AnimalMaintenance.java</filename> that
|
|
allows us to examine the animals currently in the database.
|
|
</para>
|
|
<orderedlist>
|
|
<listitem>
|
|
<para>
|
|
Add code to <filename>AnimalMaintenance.java</filename>.
|
|
</para>
|
|
<para>
|
|
Modify the <methodname>getAnimals</methodname> method of <filename>
|
|
AnimalMaintenance.java</filename> to look like this:
|
|
</para>
|
|
<programlisting>
|
|
/**
|
|
* 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();
|
|
}
|
|
</programlisting>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
Compile <filename>AnimalMaintenance.java</filename>.
|
|
</para>
|
|
<programlisting>
|
|
javac AnimalMaintenance.java
|
|
</programlisting>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
Take a look at the animals in the database.
|
|
</para>
|
|
<programlisting>
|
|
java tutorial.persistence.AnimalMaintenance list Animal
|
|
</programlisting>
|
|
<para>
|
|
Notice that <methodname>list</methodname> optionally takes a query filter. Let's
|
|
explore the database some more, this time using filters:
|
|
</para>
|
|
<programlisting>
|
|
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"
|
|
</programlisting>
|
|
<para>
|
|
The Java Persistence Query Language (JPQL) is designed to look and behave much
|
|
like an object oriented SQL dialect. The <literal>name</literal> and <literal>
|
|
price</literal> fields identified in the above queries map to the member fields
|
|
of those names in <classname> tutorial.persistence.Animal</classname>. More
|
|
details on JPQL syntax is available in <xref linkend="jpa_overview_query"/>
|
|
of the JPA Overview.
|
|
</para>
|
|
</listitem>
|
|
</orderedlist>
|
|
<para>
|
|
Great! Now that we can see the contents of the database, let's add some code
|
|
that lets us add and remove animals.
|
|
</para>
|
|
<section id="jpa_tutorial_chapter3_persist">
|
|
<title>
|
|
Persisting Objects
|
|
</title>
|
|
<para>
|
|
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 <classname>tutorial.persistence.AnimalMaintenance
|
|
</classname> class.
|
|
</para>
|
|
<para>
|
|
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
|
|
<classname>Transaction</classname> from a <classname>EntityManager</classname>,
|
|
and, within the transaction, make the new dog object persistent.
|
|
</para>
|
|
<para>
|
|
<classname>tutorial.persistence.AnimalMaintenance</classname> 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.
|
|
</para>
|
|
<orderedlist>
|
|
<listitem>
|
|
<para>
|
|
Add the following code to <filename> AnimalMaintenance.java</filename>.
|
|
</para>
|
|
<para>
|
|
Modify the <methodname>persistObject</methodname> method of <filename>
|
|
AnimalMaintenance.java</filename> to look like this:
|
|
</para>
|
|
<programlisting>
|
|
/**
|
|
* 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);
|
|
}
|
|
</programlisting>
|
|
<note>
|
|
<para>
|
|
In the above code, we pass in an <classname>EntityManager</classname>.
|
|
<classname>EntityManager</classname>s may be either container managed or
|
|
application managed. In this tutorial, because we're operating outside a
|
|
container, we're using application managed <classname>EntityManager</classname>
|
|
s. In managed environments, <classname>EntityManager</classname>s are typically
|
|
container managed, and thus injected or looked up via JNDI. Application managed
|
|
<classname>EntityManager</classname>s can be used in both managed and unmanaged
|
|
environments, and are created by an <classname>EntityManagerFactory</classname>
|
|
. An <classname>EntityManagerFactory</classname> can be obtained from the
|
|
<classname>javax.persistence.Persistence</classname> class. This class provides
|
|
some convenience methods for obtaining an <classname>EntityManagerFactory
|
|
</classname>.
|
|
</para>
|
|
</note>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
Recompile <filename>AnimalMaintenance.java</filename>.
|
|
</para>
|
|
<programlisting>
|
|
javac AnimalMaintenance.java
|
|
</programlisting>
|
|
</listitem>
|
|
</orderedlist>
|
|
<para>
|
|
You now have a mechanism for adding new dogs to the database. Go ahead and add
|
|
some by running <command>java tutorial.persistence.AnimalMaintenance add Dog
|
|
<name> <price></command> For example:
|
|
</para>
|
|
<programlisting>
|
|
java tutorial.persistence.AnimalMaintenance add Dog Fluffy 35
|
|
</programlisting>
|
|
<para>
|
|
You can view the contents of the database with:
|
|
</para>
|
|
<programlisting>
|
|
java tutorial.persistence.AnimalMaintenance list Dog
|
|
</programlisting>
|
|
</section>
|
|
<section id="jpa_tutorial_chapter3_delete">
|
|
<title>
|
|
Deleting Objects
|
|
</title>
|
|
<para>
|
|
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.
|
|
</para>
|
|
<para>
|
|
This section demonstrates how to remove data from the datastore.
|
|
</para>
|
|
<orderedlist>
|
|
<listitem>
|
|
<para>
|
|
Add the following code to <filename>AnimalMaintenance.java</filename>.
|
|
</para>
|
|
<para>
|
|
Modify the <methodname>deleteObjects</methodname> method of <filename>
|
|
AnimalMaintenance.java</filename> to look like this:
|
|
</para>
|
|
<programlisting>
|
|
/**
|
|
* 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();
|
|
}
|
|
</programlisting>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
Recompile <filename>AnimalMaintenance.java</filename>.
|
|
</para>
|
|
<programlisting>
|
|
javac AnimalMaintenance.java
|
|
</programlisting>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
Remove some animals from the database.
|
|
</para>
|
|
<programlisting>
|
|
java tutorial.persistence.AnimalMaintenance remove <query>
|
|
</programlisting>
|
|
<para>
|
|
Where <replaceable><query></replaceable> is a query string like those used
|
|
for listing animals above.
|
|
</para>
|
|
</listitem>
|
|
</orderedlist>
|
|
<para>
|
|
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.
|
|
</para>
|
|
</section>
|
|
</section>
|
|
<section id="jpa_tutorial_chapter4">
|
|
<title>
|
|
Inventory Growth
|
|
</title>
|
|
<para>
|
|
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.
|
|
</para>
|
|
<para>
|
|
In this chapter, you will see some more queries and write a bidirectional
|
|
relation between objects.
|
|
</para>
|
|
<para>
|
|
Provided with this tutorial is a file called <filename>Rabbit.java</filename>
|
|
which contains a sample <classname>Rabbit</classname> implementation.
|
|
</para>
|
|
<orderedlist>
|
|
<listitem>
|
|
<para>
|
|
Examine <filename>Rabbit.java</filename>.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
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 <link linkend="jpa_overview_meta">
|
|
annotations</link> so the mapping tool can create the most efficient schema.
|
|
</para>
|
|
<para>
|
|
Insert this snippet of code immediately <emphasis>before</emphasis> the
|
|
<literal>children</literal> field declaration in the <filename>Rabbit.java
|
|
</filename> file.
|
|
</para>
|
|
<programlisting>
|
|
@ManyToMany
|
|
@JoinTable(name="RABBIT_CHILDREN",
|
|
joinColumns=@JoinColumn(name="PARENT_ID"),
|
|
inverseJoinColumns=@JoinColumn(name="CHILD_ID"))
|
|
</programlisting>
|
|
<para>
|
|
The <literal>@ManyToMany</literal> annotation indicates that <literal>children
|
|
</literal> is one side of a many-to-many relation. <literal>@JoinTable</literal>
|
|
describes how this relation maps to a database join table. The annotation's
|
|
<literal>joinColumns</literal> name the join table's foreign key columns linking
|
|
to the owning instance (the parent). In this case, column <literal>
|
|
RABBIT_CHILDREN.PARENT_ID</literal> is a foreign key to the parent's <literal>
|
|
ID</literal> primary key column. Similarly, the <literal>inverseJoinColumns
|
|
</literal> attribute denotes the foreign key columns linking to the collection
|
|
elements (the children). For more details on the <literal>@JoinTable</literal>
|
|
annotation, see <xref linkend="jpa_overview_mapping"/> of the JPA
|
|
Overview.
|
|
</para>
|
|
<para>
|
|
Now we'll map the other side of this bidirectional relation, the <literal>
|
|
parents</literal> field. Insert the following snippet of code immediately
|
|
<emphasis>before</emphasis> the <command>parents</command> field declaration in
|
|
the <filename>Rabbit.java</filename> file. The <literal>mappedBy</literal>
|
|
attribute identifies the name of the owning side of the relation.
|
|
</para>
|
|
<programlisting>
|
|
@ManyToMany(mappedBy="children")
|
|
</programlisting>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
Compile <filename>Rabbit.java</filename>.
|
|
</para>
|
|
<programlisting>
|
|
javac Rabbit.java
|
|
</programlisting>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
Enhance the <classname>Rabbit</classname> class. (Optional)
|
|
</para>
|
|
<programlisting>
|
|
java org.apache.openjpa.enhance.PCEnhancer Rabbit.java
|
|
</programlisting>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
Refresh the object-relational mappings and database schema.
|
|
</para>
|
|
<programlisting>
|
|
java org.apache.openjpa.jdbc.meta.MappingTool Rabbit.java
|
|
</programlisting>
|
|
</listitem>
|
|
</orderedlist>
|
|
<para>
|
|
Now that we have a Rabbit class, let's get some preliminary rabbit data into the
|
|
database.
|
|
</para>
|
|
<orderedlist>
|
|
<listitem>
|
|
<para>
|
|
Add a <literal><class></literal> entry for <classname> Rabbit</classname>
|
|
to <filename>../../META-INF/persistence.xml</filename>.
|
|
</para>
|
|
<programlisting>
|
|
<class>tutorial.persistence.Rabbit</class>
|
|
</programlisting>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
Create some rabbits.
|
|
</para>
|
|
<para>
|
|
Run the following commands a few times to add some male and female rabbits to
|
|
the database:
|
|
</para>
|
|
<programlisting>
|
|
java tutorial.persistence.AnimalMaintenance add Rabbit <name> false
|
|
java tutorial.persistence.AnimalMaintenance add Rabbit <name> true
|
|
</programlisting>
|
|
<para>
|
|
Now run some breeding iterations.
|
|
</para>
|
|
<programlisting>
|
|
java tutorial.persistence.Rabbit breed 2
|
|
</programlisting>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
Look at your new rabbits.
|
|
</para>
|
|
<programlisting>
|
|
java tutorial.persistence.AnimalMaintenance list Rabbit
|
|
java tutorial.persistence.AnimalMaintenance details "select r from Rabbit r where r.name = '<name>'"
|
|
</programlisting>
|
|
</listitem>
|
|
</orderedlist>
|
|
</section>
|
|
<section id="jpa_tutorial_chapter5">
|
|
<title>
|
|
Behavioral Analysis
|
|
</title>
|
|
<para>
|
|
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.
|
|
</para>
|
|
<para>
|
|
This chapter demonstrates more queries, schema manipulation, and additional
|
|
relation types.
|
|
</para>
|
|
<para>
|
|
Provided with this tutorial is a file called <filename>Snake.java</filename>
|
|
which contains a sample <classname>Snake</classname> implementation. Let's get
|
|
it compiled and loaded:
|
|
</para>
|
|
<orderedlist>
|
|
<listitem>
|
|
<para>
|
|
Examine and compile <filename>Snake.java</filename>.
|
|
</para>
|
|
<programlisting>
|
|
javac Snake.java
|
|
</programlisting>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
Enhance the class. (Optional)
|
|
</para>
|
|
<programlisting>
|
|
java org.apache.openjpa.enhance.PCEnhancer Snake.java
|
|
</programlisting>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
Refresh the mappings and database.
|
|
</para>
|
|
<para>
|
|
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:
|
|
</para>
|
|
<programlisting>
|
|
java org.apache.openjpa.jdbc.meta.MappingTool Snake.java
|
|
</programlisting>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
Add a <literal><class></literal> entry for <classname> Snake</classname>
|
|
to <filename>../../META-INF/persistence.xml</filename>.
|
|
</para>
|
|
<programlisting>
|
|
<class>tutorial.persistence.Snake</class>
|
|
</programlisting>
|
|
</listitem>
|
|
</orderedlist>
|
|
<para>
|
|
Once you have compiled everything, add a few snakes to the database using:
|
|
</para>
|
|
<programlisting>
|
|
java tutorial.persistence.AnimalMaintenance add Snake "name" <length>
|
|
</programlisting>
|
|
<para>
|
|
Where <replaceable><length></replaceable> is the length in feet for the
|
|
new snake. To see the new snakes in the database, run:
|
|
</para>
|
|
<programlisting>
|
|
java tutorial.persistence.AnimalMaintenance list Snake
|
|
</programlisting>
|
|
<para>
|
|
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 <filename>Snake.java</filename> to support the snake's
|
|
eating behavior.
|
|
</para>
|
|
<para>
|
|
First, let's modify <filename>Snake.java</filename> to contain a list of eaten
|
|
rabbits.
|
|
</para>
|
|
<orderedlist>
|
|
<listitem>
|
|
<para>
|
|
Add the following code snippets to <filename>Snake.java</filename>.
|
|
</para>
|
|
<programlisting>
|
|
// This list will be persisted into the database as
|
|
// a one-to-many relation.
|
|
@OneToMany(mappedBy="eater")
|
|
private Set<Rabbit> giTract = new HashSet<Rabbit> ();
|
|
</programlisting>
|
|
<para>
|
|
Note that we specified a <literal>mappedBy</literal> 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 <literal>eater</literal> 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.
|
|
</para>
|
|
<para>
|
|
For more information on types of relations, see
|
|
<xref linkend="jpa_overview_mapping_field"/> of the JPA Overview.
|
|
</para>
|
|
<para>
|
|
Modify the <literal>toString(boolean)</literal> method to output the giTract
|
|
list.
|
|
</para>
|
|
<programlisting>
|
|
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();
|
|
}
|
|
</programlisting>
|
|
<para>
|
|
Add the following methods.
|
|
</para>
|
|
<programlisting>
|
|
/**
|
|
* 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\"");
|
|
}
|
|
</programlisting>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
Add an <literal>eater</literal> field to <filename>Rabbit.java</filename>, and
|
|
a getter and setter.
|
|
</para>
|
|
<programlisting>
|
|
@ManyToOne @JoinColumn(name="EATER_ID")
|
|
private Snake eater;
|
|
|
|
...
|
|
|
|
public Snake getEater()
|
|
{
|
|
return eater;
|
|
}
|
|
|
|
|
|
public void setEater(Snake snake)
|
|
{
|
|
eater = snake;
|
|
}
|
|
</programlisting>
|
|
<para>
|
|
The <literal>@ManyToOne</literal> 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 <literal>@JoinColumn</literal> describes the foreign
|
|
key that joins the rabbit table to the snake table. The rabbit table has an
|
|
<literal>EATER_ID</literal> column that is a foreign key to the <literal>ID
|
|
</literal> primary key column of the snake table.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
Compile <filename>Snake.java</filename> and <filename>Rabbit.java</filename> and
|
|
optionally enhance the classes.
|
|
</para>
|
|
<programlisting>
|
|
javac Snake.java Rabbit.java
|
|
java org.apache.openjpa.enhance.PCEnhancer Snake.java Rabbit.java
|
|
</programlisting>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
Refresh the mappings and database.
|
|
</para>
|
|
<programlisting>
|
|
java org.apache.openjpa.jdbc.meta.MappingTool Snake.java Rabbit.java
|
|
</programlisting>
|
|
</listitem>
|
|
</orderedlist>
|
|
<para>
|
|
Now, experiment with the following commands:
|
|
</para>
|
|
<programlisting>
|
|
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>'"
|
|
</programlisting>
|
|
<section id="jpa_tutorial_chapter5_query">
|
|
<title>
|
|
Complex Queries
|
|
</title>
|
|
<para>
|
|
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:
|
|
</para>
|
|
<programlisting>
|
|
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'"
|
|
</programlisting>
|
|
<para>
|
|
The first query is snake-centric - the query runs against the <classname>Snake
|
|
</classname> 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 <literal>eater</literal> is named Killer. This
|
|
second query demonstrates that the simple Java 'dot' syntax is used when
|
|
traversing a to-one field in a query.
|
|
</para>
|
|
<para>
|
|
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:
|
|
</para>
|
|
<programlisting>
|
|
java tutorial.persistence.AnimalMaintenance details "select s from Snake s inner join s.giTract r where r.name = 'Roger'"
|
|
</programlisting>
|
|
</section>
|
|
</section>
|
|
<section id="jpa_tutorial-chapter6">
|
|
<title>
|
|
Extra Features
|
|
</title>
|
|
<para>
|
|
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.
|
|
</para>
|
|
<para>
|
|
Here are a couple of suggestions to get you started:
|
|
</para>
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para>
|
|
Animal pricing.
|
|
</para>
|
|
<para>
|
|
Modify <classname>Animal</classname> 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.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
Dog categorization.
|
|
</para>
|
|
<para>
|
|
Modify <classname>Dog</classname> to have a relation to a new class called
|
|
<classname>Breed</classname>, 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.
|
|
</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
</section>
|
|
</section>
|
|
<section id="jpa_j2ee_tutorial">
|
|
<title>
|
|
J2EE Tutorial
|
|
</title>
|
|
<para>
|
|
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.
|
|
</para>
|
|
<section id="jpa_j2ee_tutorial_requirements">
|
|
<title>
|
|
Prerequisites for the OpenJPA J2EE Tutorial
|
|
</title>
|
|
<para>
|
|
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.
|
|
</para>
|
|
<para>
|
|
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.
|
|
</para>
|
|
<para>
|
|
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.
|
|
</para>
|
|
</section>
|
|
<section id="jpa_j2ee_tutorial_installation_types">
|
|
<title>
|
|
J2EE Installation Types
|
|
</title>
|
|
<para>
|
|
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.
|
|
</para>
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para>
|
|
<literal>JPA</literal>: J2EE 5 allows for the automatic injection of <classname>
|
|
EntityManager</classname> instances into the J2EE context.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
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 <classname>
|
|
org.apache.openjpa.persistence.EntityManagerFactoryImpl</classname> into JNDI.
|
|
</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
</section>
|
|
<section id="jpa_j2ee_tutorial_installing_sample">
|
|
<title>
|
|
Installing the J2EE Sample Application
|
|
</title>
|
|
<para>
|
|
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.
|
|
</para>
|
|
<section id="jpa_j2ee_tutorial_building_sample">
|
|
<title>
|
|
Compiling and Building The Sample Application
|
|
</title>
|
|
<para>
|
|
Navigate to the <filename>samples/persistence/j2ee</filename> directory of your
|
|
OpenJPA installation.
|
|
</para>
|
|
<para>
|
|
Ensure that the JNDI name in the setSessionContext() method in ejb/CarBean.java
|
|
matches your JCA installation. This defaults to <literal>java:/openjpa-ejb
|
|
</literal>, 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 <literal>openjpa-ejb</literal>.
|
|
</para>
|
|
<para>
|
|
Compile the source files in place both in this base directory as well as the
|
|
nested <filename>ejb</filename> and <filename>jsp</filename> directories:
|
|
</para>
|
|
<programlisting>
|
|
javac *.java ejb/*.java jsp/*.java
|
|
</programlisting>
|
|
<para>
|
|
Enhance the Car class. (Optional)
|
|
</para>
|
|
<programlisting>
|
|
java org.apache.openjpa.enhance.PCEnhancer Car.java
|
|
</programlisting>
|
|
<para>
|
|
Run the mapping tool; make sure that your <filename> META-INF/persistence.xml
|
|
</filename> file includes the same connection information (e.g. Driver, URL,
|
|
etc.) as your JCA installation. You should update your JCA configuration to
|
|
include <classname>samples.persistence.j2ee.Car</classname> in the
|
|
<link linkend="openjpa.MetaDataFactory">MetaDataFactory</link> property:
|
|
</para>
|
|
<programlisting>
|
|
<config-property name="MetaDataFactory">Types=samples.persistence.j2ee.Car</config-property/>
|
|
</programlisting>
|
|
<programlisting>
|
|
java org.apache.openjpa.jdbc.meta.MappingTool Car.java
|
|
</programlisting>
|
|
<para>
|
|
Build an J2EE application archive by running Ant against the <filename>
|
|
build.xml</filename>. This will create <filename>
|
|
openjpa-persistence-j2ee-sample.ear</filename>. This ear can now be deployed to
|
|
your appserver. Be sure to add the class <classname>samples.j2ee.Car</classname>
|
|
to the <literal>openjpa.PersistentClasses</literal> OpenJPA configuration
|
|
property. This will automatically register the Entity.
|
|
</para>
|
|
<programlisting>
|
|
ant -f build.xml
|
|
</programlisting>
|
|
</section>
|
|
<section id="jpa_j2ee_tutorial_sample_jboss">
|
|
<title>
|
|
Deploying Sample To JBoss
|
|
</title>
|
|
<para>
|
|
Place the ear file in the <filename>deploy</filename> directory of your JBoss
|
|
installation. You can use the above hints to view the JNDI tree to see if
|
|
<classname>samples.j2ee.ejb.CarHome</classname> was deployed to JNDI.
|
|
</para>
|
|
</section>
|
|
<section id="jpa_j2ee_tutorial_sample_weblogic">
|
|
<title>
|
|
Deploying Sample To WebLogic 9
|
|
</title>
|
|
<para>
|
|
Place the ear file in the <filename>autodeploy</filename> 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 <computeroutput>openjpa-persistence-j2ee-sample
|
|
</computeroutput> listed in the Deployments section of the admin console. In
|
|
addition you should find <literal>CarHome</literal> listed in the JNDI tree
|
|
under <computeroutput>AdminServer->samples->j2ee->ejb</computeroutput>
|
|
. Ensure that you have added the class <classname>samples.j2ee.Car</classname>
|
|
to the <literal>openjpa.PersistentClasses</literal> OpenJPA configuration
|
|
property in the <literal>META-INF/ra.xml</literal> file.
|
|
</para>
|
|
</section>
|
|
</section>
|
|
<section id="jpa_j2ee_tutorial_using">
|
|
<title>
|
|
Using The Sample Application
|
|
</title>
|
|
<para>
|
|
The sample application installs itself into the web layer at the context root of
|
|
sample. By browsing to <computeroutput>
|
|
http://yourserver:yourport/openjpa-persistence-j2ee-sample</computeroutput>,
|
|
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 <classname>
|
|
Car</classname> instances by passing in an JPQL query into the marked form (such
|
|
as <computeroutput>select car from Car car where car.model="Some Model"
|
|
</computeroutput> ).
|
|
</para>
|
|
</section>
|
|
<section id="jpa_j2ee_tutorial_architecture">
|
|
<title>
|
|
Sample Architecture
|
|
</title>
|
|
<para>
|
|
The garage application is a simple enterprise application that demonstrates some
|
|
of the basic concepts necessary when using OpenJPA in the enterprise layer.
|
|
</para>
|
|
<para>
|
|
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).
|
|
</para>
|
|
<para>
|
|
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 <classname>Car
|
|
</classname> instance will be used as the primary object upon which the client
|
|
will work.
|
|
</para>
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para>
|
|
<literal>samples/persistence/j2ee/Car.java</literal>: 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, <classname>Car
|
|
</classname> implements <classname>java.io.Serializable</classname> so that
|
|
remote clients can access cars as parameters and return values from the EJB.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
<literal> samples/persistence/j2ee/jsp/SampleUtilities.java</literal>: 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.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
<literal>samples/persistence/j2ee/ejb/Car*.java</literal>: The source for the
|
|
<classname>CarEJB</classname> session bean. Clients can use the <classname>
|
|
CarHome</classname> and <classname>CarRemote</classname> interfaces to find,
|
|
manipulate, and persist changes to <classname>Car</classname> transfer object
|
|
instances. By using J2EE transactional features, the implementation code in
|
|
<filename>CarBean.java</filename> can be focused almost entirely upon business
|
|
and persistence logic without worrying about transactions.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
<literal>samples/persistence/j2ee/jsp/*.jsp</literal>: The web presentation
|
|
client. These JSPs are not aware of the JPA; they simply use the <classname>
|
|
CarEJB</classname> session bean and the <classname>Car</classname> transfer
|
|
object to do all the work.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
<literal>samples/persistence/j2ee/resources/*</literal>: Files required to
|
|
deploy to the various appservers, including J2EE deployment descriptors, WAR/
|
|
EJB/ EAR descriptors, as well as appserver specific files.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
<literal>samples/persistence/j2ee/build.xml</literal>: A simple Ant build file
|
|
to help in creating a J2EE EAR file.
|
|
</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
</section>
|
|
<section id="jpa_j2ee_tutorial_notes">
|
|
<title>
|
|
Code Notes and J2EE Tips
|
|
</title>
|
|
<orderedlist>
|
|
<listitem>
|
|
<para>
|
|
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, <methodname>CarBean.edit</methodname> 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.
|
|
</para>
|
|
<para>
|
|
<classname>CarEJB</classname> works as a session bean facade to demarcate
|
|
transactions, provide finder methods, and encapsulate complex business logic at
|
|
the server level.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
<methodname>EntityManager.close()</methodname> should be called at the end of
|
|
every EJB method. In addition to ensuring that your code will not attempt to
|
|
access a closed <classname>EntityManager</classname>, it allows OpenJPA to free
|
|
up unused resources. Since an <classname>EntityManager</classname> is created
|
|
for every transaction, this can increase the scalability of your application.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
You should not use <methodname> EntityManager.getTransaction()</methodname> when
|
|
using JTA to manage your transactions. Instead, OpenJPA will integrate with JTA
|
|
to automatically govern transactions based on your EJB transaction
|
|
configuration.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
While serialization of entity instances is relatively straightforward, there are
|
|
several things to keep in mind:
|
|
</para>
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para>
|
|
While "default fetch group" values will always be returned to the client upon
|
|
serialization, lazily loaded fields will not as the <classname>EntityManager
|
|
</classname> 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.
|
|
</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
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 <classname>javax.transaction.UserTransaction
|
|
</classname> interface. Furthermore, outside of session beans you can control
|
|
the JPA layer's transaction via the <classname>
|
|
javax.persistence.EntityTransaction</classname> interface.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
<classname>EntityManager</classname>s are allocated on a per-Transaction basis.
|
|
Calling <methodname>getEntityManager</methodname> from the same <classname>
|
|
EntityManagerFactory</classname> 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 <literal>==</literal> operator.
|
|
</para>
|
|
</listitem>
|
|
</orderedlist>
|
|
</section>
|
|
</section>
|
|
</chapter>
|