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