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 portalCacheName) {
158 }
159
160 @Override
161 public void notifyCacheRemoved(String portalCacheName) {
162 _portalCaches.remove(portalCacheName);
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() || (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 PortalCacheHelperUtil.putWithoutReplicator(
198 portalCache, cacheKey, primaryKey);
199 }
200 else {
201 portalCache.put(cacheKey, primaryKey);
202 }
203 }
204
205 @Override
206 public void removeCache(String className) {
207 _portalCaches.remove(className);
208
209 String groupKey = _GROUP_KEY_PREFIX.concat(className);
210
211 _multiVMPool.removeCache(groupKey);
212 }
213
214 @Override
215 public void removeResult(FinderPath finderPath, Object[] args) {
216 if (!PropsValues.VALUE_OBJECT_FINDER_CACHE_ENABLED ||
217 !finderPath.isFinderCacheEnabled() ||
218 !CacheRegistryUtil.isActive()) {
219
220 return;
221 }
222
223 if (_LOCAL_CACHE_AVAILABLE) {
224 Map<Serializable, Serializable> localCache = _localCache.get();
225
226 Serializable localCacheKey = finderPath.encodeLocalCacheKey(args);
227
228 localCache.remove(localCacheKey);
229 }
230
231 PortalCache<Serializable, Serializable> portalCache = _getPortalCache(
232 finderPath.getCacheName(), true);
233
234 Serializable cacheKey = finderPath.encodeCacheKey(args);
235
236 portalCache.remove(cacheKey);
237 }
238
239 public void setMultiVMPool(MultiVMPool multiVMPool) {
240 _multiVMPool = multiVMPool;
241
242 PortalCacheManager<? extends Serializable, ? extends Serializable>
243 portalCacheManager = _multiVMPool.getCacheManager();
244
245 portalCacheManager.registerCacheManagerListener(this);
246 }
247
248 private PortalCache<Serializable, Serializable> _getPortalCache(
249 String className, boolean createIfAbsent) {
250
251 PortalCache<Serializable, Serializable> portalCache = _portalCaches.get(
252 className);
253
254 if ((portalCache == null) && createIfAbsent) {
255 String groupKey = _GROUP_KEY_PREFIX.concat(className);
256
257 portalCache =
258 (PortalCache<Serializable, Serializable>)_multiVMPool.getCache(
259 groupKey, PropsValues.VALUE_OBJECT_FINDER_BLOCKING_CACHE);
260
261 PortalCache<Serializable, Serializable> previousPortalCache =
262 _portalCaches.putIfAbsent(className, portalCache);
263
264 if (previousPortalCache != null) {
265 portalCache = previousPortalCache;
266 }
267 }
268
269 return portalCache;
270 }
271
272 private Serializable _primaryKeyToResult(
273 FinderPath finderPath,
274 BasePersistenceImpl<? extends BaseModel<?>> basePersistenceImpl,
275 Serializable primaryKey) {
276
277 if (primaryKey instanceof List<?>) {
278 List<Serializable> primaryKeys = (List<Serializable>)primaryKey;
279
280 if (primaryKeys.isEmpty()) {
281 return (Serializable)Collections.emptyList();
282 }
283
284 Set<Serializable> primaryKeysSet = new HashSet<>(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<>(primaryKeys.size());
294
295 for (Serializable curPrimaryKey : primaryKeys) {
296 list.add(map.get(curPrimaryKey));
297 }
298
299 return (Serializable)Collections.unmodifiableList(list);
300 }
301 else if (BaseModel.class.isAssignableFrom(
302 finderPath.getResultClass())) {
303
304 return EntityCacheUtil.loadResult(
305 finderPath.isEntityCacheEnabled(), finderPath.getResultClass(),
306 primaryKey, basePersistenceImpl);
307 }
308
309 return primaryKey;
310 }
311
312 private Serializable _resultToPrimaryKey(Serializable result) {
313 if (result instanceof BaseModel<?>) {
314 BaseModel<?> model = (BaseModel<?>)result;
315
316 return model.getPrimaryKeyObj();
317 }
318 else if (result instanceof List<?>) {
319 List<Serializable> list = (List<Serializable>)result;
320
321 if (list.isEmpty()) {
322 return (Serializable)Collections.emptyList();
323 }
324
325 ArrayList<Serializable> cachedList = new ArrayList<>(list.size());
326
327 for (Serializable curResult : list) {
328 Serializable primaryKey = _resultToPrimaryKey(curResult);
329
330 cachedList.add(primaryKey);
331 }
332
333 return cachedList;
334 }
335
336 return result;
337 }
338
339 private static final String _GROUP_KEY_PREFIX = CACHE_NAME.concat(
340 StringPool.PERIOD);
341
342 private static final boolean _LOCAL_CACHE_AVAILABLE;
343
344 private static final ThreadLocal<LRUMap> _localCache;
345
346 static {
347 if (PropsValues.VALUE_OBJECT_FINDER_THREAD_LOCAL_CACHE_MAX_SIZE > 0) {
348 _LOCAL_CACHE_AVAILABLE = true;
349
350 _localCache = new AutoResetThreadLocal<LRUMap>(
351 FinderCacheImpl.class + "._localCache",
352 new LRUMap(
353 PropsValues.
354 VALUE_OBJECT_FINDER_THREAD_LOCAL_CACHE_MAX_SIZE));
355 }
356 else {
357 _LOCAL_CACHE_AVAILABLE = false;
358
359 _localCache = null;
360 }
361 }
362
363 private MultiVMPool _multiVMPool;
364 private final ConcurrentMap<String, PortalCache<Serializable, Serializable>>
365 _portalCaches = new ConcurrentHashMap<>();
366
367 }