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