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