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