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