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

com.alachisoft.ncache.client.internal.caching.EventManager Maven / Gradle / Ivy

package com.alachisoft.ncache.client.internal.caching;

import Alachisoft.NCache.Caching.CallbackInfo;
import Alachisoft.NCache.Common.*;
import Alachisoft.NCache.Caching.Util.CollectionUtil;
import Alachisoft.NCache.Common.BitSet;
import Alachisoft.NCache.Common.Enum.SerializationFormat;
import Alachisoft.NCache.Common.Enum.UserObjectType;
import Alachisoft.NCache.Common.JSON.ExtendedJsonValueBase;

import Alachisoft.NCache.Common.Logger.JLogger;
import Alachisoft.NCache.Common.Threading.ThreadPool;
import com.alachisoft.ncache.client.*;
import com.alachisoft.ncache.client.internal.messaging.MessageEventItem;
import com.alachisoft.ncache.runtime.caching.DistributedDataStructure;
import com.alachisoft.ncache.runtime.caching.TopicSubscription;
import com.alachisoft.ncache.runtime.caching.messaging.MessageReceivedListener;
import com.alachisoft.ncache.runtime.events.*;
import com.alachisoft.ncache.runtime.events.EventType;
import com.alachisoft.ncache.runtime.exceptions.CacheException;
import com.alachisoft.ncache.runtime.exceptions.OperationFailedException;

import java.util.*;

/**
 * Has the responsibility of creating  and
 * registering it against a ResourcePool
 */
public class EventManager {

    public static final short REFSTART = -1;
    public static final short SELECTIVEREFSTARTRemove = 8000;
    public static final short SELECTIVEREFSTARTUpdate = 9000;
    public static final short COLLECTIONREFSTARTAdd = 11000;
    public static final short COLLECTIONREFSTARTUpdate = 12000;
    public static final short COLLECTIONREFSTARTRemove = 13000;
    MessageReceivedListener selectiveEventMessageReceivedListener =null;
    MessageReceivedListener generalEventMessageReceivedListener = null ;
    MessageReceivedListener collectionEventMessageReceivedListener = null;
    private String _cacheName = null;
    private JLogger _logger;
    private Object sync_lock_selective = new Object();
    private Object sync_lock_general = new Object();
    private Object sync_lock_collection = new Object();
    //    private static AsyncCallback asyn = new System.AsyncCallback(EndAsyncCallback);
    private CacheImpl _cache;
    private PollNotificationListener pollnotifyListener;

    private ResourcePool _addEventPool = null;
    private ResourcePool _cacheClearEventPool = null;
    private EventDataFilter _addDataFilter = EventDataFilter.None;
    private ResourcePool _removeEventPool = null;
    private EventDataFilter _removeDataFilter = EventDataFilter.None;
    private ResourcePool _updateEventPool = null;
    private EventDataFilter _updateDataFilter = EventDataFilter.None;
    private short _addEventRegistrationSequence = REFSTART; //Significant difference from old callback numbers
    private short _updateEventRegisrationSequenceId = REFSTART; //Significant difference from old callback numbers
    private short _removeEventRegistrationSequenceId = REFSTART; //Significant difference from old callback numbers
    private ResourcePool _selectiveRemoveEventPool = null;
    private ResourcePool _selectiveRemoveEventIDPool = null;
    private ResourcePool _oldSelectiveCallbackPool = new ResourcePool();
    private ResourcePool _oldSelectiveMappingCallbackPool = new ResourcePool();
    private short _selectveRemoveCallbackRef = SELECTIVEREFSTARTRemove;
    private ResourcePool _selectiveUpdateEventPool = null;
    private ResourcePool _selectiveUpdateEventIDPool = null;
    private short _selectiveUpdateCallbackRef = SELECTIVEREFSTARTUpdate;
    private EventDataFilter _generalAddDataFilter = EventDataFilter.None;
    private EventDataFilter _generalUpdateDataFilter = EventDataFilter.None;
    private EventDataFilter _generalRemoveDataFilter = EventDataFilter.None;

    private PollNotificationListener _pollClientCacheCallback;
    private PollNotificationListener _pollPubSubCallback;
    private ResourcePool _collectionAddEventPool = null;
    private ResourcePool _collectionAddEventIdPool = null;
    private short _collectionAddCallbackRef = COLLECTIONREFSTARTAdd;

    private ResourcePool _collectionUpdateEventPool = null;
    private ResourcePool _collectionUpdateEventIdPool = null;
    private short _collectionUpdateCallbackRef = COLLECTIONREFSTARTUpdate;

    private ResourcePool _collectionRemoveEventPool = null;
    private ResourcePool _collectionRemoveEventIdPool = null;
    private short _collectionRemoveCallbackRef = COLLECTIONREFSTARTRemove;
    private int addCallbacks = -1;
    private int removeCallbacks = -1;
    private int updateCallbacks = -1;

    private TopicSubscriptionImpl _generalEventsSubscription;
    private TopicSubscriptionImpl _collectionEventsSubscription;
    private TopicSubscription _selectiveEventsSubscription;
    private Set eventHandlerSet= new HashSet<>();

    public EventManager(String cacheName, JLogger logger, CacheImpl cache) {
        _cacheName = cacheName;
        _logger = logger;
        _cache = cache;
        if(generalEventMessageReceivedListener == null){
            generalEventMessageReceivedListener = new GeneralEventMessageReceivedListener(this);
        }
        if(collectionEventMessageReceivedListener == null){
            collectionEventMessageReceivedListener = new CollectionEventMessageReceivedListener(this);
        }
        if(selectiveEventMessageReceivedListener ==null)
            selectiveEventMessageReceivedListener =new SelectiveEventMessageReceivedListener(this);
    }

    private static void fire(Object obj) {
        try {
            Object[] objArray = (Object[]) obj;
            ((CacheDataModificationListener) objArray[0]).onCacheDataModified((String) objArray[1], (CacheEventArg) objArray[2]);
        } catch (Exception e) {
        }
    }

    public final short getAddSequenceNumber() {
        return _addEventRegistrationSequence;
    }

    public final short getUpdateSequenceNumber() {
        return _updateEventRegisrationSequenceId;
    }

    public final short getRemoveSequenceNumber() {
        return _removeEventRegistrationSequenceId;
    }

    public final Object getSyncLockGeneral() {
        return sync_lock_general;
    }

    public final Object getSyncLockSelective() {
        return sync_lock_selective;
    }
    public Object getSyncLockCollection()
    {
        return sync_lock_collection;
    }

    /**
     * Provide
     *
     * @param eventType
     * @return
     */
    public final short generalEventRefCountAgainstEvent(EventType eventType) {
        if ((eventType.getValue() & EventType.ItemAdded.getValue()) != 0) {
            return _addEventRegistrationSequence;
        }
        if ((eventType.getValue() & EventType.ItemRemoved.getValue()) != 0) {
            return _removeEventRegistrationSequenceId;
        }
        if ((eventType.getValue() & EventType.ItemUpdated.getValue()) != 0) {
            return _updateEventRegisrationSequenceId;
        }

        return -1;
    }

    /**
     * Returns the filter type of the eventType
     *
     * @param eventType
     * @return
     */
    public final EventDataFilter maxFilterAgainstEvent(EventType eventType) {
        if ((eventType.getValue() & EventType.ItemAdded.getValue()) != 0) {
            return _addDataFilter;
        }
        if ((eventType.getValue() & EventType.ItemRemoved.getValue()) != 0) {
            return _removeDataFilter;
        }
        if ((eventType.getValue() & EventType.ItemUpdated.getValue()) != 0) {
            return _updateDataFilter;
        }

        return EventDataFilter.DataWithMetadata;
    }


    public final short[] registerSelectiveEvent(CacheDataModificationListener listener, EnumSet enumTypeSet, EventDataFilter datafilter) throws CacheException {
        if (listener != null) {
            //Avoiding new ResourcePool(inside = new Hashtable) at constructor level
            if (_selectiveUpdateEventPool == null) {
                _selectiveUpdateEventPool = new ResourcePool();
                _selectiveUpdateEventIDPool = new ResourcePool();
            }
            if (_selectiveRemoveEventPool == null) {
                _selectiveRemoveEventPool = new ResourcePool();
                _selectiveRemoveEventIDPool = new ResourcePool();
            }

            //CacheEventDiscriptor discriptor = CacheEventDiscriptor.CreateCacheDiscriptor(eventType, _cacheName, callback, datafilter);
            return registerSelectiveDiscriptor(listener, enumTypeSet);
        } else {
            return new short[]
                    {
                            -1, -1
                    };
        }
    }

//    public final short[] registerSelectiveEvent(CacheDataModificationListener listener, EventTypeInternal eventType, EventDataFilter datafilter) throws CacheException {
//        return registerSelectiveEvent(listener, eventType, datafilter, ListenerType.PushBasedNotification);
//    }

    public final short[] registerSelectiveEvent(CacheDataModificationListener listener, EnumSet eventTypes, EventDataFilter datafilter, ListenerType listenerType) throws CacheException {
        if (listener != null) {
            if (_selectiveUpdateEventPool == null) {
                _selectiveUpdateEventPool = new ResourcePool();
                _selectiveUpdateEventIDPool = new ResourcePool();
            }
            if (_selectiveRemoveEventPool == null) {
                _selectiveRemoveEventPool = new ResourcePool();
                _selectiveRemoveEventIDPool = new ResourcePool();
            }
            return registerSelectiveDiscriptor(listener, eventTypes, listenerType);
        } else {
            return null;
        }
    }

    public CacheEventDescriptor registerGeneralEvents(CacheDataModificationListener listener, EnumSet eventTypes, EventDataFilter datafilter) throws CacheException {
        if (listener != null) {
            if (_addEventPool == null) {
                _addEventPool = new ResourcePool();
            }
            if (_removeEventPool == null) {
                _removeEventPool = new ResourcePool();
            }
            if (_updateEventPool == null) {
                _updateEventPool = new ResourcePool();
            }

            CacheEventDescriptor discriptor = CacheEventDescriptor.createCacheDiscriptor(eventTypes, _cacheName, listener, datafilter);

            //Registers the handle
            boolean registeredDescriptor=false;
            for(EventType eventType:eventTypes) {
                EventTypeInternal eventTypeInternal = EventUtil.getEventTypeInternal(eventType);
                registeredDescriptor = registerGeneralDiscriptor(discriptor, eventTypeInternal);
            }
            if (!registeredDescriptor) {
                return null;
            }

            return discriptor;

        } else {
            return null;
        }
    }


    public final void unregisterAll() {
        //TODO
    }

    /**
     * TheadSafe and no locks internally
     *
     * @param key
     * @param item
     * @param oldItem
     * @param reason
     * @param notifyAsync
     */
    public final void raiseGeneralCacheNotification(final String key, EventType eventType, EventCacheItem item, EventCacheItem oldItem, CacheItemRemovedReason reason, boolean notifyAsync) {
        try {
            Object[] registeredDiscriptors = null;

            ResourcePool eventPool = getEventPool(EventUtil.getEventTypeInternal(eventType));
            if (eventPool != null) {
                registeredDiscriptors = eventPool.GetAllResourceKeys();
            }

            if (registeredDiscriptors != null && registeredDiscriptors.length > 0) {
                for (int i = 0; i < registeredDiscriptors.length; i++) {
                    final CacheEventDescriptor discriptor = (CacheEventDescriptor) ((registeredDiscriptors[i] instanceof CacheEventDescriptor) ? registeredDiscriptors[i] : null);

                    if (discriptor == null) {
                        continue;
                    }
                    BitSet bitSet = new BitSet();

                    if (_cache.getSerializationFormat() == SerializationFormat.Json)
                        bitSet.SetBit((byte) BitSetConstants.JsonData);

                    if (item != null)
                        EventCacheItemWrapperInternal.setValue(item,_cache.safeDeserialize(item.getValue(null), _cache.getSerializationContext(), bitSet, UserObjectType.CacheItem,null));

                    if (oldItem != null)
                        EventCacheItemWrapperInternal.setValue(oldItem,_cache.safeDeserialize(oldItem.getValue(null), _cache.getSerializationContext(), bitSet, UserObjectType.CacheItem,null));

                    CacheEventArg arg = createCacheEventArgument(discriptor.getDataFilter(), key, _cacheName, eventType, item, oldItem, reason);
                    arg.setDescriptor(discriptor);

                    if (notifyAsync) {
                        ThreadPool.getInstance().executeTask((new Runnable() {
                            @Override
                            public void run() {
                                fire(new Object[]
                                        {
                                                discriptor.getCacheDataNotificationListener(), key, arg
                                        });
                            }
                        }));
                    } else {
                        discriptor.getCacheDataNotificationListener().onCacheDataModified(key, arg);
                    }
                }
            }
        } catch (RuntimeException | OperationFailedException ex) {
            if (_logger != null && _logger.getIsErrorEnabled()) {
                _logger.CriticalInfo(ex.toString());
            }
        }
    }

    private CacheEventArg createCacheEventArgument(EventDataFilter dataFilter, String key, String cacheName, EventType eventType, EventCacheItem item, EventCacheItem oldItem, CacheItemRemovedReason removedReason) {
        EventCacheItem cloneItem = null;
        EventCacheItem cloneOldItem = null;

        if (dataFilter != EventDataFilter.None && item != null) {
            Object tempVar = item.clone();
            cloneItem = (EventCacheItem) ((tempVar instanceof EventCacheItem) ? tempVar : null);

            if (cloneItem != null) {
                if (dataFilter == EventDataFilter.Metadata) {
                    EventCacheItemWrapperInternal.setValue(cloneItem,null);
                }
            }
        }

        if (dataFilter != EventDataFilter.None && oldItem != null) {
            Object tempVar2 = oldItem.clone();
            cloneOldItem = (EventCacheItem) ((tempVar2 instanceof EventCacheItem) ? tempVar2 : null);

            if (cloneOldItem != null) {
                if (dataFilter == EventDataFilter.Metadata) {
                    EventCacheItemWrapperInternal.setValue(cloneOldItem,null);
                }
            }
        }

        CacheEventArg eventArg = new CacheEventArg(key, cacheName, eventType, cloneItem, null, removedReason);
        if (eventType == EventType.ItemUpdated) {
            eventArg.setOldItem(cloneOldItem);
        }

        return eventArg;
    }

    /**
     * TheadSafe and no locks internally
     *
     * @param key
     * @param item
     * @param oldItem
     * @param reason
     * @param _notifyAsync
     * @param eventhandle
     */
    public final void raiseSelectiveCacheNotification(final String key, EnumSet eventEnumSet, EventCacheItem item, EventCacheItem oldItem, CacheItemRemovedReason reason, boolean _notifyAsync, EventHandle eventhandle, EventDataFilter dataFilter) {
        try {
            ResourcePool poolID = null;

            if (eventEnumSet.contains(EventType.ItemUpdated)) {
                poolID = _selectiveUpdateEventIDPool;
                //arg = new CacheEventArg(key, _cacheName, EventType.ItemUpdated, item, null, oldItem);
            } else if (eventEnumSet.contains(EventType.ItemRemoved)) {
                poolID = _selectiveRemoveEventIDPool;
                //arg = new CacheEventArg(key, _cacheName, EventType.ItemRemoved, item, null, reason);
            }

            if (poolID == null) {
                return;
            }

            final CacheEventArg arg = createCacheEventArgument(dataFilter, key, _cacheName, EventUtil.getEventType(eventEnumSet), item, oldItem, reason);

            Object tempVar = poolID.GetResource((short) eventhandle.getHandle());
            final CacheDataModificationListener callback = (CacheDataModificationListener) ((tempVar instanceof CacheDataModificationListener) ? tempVar : null);

            if (callback == null) //Can occur if Unregistered concurrently
            {
                return;
            }

            if (_notifyAsync) //callback.BeginInvoke(key, arg, asyn, null);
            {
                ThreadPool.getInstance().executeTask(new Runnable() {
                    @Override
                    public void run() {
                        fire(new Object[]
                                {
                                        callback, key, arg
                                });
                    }
                });
                //System.Threading.ThreadPool.QueueUserWorkItem(waitC, new Object[]{callback, key, arg}); //Faster and better
            } else {
                callback.onCacheDataModified(key, arg);
            }
        } catch (RuntimeException ex) {
            if (_logger != null && _logger.getIsErrorEnabled()) {
                _logger.CriticalInfo(ex.toString());
            }
        }
    }

    /**
     * Returning Negative value means operation not successful
     *
     * @return short array
     * 

* 1st value is Update callbackRef

nd value is removeRef */ private short[] registerSelectiveDiscriptor(CacheDataModificationListener listener, EnumSet eventTypes, ListenerType listenerType) throws CacheException { if (listener == null) { return null; //FAIL CONDITION } short[] returnValue = new short[]{-1, -1}; //First value update callback ref & sencond is remove callbackref for (EventType type : eventTypes) { if (type == EventType.ItemAdded) //ItemAdded not supported Yet { continue; } synchronized (getSyncLockSelective()) { ResourcePool pool = null; ResourcePool poolID = null; //region pool selection if (type == EventType.ItemRemoved ) { pool = _selectiveRemoveEventPool; poolID = _selectiveRemoveEventIDPool; } else if (type == EventType.ItemUpdated ) { pool = _selectiveUpdateEventPool; poolID = _selectiveUpdateEventIDPool; } if (pool == null) { continue; } //endregion while (true) { int i = type == EventType.ItemUpdated ? 0 : 1; if (pool.GetResource(listener) == null) { returnValue[i] = type == EventType.ItemUpdated ? ++_selectiveUpdateCallbackRef : ++_selectveRemoveCallbackRef; pool.AddResource(listener, returnValue[i]); poolID.AddResource(returnValue[i], listener); break; } else { try { short cref = (short) pool.GetResource(listener); if (cref < 0) { break; //FAIL CONDITION } //add it again into the table for updating ref count. pool.AddResource(listener, cref); poolID.AddResource(cref, listener); returnValue[i] = cref; break; } catch (NullPointerException e) { //Legacy code: can create an infinite loop //Recomendation of returning a negative number instead of continue continue; } } } } } if (_selectiveEventsSubscription == null && listenerType != ListenerType.PullBasedCallback) { TopicImpl topic = (TopicImpl) _cache._messagingService.getTopic(TopicConstant.ItemLevelEventsTopic, true); _selectiveEventsSubscription = topic.createEventSubscription(selectiveEventMessageReceivedListener); } return returnValue; } private short[] registerSelectiveDiscriptor(CacheDataModificationListener listener, EnumSet enumTypeSet) throws CacheException { if (listener == null) { return null; //FAIL CONDITION } short[] returnValue = new short[] { -1, -1 }; //First value update callback ref & sencond is remove callbackref for (EventType type : EventType.values()) { if (type == EventType.ItemAdded) //ItemAdded not supported Yet { continue; } synchronized (getSyncLockSelective()) { ResourcePool pool = null; ResourcePool poolID = null; if (type.equals(EventType.ItemRemoved) && enumTypeSet.contains(type)) { pool = _selectiveRemoveEventPool; poolID = _selectiveRemoveEventIDPool; } else if (type.equals(EventType.ItemUpdated) && enumTypeSet.contains(type)) { pool = _selectiveUpdateEventPool; poolID = _selectiveUpdateEventIDPool; } if (pool == null) { continue; } while (true) { int i = type.equals(EventType.ItemUpdated) ? 0 : 1; if (pool.GetResource(listener) == null) { returnValue[i] = type.equals(EventType.ItemUpdated) ? ++_selectiveUpdateCallbackRef : ++_selectveRemoveCallbackRef; pool.AddResource(listener, returnValue[i]); poolID.AddResource(returnValue[i], listener); break; } else { try { if (pool.GetResource(listener) != null) { short cref = (Short) pool.GetResource(listener); if (cref < 0) { break; //FAIL CONDITION } //add it again into the table for updating ref count. pool.AddResource(listener, cref); poolID.AddResource(cref, listener); returnValue[i] = cref; break; } } catch (NullPointerException e) { //Legacy code: can create an infinite loop //Recomendation of returning a negative number instead of continue continue; } } } if (_selectiveEventsSubscription == null ) { TopicImpl topic = (TopicImpl)_cache._messagingService.getTopic(TopicConstant.ItemLevelEventsTopic, true); SelectiveEventMessageReceivedListener eventListener=new SelectiveEventMessageReceivedListener(this); _selectiveEventsSubscription = (TopicSubscription)topic.createEventSubscription(eventListener); } } } return returnValue; } public void onSelectiveEventsMessageRecieved(MessageEventItem eventMessage) { String key = eventMessage.getKey(); CallbackInfo cbInfo = new CallbackInfo(null, eventMessage.getCallback(), eventMessage.getDataFilter()); EventHandle handle = null; if (cbInfo != null) { short handler = (short)cbInfo.getCallback(); handle = new EventHandle(handler); } switch (eventMessage.getEventType()) { case ITEM_UPDATED_CALLBACK: raiseSelectiveCacheNotification(key, EnumSet.of(EventType.ItemUpdated), eventMessage.getItem(), eventMessage.getOldItem(), CacheItemRemovedReason.Underused, false, handle, cbInfo.getDataFilter()); break; case ITEM_REMOVED_CALLBACK: raiseSelectiveCacheNotification(key, EnumSet.of(EventType.ItemRemoved), eventMessage.getItem(), null, eventMessage.getReason(), false, handle, cbInfo.getDataFilter()); break; } } private boolean registerGeneralDiscriptor(CacheEventDescriptor discriptor, EventTypeInternal eventType) throws CacheException { if (discriptor == null) { return false; //FAIL CONDITION } EventHandle handle = null; for (EventTypeInternal type : EventTypeInternal.values()) { ResourcePool pool = null; boolean registrationUpdated = false; if (type == eventType) { pool = getEventPool(type); } if (pool == null) { continue; } short registrationSequenceId = -1; synchronized (getSyncLockGeneral()) { pool.AddResource(discriptor, 1); // Everytime a new Discriptor is forcefully created //Keeps a sequence number switch (type) { case ItemAdded: if (discriptor.getDataFilter() != _generalAddDataFilter || _addEventRegistrationSequence == REFSTART) { registrationUpdated = true; registrationSequenceId = ++_addEventRegistrationSequence; _generalAddDataFilter = discriptor.getDataFilter(); } else { registrationSequenceId = _addEventRegistrationSequence; } break; case ItemRemoved: if (discriptor.getDataFilter() != _generalRemoveDataFilter || _removeEventRegistrationSequenceId == REFSTART) { registrationUpdated = true; registrationSequenceId = ++_removeEventRegistrationSequenceId; _generalRemoveDataFilter = discriptor.getDataFilter(); } else { registrationSequenceId = _removeEventRegistrationSequenceId; } break; case ItemUpdated: if (discriptor.getDataFilter() != _generalUpdateDataFilter || _updateEventRegisrationSequenceId == REFSTART) { registrationUpdated = true; registrationSequenceId = ++_updateEventRegisrationSequenceId; _generalUpdateDataFilter = discriptor.getDataFilter(); } else { registrationSequenceId = _updateEventRegisrationSequenceId; } break; } //Although the handle doesnt matter in general events if (handle == null) { handle = new EventHandle(registrationSequenceId); } } if (_cache != null && registrationSequenceId != -1) { _cache.addCacheNotificationDataFilter(type, discriptor.getDataFilter(), registrationSequenceId); } } //Check for avoiding multiple subscriptions if (_generalEventsSubscription == null) { TopicImpl topic = (TopicImpl) _cache._messagingService.getTopic(TopicConstant.GeneralEventsTopic, true); _generalEventsSubscription = (TopicSubscriptionImpl) topic.createEventSubscription(generalEventMessageReceivedListener); } discriptor.setIsRegistered(true); discriptor.setHandle(handle); return true; } /** * Unregisters CacheDataNotificationCallback *

* Flag based unregistration

* * @param listener */ public final short[] unRegisterSelectiveNotification(CacheDataModificationListener listener, EnumSet eventTypes) throws Exception { if (listener == null) { return null; } short[] returnValue = new short[] { -1, -1 }; for (EventType type : eventTypes) { if (type == EventType.ItemAdded) //ItemAdded not supported Yet { continue; } Object id = -1; synchronized (getSyncLockSelective()) { ResourcePool pool = null; ResourcePool poolID = null; ///#region pool selection if (type.equals(EventType.ItemRemoved)) { pool = _selectiveRemoveEventPool; poolID = _selectiveRemoveEventIDPool; if (pool == null) removeCallbacks = 0; } else if (type.equals(EventType.ItemUpdated) ) { pool = _selectiveUpdateEventPool; poolID = _selectiveUpdateEventIDPool; if (pool == null) updateCallbacks = 0; } if(removeCallbacks==0 && updateCallbacks==0) { _selectiveEventsSubscription.unSubscribe(); _selectiveEventsSubscription=null; } if (pool == null) { continue; } //Taimoor : For selective callback, we dont remove the callback as it can create chaos if user try to unregister //a callback more then one time or against wrong items. //cb = "iucb-" + System.Diagnostics.Process.GetCurrentProcess().Id + updateCallback.Method.Name; //id = _selectiveEventPool.GetResource(discriptor); int i = type == EventType.ItemUpdated ? 0 : 1; id = pool.GetResource(listener); if (id instanceof Short) { returnValue[i] = (Short) id; } } } return returnValue; } public final EventHandle unRegisterDiscriptor(CacheEventDescriptor discriptor) throws Exception { if (discriptor == null || !discriptor.getIsRegistered()) { return null; } for (EventType type : EventType.values()) { ResourcePool pool = null; if (discriptor.getRegisteredAgainst().contains(type)) { pool = getEventPool(EventUtil.getEventTypeInternal(type)); } if (pool == null) { continue; } short registrationSequenceId = -1; boolean unregisterNotification; EventDataFilter maxDataFilter = EventDataFilter.None; synchronized (getSyncLockGeneral()) { Object retVal = pool.RemoveResource(discriptor); if (retVal == null) { continue; } unregisterNotification = pool.getCount() == 0; if (!unregisterNotification) { Object[] pooledDescriptors = pool.GetAllResourceKeys(); if (pooledDescriptors != null) { for (int i = 0; i < pooledDescriptors.length; i++) { CacheEventDescriptor pooledDescriptor = (CacheEventDescriptor) ((pooledDescriptors[i] instanceof CacheEventDescriptor) ? pooledDescriptors[i] : null); if (pooledDescriptor != null && pooledDescriptor.getDataFilter().getValue() > maxDataFilter.getValue()) { maxDataFilter = pooledDescriptor.getDataFilter(); } if (maxDataFilter.getValue() == EventDataFilter.DataWithMetadata.getValue()) { break; } } } } discriptor.setIsRegistered(false); switch (type) { case ItemAdded: //Data filter is being updated if (maxDataFilter != _generalAddDataFilter) { _generalAddDataFilter = maxDataFilter; registrationSequenceId = ++_addEventRegistrationSequence; } if (unregisterNotification) { _generalAddDataFilter = EventDataFilter.None; } break; case ItemRemoved: if (maxDataFilter != _generalRemoveDataFilter) { _generalRemoveDataFilter = maxDataFilter; registrationSequenceId = ++_removeEventRegistrationSequenceId; } if (unregisterNotification) { _generalAddDataFilter = EventDataFilter.None; } break; case ItemUpdated: if (maxDataFilter != _generalUpdateDataFilter) { _generalUpdateDataFilter = maxDataFilter; registrationSequenceId = ++_updateEventRegisrationSequenceId; } if (unregisterNotification) { _generalAddDataFilter = EventDataFilter.None; } break; } } if (_cache != null) { if (unregisterNotification) { _cache.removeGeneralCacheNotification(EventUtil.getEventTypeInternal(type)); if(_generalEventsSubscription!=null) { _generalEventsSubscription.unSubscribeEventTopic(); _generalEventsSubscription=null; } } else if (registrationSequenceId != -1) { //only caused update of data filter either upgrade or downgrade _cache.addCacheNotificationDataFilter(EventUtil.getEventTypeInternal(type), maxDataFilter, registrationSequenceId); } } } return null; } public final EventRegistrationInfo[] getEventRegistrationInfo() { java.util.ArrayList registeredEvents = new java.util.ArrayList(); synchronized (getSyncLockGeneral()) { if (_addEventPool != null && _addEventPool.getCount() > 0) { registeredEvents.add(new EventRegistrationInfo(EventType.ItemAdded, _generalAddDataFilter, _addEventRegistrationSequence)); } if (_updateEventPool != null && _updateEventPool.getCount() > 0) { registeredEvents.add(new EventRegistrationInfo(EventType.ItemUpdated, _generalUpdateDataFilter, _updateEventRegisrationSequenceId)); } if (_removeEventPool != null && _removeEventPool.getCount() > 0) { registeredEvents.add(new EventRegistrationInfo(EventType.ItemRemoved, _generalRemoveDataFilter, _removeEventRegistrationSequenceId)); } } return registeredEvents.toArray(new EventRegistrationInfo[0]); } private ResourcePool getEventPool(EventTypeInternal eventType) { ResourcePool pool = null; if (eventType == EventTypeInternal.ItemAdded) { pool = _addEventPool; } else if (eventType == EventTypeInternal.ItemRemoved) { pool = _removeEventPool; } else if (eventType == EventTypeInternal.ItemUpdated) { pool = _updateEventPool; } return pool; } public void raisePollNotification(short callbackId, EventTypeInternal eventType) { try { PollNotificationListener _pollCallback = null; if ((eventType == EventTypeInternal.ClientCache) ) { _pollCallback = _pollClientCacheCallback; } else if ((eventType == EventTypeInternal.PubSub)) { _pollCallback = _pollPubSubCallback; } if (_pollCallback != null) _pollCallback.onPollNotified(); } catch (Exception ex) { if (_logger != null && _logger.getIsErrorEnabled()) _logger.CriticalInfo(ex.getMessage()); } } public short registerPollingEvent(PollNotificationListener pollNotifyListener, EventTypeInternal eventType) { // Only one poll callback can be configured. // No need to use pools. if (eventType == EventTypeInternal.ClientCache) { _pollClientCacheCallback = pollNotifyListener; } else if (eventType == EventTypeInternal.PubSub) { _pollPubSubCallback = pollNotifyListener; } return 10001; } public short[] registerCollectionEvent(DataStructureDataChangeListener dataStructureDataChangeListener, EnumSet enumSet, DataTypeEventDataFilter datafilter) throws CacheException { if (dataStructureDataChangeListener != null) { if (_collectionAddEventPool == null) { _collectionAddEventPool = new ResourcePool(); _collectionAddEventIdPool = new ResourcePool(); } if (_collectionUpdateEventPool == null) { _collectionUpdateEventPool = new ResourcePool(); _collectionUpdateEventIdPool = new ResourcePool(); } if (_collectionRemoveEventPool == null) { _collectionRemoveEventPool = new ResourcePool(); _collectionRemoveEventIdPool = new ResourcePool(); } return registerCollectionDescriptor(dataStructureDataChangeListener, enumSet); } else { return null; } } public short[] UnregisterCollectionNotification(DataStructureDataChangeListener listener, EnumSet enumSet) throws Exception { if (listener == null) { return null; } short[] returnValue = new short[] {-1, -1, -1}; // First value add callback ref & second is update callback ref & third is remove callbackref for (EventTypeInternal type : enumSet) { Object id = -1; synchronized (getSyncLockCollection()) { ResourcePool pool = null; ResourcePool poolID = null; if (type == EventTypeInternal.ItemAdded) { pool = _collectionAddEventPool; poolID = _collectionAddEventIdPool; if (pool == null) { addCallbacks = 0; } } if (type == EventTypeInternal.ItemRemoved) { pool = _collectionRemoveEventPool; poolID = _collectionRemoveEventIdPool; if (pool == null) { removeCallbacks = 0; } } else if (type == EventTypeInternal.ItemUpdated) { pool = _collectionUpdateEventPool; poolID = _collectionUpdateEventIdPool; if (pool == null) { updateCallbacks = 0; } } if (addCallbacks == 0 && removeCallbacks == 0 && updateCallbacks == 0) { _collectionEventsSubscription.unSubscribeEventTopic(); _collectionEventsSubscription = null; } if (pool == null) { continue; } // Taimoor : For selective callback, we dont remove the callback as it can create chaos if user tries to unregister // a callback more then one time or against wrong items. int i = type == EventTypeInternal.ItemAdded ? 0 : (type == EventTypeInternal.ItemUpdated ? 1 : 2); id = pool.GetResource(listener); if (id instanceof Short) { returnValue[i] = (Short)id; } } } return returnValue; } private short[] registerCollectionDescriptor(DataStructureDataChangeListener listener, EnumSet enumSet) throws CacheException { if (listener == null) { return null; } // First value add callback ref & sencond is update callbackref & third is remove callbackref short[] returnValue = new short[] {-1, -1, -1}; for (EventTypeInternal type : enumSet) { synchronized (getSyncLockCollection()) { ResourcePool pool = null; ResourcePool poolId = null; if (type == EventTypeInternal.ItemAdded) { pool = _collectionAddEventPool; poolId = _collectionAddEventIdPool; } else if (type == EventTypeInternal.ItemUpdated) { pool = _collectionUpdateEventPool; poolId = _collectionUpdateEventIdPool; } else if (type == EventTypeInternal.ItemRemoved) { pool = _collectionRemoveEventPool; poolId = _collectionRemoveEventIdPool; } if (pool == null) { continue; } while (true) { int index = type == EventTypeInternal.ItemAdded ? 0 : (type == EventTypeInternal.ItemUpdated ? 1 : 2); if (pool.GetResource(listener) == null) { returnValue[index] = type == EventTypeInternal.ItemAdded ?++_collectionAddCallbackRef : (type == EventTypeInternal.ItemUpdated ?++_collectionUpdateCallbackRef :++_collectionRemoveCallbackRef); pool.AddResource(listener, returnValue[index]); poolId.AddResource(returnValue[index], listener); break; } else { try { short cref = (short)pool.GetResource(listener); if (cref < 0) { break; } // Add it again into the table for updating ref count. pool.AddResource(listener, cref); poolId.AddResource(cref, listener); returnValue[index] = cref; break; } catch (NullPointerException e) { //Legacy code: can create an infinite loop //Recomendation of returning a negative number instead of continue continue; } } } } } if (_collectionEventsSubscription == null) { TopicImpl topic = (TopicImpl)_cache._messagingService.getTopic(TopicConstant.CollectionEventsTopic, true); _collectionEventsSubscription = (TopicSubscriptionImpl)topic.createEventSubscription(collectionEventMessageReceivedListener); } return returnValue; } public short registerSelectiveCallback(CacheItemRemovedListener removedCallback, ListenerType listenerType) throws CacheException { if (removedCallback == null) { return -1; } synchronized (getSyncLockSelective()) { SelectiveRemoveListenerWrapper callbackWrapper = null; if (_oldSelectiveCallbackPool.GetResource(removedCallback) == null) { callbackWrapper = new SelectiveRemoveListenerWrapper(removedCallback); _oldSelectiveCallbackPool.AddResource(removedCallback, callbackWrapper); _oldSelectiveMappingCallbackPool.AddResource(callbackWrapper, removedCallback); } else { callbackWrapper = (SelectiveRemoveListenerWrapper) _oldSelectiveCallbackPool.GetResource(removedCallback); _oldSelectiveCallbackPool.AddResource(removedCallback, callbackWrapper); //just to increment the refCount } short[] callbackIds = registerSelectiveEvent(callbackWrapper.getMappingListener(), EnumSet.of(EventType.ItemRemoved), EventDataFilter.DataWithMetadata, listenerType); return callbackIds[1]; } } public short registerSelectiveCallback(CacheItemUpdatedListener updatedCallback, ListenerType listenerType) throws CacheException { if (updatedCallback == null) { return -1; } synchronized (getSyncLockSelective()) { SelectiveUpdateListenerWrapper callbackWrapper = null; if (_oldSelectiveCallbackPool.GetResource(updatedCallback) == null) { callbackWrapper = new SelectiveUpdateListenerWrapper(updatedCallback); _oldSelectiveCallbackPool.AddResource(updatedCallback, callbackWrapper); _oldSelectiveMappingCallbackPool.AddResource(callbackWrapper, updatedCallback); } else { callbackWrapper = (SelectiveUpdateListenerWrapper) _oldSelectiveCallbackPool.GetResource(updatedCallback); _oldSelectiveCallbackPool.AddResource(updatedCallback, callbackWrapper); //just to increment the refCount } short[] callbackIds = registerSelectiveEvent(callbackWrapper.getMappingListener(), EnumSet.of(EventType.ItemRemoved), EventDataFilter.DataWithMetadata, listenerType); return callbackIds[1]; } } void raiseCollectionNotification(String collectionName, EventTypeInternal eventType, DistributedDataStructure dataType, DataTypeEventDataFilter dataFilter, Object collectionItem, Object oldCollectionItem, boolean _notifyAsync, EventHandle handle) { try { ResourcePool poolID = null; DataStructureEventArg arg = null; if (collectionItem != null) { if (dataType == DistributedDataStructure.Map) { java.util.Map.Entry pair = (java.util.Map.Entry)collectionItem; collectionItem = new AbstractMap.SimpleEntry(pair.getKey(), CollectionUtil.getValueFromJsonValueBase(pair.getValue())); } else { collectionItem = CollectionUtil.getValueFromJsonValueBase((ExtendedJsonValueBase)((collectionItem instanceof ExtendedJsonValueBase) ? collectionItem : null)); } } //collectionItem = CollectionUtil.GetValueFromJsonValueBase(collectionItem as Common.JSON.ExtendedJsonValueBase); if (oldCollectionItem != null) { if (dataType == DistributedDataStructure.Map) { java.util.Map.Entry pair = (java.util.Map.Entry)oldCollectionItem; oldCollectionItem = new AbstractMap.SimpleEntry(pair.getKey(), CollectionUtil.getValueFromJsonValueBase(pair.getValue())); } else { oldCollectionItem = CollectionUtil.getValueFromJsonValueBase((ExtendedJsonValueBase)((oldCollectionItem instanceof ExtendedJsonValueBase) ? oldCollectionItem : null)); } } if ((eventType == EventTypeInternal.ItemAdded)) { poolID = _collectionAddEventIdPool; } else if ((eventType == EventTypeInternal.ItemUpdated)) { poolID = _collectionUpdateEventIdPool; } else if ((eventType == EventTypeInternal.ItemRemoved)) { poolID = _collectionRemoveEventIdPool; } arg = createCollectionEventArgument(collectionName, _cacheName, eventType, dataFilter, dataType, collectionItem, oldCollectionItem); if (poolID == null) { return; } Object tempVar = poolID.GetResource((short)handle.getHandle()); DataStructureDataChangeListener listener = (DataStructureDataChangeListener)((tempVar instanceof DataStructureDataChangeListener) ? tempVar : null); if (listener == null) // Can occur if Unregistered concurrently { return; } if (_notifyAsync) { DataStructureEventArg finalArg = arg; ThreadPool.getInstance().executeTask((new Runnable() { @Override public void run() { listener.onDataStructureChanged(collectionName, finalArg); } })); } else { listener.onDataStructureChanged(collectionName, arg); } } catch (Exception e) { if (_logger != null && _logger.getIsErrorEnabled()) _logger.CriticalInfo(e.toString()); } } private DataStructureEventArg createCollectionEventArgument(String collectionName, String cacheName, EventTypeInternal eventType, DataTypeEventDataFilter dataFilter, DistributedDataStructure dataType, Object collectionItem, Object oldCollectionItem) { Object collectionItemCopy = null; Object oldCollectionItemCopy = null; switch (dataFilter) { case None: collectionItemCopy = null; oldCollectionItemCopy = null; break; case Data: collectionItemCopy = collectionItem; oldCollectionItemCopy = oldCollectionItem; break; } DataStructureEventArg eventArg = null; if (eventType == EventTypeInternal.ItemUpdated) { eventArg = new DataStructureEventArg(cacheName, EventType.ItemUpdated, dataType, collectionItemCopy, oldCollectionItemCopy); } else if (eventType == EventTypeInternal.ItemAdded) { eventArg = new DataStructureEventArg(cacheName, EventType.ItemAdded, dataType, collectionItemCopy, null); } else if (eventType == EventTypeInternal.ItemRemoved) { eventArg = new DataStructureEventArg(cacheName, EventType.ItemRemoved, dataType, collectionItemCopy, null); } return eventArg; } public static class EventRegistrationInfo { private EventType _eventType; private EventDataFilter _filter; private short _registrationSequence; public EventRegistrationInfo() { } public EventRegistrationInfo(EventType eventTYpe, EventDataFilter filter, short sequenceId) { _eventType = eventTYpe; _filter = filter; _registrationSequence = sequenceId; } public final EventType getEventTYpe() { return _eventType; } public final void setEventTYpe(EventType value) { _eventType = value; } public final EventDataFilter getDataFilter() { return _filter; } public final void setDataFilter(EventDataFilter value) { _filter = value; } public final short getRegistrationSequence() { return _registrationSequence; } public final void setRegistrationSequence(short value) { _registrationSequence = value; } } } class SelectiveRemoveListenerWrapper implements CacheDataModificationListener{ private CacheItemRemovedListener _listener; private CacheDataModificationListener _mappingListener; public SelectiveRemoveListenerWrapper(CacheItemRemovedListener listener) { _listener = listener; } public CacheDataModificationListener getMappingListener() { return _mappingListener; } @Override public void onCacheDataModified(String key, CacheEventArg eventArgs) { if (_listener != null) { _listener.itemRemoved(key, eventArgs.getItem().getValue(null), eventArgs.getCacheItemRemovedReason()); } } @Override public void onCacheCleared(String cacheName) { } } class SelectiveUpdateListenerWrapper implements CacheDataModificationListener{ private CacheItemUpdatedListener _listener; private CacheDataModificationListener _mappingListener; public SelectiveUpdateListenerWrapper(CacheItemUpdatedListener listener) { _listener = listener; } public CacheDataModificationListener getMappingListener() { if (_mappingListener == null) { } return _mappingListener; } @Override public void onCacheDataModified(String key, CacheEventArg eventArgs) { if (_listener != null) { _listener.itemUpdated(key); } } @Override public void onCacheCleared(String cacheName) { } }