001    /**
002     * Copyright (c) 2000-2010 Liferay, Inc. All rights reserved.
003     *
004     * The contents of this file are subject to the terms of the Liferay Enterprise
005     * Subscription License ("License"). You may not use this file except in
006     * compliance with the License. You can obtain a copy of the License by
007     * contacting Liferay, Inc. See the License for the specific language governing
008     * permissions and limitations under the License, including but not limited to
009     * distribution rights of the Software.
010     *
011     *
012     *
013     */
014    
015    package com.liferay.portal.dao.orm.common;
016    
017    import com.liferay.portal.kernel.cache.CacheRegistryItem;
018    import com.liferay.portal.kernel.cache.CacheRegistryUtil;
019    import com.liferay.portal.kernel.cache.MultiVMPool;
020    import com.liferay.portal.kernel.cache.PortalCache;
021    import com.liferay.portal.kernel.cache.key.CacheKeyGenerator;
022    import com.liferay.portal.kernel.cache.key.CacheKeyGeneratorUtil;
023    import com.liferay.portal.kernel.dao.orm.EntityCache;
024    import com.liferay.portal.kernel.dao.orm.Session;
025    import com.liferay.portal.kernel.dao.orm.SessionFactory;
026    import com.liferay.portal.kernel.log.Log;
027    import com.liferay.portal.kernel.log.LogFactoryUtil;
028    import com.liferay.portal.kernel.util.AutoResetThreadLocal;
029    import com.liferay.portal.kernel.util.StringPool;
030    import com.liferay.portal.model.BaseModel;
031    import com.liferay.portal.util.PropsValues;
032    
033    import java.io.Serializable;
034    
035    import java.util.Map;
036    import java.util.concurrent.ConcurrentHashMap;
037    import java.util.concurrent.ConcurrentMap;
038    
039    import org.apache.commons.collections.map.LRUMap;
040    
041    /**
042     * @author Brian Wing Shun Chan
043     */
044    public class EntityCacheImpl implements CacheRegistryItem, EntityCache {
045    
046            public static final String CACHE_NAME = EntityCache.class.getName();
047    
048            public void afterPropertiesSet() {
049                    CacheRegistryUtil.register(this);
050            }
051    
052            public void clearCache() {
053                    clearLocalCache();
054    
055                    for (PortalCache portalCache : _portalCaches.values()) {
056                            portalCache.removeAll();
057                    }
058            }
059    
060            public void clearCache(String className) {
061                    clearLocalCache();
062    
063                    PortalCache portalCache = _getPortalCache(className, false);
064    
065                    if (portalCache != null) {
066                            portalCache.removeAll();
067                    }
068            }
069    
070            public void clearLocalCache() {
071                    if (_localCacheAvailable) {
072                            _localCache.remove();
073                    }
074            }
075    
076            public String getRegistryName() {
077                    return CACHE_NAME;
078            }
079    
080            public Object getResult(
081                    boolean entityCacheEnabled, Class<?> classObj,
082                    Serializable primaryKeyObj, SessionFactory sessionFactory) {
083    
084                    if (!PropsValues.VALUE_OBJECT_ENTITY_CACHE_ENABLED ||
085                            !entityCacheEnabled || !CacheRegistryUtil.isActive()) {
086    
087                            return null;
088                    }
089    
090                    Object result = null;
091    
092                    Map<String, Object> localCache = null;
093    
094                    String localCacheKey = null;
095    
096                    if (_localCacheAvailable) {
097                            localCache = _localCache.get();
098    
099                            localCacheKey = _encodeLocalCacheKey(classObj, primaryKeyObj);
100    
101                            result = localCache.get(localCacheKey);
102                    }
103    
104                    if (result == null) {
105                            PortalCache portalCache = _getPortalCache(classObj.getName(), true);
106    
107                            String cacheKey = _encodeCacheKey(primaryKeyObj);
108    
109                            result = portalCache.get(cacheKey);
110    
111                            if (result == null) {
112                                    result = StringPool.BLANK;
113    
114                                    portalCache.put(cacheKey, result);
115                            }
116    
117                            if (_localCacheAvailable) {
118                                    localCache.put(localCacheKey, result);
119                            }
120                    }
121    
122                    if (result != null) {
123                            result = _objectToResult(result);
124                    }
125    
126                    return result;
127            }
128    
129            public void invalidate() {
130                    clearCache();
131            }
132    
133            public Object loadResult(
134                    boolean entityCacheEnabled, Class<?> classObj,
135                    Serializable primaryKeyObj, SessionFactory sessionFactory) {
136    
137                    if (!PropsValues.VALUE_OBJECT_ENTITY_CACHE_ENABLED ||
138                            !entityCacheEnabled || !CacheRegistryUtil.isActive()) {
139    
140                            Session session = null;
141    
142                            try {
143                                    session = sessionFactory.openSession();
144    
145                                    return session.load(classObj, primaryKeyObj);
146                            }
147                            finally {
148                                    sessionFactory.closeSession(session);
149                            }
150                    }
151    
152                    Object result = null;
153    
154                    Map<String, Object> localCache = null;
155    
156                    String localCacheKey = null;
157    
158                    if (_localCacheAvailable) {
159                            localCache = _localCache.get();
160    
161                            localCacheKey = _encodeLocalCacheKey(classObj, primaryKeyObj);
162    
163                            result = localCache.get(localCacheKey);
164                    }
165    
166                    boolean load = false;
167    
168                    if (result == null) {
169                            PortalCache portalCache = _getPortalCache(classObj.getName(), true);
170    
171                            String cacheKey = _encodeCacheKey(primaryKeyObj);
172    
173                            result = portalCache.get(cacheKey);
174    
175                            if (result == null) {
176                                    if (_log.isDebugEnabled()) {
177                                            _log.debug(
178                                                    "Load " + classObj + " " + primaryKeyObj +
179                                                            " from session");
180                                    }
181    
182                                    load = true;
183    
184                                    Session session = null;
185    
186                                    try {
187                                            session = sessionFactory.openSession();
188    
189                                            result = session.load(classObj, primaryKeyObj);
190                                    }
191                                    finally {
192                                            if (result == null) {
193                                                    result = StringPool.BLANK;
194                                            }
195                                            else {
196                                                    result = _objectToResult(result);
197                                            }
198    
199                                            portalCache.put(cacheKey, result);
200    
201                                            sessionFactory.closeSession(session);
202                                    }
203                            }
204    
205                            if (_localCacheAvailable) {
206                                    localCache.put(localCacheKey, result);
207                            }
208                    }
209    
210                    if (!load) {
211                            return _objectToResult(result);
212                    }
213    
214                    if (result instanceof String) {
215                            return null;
216                    }
217                    else {
218                            return result;
219                    }
220            }
221    
222            public void putResult(
223                    boolean entityCacheEnabled, Class<?> classObj,
224                    Serializable primaryKeyObj, Object result) {
225    
226                    if (!PropsValues.VALUE_OBJECT_ENTITY_CACHE_ENABLED ||
227                            !entityCacheEnabled || !CacheRegistryUtil.isActive() ||
228                            (result == null)) {
229    
230                            return;
231                    }
232    
233                    result = _objectToResult(result);
234    
235                    if (_localCacheAvailable) {
236                            Map<String, Object> localCache = _localCache.get();
237    
238                            String localCacheKey = _encodeLocalCacheKey(
239                                    classObj, primaryKeyObj);
240    
241                            localCache.put(localCacheKey, result);
242                    }
243    
244                    PortalCache portalCache = _getPortalCache(classObj.getName(), true);
245    
246                    String cacheKey = _encodeCacheKey(primaryKeyObj);
247    
248                    portalCache.put(cacheKey, result);
249            }
250    
251            public void removeCache(String className) {
252                    String groupKey = _GROUP_KEY_PREFIX.concat(className);
253    
254                    _portalCaches.remove(groupKey);
255                    _multiVMPool.removeCache(groupKey);
256            }
257    
258            public void removeResult(
259                    boolean entityCacheEnabled, Class<?> classObj,
260                    Serializable primaryKeyObj) {
261    
262                    if (!PropsValues.VALUE_OBJECT_ENTITY_CACHE_ENABLED ||
263                            !entityCacheEnabled || !CacheRegistryUtil.isActive()) {
264    
265                            return;
266                    }
267    
268                    if (_localCacheAvailable) {
269                            Map<String, Object> localCache = _localCache.get();
270    
271                            String localCacheKey = _encodeLocalCacheKey(
272                                    classObj, primaryKeyObj);
273    
274                            localCache.remove(localCacheKey);
275                    }
276    
277                    PortalCache portalCache = _getPortalCache(classObj.getName(), true);
278    
279                    String cacheKey = _encodeCacheKey(primaryKeyObj);
280    
281                    portalCache.remove(cacheKey);
282            }
283    
284            public void setMultiVMPool(MultiVMPool multiVMPool) {
285                    _multiVMPool = multiVMPool;
286            }
287    
288            private String _encodeCacheKey(Serializable primaryKeyObj) {
289                    CacheKeyGenerator cacheKeyGenerator =
290                            CacheKeyGeneratorUtil.getCacheKeyGenerator(CACHE_NAME);
291    
292                    return cacheKeyGenerator.getCacheKey(primaryKeyObj.toString());
293            }
294    
295            private String _encodeLocalCacheKey(
296                    Class<?> classObj, Serializable primaryKeyObj) {
297    
298                    CacheKeyGenerator cacheKeyGenerator =
299                            CacheKeyGeneratorUtil.getCacheKeyGenerator(CACHE_NAME);
300    
301                    cacheKeyGenerator.append(classObj.getName());
302                    cacheKeyGenerator.append(primaryKeyObj.toString());
303    
304                    return cacheKeyGenerator.finish();
305            }
306    
307            private PortalCache _getPortalCache(
308                    String className, boolean createIfAbsent) {
309    
310                    String groupKey = _GROUP_KEY_PREFIX.concat(className);
311    
312                    PortalCache portalCache = _portalCaches.get(groupKey);
313    
314                    if ((portalCache == null) && createIfAbsent) {
315                            portalCache = _multiVMPool.getCache(
316                                    groupKey, PropsValues.VALUE_OBJECT_ENTITY_BLOCKING_CACHE);
317    
318                            PortalCache previousPortalCache = _portalCaches.putIfAbsent(
319                                    groupKey, portalCache);
320    
321                            if (previousPortalCache != null) {
322                                    portalCache = previousPortalCache;
323                            }
324    
325                            portalCache.setDebug(true);
326                    }
327    
328                    return portalCache;
329            }
330    
331            private Object _objectToResult(Object result) {
332                    if (result instanceof String) {
333                            return null;
334                    }
335                    else {
336                            result = ((BaseModel<?>)result).clone();
337    
338                            BaseModel<?> model = (BaseModel<?>)result;
339    
340                            model.setCachedModel(true);
341    
342                            return model;
343                    }
344            }
345    
346            private static Log _log = LogFactoryUtil.getLog(EntityCacheImpl.class);
347    
348            private static final String _GROUP_KEY_PREFIX = CACHE_NAME.concat(
349                    StringPool.PERIOD);
350    
351            private static ThreadLocal<LRUMap> _localCache;
352            private static boolean _localCacheAvailable;
353    
354            static {
355                    if (PropsValues.VALUE_OBJECT_ENTITY_THREAD_LOCAL_CACHE_MAX_SIZE > 0) {
356                            _localCache = new AutoResetThreadLocal<LRUMap>(
357                                    EntityCacheImpl.class + "._localCache",
358                                    new LRUMap(
359                                            PropsValues.
360                                                    VALUE_OBJECT_ENTITY_THREAD_LOCAL_CACHE_MAX_SIZE));
361                            _localCacheAvailable = true;
362                    }
363            }
364    
365            private MultiVMPool _multiVMPool;
366            private ConcurrentMap<String, PortalCache> _portalCaches =
367                    new ConcurrentHashMap<String, PortalCache>();
368    
369    }