Using Coherence and TopLink Essentials

 

Introduction

Oracle TopLink is often described as one of the most flexible and scalable object-relational mapping libraries and performs particularly well for read-intensive applications. A streamlined version called TopLink Essentials became the Reference Implementation for the Java Persistence API (JPA) and was open sourced and donated to the Glassfish project at java.net. TopLink Essentials offers all of the essential functionality for O/R mapping through either JPA or the native TopLink API, but it also provides a number of other custom and advanced features for more sophisticated application usage. To obtain a free download of TopLink Essentials go to http://otn.oracle.com/jpa.
Coherence ships a CacheStore implementation that uses TopLink Essentials to load and store objects to the database. This document describes how to configure and use this CacheStore. Note that although this CacheStore allows the objects to be mapped as JPA entities it differs from the JPA CacheStore in that it uses the TopLink runtime API to load and store the objects.

Limitations

Support is currently limited to TopLink Essentials and not Oracle TopLink. In most cases the actual Oracle TopLink mappings used by applications will also work in TopLink Essentials, but the TopLink project mapping files (deployment XML) are not read by TopLink Essentials. TopLink Essentials will read and process TopLink Projects in Java code, though, as well as all types of JPA mappings and metadata.

Conventions

This document refers to the following Java classes and interfaces:

com.tangosol.coherence.toplink.TopLinkCacheLoader
com.tangosol.coherence.toplink.TopLinkCacheStore
 
com.tangosol.net.NamedCache (extends java.util.Map)
 
com.tangosol.net.cache.CacheLoader
com.tangosol.net.cache.CacheStore
 
oracle.toplink.essentials.sessions.Project
oracle.toplink.essentials.threetier.ServerSession
oracle.toplink.essentials.tools.sessionmanagement.SessionManager

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, "TopLinkCacheStore" will refer to both implementations.
The Coherence cache configuration file is referred to as the coherence-cache-config.xml (the default name). TopLink Essentials may be referred to simply as TopLink in this document. The JPA runtime configuration file is referred to as the persistence.xml and the JPA mapping file is referred to as the orm.xml (the default name).

Using the Coherence TopLinkCacheStore

Overview

The TopLink API provides advanced and flexible queries and many relational management features, including referential integrity, cascading deletes and child object fetching. TopLink employs an advanced caching system to properly manage the entities. In many cases the TopLink cache will short-circuit a database operation in order to minimize the operational latency, while in other cases it will simply use its cache to ensure object identity.
Coherence includes a default entity-based CacheStore implementation, TopLinkCacheStore (and a corresponding CacheLoader implementation, TopLinkCacheLoader). 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. In TopLink Essentials objects may be mapped using either standard JPA mappings or native TopLink O/R mappings.
JPA mappings are specified either by annotating the entity classes or by adding an orm.xml or other XML mapping files. See the TopLink JPA documentation for more on how to map JPA entities.
TopLink mappings may be used instead of, or in addition to JPA mappings. They may be configured using either a TopLink project class (see the TopLink documentation for more on how to create a Java project class) or a customization class to amend the TopLink descriptors for each class and add the mappings (see the TopLink documentation for more on how to create a customization class and add Java mappings). While a broader set of mappings is available in TopLink the mappings may not be portable to other JPA providers.

Configuring TopLink Essentials

The runtime configuration and startup code will be different depending upon whether JPA mappings or TopLink mappings are used.

Configuration with JPA Mappings

If using JPA mappings then TopLink Essentials is configured using a persistence.xml. Within persistence.xml are the properties that dictate runtime operation. The toplink.session-name property determines the name given to the TopLink session created to model the persistence unit entity manager factory. This property may be set to any non-empty value as long as it is set. Below is a sample persistence.xml showing the toplink.session-name property setting.

<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"/>
 
 <property name="toplink.session-name" value="EmployeeSession"/>
 </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.

Configuration with TopLink Mappings

When using a Java project class the class may be created either manually or through a tool such as the Mapping Workbench. The class need only be compiled and present on the classpath.
The project class should be instantiated and passed into the session constructor when creating the session. The session must also be added to the SessionManager. The following sample code shows how this might be done.

Project project = new EmployeeMappingProject();
ServerSession session = new ServerSession(project);
SessionManager.getManager().addSession("EmployeeSession", session);

Configuring Coherence

A coherence-cache-config.xml must be specified to override the default Coherence settings and define the TopLinkCacheStore caching scheme. The caching scheme should include a <cachestore-scheme> element that lists the TopLinkCacheStore class and includes two parameters. The first parameter is the entity name, or the alias for the entity being stored. When using JPA this is normally the unqualified name of the entity class, and when mapped using TopLink it is the alias for the class that is set on the descriptor. 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 cache store. This will work because a separate cache should be used for each type of persistent object 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 name of the session that was indicated by the value of the session-name property in the persistence.xml if using JPA mappings. It is the name that was explicitly given to the session if using a TopLink session directly.
The various named caches are then directed to use the TopLink 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. In this example we are assuming the entities are mapped using JPA mappings.

<cache-config> 
 
 <caching-scheme-mapping> 
 
 <!- Configure a named cache --> 
 <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>toplink-distributed</scheme-name> 
 </cache-mapping> 
 
 </caching-scheme-mapping> 
 
 <caching-schemes> 
 
 <distributed-scheme> 
 
 <scheme-name>toplink-distributed</scheme-name> 
 <service-name>TopLinkDistributedCache</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.toplink.TopLinkCacheStore
 </class-name> 
 <init-params> 
 <!- This param should be the entity name --> 
 <init-param> 
 <param-type>java.lang.String</param-type> 
 <param-value>{cache-name}</param-value> 
 </init-param> 
 <!- This param should match the value of the session-name property --> 
 <!- in persistence.xml file if JPA mappings are used, or the name --> 
 <!-- assigned to the TopLink session if TopLink mappings are used --> 
 <init-param> 
 <param-type>java.lang.String</param-type> 
 <param-value>EmployeeSession</param-value> 
 </init-param> 
 </init-params> 
 </class-scheme> 
 </cachestore-scheme> 
 </read-write-backing-map-scheme> 
 </backing-map-scheme> 
 
 <autostart>true</autostart> 
 </distributed-scheme> 
 
 </caching-schemes> 
 
</cache-config>