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