This chapter provides instructions for using map triggers to validate, reject, or modify map operations before a change is committed to a map entry.
This chapter contains the following sections:
Map triggers supplement the standard capabilities of Coherence to provide a highly customized cache management system. Map triggers can be used to prevent invalid transactions, enforce complex security authorizations or complex business rules, provide transparent event logging and auditing, and gather statistics on data modifications. Other possible use for triggers include restricting operations against a cache to those issued during application re-deployment time.
For example, assume that you have code that is working with a NamedCache
, and you want to change an entry's behavior or contents before the entry is inserted into the map. The addition of a map trigger enables you to make this change without having to modify all the existing code.
Map triggers could also be used as part of an upgrade process. The addition of a map trigger could prompt inserts to be diverted from one cache into another.
A map trigger in the Coherence cache is somewhat similar to a trigger that might be applied to a database. It is a functional agent represented by the MapTrigger
interface that is run in response to a pending change (or removal) of the corresponding map entry. The pending change is represented by the MapTrigger.Entry
interface. This interface inherits from the InvocableMap.Entry
interface, so it provides methods to retrieve, update, and remove values in the underlying map.
The MapTrigger
interface contains the process
method that is used to validate, reject, or modify the pending change in the map. This method is called before an operation that intends to change the underlying map content is committed. An implementation of this method can evaluate the pending change by analyzing the original and the new value and produce any of the following results:
override the requested change with a different value
undo the pending change by resetting the original value
remove the entry from the underlying map
reject the pending change by throwing a runtime exception
do nothing, and allow the pending change to be committed
MapTrigger
functionality is typically added as part of an application start-up process. It can be added programmatically as described in the MapTrigger
API, or it can be configured using the class-factory
mechanism in the coherence-cache-config.xml
configuration file. In this case, a MapTrigger
is registered during the very first CacheFactory.getCache(
...)
call for the corresponding cache. Example 26-1 assumes that the createMapTrigger
method would return a new MapTriggerListener(new MyCustomTrigger());
:
Example 26-1 Example MapTriggerListener Configuration
<distributed-scheme> ... <listener> <class-scheme> <class-factory-name>package.MyFactory</class-factory-name> <method-name>createTriggerListener</method-name> <init-params> <init-param> <param-type>string</param-type> <param-value>{cache-name}</param-value> </init-param> </init-params> </class-scheme> </listener> </distributed-scheme>
In addition to the MapTrigger
.Entry
and MapTrigger
interfaces, Coherence provides the FilterTrigger
and MapTriggerListener
classes. The FilterTrigger
is a generic MapTrigger
implementation that performs a predefined action if a pending change is rejected by the associated Filter
. The FilterTrigger
can either reject the pending operation, ignore the change and restore the entry's original value, or remove the entry itself from the underlying map.
The MapTriggerListener
is a special purpose MapListener
implementation that is used to register a MapTrigger
with a corresponding NamedCache
. In Example 26-2, MapTriggerListener
is used to register the PersonMapTrigger
with the People
named cache.
Example 26-2 A MapTriggerListener Registering a MapTrigger with a Named Cache
NamedCache person = CacheFactory.getCache("People"); MapTrigger trigger = new PersonMapTrigger(); person.addMapListener(new MapTriggerListener(trigger));
These API reside in the com.tangosol.util
package. For more information on these API, see Java API Reference for Oracle Coherence.
The code in Example 26-3 illustrates a map trigger and how it can be called. In the PersonMapTrigger
class, the process
method is implemented to modify an entry before it is placed in the map. In this case, the last name attribute of a Person
object is converted to upper case characters. The object is then returned to the entry.
Example 26-3 A MapTrigger Class
... public class PersonMapTrigger implements MapTrigger { public PersonMapTrigger() { } public void process(MapTrigger.Entry entry) { Person person = (Person) entry.getValue(); String sName = person.getLastName(); String sNameUC = sName.toUpperCase(); if (!sNameUC.equals(sName)) { person.setLastName(sNameUC); System.out.println("Changed last name of [" + sName + "] to [" + person.getLastName() + "]"); entry.setValue(person); } } // ---- hashCode() and equals() must be implemented public boolean equals(Object o) { return o != null && o.getClass() == this.getClass(); } public int hashCode() { return getClass().getName().hashCode(); } }
The MapTrigger
in Example 26-4, calls the PersonMapTrigger
. The new MapTriggerListener
passes the PersonMapTrigger
to the People
NamedCache
.
Example 26-4 Calling a MapTrigger and Passing it to a Named Cache
... public class MyFactory { /** * Instantiate a MapTriggerListener for a given NamedCache */ public static MapTriggerListener createTriggerListener(String sCacheName) { MapTrigger trigger; if ("People".equals(sCacheName)) { trigger = new PersonMapTrigger(); } else { throw IllegalArgumentException("Unknown cache name " + sCacheName); } System.out.println("Creating MapTrigger for cache " + sCacheName); return new MapTriggerListener(trigger); } public static void main(String[] args) { NamedCache cache = CacheFactory.getCache("People"); cache.addMapListener(createTriggerListener("People")); System.out.println("Installed MapTrigger into cache People"); } }