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.cache.transactional;
016    
017    import com.liferay.portal.kernel.cache.PortalCache;
018    import com.liferay.portal.kernel.util.InitialThreadLocal;
019    import com.liferay.portal.util.PropsValues;
020    
021    import java.io.Serializable;
022    
023    import java.util.ArrayList;
024    import java.util.HashMap;
025    import java.util.List;
026    import java.util.Map;
027    
028    /**
029     * @author Shuyang Zhou
030     */
031    public class TransactionalPortalCacheHelper {
032    
033            public static void begin() {
034                    if (!PropsValues.TRANSACTIONAL_CACHE_ENABLED) {
035                            return;
036                    }
037    
038                    _pushPortalCacheMap();
039            }
040    
041            public static void commit() {
042                    if (!PropsValues.TRANSACTIONAL_CACHE_ENABLED) {
043                            return;
044                    }
045    
046                    PortalCacheMap portalCacheMap = _popPortalCacheMap();
047    
048                    for (Map.Entry
049                                    <PortalCache<? extends Serializable, ?>, UncommittedBuffer>
050                                            portalCacheMapEntry : portalCacheMap.entrySet()) {
051    
052                            PortalCache<Serializable, Object> portalCache =
053                                    (PortalCache<Serializable, Object>)portalCacheMapEntry.getKey();
054    
055                            UncommittedBuffer uncommittedBuffer =
056                                    portalCacheMapEntry.getValue();
057    
058                            uncommittedBuffer.commitTo(portalCache);
059                    }
060    
061                    portalCacheMap.clear();
062            }
063    
064            public static boolean isEnabled() {
065                    if (!PropsValues.TRANSACTIONAL_CACHE_ENABLED) {
066                            return false;
067                    }
068    
069                    List<PortalCacheMap> portalCacheMaps =
070                            _portalCacheMapsThreadLocal.get();
071    
072                    return !portalCacheMaps.isEmpty();
073            }
074    
075            public static void rollback() {
076                    if (!PropsValues.TRANSACTIONAL_CACHE_ENABLED) {
077                            return;
078                    }
079    
080                    PortalCacheMap portalCacheMap = _popPortalCacheMap();
081    
082                    portalCacheMap.clear();
083            }
084    
085            protected static <K extends Serializable, V> V get(
086                    PortalCache<K, V> portalCache, K key) {
087    
088                    PortalCacheMap portalCacheMap = _peekPortalCacheMap();
089    
090                    UncommittedBuffer uncommittedBuffer = portalCacheMap.get(portalCache);
091    
092                    if (uncommittedBuffer == null) {
093                            return null;
094                    }
095    
096                    Object object = uncommittedBuffer.get(key);
097    
098                    if (object instanceof TTLValue) {
099                            TTLValue ttLValue = (TTLValue)object;
100    
101                            object = ttLValue._value;
102                    }
103    
104                    return (V)object;
105            }
106    
107            protected static <K extends Serializable, V> void put(
108                    PortalCache<K, V> portalCache, K key, V value) {
109    
110                    PortalCacheMap portalCacheMap = _peekPortalCacheMap();
111    
112                    UncommittedBuffer uncommittedBuffer = portalCacheMap.get(portalCache);
113    
114                    if (uncommittedBuffer == null) {
115                            uncommittedBuffer = new UncommittedBuffer();
116    
117                            portalCacheMap.put(portalCache, uncommittedBuffer);
118                    }
119    
120                    uncommittedBuffer.put(key, value);
121            }
122    
123            protected static <K extends Serializable, V> void put(
124                    PortalCache<K, V> portalCache, K key, V value, int ttl) {
125    
126                    PortalCacheMap portalCacheMap = _peekPortalCacheMap();
127    
128                    UncommittedBuffer uncommittedBuffer = portalCacheMap.get(portalCache);
129    
130                    if (uncommittedBuffer == null) {
131                            uncommittedBuffer = new UncommittedBuffer();
132    
133                            portalCacheMap.put(portalCache, uncommittedBuffer);
134                    }
135    
136                    uncommittedBuffer.put(key, new TTLValue(ttl, value));
137            }
138    
139            protected static <K extends Serializable, V> void removeAll(
140                    PortalCache<K, V> portalCache) {
141    
142                    PortalCacheMap portalCacheMap = _peekPortalCacheMap();
143    
144                    UncommittedBuffer uncommittedBuffer = portalCacheMap.get(portalCache);
145    
146                    if (uncommittedBuffer == null) {
147                            uncommittedBuffer = new UncommittedBuffer();
148    
149                            portalCacheMap.put(portalCache, uncommittedBuffer);
150                    }
151    
152                    uncommittedBuffer.removeAll();
153            }
154    
155            private static PortalCacheMap _peekPortalCacheMap() {
156                    List<PortalCacheMap> portalCacheMaps =
157                            _portalCacheMapsThreadLocal.get();
158    
159                    return portalCacheMaps.get(portalCacheMaps.size() - 1);
160            }
161    
162            private static PortalCacheMap _popPortalCacheMap() {
163                    List<PortalCacheMap> portalCacheMaps =
164                            _portalCacheMapsThreadLocal.get();
165    
166                    return portalCacheMaps.remove(portalCacheMaps.size() - 1);
167            }
168    
169            private static void _pushPortalCacheMap() {
170                    List<PortalCacheMap> portalCacheMaps =
171                            _portalCacheMapsThreadLocal.get();
172    
173                    portalCacheMaps.add(new PortalCacheMap());
174            }
175    
176            private static ThreadLocal<List<PortalCacheMap>>
177                    _portalCacheMapsThreadLocal =
178                            new InitialThreadLocal<List<PortalCacheMap>>(
179                                    TransactionalPortalCacheHelper.class.getName() +
180                                            "._portalCacheMapsThreadLocal",
181                                    new ArrayList<PortalCacheMap>());
182    
183            private static class PortalCacheMap
184                    extends HashMap
185                            <PortalCache<? extends Serializable, ?>, UncommittedBuffer> {
186            }
187    
188            private static class TTLValue {
189    
190                    public TTLValue(int ttl, Object value) {
191                            _ttl = ttl;
192                            _value = value;
193                    }
194    
195                    private int _ttl;
196                    private Object _value;
197    
198            }
199    
200            private static class UncommittedBuffer {
201    
202                    public void commitTo(PortalCache<Serializable, Object> portalCache) {
203                            if (_removeAll) {
204                                    portalCache.removeAll();
205                            }
206    
207                            for (Map.Entry<? extends Serializable, List<Object>> entry :
208                                            _uncommittedMap.entrySet()) {
209    
210                                    Serializable key = entry.getKey();
211                                    List<Object> valueList = entry.getValue();
212    
213                                    for (Object value : valueList) {
214                                            if (value == TransactionalPortalCache.NULL_HOLDER) {
215                                                    portalCache.remove(key);
216                                            }
217                                            else if (value instanceof TTLValue) {
218                                                    TTLValue ttlValue = (TTLValue)value;
219    
220                                                    portalCache.put(key, ttlValue._value, ttlValue._ttl);
221                                            }
222                                            else {
223                                                    portalCache.put(key, value);
224                                            }
225                                    }
226                            }
227                    }
228    
229                    public Object get(Serializable key) {
230                            List<Object> valueList = _uncommittedMap.get(key);
231    
232                            Object value = null;
233    
234                            if (valueList != null) {
235                                    value = valueList.get(valueList.size() - 1);
236                            }
237    
238                            if ((value == null) && _removeAll) {
239                                    value = TransactionalPortalCache.NULL_HOLDER;
240                            }
241    
242                            return value;
243                    }
244    
245                    public void put(Serializable key, Object value) {
246                            List<Object> valueList = _uncommittedMap.get(key);
247    
248                            if (valueList == null) {
249                                    valueList = new ArrayList<Object>();
250                            }
251    
252                            valueList.add(value);
253    
254                            _uncommittedMap.put(key, valueList);
255                    }
256    
257                    public void removeAll() {
258                            _uncommittedMap.clear();
259    
260                            _removeAll = true;
261                    }
262    
263                    private boolean _removeAll;
264                    private Map<Serializable, List<Object>> _uncommittedMap =
265                            new HashMap<Serializable, List<Object>>();
266    
267            }
268    
269    }