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