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