001
014
015 package com.liferay.portal.dao.orm.common;
016
017 import com.liferay.portal.kernel.cache.CacheKVP;
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.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
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, false);
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 Object primaryKey = null;
092
093 Map<String, Object> localCache = null;
094
095 String 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 portalCache = _getPortalCache(
107 finderPath.getClassName(), true);
108
109 String 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 Object primaryKey = _resultToPrimaryKey(result);
142
143 if (_localCacheAvailable) {
144 Map<String, Object> localCache = _localCache.get();
145
146 String localCacheKey = finderPath.encodeLocalCacheKey(args);
147
148 localCache.put(localCacheKey, primaryKey);
149 }
150
151 PortalCache portalCache = _getPortalCache(
152 finderPath.getClassName(), true);
153
154 String cacheKey = finderPath.encodeCacheKey(args);
155
156 portalCache.put(cacheKey, primaryKey);
157 }
158
159 public void removeCache(String className) {
160 String groupKey = _GROUP_KEY_PREFIX.concat(className);
161
162 _portalCaches.remove(groupKey);
163 _multiVMPool.removeCache(groupKey);
164 }
165
166 public void removeResult(FinderPath finderPath, Object[] args) {
167 if (!PropsValues.VALUE_OBJECT_FINDER_CACHE_ENABLED ||
168 !finderPath.isFinderCacheEnabled() ||
169 !CacheRegistryUtil.isActive()) {
170
171 return;
172 }
173
174 if (_localCacheAvailable) {
175 Map<String, Object> localCache = _localCache.get();
176
177 String localCacheKey = finderPath.encodeLocalCacheKey(args);
178
179 localCache.remove(localCacheKey);
180 }
181
182 PortalCache portalCache = _getPortalCache(
183 finderPath.getClassName(), true);
184
185 String cacheKey = finderPath.encodeCacheKey(args);
186
187 portalCache.remove(cacheKey);
188 }
189
190 public void setMultiVMPool(MultiVMPool multiVMPool) {
191 _multiVMPool = multiVMPool;
192 }
193
194 private PortalCache _getPortalCache(
195 String className, boolean createIfAbsent) {
196
197 String groupKey = _GROUP_KEY_PREFIX.concat(className);
198
199 PortalCache portalCache = _portalCaches.get(groupKey);
200
201 if ((portalCache == null) && createIfAbsent) {
202 portalCache = _multiVMPool.getCache(
203 groupKey, PropsValues.VALUE_OBJECT_FINDER_BLOCKING_CACHE);
204
205 PortalCache previousPortalCache = _portalCaches.putIfAbsent(
206 groupKey, portalCache);
207
208 if (previousPortalCache != null) {
209 portalCache = previousPortalCache;
210 }
211
212 portalCache.setDebug(true);
213 }
214
215 return portalCache;
216 }
217
218 private Object _primaryKeyToResult(
219 FinderPath finderPath, SessionFactory sessionFactory,
220 Object primaryKey) {
221
222 if (primaryKey instanceof CacheKVP) {
223 CacheKVP cacheKVP = (CacheKVP)primaryKey;
224
225 Class<?> modelClass = cacheKVP.getModelClass();
226 Serializable primaryKeyObj = cacheKVP.getPrimaryKeyObj();
227
228 return EntityCacheUtil.loadResult(
229 finderPath.isEntityCacheEnabled(), modelClass, primaryKeyObj,
230 sessionFactory);
231 }
232 else if (primaryKey instanceof List<?>) {
233 List<Object> cachedList = (List<Object>)primaryKey;
234
235 if (cachedList.isEmpty()) {
236 return Collections.EMPTY_LIST;
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 {
251 return primaryKey;
252 }
253 }
254
255 private Object _resultToPrimaryKey(Object result) {
256 if (result instanceof BaseModel<?>) {
257 BaseModel<?> model = (BaseModel<?>)result;
258
259 Class<?> modelClass = model.getClass();
260 Serializable primaryKeyObj = model.getPrimaryKeyObj();
261
262 return new CacheKVP(modelClass, primaryKeyObj);
263 }
264 else if (result instanceof List<?>) {
265 List<Object> list = (List<Object>)result;
266
267 if (list.isEmpty()) {
268 return Collections.EMPTY_LIST;
269 }
270
271 List<Object> cachedList = new ArrayList<Object>(list.size());
272
273 for (Object curResult : list) {
274 Object primaryKey = _resultToPrimaryKey(curResult);
275
276 cachedList.add(primaryKey);
277 }
278
279 return cachedList;
280 }
281 else {
282 return result;
283 }
284 }
285
286 private static final String _GROUP_KEY_PREFIX = CACHE_NAME.concat(
287 StringPool.PERIOD);
288
289 private static ThreadLocal<LRUMap> _localCache;
290 private static boolean _localCacheAvailable;
291
292 static {
293 if (PropsValues.VALUE_OBJECT_FINDER_THREAD_LOCAL_CACHE_MAX_SIZE > 0) {
294 _localCache = new AutoResetThreadLocal<LRUMap>(
295 FinderCacheImpl.class + "._localCache",
296 new LRUMap(
297 PropsValues.
298 VALUE_OBJECT_FINDER_THREAD_LOCAL_CACHE_MAX_SIZE));
299 _localCacheAvailable = true;
300 }
301 }
302
303 private MultiVMPool _multiVMPool;
304 private ConcurrentMap<String, PortalCache> _portalCaches =
305 new ConcurrentHashMap<String, PortalCache>();
306
307 }