33 Introduction to Coherence JCache

This chapter provides an overview of the Coherence implementation of the JSR-107 JCACHE - Java Caching API specification. The specification and API is commonly referred to as JCache in this documentation. A JCache overview section is also provided and includes a basic introduction to the API. For complete details about the API, download the JCache specification, Java sources, and JavaDoc from the Java Community Process (JCP) website:

https://www.jcp.org/en/jsr/detail?id=107

This chapter includes the following sections:

33.1 Overview of the Coherence JCache Implementation

Coherence includes a JCache provider implementation (COHERENCE_HOME\lib\coherence-jcache.jar). JCache is a common API for using caching in Java. Application developers use the JCache API (javax.cache.*) and Coherence provides the underlying caching capabilities. The provider-based approach guarantees cross-provider portability and allows developers to focus on application logic rather than creating and managing complex caching systems. For additional information about JCache, see "JCache Primer".

The Coherence JCache provider uses existing Coherence technology and can be thought of as a wrapper for the Coherence NamedCache API. This allows Coherence to reuse and expose many of its best-in-class technologies through JCache interfaces.

Supported Cache Types

The Coherence JCache provider offers the following cache types:

  • Local Cache – A cache that is local to an application process. Entries that are stored in local caches do not persist after an application process ends. A local cache is similar to a NamedCache cache that is configured using a local-scheme cache definition. The local cache implementation is defined in the com.tangosol.coherence.jcache.localcache package. For details about creating local caches, see "Creating Local Caches".

  • Partitioned Cache – A cache that is partitioned (distributed) among multiple processes in a Coherence cluster. Entries that are stored in partitioned caches are backed up and persist on the cluster after an application process ends. A partitioned cache is similar to a NamedCache cache that is configured using a distributed-scheme cache definition. The partitioned cache implementation is defined in the com.tangosol.coherence.jcache.partitionedcache package. For details about creating partitioned caches, see "Creating Partitioned Caches". To learn more about partitioned caches, see "Understanding Distributed Caches".

  • Pass-Through Cache – A cache that delegates to an existing NamedCache cache. Pass-through caches offer applications the ability to use all Coherence native features from a JCache interface. Pass-through caches are ideal for applications that want to migrate to JCache but also want to reuse their existing Coherence application components. The pass-through cache implementation is defined in the com.tangosol.coherence.jcache.passthroughcache package. For details about creating pass-through caches, see "Creating Pass-Through Caches".

  • Remote Cache – A cache that delegates to a partitioned cache through a proxy service. A remote cache is similar to a partitioned cache except that access to the cluster is through Coherence*Extend. Remote caches are ideal for applications that want to use a Coherence cache, but do not want to become members of the cluster. The remote cache implementation is defined in the com.tangosol.coherence.jcache.remote package. For details about creating remote caches, see "Creating Remote Caches."

Coherence JCache Events

The Coherence JCache provider uses the native Coherence event APIs to implement JCache events. The local and partitioned cache implementations leverage the Coherence MapListener API. The pass-through cache implementation only supports the Coherence MapEvents that map directly to the JCache events and there is no support for JCache expired events. Each cache type is responsible for registering map listeners and for dispatching map events. Event classes are located in the com.tangosol.coherence.jcache.common package as well as in each cache type package. For details about creating and using JCache events, see "Using JCache Events".

Note:

  • There is no equivalent of the javax.cache.event.CacheEntryExpiredListener API in the Coherence MapListener API.

  • The NamedCache.clear method results in a Coherence MapListener.entryDeleted event; however, the JCache Cache.clear method does not result in any events.

Coherence JCache Entry Processors

The Coherence JCache provider uses the native Coherence InvocableMap.EntryProcessor API to implement JCache entry processors. Each cache type includes an InvokeProcessor class in their respective processors package that is responsible for executing JCache entry processors when the invoke or invokeAll methods are called from a cache. For details about creating and using JCache entry processors, see "Processing JCache Entries".

The processors package for each cache type also includes many native Coherence entry processors that are used to perform cache operations. For example, when using a partitioned cache, the use of the put method results in the use of the PutProcessor class.

Coherence Serialization for JCache

The Coherence JCache provider makes use of Coherence Portable Object Format (POF) serialization. POF is a proven binary format within Coherence and is efficient in both space and time. For partitioned and pass-through caches, many cache operations utilize POF. Cache configuration, entry processors, event listeners and filters, and JCache statistics also make use of POF.

POF is also used to provide serialization as required by parts of the JCache specification. The com.tangosol.coherence.jcache.serialization package includes POF serializer implementations to support JCache factory builders, expiry policies, and cache entry listener configuration.

Lastly, applications can choose to use POF for serialization as required; however, it is not a requirement when using the Coherence JCache provider. In use cases where portability between cache providers is a requirement, applications should use Java serialization.

Coherence JCache Management

The Coherence JCache provider implements the JCache CacheMXBean and CacheStatisticsMXBean MXBean interfaces. The implementation are located in the com.tangosol.coherence.jcache.common package. Management information for local and partitioned caches are registered to the default MBean server and are found under the javax.cache namespace. Management information for pass-through caches are reported using the native Coherence JMX management implementation. For details about enabling JCache management, see "Viewing JCache Management Information".

33.2 Comparison of JCache and NamedCache Features

The Coherence JCache provider offers support for many features that are also available with the Coherence native NamedCache API. However, not all features are available through JCache. Table 33-1 shows a comparison of the two APIs.

Table 33-1 Comparison of JCache and NamedCache Features

Feature JCache NamedCache

Local Cache

X

X

Partitioned (Distributed) Cache

X

X

Replicated Cache

 

X

Optimistic Cache

 

X

Near Cache

 

X

Read Through

X

X

Write Through

X

X

Events

X

X

Query Filters

 

X

Indexes

 

X

Entry Processors

X

X

Aggregation

 

X

33.3 Dependencies for Coherence JCache

Applications that use JCache and the Coherence JCache provider must include the following libraries on the application classpath:

  • COHERENCE_HOME\lib\cache-api.jar – The standard JCache API.

  • COHERENCE_HOME\lib\coherence-jcache.jar – The Coherence JCache provider implementation.

  • COHERENCE_HOME\lib\coherence.jar – The core Coherence library.

The Coherence JCache provider includes a service definition in the META-INF/services directory of the coherence-jcache.jar library. The definition allows Coherence to be automatically loaded and used as the default caching provider by applications that use the javax.cache.Caching bootstrap class. For details about using Coherence as the default JCache provider, see"Specifying Coherence as the JCache Provider".

33.4 Overview of Configuration for the Coherence JCache Provider

The JCache provider utilizes the same configuration files as the native Coherence NamedCache API. However, the need to customize the configuration files has been simplified and in some cases not required at all. The following lists the configuration file used by the JCache implementation:

  • tangosol-coherence-override.xml – A Coherence operational override file is used when configuring a Coherence cluster for partitioned caches and when using pass-through caches. The override file is not required for local caches. For details about operational override files, see "Specifying an Operational Configuration File".

  • coherence-jcache-cache-config.xml – A Coherence JCache provider-specific cache configuration file that is called coherence-jcache-cache-cofig.xml is included in the provider JAR file and used to create local and partitioned caches; however, applications are not expected to edit the configuration. The included cache configuration file defines a JCacheNamespace handler class that is used to programmatically define local and partitioned caches for use by JCache applications.

  • coherence-jcache-pof-config.xml – A Coherence JCache provider-specific POF configuration file that is called coherence-jcache-pof-cofig.xml is included in the provider JAR file and is used to define JCache POF types. For details about including JCache POF types with an existing Coherence application, see "Configuring a JCache POF Configuration file".

33.5 JCache Primer

This section provides an overview of the JCache specification and API and is intended for those that are new to JCache. It includes basic concepts that are used when completing the instructions in this book. If you are familiar with JCache, you can skip this section.

This section is not intended to replace the specification or the API documentation. For complete details, download the JCache specification, Java sources, and JavaDoc from the Java Community Process (JCP) website:

https://www.jcp.org/en/jsr/detail?id=107

33.5.1 What is JCache

The JCache specification defines an API for creating and using caches in Java programs. Applications often use caches to store and reuse resources that require a significant cost to create. Applications can then quickly access the resources in memory without having to incur the cost associated with recreating the resources. Applications commonly use caching to increase application performance, availability, and scalability.

The JCache API defines a provider-based model for caching. The provider model separates the cache client API from the cache implementation. Applications use a well-defined client API and cache providers are responsible for the actual cache implementation. The provider-based model frees application developers from having to create and manage complex caching sub-systems and ensures portability between cache providers that implement the specification.

33.5.2 JCache Caching Providers and Cache Managers

The JCache API defines the CachingProvider and CacheManager interfaces. Applications use the CachingProvider interface to get and use a cache manager. Applications use the CacheManager interface to create and use caches. Applications are free to use multiple cache providers. However, a cache manager can only be associated with a single cache provider.

JCache offers several ways to get cache providers and access cache managers. A common access pattern that is used throughout this documentation is to use the Caching bootstrap class. The class provides a convenient way to get a CachingPovider implementation and automatically discovers providers that include a standard Java service definition.

The following example gets a default CachingProvider implementation and then creates a cache manager:

CachingProvider cachingProvider = Caching.getCachingProvider();
CacheManager cacheManager = cachingProvider.getCacheManager();

33.5.3 JCache Caches

The JCache API defines a Cache interface. The Cache interface creates a data structure that stores key and value pairs. Each key and value pair is referred to an entry and is defined by the Cache.Entry interface. A cache is similar to a Java Map data structure; However, there are some key differences:

  • Keys or values cannot be null.

  • Cache.put operations do not return an entry's previous value. The Cache.getAndPut operation is functionally equivalent to the Map.put operation.

  • Cache Entries expire and can be evicted.

  • Values can be automatically loaded from, and written to, an external source to support read-through and write-through caching.

  • Cache entry changes can be observed.

  • Cache statistics can be collected.

The Cache interface includes methods for putting, getting, replacing, and removing cache entries. Methods are also provided for loading a cache, registering cache listeners, and invoking entry processors.

The following example demonstrates using a cache manager to create a Cache instance called MyCache:

Cache<String, Integer> cache = cacheManager.createCache("MyCache", config);

JCache makes use of generics to support both compile and runtime type checking. The example creates a cache that requires keys to be of type String and values to be of type Integer. Type checking is not required but is often a best practice.

Operations are performed on the cache instance:

String key = "k";
Integer value = 1;

cache.put(key, value);

33.5.4 JCache Cache Configuration

The JCache API defines the CompleteConfiguration interface that is used to configure a cache. The MutableConfiguration class is a default implementation of the interface. The configuration options include:

  • setting store-by semantics (by value or by reference)

  • setting cache entry types

  • setting cache expiry

  • enabling read-through and write-through caching

  • enabling management and statistics

Caches are configured when the cache is created. In the previous cache example, the createCache method required both a name and configuration for the cache. The following example demonstrates creating a configuration object to be used by the createCache method:

MutableConfiguration<String, Integer> config = 
   new MutableConfiguration<String, Integer>();
config.setStoreByValue(true).setTypes(String.class, Integer.class)
   .setReadThrough(true)
   .setWriteThrough(true)
   .setManagementEnabled(true)
   .setStatisticsEnabled(true)
   .setExpiryPolicyFactory(CreatedExpiryPolicy.factoryOf(Duration.FIVE_MINUTES));

Cache<String, Integer> cache = cacheManager.createCache("MyCache", config);

33.5.5 JCache Custom Programming

The JCache API provides multiple interfaces that give applications the ability to customize caching. To use an implementation, you must use the Factory interface to create the instance. This ensures that the instance is serializable. The following interfaces can be implemented by an application:

  • ExpiryPolicy – This interface is used to define when (Duration) cache entries expire based on entry creation, access, and modification operations.

  • CacheLoader – This interface is used to load data into a cache from an external resource as is required when using read-through caching.

  • CacheWriter – This interface is used to write data to an external resource as is required when using read-through caching.

  • CacheEntryListener – A set of subinterfaces (CacheEntryCreatedListener, CacheEntryUpdatedListener, CacheEntryRemovedListener, and CacheEntryExpiredListener) that are used to receive and react to Cache events.

  • EntryProcessor – This interface is used to perform compound operations on cache entries in an atomic, lock-free manner. Unlike the other interfaces, the EntryProcessor interface does not require the use of the Factory interface to create an instance; however, the implementation will need to be serialized if the intention is to use distributed caching.

33.5.6 JCache Management

The JCache API defines two dynamic MBeans that are used to manage caches. The CacheMXBean MXBean reports cache configuration information. The CacheStatisticsMXBean MXBean reports cache performance statistics that are used to troubleshoot potential issues. The dynamic MBeans are registered with an implementation-specific MBean server and are obtained using standard JMX; including, the use of any JMX MBean-compliant browser.