001
014
015 package com.liferay.portal.dao.orm.common;
016
017 import com.liferay.portal.kernel.cache.CacheRegistryItem;
018 import com.liferay.portal.kernel.cache.CacheRegistryUtil;
019 import com.liferay.portal.kernel.cache.MultiVMPool;
020 import com.liferay.portal.kernel.cache.PortalCache;
021 import com.liferay.portal.kernel.dao.orm.EntityCacheUtil;
022 import com.liferay.portal.kernel.dao.orm.FinderCache;
023 import com.liferay.portal.kernel.dao.orm.FinderPath;
024 import com.liferay.portal.kernel.dao.orm.SessionFactory;
025 import com.liferay.portal.kernel.util.AutoResetThreadLocal;
026 import com.liferay.portal.kernel.util.StringPool;
027 import com.liferay.portal.model.BaseModel;
028 import com.liferay.portal.util.PropsValues;
029
030 import java.io.Serializable;
031
032 import java.util.ArrayList;
033 import java.util.Collections;
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
045 public class FinderCacheImpl implements CacheRegistryItem, FinderCache {
046
047 public static final String CACHE_NAME = FinderCache.class.getName();
048
049 public void afterPropertiesSet() {
050 CacheRegistryUtil.register(this);
051 }
052
053 public void clearCache() {
054 clearLocalCache();
055
056 for (PortalCache portalCache : _portalCaches.values()) {
057 portalCache.removeAll();
058 }
059 }
060
061 public void clearCache(String className) {
062 clearLocalCache();
063
064 PortalCache portalCache = _getPortalCache(className, false);
065
066 if (portalCache != null) {
067 portalCache.removeAll();
068 }
069 }
070
071 public void clearLocalCache() {
072 if (_localCacheAvailable) {
073 _localCache.remove();
074 }
075 }
076
077 public String getRegistryName() {
078 return CACHE_NAME;
079 }
080
081 public Object getResult(
082 FinderPath finderPath, Object[] args, SessionFactory sessionFactory) {
083
084 if (!PropsValues.VALUE_OBJECT_FINDER_CACHE_ENABLED ||
085 !finderPath.isFinderCacheEnabled() ||
086 !CacheRegistryUtil.isActive()) {
087
088 return null;
089 }
090
091 Object primaryKey = null;
092
093 Map<Serializable, Object> localCache = null;
094
095 Serializable localCacheKey = null;
096
097 if (_localCacheAvailable) {
098 localCache = _localCache.get();
099
100 localCacheKey = finderPath.encodeLocalCacheKey(args);
101
102 primaryKey = localCache.get(localCacheKey);
103 }
104
105 if (primaryKey == null) {
106 PortalCache portalCache = _getPortalCache(
107 finderPath.getCacheName(), true);
108
109 Serializable 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() ||
135 !CacheRegistryUtil.isActive() ||
136 (result == null)) {
137
138 return;
139 }
140
141 Object primaryKey = _resultToPrimaryKey(result);
142
143 if (_localCacheAvailable) {
144 Map<Serializable, Object> localCache = _localCache.get();
145
146 Serializable localCacheKey = finderPath.encodeLocalCacheKey(args);
147
148 localCache.put(localCacheKey, primaryKey);
149 }
150
151 PortalCache portalCache = _getPortalCache(
152 finderPath.getCacheName(), true);
153
154 Serializable cacheKey = finderPath.encodeCacheKey(args);
155
156 portalCache.put(cacheKey, primaryKey);
157 }
158
159 public void removeCache(String className) {
160 _portalCaches.remove(className);
161
162 String groupKey = _GROUP_KEY_PREFIX.concat(className);
163
164 _multiVMPool.removeCache(groupKey);
165 }
166
167 public void removeResult(FinderPath finderPath, Object[] args) {
168 if (!PropsValues.VALUE_OBJECT_FINDER_CACHE_ENABLED ||
169 !finderPath.isFinderCacheEnabled() ||
170 !CacheRegistryUtil.isActive()) {
171
172 return;
173 }
174
175 if (_localCacheAvailable) {
176 Map<Serializable, Object> localCache = _localCache.get();
177
178 Serializable localCacheKey = finderPath.encodeLocalCacheKey(args);
179
180 localCache.remove(localCacheKey);
181 }
182
183 PortalCache portalCache = _getPortalCache(
184 finderPath.getCacheName(), true);
185
186 Serializable cacheKey = finderPath.encodeCacheKey(args);
187
188 portalCache.remove(cacheKey);
189 }
190
191 public void setMultiVMPool(MultiVMPool multiVMPool) {
192 _multiVMPool = multiVMPool;
193 }
194
195 private PortalCache _getPortalCache(
196 String className, boolean createIfAbsent) {
197
198 PortalCache portalCache = _portalCaches.get(className);
199
200 if ((portalCache == null) && createIfAbsent) {
201 String groupKey = _GROUP_KEY_PREFIX.concat(className);
202
203 portalCache = _multiVMPool.getCache(
204 groupKey, PropsValues.VALUE_OBJECT_FINDER_BLOCKING_CACHE);
205
206 PortalCache previousPortalCache = _portalCaches.putIfAbsent(
207 className, portalCache);
208
209 if (previousPortalCache != null) {
210 portalCache = previousPortalCache;
211 }
212 }
213
214 return portalCache;
215 }
216
217 private Object _primaryKeyToResult(
218 FinderPath finderPath, SessionFactory sessionFactory,
219 Object primaryKey) {
220
221 if (primaryKey instanceof List<?>) {
222 List<Object> cachedList = (List<Object>)primaryKey;
223
224 if (cachedList.isEmpty()) {
225 return Collections.emptyList();
226 }
227
228 List<Object> list = new ArrayList<Object>(cachedList.size());
229
230 for (Object curPrimaryKey : cachedList) {
231 Object result = _primaryKeyToResult(
232 finderPath, sessionFactory, curPrimaryKey);
233
234 list.add(result);
235 }
236
237 return list;
238 }
239 else if (BaseModel.class.isAssignableFrom(
240 finderPath.getResultClass())) {
241
242 return EntityCacheUtil.loadResult(
243 finderPath.isEntityCacheEnabled(), finderPath.getResultClass(),
244 (Serializable)primaryKey, sessionFactory);
245 }
246 else {
247 return primaryKey;
248 }
249 }
250
251 private Object _resultToPrimaryKey(Object result) {
252 if (result instanceof BaseModel<?>) {
253 BaseModel<?> model = (BaseModel<?>)result;
254
255 return model.getPrimaryKeyObj();
256 }
257 else if (result instanceof List<?>) {
258 List<Object> list = (List<Object>)result;
259
260 if (list.isEmpty()) {
261 return Collections.emptyList();
262 }
263
264 List<Object> cachedList = new ArrayList<Object>(list.size());
265
266 for (Object curResult : list) {
267 Object primaryKey = _resultToPrimaryKey(curResult);
268
269 cachedList.add(primaryKey);
270 }
271
272 return cachedList;
273 }
274 else {
275 return result;
276 }
277 }
278
279 private static final String _GROUP_KEY_PREFIX = CACHE_NAME.concat(
280 StringPool.PERIOD);
281
282 private static ThreadLocal<LRUMap> _localCache;
283 private static boolean _localCacheAvailable;
284
285 static {
286 if (PropsValues.VALUE_OBJECT_FINDER_THREAD_LOCAL_CACHE_MAX_SIZE > 0) {
287 _localCache = new AutoResetThreadLocal<LRUMap>(
288 FinderCacheImpl.class + "._localCache",
289 new LRUMap(
290 PropsValues.
291 VALUE_OBJECT_FINDER_THREAD_LOCAL_CACHE_MAX_SIZE));
292 _localCacheAvailable = true;
293 }
294 }
295
296 private MultiVMPool _multiVMPool;
297 private ConcurrentMap<String, PortalCache> _portalCaches =
298 new ConcurrentHashMap<String, PortalCache>();
299
300 }