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