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                    _cacheListeners.clear();
053            }
054    
055            public Map<CacheListener<K, V>, CacheListenerScope> getCacheListeners() {
056                    return Collections.unmodifiableMap(_cacheListeners);
057            }
058    
059            @Override
060            public void notifyEntryEvicted(
061                            PortalCache<K, V> portalCache, K key, V value, int timeToLive)
062                    throws PortalCacheException {
063    
064                    for (Map.Entry<CacheListener<K, V>, CacheListenerScope> entry :
065                                    _cacheListeners.entrySet()) {
066    
067                            CacheListener<K, V> cacheListener = entry.getKey();
068    
069                            if (_shouldDeliver(cacheListener, entry.getValue())) {
070                                    cacheListener.notifyEntryEvicted(
071                                            portalCache, key, value, timeToLive);
072                            }
073                    }
074            }
075    
076            @Override
077            public void notifyEntryExpired(
078                            PortalCache<K, V> portalCache, K key, V value, int timeToLive)
079                    throws PortalCacheException {
080    
081                    for (Map.Entry<CacheListener<K, V>, CacheListenerScope> entry :
082                                    _cacheListeners.entrySet()) {
083    
084                            CacheListener<K, V> cacheListener = entry.getKey();
085    
086                            if (_shouldDeliver(cacheListener, entry.getValue())) {
087                                    cacheListener.notifyEntryExpired(
088                                            portalCache, key, value, timeToLive);
089                            }
090                    }
091            }
092    
093            @Override
094            public void notifyEntryPut(
095                            PortalCache<K, V> portalCache, K key, V value, int timeToLive)
096                    throws PortalCacheException {
097    
098                    for (Map.Entry<CacheListener<K, V>, CacheListenerScope> entry :
099                                    _cacheListeners.entrySet()) {
100    
101                            CacheListener<K, V> cacheListener = entry.getKey();
102    
103                            if (_shouldDeliver(cacheListener, entry.getValue())) {
104                                    cacheListener.notifyEntryPut(
105                                            portalCache, key, value, timeToLive);
106                            }
107                    }
108            }
109    
110            @Override
111            public void notifyEntryRemoved(
112                            PortalCache<K, V> portalCache, K key, V value, int timeToLive)
113                    throws PortalCacheException {
114    
115                    for (Map.Entry<CacheListener<K, V>, CacheListenerScope> entry :
116                                    _cacheListeners.entrySet()) {
117    
118                            CacheListener<K, V> cacheListener = entry.getKey();
119    
120                            if (_shouldDeliver(cacheListener, entry.getValue())) {
121                                    cacheListener.notifyEntryRemoved(
122                                            portalCache, key, value, timeToLive);
123                            }
124                    }
125            }
126    
127            @Override
128            public void notifyEntryUpdated(
129                            PortalCache<K, V> portalCache, K key, V value, int timeToLive)
130                    throws PortalCacheException {
131    
132                    for (Map.Entry<CacheListener<K, V>, CacheListenerScope> entry :
133                                    _cacheListeners.entrySet()) {
134    
135                            CacheListener<K, V> cacheListener = entry.getKey();
136    
137                            if (_shouldDeliver(cacheListener, entry.getValue())) {
138                                    cacheListener.notifyEntryUpdated(
139                                            portalCache, key, value, timeToLive);
140                            }
141                    }
142            }
143    
144            @Override
145            public void notifyRemoveAll(PortalCache<K, V> portalCache)
146                    throws PortalCacheException {
147    
148                    for (Map.Entry<CacheListener<K, V>, CacheListenerScope> entry :
149                                    _cacheListeners.entrySet()) {
150    
151                            CacheListener<K, V> cacheListener = entry.getKey();
152    
153                            if (_shouldDeliver(cacheListener, entry.getValue())) {
154                                    cacheListener.notifyRemoveAll(portalCache);
155                            }
156                    }
157            }
158    
159            public void removeCacheListener(CacheListener<K, V> cacheListener) {
160                    _cacheListeners.remove(cacheListener);
161            }
162    
163            private boolean _shouldDeliver(
164                    CacheListener<K, V> cacheListener,
165                    CacheListenerScope cacheListenerScope) {
166    
167                    if (_remoteInvokeThreadLocal.get()) {
168                            if (cacheListener instanceof CacheReplicator) {
169                                    return false;
170                            }
171    
172                            if (cacheListenerScope.equals(CacheListenerScope.ALL) ||
173                                    cacheListenerScope.equals(CacheListenerScope.REMOTE)) {
174    
175                                    return true;
176                            }
177    
178                            return false;
179                    }
180    
181                    if (cacheListenerScope.equals(CacheListenerScope.ALL) ||
182                            cacheListenerScope.equals(CacheListenerScope.LOCAL)) {
183    
184                            return true;
185                    }
186    
187                    return false;
188            }
189    
190            private static final ThreadLocal<Boolean> _remoteInvokeThreadLocal =
191                    new InitialThreadLocal<Boolean>(
192                            AggregatedCacheListener.class + "._remoteInvokeThreadLocal", false);
193    
194            private final ConcurrentMap<CacheListener<K, V>, CacheListenerScope>
195                    _cacheListeners =
196                            new ConcurrentHashMap<CacheListener<K, V>, CacheListenerScope>();
197    
198    }