001
014
015 package com.liferay.portal.dao.orm.common;
016
017 import com.liferay.portal.kernel.cache.CacheKVP;
018 import com.liferay.portal.kernel.cache.CacheRegistryItem;
019 import com.liferay.portal.kernel.cache.CacheRegistryUtil;
020 import com.liferay.portal.kernel.cache.MultiVMPool;
021 import com.liferay.portal.kernel.cache.PortalCache;
022 import com.liferay.portal.kernel.dao.orm.EntityCacheUtil;
023 import com.liferay.portal.kernel.dao.orm.FinderCache;
024 import com.liferay.portal.kernel.dao.orm.FinderPath;
025 import com.liferay.portal.kernel.dao.orm.SessionFactory;
026 import com.liferay.portal.kernel.util.AutoResetThreadLocal;
027 import com.liferay.portal.kernel.util.StringPool;
028 import com.liferay.portal.model.BaseModel;
029 import com.liferay.portal.util.PropsValues;
030
031 import java.io.Serializable;
032
033 import java.util.ArrayList;
034 import java.util.List;
035 import java.util.Map;
036 import java.util.concurrent.ConcurrentHashMap;
037 import java.util.concurrent.ConcurrentMap;
038
039 import org.apache.commons.collections.map.LRUMap;
040
041
044 public class FinderCacheImpl implements CacheRegistryItem, FinderCache {
045
046 public static final String CACHE_NAME = FinderCache.class.getName();
047
048 public void afterPropertiesSet() {
049 CacheRegistryUtil.register(this);
050 }
051
052 public void clearCache() {
053 clearLocalCache();
054
055 for (PortalCache portalCache : _portalCaches.values()) {
056 portalCache.removeAll();
057 }
058 }
059
060 public void clearCache(String className) {
061 clearLocalCache();
062
063 PortalCache portalCache = _getPortalCache(className, false);
064
065 if (portalCache != null) {
066 portalCache.removeAll();
067 }
068 }
069
070 public void clearLocalCache() {
071 if (_localCacheAvailable) {
072 _localCache.remove();
073 }
074 }
075
076 public String getRegistryName() {
077 return CACHE_NAME;
078 }
079
080 public Object getResult(
081 FinderPath finderPath, Object[] args, SessionFactory sessionFactory) {
082
083 if (!PropsValues.VALUE_OBJECT_FINDER_CACHE_ENABLED ||
084 !finderPath.isFinderCacheEnabled() ||
085 !CacheRegistryUtil.isActive()) {
086
087 return null;
088 }
089
090 Object primaryKey = null;
091
092 Map<String, Object> localCache = null;
093
094 String localCacheKey = null;
095
096 if (_localCacheAvailable) {
097 localCache = _localCache.get();
098
099 localCacheKey = finderPath.encodeLocalCacheKey(args);
100
101 primaryKey = localCache.get(localCacheKey);
102 }
103
104 if (primaryKey == null) {
105 PortalCache portalCache = _getPortalCache(
106 finderPath.getClassName(), true);
107
108 String cacheKey = finderPath.encodeCacheKey(args);
109
110 primaryKey = portalCache.get(cacheKey);
111
112 if (primaryKey != null) {
113 if (_localCacheAvailable) {
114 localCache.put(localCacheKey, primaryKey);
115 }
116 }
117 }
118
119 if (primaryKey != null) {
120 return _primaryKeyToResult(finderPath, sessionFactory, primaryKey);
121 }
122 else {
123 return null;
124 }
125 }
126
127 public void invalidate() {
128 clearCache();
129 }
130
131 public void putResult(FinderPath finderPath, Object[] args, Object result) {
132 if (!PropsValues.VALUE_OBJECT_FINDER_CACHE_ENABLED ||
133 !finderPath.isFinderCacheEnabled() ||
134 !CacheRegistryUtil.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() ||
161 !CacheRegistryUtil.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(
175 finderPath.getClassName(), true);
176
177 String cacheKey = finderPath.encodeCacheKey(args);
178
179 portalCache.remove(cacheKey);
180 }
181
182 public void setMultiVMPool(MultiVMPool multiVMPool) {
183 _multiVMPool = multiVMPool;
184 }
185
186 private PortalCache _getPortalCache(
187 String className, boolean createIfAbsent) {
188 String groupKey = _GROUP_KEY_PREFIX.concat(className);
189
190 PortalCache portalCache = _portalCaches.get(groupKey);
191
192 if ((portalCache == null) && createIfAbsent) {
193 portalCache = _multiVMPool.getCache(
194 groupKey, PropsValues.VALUE_OBJECT_FINDER_BLOCKING_CACHE);
195
196 PortalCache previousPortalCache = _portalCaches.putIfAbsent(
197 groupKey, portalCache);
198
199 if (previousPortalCache != null) {
200 portalCache = previousPortalCache;
201 }
202
203 portalCache.setDebug(true);
204 }
205
206 return portalCache;
207 }
208
209 private Object _primaryKeyToResult(
210 FinderPath finderPath, SessionFactory sessionFactory,
211 Object primaryKey) {
212
213 if (primaryKey instanceof CacheKVP) {
214 CacheKVP cacheKVP = (CacheKVP)primaryKey;
215
216 Class<?> modelClass = cacheKVP.getModelClass();
217 Serializable primaryKeyObj = cacheKVP.getPrimaryKeyObj();
218
219 return EntityCacheUtil.loadResult(
220 finderPath.isEntityCacheEnabled(), modelClass, primaryKeyObj,
221 sessionFactory);
222 }
223 else if (primaryKey instanceof List<?>) {
224 List<Object> cachedList = (List<Object>)primaryKey;
225
226 List<Object> list = new ArrayList<Object>(cachedList.size());
227
228 for (Object curPrimaryKey : cachedList) {
229 Object result = _primaryKeyToResult(
230 finderPath, sessionFactory, curPrimaryKey);
231
232 list.add(result);
233 }
234
235 return list;
236 }
237 else {
238 return primaryKey;
239 }
240 }
241
242 private Object _resultToPrimaryKey(Object result) {
243 if (result instanceof BaseModel<?>) {
244 BaseModel<?> model = (BaseModel<?>)result;
245
246 Class<?> modelClass = model.getClass();
247 Serializable primaryKeyObj = model.getPrimaryKeyObj();
248
249 return new CacheKVP(modelClass, primaryKeyObj);
250 }
251 else if (result instanceof List<?>) {
252 List<Object> list = (List<Object>)result;
253
254 List<Object> cachedList = new ArrayList<Object>(list.size());
255
256 for (Object curResult : list) {
257 Object primaryKey = _resultToPrimaryKey(curResult);
258
259 cachedList.add(primaryKey);
260 }
261
262 return cachedList;
263 }
264 else {
265 return result;
266 }
267 }
268
269 private static final String _GROUP_KEY_PREFIX = CACHE_NAME.concat(
270 StringPool.PERIOD);
271
272 private static ThreadLocal<LRUMap> _localCache;
273 private static boolean _localCacheAvailable;
274
275 static {
276 if (PropsValues.VALUE_OBJECT_FINDER_THREAD_LOCAL_CACHE_MAX_SIZE > 0) {
277 _localCache = new AutoResetThreadLocal<LRUMap>(
278 FinderCacheImpl.class + "._localCache",
279 new LRUMap(
280 PropsValues.
281 VALUE_OBJECT_FINDER_THREAD_LOCAL_CACHE_MAX_SIZE));
282 _localCacheAvailable = true;
283 }
284 }
285
286 private MultiVMPool _multiVMPool;
287 private ConcurrentMap<String, PortalCache> _portalCaches =
288 new ConcurrentHashMap<String, PortalCache>();
289
290 }