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                    return (V)uncommittedBuffer.get(key);
097            }
098    
099            protected static <K extends Serializable, V> void put(
100                    PortalCache<K, V> portalCache, K key, V value) {
101    
102                    PortalCacheMap portalCacheMap = _peekPortalCacheMap();
103    
104                    UncommittedBuffer uncommittedBuffer = portalCacheMap.get(portalCache);
105    
106                    if (uncommittedBuffer == null) {
107                            uncommittedBuffer = new UncommittedBuffer();
108    
109                            portalCacheMap.put(portalCache, uncommittedBuffer);
110                    }
111    
112                    uncommittedBuffer.put(key, value);
113            }
114    
115            protected static <K extends Serializable, V> void removeAll(
116                    PortalCache<K, V> portalCache) {
117    
118                    PortalCacheMap portalCacheMap = _peekPortalCacheMap();
119    
120                    UncommittedBuffer uncommittedBuffer = portalCacheMap.get(portalCache);
121    
122                    if (uncommittedBuffer == null) {
123                            uncommittedBuffer = new UncommittedBuffer();
124    
125                            portalCacheMap.put(portalCache, uncommittedBuffer);
126                    }
127    
128                    uncommittedBuffer.removeAll();
129            }
130    
131            private static PortalCacheMap _peekPortalCacheMap() {
132                    List<PortalCacheMap> portalCacheMaps =
133                            _portalCacheMapsThreadLocal.get();
134    
135                    return portalCacheMaps.get(portalCacheMaps.size() - 1);
136            }
137    
138            private static PortalCacheMap _popPortalCacheMap() {
139                    List<PortalCacheMap> portalCacheMaps =
140                            _portalCacheMapsThreadLocal.get();
141    
142                    return portalCacheMaps.remove(portalCacheMaps.size() - 1);
143            }
144    
145            private static void _pushPortalCacheMap() {
146                    List<PortalCacheMap> portalCacheMaps =
147                            _portalCacheMapsThreadLocal.get();
148    
149                    portalCacheMaps.add(new PortalCacheMap());
150            }
151    
152            private static ThreadLocal<List<PortalCacheMap>>
153                    _portalCacheMapsThreadLocal =
154                            new InitialThreadLocal<List<PortalCacheMap>>(
155                                    TransactionalPortalCacheHelper.class.getName() +
156                                            "._portalCacheMapsThreadLocal",
157                                    new ArrayList<PortalCacheMap>());
158    
159            private static class PortalCacheMap
160                    extends HashMap
161                            <PortalCache<? extends Serializable, ?>, UncommittedBuffer> {
162            }
163    
164            private static class UncommittedBuffer {
165    
166                    public void commitTo(PortalCache<Serializable, Object> portalCache) {
167                            if (_removeAll) {
168                                    portalCache.removeAll();
169                            }
170    
171                            for (Map.Entry<? extends Serializable, ?> entry :
172                                            _uncommittedMap.entrySet()) {
173    
174                                    Serializable key = entry.getKey();
175                                    Object value = entry.getValue();
176    
177                                    if (value == TransactionalPortalCache.NULL_HOLDER) {
178                                            portalCache.remove(key);
179                                    }
180                                    else {
181                                            portalCache.put(entry.getKey(), entry.getValue());
182                                    }
183                            }
184                    }
185    
186                    public Object get(Serializable key) {
187                            Object value = _uncommittedMap.get(key);
188    
189                            if ((value == null) && _removeAll) {
190                                    value = TransactionalPortalCache.NULL_HOLDER;
191                            }
192    
193                            return value;
194                    }
195    
196                    public void put(Serializable key, Object value) {
197                            _uncommittedMap.put(key, value);
198                    }
199    
200                    public void removeAll() {
201                            _uncommittedMap.clear();
202    
203                            _removeAll = true;
204                    }
205    
206                    private boolean _removeAll;
207                    private Map<Serializable, Object> _uncommittedMap =
208                            new HashMap<Serializable, Object>();
209    
210            }
211    
212    }