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.dao.orm.hibernate;
24  
25  import com.liferay.portal.kernel.bean.InitializingBean;
26  import com.liferay.portal.kernel.cache.CacheKVP;
27  import com.liferay.portal.kernel.cache.CacheRegistry;
28  import com.liferay.portal.kernel.cache.CacheRegistryItem;
29  import com.liferay.portal.kernel.cache.MultiVMPool;
30  import com.liferay.portal.kernel.cache.PortalCache;
31  import com.liferay.portal.kernel.dao.orm.FinderCache;
32  import com.liferay.portal.kernel.dao.orm.Session;
33  import com.liferay.portal.kernel.dao.orm.SessionFactory;
34  import com.liferay.portal.kernel.util.ArrayUtil;
35  import com.liferay.portal.kernel.util.GetterUtil;
36  import com.liferay.portal.kernel.util.StringPool;
37  import com.liferay.portal.model.BaseModel;
38  import com.liferay.portal.util.PropsKeys;
39  import com.liferay.portal.util.PropsUtil;
40  
41  import java.io.Serializable;
42  
43  import java.util.ArrayList;
44  import java.util.List;
45  import java.util.Map;
46  import java.util.Set;
47  import java.util.concurrent.ConcurrentHashMap;
48  
49  /**
50   * <a href="FinderCacheImpl.java.html"><b><i>View Source</i></b></a>
51   *
52   * @author Brian Wing Shun Chan
53   *
54   */
55  public class FinderCacheImpl
56      implements CacheRegistryItem, FinderCache, InitializingBean {
57  
58      public static final boolean CACHE_ENABLED = GetterUtil.getBoolean(
59          PropsUtil.get(PropsKeys.VALUE_OBJECT_FINDER_CACHE_ENABLED), true);
60  
61      public static final String CACHE_NAME = FinderCache.class.getName();
62  
63      public void afterPropertiesSet() {
64          CacheRegistry.register(this);
65  
66          _cache = _multiVMPool.getCache(CACHE_NAME);
67      }
68  
69      public void clearCache() {
70          _cache.removeAll();
71      }
72  
73      public void clearCache(String className) {
74          String groupKey = _encodeGroupKey(className);
75  
76          _multiVMPool.clearGroup(_groups, groupKey, _cache);
77      }
78  
79      public Object getResult(
80          String className, String methodName, String[] params, Object[] args,
81          SessionFactory sessionFactory) {
82  
83          String key = _encodeKey(className, methodName, params, args);
84  
85          Object primaryKey = _multiVMPool.get(_cache, key);
86  
87          if (primaryKey != null) {
88              Session session = null;
89  
90              try {
91                  session = sessionFactory.openSession();
92  
93                  return _primaryKeyToResult(session, primaryKey);
94              }
95              finally {
96                  sessionFactory.closeSession(session);
97              }
98          }
99          else {
100             return null;
101         }
102     }
103 
104     public Object getResult(
105         String sql, String[] classNames, String methodName, String[] params,
106         Object[] args, SessionFactory sessionFactory) {
107 
108         String key = _encodeKey(sql, methodName, params, args);
109 
110         Object primaryKey = _multiVMPool.get(_cache, key);
111 
112         if (primaryKey != null) {
113             Session session = null;
114 
115             try {
116                 session = sessionFactory.openSession();
117 
118                 return _primaryKeyToResult(session, primaryKey);
119             }
120             finally {
121                 sessionFactory.closeSession(session);
122             }
123         }
124         else {
125             return null;
126         }
127     }
128 
129     public void invalidate() {
130         clearCache();
131     }
132 
133     public void putResult(
134         boolean classNameCacheEnabled, String className, String methodName,
135         String[] params, Object[] args, Object result) {
136 
137         if (classNameCacheEnabled && CACHE_ENABLED &&
138             CacheRegistry.isActive() && (result != null)) {
139 
140             String key = _encodeKey(className, methodName, params, args);
141 
142             String groupKey = _encodeGroupKey(className);
143 
144             _multiVMPool.put(
145                 _cache, key, _groups, groupKey, _resultToPrimaryKey(result));
146         }
147     }
148 
149     public void putResult(
150         String sql, boolean[] classNamesCacheEnabled, String[] classNames,
151         String methodName, String[] params, Object[] args, Object result) {
152 
153         if (ArrayUtil.contains(classNamesCacheEnabled, false)) {
154             return;
155         }
156 
157         if (CACHE_ENABLED && CacheRegistry.isActive() && (result != null)) {
158             String key = _encodeKey(sql, methodName, params, args);
159 
160             for (String className : classNames) {
161                 String groupKey = _encodeGroupKey(className);
162 
163                 _multiVMPool.updateGroup(_groups, groupKey, key);
164             }
165 
166             _multiVMPool.put(_cache, key, _resultToPrimaryKey(result));
167         }
168     }
169 
170     public void setMultiVMPool(MultiVMPool multiVMPool) {
171         _multiVMPool = multiVMPool;
172     }
173 
174     private String _encodeGroupKey(String className) {
175         StringBuilder sb = new StringBuilder();
176 
177         sb.append(CACHE_NAME);
178         sb.append(StringPool.POUND);
179         sb.append(className);
180 
181         return sb.toString();
182     }
183 
184     private String _encodeKey(
185         String className, String methodName, String[] params, Object[] args) {
186 
187         StringBuilder sb = new StringBuilder();
188 
189         sb.append(CACHE_NAME);
190         sb.append(StringPool.POUND);
191         sb.append(className);
192         sb.append(StringPool.POUND);
193         sb.append(methodName);
194         sb.append(_PARAMS_SEPARATOR);
195 
196         for (String param : params) {
197             sb.append(StringPool.POUND);
198             sb.append(param);
199         }
200 
201         sb.append(_ARGS_SEPARATOR);
202 
203         for (Object arg : args) {
204             sb.append(StringPool.POUND);
205             sb.append(String.valueOf(arg));
206         }
207 
208         return sb.toString();
209     }
210 
211     private Object _primaryKeyToResult(
212         Session session, Object primaryKey) {
213 
214         if (primaryKey instanceof CacheKVP) {
215             CacheKVP cacheKVP = (CacheKVP)primaryKey;
216 
217             Class<?> modelClass = cacheKVP.getModelClass();
218             Serializable primaryKeyObj = cacheKVP.getPrimaryKeyObj();
219 
220             return session.load(modelClass, primaryKeyObj);
221         }
222         else if (primaryKey instanceof List) {
223             List<Object> cachedList = (List<Object>)primaryKey;
224 
225             List<Object> list = new ArrayList<Object>(cachedList.size());
226 
227             for (Object curPrimaryKey : cachedList) {
228                 Object result = _primaryKeyToResult(session, curPrimaryKey);
229 
230                 list.add(result);
231             }
232 
233             return list;
234         }
235         else {
236             return primaryKey;
237         }
238     }
239 
240     private Object _resultToPrimaryKey(Object result) {
241         if (result instanceof BaseModel) {
242             BaseModel model = (BaseModel)result;
243 
244             Class<?> modelClass = model.getClass();
245             Serializable primaryKeyObj = model.getPrimaryKeyObj();
246 
247             return new CacheKVP(modelClass, primaryKeyObj);
248         }
249         else if (result instanceof List) {
250             List<Object> list = (List<Object>)result;
251 
252             List<Object> cachedList = new ArrayList<Object>(list.size());
253 
254             for (Object curResult : list) {
255                 Object primaryKey = _resultToPrimaryKey(curResult);
256 
257                 cachedList.add(primaryKey);
258             }
259 
260             return cachedList;
261         }
262         else {
263             return result;
264         }
265     }
266 
267     private static final String _ARGS_SEPARATOR = "_ARGS_SEPARATOR_";
268 
269     private static final String _PARAMS_SEPARATOR = "_PARAMS_SEPARATOR_";
270 
271     private MultiVMPool _multiVMPool;
272     private PortalCache _cache;
273     private Map<String, Set<String>> _groups =
274         new ConcurrentHashMap<String, Set<String>>();
275 
276 }