001
014
015 package com.liferay.portal.dao.orm.common;
016
017 import com.liferay.portal.cache.transactional.TransactionalPortalCache;
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.cache.key.CacheKeyGenerator;
023 import com.liferay.portal.kernel.cache.key.CacheKeyGeneratorUtil;
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.util.AutoResetThreadLocal;
031 import com.liferay.portal.kernel.util.StringPool;
032 import com.liferay.portal.model.BaseModel;
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
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<?> classObj,
084 Serializable primaryKeyObj, SessionFactory sessionFactory) {
085
086 if (!PropsValues.VALUE_OBJECT_ENTITY_CACHE_ENABLED ||
087 !entityCacheEnabled || !CacheRegistryUtil.isActive()) {
088
089 return null;
090 }
091
092 Object result = null;
093
094 Map<String, Object> localCache = null;
095
096 String localCacheKey = null;
097
098 if (_localCacheAvailable) {
099 localCache = _localCache.get();
100
101 localCacheKey = _encodeLocalCacheKey(classObj, primaryKeyObj);
102
103 result = localCache.get(localCacheKey);
104 }
105
106 if (result == null) {
107 PortalCache portalCache = _getPortalCache(classObj.getName(), true);
108
109 String cacheKey = _encodeCacheKey(primaryKeyObj);
110
111 result = portalCache.get(cacheKey);
112
113 if (result == null) {
114 result = StringPool.BLANK;
115
116 portalCache.put(cacheKey, result);
117 }
118
119 if (_localCacheAvailable) {
120 localCache.put(localCacheKey, result);
121 }
122 }
123
124 if (result != null) {
125 result = _objectToResult(result);
126 }
127
128 return result;
129 }
130
131 public void invalidate() {
132 clearCache();
133 }
134
135 public Object loadResult(
136 boolean entityCacheEnabled, Class<?> classObj,
137 Serializable primaryKeyObj, SessionFactory sessionFactory) {
138
139 if (!PropsValues.VALUE_OBJECT_ENTITY_CACHE_ENABLED ||
140 !entityCacheEnabled || !CacheRegistryUtil.isActive()) {
141
142 Session session = null;
143
144 try {
145 session = sessionFactory.openSession();
146
147 return session.load(classObj, primaryKeyObj);
148 }
149 finally {
150 sessionFactory.closeSession(session);
151 }
152 }
153
154 Object result = null;
155
156 Map<String, Object> localCache = null;
157
158 String localCacheKey = null;
159
160 if (_localCacheAvailable) {
161 localCache = _localCache.get();
162
163 localCacheKey = _encodeLocalCacheKey(classObj, primaryKeyObj);
164
165 result = localCache.get(localCacheKey);
166 }
167
168 boolean load = false;
169
170 if (result == null) {
171 PortalCache portalCache = _getPortalCache(classObj.getName(), true);
172
173 String cacheKey = _encodeCacheKey(primaryKeyObj);
174
175 result = portalCache.get(cacheKey);
176
177 if (result == null) {
178 if (_log.isDebugEnabled()) {
179 _log.debug(
180 "Load " + classObj + " " + primaryKeyObj +
181 " from session");
182 }
183
184 load = true;
185
186 Session session = null;
187
188 try {
189 session = sessionFactory.openSession();
190
191 result = session.load(classObj, primaryKeyObj);
192 }
193 finally {
194 if (result == null) {
195 result = StringPool.BLANK;
196 }
197 else {
198 result = _objectToResult(result);
199 }
200
201 portalCache.put(cacheKey, result);
202
203 sessionFactory.closeSession(session);
204 }
205 }
206
207 if (_localCacheAvailable) {
208 localCache.put(localCacheKey, result);
209 }
210 }
211
212 if (!load) {
213 return _objectToResult(result);
214 }
215
216 if (result instanceof String) {
217 return null;
218 }
219 else {
220 return result;
221 }
222 }
223
224 public void putResult(
225 boolean entityCacheEnabled, Class<?> classObj,
226 Serializable primaryKeyObj, Object result) {
227
228 if (!PropsValues.VALUE_OBJECT_ENTITY_CACHE_ENABLED ||
229 !entityCacheEnabled || !CacheRegistryUtil.isActive() ||
230 (result == null)) {
231
232 return;
233 }
234
235 result = _objectToResult(result);
236
237 if (_localCacheAvailable) {
238 Map<String, Object> localCache = _localCache.get();
239
240 String localCacheKey = _encodeLocalCacheKey(
241 classObj, primaryKeyObj);
242
243 localCache.put(localCacheKey, result);
244 }
245
246 PortalCache portalCache = _getPortalCache(classObj.getName(), true);
247
248 String cacheKey = _encodeCacheKey(primaryKeyObj);
249
250 portalCache.put(cacheKey, result);
251 }
252
253 public void removeCache(String className) {
254 String groupKey = _GROUP_KEY_PREFIX.concat(className);
255
256 _portalCaches.remove(groupKey);
257 _multiVMPool.removeCache(groupKey);
258 }
259
260 public void removeResult(
261 boolean entityCacheEnabled, Class<?> classObj,
262 Serializable primaryKeyObj) {
263
264 if (!PropsValues.VALUE_OBJECT_ENTITY_CACHE_ENABLED ||
265 !entityCacheEnabled || !CacheRegistryUtil.isActive()) {
266
267 return;
268 }
269
270 if (_localCacheAvailable) {
271 Map<String, Object> localCache = _localCache.get();
272
273 String localCacheKey = _encodeLocalCacheKey(
274 classObj, primaryKeyObj);
275
276 localCache.remove(localCacheKey);
277 }
278
279 PortalCache portalCache = _getPortalCache(classObj.getName(), true);
280
281 String cacheKey = _encodeCacheKey(primaryKeyObj);
282
283 portalCache.remove(cacheKey);
284 }
285
286 public void setMultiVMPool(MultiVMPool multiVMPool) {
287 _multiVMPool = multiVMPool;
288 }
289
290 private String _encodeCacheKey(Serializable primaryKeyObj) {
291 CacheKeyGenerator cacheKeyGenerator =
292 CacheKeyGeneratorUtil.getCacheKeyGenerator(CACHE_NAME);
293
294 cacheKeyGenerator.append(ShardUtil.getCurrentShardName());
295 cacheKeyGenerator.append(primaryKeyObj.toString());
296
297 return cacheKeyGenerator.finish();
298 }
299
300 private String _encodeLocalCacheKey(
301 Class<?> classObj, Serializable primaryKeyObj) {
302
303 CacheKeyGenerator cacheKeyGenerator =
304 CacheKeyGeneratorUtil.getCacheKeyGenerator(CACHE_NAME);
305
306 cacheKeyGenerator.append(ShardUtil.getCurrentShardName());
307 cacheKeyGenerator.append(classObj.getName());
308 cacheKeyGenerator.append(primaryKeyObj.toString());
309
310 return cacheKeyGenerator.finish();
311 }
312
313 private PortalCache _getPortalCache(
314 String className, boolean createIfAbsent) {
315
316 String groupKey = _GROUP_KEY_PREFIX.concat(className);
317
318 PortalCache portalCache = _portalCaches.get(groupKey);
319
320 if ((portalCache == null) && createIfAbsent) {
321 portalCache = _multiVMPool.getCache(
322 groupKey, PropsValues.VALUE_OBJECT_ENTITY_BLOCKING_CACHE);
323
324 if (PropsValues.TRANSACTIONAL_CACHE_ENABLED) {
325 portalCache = new TransactionalPortalCache(portalCache);
326 }
327
328 PortalCache previousPortalCache = _portalCaches.putIfAbsent(
329 groupKey, portalCache);
330
331 if (previousPortalCache != null) {
332 portalCache = previousPortalCache;
333 }
334
335 portalCache.setDebug(true);
336 }
337
338 return portalCache;
339 }
340
341 private Object _objectToResult(Object result) {
342 if (result instanceof String) {
343 return null;
344 }
345 else {
346 result = ((BaseModel<?>)result).clone();
347
348 BaseModel<?> model = (BaseModel<?>)result;
349
350 model.setCachedModel(true);
351
352 return model;
353 }
354 }
355
356 private static Log _log = LogFactoryUtil.getLog(EntityCacheImpl.class);
357
358 private static final String _GROUP_KEY_PREFIX = CACHE_NAME.concat(
359 StringPool.PERIOD);
360
361 private static ThreadLocal<LRUMap> _localCache;
362 private static boolean _localCacheAvailable;
363
364 static {
365 if (PropsValues.VALUE_OBJECT_ENTITY_THREAD_LOCAL_CACHE_MAX_SIZE > 0) {
366 _localCache = new AutoResetThreadLocal<LRUMap>(
367 EntityCacheImpl.class + "._localCache",
368 new LRUMap(
369 PropsValues.
370 VALUE_OBJECT_ENTITY_THREAD_LOCAL_CACHE_MAX_SIZE));
371 _localCacheAvailable = true;
372 }
373 }
374
375 private MultiVMPool _multiVMPool;
376 private ConcurrentMap<String, PortalCache> _portalCaches =
377 new ConcurrentHashMap<String, PortalCache>();
378
379 }