1
14
15 package com.liferay.portal.dao.orm.common;
16
17 import com.liferay.portal.cache.transactional.TransactionalPortalCache;
18 import com.liferay.portal.kernel.cache.CacheKVP;
19 import com.liferay.portal.kernel.cache.CacheRegistry;
20 import com.liferay.portal.kernel.cache.CacheRegistryItem;
21 import com.liferay.portal.kernel.cache.MultiVMPool;
22 import com.liferay.portal.kernel.cache.PortalCache;
23 import com.liferay.portal.kernel.dao.orm.EntityCacheUtil;
24 import com.liferay.portal.kernel.dao.orm.FinderCache;
25 import com.liferay.portal.kernel.dao.orm.FinderPath;
26 import com.liferay.portal.kernel.dao.orm.SessionFactory;
27 import com.liferay.portal.kernel.util.AutoResetThreadLocal;
28 import com.liferay.portal.kernel.util.StringPool;
29 import com.liferay.portal.model.BaseModel;
30 import com.liferay.portal.util.PropsValues;
31
32 import java.io.Serializable;
33
34 import java.util.ArrayList;
35 import java.util.Collections;
36 import java.util.List;
37 import java.util.Map;
38 import java.util.concurrent.ConcurrentHashMap;
39 import java.util.concurrent.ConcurrentMap;
40
41 import org.apache.commons.collections.map.LRUMap;
42
43
48 public class FinderCacheImpl implements CacheRegistryItem, FinderCache {
49
50 public static final String CACHE_NAME = FinderCache.class.getName();
51
52 public void afterPropertiesSet() {
53 CacheRegistry.register(this);
54 }
55
56 public void clearCache() {
57 clearLocalCache();
58
59 for (PortalCache portalCache : _portalCaches.values()) {
60 portalCache.removeAll();
61 }
62 }
63
64 public void clearCache(String className) {
65 clearLocalCache();
66
67 PortalCache portalCache = _getPortalCache(className, false);
68
69 if (portalCache != null) {
70 portalCache.removeAll();
71 }
72 }
73
74 public void clearLocalCache() {
75 if (_localCacheAvailable) {
76 _localCache.remove();
77 }
78 }
79
80 public String getRegistryName() {
81 return CACHE_NAME;
82 }
83
84 public Object getResult(
85 FinderPath finderPath, Object[] args, SessionFactory sessionFactory) {
86
87 if (!PropsValues.VALUE_OBJECT_FINDER_CACHE_ENABLED ||
88 !finderPath.isFinderCacheEnabled() || !CacheRegistry.isActive()) {
89
90 return null;
91 }
92
93 Object primaryKey = null;
94
95 Map<String, Object> localCache = null;
96
97 String localCacheKey = null;
98
99 if (_localCacheAvailable) {
100 localCache = _localCache.get();
101
102 localCacheKey = finderPath.encodeLocalCacheKey(args);
103
104 primaryKey = localCache.get(localCacheKey);
105 }
106
107 if (primaryKey == null) {
108 PortalCache portalCache = _getPortalCache(
109 finderPath.getClassName(), true);
110
111 String cacheKey = finderPath.encodeCacheKey(args);
112
113 primaryKey = portalCache.get(cacheKey);
114
115 if (primaryKey != null) {
116 if (_localCacheAvailable) {
117 localCache.put(localCacheKey, primaryKey);
118 }
119 }
120 }
121
122 if (primaryKey != null) {
123 return _primaryKeyToResult(finderPath, sessionFactory, primaryKey);
124 }
125 else {
126 return null;
127 }
128 }
129
130 public void invalidate() {
131 clearCache();
132 }
133
134 public void putResult(FinderPath finderPath, Object[] args, Object result) {
135 if (!PropsValues.VALUE_OBJECT_FINDER_CACHE_ENABLED ||
136 !finderPath.isFinderCacheEnabled() || !CacheRegistry.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() || !CacheRegistry.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 if (PropsValues.TRANSACTIONAL_CACHE_ENABLED) {
206 portalCache = new TransactionalPortalCache(portalCache);
207 }
208
209 PortalCache previousPortalCache = _portalCaches.putIfAbsent(
210 groupKey, portalCache);
211
212 if (previousPortalCache != null) {
213 portalCache = previousPortalCache;
214 }
215
216 portalCache.setDebug(true);
217 }
218
219 return portalCache;
220 }
221
222 private Object _primaryKeyToResult(
223 FinderPath finderPath, SessionFactory sessionFactory,
224 Object primaryKey) {
225
226 if (primaryKey instanceof CacheKVP) {
227 CacheKVP cacheKVP = (CacheKVP)primaryKey;
228
229 Class<?> modelClass = cacheKVP.getModelClass();
230 Serializable primaryKeyObj = cacheKVP.getPrimaryKeyObj();
231
232 return EntityCacheUtil.loadResult(
233 finderPath.isEntityCacheEnabled(), modelClass, primaryKeyObj,
234 sessionFactory);
235 }
236 else if (primaryKey instanceof List<?>) {
237 List<Object> cachedList = (List<Object>)primaryKey;
238
239 if (cachedList.isEmpty()) {
240 return Collections.EMPTY_LIST;
241 }
242
243 List<Object> list = new ArrayList<Object>(cachedList.size());
244
245 for (Object curPrimaryKey : cachedList) {
246 Object result = _primaryKeyToResult(
247 finderPath, sessionFactory, curPrimaryKey);
248
249 list.add(result);
250 }
251
252 return list;
253 }
254 else {
255 return primaryKey;
256 }
257 }
258
259 private Object _resultToPrimaryKey(Object result) {
260 if (result instanceof BaseModel<?>) {
261 BaseModel<?> model = (BaseModel<?>)result;
262
263 Class<?> modelClass = model.getClass();
264 Serializable primaryKeyObj = model.getPrimaryKeyObj();
265
266 return new CacheKVP(modelClass, primaryKeyObj);
267 }
268 else if (result instanceof List<?>) {
269 List<Object> list = (List<Object>)result;
270
271 if (list.isEmpty()) {
272 return Collections.EMPTY_LIST;
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>(new LRUMap(
299 PropsValues.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 }