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