Tutorial: Build a Web Application (JSF) Using JPA

Version: 8/31/06 GlassFish: Version 2, Build 15

  • Introduction

  • Tutorial Steps

  • Summary

  • List of Examples

  • Introduction

    This tutorial will walk you through the basic steps of developing, packaging, and deploying a Web application using the EJB 3.0 Java Persistence API (JPA).

    In this application, a Java Server Faces (JSF) presentation layer will make use of JPA for persistence outside of an EJB 3.0 container.

    Figure 1-1 shows the object model that this tutorial uses.

    Figure 1-1 Tutorial Object Model

    Description of Figure 1-1 follows

    For more information on JPA, see:

    1. JSR-220 Enterprise JavaBeans v3.0 Java Persistence API specification

    Required Software

    1. Ant
    2. Source Code:

      1. Example Source Code ( order-jsf-jpa-example.zip ) - this is a completed version of the tutorial that you can build and deploy immediately.
      2. Tutorial Source Code ( order-jsf-jpa-tutorial.zip ) - this is the starting point for the tutorial. By the end of the tutorial, you will make this code match the example source code.
    3. Relational Database:

      You can use any modern, relational database. This tutorial assumes that you are using Oracle Database XE:

      Use the JDBC driver recommended for your database.

      For Oracle Database XE, JDBC drivers are located in <ORACLE_HOME>\jdbc\lib.

      Note:

      For an Oracle database, you may also need <ORACLE_HOME>\lib\dms.jar.

    4. Web Container:

      You can use any Web container. This tutorial assumes that you are using one of the following Web containers:

      1. Tomcat Version 5.x

    Setup and Configuration

    Before starting this tutorial, you must setup and configure the required software:

    1. Install Ant
    2. Install the example and tutorial source files:

      1. Create a directory in which to unzip the example source files.

        This is the <EXAMPLE_HOME> directory.

      2. Unzip the order-jsf-jpa-example.zip file to the <EXAMPLE_HOME> directory.

        This directory contains the completed tutorial source.

      3. Create a directory in which to unzip the tutorial source files.

        This is the <TUTORIAL_HOME> directory.

      4. Unzip the order-jsf-jpa-tutorial.zip file to the <TUTORIAL_HOME> directory.

        This directory contains the stubbed tutorial source that you will complete in this tutorial.

      For more information about the structure and content of the <EXAMPLE_HOME> and <TUTORIAL_HOME> directories, see Understanding the Tutorial Source Files.

    3. Install and setup your relational database:

      1. Installing Oracle Database XE - Linux
      2. Oracle Database XE - Windows
      3. Getting Started with Oracle Database XE
      4. Add your relational database JDBC driver to:

        1. <EXAMPLE_HOME>\lib
        2. <TUTORIAL_HOME>\lib
    4. Install and setup your Web container:

        Note:

        Before starting OC4J, remove the <ORACLE_HOME>/j2ee/home/lib/persistence.jar, if present.

      1. Installing and Setting Up Tomcat
    5. Install TopLink JPA:
      1. Move the TopLink JPA installer JAR file to a temporary directory.

      2. Execute the TopLink JPA installer JAR file you downloaded by entering the following on the command line (you must use JDK 1.5):
      3. java -jar glassfish-persistence-installer-X.X-bXX.jar
      4. Scroll down to the end of the license agreement and click Accept.
      5. The installer un-packs the README, license files, and the TopLink Essentials JAR files as follows:

        glassfish-persistence\README
        glassfish-persistence\3RD-PARTY-LICENSE.txt
        glassfish-persistence\toplink-essentials.jar
        glassfish-persistence\toplink-essentials-agent.jar
        glassfish-persistence\CDDLv1.0.txt
      6. Add toplink-essentials.jar and toplink-essentials-agent.jar to:

        1. <EXAMPLE_HOME>\lib
        2. <TUTORIAL_HOME>\lib
    6. Validate your installation
      1. Edit the <EXAMPLE_HOME>\persistence-unit\src\META-INF\persistence.xml file and set the following properties to match your relational database:
      2. <property name=" toplink.jdbc.driver" value="<jdbc-driver>"/> <property name="
      3. toplink.jdbc.url " value="<jdbc-url>"/> <property name="
      4. toplink.jdbc.password " value="<jdbc-password>"/> <property name="
      5. toplink.jdbc.user " value="<jdbc-user>"/>

      Where:

      1. <jdbc-driver> is the name of your JDBC driver class. Example: oracle.jdbc.OracleDriver.
      2. <jdbc-url> is the JDBC connection URL to your database. Example: jdbc:oracle:thin:@myhost:l521:MYSID.
      3. <jdbc-password> is the JDBC password you use to connect to your database. Example: tiger.
      4. <jdbc-user> is the JDBC user name you use to connect to your databse. Example: scott
    7. From the command line, change directories to the <EXAMPLE_HOME> directory and execute:

      ant -f build.xml generate-tables ant -f build.xml populate-data
    8. Confirm that TABLE CREATE statements are visible in the log messages written to standard out.

      If they are, then you are connecting to the database successfully.

      If they are not, then you are not connecting to the database. In this case, confirm your persistence.xml file settings and ensure that your database is up and running.

    9. From the command line, change directories to the <EXAMPLE_HOME> directory and execute: ant -f build.xml package.webapp
    10. Deploy the <EXAMPLE_HOME>\web-application\deploy\jpa-example.war file. See:
      1. Deploying to OC4J
      2. Deploying to Tomcat
    11. Run the application. See:

      1. Running the Application on OC4J
      2. Running the Application on Tomcat

      Confirm that you can see the tutorial application main page as Figure 1-2 shows.

      You are now ready to start the tutorial (see Tutorial Steps).

      Figure 1-2 Tutorial Application Main Page

      Description of Figure 1-2 follows

    Understanding the Tutorial Source Files

    After unzipping the order-jsf-jpa-example.zip and order-jsf-jpa-tutorial.zip (see Setup and Configuration), you have an <EXAMPLE_HOME> and <TUTORIAL_HOME> directory.

    These directories contain the same structure as Example 1-1 shows. Table 1-1 describes the important content of these subdirectories.

    The source files in the <EXAMPLE_HOME> are completed versions of the tutorial that you can build and deploy immediately.

    The source files in the <TUTORIAL_HOME> subdirectory are the starting point for the tutorial. By the end of the tutorial, you will make this code match the example source code.

    Example 1-1 Structure of <EXAMPLE_HOME> and <TUTORIAL_HOME>

    build.xml
    extras/
        bin/
        classes/
        src/oracle/toplink/jpa/example/inventory/tools/
            DDLGenerator.java
            Populator.java
    lib/
        - JSF and JSTL JARs
        - JDBC driver JARs (user-supplied)
        - TopLink JPA JARs (user-supplied)
    persistence-unit/
        classes/
        deploy/
        src/META-INF
            persistence.xml
        src/oracle/toplink/jpa/example/inventory/
            model/
                Inventory.java
                Item.java
                Order.java
            nonentity/
                Category.java
    web-application/
        classes/
        deploy/
        public_html/
            *.jsp
            css/
            images/
            WEB-INF/
                faces-config.xml
                web.xml
        src/oracle/toplink/jpa/example/inventory/
            services/
                InventoryService.java
                OrderService.java
            services/impl/
                JPAResourceBean.java
                ManagedInventoryBean.java
                ManagedOrderBean.java
            ui/
                InventoryManagerBean.java

    Table 1-1 Important Subdirectories in <EXAMPLE_HOME> and <TUTORIAL_HOME>

    Subdirectory Description

    extras/

    Contains source files that are not directly executed by the tutorial application.

    classes/

    The directory in which the extra/src source files are compiled by the tutorial build.xml Ant script.

    src/

    The src/oracle/toplink/jpa/example/inventory/tools/ directory contains helper classes that you can optionally invoke with tutorial build.xml Ant script targets:

    1. generate-tables - invokes DDLGenerator to generate the tutorial application's database tables.
    2. populate-data - invokes Populator to populate the tutorial application's database tables.

    lib/

    The lib directory contains all the JAR files that the tutorial application depends on. In particular, this includes:

    1. JSF and JSTL JARs (included)
    2. JDBC driver JARs (user-supplied)
    3. TopLink JPA JAR files (user-supplied)

    persistence-unit/

    Contains the source files for persistent JPA entities.

    classes/

    This is a temporary directory where the persistence unit source files are built before packaging into the persistence unit archive.

    deploy/

    This directory will contain the built and packaged persistence unit persistence-unit.jar file.

    src/

    This directory contains the sources required for the persistence unit including the domain classes.

    It also contains the persistence.xml file located in the sub-directory META-INF, as per the JPA specification.

    web-application/

    Contains the source files that implement the services and user interface of the tutorial application that use the JPA entities.

    classes/

    This is a temporary directory where the sources are built before packaging into the deployable archive.

    deploy/

    This directory will contain the built deployable Web application, jpa-example.war. This is built using the ant target package.webapp.

    public_html/

    Contains the presentation layer of the application including JSPs, stylesheets ( css/), images ( images/), and deployment descriptor ( WEB-INF/web.xml).

    src/

    This directory includes the sources for the controller layer of the application.

    1. The oracle/toplink/jpa/example/inventory/services directory contains the sources for the services interfaces that provide access to the persistence layer:
    2. The oracle/toplink/jpa/example/inventory/services/impl directory contains the classes that implement the service interfaces.

      The ManagedOrderBean implements the OrderService interface.

      The ManagedInventoryBean implements the InventoryService interface.

      The JPAResourceBean is a helper class that the tutorial application uses to acquire an EntityManager for the tutorial application's persistence unit.

    3. The oracle/toplink/jpa/example/inventory/ui directory contains the InventoryManagerBean class that drives the tutorial application user interface.

    Tutorial Steps

    The following procedure leads you through the important steps in creating the tutorial application. At each step, you will be directed to modify the <TUTORIAL_HOME> source files as necessary.

    • Step 1: Annotating the Entities
    • Step 2: Configuring the Persistence Unit
    • Step 3: Using JPA to Implement the Service
    • Step 4: Using JPA Queries
    • Step 5: Packaging and Deployment
    • Step 6: Run the Application
    • Step 1: Annotating the Entities

      Annotations are a simple, expressive means of decorating Java source code with metadata that is compiled into the corresponding Java class files for interpretation at runtime by a JPA persistence provider to manage JPA behavior.

      Persistent classes are decorated with JPA annotations to tell the JPA persistence provider what classes require persistence and to specify persistent class details.

      In most cases, you can rely on JPA defaults. This tutorial shows the required annotations and some common optional annotations.

      This section describes:

      1. Annotating the Inventory Entity
      2. Annotating the Item Entity
      3. Annotating the Order Entity

      Annotating the Inventory Entity

      This section describes how to annotate the Inventory.java file. This is a plain old Java object (POJO). It is one of the persistent entities we want to manage using JPA.

      1. Using the editor of your choice, open the <TUTORIAL_HOME>\persistence-unit\src\oracle\toplink\jpa\example\inventory\model\Inventory.java source file.
      2. Designate this class as a persistent entity using the @Entity annotation as Example 1-2 shows.

        Example 1-2 @Entity in Inventory.java

        @Entity public class Inventory { ...}

        By default, the name of an entity is its class name.

        Also by default, the entity name is the name of the entity's database table. You can use the

        @Table

        annotation to override this default behavior (for an example, see Annotating the Order Entity).

        An entity's table will contain all its persistent fields. JPA specifies that all the fields of an entity are persistent unless they are decorated with the @Transient annotation.

      3. Designate a persistent field as the entity's primary key using the @Id annotation as Example 1-3 shows.

        Example 1-3 @Id in Inventory.java

        @Entity
        public class Inventory {
            @Id
            protected long id;
            ...
            public void setItem(Item item) {
                this.item = item;
                this.id = item.getSKU();
            }
            ...
        }

        Each entity must have a primary key.

        The Inventory class field id is designated as the primary key. In this case, a @GeneratedValue annotation is not used because the Inventory entity gets its primary key value from its Item as the Inventory method setItem shows.

      4. Specify the characteristics of the database table column that corresponds to the primary key field using the @Column annotation as Example 1-4 shows.

        Example 1-4 @Column in Inventory.java

        @Entity
        public class Inventory {
            @Id
            @Column(name="ITEM_SKU", insertable=false, updatable=false)
            protected long id;
            ...
            public void setItem(Item item) {
                this.item = item;
                this.id = item.getSKU();
            }
            ...
        }

        By default, JPA specifies that for each entity, each persistent field will correspond to a column in the entity's relational database table where the column name and type correspond to the field name and type.

        You can use the @Column annotation to override this default behavior.

        In the Inventory class, the @Column annotation is used to fine-tune the relational database column for field id as Example 1-4 shows. Because the Inventory entity gets its primary key value from its Item as the Inventory method setItem shows, we must ensure that this value is never overwritten in the database. In this case, we use the @Column annotation to configure the column as not insertable or updatable. This means the JPA persistence provider will not include this column in SQL INSERT or SQL UPDATE statements. Because this column contains the foreign key to the Inventory class's Item, we use the @Column annotation attribute name to specify a name for this column that we can use when we specify the join column for the OneToOne mapping we will make to Item (see step 5 and 6).

      5. Specify the relationship between the Inventory entity and the Item entity using the @OneToOne annotation as Example 1-5 shows.

        Example 1-5 @OneToOne in Inventory.java

        @Entity
        public class Inventory {
            @Id
            @Column(name="ITEM_SKU", insertable=false, updatable=false)
            protected long id;
        
            @OneToOne
            protected Item item;
            ...
            public void setItem(Item item) {
                this.item = item;
                this.id = item.getSKU();
            }
        }
        By default, a JPA persistence provider will automatically manage basic mappings (for most Java primitive types, wrappers of the primitive types, and enums). You can use the @Basic annotation to fine-tune basic mappings.

        You must specify mappings for relationships. In addition to the @OneToOne annotation, you can use the following annotations for relationship mappings:

        1. @ManyToMany
        2. @ManyToOne
        3. @OneToMany

        The Inventory class field item is decorated with the @OneToOne annotation to specify the relationship between Inventory and Item as Example 1-5 shows.

      6. Specify that the foreign key column that references the Item is the Inventory column named ITEM_SKU using the @JoinColumn annotation as Example 1-6 shows.

        Example 1-6 @JoinColumn in Inventory.java

        @Entity
        public class Inventory {
            @Id
            @Column(name="ITEM_SKU", insertable=false, updatable=false)
            protected long id;
        
            @OneToOne
            @JoinColumn(name="ITEM_SKU")
            protected Item item;
            ...
            public void setItem(Item item) {
                this.item = item;
                this.id = item.getSKU();
            }
        }
      7. Specify a persistent field as the optimistic locking field using the @Version annotation as Example 1-7 shows.

        Example 1-7 @Version in Inventory.java

        @Entity
        public class Inventory {
            @Id
            @Column(name="ITEM_SKU", insertable=false, updatable=false)
            protected long id;
        
            @OneToOne
            @JoinColumn(name="ITEM_SKU")
            protected Item item;
            ...
            @Version
            protected int version;
            ...
            public void setItem(Item item) {
                this.item = item;
                this.id = item.getSKU();
            }
        }

        The Inventory class field version is decorated with the @Version annotation to specify it as the optimistic locking field.

        By default, a JPA persistence provider assumes that the application is responsible for data consistency.

        Oracle recommends that you use the @Version annotation to enable JPA persistence provider-managed optimistic locking by specifying the version field or property of an entity class that serves as its optimistic lock value.

      8. Define a named query using the < @NamedQuery annotation as Example 1-8 shows.

        Example 1-8 @NamedQuery in Inventory.java

        @Entity
        
        @NamedQuery(
            name="inventoryForCategory",
            query="SELECT i FROM Inventory i WHERE i.item.category = 
            :category and i.quantity <= :maxQuantity"
        )
        public class Inventory {
            ....
        }
        In a JPA application, you can use an EntityManager to create JPA query language queries dynamically at runtime or you can pre-define such queries using the @NamedQuery annotation and execute them by name at runtime (see Step 4: Using JPA Queries). This is convenient for frequently used or complex queries.

        If you want to define two or more named queries, you must use the @NamedQueries annotations as is done in Order.java (see Example 1-17).

        You can also create native SQL queries (see @NamedNativeQuery and the @NamedNativeQueries ).

      9. Save and close the file.

      Annotating the Item Entity

      This section describes how to annotate the Item.java file. This is a plain old Java object (POJO). It is one of the persistent entities we want to manage using JPA.

      1. Using the editor of your choice, open the <TUTORIAL_HOME>\persistence-unit\src\oracle\toplink\jpa\example\inventory\model\Item.java source file.
      2. Designate this class as a persistent entity using the @Entity annotation as Example 1-2 shows.

        Example 1-9 @Entity in Item.java

        @Entity public class Item { ...}
      3. Designate a persistent field as the entity's primary key using the @Id annotation as Example 1-10 shows.

        Example 1-10 @Id in Item.java

        @Entity
        public class Item {
            protected long SKU;
            ...
            @Id
            @GeneratedValue
            public long getSKU() {
                return SKU;
            }
            ...
        }
        The Item class property getSKU is designated as the primary key as Example 1-10 shows. In general, you can annotate either the field (as in Inventory.java) or the property associated with a field. The @GeneratedValue annotation tells the JPA persistence provider to take responsibility for sequencing: generating and managing unique identifier values for this field.
      4. Specify a persistent field as the optimistic locking field using the @Version annotation as Example 1-11 shows.

        Example 1-11 @Version in Item.java

        @Entity
        public class Item {
            protected long SKU;
            ...
            @Id
            @GeneratedValue
            public long getSKU() {
                return SKU;
            }
            ...
            @Version
            public void setVersion(int version) {
                this.version = version;
            }
            ...
        }

        The Item class property setVersion is decorated with the @Version annotation to specify that corresponding field version is the optimistic locking field.

      5. Save and close the file.

      Annotating the Order Entity

      This section describes how to annotate the Order.java file. This is a plain old Java object (POJO). It is one of the persistent entities we want to manage using JPA.

      1. Using the editor of your choice, open the <TUTORIAL_HOME>\persistence-unit\src\oracle\toplink\jpa\example\inventory\model\Order.java source file.
      2. Designate this class as a persistent entity using the @Entity annotation as Example 1-2 shows.

        Example 1-12 @Entity in Order.java

        @Entity public class Order {...}

        By default, the name of an entity is its class name and, also by default, the entity name is the name of the entity's database table.

        For Order entities, you cannot create a table named ORDER because that name is a reserved word in most relational databases. In this case, we use the @Table annotation to override the default table name as Example 1-13 shows.

        Example 1-13 @Table in Order.java

        @Entity @Table(name="ORDER_TABLE") public class Order {...}
      3. Designate a persistent field as the entity's primary key using the @Id annotation as Example 1-3 shows.

        Example 1-14 @Id in Order.java

        @Entity
        @Table(name="ORDER_TABLE")
        public class Order {
            @Id
            @GeneratedValue
            protected long orderId;
            ...
        }
        The Order class field orderId is designated as the primary key. The @GeneratedValue annotation tells the JPA persistence provider to take responsibility for sequencing: generating and managing unique identifier values for this field.
      4. Specify the relationship between the Order entity and the Item entity using the @OneToOne annotation as Example 1-5 shows.

        Example 1-15 @OneToOne in Order.java

        @Entity
        @Table(name="ORDER_TABLE")
        public class Order {
            @Id
            @GeneratedValue
            protected long orderId;
            ...
            @OneToOne
            protected Item item;
            ...
        }
        The Order class field item is decorated with the @OneToOne annotation to specify the relationship between Order and Item as Example 1-15 shows.
      5. Specify a persistent field as the optimistic locking field using the @Version annotation as Example 1-7 shows.

        Example 1-16 @Version in Order.java

        @Entity
        @Table(name="ORDER_TABLE")
        public class Order {
            @Id
            @GeneratedValue
            protected long orderId;
            ...
            @Version
            protected int version;
        
            @OneToOne
            protected Item item;
            ...
        }

        The Order class field version is decorated with the @Version annotation to specify it as the optimistic locking field.

        By default, a JPA persistence provider assumes that the application is responsible for data consistency.

        Oracle recommends that you use the @Version annotation to enable JPA persistence provider-managed optimistic locking by specifying the version field or property of an entity class that serves as its optimistic lock value.

      6. Define two named queries using the @NamedQueries annotation as Example 1-17 shows.

        Example 1-17 @NamedQueries in Order.java

        @Entity
        @Table(name="ORDER_TABLE")
        @NamedQueries({
        
            @NamedQuery(
            name="shippedOrdersForItem",
            query="SELECT o FROM Order o JOIN o.item i WHERE i.sKU =
            :itemId and o.arrivalDate is not null"
            ),
        
            @NamedQuery(
            name="pendingOrdersForItem",
            query="SELECT o FROM Order o WHERE o.item.sKU =
            :itemId and o.arrivalDate is null"
            )
        })
        public class Order {
            ...
        }
        If you want to define one named query, you must use the @NamedQuery annotation as is done in Inventory.java (see Example 1-8).
      7. Save and close the file.

      Step 2: Configuring the Persistence Unit

      The entity manager is the primary JPA interface you use to perform basic persistence operations on your entities (create, read, update, and delete).

      A persistence unit defines an entity manager's configuration by logically grouping details like entity manager provider, configuration properties, and persistent managed classes.

      Each persistence unit must have a name. Only one persistence unit of a given name may exist in a given EJB-JAR, WAR, EAR, or application client JAR. You specify a persistence unit by name when you acquire an entity manager factory (see Acquire an Entity Manager Factory).

      You define persistence units in the persistence.xml file.

      To configure the persistence unit:

      1. Using the editor of your choice, open the <TUTORIAL_HOME>\persistence-unit\src\META-INF\persistence.xml file.
      2. Replace the

      <!-- class list goes here --> comment with a <class> element for each of the persistent JPA entity classes:

      <class>oracle.toplink.jpa.example.
                     inventory.model.Inventory</class>
      <class>oracle.toplink.jpa.example.
      inventory.model.Order</class>
      <class>oracle.toplink.jpa.example.
      inventory.model.Item</class>
      1. Set the following properties to match your relational database:

        <property name="
      2. toplink.jdbc.driver " value="<jdbc-driver>"/> <property name="
      3. toplink.jdbc.url " value="<jdbc-url>"/> <property name="
      4. toplink.jdbc.password " value="<jdbc-password>"/> <property name="
      5. toplink.jdbc.user " value="<jdbc-user>"/>

      Where:

      1. <jdbc-driver> is the name of your JDBC driver class. Example: oracle.jdbc.OracleDriver.
      2. <jdbc-url> is the JDBC connection URL to your database. Example: jdbc:oracle:thin:@myhost:l521:MYSID.
      3. <jdbc-password> is the JDBC password you use to connect to your databse. Example: tiger.
      4. <jdbc-user> is the JDBC user name you use to connect to your databse. Example: scott

      Your persistence.xml file should look like Example 1-18.

      Example 1-18 Persistence Unit in Persistence.xml

      ...
          <persistence-unit name="default" transaction-type="RESOURCE_LOCAL">
              <provider>
                 oracle.toplink.essentials.PersistenceProvider
              </provider>
              <class>oracle.toplink.jpa.example.inventory.model.Inventory</class>
              <class>oracle.toplink.jpa.example.inventory.model.Order</class>
              <class>oracle.toplink.jpa.example.inventory.model.Item</class>
              <properties>
                  <property name="toplink.logging.level" value="FINE"/>
                  <property name="toplink.jdbc.driver" value="oracle.jdbc.OracleDriver"/
                  >  <!-- update to match database-->
                  <property name="toplink.jdbc.url" value="jdbc:oracle:thin:
                  @localhost:1521:XE"/> <!-- update to match database-->
                  <property name="toplink.jdbc.password" value="tiger"/>
                  <!-- update to match database-->
                  <property name="toplink.jdbc.user" value="scott"/> 
                  <!-- update to match database-->
              </properties>
          </persistence-unit>
      ...

      The name of this persistence unit is default.

      Its transaction-type is RESOURCE_LOCAL, meaning that entity managers for this persistence unit do not participate in JTA transactions.

      It uses provider oracle.toplink.essentials.PersistenceProvider.

      Finally, persistence unit properties are set. You can use persistence unit properties to fine-tune the underlying JPA persistence provider and to specify the connection details for the underlying relational database that this persistence unit should be associated with.

      For more information about the persistence.xml file, see JSR-000220 Enterprise JavaBeans v3.0 JPA specification, section 6.3.

    Save and close the file.

    Step 3: Using JPA to Implement the Service

    The main resource for managing the tutorial user interface is oracle.toplink.jpa.example.inventory.ui.InventoryManagerBean. It contains a reference to the following classes that use JPA to implement the services provided by this application:

    1. oracle.toplink.jpa.example.inventory.services.impl.ManagedOrderBean (implements oracle.toplink.jpa.example.inventory.services.OrderService)
    2. oracle.toplink.jpa.example.inventory.services.impl.ManagedInventoryBean (implements oracle.toplink.jpa.example.inventory.services.InventoryService)

    These two classes show how to use JPA to:

    1. Acquire an Entity Manager Factory
    2. Create an Entity
    3. Read an Entity
    4. Update an Entity
    5. Delete an Entity

    Acquire an Entity Manager Factory

    Both the ManagedOrderBean and ManagedInventoryBean use an instance of helper class oracle.toplink.jpa.example.inventory.services.impl.JPAResourceBean to acquire an instance of the entity manager factory for the persistence unit named default that we defined in the persistence.xml file (see Step 2: Configuring the Persistence Unit). Example 1-19 shows how the entity manager factory is acquired.

    Example 1-19 Acquiring the Entity Manager Factory

    public EntityManagerFactory getEMF (){
        if (emf == null){
            emf = Persistence.createEntityManagerFactory("default");
        }
        return emf;
    }

    Once acquired, the ManagedOrderBean and ManagedInventoryBean classes use the entity manager factory to obtain an entity manager to perform all the basic persistence operations (create, read, update, and delete).

    Create an Entity

    Example 1-20 shows how the ManagedOrderBean uses its EntityManager to create a new Order entity.

    Example 1-20 Creating an Order in ManagedOrderBean

    public void  createNewOrder(Order order){
        EntityManager em = jpaResourceBean.getEMF().createEntityManager();
        try{
            em.getTransaction().begin();
            em.persist(order);
            em.getTransaction().commit();
        }finally{
            em.close();
        }
    }

    Read an Entity

    Example 1-21 shows how the ManagedOrderBean uses its EntityManager to read an existing Order entity by primary key.

    Example 1-21 Reading an Order in ManagedOrderBean

    public Order getOrderById(long orderId){
        EntityManager em = jpaResourceBean.getEMF().createEntityManager();
        try{
            return em.find(Order.class, orderId);
        }finally{
            em.close();
        }
    }

    Update an Entity

    Example 1-22 shows how the ManagedOrderBean uses its EntityManager to update an existing Order entity. Any changes made to the Order entity are persisted when the local transaction is committed.

    Example 1-22 Updating an Order in ManagedOrderBean

    public void alterOrderQuantity(long orderId, int newQuantity){
        EntityManager em = jpaResourceBean.getEMF().createEntityManager();
        try{
            em.getTransaction().begin();
            Order order = em.find(Order.class, orderId);
            order.setQuantity(newQuantity);
            em.getTransaction().commit();
        }finally{
            em.close();
        }
    }

    Delete an Entity

    Example 1-23 shows how the ManagedOrderBean uses its EntityManager to delete an existing Order entity by primary key.

    Example 1-23 Deleting an Order in ManagedOrderBean

    public void requestCancelOrder(long orderId){
        EntityManager em = jpaResourceBean.getEMF().createEntityManager();
        try{
            em.getTransaction().begin();
            Order order = em.find(Order.class, orderId);
            em.remove(order);
            em.getTransaction().commit();
        }finally{
            em.close();
        }
    }

    Step 4: Using JPA Queries

    Both the ManagedInventoryBean and ManagedOrderBean classes use JPA queries. This section describes:

    1. Using Queries in the ManagedInventoryBean Class
    2. Using Queries in the ManagedOrderBean Class

    Using Queries in the ManagedInventoryBean Class

    This section describes how to code named and dynamic queries in the ManagedInventoryBean.java file.

    1. Using the editor of your choice, open the <TUTORIAL_HOME>\web-application\src\oracle\toplink\jpa\example\inventory\services\impl\ManagedInventoryBean.java source file.
    2. Use the EntityManager method createNamedQuery to return a Query instance for the query named inventoryForCategory as Example 1-24 shows.

      Example 1-24 Using a Named Query in ManagedInventoryBean

      public class ManagedInventoryBean implements InventoryService{
          ...
          public Collection<Inventory> 
          getInventoryForCategoryMaxQuantity(String category, int quantity){
              EntityManager em = jpaResourceBean.getEMF().createEntityManager();
              try{
                  Query query = em.createNamedQuery("inventoryForCategory");
                  query.setParameter("category", category);
                  query.setParameter("maxQuantity", quantity);
                  return query.getResultList();
              }finally{
                  em.close();
              }
          }
          ...
      }
      You created this named query in the Inventory class (see Example 1-8).
    3. Use the EntityManager method createQuery to create a dynamic query as Example 1-25 shows.

      Example 1-25 Using a Dynamic Query in ManagedInventoryBean

      public class ManagedInventoryBean implements InventoryService{
          ...
          //Returns a list of available item categories
          public Collection<Category> getCategories(){
              //Create an EntityManager from the Factory stored in the JPAResourceBean
              EntityManager em = jpaResourceBean.getEMF().createEntityManager();
      
              try{
                  //execute a JPQL query that collects summary data and stores it in a
                  //non-entity class Category.  This query will pass the results  of the
                  //query into the constructor of Category and return a list of Category
                  //objects
                  Collection<Category> result = em.createQuery
                  ("Select new oracle.toplink.jpa.example.
                  inventory.nonentity.Category(i.category)
                  from Item i group by i.category").getResultList();
                  return result;
              }finally{
                  em.close();
              }
          }
          ...
      }

      Note that this query builds and returns a Collection of Category classes that are not entity classes. It uses summary data to create this non-entity helper class.

    4. Save and close the file.

    Using Queries in the ManagedOrderBean Class

    This section describes how to code named and dynamic queries in the ManagedOrderBean.java file.

    1. Using the editor of your choice, open the <TUTORIAL_HOME>\web-application\src\oracle\toplink\jpa\example\inventory\services\impl\ManagedOrderBean.java source file.
    2. Use the EntityManager method createNamedQuery to return a Query instance for the query named inventoryForCategory as Example 1-24 shows.

      Example 1-26 Using a Named Query in ManagedOrderBean

      public class ManagedOrderBean implements OrderService{
          ...
          // Returns those orders that have a set arrival date indicating that they have shipped
          public Collection<Order> getShippedOrdersForItem(long itemId){
              //Create an EntityManager from the Factory stored in the JPAResourceBean
              EntityManager em = jpaResourceBean.getEMF().createEntityManager();
              try{
                  //create an instance of the NamedQuery defined in the Inventory class.
                  Query query = em.createNamedQuery("shippedOrdersForItem");
                  //setting the provided parameters on the query
                  query.setParameter("itemId", itemId);
                  //return result of query 
                  return query.getResultList();
              }finally{
                  em.close();
              }
          }
      
          // Returns those orders that have a set arrival date indicating that they have shipped
          public Collection<Order> getPendingOrdersForItem(long itemId){
              EntityManager em = jpaResourceBean.getEMF().createEntityManager();
              try{
                  Query query = em.createNamedQuery("pendingOrdersForItem");
                  query.setParameter("itemId", itemId);
                  return query.getResultList();
              }finally{
                  em.close();
              }
          }
          ...
      }
      You created these named queries in the Order class (see Example 1-17).
    3. Use the EntityManager method createQuery to create a dynamic query as Example 1-25 shows.

      Example 1-27 Using a Dynamic Query in ManagedOrderBean

      public class ManagedInventoryBean implements InventoryService{
          ...
          //Returns a list of available item categories
          public Collection<Category> getCategories(){
              //Create an EntityManager from the Factory stored in the JPAResourceBean
              EntityManager em = jpaResourceBean.getEMF().createEntityManager();
      
              try{
                  //execute a JPQL query that collects summary data and stores it in a
                  //non-entity class Category.  This query will pass the results  of the
                  //query into the constructor of Category and return a list of Category
                  //objects
                  Collection<Category> result = em.createQuery
                  ("Select new oracle.toplink.jpa.example.inventory.nonentity.
                  Category(i.category) from Item i group by i.category").getResultList();
                  return result;
              }finally{
                  em.close();
              }
          }
          ...
      }
    4. As Example 1-28 shows, use the appropriate EntityManager methods to transactionally find an Order by primary key and remove it.

      Example 1-28 Finding and Removing an Order in a Transaction in ManagedOrderBean

      public class ManagedInventoryBean implements InventoryService{
          ...
          // request that an order be canceled.  Assume success if no exception is thrown
          public void requestCancelOrder(long orderId){
                 //Create an EntityManager from the Factory stored in the JPAResourceBean
              EntityManager em = jpaResourceBean.getEMF().createEntityManager();
              try{
                  //changes will be made so begin a transaction
                  em.getTransaction().begin();
                  //find the order that will be deleted.  This step ensures the order
                  //will be managed as the specification requires the object be
                  //managed before remove can be called.
                  Order order = em.find(Order.class, orderId);
                  //set the order to be delet4ed
                  em.remove(order);
                  //commit the transaction, this will cause the the delete SQL to be
                  //sent to the database.
                  em.getTransaction().commit();
              }finally{
                  em.close();
              }
          }
      
          // request that an order be canceled assume success if no exception is thrown
          public void alterOrderQuantity(long orderId, int newQuantity){
              EntityManager em = jpaResourceBean.getEMF().createEntityManager();
              try{
                  em.getTransaction().begin();
                  //ensure that this order is a managed object.
                  Order order = em.find(Order.class, orderId);
                  //update the order object directly
                  order.setQuantity(newQuantity);
                  //commit the transaction to have the update sent to the database
                  em.getTransaction().commit();
              }finally{
                  em.close();
              }
          }
      
          // Create a new order request for a particular item;
          public void  createNewOrder(Order order){
              EntityManager em = jpaResourceBean.getEMF().createEntityManager();
              try{
                  em.getTransaction().begin();
                  //calling persist on the order object will mark the object as new
                  //within the persistence context.
                  em.persist(order);
                  //commit the transaction to have the object data inserted to the
                  //database
                  em.getTransaction().commit();
              }finally{
                  em.close();
              }
          }
          ...
      }
    5. As Example 1-29 shows, use EntityManager method find to retrieve an Order by primary key.

      Example 1-29 Finding an Order by Primary Key in ManagedOrderBean

      public class ManagedInventoryBean implements InventoryService{
          ...
          // finds a particular order by the specified order id
          public Order getOrderById(long orderId){
              EntityManager em = jpaResourceBean.getEMF().createEntityManager();
              try{
                  return em.find(Order.class, orderId);
              }finally{
                  em.close();
              }
          }
      
          // finds a particular order by the specified order id
          public Item getItemById(long itemId){
              EntityManager em = jpaResourceBean.getEMF().createEntityManager();
              try{
                  return em.find(Item.class, itemId);
              }finally{
                  em.close();
              }
          }
          ...
      }
    6. Save and close the file.

    Step 5: Packaging and Deployment

    This section describes how to package and deploy the tutorial application, including:

    1. Compiling and Packaging the Application
    2. Deploying to OC4J
    3. Deploying to Tomcat

    Compiling and Packaging the Application

    To compile and package the tutorial application, from the command line, change directories to the <TUTORIAL_HOME> directory and execute the following:

    ant -f build.xml package.webapp

    This creates <TUTORIAL_HOME>\web-application\deploy\jpa-example.war.

    In this tutorial, we package the persistence unit in WEB-INF\lib\persistence-unit.jar within the jpa-example.war file. By confining the persistence unit to its own JAR file, you can easily re-use the persistence unit in other applications.

    Deploying to OC4J

    To deploy the tutorial application to OC4J:

    1. Verify that the following system properties are set:

      1. JAVA_HOME - set to your JDK 1.5 installation.

        Example: C:\Program Files\Java\jdk1.5.0_06

      2. ORACLE_HOME - set to your OC4J installation directory

        Example: C:\OC4JHome

      3. PATH - your path must include %JAVA_HOME%\bin
    2. Start OC4J from the command line:

      On Windows:

      cd %ORACLE_HOME% cd bin oc4j.cmd -start

      On UNIX:

      cd %ORACLE_HOME% cd bin oc4j.sh -start
    3. Log into the Oracle Enterprise Manager Application Server Control console:

      Start a browser and enter the following URL: http://<hostname>:8888/em/console/ias/oc4j/administration

      Where <hostname> is the name of the computer you started OC4J on.

    4. Select Home > Applications and click the Deploy button.
    5. In the Archive area, click the radio button next to Archive is present on local host.
    6. Click the Browse button and locate the jpa-example.war file.
    7. Click Next.
    8. Enter an application name without spaces. For example, "JSF-JPA-Tutorial" and then click Next.
    9. Click Deploy.

      Confirm that the application deploys successfully according to the displayed log message "Application Deployer for JSF JPA Tutorial COMPLETES".

    10. Click Return. Confirm that the "JSF JPA Tutorial" application is listed in the Applications tab.

    Deploying to Tomcat

    To deploy the tutorial application to Tomcat:

    1. Verify that the following system properties are set:

      1. JAVA_HOME - set to your JDK 1.5 installation.

        Example: C:\Program Files\Java\jdk1.5.0_06

      2. CATALINA_HOME - set to your Tomcat installation directory.

        Example: C:\apache-tomcat-5.5.17

      3. PATH - your path must include %JAVA_HOME%\bin
    2. Copy the jpa-example.war file to the Tomcat CATALINA_HOME\webapps directory.
    3. Start Tomcat from the command line:

      On Windows:

      cd %CATALINA_HOME% cd bin startup.cmd

      On UNIX:

      cd $CATALINA_HOME cd bin startup.sh
    4. Confirm that the application deploys successfully by looking for the log message "deployWAR INFO: Deploying web application archive jpa-example.war" on standard out or in the CATALINA_HOME/logs/catalina.out log file.

    Step 6: Run the Application

    This section describes how to access the application after deployment:

    1. Running the Application on OC4J
    2. Running the Application on Tomcat

    Running the Application on OC4J

    Start a browser and enter the following URL:

    http://<hostname>:8888/jpa-example/index.faces

    Where <hostname> is the name of the computer you deployed the application to.

    Running the Application on Tomcat

    Start a browser and enter the following URL:

    http://<hostname>:8080/jpa-example/ or http://<hostname>:8080/jpa-example/index.jsp

    Where <hostname> is the name of the computer you deployed the application to.

    Summary

    This tutorial described a JSF Web application that manages persistence using JPA.

    For more information, see:

    1. JSF on OTN
    2. JSR-220 Enterprise JavaBeans v3.0 Java Persistence API specification

    List of Examples

    This tutorial includes the following examples:

    Structure of <EXAMPLE_HOME> and <TUTORIAL_HOME>