001
014
015 package com.liferay.portal.dao.orm.common;
016
017 import com.liferay.portal.cache.mvcc.MVCCPortalCacheFactory;
018 import com.liferay.portal.kernel.cache.CacheManagerListener;
019 import com.liferay.portal.kernel.cache.CacheRegistryItem;
020 import com.liferay.portal.kernel.cache.CacheRegistryUtil;
021 import com.liferay.portal.kernel.cache.MultiVMPool;
022 import com.liferay.portal.kernel.cache.PortalCache;
023 import com.liferay.portal.kernel.cache.PortalCacheHelperUtil;
024 import com.liferay.portal.kernel.cache.PortalCacheManager;
025 import com.liferay.portal.kernel.dao.orm.EntityCache;
026 import com.liferay.portal.kernel.dao.orm.Session;
027 import com.liferay.portal.kernel.dao.orm.SessionFactory;
028 import com.liferay.portal.kernel.dao.shard.ShardUtil;
029 import com.liferay.portal.kernel.log.Log;
030 import com.liferay.portal.kernel.log.LogFactoryUtil;
031 import com.liferay.portal.kernel.security.pacl.DoPrivileged;
032 import com.liferay.portal.kernel.util.AutoResetThreadLocal;
033 import com.liferay.portal.kernel.util.HashUtil;
034 import com.liferay.portal.kernel.util.StringPool;
035 import com.liferay.portal.model.BaseModel;
036 import com.liferay.portal.model.CacheModel;
037 import com.liferay.portal.model.MVCCModel;
038 import com.liferay.portal.util.PropsValues;
039
040 import java.io.Externalizable;
041 import java.io.IOException;
042 import java.io.ObjectInput;
043 import java.io.ObjectOutput;
044 import java.io.Serializable;
045
046 import java.util.Map;
047 import java.util.concurrent.ConcurrentHashMap;
048 import java.util.concurrent.ConcurrentMap;
049
050 import org.apache.commons.collections.map.LRUMap;
051
052
056 @DoPrivileged
057 public class EntityCacheImpl
058 implements CacheManagerListener, CacheRegistryItem, EntityCache {
059
060 public static final String CACHE_NAME = EntityCache.class.getName();
061
062 public void afterPropertiesSet() {
063 CacheRegistryUtil.register(this);
064 }
065
066 @Override
067 public void clearCache() {
068 clearLocalCache();
069
070 for (PortalCache<?, ?> portalCache : _portalCaches.values()) {
071 portalCache.removeAll();
072 }
073 }
074
075 @Override
076 public void clearCache(Class<?> clazz) {
077 clearLocalCache();
078
079 PortalCache<?, ?> portalCache = _getPortalCache(clazz, true);
080
081 if (portalCache != null) {
082 portalCache.removeAll();
083 }
084 }
085
086 @Override
087 public void clearLocalCache() {
088 if (_LOCAL_CACHE_AVAILABLE) {
089 _localCache.remove();
090 }
091 }
092
093 @Override
094 public void dispose() {
095 _portalCaches.clear();
096 }
097
098 @Override
099 public PortalCache<Serializable, Serializable> getPortalCache(
100 Class<?> clazz) {
101
102 return _getPortalCache(clazz, true);
103 }
104
105 @Override
106 public String getRegistryName() {
107 return CACHE_NAME;
108 }
109
110 @Override
111 public Serializable getResult(
112 boolean entityCacheEnabled, Class<?> clazz, Serializable primaryKey) {
113
114 if (!PropsValues.VALUE_OBJECT_ENTITY_CACHE_ENABLED ||
115 !entityCacheEnabled || !CacheRegistryUtil.isActive()) {
116
117 return null;
118 }
119
120 Serializable result = null;
121
122 Map<Serializable, Serializable> localCache = null;
123
124 Serializable localCacheKey = null;
125
126 if (_LOCAL_CACHE_AVAILABLE) {
127 localCache = _localCache.get();
128
129 localCacheKey = _encodeLocalCacheKey(clazz, primaryKey);
130
131 result = localCache.get(localCacheKey);
132 }
133
134 if (result == null) {
135 PortalCache<Serializable, Serializable> portalCache =
136 _getPortalCache(clazz, true);
137
138 Serializable cacheKey = _encodeCacheKey(primaryKey);
139
140 result = portalCache.get(cacheKey);
141
142 if (result == null) {
143 result = StringPool.BLANK;
144 }
145
146 if (_LOCAL_CACHE_AVAILABLE) {
147 localCache.put(localCacheKey, result);
148 }
149 }
150
151 return _toEntityModel(result);
152 }
153
154 @Override
155 public void init() {
156 }
157
158 @Override
159 public void invalidate() {
160 clearCache();
161 }
162
163 @Override
164 public Serializable loadResult(
165 boolean entityCacheEnabled, Class<?> clazz, Serializable primaryKey,
166 SessionFactory sessionFactory) {
167
168 if (!PropsValues.VALUE_OBJECT_ENTITY_CACHE_ENABLED ||
169 !entityCacheEnabled || !CacheRegistryUtil.isActive()) {
170
171 Session session = null;
172
173 try {
174 session = sessionFactory.openSession();
175
176 return (Serializable)session.load(clazz, primaryKey);
177 }
178 finally {
179 sessionFactory.closeSession(session);
180 }
181 }
182
183 Serializable result = null;
184
185 Map<Serializable, Serializable> localCache = null;
186
187 Serializable localCacheKey = null;
188
189 if (_LOCAL_CACHE_AVAILABLE) {
190 localCache = _localCache.get();
191
192 localCacheKey = _encodeLocalCacheKey(clazz, primaryKey);
193
194 result = localCache.get(localCacheKey);
195 }
196
197 Serializable loadResult = null;
198
199 if (result == null) {
200 PortalCache<Serializable, Serializable> portalCache =
201 _getPortalCache(clazz, true);
202
203 Serializable cacheKey = _encodeCacheKey(primaryKey);
204
205 result = portalCache.get(cacheKey);
206
207 if (result == null) {
208 if (_log.isDebugEnabled()) {
209 _log.debug(
210 "Load " + clazz + " " + primaryKey + " from session");
211 }
212
213 Session session = null;
214
215 try {
216 session = sessionFactory.openSession();
217
218 loadResult = (Serializable)session.load(clazz, primaryKey);
219 }
220 finally {
221 if (loadResult == null) {
222 result = StringPool.BLANK;
223 }
224 else {
225 result = ((BaseModel<?>)loadResult).toCacheModel();
226 }
227
228 PortalCacheHelperUtil.putWithoutReplicator(
229 portalCache, cacheKey, result);
230
231 sessionFactory.closeSession(session);
232 }
233 }
234
235 if (_LOCAL_CACHE_AVAILABLE) {
236 localCache.put(localCacheKey, result);
237 }
238 }
239
240 if (loadResult != null) {
241 return loadResult;
242 }
243
244 return _toEntityModel(result);
245 }
246
247 @Override
248 public void notifyCacheAdded(String portalCacheName) {
249 }
250
251 @Override
252 public void notifyCacheRemoved(String portalCacheName) {
253 _portalCaches.remove(portalCacheName);
254 }
255
256 @Override
257 public void putResult(
258 boolean entityCacheEnabled, Class<?> clazz, Serializable primaryKey,
259 Serializable result) {
260
261 putResult(entityCacheEnabled, clazz, primaryKey, result, true);
262 }
263
264 @Override
265 public void putResult(
266 boolean entityCacheEnabled, Class<?> clazz, Serializable primaryKey,
267 Serializable result, boolean quiet) {
268
269 if (!PropsValues.VALUE_OBJECT_ENTITY_CACHE_ENABLED ||
270 !entityCacheEnabled || !CacheRegistryUtil.isActive() ||
271 (result == null)) {
272
273 return;
274 }
275
276 result = ((BaseModel<?>)result).toCacheModel();
277
278 if (_LOCAL_CACHE_AVAILABLE) {
279 Map<Serializable, Serializable> localCache = _localCache.get();
280
281 Serializable localCacheKey = _encodeLocalCacheKey(
282 clazz, primaryKey);
283
284 localCache.put(localCacheKey, result);
285 }
286
287 PortalCache<Serializable, Serializable> portalCache = _getPortalCache(
288 clazz, true);
289
290 Serializable cacheKey = _encodeCacheKey(primaryKey);
291
292 if (quiet) {
293 PortalCacheHelperUtil.putWithoutReplicator(
294 portalCache, cacheKey, result);
295 }
296 else {
297 portalCache.put(cacheKey, result);
298 }
299 }
300
301 @Override
302 public void removeCache(String className) {
303 _portalCaches.remove(className);
304
305 String groupKey = _GROUP_KEY_PREFIX.concat(className);
306
307 _multiVMPool.removeCache(groupKey);
308 }
309
310 @Override
311 public void removeResult(
312 boolean entityCacheEnabled, Class<?> clazz, Serializable primaryKey) {
313
314 if (!PropsValues.VALUE_OBJECT_ENTITY_CACHE_ENABLED ||
315 !entityCacheEnabled || !CacheRegistryUtil.isActive()) {
316
317 return;
318 }
319
320 if (_LOCAL_CACHE_AVAILABLE) {
321 Map<Serializable, Serializable> localCache = _localCache.get();
322
323 Serializable localCacheKey = _encodeLocalCacheKey(
324 clazz, primaryKey);
325
326 localCache.remove(localCacheKey);
327 }
328
329 PortalCache<Serializable, Serializable> portalCache = _getPortalCache(
330 clazz, true);
331
332 Serializable cacheKey = _encodeCacheKey(primaryKey);
333
334 portalCache.remove(cacheKey);
335 }
336
337 public void setMultiVMPool(MultiVMPool multiVMPool) {
338 _multiVMPool = multiVMPool;
339
340 PortalCacheManager<? extends Serializable, ? extends Serializable>
341 portalCacheManager = _multiVMPool.getCacheManager();
342
343 portalCacheManager.registerCacheManagerListener(this);
344 }
345
346 private Serializable _encodeCacheKey(Serializable primaryKey) {
347 if (ShardUtil.isEnabled()) {
348 return new CacheKey(ShardUtil.getCurrentShardName(), primaryKey);
349 }
350
351 return primaryKey;
352 }
353
354 private Serializable _encodeLocalCacheKey(
355 Class<?> clazz, Serializable primaryKey) {
356
357 if (ShardUtil.isEnabled()) {
358 return new ShardLocalCacheKey(
359 ShardUtil.getCurrentShardName(), clazz.getName(), primaryKey);
360 }
361
362 return new LocalCacheKey(clazz.getName(), primaryKey);
363 }
364
365 private PortalCache<Serializable, Serializable> _getPortalCache(
366 Class<?> clazz, boolean createIfAbsent) {
367
368 String className = clazz.getName();
369
370 PortalCache<Serializable, Serializable> portalCache = _portalCaches.get(
371 className);
372
373 if ((portalCache == null) && createIfAbsent) {
374 String groupKey = _GROUP_KEY_PREFIX.concat(className);
375
376 portalCache =
377 (PortalCache<Serializable, Serializable>)_multiVMPool.getCache(
378 groupKey, PropsValues.VALUE_OBJECT_ENTITY_BLOCKING_CACHE);
379
380 if (PropsValues.VALUE_OBJECT_MVCC_ENTITY_CACHE_ENABLED &&
381 MVCCModel.class.isAssignableFrom(clazz)) {
382
383 portalCache =
384 (PortalCache<Serializable, Serializable>)
385 MVCCPortalCacheFactory.createMVCCEhcachePortalCache(
386 portalCache);
387 }
388
389 PortalCache<Serializable, Serializable> previousPortalCache =
390 _portalCaches.putIfAbsent(className, portalCache);
391
392 if (previousPortalCache != null) {
393 portalCache = previousPortalCache;
394 }
395 }
396
397 return portalCache;
398 }
399
400 private Serializable _toEntityModel(Serializable result) {
401 if (result == StringPool.BLANK) {
402 return null;
403 }
404
405 CacheModel<?> cacheModel = (CacheModel<?>)result;
406
407 BaseModel<?> entityModel = (BaseModel<?>)cacheModel.toEntityModel();
408
409 entityModel.setCachedModel(true);
410
411 return entityModel;
412 }
413
414 private static final String _GROUP_KEY_PREFIX = CACHE_NAME.concat(
415 StringPool.PERIOD);
416
417 private static final boolean _LOCAL_CACHE_AVAILABLE;
418
419 private static final Log _log = LogFactoryUtil.getLog(
420 EntityCacheImpl.class);
421
422 private static final ThreadLocal<LRUMap> _localCache;
423
424 static {
425 if (PropsValues.VALUE_OBJECT_ENTITY_THREAD_LOCAL_CACHE_MAX_SIZE > 0) {
426 _LOCAL_CACHE_AVAILABLE = true;
427
428 _localCache = new AutoResetThreadLocal<LRUMap>(
429 EntityCacheImpl.class + "._localCache",
430 new LRUMap(
431 PropsValues.
432 VALUE_OBJECT_ENTITY_THREAD_LOCAL_CACHE_MAX_SIZE));
433 }
434 else {
435 _LOCAL_CACHE_AVAILABLE = false;
436
437 _localCache = null;
438 }
439 }
440
441 private MultiVMPool _multiVMPool;
442 private final ConcurrentMap<String, PortalCache<Serializable, Serializable>>
443 _portalCaches = new ConcurrentHashMap<>();
444
445 private static class CacheKey implements Externalizable {
446
447 public CacheKey() {
448 }
449
450 public CacheKey(String shardName, Serializable primaryKey) {
451 _shardName = shardName;
452 _primaryKey = primaryKey;
453 }
454
455 @Override
456 public boolean equals(Object obj) {
457 CacheKey cacheKey = (CacheKey)obj;
458
459 if (cacheKey._shardName.equals(_shardName) &&
460 cacheKey._primaryKey.equals(_primaryKey)) {
461
462 return true;
463 }
464
465 return false;
466 }
467
468 @Override
469 public int hashCode() {
470 return _shardName.hashCode() * 11 + _primaryKey.hashCode();
471 }
472
473 @Override
474 public void readExternal(ObjectInput objectInput)
475 throws ClassNotFoundException, IOException {
476
477 _primaryKey = (Serializable)objectInput.readObject();
478 _shardName = objectInput.readUTF();
479 }
480
481 @Override
482 public void writeExternal(ObjectOutput objectOutput)
483 throws IOException {
484
485 objectOutput.writeObject(_primaryKey);
486 objectOutput.writeUTF(_shardName);
487 }
488
489 private static final long serialVersionUID = 1L;
490
491 private Serializable _primaryKey;
492 private String _shardName;
493
494 }
495
496 private static class LocalCacheKey implements Serializable {
497
498 public LocalCacheKey(String className, Serializable primaryKey) {
499 _className = className;
500 _primaryKey = primaryKey;
501 }
502
503 @Override
504 public boolean equals(Object obj) {
505 LocalCacheKey localCacheKey = (LocalCacheKey)obj;
506
507 if (localCacheKey._className.equals(_className) &&
508 localCacheKey._primaryKey.equals(_primaryKey)) {
509
510 return true;
511 }
512
513 return false;
514 }
515
516 @Override
517 public int hashCode() {
518 return _className.hashCode() * 11 + _primaryKey.hashCode();
519 }
520
521 private static final long serialVersionUID = 1L;
522
523 private final String _className;
524 private final Serializable _primaryKey;
525
526 }
527
528 private static class ShardLocalCacheKey implements Serializable {
529
530 public ShardLocalCacheKey(
531 String shardName, String className, Serializable primaryKey) {
532
533 _shardName = shardName;
534 _className = className;
535 _primaryKey = primaryKey;
536 }
537
538 @Override
539 public boolean equals(Object obj) {
540 ShardLocalCacheKey shardLocalCacheKey = (ShardLocalCacheKey)obj;
541
542 if (shardLocalCacheKey._shardName.equals(_shardName) &&
543 shardLocalCacheKey._className.equals(_className) &&
544 shardLocalCacheKey._primaryKey.equals(_primaryKey)) {
545
546 return true;
547 }
548
549 return false;
550 }
551
552 @Override
553 public int hashCode() {
554 int hashCode = HashUtil.hash(0, _shardName);
555
556 hashCode = HashUtil.hash(hashCode, _className);
557 hashCode = HashUtil.hash(hashCode, _primaryKey);
558
559 return hashCode;
560 }
561
562 private static final long serialVersionUID = 1L;
563
564 private final String _className;
565 private final Serializable _primaryKey;
566 private final String _shardName;
567
568 }
569
570 }