001    /**
002     * Copyright (c) 2000-2013 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.concurrent.CompeteLatch;
018    
019    import java.io.Serializable;
020    
021    import java.util.Collection;
022    import java.util.concurrent.ConcurrentHashMap;
023    import java.util.concurrent.ConcurrentMap;
024    
025    /**
026     * @author Shuyang Zhou
027     */
028    public class BlockingPortalCache<K extends Serializable, V>
029            implements PortalCache<K, V> {
030    
031            public BlockingPortalCache(PortalCache<K, V> portalCache) {
032                    _portalCache = portalCache;
033            }
034    
035            @Override
036            public void destroy() {
037            }
038    
039            @Override
040            public Collection<V> get(Collection<K> keys) {
041                    return _portalCache.get(keys);
042            }
043    
044            @Override
045            public V get(K key) {
046                    V value = _portalCache.get(key);
047    
048                    if (value != null) {
049                            return value;
050                    }
051    
052                    CompeteLatch lastCompeteLatch = _competeLatch.get();
053    
054                    if (lastCompeteLatch != null) {
055                            lastCompeteLatch.done();
056    
057                            _competeLatch.set(null);
058                    }
059    
060                    CompeteLatch currentCompeteLatch = _competeLatchMap.get(key);
061    
062                    if (currentCompeteLatch == null) {
063                            CompeteLatch newCompeteLatch = new CompeteLatch();
064    
065                            currentCompeteLatch = _competeLatchMap.putIfAbsent(
066                                    key, newCompeteLatch);
067    
068                            if (currentCompeteLatch == null) {
069                                    currentCompeteLatch = newCompeteLatch;
070                            }
071                    }
072    
073                    _competeLatch.set(currentCompeteLatch);
074    
075                    if (!currentCompeteLatch.compete()) {
076                            try {
077                                    currentCompeteLatch.await();
078                            }
079                            catch (InterruptedException ie) {
080                            }
081    
082                            _competeLatch.set(null);
083    
084                            value = _portalCache.get(key);
085                    }
086    
087                    return value;
088            }
089    
090            @Override
091            public String getName() {
092                    return _portalCache.getName();
093            }
094    
095            @Override
096            public void put(K key, V value) {
097                    if (key == null) {
098                            throw new IllegalArgumentException("Key is null");
099                    }
100    
101                    if (value == null) {
102                            throw new IllegalArgumentException("Value is null");
103                    }
104    
105                    _portalCache.put(key, value);
106    
107                    CompeteLatch competeLatch = _competeLatch.get();
108    
109                    if (competeLatch != null) {
110                            competeLatch.done();
111    
112                            _competeLatch.set(null);
113                    }
114    
115                    _competeLatchMap.remove(key);
116            }
117    
118            @Override
119            public void put(K key, V value, int timeToLive) {
120                    if (key == null) {
121                            throw new IllegalArgumentException("Key is null");
122                    }
123    
124                    if (value == null) {
125                            throw new IllegalArgumentException("Value is null");
126                    }
127    
128                    _portalCache.put(key, value, timeToLive);
129    
130                    CompeteLatch competeLatch = _competeLatch.get();
131    
132                    if (competeLatch != null) {
133                            competeLatch.done();
134    
135                            _competeLatch.set(null);
136                    }
137    
138                    _competeLatchMap.remove(key);
139            }
140    
141            @Override
142            public void registerCacheListener(CacheListener<K, V> cacheListener) {
143                    _portalCache.registerCacheListener(cacheListener);
144            }
145    
146            @Override
147            public void registerCacheListener(
148                    CacheListener<K, V> cacheListener,
149                    CacheListenerScope cacheListenerScope) {
150    
151                    _portalCache.registerCacheListener(cacheListener, cacheListenerScope);
152            }
153    
154            @Override
155            public void remove(K key) {
156                    _portalCache.remove(key);
157    
158                    CompeteLatch competeLatch = _competeLatchMap.remove(key);
159    
160                    if (competeLatch != null) {
161                            competeLatch.done();
162                    }
163            }
164    
165            @Override
166            public void removeAll() {
167                    _portalCache.removeAll();
168                    _competeLatchMap.clear();
169            }
170    
171            @Override
172            public void unregisterCacheListener(CacheListener<K, V> cacheListener) {
173                    _portalCache.unregisterCacheListener(cacheListener);
174            }
175    
176            @Override
177            public void unregisterCacheListeners() {
178                    _portalCache.unregisterCacheListeners();
179            }
180    
181            private static ThreadLocal<CompeteLatch> _competeLatch =
182                    new ThreadLocal<CompeteLatch>();
183    
184            private final ConcurrentMap<K, CompeteLatch> _competeLatchMap =
185                    new ConcurrentHashMap<K, CompeteLatch>();
186            private final PortalCache<K, V> _portalCache;
187    
188    }