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