Exercise 8.1: Single Table per Hierarchy




Exercise 8.1: Single Table per Hierarchy

This exercise maps the Person-Customer-Employee hierarchy shown in Chapter 8 using the SINGLE_TABLE inheritance mapping strategy.

Start Up JBoss

If you already have JBoss running, there is no reason to restart it. Otherwise, start it up as instructed in Workbook 1.

Initialize the Database

The database tables will be created when Exercise 8.1 is deployed to JBoss. If you have problems running this example, shut down JBoss and run the clean.db Ant task.

Build and Deploy the Example Programs

Perform the following steps:

  1. Open a command prompt or shell terminal and change to the ex08_1 directory created by the extraction process.

  2. Set the JAVA_HOME and JBOSS_HOME environment variables to point to where your JDK and JBoss 4.0 are installed. Examples:


    Windows:

    C:\workbook\ex08_1> set JAVA_HOME=C:\jdk1.5.0
    C:\workbook\ex08_1> set JBOSS_HOME=C:\jboss-4.0.x
    


    Unix:

    $ export JAVA_HOME=/usr/local/jdk1.5.0
    $ export JBOSS_HOME=/usr/local/jboss-4.0
    

  3. Add ant to your execution path. Ant is the build utility.


    Windows:

    C:\workbook\ex08_1> set PATH=..\ant\bin;%PATH%
    


    Unix:

    $ export PATH=../ant/bin:$PATH
    

  4. Perform the build by typing ant.

titan.jar is rebuilt, copied to the JBoss deploy directory, and redeployed by the application server.

Examine the Database Schema

Now that you have built the example, look at the database schema by going to the JMX manage console and bringing up the Hypersonic Database Manager described in previous chapters. This will allow you to see how the code in Chapter 8 maps to an autogenerated database (see Figure W-13).

Figure W-13. PERSON_HIERARCHY Table


The Hypersonic Database Manager is particularly useful in the exercises in this chapter because the code is basically the same, but the schema is different for each example.

Examine the Code

We're not going to examine any of the entity classes in this chapter because they are already discussed in detail in Chapter 8. Instead, we will look at the stateless session bean that has business methods to initialize and query the database, as well as the client code.

DataAccessBean.java
package com.titan.access;

import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import java.util.List;

import com.titan.domain.*;

@Stateless
public class DataAccessBean implements DataAccessRemote
{
   @PersistenceContext private EntityManager manager;

   public void initializeDatabase( )
   {
      Person p = new Person( );
      p.setFirstName("Bill");
      p.setLastName("Burke");
      manager.persist(p);

      Customer cust = new Customer( );
      cust.setFirstName("Sacha");
      cust.setLastName("Labourey");
      cust.setStreet("C'est La Vie");
      cust.setCity("Neuchatel");
      cust.setState("Switzerland");
      cust.setZip("3332002-111");
      manager.persist(cust);

      Employee employee = new Employee( );
      employee.setFirstName("Gavin");
      employee.setLastName("King");
      employee.setStreet("1st Street");
      employee.setCity("Atlanta");
      employee.setState("GA");
      employee.setZip("33320");
      employee.setEmployeeId(15);
      manager.persist(employee);

   }

The initializeDatabase( ) method simply allocates and persists three entity beans. These three beans are of type Person, Customer, and Employee, respectively.

   public List findAllPersons( )
   {
      return manager.createQuery("FROM Person p").getResultList( );
   }
}

The findAllPersons( ) method creates and executes a query that pulls all Person entities from the database. Because Person is the root of a mapped inheritance hierarchy, this query is polymorphic and returns all Person, Customer, and Employee records.

Client.java
package com.titan.clients;

import com.titan.access.DataAccessRemote;
import com.titan.domain.*;

import javax.naming.InitialContext;
import javax.naming.Context;
import javax.naming.NamingException;
import java.util.List;

import javax.rmi.PortableRemoteObject;

public class Client
{
    public static void main(String [] args)
    {
        try
        {
            Context jndiContext = getInitialContext( );
            Object ref = jndiContext.lookup("DataAccessBean/remote");
            DataAccessRemote dao = (DataAccessRemote)
                PortableRemoteObject.narrow(ref,DataAccessRemote.class);
            dao.initializeDatabase( );
            List persons = dao.findAllPersons( );
            System.out.println("persons.size() = " + persons.size( ));
            for (Object obj : persons)
            {
               Person p = (Person)obj;
               System.out.println("\tclass is: " + p.getClass().getName( ));
               System.out.println("\tperson: " + p.getFirstName( ) + " "
                                  + p.getLastName( ));
            }
        }
        catch (javax.naming.NamingException ne)
        {
           ne.printStackTrace( );
        }
    }

    public static Context getInitialContext( )
        throws javax.naming.NamingException
    {
        return new javax.naming.InitialContext( );
    }
}

The client code simply looks up the remote interface of the DataAccess EJB and invokes its two methods. It iterates through the list returned from findAllPersons( ) and shows that the query returned the entities created earlier.

Run the Client

Run the Client application by invoking ant run.client at the command prompt. Remember to set your JBOSS_HOME and PATH environment variables. This is the output:

run.client:
     [java] persons.size( ) = 3
     [java]     class is: com.titan.domain.Person
     [java]     person: Bill Burke
     [java]     class is: com.titan.domain.Customer
     [java]     person: Sacha Labourey
     [java]     class is: com.titan.domain.Employee
     [java]     person: Gavin King