1   /**
2    * Copyright (c) 2000-2008 Liferay, Inc. All rights reserved.
3    *
4    * Permission is hereby granted, free of charge, to any person obtaining a copy
5    * of this software and associated documentation files (the "Software"), to deal
6    * in the Software without restriction, including without limitation the rights
7    * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8    * copies of the Software, and to permit persons to whom the Software is
9    * furnished to do so, subject to the following conditions:
10   *
11   * The above copyright notice and this permission notice shall be included in
12   * all copies or substantial portions of the Software.
13   *
14   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20   * SOFTWARE.
21   */
22  
23  package com.liferay.portal.spring.hibernate;
24  
25  import com.liferay.portal.kernel.cache.CacheKVP;
26  import com.liferay.portal.kernel.cache.CacheRegistry;
27  import com.liferay.portal.kernel.cache.CacheRegistryItem;
28  import com.liferay.portal.kernel.cache.MultiVMPoolUtil;
29  import com.liferay.portal.kernel.cache.PortalCache;
30  import com.liferay.portal.kernel.util.ArrayUtil;
31  import com.liferay.portal.kernel.util.GetterUtil;
32  import com.liferay.portal.kernel.util.StringMaker;
33  import com.liferay.portal.kernel.util.StringPool;
34  import com.liferay.portal.model.BaseModel;
35  import com.liferay.portal.util.PropsUtil;
36  
37  import java.io.Serializable;
38  
39  import java.util.ArrayList;
40  import java.util.List;
41  import java.util.Map;
42  import java.util.Set;
43  import java.util.concurrent.ConcurrentHashMap;
44  
45  import org.hibernate.Session;
46  import org.hibernate.SessionFactory;
47  
48  /**
49   * <a href="FinderCache.java.html"><b><i>View Source</i></b></a>
50   *
51   * @author Brian Wing Shun Chan
52   *
53   */
54  public class FinderCache implements CacheRegistryItem {
55  
56      public static final boolean CACHE_ENABLED = GetterUtil.getBoolean(
57          PropsUtil.get(PropsUtil.VALUE_OBJECT_FINDER_CACHE_ENABLED), true);
58  
59      public static final String CACHE_NAME = FinderCache.class.getName();
60  
61      public static void clearCache() {
62          _instance._clearCache();
63      }
64  
65      public static void clearCache(String className) {
66          _instance._clearCache(className);
67      }
68  
69      public static Object getResult(
70          String className, String methodName, String[] params, Object[] args) {
71  
72          return _instance._getResult(className, methodName, params, args);
73      }
74  
75      public static Object getResult(
76          String className, String methodName, String[] params, Object[] args,
77          SessionFactory sessionFactory) {
78  
79          return _instance._getResult(
80              className, methodName, params, args, sessionFactory);
81      }
82  
83      public static Object getResult(
84          String sql, String[] classNames, String methodName, String[] params,
85          Object[] args) {
86  
87          return _instance._getResult(sql, classNames, methodName, params, args);
88      }
89  
90      public static Object getResult(
91          String sql, String[] classNames, String methodName, String[] params,
92          Object[] args, SessionFactory sessionFactory) {
93  
94          return _instance._getResult(
95              sql, classNames, methodName, params, args, sessionFactory);
96      }
97  
98      public static void putResult(
99          boolean classNameCacheEnabled, String className, String methodName,
100         String[] params, Object[] args, Object result) {
101 
102         _instance._putResult(
103             classNameCacheEnabled, className, methodName, params, args, result);
104     }
105 
106     public static void putResult(
107         String sql, boolean[] classNamesCacheEnabled, String[] classNames,
108         String methodName, String[] params, Object[] args, Object result) {
109 
110         _instance._putResult(
111             sql, classNamesCacheEnabled, classNames, methodName, params, args,
112             result);
113     }
114 
115     public void invalidate() {
116         _clearCache();
117     }
118 
119     private FinderCache() {
120         CacheRegistry.register(this);
121     }
122 
123     private void _clearCache() {
124         _cache.removeAll();
125     }
126 
127     private void _clearCache(String className) {
128         String groupKey = _encodeGroupKey(className);
129 
130         MultiVMPoolUtil.clearGroup(_groups, groupKey, _cache);
131     }
132 
133     private Object _getResult(
134         String className, String methodName, String[] params, Object[] args) {
135 
136         return _getResult(className, methodName, params, args, null);
137     }
138 
139     private Object _getResult(
140         String className, String methodName, String[] params, Object[] args,
141         SessionFactory sessionFactory) {
142 
143         String key = _encodeKey(className, methodName, params, args);
144 
145         Object primaryKey = MultiVMPoolUtil.get(_cache, key);
146 
147         if (primaryKey != null) {
148             Session session = null;
149 
150             try {
151                 session = HibernateUtil.openSession(sessionFactory);
152 
153                 return _primaryKeyToResult(session, primaryKey);
154             }
155             finally {
156                 HibernateUtil.closeSession(session);
157             }
158         }
159         else {
160             return null;
161         }
162     }
163 
164     private Object _getResult(
165         String sql, String[] classNames, String methodName, String[] params,
166         Object[] args) {
167 
168         return _getResult(sql, classNames, methodName, params, args, null);
169     }
170 
171     private Object _getResult(
172         String sql, String[] classNames, String methodName, String[] params,
173         Object[] args, SessionFactory sessionFactory) {
174 
175         String key = _encodeKey(sql, methodName, params, args);
176 
177         Object primaryKey = MultiVMPoolUtil.get(_cache, key);
178 
179         if (primaryKey != null) {
180             Session session = null;
181 
182             try {
183                 session = HibernateUtil.openSession(sessionFactory);
184 
185                 return _primaryKeyToResult(session, primaryKey);
186             }
187             finally {
188                 HibernateUtil.closeSession(session);
189             }
190         }
191         else {
192             return null;
193         }
194     }
195 
196     private void _putResult(
197         boolean classNameCacheEnabled, String className, String methodName,
198         String[] params, Object[] args, Object result) {
199 
200         if (classNameCacheEnabled && CACHE_ENABLED &&
201             CacheRegistry.isActive() && (result != null)) {
202 
203             String key = _encodeKey(className, methodName, params, args);
204 
205             String groupKey = _encodeGroupKey(className);
206 
207             MultiVMPoolUtil.put(
208                 _cache, key, _groups, groupKey, _resultToPrimaryKey(result));
209         }
210     }
211 
212     private void _putResult(
213         String sql, boolean[] classNamesCacheEnabled, String[] classNames,
214         String methodName, String[] params, Object[] args, Object result) {
215 
216         if (ArrayUtil.contains(classNamesCacheEnabled, false)) {
217             return;
218         }
219 
220         if (CACHE_ENABLED && CacheRegistry.isActive() && (result != null)) {
221             String key = _encodeKey(sql, methodName, params, args);
222 
223             for (String className : classNames) {
224                 String groupKey = _encodeGroupKey(className);
225 
226                 MultiVMPoolUtil.updateGroup(_groups, groupKey, key);
227             }
228 
229             MultiVMPoolUtil.put(_cache, key, _resultToPrimaryKey(result));
230         }
231     }
232 
233     private String _encodeGroupKey(String className) {
234         StringMaker sm = new StringMaker();
235 
236         sm.append(CACHE_NAME);
237         sm.append(StringPool.POUND);
238         sm.append(className);
239 
240         return sm.toString();
241     }
242 
243     private String _encodeKey(
244         String className, String methodName, String[] params, Object[] args) {
245 
246         StringMaker sm = new StringMaker();
247 
248         sm.append(CACHE_NAME);
249         sm.append(StringPool.POUND);
250         sm.append(className);
251         sm.append(StringPool.POUND);
252         sm.append(methodName);
253         sm.append(_PARAMS_SEPARATOR);
254 
255         for (String param : params) {
256             sm.append(StringPool.POUND);
257             sm.append(param);
258         }
259 
260         sm.append(_ARGS_SEPARATOR);
261 
262         for (Object arg : args) {
263             sm.append(StringPool.POUND);
264             sm.append(String.valueOf(arg));
265         }
266 
267         return sm.toString();
268     }
269 
270     private Object _primaryKeyToResult(
271         Session session, Object primaryKey) {
272 
273         if (primaryKey instanceof CacheKVP) {
274             CacheKVP cacheKVP = (CacheKVP)primaryKey;
275 
276             Class<?> modelClass = cacheKVP.getModelClass();
277             Serializable primaryKeyObj = cacheKVP.getPrimaryKeyObj();
278 
279             return session.load(modelClass, primaryKeyObj);
280         }
281         else if (primaryKey instanceof List) {
282             List<Object> cachedList = (List<Object>)primaryKey;
283 
284             List<Object> list = new ArrayList<Object>(cachedList.size());
285 
286             for (Object curPrimaryKey : cachedList) {
287                 Object result = _primaryKeyToResult(session, curPrimaryKey);
288 
289                 list.add(result);
290             }
291 
292             return list;
293         }
294         else {
295             return primaryKey;
296         }
297     }
298 
299     private Object _resultToPrimaryKey(Object result) {
300         if (result instanceof BaseModel) {
301             BaseModel model = (BaseModel)result;
302 
303             Class<?> modelClass = model.getClass();
304             Serializable primaryKeyObj = model.getPrimaryKeyObj();
305 
306             return new CacheKVP(modelClass, primaryKeyObj);
307         }
308         else if (result instanceof List) {
309             List<Object> list = (List<Object>)result;
310 
311             List<Object> cachedList = new ArrayList<Object>(list.size());
312 
313             for (Object curResult : list) {
314                 Object primaryKey = _resultToPrimaryKey(curResult);
315 
316                 cachedList.add(primaryKey);
317             }
318 
319             return cachedList;
320         }
321         else {
322             return result;
323         }
324     }
325 
326     private static final String _ARGS_SEPARATOR = "_ARGS_SEPARATOR_";
327 
328     private static final String _PARAMS_SEPARATOR = "_PARAMS_SEPARATOR_";
329 
330     private static FinderCache _instance = new FinderCache();
331 
332     private PortalCache _cache = MultiVMPoolUtil.getCache(CACHE_NAME);
333 
334     private Map<String, Set<String>> _groups =
335         new ConcurrentHashMap<String, Set<String>>();
336 
337 }