1
14
15 package com.liferay.portal.dao.orm.common;
16
17 import com.liferay.portal.kernel.cache.CacheKVP;
18 import com.liferay.portal.kernel.cache.CacheRegistry;
19 import com.liferay.portal.kernel.cache.CacheRegistryItem;
20 import com.liferay.portal.kernel.cache.MultiVMPool;
21 import com.liferay.portal.kernel.cache.PortalCache;
22 import com.liferay.portal.kernel.dao.orm.EntityCacheUtil;
23 import com.liferay.portal.kernel.dao.orm.FinderCache;
24 import com.liferay.portal.kernel.dao.orm.FinderPath;
25 import com.liferay.portal.kernel.dao.orm.SessionFactory;
26 import com.liferay.portal.kernel.util.AutoResetThreadLocal;
27 import com.liferay.portal.kernel.util.StringPool;
28 import com.liferay.portal.model.BaseModel;
29 import com.liferay.portal.util.PropsValues;
30
31 import java.io.Serializable;
32
33 import java.util.ArrayList;
34 import java.util.List;
35 import java.util.Map;
36 import java.util.concurrent.ConcurrentHashMap;
37
38 import org.apache.commons.collections.map.LRUMap;
39
40
45 public class FinderCacheImpl implements CacheRegistryItem, FinderCache {
46
47 public static final String CACHE_NAME = FinderCache.class.getName();
48
49 public void afterPropertiesSet() {
50 CacheRegistry.register(this);
51 }
52
53 public void clearCache() {
54 clearLocalCache();
55
56 PortalCache[] portalCaches = _portalCaches.values().toArray(
57 new PortalCache[_portalCaches.size()]);
58
59 for (PortalCache portalCache : portalCaches) {
60 portalCache.removeAll();
61 }
62 }
63
64 public void clearCache(String className) {
65 clearLocalCache();
66
67 PortalCache portalCache = _getPortalCache(className);
68
69 portalCache.removeAll();
70 }
71
72 public void clearLocalCache() {
73 if (_localCacheAvailable) {
74 Map<String, Object> localCache = _localCache.get();
75
76 localCache.clear();
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());
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(finderPath.getClassName());
153
154 String cacheKey = finderPath.encodeCacheKey(args);
155
156 portalCache.put(cacheKey, primaryKey);
157 }
158
159 public void removeResult(FinderPath finderPath, Object[] args) {
160 if (!PropsValues.VALUE_OBJECT_FINDER_CACHE_ENABLED ||
161 !finderPath.isFinderCacheEnabled() || !CacheRegistry.isActive()) {
162
163 return;
164 }
165
166 if (_localCacheAvailable) {
167 Map<String, Object> localCache = _localCache.get();
168
169 String localCacheKey = finderPath.encodeLocalCacheKey(args);
170
171 localCache.remove(localCacheKey);
172 }
173
174 PortalCache portalCache = _getPortalCache(finderPath.getClassName());
175
176 String cacheKey = finderPath.encodeCacheKey(args);
177
178 portalCache.remove(cacheKey);
179 }
180
181 public void setMultiVMPool(MultiVMPool multiVMPool) {
182 _multiVMPool = multiVMPool;
183 }
184
185 private PortalCache _getPortalCache(String className) {
186 String groupKey = _GROUP_KEY_PREFIX.concat(className);
187
188 PortalCache portalCache = _portalCaches.get(groupKey);
189
190 if (portalCache == null) {
191 portalCache = _multiVMPool.getCache(
192 groupKey, PropsValues.VALUE_OBJECT_FINDER_BLOCKING_CACHE);
193
194 _portalCaches.put(groupKey, portalCache);
195 }
196
197 return portalCache;
198 }
199
200 private Object _primaryKeyToResult(
201 FinderPath finderPath, SessionFactory sessionFactory,
202 Object primaryKey) {
203
204 if (primaryKey instanceof CacheKVP) {
205 CacheKVP cacheKVP = (CacheKVP)primaryKey;
206
207 Class<?> modelClass = cacheKVP.getModelClass();
208 Serializable primaryKeyObj = cacheKVP.getPrimaryKeyObj();
209
210 return EntityCacheUtil.loadResult(
211 finderPath.isEntityCacheEnabled(), modelClass, primaryKeyObj,
212 sessionFactory);
213 }
214 else if (primaryKey instanceof List<?>) {
215 List<Object> cachedList = (List<Object>)primaryKey;
216
217 List<Object> list = new ArrayList<Object>(cachedList.size());
218
219 for (Object curPrimaryKey : cachedList) {
220 Object result = _primaryKeyToResult(
221 finderPath, sessionFactory, curPrimaryKey);
222
223 list.add(result);
224 }
225
226 return list;
227 }
228 else {
229 return primaryKey;
230 }
231 }
232
233 private Object _resultToPrimaryKey(Object result) {
234 if (result instanceof BaseModel<?>) {
235 BaseModel<?> model = (BaseModel<?>)result;
236
237 Class<?> modelClass = model.getClass();
238 Serializable primaryKeyObj = model.getPrimaryKeyObj();
239
240 return new CacheKVP(modelClass, primaryKeyObj);
241 }
242 else if (result instanceof List<?>) {
243 List<Object> list = (List<Object>)result;
244
245 List<Object> cachedList = new ArrayList<Object>(list.size());
246
247 for (Object curResult : list) {
248 Object primaryKey = _resultToPrimaryKey(curResult);
249
250 cachedList.add(primaryKey);
251 }
252
253 return cachedList;
254 }
255 else {
256 return result;
257 }
258 }
259
260 private static final String _GROUP_KEY_PREFIX = CACHE_NAME.concat(
261 StringPool.PERIOD);
262
263 private static ThreadLocal<LRUMap> _localCache;
264 private static boolean _localCacheAvailable;
265
266 static {
267 if (PropsValues.VALUE_OBJECT_FINDER_THREAD_LOCAL_CACHE_MAX_SIZE > 0) {
268 _localCache = new AutoResetThreadLocal<LRUMap>(new LRUMap(
269 PropsValues.VALUE_OBJECT_FINDER_THREAD_LOCAL_CACHE_MAX_SIZE));
270 _localCacheAvailable = true;
271 }
272 }
273
274 private MultiVMPool _multiVMPool;
275 private Map<String, PortalCache> _portalCaches =
276 new ConcurrentHashMap<String, PortalCache>();
277
278 }