1   /**
2    * Copyright (c) 2000-2009 Liferay, Inc. All rights reserved.
3    *
4    *
5    *
6    *
7    * The contents of this file are subject to the terms of the Liferay Enterprise
8    * Subscription License ("License"). You may not use this file except in
9    * compliance with the License. You can obtain a copy of the License by
10   * contacting Liferay, Inc. See the License for the specific language governing
11   * permissions and limitations under the License, including but not limited to
12   * distribution rights 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.common;
24  
25  import com.liferay.portal.kernel.cache.CacheRegistry;
26  import com.liferay.portal.kernel.cache.CacheRegistryItem;
27  import com.liferay.portal.kernel.cache.MultiVMPool;
28  import com.liferay.portal.kernel.cache.PortalCache;
29  import com.liferay.portal.kernel.dao.orm.EntityCache;
30  import com.liferay.portal.kernel.dao.orm.Session;
31  import com.liferay.portal.kernel.dao.orm.SessionFactory;
32  import com.liferay.portal.kernel.log.Log;
33  import com.liferay.portal.kernel.log.LogFactoryUtil;
34  import com.liferay.portal.kernel.util.InitialThreadLocal;
35  import com.liferay.portal.kernel.util.StringPool;
36  import com.liferay.portal.model.BaseModel;
37  import com.liferay.portal.util.PropsValues;
38  
39  import java.io.Serializable;
40  
41  import java.util.Map;
42  import java.util.concurrent.ConcurrentHashMap;
43  
44  import org.apache.commons.collections.map.LRUMap;
45  
46  /**
47   * <a href="EntityCacheImpl.java.html"><b><i>View Source</i></b></a>
48   *
49   * @author Brian Wing Shun Chan
50   */
51  public class EntityCacheImpl implements CacheRegistryItem, EntityCache {
52  
53      public static final String CACHE_NAME = EntityCache.class.getName();
54  
55      public void afterPropertiesSet() {
56          CacheRegistry.register(this);
57      }
58  
59      public void clearCache() {
60          clearLocalCache();
61  
62          PortalCache[] portalCaches = _portalCaches.values().toArray(
63              new PortalCache[_portalCaches.size()]);
64  
65          for (PortalCache portalCache : portalCaches) {
66              portalCache.removeAll();
67          }
68      }
69  
70      public void clearCache(String className) {
71          clearLocalCache();
72  
73          PortalCache portalCache = _getPortalCache(className);
74  
75          portalCache.removeAll();
76      }
77  
78      public void clearLocalCache() {
79          if (_localCacheEnabled.get().booleanValue()) {
80              Map<String, Object> localCache = _localCache.get();
81  
82              localCache.clear();
83          }
84      }
85  
86      public String getRegistryName() {
87          return CACHE_NAME;
88      }
89  
90      public Object getResult(
91          boolean entityCacheEnabled, Class<?> classObj,
92          Serializable primaryKeyObj, SessionFactory sessionFactory) {
93  
94          if (!PropsValues.VALUE_OBJECT_ENTITY_CACHE_ENABLED ||
95              !entityCacheEnabled || !CacheRegistry.isActive()) {
96  
97              return null;
98          }
99  
100         Object result = null;
101 
102         Map<String, Object> localCache = null;
103 
104         String localCacheKey = null;
105 
106         if (_localCacheEnabled.get().booleanValue()) {
107             localCache = _localCache.get();
108 
109             localCacheKey = _encodeLocalCacheKey(classObj, primaryKeyObj);
110 
111             result = localCache.get(localCacheKey);
112         }
113 
114         if (result == null) {
115             PortalCache portalCache = _getPortalCache(classObj.getName());
116 
117             String cacheKey = _encodeCacheKey(primaryKeyObj);
118 
119             result = _multiVMPool.get(portalCache, cacheKey);
120 
121             if (result == null) {
122                 result = StringPool.BLANK;
123 
124                 _multiVMPool.put(portalCache, cacheKey, result);
125             }
126 
127             if (_localCacheEnabled.get().booleanValue()) {
128                 localCache.put(localCacheKey, result);
129             }
130         }
131 
132         if (result != null) {
133             result = _objectToResult(result);
134         }
135 
136         return result;
137     }
138 
139     public void invalidate() {
140         clearCache();
141     }
142 
143     public Object loadResult(
144         boolean entityCacheEnabled, Class<?> classObj,
145         Serializable primaryKeyObj, SessionFactory sessionFactory) {
146 
147         if (!PropsValues.VALUE_OBJECT_ENTITY_CACHE_ENABLED ||
148             !entityCacheEnabled || !CacheRegistry.isActive()) {
149 
150             Session session = null;
151 
152             try {
153                 session = sessionFactory.openSession();
154 
155                 return session.load(classObj, primaryKeyObj);
156             }
157             finally {
158                 sessionFactory.closeSession(session);
159             }
160         }
161 
162         Object result = null;
163 
164         Map<String, Object> localCache = null;
165 
166         String localCacheKey = null;
167 
168         if (_localCacheEnabled.get().booleanValue()) {
169             localCache = _localCache.get();
170 
171             localCacheKey = _encodeLocalCacheKey(classObj, primaryKeyObj);
172 
173             result = localCache.get(localCacheKey);
174         }
175 
176         if (result == null) {
177             PortalCache portalCache = _getPortalCache(classObj.getName());
178 
179             String cacheKey = _encodeCacheKey(primaryKeyObj);
180 
181             result = _multiVMPool.get(portalCache, cacheKey);
182 
183             if (result == null) {
184                 if (_log.isDebugEnabled()) {
185                     _log.debug(
186                         "Load " + classObj + " " + primaryKeyObj +
187                             " from session");
188                 }
189 
190                 Session session = null;
191 
192                 try {
193                     session = sessionFactory.openSession();
194 
195                     result = session.load(classObj, primaryKeyObj);
196                 }
197                 finally {
198                     if (result == null) {
199                         result = StringPool.BLANK;
200                     }
201 
202                     result = _objectToResult(result);
203 
204                     _multiVMPool.put(portalCache, cacheKey, result);
205 
206                     sessionFactory.closeSession(session);
207                 }
208             }
209 
210             if (_localCacheEnabled.get().booleanValue()) {
211                 localCache.put(localCacheKey, result);
212             }
213         }
214 
215         result = _objectToResult(result);
216 
217         return result;
218     }
219 
220     public void putResult(
221         boolean entityCacheEnabled, Class<?> classObj,
222         Serializable primaryKeyObj, Object result) {
223 
224         if (!PropsValues.VALUE_OBJECT_ENTITY_CACHE_ENABLED ||
225             !entityCacheEnabled || !CacheRegistry.isActive() ||
226             (result == null)) {
227 
228             return;
229         }
230 
231         result = _objectToResult(result);
232 
233         if (_localCacheEnabled.get().booleanValue()) {
234             Map<String, Object> localCache = _localCache.get();
235 
236             String localCacheKey = _encodeLocalCacheKey(
237                 classObj, primaryKeyObj);
238 
239             localCache.put(localCacheKey, result);
240         }
241 
242         PortalCache portalCache = _getPortalCache(classObj.getName());
243 
244         String cacheKey = _encodeCacheKey(primaryKeyObj);
245 
246         _multiVMPool.put(portalCache, cacheKey, result);
247     }
248 
249     public void removeResult(
250         boolean entityCacheEnabled, Class<?> classObj,
251         Serializable primaryKeyObj) {
252 
253         if (!PropsValues.VALUE_OBJECT_ENTITY_CACHE_ENABLED ||
254             !entityCacheEnabled || !CacheRegistry.isActive()) {
255 
256             return;
257         }
258 
259         if (_localCacheEnabled.get().booleanValue()) {
260             Map<String, Object> localCache = _localCache.get();
261 
262             String localCacheKey = _encodeLocalCacheKey(
263                 classObj, primaryKeyObj);
264 
265             localCache.remove(localCacheKey);
266         }
267 
268         PortalCache portalCache = _getPortalCache(classObj.getName());
269 
270         String cacheKey = _encodeCacheKey(primaryKeyObj);
271 
272         _multiVMPool.remove(portalCache, cacheKey);
273     }
274 
275     public void setLocalCacheEnabled(boolean localCacheEnabled) {
276         if (_localCacheAvailable) {
277             _localCacheEnabled.set(Boolean.valueOf(localCacheEnabled));
278         }
279     }
280 
281     public void setMultiVMPool(MultiVMPool multiVMPool) {
282         _multiVMPool = multiVMPool;
283     }
284 
285     private String _encodeCacheKey(Serializable primaryKeyObj) {
286         return String.valueOf(primaryKeyObj);
287     }
288 
289     private String _encodeGroupKey(String className) {
290         StringBuilder sb = new StringBuilder();
291 
292         sb.append(CACHE_NAME);
293         sb.append(StringPool.PERIOD);
294         sb.append(className);
295 
296         return sb.toString();
297     }
298 
299     private String _encodeLocalCacheKey(
300         Class<?> classObj, Serializable primaryKeyObj) {
301 
302         StringBuilder sb = new StringBuilder();
303 
304         sb.append(classObj.getName());
305         sb.append(StringPool.PERIOD);
306         sb.append(primaryKeyObj);
307 
308         return sb.toString();
309     }
310 
311     private PortalCache _getPortalCache(String className) {
312         String groupKey = _encodeGroupKey(className);
313 
314         PortalCache portalCache = _portalCaches.get(groupKey);
315 
316         if (portalCache == null) {
317             portalCache = _multiVMPool.getCache(
318                 groupKey, PropsValues.VALUE_OBJECT_ENTITY_BLOCKING_CACHE);
319 
320             _portalCaches.put(groupKey, portalCache);
321         }
322 
323         return portalCache;
324     }
325 
326     private Object _objectToResult(Object result) {
327         if (result instanceof String) {
328             return null;
329         }
330         else {
331             result = ((BaseModel<?>)result).clone();
332 
333             BaseModel<?> model = (BaseModel<?>)result;
334 
335             model.setCachedModel(true);
336 
337             return model;
338         }
339     }
340 
341     private static Log _log = LogFactoryUtil.getLog(EntityCacheImpl.class);
342 
343     private static ThreadLocal<Map> _localCache;
344     private static boolean _localCacheAvailable;
345     private static ThreadLocal<Boolean> _localCacheEnabled =
346         new InitialThreadLocal<Boolean>(Boolean.FALSE);
347 
348     static {
349         if (PropsValues.VALUE_OBJECT_ENTITY_THREAD_LOCAL_CACHE_MAX_SIZE > 0) {
350             _localCache = new InitialThreadLocal<Map>(new LRUMap(
351                 PropsValues.VALUE_OBJECT_ENTITY_THREAD_LOCAL_CACHE_MAX_SIZE));
352             _localCacheAvailable = true;
353         }
354     }
355 
356     private MultiVMPool _multiVMPool;
357     private Map<String, PortalCache> _portalCaches =
358         new ConcurrentHashMap<String, PortalCache>();
359 
360 }