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