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.PortalCacheManager;
024 import com.liferay.portal.kernel.dao.orm.EntityCache;
025 import com.liferay.portal.kernel.dao.orm.Session;
026 import com.liferay.portal.kernel.dao.orm.SessionFactory;
027 import com.liferay.portal.kernel.dao.shard.ShardUtil;
028 import com.liferay.portal.kernel.log.Log;
029 import com.liferay.portal.kernel.log.LogFactoryUtil;
030 import com.liferay.portal.kernel.security.pacl.DoPrivileged;
031 import com.liferay.portal.kernel.util.AutoResetThreadLocal;
032 import com.liferay.portal.kernel.util.HashUtil;
033 import com.liferay.portal.kernel.util.StringPool;
034 import com.liferay.portal.model.BaseModel;
035 import com.liferay.portal.model.CacheModel;
036 import com.liferay.portal.model.MVCCModel;
037 import com.liferay.portal.util.PropsValues;
038
039 import java.io.Externalizable;
040 import java.io.IOException;
041 import java.io.ObjectInput;
042 import java.io.ObjectOutput;
043 import java.io.Serializable;
044
045 import java.util.Map;
046 import java.util.concurrent.ConcurrentHashMap;
047 import java.util.concurrent.ConcurrentMap;
048
049 import org.apache.commons.collections.map.LRUMap;
050
051
055 @DoPrivileged
056 public class EntityCacheImpl
057 implements CacheManagerListener, CacheRegistryItem, EntityCache {
058
059 public static final String CACHE_NAME = EntityCache.class.getName();
060
061 public void afterPropertiesSet() {
062 CacheRegistryUtil.register(this);
063 }
064
065 @Override
066 public void clearCache() {
067 clearLocalCache();
068
069 for (PortalCache<?, ?> portalCache : _portalCaches.values()) {
070 portalCache.removeAll();
071 }
072 }
073
074 @Override
075 public void clearCache(Class<?> clazz) {
076 clearLocalCache();
077
078 PortalCache<?, ?> portalCache = _getPortalCache(clazz, true);
079
080 if (portalCache != null) {
081 portalCache.removeAll();
082 }
083 }
084
085 @Override
086 public void clearLocalCache() {
087 if (_LOCAL_CACHE_AVAILABLE) {
088 _localCache.remove();
089 }
090 }
091
092 @Override
093 public void dispose() {
094 _portalCaches.clear();
095 }
096
097 @Override
098 public PortalCache<Serializable, Serializable> getPortalCache(
099 Class<?> clazz) {
100
101 return _getPortalCache(clazz, true);
102 }
103
104 @Override
105 public String getRegistryName() {
106 return CACHE_NAME;
107 }
108
109 @Override
110 public Serializable getResult(
111 boolean entityCacheEnabled, Class<?> clazz, Serializable primaryKey) {
112
113 if (!PropsValues.VALUE_OBJECT_ENTITY_CACHE_ENABLED ||
114 !entityCacheEnabled || !CacheRegistryUtil.isActive()) {
115
116 return null;
117 }
118
119 Serializable result = null;
120
121 Map<Serializable, Serializable> localCache = null;
122
123 Serializable localCacheKey = null;
124
125 if (_LOCAL_CACHE_AVAILABLE) {
126 localCache = _localCache.get();
127
128 localCacheKey = _encodeLocalCacheKey(clazz, primaryKey);
129
130 result = localCache.get(localCacheKey);
131 }
132
133 if (result == null) {
134 PortalCache<Serializable, Serializable> portalCache =
135 _getPortalCache(clazz, true);
136
137 Serializable cacheKey = _encodeCacheKey(primaryKey);
138
139 result = portalCache.get(cacheKey);
140
141 if (result == null) {
142 result = StringPool.BLANK;
143 }
144
145 if (_LOCAL_CACHE_AVAILABLE) {
146 localCache.put(localCacheKey, result);
147 }
148 }
149
150 return _toEntityModel(result);
151 }
152
153 @Override
154 public void init() {
155 }
156
157 @Override
158 public void invalidate() {
159 clearCache();
160 }
161
162 @Override
163 public Serializable loadResult(
164 boolean entityCacheEnabled, Class<?> clazz, Serializable primaryKey,
165 SessionFactory sessionFactory) {
166
167 if (!PropsValues.VALUE_OBJECT_ENTITY_CACHE_ENABLED ||
168 !entityCacheEnabled || !CacheRegistryUtil.isActive()) {
169
170 Session session = null;
171
172 try {
173 session = sessionFactory.openSession();
174
175 return (Serializable)session.load(clazz, primaryKey);
176 }
177 finally {
178 sessionFactory.closeSession(session);
179 }
180 }
181
182 Serializable result = null;
183
184 Map<Serializable, Serializable> localCache = null;
185
186 Serializable localCacheKey = null;
187
188 if (_LOCAL_CACHE_AVAILABLE) {
189 localCache = _localCache.get();
190
191 localCacheKey = _encodeLocalCacheKey(clazz, primaryKey);
192
193 result = localCache.get(localCacheKey);
194 }
195
196 Serializable loadResult = null;
197
198 if (result == null) {
199 PortalCache<Serializable, Serializable> portalCache =
200 _getPortalCache(clazz, true);
201
202 Serializable cacheKey = _encodeCacheKey(primaryKey);
203
204 result = portalCache.get(cacheKey);
205
206 if (result == null) {
207 if (_log.isDebugEnabled()) {
208 _log.debug(
209 "Load " + clazz + " " + primaryKey + " from session");
210 }
211
212 Session session = null;
213
214 try {
215 session = sessionFactory.openSession();
216
217 loadResult = (Serializable)session.load(clazz, primaryKey);
218 }
219 finally {
220 if (loadResult == null) {
221 result = StringPool.BLANK;
222 }
223 else {
224 result = ((BaseModel<?>)loadResult).toCacheModel();
225 }
226
227 portalCache.putQuiet(cacheKey, result);
228
229 sessionFactory.closeSession(session);
230 }
231 }
232
233 if (_LOCAL_CACHE_AVAILABLE) {
234 localCache.put(localCacheKey, result);
235 }
236 }
237
238 if (loadResult != null) {
239 return loadResult;
240 }
241
242 return _toEntityModel(result);
243 }
244
245 @Override
246 public void notifyCacheAdded(String name) {
247 }
248
249 @Override
250 public void notifyCacheRemoved(String name) {
251 _portalCaches.remove(name);
252 }
253
254 @Override
255 public void putResult(
256 boolean entityCacheEnabled, Class<?> clazz, Serializable primaryKey,
257 Serializable result) {
258
259 putResult(entityCacheEnabled, clazz, primaryKey, result, true);
260 }
261
262 @Override
263 public void putResult(
264 boolean entityCacheEnabled, Class<?> clazz, Serializable primaryKey,
265 Serializable result, boolean quiet) {
266
267 if (!PropsValues.VALUE_OBJECT_ENTITY_CACHE_ENABLED ||
268 !entityCacheEnabled || !CacheRegistryUtil.isActive() ||
269 (result == null)) {
270
271 return;
272 }
273
274 result = ((BaseModel<?>)result).toCacheModel();
275
276 if (_LOCAL_CACHE_AVAILABLE) {
277 Map<Serializable, Serializable> localCache = _localCache.get();
278
279 Serializable localCacheKey = _encodeLocalCacheKey(
280 clazz, primaryKey);
281
282 localCache.put(localCacheKey, result);
283 }
284
285 PortalCache<Serializable, Serializable> portalCache = _getPortalCache(
286 clazz, true);
287
288 Serializable cacheKey = _encodeCacheKey(primaryKey);
289
290 if (quiet) {
291 portalCache.putQuiet(cacheKey, result);
292 }
293 else {
294 portalCache.put(cacheKey, result);
295 }
296 }
297
298 @Override
299 public void removeCache(String className) {
300 _portalCaches.remove(className);
301
302 String groupKey = _GROUP_KEY_PREFIX.concat(className);
303
304 _multiVMPool.removeCache(groupKey);
305 }
306
307 @Override
308 public void removeResult(
309 boolean entityCacheEnabled, Class<?> clazz, Serializable primaryKey) {
310
311 if (!PropsValues.VALUE_OBJECT_ENTITY_CACHE_ENABLED ||
312 !entityCacheEnabled || !CacheRegistryUtil.isActive()) {
313
314 return;
315 }
316
317 if (_LOCAL_CACHE_AVAILABLE) {
318 Map<Serializable, Serializable> localCache = _localCache.get();
319
320 Serializable localCacheKey = _encodeLocalCacheKey(
321 clazz, primaryKey);
322
323 localCache.remove(localCacheKey);
324 }
325
326 PortalCache<Serializable, Serializable> portalCache = _getPortalCache(
327 clazz, true);
328
329 Serializable cacheKey = _encodeCacheKey(primaryKey);
330
331 portalCache.remove(cacheKey);
332 }
333
334 public void setMultiVMPool(MultiVMPool multiVMPool) {
335 _multiVMPool = multiVMPool;
336
337 PortalCacheManager<? extends Serializable, ? extends Serializable>
338 portalCacheManager = _multiVMPool.getCacheManager();
339
340 portalCacheManager.registerCacheManagerListener(this);
341 }
342
343 private Serializable _encodeCacheKey(Serializable primaryKey) {
344 if (ShardUtil.isEnabled()) {
345 return new CacheKey(ShardUtil.getCurrentShardName(), primaryKey);
346 }
347
348 return primaryKey;
349 }
350
351 private Serializable _encodeLocalCacheKey(
352 Class<?> clazz, Serializable primaryKey) {
353
354 if (ShardUtil.isEnabled()) {
355 return new ShardLocalCacheKey(
356 ShardUtil.getCurrentShardName(), clazz.getName(), primaryKey);
357 }
358
359 return new LocalCacheKey(clazz.getName(), primaryKey);
360 }
361
362 private PortalCache<Serializable, Serializable> _getPortalCache(
363 Class<?> clazz, boolean createIfAbsent) {
364
365 String className = clazz.getName();
366
367 PortalCache<Serializable, Serializable> portalCache = _portalCaches.get(
368 className);
369
370 if ((portalCache == null) && createIfAbsent) {
371 String groupKey = _GROUP_KEY_PREFIX.concat(className);
372
373 portalCache =
374 (PortalCache<Serializable, Serializable>)_multiVMPool.getCache(
375 groupKey, PropsValues.VALUE_OBJECT_ENTITY_BLOCKING_CACHE);
376
377 if (PropsValues.VALUE_OBJECT_MVCC_ENTITY_CACHE_ENABLED &&
378 MVCCModel.class.isAssignableFrom(clazz)) {
379
380 portalCache =
381 (PortalCache<Serializable, Serializable>)
382 MVCCPortalCacheFactory.createMVCCEhcachePortalCache(
383 portalCache);
384 }
385
386 PortalCache<Serializable, Serializable> previousPortalCache =
387 _portalCaches.putIfAbsent(className, portalCache);
388
389 if (previousPortalCache != null) {
390 portalCache = previousPortalCache;
391 }
392 }
393
394 return portalCache;
395 }
396
397 private Serializable _toEntityModel(Serializable result) {
398 if (result == StringPool.BLANK) {
399 return null;
400 }
401
402 CacheModel<?> cacheModel = (CacheModel<?>)result;
403
404 BaseModel<?> entityModel = (BaseModel<?>)cacheModel.toEntityModel();
405
406 entityModel.setCachedModel(true);
407
408 return entityModel;
409 }
410
411 private static final String _GROUP_KEY_PREFIX = CACHE_NAME.concat(
412 StringPool.PERIOD);
413
414 private static final boolean _LOCAL_CACHE_AVAILABLE;
415
416 private static final Log _log = LogFactoryUtil.getLog(
417 EntityCacheImpl.class);
418
419 private static final ThreadLocal<LRUMap> _localCache;
420
421 static {
422 if (PropsValues.VALUE_OBJECT_ENTITY_THREAD_LOCAL_CACHE_MAX_SIZE > 0) {
423 _LOCAL_CACHE_AVAILABLE = true;
424
425 _localCache = new AutoResetThreadLocal<LRUMap>(
426 EntityCacheImpl.class + "._localCache",
427 new LRUMap(
428 PropsValues.
429 VALUE_OBJECT_ENTITY_THREAD_LOCAL_CACHE_MAX_SIZE));
430 }
431 else {
432 _LOCAL_CACHE_AVAILABLE = false;
433
434 _localCache = null;
435 }
436 }
437
438 private MultiVMPool _multiVMPool;
439 private final ConcurrentMap<String, PortalCache<Serializable, Serializable>>
440 _portalCaches =
441 new ConcurrentHashMap
442 <String, PortalCache<Serializable, Serializable>>();
443
444 private static class CacheKey implements Externalizable {
445
446 @SuppressWarnings("unused")
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 }