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.EntityCacheUtil;
022 import com.liferay.portal.kernel.dao.orm.FinderCache;
023 import com.liferay.portal.kernel.dao.orm.FinderPath;
024 import com.liferay.portal.kernel.dao.orm.SessionFactory;
025 import com.liferay.portal.kernel.security.pacl.DoPrivileged;
026 import com.liferay.portal.kernel.util.AutoResetThreadLocal;
027 import com.liferay.portal.kernel.util.StringPool;
028 import com.liferay.portal.kernel.util.UnmodifiableList;
029 import com.liferay.portal.model.BaseModel;
030 import com.liferay.portal.util.PropsValues;
031
032 import java.io.Serializable;
033
034 import java.util.ArrayList;
035 import java.util.Collections;
036 import java.util.List;
037 import java.util.Map;
038 import java.util.concurrent.ConcurrentHashMap;
039 import java.util.concurrent.ConcurrentMap;
040
041 import org.apache.commons.collections.map.LRUMap;
042
043
047 @DoPrivileged
048 public class FinderCacheImpl implements CacheRegistryItem, FinderCache {
049
050 public static final String CACHE_NAME = FinderCache.class.getName();
051
052 public void afterPropertiesSet() {
053 CacheRegistryUtil.register(this);
054 }
055
056 @Override
057 public void clearCache() {
058 clearLocalCache();
059
060 for (PortalCache<?, ?> portalCache : _portalCaches.values()) {
061 portalCache.removeAll();
062 }
063 }
064
065 @Override
066 public void clearCache(String className) {
067 clearLocalCache();
068
069 PortalCache<?, ?> portalCache = _getPortalCache(className, true);
070
071 if (portalCache != null) {
072 portalCache.removeAll();
073 }
074 }
075
076 @Override
077 public void clearLocalCache() {
078 if (_localCacheAvailable) {
079 _localCache.remove();
080 }
081 }
082
083 @Override
084 public String getRegistryName() {
085 return CACHE_NAME;
086 }
087
088 @Override
089 public Object getResult(
090 FinderPath finderPath, Object[] args, SessionFactory sessionFactory) {
091
092 if (!PropsValues.VALUE_OBJECT_FINDER_CACHE_ENABLED ||
093 !finderPath.isFinderCacheEnabled() ||
094 !CacheRegistryUtil.isActive()) {
095
096 return null;
097 }
098
099 Serializable primaryKey = null;
100
101 Map<Serializable, Serializable> localCache = null;
102
103 Serializable localCacheKey = null;
104
105 if (_localCacheAvailable) {
106 localCache = _localCache.get();
107
108 localCacheKey = finderPath.encodeLocalCacheKey(args);
109
110 primaryKey = localCache.get(localCacheKey);
111 }
112
113 if (primaryKey == null) {
114 PortalCache<Serializable, Serializable> portalCache =
115 _getPortalCache(finderPath.getCacheName(), true);
116
117 Serializable cacheKey = finderPath.encodeCacheKey(args);
118
119 primaryKey = portalCache.get(cacheKey);
120
121 if (primaryKey != null) {
122 if (_localCacheAvailable) {
123 localCache.put(localCacheKey, primaryKey);
124 }
125 }
126 }
127
128 if (primaryKey != null) {
129 return _primaryKeyToResult(finderPath, sessionFactory, primaryKey);
130 }
131 else {
132 return null;
133 }
134 }
135
136 @Override
137 public void invalidate() {
138 clearCache();
139 }
140
141 @Override
142 public void putResult(FinderPath finderPath, Object[] args, Object result) {
143 if (!PropsValues.VALUE_OBJECT_FINDER_CACHE_ENABLED ||
144 !finderPath.isFinderCacheEnabled() ||
145 !CacheRegistryUtil.isActive() ||
146 (result == null)) {
147
148 return;
149 }
150
151 Serializable primaryKey = _resultToPrimaryKey((Serializable)result);
152
153 if (_localCacheAvailable) {
154 Map<Serializable, Serializable> localCache = _localCache.get();
155
156 Serializable localCacheKey = finderPath.encodeLocalCacheKey(args);
157
158 localCache.put(localCacheKey, primaryKey);
159 }
160
161 PortalCache<Serializable, Serializable> portalCache = _getPortalCache(
162 finderPath.getCacheName(), true);
163
164 Serializable cacheKey = finderPath.encodeCacheKey(args);
165
166 portalCache.put(cacheKey, primaryKey);
167 }
168
169 @Override
170 public void removeCache(String className) {
171 _portalCaches.remove(className);
172
173 String groupKey = _GROUP_KEY_PREFIX.concat(className);
174
175 _multiVMPool.removeCache(groupKey);
176 }
177
178 @Override
179 public void removeResult(FinderPath finderPath, Object[] args) {
180 if (!PropsValues.VALUE_OBJECT_FINDER_CACHE_ENABLED ||
181 !finderPath.isFinderCacheEnabled() ||
182 !CacheRegistryUtil.isActive()) {
183
184 return;
185 }
186
187 if (_localCacheAvailable) {
188 Map<Serializable, Serializable> localCache = _localCache.get();
189
190 Serializable localCacheKey = finderPath.encodeLocalCacheKey(args);
191
192 localCache.remove(localCacheKey);
193 }
194
195 PortalCache<Serializable, Serializable> portalCache = _getPortalCache(
196 finderPath.getCacheName(), true);
197
198 Serializable cacheKey = finderPath.encodeCacheKey(args);
199
200 portalCache.remove(cacheKey);
201 }
202
203 public void setMultiVMPool(MultiVMPool multiVMPool) {
204 _multiVMPool = multiVMPool;
205 }
206
207 private PortalCache<Serializable, Serializable> _getPortalCache(
208 String className, boolean createIfAbsent) {
209
210 PortalCache<Serializable, Serializable> portalCache = _portalCaches.get(
211 className);
212
213 if ((portalCache == null) && createIfAbsent) {
214 String groupKey = _GROUP_KEY_PREFIX.concat(className);
215
216 portalCache =
217 (PortalCache<Serializable, Serializable>)_multiVMPool.getCache(
218 groupKey, PropsValues.VALUE_OBJECT_FINDER_BLOCKING_CACHE);
219
220 PortalCache<Serializable, Serializable> previousPortalCache =
221 _portalCaches.putIfAbsent(className, portalCache);
222
223 if (previousPortalCache != null) {
224 portalCache = previousPortalCache;
225 }
226 }
227
228 return portalCache;
229 }
230
231 private Serializable _primaryKeyToResult(
232 FinderPath finderPath, SessionFactory sessionFactory,
233 Serializable primaryKey) {
234
235 if (primaryKey instanceof List<?>) {
236 List<Serializable> cachedList = (List<Serializable>)primaryKey;
237
238 if (cachedList.isEmpty()) {
239 return (Serializable)Collections.emptyList();
240 }
241
242 List<Serializable> list = new ArrayList<Serializable>(
243 cachedList.size());
244
245 for (Serializable curPrimaryKey : cachedList) {
246 Serializable result = _primaryKeyToResult(
247 finderPath, sessionFactory, curPrimaryKey);
248
249 list.add(result);
250 }
251
252 list = new UnmodifiableList<Serializable>(list);
253
254 return (Serializable)list;
255 }
256 else if (BaseModel.class.isAssignableFrom(
257 finderPath.getResultClass())) {
258
259 return EntityCacheUtil.loadResult(
260 finderPath.isEntityCacheEnabled(), finderPath.getResultClass(),
261 primaryKey, sessionFactory);
262 }
263 else {
264 return primaryKey;
265 }
266 }
267
268 private Serializable _resultToPrimaryKey(Serializable result) {
269 if (result instanceof BaseModel<?>) {
270 BaseModel<?> model = (BaseModel<?>)result;
271
272 return model.getPrimaryKeyObj();
273 }
274 else if (result instanceof List<?>) {
275 List<Serializable> list = (List<Serializable>)result;
276
277 if (list.isEmpty()) {
278 return (Serializable)Collections.emptyList();
279 }
280
281 ArrayList<Serializable> cachedList = new ArrayList<Serializable>(
282 list.size());
283
284 for (Serializable curResult : list) {
285 Serializable primaryKey = _resultToPrimaryKey(curResult);
286
287 cachedList.add(primaryKey);
288 }
289
290 return cachedList;
291 }
292 else {
293 return result;
294 }
295 }
296
297 private static final String _GROUP_KEY_PREFIX = CACHE_NAME.concat(
298 StringPool.PERIOD);
299
300 private static ThreadLocal<LRUMap> _localCache;
301 private static boolean _localCacheAvailable;
302
303 static {
304 if (PropsValues.VALUE_OBJECT_FINDER_THREAD_LOCAL_CACHE_MAX_SIZE > 0) {
305 _localCache = new AutoResetThreadLocal<LRUMap>(
306 FinderCacheImpl.class + "._localCache",
307 new LRUMap(
308 PropsValues.
309 VALUE_OBJECT_FINDER_THREAD_LOCAL_CACHE_MAX_SIZE));
310 _localCacheAvailable = true;
311 }
312 }
313
314 private MultiVMPool _multiVMPool;
315 private ConcurrentMap<String, PortalCache<Serializable, Serializable>>
316 _portalCaches =
317 new ConcurrentHashMap
318 <String, PortalCache<Serializable, Serializable>>();
319
320 }