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 name) {
249 }
250
251 @Override
252 public void notifyCacheRemoved(String name) {
253 _portalCaches.remove(name);
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 =
444 new ConcurrentHashMap
445 <String, PortalCache<Serializable, Serializable>>();
446
447 private static class CacheKey implements Externalizable {
448
449 public CacheKey() {
450 }
451
452 public CacheKey(String shardName, Serializable primaryKey) {
453 _shardName = shardName;
454 _primaryKey = primaryKey;
455 }
456
457 @Override
458 public boolean equals(Object obj) {
459 CacheKey cacheKey = (CacheKey)obj;
460
461 if (cacheKey._shardName.equals(_shardName) &&
462 cacheKey._primaryKey.equals(_primaryKey)) {
463
464 return true;
465 }
466
467 return false;
468 }
469
470 @Override
471 public int hashCode() {
472 return _shardName.hashCode() * 11 + _primaryKey.hashCode();
473 }
474
475 @Override
476 public void readExternal(ObjectInput objectInput)
477 throws ClassNotFoundException, IOException {
478
479 _primaryKey = (Serializable)objectInput.readObject();
480 _shardName = objectInput.readUTF();
481 }
482
483 @Override
484 public void writeExternal(ObjectOutput objectOutput)
485 throws IOException {
486
487 objectOutput.writeObject(_primaryKey);
488 objectOutput.writeUTF(_shardName);
489 }
490
491 private static final long serialVersionUID = 1L;
492
493 private Serializable _primaryKey;
494 private String _shardName;
495
496 }
497
498 private static class LocalCacheKey implements Serializable {
499
500 public LocalCacheKey(String className, Serializable primaryKey) {
501 _className = className;
502 _primaryKey = primaryKey;
503 }
504
505 @Override
506 public boolean equals(Object obj) {
507 LocalCacheKey localCacheKey = (LocalCacheKey)obj;
508
509 if (localCacheKey._className.equals(_className) &&
510 localCacheKey._primaryKey.equals(_primaryKey)) {
511
512 return true;
513 }
514
515 return false;
516 }
517
518 @Override
519 public int hashCode() {
520 return _className.hashCode() * 11 + _primaryKey.hashCode();
521 }
522
523 private static final long serialVersionUID = 1L;
524
525 private final String _className;
526 private final Serializable _primaryKey;
527
528 }
529
530 private static class ShardLocalCacheKey implements Serializable {
531
532 public ShardLocalCacheKey(
533 String shardName, String className, Serializable primaryKey) {
534
535 _shardName = shardName;
536 _className = className;
537 _primaryKey = primaryKey;
538 }
539
540 @Override
541 public boolean equals(Object obj) {
542 ShardLocalCacheKey shardLocalCacheKey = (ShardLocalCacheKey)obj;
543
544 if (shardLocalCacheKey._shardName.equals(_shardName) &&
545 shardLocalCacheKey._className.equals(_className) &&
546 shardLocalCacheKey._primaryKey.equals(_primaryKey)) {
547
548 return true;
549 }
550
551 return false;
552 }
553
554 @Override
555 public int hashCode() {
556 int hashCode = HashUtil.hash(0, _shardName);
557
558 hashCode = HashUtil.hash(hashCode, _className);
559 hashCode = HashUtil.hash(hashCode, _primaryKey);
560
561 return hashCode;
562 }
563
564 private static final long serialVersionUID = 1L;
565
566 private final String _className;
567 private final Serializable _primaryKey;
568 private final String _shardName;
569
570 }
571
572 }