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