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