001    /**
002     * Copyright (c) 2000-present Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portal.kernel.cache;
016    
017    import com.liferay.portal.kernel.util.InitialThreadLocal;
018    
019    import java.io.Serializable;
020    
021    import java.util.Collections;
022    import java.util.Map;
023    import java.util.concurrent.ConcurrentHashMap;
024    import java.util.concurrent.ConcurrentMap;
025    
026    /**
027     * @author Tina Tian
028     */
029    public class AggregatedCacheListener<K extends Serializable, V>
030            implements CacheListener<K, V> {
031    
032            public static boolean isRemoteInvoke() {
033                    return _remoteInvokeThreadLocal.get();
034            }
035    
036            public static void setRemoteInvoke(boolean remoteInvoke) {
037                    _remoteInvokeThreadLocal.set(remoteInvoke);
038            }
039    
040            public void addCacheListener(CacheListener<K, V> cacheListener) {
041                    addCacheListener(cacheListener, CacheListenerScope.ALL);
042            }
043    
044            public void addCacheListener(
045                    CacheListener<K, V> cacheListener,
046                    CacheListenerScope cacheListenerScope) {
047    
048                    _cacheListeners.putIfAbsent(cacheListener, cacheListenerScope);
049            }
050    
051            public void clearAll() {
052                    dispose();
053    
054                    _cacheListeners.clear();
055            }
056    
057            @Override
058            public void dispose() {
059                    for (CacheListener<K, V> cacheListener : _cacheListeners.keySet()) {
060                            cacheListener.dispose();
061                    }
062            }
063    
064            public Map<CacheListener<K, V>, CacheListenerScope> getCacheListeners() {
065                    return Collections.unmodifiableMap(_cacheListeners);
066            }
067    
068            public boolean isEmpty() {
069                    return _cacheListeners.isEmpty();
070            }
071    
072            @Override
073            public void notifyEntryEvicted(
074                            PortalCache<K, V> portalCache, K key, V value, int timeToLive)
075                    throws PortalCacheException {
076    
077                    for (Map.Entry<CacheListener<K, V>, CacheListenerScope> entry :
078                                    _cacheListeners.entrySet()) {
079    
080                            CacheListener<K, V> cacheListener = entry.getKey();
081    
082                            if (_shouldDeliver(cacheListener, entry.getValue())) {
083                                    cacheListener.notifyEntryEvicted(
084                                            portalCache, key, value, timeToLive);
085                            }
086                    }
087            }
088    
089            @Override
090            public void notifyEntryExpired(
091                            PortalCache<K, V> portalCache, K key, V value, int timeToLive)
092                    throws PortalCacheException {
093    
094                    for (Map.Entry<CacheListener<K, V>, CacheListenerScope> entry :
095                                    _cacheListeners.entrySet()) {
096    
097                            CacheListener<K, V> cacheListener = entry.getKey();
098    
099                            if (_shouldDeliver(cacheListener, entry.getValue())) {
100                                    cacheListener.notifyEntryExpired(
101                                            portalCache, key, value, timeToLive);
102                            }
103                    }
104            }
105    
106            @Override
107            public void notifyEntryPut(
108                            PortalCache<K, V> portalCache, K key, V value, int timeToLive)
109                    throws PortalCacheException {
110    
111                    for (Map.Entry<CacheListener<K, V>, CacheListenerScope> entry :
112                                    _cacheListeners.entrySet()) {
113    
114                            CacheListener<K, V> cacheListener = entry.getKey();
115    
116                            if (_shouldDeliver(cacheListener, entry.getValue())) {
117                                    cacheListener.notifyEntryPut(
118                                            portalCache, key, value, timeToLive);
119                            }
120                    }
121            }
122    
123            @Override
124            public void notifyEntryRemoved(
125                            PortalCache<K, V> portalCache, K key, V value, int timeToLive)
126                    throws PortalCacheException {
127    
128                    for (Map.Entry<CacheListener<K, V>, CacheListenerScope> entry :
129                                    _cacheListeners.entrySet()) {
130    
131                            CacheListener<K, V> cacheListener = entry.getKey();
132    
133                            if (_shouldDeliver(cacheListener, entry.getValue())) {
134                                    cacheListener.notifyEntryRemoved(
135                                            portalCache, key, value, timeToLive);
136                            }
137                    }
138            }
139    
140            @Override
141            public void notifyEntryUpdated(
142                            PortalCache<K, V> portalCache, K key, V value, int timeToLive)
143                    throws PortalCacheException {
144    
145                    for (Map.Entry<CacheListener<K, V>, CacheListenerScope> entry :
146                                    _cacheListeners.entrySet()) {
147    
148                            CacheListener<K, V> cacheListener = entry.getKey();
149    
150                            if (_shouldDeliver(cacheListener, entry.getValue())) {
151                                    cacheListener.notifyEntryUpdated(
152                                            portalCache, key, value, timeToLive);
153                            }
154                    }
155            }
156    
157            @Override
158            public void notifyRemoveAll(PortalCache<K, V> portalCache)
159                    throws PortalCacheException {
160    
161                    for (Map.Entry<CacheListener<K, V>, CacheListenerScope> entry :
162                                    _cacheListeners.entrySet()) {
163    
164                            CacheListener<K, V> cacheListener = entry.getKey();
165    
166                            if (_shouldDeliver(cacheListener, entry.getValue())) {
167                                    cacheListener.notifyRemoveAll(portalCache);
168                            }
169                    }
170            }
171    
172            public void removeCacheListener(CacheListener<K, V> cacheListener) {
173                    cacheListener.dispose();
174    
175                    _cacheListeners.remove(cacheListener);
176            }
177    
178            private boolean _shouldDeliver(
179                    CacheListener<K, V> cacheListener,
180                    CacheListenerScope cacheListenerScope) {
181    
182                    if (_remoteInvokeThreadLocal.get()) {
183                            if (cacheListener instanceof CacheReplicator) {
184                                    return false;
185                            }
186    
187                            if (cacheListenerScope.equals(CacheListenerScope.ALL) ||
188                                    cacheListenerScope.equals(CacheListenerScope.REMOTE)) {
189    
190                                    return true;
191                            }
192    
193                            return false;
194                    }
195    
196                    if (cacheListenerScope.equals(CacheListenerScope.ALL) ||
197                            cacheListenerScope.equals(CacheListenerScope.LOCAL)) {
198    
199                            return true;
200                    }
201    
202                    return false;
203            }
204    
205            private static final ThreadLocal<Boolean> _remoteInvokeThreadLocal =
206                    new InitialThreadLocal<>(
207                            AggregatedCacheListener.class + "._remoteInvokeThreadLocal", false);
208    
209            private final ConcurrentMap<CacheListener<K, V>, CacheListenerScope>
210                    _cacheListeners = new ConcurrentHashMap<>();
211    
212    }