Manik Surtani is a core R&D engineer at JBoss and project lead on JBoss Cache. He has a background in artificial intelligence and neural networks, a field he left behind when he moved from academic circles to the commercial world. Since then, he's been working with Java-related technologies, first for a startup, focusing on knowledge management and information exchange. He later worked for a large London-based consultancy as a tech lead focused on e-commerce applications on large J2EE and peer-to-peer technology. Manik is a strong proponent of open source development methodologies, ethos, and collaborative processes, and often speaks at Java User Groups around the world. Manik is a DZone MVB and is not an employee of DZone and has posted 39 posts at DZone. You can read more from them at their website. View Full User Profile

Infinispan for the Power-user: Event Notifications

  • submit to reddit

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.

Published at DZone with permission of Manik Surtani, author and DZone MVB.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)


Deng Zhiyong replied on Fri, 2010/05/07 - 5:18am

Thanks,Good job!

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.