@Override
 public void notifyTransactionRegistered(
     GlobalTransaction globalTransaction, InvocationContext ctx) {
   if (!transactionRegisteredListeners.isEmpty()) {
     boolean isOriginLocal = ctx.isOriginLocal();
     EventImpl<Object, Object> e = EventImpl.createEvent(cache, TRANSACTION_REGISTERED);
     e.setOriginLocal(isOriginLocal);
     e.setTransactionId(globalTransaction);
     for (ListenerInvocation listener : transactionRegisteredListeners) listener.invoke(e);
   }
 }
 @Override
 public void notifyCacheEntryPassivated(
     Object key, Object value, boolean pre, InvocationContext ctx, FlagAffectedCommand command) {
   if (isNotificationAllowed(command, cacheEntryPassivatedListeners)) {
     EventImpl<Object, Object> e = EventImpl.createEvent(cache, CACHE_ENTRY_PASSIVATED);
     e.setPre(pre);
     e.setKey(key);
     e.setValue(value);
     for (ListenerInvocation listener : cacheEntryPassivatedListeners) listener.invoke(e);
   }
 }
 @Override
 public void notifyTransactionCompleted(
     GlobalTransaction transaction, boolean successful, InvocationContext ctx) {
   if (!transactionCompletedListeners.isEmpty()) {
     boolean isOriginLocal = ctx.isOriginLocal();
     EventImpl<Object, Object> e = EventImpl.createEvent(cache, TRANSACTION_COMPLETED);
     e.setOriginLocal(isOriginLocal);
     e.setTransactionId(transaction);
     e.setTransactionSuccessful(successful);
     for (ListenerInvocation listener : transactionCompletedListeners) listener.invoke(e);
   }
 }
 @Override
 public void notifyCacheEntryModified(
     Object key,
     Object value,
     boolean created,
     boolean pre,
     InvocationContext ctx,
     FlagAffectedCommand command) {
   if (!cacheEntryModifiedListeners.isEmpty()) {
     boolean originLocal = ctx.isOriginLocal();
     EventImpl<Object, Object> e = EventImpl.createEvent(cache, CACHE_ENTRY_MODIFIED);
     e.setOriginLocal(originLocal);
     e.setValue(value);
     e.setPre(pre);
     e.setKey(key);
     // Even if CacheEntryCreatedEvent.getValue() has been added, to
     // avoid breaking old behaviour and make it easy to comply with
     // JSR-107 specification TCK, it's necessary to find out whether a
     // modification is the result of a cache entry being created or not.
     // This is needed because on JSR-107, a modification is only fired
     // when the entry is updated, and only one event is fired, so you
     // want to fire it when isPre=false.
     e.setCreated(created);
     setTx(ctx, e);
     for (ListenerInvocation listener : cacheEntryModifiedListeners) listener.invoke(e);
   }
 }
 @Override
 public void notifyDataRehashed(
     ConsistentHash oldCH, ConsistentHash newCH, int newTopologyId, boolean pre) {
   if (!dataRehashedListeners.isEmpty()) {
     EventImpl<Object, Object> e = EventImpl.createEvent(cache, DATA_REHASHED);
     e.setPre(pre);
     e.setConsistentHashAtStart(oldCH);
     e.setConsistentHashAtEnd(newCH);
     e.setNewTopologyId(newTopologyId);
     for (ListenerInvocation listener : dataRehashedListeners) listener.invoke(e);
   }
 }
  @Override
  public void notifyCacheEntryEvicted(
      Object key, Object value, InvocationContext ctx, FlagAffectedCommand command) {
    if (isNotificationAllowed(command, cacheEntriesEvictedListeners)) {
      EventImpl<Object, Object> e = EventImpl.createEvent(cache, CACHE_ENTRY_EVICTED);
      e.setEntries(Collections.singletonMap(key, value));
      for (ListenerInvocation listener : cacheEntriesEvictedListeners) listener.invoke(e);
    }

    // For backward compat
    if (isNotificationAllowed(command, cacheEntryEvictedListeners)) {
      EventImpl<Object, Object> e = EventImpl.createEvent(cache, CACHE_ENTRY_EVICTED);
      e.setKey(key);
      e.setValue(value);
      for (ListenerInvocation listener : cacheEntryEvictedListeners) listener.invoke(e);
    }
  }
  @Override
  public void notifyCacheEntriesEvicted(
      Collection<InternalCacheEntry> entries, InvocationContext ctx, FlagAffectedCommand command) {
    if (!entries.isEmpty()) {
      if (isNotificationAllowed(command, cacheEntriesEvictedListeners)) {
        EventImpl<Object, Object> e = EventImpl.createEvent(cache, CACHE_ENTRY_EVICTED);
        Map<Object, Object> evictedKeysAndValues =
            transformCollectionToMap(
                entries,
                new InfinispanCollections.MapMakerFunction<Object, Object, InternalCacheEntry>() {
                  @Override
                  public Map.Entry<Object, Object> transform(final InternalCacheEntry input) {
                    return new Map.Entry<Object, Object>() {
                      @Override
                      public Object getKey() {
                        return input.getKey();
                      }

                      @Override
                      public Object getValue() {
                        return input.getValue();
                      }

                      @Override
                      public Object setValue(Object value) {
                        throw new UnsupportedOperationException();
                      }
                    };
                  }
                });

        e.setEntries(evictedKeysAndValues);
        for (ListenerInvocation listener : cacheEntriesEvictedListeners) listener.invoke(e);
      }

      // For backward compat
      if (isNotificationAllowed(command, cacheEntryEvictedListeners)) {
        for (InternalCacheEntry ice : entries) {
          EventImpl<Object, Object> e = EventImpl.createEvent(cache, CACHE_ENTRY_EVICTED);
          e.setKey(ice.getKey());
          e.setValue(ice.getValue());
          for (ListenerInvocation listener : cacheEntryEvictedListeners) listener.invoke(e);
        }
      }
    }
  }
 @Override
 public void notifyCacheEntryActivated(
     Object key, Object value, boolean pre, InvocationContext ctx, FlagAffectedCommand command) {
   if (isNotificationAllowed(command, cacheEntryActivatedListeners)) {
     boolean originLocal = ctx.isOriginLocal();
     EventImpl<Object, Object> e = EventImpl.createEvent(cache, CACHE_ENTRY_ACTIVATED);
     e.setOriginLocal(originLocal);
     e.setPre(pre);
     e.setKey(key);
     e.setValue(value);
     setTx(ctx, e);
     for (ListenerInvocation listener : cacheEntryActivatedListeners) listener.invoke(e);
   }
 }
 @Override
 public void notifyTopologyChanged(
     ConsistentHash oldConsistentHash,
     ConsistentHash newConsistentHash,
     int newTopologyId,
     boolean pre) {
   if (!topologyChangedListeners.isEmpty()) {
     EventImpl<Object, Object> e = EventImpl.createEvent(cache, TOPOLOGY_CHANGED);
     e.setPre(pre);
     e.setConsistentHashAtStart(oldConsistentHash);
     e.setConsistentHashAtEnd(newConsistentHash);
     e.setNewTopologyId(newTopologyId);
     for (ListenerInvocation listener : topologyChangedListeners) listener.invoke(e);
   }
 }
 @Override
 public void notifyCacheEntryCreated(
     Object key, Object value, boolean pre, InvocationContext ctx, FlagAffectedCommand command) {
   if (!cacheEntryCreatedListeners.isEmpty()) {
     boolean originLocal = ctx.isOriginLocal();
     EventImpl<Object, Object> e = EventImpl.createEvent(cache, CACHE_ENTRY_CREATED);
     e.setOriginLocal(originLocal);
     // Added capability to set cache entry created value in order
     // to avoid breaking behaviour of CacheEntryModifiedEvent.getValue()
     // when isPre=false.
     e.setValue(value);
     e.setPre(pre);
     e.setKey(key);
     setTx(ctx, e);
     for (ListenerInvocation listener : cacheEntryCreatedListeners) listener.invoke(e);
   }
 }
 private void setTx(InvocationContext ctx, EventImpl<Object, Object> e) {
   if (ctx != null && ctx.isInTxScope()) {
     GlobalTransaction tx = ((TxInvocationContext) ctx).getGlobalTransaction();
     e.setTransactionId(tx);
   }
 }
 public static <K, V> EventImpl<K, V> createEvent(Cache<K, V> cache, Type type) {
   EventImpl<K, V> e = new EventImpl<K, V>();
   e.cache = cache;
   e.type = type;
   return e;
 }