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