1.2. Kodo JPA Tutorial
Prev | Chapter 1. JPA Tutorials | Next

## 1.2. Kodo JPA Tutorial

In this tutorial you will become familiar with the basic tools and development processes under Kodo by creating a simple JPA application.

### 1.2.1. 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

#### 1.2.1.1. 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 Section 1.2.3, “Inventory Maintenance”.

- `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 Section 1.2.4, “Inventory Growth”.

- `tutorial.persistence.Snake`: Contains data and methods specific to snakes. It will be used in Section 1.2.5, “Behavioral Analysis”.

- `../../META-INF/persistence.xml`: This XML file contains Kodo-specific and standard JPA configuration settings.

  | Important
  You must ensure you have valid BEA license key available to Kodo. For further details on Kodo licensing, see Section 2.2, “License Configuration”.

  It is important to load all persistent entity classes at startup so that Kodo 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.

#### 1.2.1.2. Important Utilities

- `java`: Runs main methods in specified Java classes.

- `javac`: Compiles `.java` files into `.class` files that can be executed by `java`.

- `kodoc`: Runs the Kodo enhancer against the specified classes. More information is available in Section 5.2, “Enhancement” of the Reference Guide.

- `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 Chapter 7, Mapping of the Reference Guide for more information.

### 1.2.2. 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 pass the resulting classes through the Kodo enhancer:

| Note
Be sure that your `CLASSPATH` is set correctly. Please see Section 2.8, “Windows Installation” of Part I of this manual for Windows, or Section 2.9, “POSIX (Linux, Solaris, Mac OS X, Windows with cygwin, etc.) Installation” of Part I of this manual for POSIX (Linux, Solaris, Cygwin, etc.). Detailed information on which libraries are needed can be found in Appendix 7, Development and Runtime Libraries. Note, also, that your Kodo install directory should be in the `CLASSPATH`, as the tutorial classes are located in the `tutorial/persistence` directory under your Kodo install directory, and are in the `tutorial.persistence` package.

1. Make sure you are in the `tutorial/persistence` directory. All examples throughout the tutorial assume that you are in this directory.

2. 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 Chapter 5, Metadata and Chapter 12, Mapping Metadata.

   1. `@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.

   2. `@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.

   3. `@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.

   4. `@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 Chapter 5, Metadata.

   1. `@Id`: This annotation indicates that the field is to be mapped to a primary key column in the database.

   2. `@GeneratedValue`: Indicates that the implementation will generate a value for the field automatically.

   3. `@Column`: This annotation describes the column to which the field will be mapped. The `name` attribute specifies the name of the column.

   4. `@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.

3. Compile the `.java` files.

       javac *.java

   You can use any java compiler instead of `javac`.

4. Enhance the persistent classes.

       kodoc Animal.java Dog.java

   This step runs the Kodo enhancer on the `Animal.java` and `Dog.java` files mentioned above. See Section 5.2, “Enhancement” of the Reference Guide for more information on the enhancer, including how to use automatic runtime enhancement.

#### 1.2.2.1. Configuring the Datastore

Now that we've compiled the source files and enhanced the persistent classes, we're ready to set up the database. Hypersonic SQL, a pure Java relational database, is included in the Kodo 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 Chapter 4, JDBC of the Reference Guide.

1. Create the object-relational mappings and database schema.

       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. Chapter 12, Mapping Metadata of the JPA Overview will help you understand mapping annotations. Additionally, Chapter 7, Mapping of the Reference Guide describes your other mapping options in detail.

   If you are curious, you can view the schema Kodo created for the tutorial classes with Kodo's schema tool:

       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 Section 4.15, “XML Schema Format” of the Reference Guide for details. You may delete the `tmp.schema` file before proceeding.

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

### 1.2.3. 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.

1. 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();
           }

2. Compile `AnimalMaintenance.java`.

       javac AnimalMaintenance.java

3. 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 Chapter 10, JPA Query 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.

#### 1.2.3.1. 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.

1. 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);
           }

   | Note
   In the above code, we pass in an `EntityManager`. `EntityManager`s 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, `EntityManager`s are typically container managed, and thus injected or looked up via JNDI. Application managed `EntityManager`s 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`.

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

#### 1.2.3.2. 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.

1. 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();
           }

2. Recompile `AnimalMaintenance.java`.

       javac AnimalMaintenance.java

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

### 1.2.4. 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.

1. Examine `Rabbit.java`.

2. 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 Chapter 12, Mapping Metadata 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")

3. Compile `Rabbit.java`.

       javac Rabbit.java

4. Enhance the `Rabbit` class.

       kodoc Rabbit.java

5. Refresh the object-relational mappings and database schema.

       mappingtool Rabbit.java

Now that we have a Rabbit class, let's get some preliminary rabbit data into the database.

1. Add a `<class>` entry for `Rabbit` to `../../META-INF/persistence.xml`.

       <class>tutorial.persistence.Rabbit</class>

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

3. 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>'"

### 1.2.5. 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:

1. Examine and compile `Snake.java`.

       javac Snake.java

2. Enhance the class.

       kodoc Snake.java

3. 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:

       mappingtool Snake.java

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

1. 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 Section 12.8, “Field Mapping” 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\"");
           }

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

3. Compile `Snake.java` and `Rabbit.java` and enhance the classes.

       javac Snake.java Rabbit.java
       kodoc Snake.java Rabbit.java

4. Refresh the mappings and database.

       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>'"

#### 1.2.5.1. 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 the that simple java 'dot' syntax is used when traversing an 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'"

### 1.2.6. 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.

Prev | Up | Next
Chapter 1. JPA Tutorials | Home | 1.3. J2EE Tutorial