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                    Map<PortalCache, UncommittedBuffer> portalCacheMap =
047                            _popPortalCacheMap();
048    
049                    for (Map.Entry<PortalCache, UncommittedBuffer>
050                                    portalCacheMapEntry : portalCacheMap.entrySet()) {
051    
052                            PortalCache portalCache = portalCacheMapEntry.getKey();
053    
054                            UncommittedBuffer uncommittedBuffer =
055                                    portalCacheMapEntry.getValue();
056    
057                            uncommittedBuffer.commitTo(portalCache);
058                    }
059    
060                    portalCacheMap.clear();
061            }
062    
063            public static boolean isEnabled() {
064                    if (!PropsValues.TRANSACTIONAL_CACHE_ENABLED) {
065                            return false;
066                    }
067    
068                    List<Map<PortalCache, UncommittedBuffer>> portalCacheList =
069                            _portalCacheListThreadLocal.get();
070    
071                    return !portalCacheList.isEmpty();
072            }
073    
074            public static void rollback() {
075                    if (!PropsValues.TRANSACTIONAL_CACHE_ENABLED) {
076                            return;
077                    }
078    
079                    Map<PortalCache, UncommittedBuffer> portalCacheMap =
080                            _popPortalCacheMap();
081    
082                    portalCacheMap.clear();
083            }
084    
085            protected static Object get(PortalCache portalCache, Serializable key) {
086                    Map<PortalCache, UncommittedBuffer> portalCacheMap =
087                            _peekPortalCacheMap();
088    
089                    UncommittedBuffer uncommittedBuffer = portalCacheMap.get(portalCache);
090    
091                    if (uncommittedBuffer == null) {
092                            return null;
093                    }
094    
095                    return uncommittedBuffer.get(key);
096            }
097    
098            protected static void put(
099                    PortalCache portalCache, Serializable key, Object value) {
100    
101                    Map<PortalCache, UncommittedBuffer> portalCacheMap =
102                            _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 void removeAll(PortalCache portalCache) {
116                    Map<PortalCache, UncommittedBuffer> portalCacheMap =
117                            _peekPortalCacheMap();
118    
119                    UncommittedBuffer uncommittedBuffer = portalCacheMap.get(portalCache);
120    
121                    if (uncommittedBuffer == null) {
122                            uncommittedBuffer = new UncommittedBuffer();
123    
124                            portalCacheMap.put(portalCache, uncommittedBuffer);
125                    }
126    
127                    uncommittedBuffer.removeAll();
128            }
129    
130            private static Map<PortalCache, UncommittedBuffer>
131                    _peekPortalCacheMap() {
132    
133                    List<Map<PortalCache, UncommittedBuffer>> portalCacheList =
134                            _portalCacheListThreadLocal.get();
135    
136                    return portalCacheList.get(portalCacheList.size() - 1);
137            }
138    
139            private static Map<PortalCache, UncommittedBuffer>
140                    _popPortalCacheMap() {
141    
142                    List<Map<PortalCache, UncommittedBuffer>> portalCacheList =
143                            _portalCacheListThreadLocal.get();
144    
145                    return portalCacheList.remove(portalCacheList.size() - 1);
146            }
147    
148            private static void _pushPortalCacheMap() {
149                    List<Map<PortalCache, UncommittedBuffer>> portalCacheList =
150                            _portalCacheListThreadLocal.get();
151    
152                    portalCacheList.add(new HashMap<PortalCache, UncommittedBuffer>());
153            }
154    
155            private static ThreadLocal<List<Map<PortalCache, UncommittedBuffer>>>
156                    _portalCacheListThreadLocal = new InitialThreadLocal
157                            <List<Map<PortalCache, UncommittedBuffer>>>(
158                                    TransactionalPortalCacheHelper.class.getName() +
159                                            "._portalCacheListThreadLocal",
160                                    new ArrayList<Map<PortalCache, UncommittedBuffer>>());
161    
162            private static class UncommittedBuffer {
163    
164                    public void commitTo(PortalCache portalCache) {
165                            if (_removeAll) {
166                                    portalCache.removeAll();
167                            }
168    
169                            for (Map.Entry<? extends Serializable, ?> entry :
170                                            _uncommittedMap.entrySet()) {
171    
172                                    Serializable key = entry.getKey();
173                                    Object value = entry.getValue();
174    
175                                    if (value == TransactionalPortalCache.NULL_HOLDER) {
176                                            portalCache.remove(key);
177                                    }
178                                    else {
179                                            portalCache.put(entry.getKey(), entry.getValue());
180                                    }
181                            }
182                    }
183    
184                    public Object get(Serializable key) {
185                            Object value = _uncommittedMap.get(key);
186    
187                            if ((value == null) && _removeAll) {
188                                    value = TransactionalPortalCache.NULL_HOLDER;
189                            }
190    
191                            return value;
192                    }
193    
194                    public void put(Serializable key, Object value) {
195                            _uncommittedMap.put(key, value);
196                    }
197    
198                    public void removeAll() {
199                            _uncommittedMap.clear();
200    
201                            _removeAll = true;
202                    }
203    
204                    private boolean _removeAll;
205                    private Map<Serializable, Object> _uncommittedMap =
206                            new HashMap<Serializable, Object>();
207    
208            }
209    
210    }