Using Coherence and JPA

 

Introduction

The Java Persistence API (JPA) is the primary standard for O/R mapping and enterprise Java persistence. A number of open source and commercial implementations exist and still others are being developed.
Coherence ships a CacheStore implementation that uses JPA to load and store objects to the database. This document describes how to configure and use this CacheStore.

Limitations

A JPA provider is not shipped with Coherence, but is easy to procure. The Reference Implementation for JPA is called TopLink Essentials and is free and open source. It is available from the Oracle Technology Network (OTN) at http://otn.oracle.com/jpa
Only resource-local and bootstrapped entity managers are currently supported. Container-managed entity managers and those that use JTA transactions are not supported at this time.

Conventions

This document refers to the following Java classes and interfaces:

com.tangosol.coherence.jpa.JpaCacheLoader
com.tangosol.coherence.jpa.JpaCacheStore
 
com.tangosol.net.NamedCache (extends java.util.Map)
 
com.tangosol.net.cache.CacheLoader
com.tangosol.net.cache.CacheStore

As the CacheStore interface extends CacheLoader, the term "CacheStore" will be used generically to refer to both interfaces (the appropriate interface being determined by whether read-only or read-write support is required). Similarly, "JpaCacheStore" will refer to both implementations.
The Coherence cache configuration file is referred to as the coherence-cache-config.xml (the default name). The JPA persistence implementation is referred to simply as the JPA provider or JPA vendor. The JPA runtime configuration file is referred to as the persistence.xml, and the JPA O/R mapping file is referred to as the orm.xml (the default name).

Using the Coherence JpaCacheStore

Overview

The JPA is a standard API for mapping, querying and storing Java objects to a database. The characteristics of the different JPA implementations may differ, however, when it comes to caching, threading, and overall performance. TopLink Essentials is a high-performing JPA implementation that meets the performance needs of most applications.
Coherence includes a default entity-based CacheStore implementation, JpaCacheStore (and a corresponding CacheLoader implementation, JpaCacheLoader). Other information may be found in the Javadoc for the implementing classes.

Mapping the Persistent Classes

The first step in being able to load and store objects through the CacheStore is to ensure that the classes are mapped to the database. JPA mappings are standard, and hence may be specified the same way for any and all JPA providers.
Entities may be mapped either by annotating the entity classes or by adding an orm.xml or other XML mapping file(s). See the JPA vendor documentation for more on how to map JPA entities.

Configuring JPA

A typical JPA configuration involves making changes to the persistence.xml. Within the persistence.xml are the properties that dictate runtime operation. Below is a sample persistence.xml showing the typical properties that are set.

<persistence xmlns="http://java.sun.com/xml/ns/persistence" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
        http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"
    version="1.0">
 
   <persistence-unit name="EmpUnit" transaction-type="RESOURCE_LOCAL"> 
         
     <provider>oracle.toplink.essentials.PersistenceProvider</provider> 
 
     <class>com.acme.Employee</class> 
 
     <properties> 
       <property name="toplink.jdbc.driver" value="oracle.jdbc.OracleDriver"/> 
       <property name="toplink.jdbc.url" value="jdbc:oracle:thin:@localhost:1521:XE"/> 
       <property name="toplink.jdbc.user" value="scott"/> 
       <property name="toplink.jdbc.password" value="tiger"/> 
     </properties> 
 
   </persistence-unit> 
    
</persistence> 

The transaction type should be set to RESOURCE_LOCAL and the four JDBC properties should contain the appropriate values for connecting and logging in to the database being used. Classes that are mapped using JPA annotations should be listed in <class> elements.

Configuring Coherence

A coherence-cache-config.xml must be specified to override the default Coherence settings and define the JpaCacheStore caching scheme. The caching scheme should include a <cachestore-scheme> element that lists the JpaCacheStore class and includes three parameters.
The first parameter is the entity name of the entity being stored. Unless it is explictly overridden in JPA it will be the unqualified name of the entity class. In the example cache scheme listed below we make use of the built-in Coherence macro {cache-name} that translates to the name of the cache that is constructing and using the CacheStore. This works because a separate cache should be used for each type of persistent entity and we will ensure that the name of each cache will be set to the name of the entity that is being stored in it.
The second parameter is the fully qualified name of the entity class. If the classes are all in the same package and use the default JPA entity names then we can once again use the {cache-name} macro to fill in the part that is variable across the different entity types. In this way the same caching scheme can be used for all of the entities that are cached within the same persistence unit.
The third parameter is the persistence unit name, which should be the same as the name specified in the persistence.xml.
The various named caches are then directed to use the JPA caching scheme. The following is a sample coherence-cache-config.xml used to define a NamedCache called "Employee" that caches instances of the Employee class. To define additional entity caches for more classes then more <cache-mapping> elements may be added.

<cache-config> 
 
  <caching-scheme-mapping> 
 
    <cache-mapping> 
      <!—- Set the name of the cache to be the entity name  --> 
      <cache-name>Employee</cache-name> 
      <!—- Configure this cache to use the scheme defined below  --> 
      <scheme-name>jpa-distributed</scheme-name> 
    </cache-mapping> 
 
  </caching-scheme-mapping> 
 
  <caching-schemes> 
 
    <distributed-scheme> 
 
      <scheme-name>jpa-distributed</scheme-name> 
      <service-name>JpaDistributedCache</service-name> 
 
      <backing-map-scheme> 
        <read-write-backing-map-scheme> 
 
          <internal-cache-scheme> 
            <local-scheme/> 
          </internal-cache-scheme> 
  
          <!— Define the cache scheme --> 
          <cachestore-scheme> 
            <class-scheme> 
              <class-name> 
                com.tangosol.coherence.jpa.JpaCacheStore
              </class-name> 
              <init-params> 
 
                <!—- This param is the entity name --> 
                <init-param> 
                  <param-type>java.lang.String</param-type> 
                  <param-value>{cache-name}</param-value> 
                </init-param> 
 
                <!—- This param is the fully qualified entity class --> 
                <init-param> 
                  <param-type>java.lang.String</param-type> 
                  <param-value>com.acme.{cache-name}</param-value> 
                </init-param> 
 
                <!—- This param should match the value of the --> 
                <!—- persistence unit name in persistence.xml --> 
                <init-param> 
                  <param-type>java.lang.String</param-type> 
                  <param-value>EmpUnit</param-value> 
                </init-param> 
 
              </init-params> 
            </class-scheme> 
          </cachestore-scheme> 
 
        </read-write-backing-map-scheme> 
      </backing-map-scheme> 
 
    </distributed-scheme> 
 
  </caching-schemes> 
 
</cache-config>