All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.infinispan.notifications.Listener Maven / Gradle / Ivy

There is a newer version: 9.1.7.Final
Show newest version
package org.infinispan.notifications;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * Class-level annotation used to annotate an object as being a valid cache listener.  Used with the {@link
 * org.infinispan.Cache#addListener(Object)} and related APIs. 

Note that even if a class is annotated with this * annotation, it still needs method-level annotation (such as {@link org.infinispan.notifications.cachemanagerlistener.annotation.CacheStarted}) * to actually receive notifications.

Objects annotated with this annotation - listeners - can be attached to a * running {@link org.infinispan.Cache} so users can be notified of {@link org.infinispan.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, {@link org.infinispan.notifications.cachelistener.event.TransactionalEvent#getGlobalTransaction()} * can be used, along with {@link org.infinispan.notifications.cachelistener.event.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 {@link org.infinispan.config.GlobalConfiguration#setAsyncListenerExecutorProperties(java.util.Properties)} * and {@link org.infinispan.config.GlobalConfiguration#setAsyncListenerExecutorFactoryClass(String)}. *

* Summary of Notification Annotations

* * * * * * * * * *

*

Annotation Event Description
{@link * org.infinispan.notifications.cachemanagerlistener.annotation.CacheStarted} {@link * org.infinispan.notifications.cachemanagerlistener.event.CacheStartedEvent} A cache was * started
{@link org.infinispan.notifications.cachemanagerlistener.annotation.CacheStopped}{@link org.infinispan.notifications.cachemanagerlistener.event.CacheStoppedEvent} A cache was stopped
{@link org.infinispan.notifications.cachelistener.annotation.CacheEntryModified}{@link org.infinispan.notifications.cachelistener.event.CacheEntryModifiedEvent} A cache entry was modified
{@link * org.infinispan.notifications.cachelistener.annotation.CacheEntryCreated} {@link * org.infinispan.notifications.cachelistener.event.CacheEntryCreatedEvent} A cache entry was * created
{@link org.infinispan.notifications.cachelistener.annotation.CacheEntryRemoved}{@link org.infinispan.notifications.cachelistener.event.CacheEntryRemovedEvent} A * cache entry was removed
{@link org.infinispan.notifications.cachelistener.annotation.CacheEntryVisited}{@link org.infinispan.notifications.cachelistener.event.CacheEntryVisitedEvent} A * cache entry was visited
{@link org.infinispan.notifications.cachelistener.annotation.CacheEntryLoaded}{@link org.infinispan.notifications.cachelistener.event.CacheEntryLoadedEvent} A * cache entry was loaded
{@link org.infinispan.notifications.cachelistener.annotation.CacheEntriesEvicted}{@link org.infinispan.notifications.cachelistener.event.CacheEntriesEvictedEvent} A * cache entries were evicted
{@link org.infinispan.notifications.cachelistener.annotation.CacheEntryActivated}{@link org.infinispan.notifications.cachelistener.event.CacheEntryActivatedEvent} A cache entry was activated
{@link * org.infinispan.notifications.cachelistener.annotation.CacheEntryPassivated} {@link * org.infinispan.notifications.cachelistener.event.CacheEntryPassivatedEvent} One or more cache entries were * passivated
{@link org.infinispan.notifications.cachemanagerlistener.annotation.ViewChanged}{@link org.infinispan.notifications.cachemanagerlistener.event.ViewChangedEvent} A view change event was detected
{@link * org.infinispan.notifications.cachelistener.annotation.TransactionRegistered} {@link * org.infinispan.notifications.cachelistener.event.TransactionRegisteredEvent} The cache has started * to participate in a transaction
{@link org.infinispan.notifications.cachelistener.annotation.TransactionCompleted}{@link org.infinispan.notifications.cachelistener.event.TransactionCompletedEvent} The cache has completed its participation in a transaction
{@link * org.infinispan.notifications.cachelistener.annotation.CacheEntryInvalidated} {@link * org.infinispan.notifications.cachelistener.event.CacheEntryInvalidatedEvent} A cache entry was * invalidated by a remote cache. Only if cache mode is INVALIDATION_SYNC or INVALIDATION_ASYNC.
*

*

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);
 *             }
 *          }
 *       }
 *    }
 * 
* * @author Manik Surtani * @author Jason T. Greene * @see org.infinispan.notifications.cachemanagerlistener.annotation.CacheStarted * @see org.infinispan.notifications.cachemanagerlistener.annotation.CacheStopped * @see org.infinispan.notifications.cachelistener.annotation.CacheEntryModified * @see org.infinispan.notifications.cachelistener.annotation.CacheEntryCreated * @see org.infinispan.notifications.cachelistener.annotation.CacheEntryRemoved * @see org.infinispan.notifications.cachelistener.annotation.CacheEntryVisited * @see org.infinispan.notifications.cachelistener.annotation.CacheEntryLoaded * @see org.infinispan.notifications.cachelistener.annotation.CacheEntriesEvicted * @see org.infinispan.notifications.cachelistener.annotation.CacheEntryActivated * @see org.infinispan.notifications.cachelistener.annotation.CacheEntryPassivated * @see org.infinispan.notifications.cachemanagerlistener.annotation.ViewChanged * @see org.infinispan.notifications.cachelistener.annotation.TransactionCompleted * @see org.infinispan.notifications.cachelistener.annotation.TransactionRegistered * @see org.infinispan.notifications.cachelistener.annotation.CacheEntryInvalidated * @see org.infinispan.notifications.cachelistener.annotation.DataRehashed * @see org.infinispan.notifications.cachelistener.annotation.TopologyChanged * @since 4.0 */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface Listener { /** * 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. * * @return 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 */ boolean sync() default true; /** * Specifies whether the event should be fired on the primary data owner of the affected key, or all nodes that see * the update. *

* Note that is value is ignored when {@link org.infinispan.notifications.Listener#clustered()} is true. * @return true if the expectation is that only the primary data owner will fire the event, false if all nodes that * see the update fire the event. * * @since 5.3 */ boolean primaryOnly() default false; /** * Defines whether the annotated listener is clustered or not. * Important: Clustered listener can only be notified for @CacheEntryRemoved, @CacheEntryCreated, * @CacheEntryModified and @CacheEntryExpired events. * @return true if the expectation is that this listener is to be a cluster listener, as in it will receive * all notifications for data modifications * @since 7.0 */ boolean clustered() default false; /** * If set to true then the entire existing state within the cluster is * evaluated. For existing matches of the value, an @CacheEntryCreated event is triggered against the listener * during registration. This is only supported if the listener is also * {@link org.infinispan.notifications.Listener#clustered()}. *

* If using a distributed clustered cache it is possible to retrieve new events before the initial transfer is * completed. This is handled since only new events are queued until the segment it belongs to is completed * for iteration. This also will help reduce memory strain since a distributed clustered listener will need * to eventually retrieve all values from the cache. * @return true if the expectation is that when the listener is installed that all of the current data is sent * as new events to the listener before receiving new events * @since 7.0 **/ boolean includeCurrentState() default false; Observation observation() default Observation.BOTH; enum Observation { PRE() { @Override public boolean shouldInvoke(boolean pre) { return pre; } }, POST() { @Override public boolean shouldInvoke(boolean pre) { return !pre; } }, BOTH() { @Override public boolean shouldInvoke(boolean pre) { return true; } }; public abstract boolean shouldInvoke(boolean pre); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy