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  import com.liferay.util.CollectionFactory;
37  
38  import java.io.Serializable;
39  
40  import java.util.ArrayList;
41  import java.util.List;
42  import java.util.Map;
43  
44  import org.hibernate.Session;
45  import org.hibernate.SessionFactory;
46  
47  /**
48   * <a href="FinderCache.java.html"><b><i>View Source</i></b></a>
49   *
50   * @author Brian Wing Shun Chan
51   *
52   */
53  public class FinderCache implements CacheRegistryItem {
54  
55      public static final boolean CACHE_ENABLED = GetterUtil.getBoolean(
56          PropsUtil.get(PropsUtil.VALUE_OBJECT_FINDER_CACHE_ENABLED), true);
57  
58      public static final String CACHE_NAME = FinderCache.class.getName();
59  
60      public static void clearCache() {
61          _instance._clearCache();
62      }
63  
64      public static void clearCache(String className) {
65          _instance._clearCache(className);
66      }
67  
68      public static Object getResult(
69          String className, String methodName, String[] params, Object[] args) {
70  
71          return _instance._getResult(className, methodName, params, args);
72      }
73  
74      public static Object getResult(
75          String className, String methodName, String[] params, Object[] args,
76          SessionFactory sessionFactory) {
77  
78          return _instance._getResult(
79              className, methodName, params, args, sessionFactory);
80      }
81  
82      public static Object getResult(
83          String sql, String[] classNames, String methodName, String[] params,
84          Object[] args) {
85  
86          return _instance._getResult(sql, classNames, methodName, params, args);
87      }
88  
89      public static Object getResult(
90          String sql, String[] classNames, String methodName, String[] params,
91          Object[] args, SessionFactory sessionFactory) {
92  
93          return _instance._getResult(
94              sql, classNames, methodName, params, args, sessionFactory);
95      }
96  
97      public static void putResult(
98          boolean classNameCacheEnabled, String className, String methodName,
99          String[] params, Object[] args, Object result) {
100 
101         _instance._putResult(
102             classNameCacheEnabled, className, methodName, params, args, result);
103     }
104 
105     public static void putResult(
106         String sql, boolean[] classNamesCacheEnabled, String[] classNames,
107         String methodName, String[] params, Object[] args, Object result) {
108 
109         _instance._putResult(
110             sql, classNamesCacheEnabled, classNames, methodName, params, args,
111             result);
112     }
113 
114     public void invalidate() {
115         _clearCache();
116     }
117 
118     private FinderCache() {
119         CacheRegistry.register(this);
120     }
121 
122     private void _clearCache() {
123         _cache.removeAll();
124     }
125 
126     private void _clearCache(String className) {
127         String groupKey = _encodeGroupKey(className);
128 
129         MultiVMPoolUtil.clearGroup(_groups, groupKey, _cache);
130     }
131 
132     private Object _getResult(
133         String className, String methodName, String[] params, Object[] args) {
134 
135         return _getResult(className, methodName, params, args, null);
136     }
137 
138     private Object _getResult(
139         String className, String methodName, String[] params, Object[] args,
140         SessionFactory sessionFactory) {
141 
142         String key = _encodeKey(className, methodName, params, args);
143 
144         Object primaryKey = MultiVMPoolUtil.get(_cache, key);
145 
146         if (primaryKey != null) {
147             Session session = null;
148 
149             try {
150                 session = HibernateUtil.openSession(sessionFactory);
151 
152                 return _primaryKeyToResult(session, primaryKey);
153             }
154             finally {
155                 HibernateUtil.closeSession(session);
156             }
157         }
158         else {
159             return null;
160         }
161     }
162 
163     private Object _getResult(
164         String sql, String[] classNames, String methodName, String[] params,
165         Object[] args) {
166 
167         return _getResult(sql, classNames, methodName, params, args, null);
168     }
169 
170     private Object _getResult(
171         String sql, String[] classNames, String methodName, String[] params,
172         Object[] args, SessionFactory sessionFactory) {
173 
174         String key = _encodeKey(sql, methodName, params, args);
175 
176         Object primaryKey = MultiVMPoolUtil.get(_cache, key);
177 
178         if (primaryKey != null) {
179             Session session = null;
180 
181             try {
182                 session = HibernateUtil.openSession(sessionFactory);
183 
184                 return _primaryKeyToResult(session, primaryKey);
185             }
186             finally {
187                 HibernateUtil.closeSession(session);
188             }
189         }
190         else {
191             return null;
192         }
193     }
194 
195     private void _putResult(
196         boolean classNameCacheEnabled, String className, String methodName,
197         String[] params, Object[] args, Object result) {
198 
199         if (classNameCacheEnabled && CACHE_ENABLED &&
200             CacheRegistry.isActive() && (result != null)) {
201 
202             String key = _encodeKey(className, methodName, params, args);
203 
204             String groupKey = _encodeGroupKey(className);
205 
206             MultiVMPoolUtil.put(
207                 _cache, key, _groups, groupKey, _resultToPrimaryKey(result));
208         }
209     }
210 
211     private void _putResult(
212         String sql, boolean[] classNamesCacheEnabled, String[] classNames,
213         String methodName, String[] params, Object[] args, Object result) {
214 
215         if (ArrayUtil.contains(classNamesCacheEnabled, false)) {
216             return;
217         }
218 
219         if (CACHE_ENABLED && CacheRegistry.isActive() && (result != null)) {
220             String key = _encodeKey(sql, methodName, params, args);
221 
222             for (int i = 0; i < classNames.length; i++) {
223                 String className = classNames[i];
224 
225                 String groupKey = _encodeGroupKey(className);
226 
227                 MultiVMPoolUtil.updateGroup(_groups, groupKey, key);
228             }
229 
230             MultiVMPoolUtil.put(_cache, key, _resultToPrimaryKey(result));
231         }
232     }
233 
234     private String _encodeGroupKey(String className) {
235         StringMaker sm = new StringMaker();
236 
237         sm.append(CACHE_NAME);
238         sm.append(StringPool.POUND);
239         sm.append(className);
240 
241         return sm.toString();
242     }
243 
244     private String _encodeKey(
245         String className, String methodName, String[] params, Object[] args) {
246 
247         StringMaker sm = new StringMaker();
248 
249         sm.append(CACHE_NAME);
250         sm.append(StringPool.POUND);
251         sm.append(className);
252         sm.append(StringPool.POUND);
253         sm.append(methodName);
254         sm.append(_PARAMS_SEPARATOR);
255 
256         for (int i = 0; i < params.length; i++) {
257             String param = params[i];
258 
259             sm.append(StringPool.POUND);
260             sm.append(param);
261         }
262 
263         sm.append(_ARGS_SEPARATOR);
264 
265         for (int i = 0; i < args.length; i++) {
266             Object arg = args[i];
267 
268             sm.append(StringPool.POUND);
269             sm.append(String.valueOf(arg));
270         }
271 
272         return sm.toString();
273     }
274 
275     private Object _primaryKeyToResult(
276         Session session, Object primaryKey) {
277 
278         if (primaryKey instanceof CacheKVP) {
279             CacheKVP cacheKVP = (CacheKVP)primaryKey;
280 
281             Class modelClass = cacheKVP.getModelClass();
282             Serializable primaryKeyObj = cacheKVP.getPrimaryKeyObj();
283 
284             return session.load(modelClass, primaryKeyObj);
285         }
286         else if (primaryKey instanceof List) {
287             List cachedList = (List)primaryKey;
288 
289             List list = new ArrayList(cachedList.size());
290 
291             for (int i = 0; i < cachedList.size(); i++) {
292                 Object result = _primaryKeyToResult(session, cachedList.get(i));
293 
294                 list.add(result);
295             }
296 
297             return list;
298         }
299         else {
300             return primaryKey;
301         }
302     }
303 
304     private Object _resultToPrimaryKey(Object result) {
305         if (result instanceof BaseModel) {
306             BaseModel model = (BaseModel)result;
307 
308             Class modelClass = model.getClass();
309             Serializable primaryKeyObj = model.getPrimaryKeyObj();
310 
311             return new CacheKVP(modelClass, primaryKeyObj);
312         }
313         else if (result instanceof List) {
314             List list = (ArrayList)result;
315 
316             List cachedList = new ArrayList(list.size());
317 
318             for (int i = 0; i < list.size(); i++) {
319                 Object primaryKey = _resultToPrimaryKey(list.get(i));
320 
321                 cachedList.add(primaryKey);
322             }
323 
324             return cachedList;
325         }
326         else {
327             return result;
328         }
329     }
330 
331     private static final String _ARGS_SEPARATOR = "_ARGS_SEPARATOR_";
332 
333     private static final String _PARAMS_SEPARATOR = "_PARAMS_SEPARATOR_";
334 
335     private static FinderCache _instance = new FinderCache();
336 
337     private PortalCache _cache = MultiVMPoolUtil.getCache(CACHE_NAME);
338 
339     private Map _groups = CollectionFactory.getSyncHashMap();
340 
341 }