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 if (result == null) {
167 PortalCache portalCache = _getPortalCache(classObj.getName(), true);
168
169 String cacheKey = _encodeCacheKey(primaryKeyObj);
170
171 result = portalCache.get(cacheKey);
172
173 if (result == null) {
174 if (_log.isDebugEnabled()) {
175 _log.debug(
176 "Load " + classObj + " " + primaryKeyObj +
177 " from session");
178 }
179
180 Session session = null;
181
182 try {
183 session = sessionFactory.openSession();
184
185 result = session.load(classObj, primaryKeyObj);
186 }
187 finally {
188 if (result == null) {
189 result = StringPool.BLANK;
190 }
191 else {
192 result = _objectToResult(result);
193 }
194
195 portalCache.put(cacheKey, result);
196
197 sessionFactory.closeSession(session);
198 }
199 }
200
201 if (_localCacheAvailable) {
202 localCache.put(localCacheKey, result);
203 }
204 }
205
206 result = _objectToResult(result);
207
208 return result;
209 }
210
211 public void putResult(
212 boolean entityCacheEnabled, Class<?> classObj,
213 Serializable primaryKeyObj, Object result) {
214
215 if (!PropsValues.VALUE_OBJECT_ENTITY_CACHE_ENABLED ||
216 !entityCacheEnabled || !CacheRegistryUtil.isActive() ||
217 (result == null)) {
218
219 return;
220 }
221
222 result = _objectToResult(result);
223
224 if (_localCacheAvailable) {
225 Map<String, Object> localCache = _localCache.get();
226
227 String localCacheKey = _encodeLocalCacheKey(
228 classObj, primaryKeyObj);
229
230 localCache.put(localCacheKey, result);
231 }
232
233 PortalCache portalCache = _getPortalCache(classObj.getName(), true);
234
235 String cacheKey = _encodeCacheKey(primaryKeyObj);
236
237 portalCache.put(cacheKey, result);
238 }
239
240 public void removeResult(
241 boolean entityCacheEnabled, Class<?> classObj,
242 Serializable primaryKeyObj) {
243
244 if (!PropsValues.VALUE_OBJECT_ENTITY_CACHE_ENABLED ||
245 !entityCacheEnabled || !CacheRegistryUtil.isActive()) {
246
247 return;
248 }
249
250 if (_localCacheAvailable) {
251 Map<String, Object> localCache = _localCache.get();
252
253 String localCacheKey = _encodeLocalCacheKey(
254 classObj, primaryKeyObj);
255
256 localCache.remove(localCacheKey);
257 }
258
259 PortalCache portalCache = _getPortalCache(classObj.getName(), true);
260
261 String cacheKey = _encodeCacheKey(primaryKeyObj);
262
263 portalCache.remove(cacheKey);
264 }
265
266 public void setMultiVMPool(MultiVMPool multiVMPool) {
267 _multiVMPool = multiVMPool;
268 }
269
270 private String _encodeCacheKey(Serializable primaryKeyObj) {
271 CacheKeyGenerator cacheKeyGenerator =
272 CacheKeyGeneratorUtil.getCacheKeyGenerator(CACHE_NAME);
273
274 return cacheKeyGenerator.getCacheKey(primaryKeyObj.toString());
275 }
276
277 private String _encodeLocalCacheKey(
278 Class<?> classObj, Serializable primaryKeyObj) {
279
280 CacheKeyGenerator cacheKeyGenerator =
281 CacheKeyGeneratorUtil.getCacheKeyGenerator(CACHE_NAME);
282
283 cacheKeyGenerator.append(classObj.getName());
284 cacheKeyGenerator.append(primaryKeyObj.toString());
285
286 return cacheKeyGenerator.finish();
287 }
288
289 private PortalCache _getPortalCache(
290 String className, boolean createIfAbsent) {
291 String groupKey = _GROUP_KEY_PREFIX.concat(className);
292
293 PortalCache portalCache = _portalCaches.get(groupKey);
294
295 if ((portalCache == null) && createIfAbsent) {
296 portalCache = _multiVMPool.getCache(
297 groupKey, PropsValues.VALUE_OBJECT_ENTITY_BLOCKING_CACHE);
298
299 PortalCache previousPortalCache = _portalCaches.putIfAbsent(
300 groupKey, portalCache);
301
302 if (previousPortalCache != null) {
303 portalCache = previousPortalCache;
304 }
305
306 portalCache.setDebug(true);
307 }
308
309 return portalCache;
310 }
311
312 private Object _objectToResult(Object result) {
313 if (result instanceof String) {
314 return null;
315 }
316 else {
317 result = ((BaseModel<?>)result).clone();
318
319 BaseModel<?> model = (BaseModel<?>)result;
320
321 model.setCachedModel(true);
322
323 return model;
324 }
325 }
326
327 private static Log _log = LogFactoryUtil.getLog(EntityCacheImpl.class);
328
329 private static final String _GROUP_KEY_PREFIX = CACHE_NAME.concat(
330 StringPool.PERIOD);
331
332 private static ThreadLocal<LRUMap> _localCache;
333 private static boolean _localCacheAvailable;
334
335 static {
336 if (PropsValues.VALUE_OBJECT_ENTITY_THREAD_LOCAL_CACHE_MAX_SIZE > 0) {
337 _localCache = new AutoResetThreadLocal<LRUMap>(
338 EntityCacheImpl.class + "._localCache",
339 new LRUMap(
340 PropsValues.
341 VALUE_OBJECT_ENTITY_THREAD_LOCAL_CACHE_MAX_SIZE));
342 _localCacheAvailable = true;
343 }
344 }
345
346 private MultiVMPool _multiVMPool;
347 private ConcurrentMap<String, PortalCache> _portalCaches =
348 new ConcurrentHashMap<String, PortalCache>();
349
350 }