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 import java.util.concurrent.ConcurrentMap;
38
39 import org.apache.commons.collections.map.LRUMap;
40
41
46 public class FinderCacheImpl implements CacheRegistryItem, FinderCache {
47
48 public static final String CACHE_NAME = FinderCache.class.getName();
49
50 public void afterPropertiesSet() {
51 CacheRegistry.register(this);
52 }
53
54 public void clearCache() {
55 clearLocalCache();
56
57 for (PortalCache portalCache : _portalCaches.values()) {
58 portalCache.removeAll();
59 }
60 }
61
62 public void clearCache(String className) {
63 clearLocalCache();
64
65 PortalCache portalCache = _getPortalCache(className, false);
66
67 if (portalCache != null) {
68 portalCache.removeAll();
69 }
70 }
71
72 public void clearLocalCache() {
73 if (_localCacheAvailable) {
74 _localCache.remove();
75 }
76 }
77
78 public String getRegistryName() {
79 return CACHE_NAME;
80 }
81
82 public Object getResult(
83 FinderPath finderPath, Object[] args, SessionFactory sessionFactory) {
84
85 if (!PropsValues.VALUE_OBJECT_FINDER_CACHE_ENABLED ||
86 !finderPath.isFinderCacheEnabled() || !CacheRegistry.isActive()) {
87
88 return null;
89 }
90
91 Object primaryKey = null;
92
93 Map<String, Object> localCache = null;
94
95 String localCacheKey = null;
96
97 if (_localCacheAvailable) {
98 localCache = _localCache.get();
99
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() || !CacheRegistry.isActive() ||
135 (result == null)) {
136
137 return;
138 }
139
140 Object primaryKey = _resultToPrimaryKey(result);
141
142 if (_localCacheAvailable) {
143 Map<String, Object> localCache = _localCache.get();
144
145 String localCacheKey = finderPath.encodeLocalCacheKey(args);
146
147 localCache.put(localCacheKey, primaryKey);
148 }
149
150 PortalCache portalCache = _getPortalCache(
151 finderPath.getClassName(), true);
152
153 String cacheKey = finderPath.encodeCacheKey(args);
154
155 portalCache.put(cacheKey, primaryKey);
156 }
157
158 public void removeResult(FinderPath finderPath, Object[] args) {
159 if (!PropsValues.VALUE_OBJECT_FINDER_CACHE_ENABLED ||
160 !finderPath.isFinderCacheEnabled() || !CacheRegistry.isActive()) {
161
162 return;
163 }
164
165 if (_localCacheAvailable) {
166 Map<String, Object> localCache = _localCache.get();
167
168 String localCacheKey = finderPath.encodeLocalCacheKey(args);
169
170 localCache.remove(localCacheKey);
171 }
172
173 PortalCache portalCache = _getPortalCache(
174 finderPath.getClassName(), true);
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(
186 String className, boolean createIfAbsent) {
187 String groupKey = _GROUP_KEY_PREFIX.concat(className);
188
189 PortalCache portalCache = _portalCaches.get(groupKey);
190
191 if ((portalCache == null) && createIfAbsent) {
192 portalCache = _multiVMPool.getCache(
193 groupKey, PropsValues.VALUE_OBJECT_FINDER_BLOCKING_CACHE);
194
195 PortalCache previousPortalCache = _portalCaches.putIfAbsent(
196 groupKey, portalCache);
197
198 if (previousPortalCache != null) {
199 portalCache = previousPortalCache;
200 }
201
202 portalCache.setDebug(true);
203 }
204
205 return portalCache;
206 }
207
208 private Object _primaryKeyToResult(
209 FinderPath finderPath, SessionFactory sessionFactory,
210 Object primaryKey) {
211
212 if (primaryKey instanceof CacheKVP) {
213 CacheKVP cacheKVP = (CacheKVP)primaryKey;
214
215 Class<?> modelClass = cacheKVP.getModelClass();
216 Serializable primaryKeyObj = cacheKVP.getPrimaryKeyObj();
217
218 return EntityCacheUtil.loadResult(
219 finderPath.isEntityCacheEnabled(), modelClass, primaryKeyObj,
220 sessionFactory);
221 }
222 else if (primaryKey instanceof List<?>) {
223 List<Object> cachedList = (List<Object>)primaryKey;
224
225 List<Object> list = new ArrayList<Object>(cachedList.size());
226
227 for (Object curPrimaryKey : cachedList) {
228 Object result = _primaryKeyToResult(
229 finderPath, sessionFactory, curPrimaryKey);
230
231 list.add(result);
232 }
233
234 return list;
235 }
236 else {
237 return primaryKey;
238 }
239 }
240
241 private Object _resultToPrimaryKey(Object result) {
242 if (result instanceof BaseModel<?>) {
243 BaseModel<?> model = (BaseModel<?>)result;
244
245 Class<?> modelClass = model.getClass();
246 Serializable primaryKeyObj = model.getPrimaryKeyObj();
247
248 return new CacheKVP(modelClass, primaryKeyObj);
249 }
250 else if (result instanceof List<?>) {
251 List<Object> list = (List<Object>)result;
252
253 List<Object> cachedList = new ArrayList<Object>(list.size());
254
255 for (Object curResult : list) {
256 Object primaryKey = _resultToPrimaryKey(curResult);
257
258 cachedList.add(primaryKey);
259 }
260
261 return cachedList;
262 }
263 else {
264 return result;
265 }
266 }
267
268 private static final String _GROUP_KEY_PREFIX = CACHE_NAME.concat(
269 StringPool.PERIOD);
270
271 private static ThreadLocal<LRUMap> _localCache;
272 private static boolean _localCacheAvailable;
273
274 static {
275 if (PropsValues.VALUE_OBJECT_FINDER_THREAD_LOCAL_CACHE_MAX_SIZE > 0) {
276 _localCache = new AutoResetThreadLocal<LRUMap>(
277 FinderCacheImpl.class + "._localCache",
278 new LRUMap(
279 PropsValues.
280 VALUE_OBJECT_FINDER_THREAD_LOCAL_CACHE_MAX_SIZE));
281 _localCacheAvailable = true;
282 }
283 }
284
285 private MultiVMPool _multiVMPool;
286 private ConcurrentMap<String, PortalCache> _portalCaches =
287 new ConcurrentHashMap<String, PortalCache>();
288
289 }