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