Ce contenu n'est pas disponible dans la langue sélectionnée.
7.7. Remote Event Listeners (Hot Rod)
CacheEntryCreated, CacheEntryModified, and CacheEntryRemoved. Clients can choose whether or not to listen to these events to avoid flooding connected clients. This assumes that clients maintain persistent connections to the servers.
Example 7.7. Event Print Listener
import org.infinispan.client.hotrod.annotation.*;
import org.infinispan.client.hotrod.event.*;
@ClientListener
public class EventLogListener {
@ClientCacheEntryCreated
public void handleCreatedEvent(ClientCacheEntryCreatedEvent e) {
System.out.println(e);
}
@ClientCacheEntryModified
public void handleModifiedEvent(ClientCacheEntryModifiedEvent e) {
System.out.println(e);
}
@ClientCacheEntryRemoved
public void handleRemovedEvent(ClientCacheEntryRemovedEvent e) {
System.out.println(e);
}
}
ClientCacheEntryCreatedEventandClientCacheEntryModifiedEventinstances provide information on the key and version of the entry. This version can be used to invoke conditional operations on the server, such areplaceWithVersionorremoveWithVersion.ClientCacheEntryRemovedEventevents are only sent when the remove operation succeeds. If a remove operation is invoked and no entry is found or there are no entries to remove, no event is generated. If users require remove events regardless of whether or not they are successful, a customized event logic can be created.- All client cache entry created, modified, and removed events provide a
boolean isCommandRetried()method that will returntrueif the write command that caused it has to be retried due to a topology change. This indicates that the event has been duplicated or that another event was dropped and replaced, such as where a Modified event replaced a Created event.
Important
Warning
7.7.1. Adding and Removing Event Listeners Copier lienLien copié sur presse-papiers!
The following example registers the Event Print Listener with the server. See Example 7.7, “Event Print Listener”.
Example 7.8. Adding an Event Listener
RemoteCache<Integer, String> cache = rcm.getCache();
cache.addClientListener(new EventLogListener();
A client event listener can be removed as follows
Example 7.9. Removing an Event Listener
EventLogListener listener = ...
cache.removeClientListener(listener);
7.7.2. Remote Event Client Listener Example Copier lienLien copié sur presse-papiers!
Procedure 7.2. Configuring Remote Event Listeners
Download the Red Hat JBoss Data Grid Server distribution from the Red Hat Customer Portal
The latest Red Hat JBoss Data Grid distribution includes the Hot Rod server with which the client will communicate.Start the server
Start the JBoss Data Grid server by using the following command from the root of the server.$ ./bin/standalone.shWrite an application to interact with the Hot Rod server
Maven users
Create an application with the following dependency, changing the version to6.4.0-Final-redhat-1or better.<dependency> <groupId>org.infinispan</groupId> <artifactId>infinispan-remote</artifactId> <version>${infinispan.version}</version> </dependency>- Non-Maven users, adjust according to your chosen build tool or download the distribution containing all JBoss Data Grid jars.
Write the client application
The following demonstrates a simple remote event listener that logs all events received.import org.infinispan.client.hotrod.annotation.*; import org.infinispan.client.hotrod.event.*; @ClientListener public class EventLogListener { @ClientCacheEntryCreated @ClientCacheEntryModified @ClientCacheEntryRemoved public void handleRemoteEvent(ClientEvent event) { System.out.println(event); } }Use the remote event listener to execute operations against the remote cache
The following example demonstrates a simple main java class, which adds the remote event listener and executes some operations against the remote cache.import org.infinispan.client.hotrod.*; RemoteCacheManager rcm = new RemoteCacheManager(); RemoteCache<Integer, String> cache = rcm.getCache(); EventLogListener listener = new EventLogListener(); try { cache.addClientListener(listener); cache.put(1, "one"); cache.put(1, "new-one"); cache.remove(1); } finally { cache.removeClientListener(listener); }
Once executed, the console output should appear similar to the following:
ClientCacheEntryCreatedEvent(key=1,dataVersion=1)
ClientCacheEntryModifiedEvent(key=1,dataVersion=2)
ClientCacheEntryRemovedEvent(key=1)
7.7.3. Filtering Remote Events Copier lienLien copié sur presse-papiers!
Example 7.10. KeyValueFilter
package sample;
import java.io.Serializable;
import org.infinispan.filter.*;
import org.infinispan.metadata.*;
@NamedFactory(name = "basic-filter-factory")
public class BasicKeyValueFilterFactory implements KeyValueFilterFactory {
@Override public KeyValueFilter<Integer, String> getKeyValueFilter(final Object[] params) {
return new BasicKeyValueFilter();
}
static class BasicKeyValueFilter implements KeyValueFilter<Integer, String>, Serializable {
@Override public boolean accept(Integer key, String value, Metadata metadata) {
return !"2".equals(key);
}
}
}
7.7.3.1. Custom Filters for Remote Events Copier lienLien copié sur presse-papiers!
Note
Procedure 7.3. Using a Custom Filter
- Create a
JARfile with the filter implementation within it. Each factory must have a name assigned to it via theorg.infinispan.filter.NamedFactoryannotation. The example uses aKeyValueFilterFactory. - Create a
META-INF/services/org.infinispan.notifications.filter.KeyValueFilterFactoryfile within theJARfile, and within it write the fully qualified class name of the filter class implementation. - Deploy the
JARfile in the JBoss Data Grid Server.
@ClientListener annotation to indicate the filter factory to use with the listener.
Example 7.11. Add Filter Factory to the Listener
@org.infinispan.client.hotrod.annotation.ClientListener(filterFactoryName = "basic-filter-factory")
public class BasicFilteredEventLogListener extends EventLogListener {}
Example 7.12. Register the Listener with the Server
import org.infinispan.client.hotrod.*;
RemoteCacheManager rcm = new RemoteCacheManager();
RemoteCache<Integer, String> cache = rcm.getCache();
BasicFilteredEventLogListener listener = new BasicFilteredEventLogListener();
try {
cache.addClientListener(listener);
cache.putIfAbsent(1, "one");
cache.replace(1, "new-one");
cache.putIfAbsent(2, "two");
cache.replace(2, "new-two");
cache.putIfAbsent(3, "three");
cache.replace(3, "new-three");
cache.remove(1);
cache.remove(2);
cache.remove(3);
} finally {
cache.removeClientListener(listener);
}
The following demonstrates the resulting system output from the provided example.
ClientCacheEntryCreatedEvent(key=1,dataVersion=1)
ClientCacheEntryModifiedEvent(key=1,dataVersion=2)
ClientCacheEntryCreatedEvent(key=3,dataVersion=5)
ClientCacheEntryModifiedEvent(key=3,dataVersion=6)
ClientCacheEntryRemovedEvent(key=1)
ClientCacheEntryRemovedEvent(key=3)
Important
7.7.3.2. Enhanced Filter Factories Copier lienLien copié sur presse-papiers!
Example 7.13. Configuring an Enhanced Filter Factory
package sample;
import java.io.Serializable;
import org.infinispan.filter.*;
import org.infinispan.metadata.*;
@NamedFactory(name = "basic-filter-factory")
public class BasicKeyValueFilterFactory implements KeyValueFilterFactory {
@Override public KeyValueFilter<Integer, String> getKeyValueFilter(final Object[] params) {
return new BasicKeyValueFilter(params);
}
static class BasicKeyValueFilter implements KeyValueFilter<Integer, String>, Serializable {
private final Object[] params;
public BasicKeyValueFilter(Object[] params) { this.params = params; }
@Override public boolean accept(Integer key, String value, Metadata metadata) {
return !params[0].equals(key);
}
}
}
Example 7.14. Running an Enhanced Filter Factory
import org.infinispan.client.hotrod.*;
RemoteCacheManager rcm = new RemoteCacheManager();
RemoteCache<Integer, String> cache = rcm.getCache();
BasicFilteredEventLogListener listener = new BasicFilteredEventLogListener();
try {
cache.addClientListener(listener, new Object[]{3}, null); // <- Filter parameter passed
cache.putIfAbsent(1, "one");
cache.replace(1, "new-one");
cache.putIfAbsent(2, "two");
cache.replace(2, "new-two");
cache.putIfAbsent(3, "three");
cache.replace(3, "new-three");
cache.remove(1);
cache.remove(2);
cache.remove(3);
} finally {
cache.removeClientListener(listener);
}
The provided example results in the following output:
ClientCacheEntryCreatedEvent(key=1,dataVersion=1)
ClientCacheEntryModifiedEvent(key=1,dataVersion=2)
ClientCacheEntryCreatedEvent(key=2,dataVersion=3)
ClientCacheEntryModifiedEvent(key=2,dataVersion=4)
ClientCacheEntryRemovedEvent(key=1)
ClientCacheEntryRemovedEvent(key=2)
7.7.4. Customizing Remote Events Copier lienLien copié sur presse-papiers!
Note
CacheEventConverter instances, which are created by implementing a CacheEventConverterFactory class. Each factory must have a name associated to it via the @NamedFactory annotation.
Procedure 7.4. Using a Converter
- Create a
JARfile with the converter implementation within it. Each factory must have a name assigned to it via theorg.infinispan.filter.NamedFactoryannotation. - Create a
META-INF/services/org.infinispan.notifications.filter.CacheEventConverterFactoryfile within theJARfile and within it, write the fully qualified class name of the converter class implementation. - Deploy the
JARfile in the JBoss Data Grid Server.
7.7.4.1. Adding a Converter Copier lienLien copié sur presse-papiers!
getConverter method to get a org.infinispan.filter.Converter class instance to customize events server side.
Example 7.15. Sending Custom Events
import org.infinispan.filter.*;
@NamedFactory(name = "value-added-converter-factory")
class ValueAddedConverterFactory implements ConverterFactory {
public Converter<Integer, String, ValueAddedEvent> getConverter(final Object[] params) {
return new ValueAddedConverter();
}
static class ValueAddedConverter implements Converter<Integer, String, ValueAddedEvent> {
public ValueAddedEvent convert(Integer key, String value, Metadata metadata) {
return new ValueAddedEvent(key, value);
}
}
}
// Must be Serializable or Externalizable.
class ValueAddedEvent implements Serializable {
final Integer key;
final String value;
ValueAddedEvent(Integer key, String value) {
this.key = key;
this.value = value;
}
}
7.7.4.2. Lightweight Events Copier lienLien copié sur presse-papiers!
JAR file including a service definition inside the META-INF/services/org.infinispan.filter.ConverterFactory file as follows:
sample.ValueAddedConverterFactor
@ClientListener annotation.
@ClientListener(converterFactoryName = "value-added-converter-factory")
public class CustomEventLogListener { ... }
7.7.4.3. Dynamic Converter Instances Copier lienLien copié sur presse-papiers!
Example 7.16. Dynamic Converter
import org.infinispan.notifications.cachelistener.filter.CacheEventConverterFactory;
import org.infinispan.notifications.cachelistener.filter.CacheEventConverter;
class DynamicCacheEventConverterFactory implements CacheEventConverterFactory {
public CacheEventConverter<Integer, String, CustomEvent> getConverter(final Object[] params) {
return new DynamicCacheEventConverter(params);
}
}
// Serializable, Externalizable or marshallable with Infinispan Externalizers needed when running in a cluster
class DynamicCacheEventConverter implements CacheEventConverter<Integer, String, CustomEvent>, Serializable {
final Object[] params;
DynamicCacheEventConverter(Object[] params) {
this.params = params;
}
public CustomEvent convert(Integer key, String value, Metadata metadata, String prevValue, Metadata prevMetadata, EventType eventType) {
// If the key matches a key given via parameter, only send the key information
if (params[0].equals(key))
return new ValueAddedEvent(key, null);
return new ValueAddedEvent(key, value);
}
}
RemoteCache<Integer, String> cache = rcm.getCache();
cache.addClientListener(new EventLogListener(), null, new Object[]{1});
7.7.4.4. Adding a Remote Client Listener for Custom Events Copier lienLien copié sur presse-papiers!
ClientCacheEntryCustomEvent<T>, where T is the type of custom event we are sending from the server. For example:
Example 7.17. Custom Event Listener Implementation
import org.infinispan.client.hotrod.annotation.*;
import org.infinispan.client.hotrod.event.*;
@ClientListener(converterFactoryName = "value-added-converter-factory")
public class CustomEventLogListener {
@ClientCacheEntryCreated
@ClientCacheEntryModified
@ClientCacheEntryRemoved
public void handleRemoteEvent(ClientCacheEntryCustomEvent<ValueAddedEvent> {
System.out.println(event);
}
}
Example 7.18. Execute Operations against the Remote Cache
import org.infinispan.client.hotrod.*;
RemoteCacheManager rcm = new RemoteCacheManager();
RemoteCache<Integer, String> cache = rcm.getCache();
CustomEventLogListener listener = new CustomEventLogListener();
try {
cache.addClientListener(listener);
cache.put(1, "one");
cache.put(1, "new-one");
cache.remove(1);
} finally {
cache.removeClientListener(listener);
}
Once executed, the console output should appear similar to the following:
ClientCacheEntryCustomEvent(eventData=ValueAddedEvent{key=1, value='one'}, eventType=CLIENT_CACHE_ENTRY_CREATED)
ClientCacheEntryCustomEvent(eventData=ValueAddedEvent{key=1, value='ne-wone'}, eventType=CLIENT_CACHE_ENTRY_MODIFIED)
ClientCacheEntryCustomEvent(eventData=ValueAddedEvent{key=1, value='null'}, eventType=CLIENT_CACHE_ENTRY_REMOVED
Important
7.7.5. Event Marshalling Copier lienLien copié sur presse-papiers!
Note
Procedure 7.5. Deploying a Marshaller
- Create a
JARfile with the converter implementation within it. Each factory must have a name assigned to it via theorg.infinispan.filter.NamedFactoryannotation. - Create a
META-INF/services/org.infinispan.commons.marshall.Marshallerfile within theJARfile and within it, write the fully qualified class name of the marshaller class implementation - Deploy the
JARfile in the Red Hat JBoss Data Grid Server
Note
7.7.6. Remote Event Clustering and Failover Copier lienLien copié sur presse-papiers!
The @ClientListener annotation has an optional includeCurrentState parameter, which when enabled, has the server send CacheEntryCreatedEvent event instances for all existing cache entries to the client. This allows clients to recompute their state or computation in the event the Hot Rod client transparently fails over registered listeners. The performance of the includeCurrentState parameter is impacted by the cache size, and therefore it is disabled by default.
Rather than relying on receiving state, users can define a method with the @ClientCacheFailover annotation, which receives ClientCacheFailoverEvent parameter inside the client listener implementation. If the node where a Hot Rod client has registered a client listener fails, the Hot Rod client detects it transparently, and fails over all listeners registered in the node that failed to another node.
includeCurrentState parameter can be set to true. Alternatively, Hot Rod clients can be made aware of failover events by adding a callback handler. This callback method is an efficient solution to handling cluster topology changes affecting client listeners.
Example 7.19. @ClientCacheFailove
import org.infinispan.client.hotrod.annotation.*;
import org.infinispan.client.hotrod.event.*;
@ClientListener
public class EventLogListener {
// ...
@ClientCacheFailover
public void handleFailover(ClientCacheFailoverEvent e) {
// Deal with client failover, e.g. clear a near cache.
}
}