26 Controlling Map Operations with Triggers
This chapter contains the following sections:
- Overview of Map Triggers
Map triggers supplement the standard capabilities of Coherence to provide a highly customized cache management system. - A Map Trigger Example
Learn how to use map triggers by following a basic example.
Parent topic: Performing Data Grid Operations
Overview of Map Triggers
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. The following example assumes that the createMapTrigger
method would return a new MapTriggerListener(new MyCustomTrigger());
:
<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
. The following example registers the PersonMapTrigger
with the People
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.
Parent topic: Controlling Map Operations with Triggers
A Map Trigger Example
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-1 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-2, calls the PersonMapTrigger
. The new MapTriggerListener
passes the PersonMapTrigger
to the People
NamedCache
.
Example 26-2 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"); } }
Parent topic: Controlling Map Operations with Triggers