org.infinispan.notifications
Annotation Type Listener
@Retention(value=RUNTIME)
@Target(value=TYPE)
public @interface Listener
Class-level annotation used to annotate an object as being a valid cache listener. Used with the Listenable.addListener(Object)
and related APIs.
Note that even if a class is annotated with this
annotation, it still needs method-level annotation (such as CacheStarted
)
to actually receive notifications. Objects annotated with this annotation - listeners - can be attached to a
running Cache
so users can be notified of Cache
events. There can
be multiple methods that are annotated to receive the same event, and a method may receive multiple events by using a
super type. Delivery Semantics
An event is delivered immediately after the respective
operation, but before the underlying cache call returns. For this reason it is important to keep listener processing
logic short-lived. If a long running task needs to be performed, it's recommended to use another thread.
Transactional Semantics
Since the event is delivered during the actual cache call, the transactional
outcome is not yet known. For this reason, events are always delivered, even if the changes they represent are
discarded by their containing transaction. For applications that must only process events that represent changes
in a completed transaction, TransactionalEvent.getGlobalTransaction()
can be used, along with TransactionCompletedEvent.isTransactionSuccessful()
to record events and later process them once the transaction has been successfully committed. Example 4 demonstrates
this. Threading Semantics
A listener implementation must be capable of handling concurrent
invocations. Local notifications reuse the calling thread; remote notifications reuse the network thread.
Since notifications reuse the calling or network thread, it is important to realise that if your listener
implementation blocks or performs a long-running task, the original caller which triggered the cache event may block
until the listener callback completes. It is therefore a good idea to use the listener to be notified of an event
but to perform any long running tasks in a separate thread so as not to block the original caller. In
addition, any locks acquired for the operation being performed will still be held for the callback. This needs to be
kept in mind as locks may be held longer than necessary or intended to and may cause deadlocking in certain
situations. See above paragraph on long-running tasks that should be run in a separate thread. Note:
The sync parameter on this annotation defaults to true
which provides the above semantics. Alternatively, if you set sync to false, then invocations are
made in a separate thread, which will not cause any blocking on the caller or network thread. The separate
thread is taken from a pool, which can be configured using GlobalConfiguration.setAsyncListenerExecutorProperties(java.util.Properties)
and GlobalConfiguration.setAsyncListenerExecutorFactoryClass(String)
.
Summary of Notification Annotations
Example 1 - Method receiving a single event
@Listener
public class SingleEventListener
{
@CacheStarted
public void doSomething(Event event)
{
System.out.println("Cache started. Details = " + event);
}
}
Example 2 - Method receiving multiple events
@Listener
public class MultipleEventListener
{
@CacheStarted
@CacheStopped
public void doSomething(Event event)
{
if (event.getType() == Event.Type.CACHE_STARTED)
System.out.println("Cache started. Details = " + event);
else if (event.getType() == Event.Type.CACHE_STOPPED)
System.out.println("Cache stopped. Details = " + event);
}
}
Example 3 - Multiple methods receiving the same event
@Listener
public class SingleEventListener
{
@CacheStarted
public void handleStart(Event event)
{
System.out.println("Cache started");
}
@CacheStarted
@CacheStopped
@CacheBlocked
@CacheUnblocked
@ViewChanged
public void logEvent(Event event)
{
logSystem.logEvent(event.getType());
}
}
Example 4 - Processing only events with a committed transaction.
@Listener
public class EventHandler
{
private ConcurrentMap<GlobalTransaction, Queue<Event>> map = new ConcurrentHashMap<GlobalTransaction, Queue<Event>>();
@TransactionRegistered
public void startTransaction(TransactionRegisteredEvent event)
{
map.put(event.getGlobalTransaction(), new ConcurrentLinkedQueue<Event>());
}
@CacheEntryCreated
@CacheEntryModified
@CacheEntryRemoved
public void addEvent(TransactionalEvent event)
{
map.get(event.getGlobalTransaction()).add(event);
}
@TransactionCompleted
public void endTransaction(TransactionCompletedEvent event)
{
Queue<Event> events = map.get(event.getGlobalTransaction());
map.remove(event.getGlobalTransaction());
System.out.println("Ended transaction " + event.getGlobalTransaction().getId());
if(event.isTransactionSuccessful())
{
for(Event e : events)
{
System.out.println("Event " + e);
}
}
}
}
- Since:
- 4.0
- Author:
- Manik Surtani, Jason T. Greene
- See Also:
CacheStarted
,
CacheStopped
,
CacheEntryModified
,
CacheEntryCreated
,
CacheEntryRemoved
,
CacheEntryVisited
,
CacheEntryLoaded
,
CacheEntriesEvicted
,
CacheEntryActivated
,
CacheEntryPassivated
,
ViewChanged
,
TransactionCompleted
,
TransactionRegistered
,
CacheEntryInvalidated
,
DataRehashed
,
TopologyChanged
Optional Element Summary |
boolean |
sync
Specifies whether callbacks on any class annotated with this annotation happens synchronously (in the caller's
thread) or asynchronously (using a separate thread). |
sync
public abstract boolean sync
- Specifies whether callbacks on any class annotated with this annotation happens synchronously (in the caller's
thread) or asynchronously (using a separate thread). Defaults to true.
- Returns:
- true if the expectation is that callbacks are called using the caller's thread; false if they are to be
made in a separate thread.
- Since:
- 4.0
- Default:
- true
Copyright © 2012 JBoss, a division of Red Hat. All Rights Reserved.