1
22
23 package com.liferay.portal.dao.orm.common;
24
25 import com.liferay.portal.kernel.cache.CacheKVP;
26 import com.liferay.portal.kernel.cache.CacheRegistry;
27 import com.liferay.portal.kernel.cache.CacheRegistryItem;
28 import com.liferay.portal.kernel.cache.MultiVMPool;
29 import com.liferay.portal.kernel.cache.PortalCache;
30 import com.liferay.portal.kernel.dao.orm.EntityCacheUtil;
31 import com.liferay.portal.kernel.dao.orm.FinderCache;
32 import com.liferay.portal.kernel.dao.orm.FinderPath;
33 import com.liferay.portal.kernel.dao.orm.SessionFactory;
34 import com.liferay.portal.kernel.util.InitialThreadLocal;
35 import com.liferay.portal.kernel.util.StringPool;
36 import com.liferay.portal.model.BaseModel;
37 import com.liferay.portal.util.PropsValues;
38
39 import java.io.Serializable;
40
41 import java.util.ArrayList;
42 import java.util.List;
43 import java.util.Map;
44 import java.util.concurrent.ConcurrentHashMap;
45
46 import org.apache.commons.collections.map.LRUMap;
47
48
53 public class FinderCacheImpl implements CacheRegistryItem, FinderCache {
54
55 public static final String CACHE_NAME = FinderCache.class.getName();
56
57 public void afterPropertiesSet() {
58 CacheRegistry.register(this);
59 }
60
61 public void clearCache() {
62 clearLocalCache();
63
64 PortalCache[] portalCaches = _portalCaches.values().toArray(
65 new PortalCache[_portalCaches.size()]);
66
67 for (PortalCache portalCache : portalCaches) {
68 portalCache.removeAll();
69 }
70 }
71
72 public void clearCache(String className) {
73 clearLocalCache();
74
75 PortalCache portalCache = _getPortalCache(className);
76
77 portalCache.removeAll();
78 }
79
80 public void clearLocalCache() {
81 if (_localCacheEnabled.get().booleanValue()) {
82 Map<String, Object> localCache = _localCache.get();
83
84 localCache.clear();
85 }
86 }
87
88 public String getRegistryName() {
89 return CACHE_NAME;
90 }
91
92 public Object getResult(
93 FinderPath finderPath, Object[] args, SessionFactory sessionFactory) {
94
95 if (!PropsValues.VALUE_OBJECT_FINDER_CACHE_ENABLED ||
96 !finderPath.isFinderCacheEnabled() || !CacheRegistry.isActive()) {
97
98 return null;
99 }
100
101 Object primaryKey = null;
102
103 Map<String, Object> localCache = null;
104
105 String localCacheKey = null;
106
107 if (_localCacheEnabled.get().booleanValue()) {
108 localCache = _localCache.get();
109
110 localCacheKey = _encodeLocalCacheKey(
111 finderPath.getClassName(), finderPath.getMethodName(),
112 finderPath.getParams(), args);
113
114 primaryKey = localCache.get(localCacheKey);
115 }
116
117 if (primaryKey == null) {
118 PortalCache portalCache = _getPortalCache(
119 finderPath.getClassName());
120
121 String cacheKey = _encodeCacheKey(
122 finderPath.getMethodName(), finderPath.getParams(), args);
123
124 primaryKey = _multiVMPool.get(portalCache, cacheKey);
125
126 if (primaryKey != null) {
127 if (_localCacheEnabled.get().booleanValue()) {
128 localCache.put(localCacheKey, primaryKey);
129 }
130 }
131 }
132
133 if (primaryKey != null) {
134 return _primaryKeyToResult(finderPath, sessionFactory, primaryKey);
135 }
136 else {
137 return null;
138 }
139 }
140
141 public void invalidate() {
142 clearCache();
143 }
144
145 public void putResult(FinderPath finderPath, Object[] args, Object result) {
146 if (!PropsValues.VALUE_OBJECT_FINDER_CACHE_ENABLED ||
147 !finderPath.isFinderCacheEnabled() || !CacheRegistry.isActive() ||
148 (result == null)) {
149
150 return;
151 }
152
153 Object primaryKey = _resultToPrimaryKey(result);
154
155 if (_localCacheEnabled.get().booleanValue()) {
156 Map<String, Object> localCache = _localCache.get();
157
158 String localCacheKey = _encodeLocalCacheKey(
159 finderPath.getClassName(), finderPath.getMethodName(),
160 finderPath.getParams(), args);
161
162 localCache.put(localCacheKey, primaryKey);
163 }
164
165 PortalCache portalCache = _getPortalCache(finderPath.getClassName());
166
167 String cacheKey = _encodeCacheKey(
168 finderPath.getMethodName(), finderPath.getParams(), args);
169
170 _multiVMPool.put(portalCache, cacheKey, primaryKey);
171 }
172
173 public void removeResult(FinderPath finderPath, Object[] args) {
174 if (!PropsValues.VALUE_OBJECT_FINDER_CACHE_ENABLED ||
175 !finderPath.isFinderCacheEnabled() || !CacheRegistry.isActive()) {
176
177 return;
178 }
179
180 if (_localCacheEnabled.get().booleanValue()) {
181 Map<String, Object> localCache = _localCache.get();
182
183 String localCacheKey = _encodeLocalCacheKey(
184 finderPath.getClassName(), finderPath.getMethodName(),
185 finderPath.getParams(), args);
186
187 localCache.remove(localCacheKey);
188 }
189
190 PortalCache portalCache = _getPortalCache(finderPath.getClassName());
191
192 String cacheKey = _encodeCacheKey(
193 finderPath.getMethodName(), finderPath.getParams(), args);
194
195 _multiVMPool.remove(portalCache, cacheKey);
196 }
197
198 public void setLocalCacheEnabled(boolean localCacheEnabled) {
199 if (_localCacheAvailable) {
200 _localCacheEnabled.set(Boolean.valueOf(localCacheEnabled));
201 }
202 }
203
204 public void setMultiVMPool(MultiVMPool multiVMPool) {
205 _multiVMPool = multiVMPool;
206 }
207
208 private String _encodeCacheKey(
209 String methodName, String[] params, Object[] args) {
210
211 StringBuilder sb = new StringBuilder();
212
213 sb.append(methodName);
214 sb.append(_PARAMS_SEPARATOR);
215
216 for (String param : params) {
217 sb.append(StringPool.PERIOD);
218 sb.append(param);
219 }
220
221 sb.append(_ARGS_SEPARATOR);
222
223 for (Object arg : args) {
224 sb.append(StringPool.PERIOD);
225 sb.append(String.valueOf(arg));
226 }
227
228 return sb.toString();
229 }
230
231 private String _encodeGroupKey(String className) {
232 StringBuilder sb = new StringBuilder();
233
234 sb.append(CACHE_NAME);
235 sb.append(StringPool.PERIOD);
236 sb.append(className);
237
238 return sb.toString();
239 }
240
241 private String _encodeLocalCacheKey(
242 String className, String methodName, String[] params, Object[] args) {
243
244 StringBuilder sb = new StringBuilder();
245
246 sb.append(className);
247 sb.append(StringPool.PERIOD);
248 sb.append(methodName);
249 sb.append(_PARAMS_SEPARATOR);
250
251 for (String param : params) {
252 sb.append(StringPool.PERIOD);
253 sb.append(param);
254 }
255
256 sb.append(_ARGS_SEPARATOR);
257
258 for (Object arg : args) {
259 sb.append(StringPool.PERIOD);
260 sb.append(String.valueOf(arg));
261 }
262
263 return sb.toString();
264 }
265
266 private PortalCache _getPortalCache(String className) {
267 String groupKey = _encodeGroupKey(className);
268
269 PortalCache portalCache = _portalCaches.get(groupKey);
270
271 if (portalCache == null) {
272 portalCache = _multiVMPool.getCache(
273 groupKey, PropsValues.VALUE_OBJECT_FINDER_BLOCKING_CACHE);
274
275 _portalCaches.put(groupKey, portalCache);
276 }
277
278 return portalCache;
279 }
280
281 private Object _primaryKeyToResult(
282 FinderPath finderPath, SessionFactory sessionFactory,
283 Object primaryKey) {
284
285 if (primaryKey instanceof CacheKVP) {
286 CacheKVP cacheKVP = (CacheKVP)primaryKey;
287
288 Class<?> modelClass = cacheKVP.getModelClass();
289 Serializable primaryKeyObj = cacheKVP.getPrimaryKeyObj();
290
291 return EntityCacheUtil.loadResult(
292 finderPath.isEntityCacheEnabled(), modelClass, primaryKeyObj,
293 sessionFactory);
294 }
295 else if (primaryKey instanceof List) {
296 List<Object> cachedList = (List<Object>)primaryKey;
297
298 List<Object> list = new ArrayList<Object>(cachedList.size());
299
300 for (Object curPrimaryKey : cachedList) {
301 Object result = _primaryKeyToResult(
302 finderPath, sessionFactory, curPrimaryKey);
303
304 list.add(result);
305 }
306
307 return list;
308 }
309 else {
310 return primaryKey;
311 }
312 }
313
314 private Object _resultToPrimaryKey(Object result) {
315 if (result instanceof BaseModel) {
316 BaseModel<?> model = (BaseModel<?>)result;
317
318 Class<?> modelClass = model.getClass();
319 Serializable primaryKeyObj = model.getPrimaryKeyObj();
320
321 return new CacheKVP(modelClass, primaryKeyObj);
322 }
323 else if (result instanceof List) {
324 List<Object> list = (List<Object>)result;
325
326 List<Object> cachedList = new ArrayList<Object>(list.size());
327
328 for (Object curResult : list) {
329 Object primaryKey = _resultToPrimaryKey(curResult);
330
331 cachedList.add(primaryKey);
332 }
333
334 return cachedList;
335 }
336 else {
337 return result;
338 }
339 }
340
341 private static final String _ARGS_SEPARATOR = "_A_";
342
343 private static final String _PARAMS_SEPARATOR = "_P_";
344
345 private static ThreadLocal<Map> _localCache;
346 private static boolean _localCacheAvailable;
347 private static ThreadLocal<Boolean> _localCacheEnabled =
348 new InitialThreadLocal<Boolean>(Boolean.FALSE);
349
350 static {
351 if (PropsValues.VALUE_OBJECT_FINDER_THREAD_LOCAL_CACHE_MAX_SIZE > 0) {
352 _localCache = new InitialThreadLocal<Map>(new LRUMap(
353 PropsValues.VALUE_OBJECT_FINDER_THREAD_LOCAL_CACHE_MAX_SIZE));
354 _localCacheAvailable = true;
355 }
356 }
357
358 private MultiVMPool _multiVMPool;
359 private Map<String, PortalCache> _portalCaches =
360 new ConcurrentHashMap<String, PortalCache>();
361
362 }