001
014
015 package com.liferay.portal.dao.orm.common;
016
017 import com.liferay.portal.kernel.cache.CacheManagerListener;
018 import com.liferay.portal.kernel.cache.CacheRegistryItem;
019 import com.liferay.portal.kernel.cache.CacheRegistryUtil;
020 import com.liferay.portal.kernel.cache.MultiVMPool;
021 import com.liferay.portal.kernel.cache.PortalCache;
022 import com.liferay.portal.kernel.cache.PortalCacheHelperUtil;
023 import com.liferay.portal.kernel.cache.PortalCacheManager;
024 import com.liferay.portal.kernel.dao.orm.EntityCacheUtil;
025 import com.liferay.portal.kernel.dao.orm.FinderCache;
026 import com.liferay.portal.kernel.dao.orm.FinderPath;
027 import com.liferay.portal.kernel.security.pacl.DoPrivileged;
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.service.persistence.impl.BasePersistenceImpl;
032 import com.liferay.portal.util.PropsValues;
033
034 import java.io.Serializable;
035
036 import java.util.ArrayList;
037 import java.util.Collections;
038 import java.util.HashSet;
039 import java.util.List;
040 import java.util.Map;
041 import java.util.Set;
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 FinderCacheImpl
053 implements CacheManagerListener, CacheRegistryItem, FinderCache {
054
055 public static final String CACHE_NAME = FinderCache.class.getName();
056
057 public void afterPropertiesSet() {
058 CacheRegistryUtil.register(this);
059 }
060
061 @Override
062 public void clearCache() {
063 clearLocalCache();
064
065 for (PortalCache<?, ?> portalCache : _portalCaches.values()) {
066 portalCache.removeAll();
067 }
068 }
069
070 @Override
071 public void clearCache(String className) {
072 clearLocalCache();
073
074 PortalCache<?, ?> portalCache = _getPortalCache(className, true);
075
076 if (portalCache != null) {
077 portalCache.removeAll();
078 }
079 }
080
081 @Override
082 public void clearLocalCache() {
083 if (_LOCAL_CACHE_AVAILABLE) {
084 _localCache.remove();
085 }
086 }
087
088 @Override
089 public void dispose() {
090 _portalCaches.clear();
091 }
092
093 @Override
094 public String getRegistryName() {
095 return CACHE_NAME;
096 }
097
098 @Override
099 public Object getResult(
100 FinderPath finderPath, Object[] args,
101 BasePersistenceImpl<? extends BaseModel<?>> basePersistenceImpl) {
102
103 if (!PropsValues.VALUE_OBJECT_FINDER_CACHE_ENABLED ||
104 !finderPath.isFinderCacheEnabled() ||
105 !CacheRegistryUtil.isActive()) {
106
107 return null;
108 }
109
110 Serializable primaryKey = null;
111
112 Map<Serializable, Serializable> localCache = null;
113
114 Serializable localCacheKey = null;
115
116 if (_LOCAL_CACHE_AVAILABLE) {
117 localCache = _localCache.get();
118
119 localCacheKey = finderPath.encodeLocalCacheKey(args);
120
121 primaryKey = localCache.get(localCacheKey);
122 }
123
124 if (primaryKey == null) {
125 PortalCache<Serializable, Serializable> portalCache =
126 _getPortalCache(finderPath.getCacheName(), true);
127
128 Serializable cacheKey = finderPath.encodeCacheKey(args);
129
130 primaryKey = portalCache.get(cacheKey);
131
132 if (primaryKey != null) {
133 if (_LOCAL_CACHE_AVAILABLE) {
134 localCache.put(localCacheKey, primaryKey);
135 }
136 }
137 }
138
139 if (primaryKey != null) {
140 return _primaryKeyToResult(
141 finderPath, basePersistenceImpl, primaryKey);
142 }
143
144 return null;
145 }
146
147 @Override
148 public void init() {
149 }
150
151 @Override
152 public void invalidate() {
153 clearCache();
154 }
155
156 @Override
157 public void notifyCacheAdded(String name) {
158 }
159
160 @Override
161 public void notifyCacheRemoved(String name) {
162 _portalCaches.remove(name);
163 }
164
165 @Override
166 public void putResult(FinderPath finderPath, Object[] args, Object result) {
167 putResult(finderPath, args, result, true);
168 }
169
170 @Override
171 public void putResult(
172 FinderPath finderPath, Object[] args, Object result, boolean quiet) {
173
174 if (!PropsValues.VALUE_OBJECT_FINDER_CACHE_ENABLED ||
175 !finderPath.isFinderCacheEnabled() ||
176 !CacheRegistryUtil.isActive() ||
177 (result == null)) {
178
179 return;
180 }
181
182 Serializable primaryKey = _resultToPrimaryKey((Serializable)result);
183
184 if (_LOCAL_CACHE_AVAILABLE) {
185 Map<Serializable, Serializable> localCache = _localCache.get();
186
187 Serializable localCacheKey = finderPath.encodeLocalCacheKey(args);
188
189 localCache.put(localCacheKey, primaryKey);
190 }
191
192 PortalCache<Serializable, Serializable> portalCache = _getPortalCache(
193 finderPath.getCacheName(), true);
194
195 Serializable cacheKey = finderPath.encodeCacheKey(args);
196
197 if (quiet) {
198 PortalCacheHelperUtil.putWithoutReplicator(
199 portalCache, cacheKey, primaryKey);
200 }
201 else {
202 portalCache.put(cacheKey, primaryKey);
203 }
204 }
205
206 @Override
207 public void removeCache(String className) {
208 _portalCaches.remove(className);
209
210 String groupKey = _GROUP_KEY_PREFIX.concat(className);
211
212 _multiVMPool.removeCache(groupKey);
213 }
214
215 @Override
216 public void removeResult(FinderPath finderPath, Object[] args) {
217 if (!PropsValues.VALUE_OBJECT_FINDER_CACHE_ENABLED ||
218 !finderPath.isFinderCacheEnabled() ||
219 !CacheRegistryUtil.isActive()) {
220
221 return;
222 }
223
224 if (_LOCAL_CACHE_AVAILABLE) {
225 Map<Serializable, Serializable> localCache = _localCache.get();
226
227 Serializable localCacheKey = finderPath.encodeLocalCacheKey(args);
228
229 localCache.remove(localCacheKey);
230 }
231
232 PortalCache<Serializable, Serializable> portalCache = _getPortalCache(
233 finderPath.getCacheName(), true);
234
235 Serializable cacheKey = finderPath.encodeCacheKey(args);
236
237 portalCache.remove(cacheKey);
238 }
239
240 public void setMultiVMPool(MultiVMPool multiVMPool) {
241 _multiVMPool = multiVMPool;
242
243 PortalCacheManager<? extends Serializable, ? extends Serializable>
244 portalCacheManager = _multiVMPool.getCacheManager();
245
246 portalCacheManager.registerCacheManagerListener(this);
247 }
248
249 private PortalCache<Serializable, Serializable> _getPortalCache(
250 String className, boolean createIfAbsent) {
251
252 PortalCache<Serializable, Serializable> portalCache = _portalCaches.get(
253 className);
254
255 if ((portalCache == null) && createIfAbsent) {
256 String groupKey = _GROUP_KEY_PREFIX.concat(className);
257
258 portalCache =
259 (PortalCache<Serializable, Serializable>)_multiVMPool.getCache(
260 groupKey, PropsValues.VALUE_OBJECT_FINDER_BLOCKING_CACHE);
261
262 PortalCache<Serializable, Serializable> previousPortalCache =
263 _portalCaches.putIfAbsent(className, portalCache);
264
265 if (previousPortalCache != null) {
266 portalCache = previousPortalCache;
267 }
268 }
269
270 return portalCache;
271 }
272
273 private Serializable _primaryKeyToResult(
274 FinderPath finderPath,
275 BasePersistenceImpl<? extends BaseModel<?>> basePersistenceImpl,
276 Serializable primaryKey) {
277
278 if (primaryKey instanceof List<?>) {
279 List<Serializable> primaryKeys = (List<Serializable>)primaryKey;
280
281 if (primaryKeys.isEmpty()) {
282 return (Serializable)Collections.emptyList();
283 }
284
285 Set<Serializable> primaryKeysSet = new HashSet<Serializable>(
286 primaryKeys);
287
288 Map<Serializable, ? extends BaseModel<?>> map =
289 basePersistenceImpl.fetchByPrimaryKeys(primaryKeysSet);
290
291 if (map.size() < primaryKeysSet.size()) {
292 return null;
293 }
294
295 List<Serializable> list = new ArrayList<Serializable>(
296 primaryKeys.size());
297
298 for (Serializable curPrimaryKey : primaryKeys) {
299 list.add(map.get(curPrimaryKey));
300 }
301
302 return (Serializable)Collections.unmodifiableList(list);
303 }
304 else if (BaseModel.class.isAssignableFrom(
305 finderPath.getResultClass())) {
306
307 return EntityCacheUtil.loadResult(
308 finderPath.isEntityCacheEnabled(), finderPath.getResultClass(),
309 primaryKey, basePersistenceImpl);
310 }
311
312 return primaryKey;
313 }
314
315 private Serializable _resultToPrimaryKey(Serializable result) {
316 if (result instanceof BaseModel<?>) {
317 BaseModel<?> model = (BaseModel<?>)result;
318
319 return model.getPrimaryKeyObj();
320 }
321 else if (result instanceof List<?>) {
322 List<Serializable> list = (List<Serializable>)result;
323
324 if (list.isEmpty()) {
325 return (Serializable)Collections.emptyList();
326 }
327
328 ArrayList<Serializable> cachedList = new ArrayList<Serializable>(
329 list.size());
330
331 for (Serializable curResult : list) {
332 Serializable primaryKey = _resultToPrimaryKey(curResult);
333
334 cachedList.add(primaryKey);
335 }
336
337 return cachedList;
338 }
339
340 return result;
341 }
342
343 private static final String _GROUP_KEY_PREFIX = CACHE_NAME.concat(
344 StringPool.PERIOD);
345
346 private static final boolean _LOCAL_CACHE_AVAILABLE;
347
348 private static final ThreadLocal<LRUMap> _localCache;
349
350 static {
351 if (PropsValues.VALUE_OBJECT_FINDER_THREAD_LOCAL_CACHE_MAX_SIZE > 0) {
352 _LOCAL_CACHE_AVAILABLE = true;
353
354 _localCache = new AutoResetThreadLocal<LRUMap>(
355 FinderCacheImpl.class + "._localCache",
356 new LRUMap(
357 PropsValues.
358 VALUE_OBJECT_FINDER_THREAD_LOCAL_CACHE_MAX_SIZE));
359 }
360 else {
361 _LOCAL_CACHE_AVAILABLE = false;
362
363 _localCache = null;
364 }
365 }
366
367 private MultiVMPool _multiVMPool;
368 private final ConcurrentMap<String, PortalCache<Serializable, Serializable>>
369 _portalCaches =
370 new ConcurrentHashMap
371 <String, PortalCache<Serializable, Serializable>>();
372
373 }