1
14
15 package com.liferay.portal.dao.orm.common;
16
17 import com.liferay.portal.cache.transactional.TransactionalPortalCache;
18 import com.liferay.portal.kernel.cache.CacheRegistry;
19 import com.liferay.portal.kernel.cache.CacheRegistryItem;
20 import com.liferay.portal.kernel.cache.MultiVMPool;
21 import com.liferay.portal.kernel.cache.PortalCache;
22 import com.liferay.portal.kernel.cache.key.CacheKeyGenerator;
23 import com.liferay.portal.kernel.cache.key.CacheKeyGeneratorUtil;
24 import com.liferay.portal.kernel.dao.orm.EntityCache;
25 import com.liferay.portal.kernel.dao.orm.Session;
26 import com.liferay.portal.kernel.dao.orm.SessionFactory;
27 import com.liferay.portal.kernel.log.Log;
28 import com.liferay.portal.kernel.log.LogFactoryUtil;
29 import com.liferay.portal.kernel.util.AutoResetThreadLocal;
30 import com.liferay.portal.kernel.util.StringPool;
31 import com.liferay.portal.kernel.util.StringUtil;
32 import com.liferay.portal.model.BaseModel;
33 import com.liferay.portal.util.PropsValues;
34
35 import java.io.Serializable;
36
37 import java.util.Map;
38 import java.util.concurrent.ConcurrentHashMap;
39 import java.util.concurrent.ConcurrentMap;
40
41 import org.apache.commons.collections.map.LRUMap;
42
43
48 public class EntityCacheImpl implements CacheRegistryItem, EntityCache {
49
50 public static final String CACHE_NAME = EntityCache.class.getName();
51
52 public void afterPropertiesSet() {
53 CacheRegistry.register(this);
54 }
55
56 public void clearCache() {
57 clearLocalCache();
58
59 for (PortalCache portalCache : _portalCaches.values()) {
60 portalCache.removeAll();
61 }
62 }
63
64 public void clearCache(String className) {
65 clearLocalCache();
66
67 PortalCache portalCache = _getPortalCache(className, false);
68
69 if (portalCache != null) {
70 portalCache.removeAll();
71 }
72 }
73
74 public void clearLocalCache() {
75 if (_localCacheAvailable) {
76 _localCache.remove();
77 }
78 }
79
80 public String getRegistryName() {
81 return CACHE_NAME;
82 }
83
84 public Object getResult(
85 boolean entityCacheEnabled, Class<?> classObj,
86 Serializable primaryKeyObj, SessionFactory sessionFactory) {
87
88 if (!PropsValues.VALUE_OBJECT_ENTITY_CACHE_ENABLED ||
89 !entityCacheEnabled || !CacheRegistry.isActive()) {
90
91 return null;
92 }
93
94 Object result = null;
95
96 Map<String, Object> localCache = null;
97
98 String localCacheKey = null;
99
100 if (_localCacheAvailable) {
101 localCache = _localCache.get();
102
103 localCacheKey = _encodeLocalCacheKey(classObj, primaryKeyObj);
104
105 result = localCache.get(localCacheKey);
106 }
107
108 if (result == null) {
109 PortalCache portalCache = _getPortalCache(classObj.getName(), true);
110
111 String cacheKey = _encodeCacheKey(primaryKeyObj);
112
113 result = portalCache.get(cacheKey);
114
115 if (result == null) {
116 result = StringPool.BLANK;
117
118 portalCache.put(cacheKey, result);
119 }
120
121 if (_localCacheAvailable) {
122 localCache.put(localCacheKey, result);
123 }
124 }
125
126 if (result != null) {
127 result = _objectToResult(result);
128 }
129
130 return result;
131 }
132
133 public void invalidate() {
134 clearCache();
135 }
136
137 public Object loadResult(
138 boolean entityCacheEnabled, Class<?> classObj,
139 Serializable primaryKeyObj, SessionFactory sessionFactory) {
140
141 if (!PropsValues.VALUE_OBJECT_ENTITY_CACHE_ENABLED ||
142 !entityCacheEnabled || !CacheRegistry.isActive()) {
143
144 Session session = null;
145
146 try {
147 session = sessionFactory.openSession();
148
149 return session.load(classObj, primaryKeyObj);
150 }
151 finally {
152 sessionFactory.closeSession(session);
153 }
154 }
155
156 Object result = null;
157
158 Map<String, Object> localCache = null;
159
160 String localCacheKey = null;
161
162 if (_localCacheAvailable) {
163 localCache = _localCache.get();
164
165 localCacheKey = _encodeLocalCacheKey(classObj, primaryKeyObj);
166
167 result = localCache.get(localCacheKey);
168 }
169
170 boolean load = false;
171
172 if (result == null) {
173 PortalCache portalCache = _getPortalCache(classObj.getName(), true);
174
175 String cacheKey = _encodeCacheKey(primaryKeyObj);
176
177 result = portalCache.get(cacheKey);
178
179 if (result == null) {
180 if (_log.isDebugEnabled()) {
181 _log.debug(
182 "Load " + classObj + " " + primaryKeyObj +
183 " from session");
184 }
185
186 load = true;
187
188 Session session = null;
189
190 try {
191 session = sessionFactory.openSession();
192
193 result = session.load(classObj, primaryKeyObj);
194 }
195 finally {
196 if (result == null) {
197 result = StringPool.BLANK;
198 }
199 else {
200 result = _objectToResult(result);
201 }
202
203 portalCache.put(cacheKey, result);
204
205 sessionFactory.closeSession(session);
206 }
207 }
208
209 if (_localCacheAvailable) {
210 localCache.put(localCacheKey, result);
211 }
212 }
213
214 if (!load) {
215 return _objectToResult(result);
216 }
217
218 if (result instanceof String) {
219 return null;
220 }
221 else {
222 return result;
223 }
224 }
225
226 public void putResult(
227 boolean entityCacheEnabled, Class<?> classObj,
228 Serializable primaryKeyObj, Object result) {
229
230 if (!PropsValues.VALUE_OBJECT_ENTITY_CACHE_ENABLED ||
231 !entityCacheEnabled || !CacheRegistry.isActive() ||
232 (result == null)) {
233
234 return;
235 }
236
237 result = _objectToResult(result);
238
239 if (_localCacheAvailable) {
240 Map<String, Object> localCache = _localCache.get();
241
242 String localCacheKey = _encodeLocalCacheKey(
243 classObj, primaryKeyObj);
244
245 localCache.put(localCacheKey, result);
246 }
247
248 PortalCache portalCache = _getPortalCache(classObj.getName(), true);
249
250 String cacheKey = _encodeCacheKey(primaryKeyObj);
251
252 portalCache.put(cacheKey, result);
253 }
254
255 public void removeCache(String className) {
256 String groupKey = _GROUP_KEY_PREFIX.concat(className);
257
258 _portalCaches.remove(groupKey);
259 _multiVMPool.removeCache(groupKey);
260 }
261
262 public void removeResult(
263 boolean entityCacheEnabled, Class<?> classObj,
264 Serializable primaryKeyObj) {
265
266 if (!PropsValues.VALUE_OBJECT_ENTITY_CACHE_ENABLED ||
267 !entityCacheEnabled || !CacheRegistry.isActive()) {
268
269 return;
270 }
271
272 if (_localCacheAvailable) {
273 Map<String, Object> localCache = _localCache.get();
274
275 String localCacheKey = _encodeLocalCacheKey(
276 classObj, primaryKeyObj);
277
278 localCache.remove(localCacheKey);
279 }
280
281 PortalCache portalCache = _getPortalCache(classObj.getName(), true);
282
283 String cacheKey = _encodeCacheKey(primaryKeyObj);
284
285 portalCache.remove(cacheKey);
286 }
287
288 public void setMultiVMPool(MultiVMPool multiVMPool) {
289 _multiVMPool = multiVMPool;
290 }
291
292 private String _encodeCacheKey(Serializable primaryKeyObj) {
293 CacheKeyGenerator cacheKeyGenerator =
294 CacheKeyGeneratorUtil.getCacheKeyGenerator(CACHE_NAME);
295
296 return cacheKeyGenerator.getCacheKey(
297 StringUtil.toHexString(primaryKeyObj));
298 }
299
300 private String _encodeLocalCacheKey(
301 Class<?> classObj, Serializable primaryKeyObj) {
302
303 CacheKeyGenerator cacheKeyGenerator =
304 CacheKeyGeneratorUtil.getCacheKeyGenerator(CACHE_NAME);
305
306 cacheKeyGenerator.append(classObj.getName());
307 cacheKeyGenerator.append(StringUtil.toHexString(primaryKeyObj));
308
309 return cacheKeyGenerator.finish();
310 }
311
312 private PortalCache _getPortalCache(
313 String className, boolean createIfAbsent) {
314
315 String groupKey = _GROUP_KEY_PREFIX.concat(className);
316
317 PortalCache portalCache = _portalCaches.get(groupKey);
318
319 if ((portalCache == null) && createIfAbsent) {
320 portalCache = _multiVMPool.getCache(
321 groupKey, PropsValues.VALUE_OBJECT_ENTITY_BLOCKING_CACHE);
322
323 if (PropsValues.TRANSACTIONAL_CACHE_ENABLED) {
324 portalCache = new TransactionalPortalCache(portalCache);
325 }
326
327 PortalCache previousPortalCache = _portalCaches.putIfAbsent(
328 groupKey, portalCache);
329
330 if (previousPortalCache != null) {
331 portalCache = previousPortalCache;
332 }
333
334 portalCache.setDebug(true);
335 }
336
337 return portalCache;
338 }
339
340 private Object _objectToResult(Object result) {
341 if (result instanceof String) {
342 return null;
343 }
344 else {
345 result = ((BaseModel<?>)result).clone();
346
347 BaseModel<?> model = (BaseModel<?>)result;
348
349 model.setCachedModel(true);
350
351 return model;
352 }
353 }
354
355 private static Log _log = LogFactoryUtil.getLog(EntityCacheImpl.class);
356
357 private static final String _GROUP_KEY_PREFIX = CACHE_NAME.concat(
358 StringPool.PERIOD);
359
360 private static ThreadLocal<LRUMap> _localCache;
361 private static boolean _localCacheAvailable;
362
363 static {
364 if (PropsValues.VALUE_OBJECT_ENTITY_THREAD_LOCAL_CACHE_MAX_SIZE > 0) {
365 _localCache = new AutoResetThreadLocal<LRUMap>(new LRUMap(
366 PropsValues.VALUE_OBJECT_ENTITY_THREAD_LOCAL_CACHE_MAX_SIZE));
367 _localCacheAvailable = true;
368 }
369 }
370
371 private MultiVMPool _multiVMPool;
372 private ConcurrentMap<String, PortalCache> _portalCaches =
373 new ConcurrentHashMap<String, PortalCache>();
374
375 }