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