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