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