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