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