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.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.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 FinderCacheImpl() {
62          CacheRegistry.register(this);
63      }
64  
65      public void clearCache() {
66          _cache.removeAll();
67      }
68  
69      public void clearCache(String className) {
70          String groupKey = _encodeGroupKey(className);
71  
72          MultiVMPoolUtil.clearGroup(_groups, groupKey, _cache);
73      }
74  
75      public Object getResult(
76          String className, String methodName, String[] params, Object[] args,
77          SessionFactory sessionFactory) {
78  
79          String key = _encodeKey(className, methodName, params, args);
80  
81          Object primaryKey = MultiVMPoolUtil.get(_cache, key);
82  
83          if (primaryKey != null) {
84              Session session = null;
85  
86              try {
87                  session = sessionFactory.openSession();
88  
89                  return _primaryKeyToResult(session, primaryKey);
90              }
91              finally {
92                  sessionFactory.closeSession(session);
93              }
94          }
95          else {
96              return null;
97          }
98      }
99  
100     public Object getResult(
101         String sql, String[] classNames, String methodName, String[] params,
102         Object[] args, SessionFactory sessionFactory) {
103 
104         String key = _encodeKey(sql, methodName, params, args);
105 
106         Object primaryKey = MultiVMPoolUtil.get(_cache, key);
107 
108         if (primaryKey != null) {
109             Session session = null;
110 
111             try {
112                 session = sessionFactory.openSession();
113 
114                 return _primaryKeyToResult(session, primaryKey);
115             }
116             finally {
117                 sessionFactory.closeSession(session);
118             }
119         }
120         else {
121             return null;
122         }
123     }
124 
125     public void putResult(
126         boolean classNameCacheEnabled, String className, String methodName,
127         String[] params, Object[] args, Object result) {
128 
129         if (classNameCacheEnabled && CACHE_ENABLED &&
130             CacheRegistry.isActive() && (result != null)) {
131 
132             String key = _encodeKey(className, methodName, params, args);
133 
134             String groupKey = _encodeGroupKey(className);
135 
136             MultiVMPoolUtil.put(
137                 _cache, key, _groups, groupKey, _resultToPrimaryKey(result));
138         }
139     }
140 
141     public void putResult(
142         String sql, boolean[] classNamesCacheEnabled, String[] classNames,
143         String methodName, String[] params, Object[] args, Object result) {
144 
145         if (ArrayUtil.contains(classNamesCacheEnabled, false)) {
146             return;
147         }
148 
149         if (CACHE_ENABLED && CacheRegistry.isActive() && (result != null)) {
150             String key = _encodeKey(sql, methodName, params, args);
151 
152             for (String className : classNames) {
153                 String groupKey = _encodeGroupKey(className);
154 
155                 MultiVMPoolUtil.updateGroup(_groups, groupKey, key);
156             }
157 
158             MultiVMPoolUtil.put(_cache, key, _resultToPrimaryKey(result));
159         }
160     }
161 
162     public void invalidate() {
163         clearCache();
164     }
165 
166     private String _encodeGroupKey(String className) {
167         StringBuilder sb = new StringBuilder();
168 
169         sb.append(CACHE_NAME);
170         sb.append(StringPool.POUND);
171         sb.append(className);
172 
173         return sb.toString();
174     }
175 
176     private String _encodeKey(
177         String className, String methodName, String[] params, Object[] args) {
178 
179         StringBuilder sb = new StringBuilder();
180 
181         sb.append(CACHE_NAME);
182         sb.append(StringPool.POUND);
183         sb.append(className);
184         sb.append(StringPool.POUND);
185         sb.append(methodName);
186         sb.append(_PARAMS_SEPARATOR);
187 
188         for (String param : params) {
189             sb.append(StringPool.POUND);
190             sb.append(param);
191         }
192 
193         sb.append(_ARGS_SEPARATOR);
194 
195         for (Object arg : args) {
196             sb.append(StringPool.POUND);
197             sb.append(String.valueOf(arg));
198         }
199 
200         return sb.toString();
201     }
202 
203     private Object _primaryKeyToResult(
204         Session session, Object primaryKey) {
205 
206         if (primaryKey instanceof CacheKVP) {
207             CacheKVP cacheKVP = (CacheKVP)primaryKey;
208 
209             Class<?> modelClass = cacheKVP.getModelClass();
210             Serializable primaryKeyObj = cacheKVP.getPrimaryKeyObj();
211 
212             return session.load(modelClass, primaryKeyObj);
213         }
214         else if (primaryKey instanceof List) {
215             List<Object> cachedList = (List<Object>)primaryKey;
216 
217             List<Object> list = new ArrayList<Object>(cachedList.size());
218 
219             for (Object curPrimaryKey : cachedList) {
220                 Object result = _primaryKeyToResult(session, curPrimaryKey);
221 
222                 list.add(result);
223             }
224 
225             return list;
226         }
227         else {
228             return primaryKey;
229         }
230     }
231 
232     private Object _resultToPrimaryKey(Object result) {
233         if (result instanceof BaseModel) {
234             BaseModel model = (BaseModel)result;
235 
236             Class<?> modelClass = model.getClass();
237             Serializable primaryKeyObj = model.getPrimaryKeyObj();
238 
239             return new CacheKVP(modelClass, primaryKeyObj);
240         }
241         else if (result instanceof List) {
242             List<Object> list = (List<Object>)result;
243 
244             List<Object> cachedList = new ArrayList<Object>(list.size());
245 
246             for (Object curResult : list) {
247                 Object primaryKey = _resultToPrimaryKey(curResult);
248 
249                 cachedList.add(primaryKey);
250             }
251 
252             return cachedList;
253         }
254         else {
255             return result;
256         }
257     }
258 
259     private static final String _ARGS_SEPARATOR = "_ARGS_SEPARATOR_";
260 
261     private static final String _PARAMS_SEPARATOR = "_PARAMS_SEPARATOR_";
262 
263     private PortalCache _cache = MultiVMPoolUtil.getCache(CACHE_NAME);
264 
265     private Map<String, Set<String>> _groups =
266         new ConcurrentHashMap<String, Set<String>>();
267 
268 }