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