Infinispan for the Power-user: Event Notifications

DZone 's Guide to

Infinispan for the Power-user: Event Notifications

· ·
Free Resource

Welcome to the third part of this deep-dive series of articles on Infinispan.  In this article I'd like to talk about Infinispan's event notification system.  This mechanism allows you to register listeners on Infinispan and receive notifications when interesting things happen.  The API in question is encapsulated by the Listenable interface.  Both Cache and CacheManager interfaces extend Listenable.

The Listenable interface exposes the following methods on which listeners can be attached, to receive notifications.

Read the other parts in this series:

Part 1 - Remoting
Part 2 - Cache Modes
Part 3 - Event Notifications


Registering listeners

Listeners themselves are simple POJO instances.  These POJOs need to be annotated with @Listener though.  @Listener has one optional, boolean property, sync, which defaults to true.  More on this later.

Listener instances themselves should expose one or more methods which are invoked when events happen, to be useful.  These methods should then be annotated with the event it is interested in.  Events that occur on the Cache interface represented by annotations in the  org.infinispan.notifications.cachelistener.annotation package, such as the @CacheEntryModified annotation.  Similarly, events that occur on the CacheManager interface are represented by annotations in the org.infinispan.notifications.cachemanagerlistener.annotation package, such as @CacheStarted.  Please see the Javadocs for these packages for a detailed list of the events available and what they mean.

Methods on listeners

Listener methods annotated with these events must be public, return a void, and take in a single parameter representing the event type, or something that the event type can be assigned to.  For example, a method annotated with @CacheEntryModified may look like:

public void handle(CacheEntryModifiedEvent e) {}

or even:

public void handle(Event e) {}

...since CacheEntryModifiedEvents can be assigned to Event.

Multiple annotations can be placed on the same method, too:

public void handle(Event e) {}

because both CacheEntryModifiedEvent and CacheEntryVisitedEvent can be assigned to Event.
Practically, you may want to know what type of event you've received.  You have two ways of doing this; either testing the type of the event passed in (using instanceof) or by inspecting the results of Event.getType() which returns an enumeration, which allows use within a switch block.

public void handle(Event e) {
switch (e.getType()) {
// a cache entry has been modified
// a cache entry has been visited


Event ordering

Event notifications are fired both before and after an event happens.  So if you register a listener interested in, say, @CacheEntryModified, your listener will be called both before and after the event takes place.  Querying Event.isPre() will tell you whether the callback is before or after the event takes place.

Threads and notification dispatching

Notifications are, by default, dispatched synchronously.  That is, the callback your listener receives happens on the same thread that causes the event.

This means that if your listener performs tasks that could be slow, the original caller's thread that triggered the event will block until your listener completes.

This side-effect can be undesirable for certain applications, so the general recommendation is that your listener implementations must not perform any long-running tasks, or tasks that could block.  If you do need to perform such tasks, annotate your listener with @Listener(sync = false) to force asynchronous dispatch of notifications for this listener.  This means that notifications will be invoked by a separate thread pool, and won't block the original caller's thread that triggered the event.

For further reading, I recommend looking through the Javadocs of the respective annotations and event types.


Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}