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