001    /**
002     * Copyright (c) 2000-2013 Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portal.cache.ehcache;
016    
017    import com.liferay.portal.cache.transactional.TransactionalPortalCache;
018    import com.liferay.portal.dao.orm.common.EntityCacheImpl;
019    import com.liferay.portal.dao.orm.common.FinderCacheImpl;
020    import com.liferay.portal.kernel.cache.BlockingPortalCache;
021    import com.liferay.portal.kernel.cache.PortalCache;
022    import com.liferay.portal.kernel.cache.PortalCacheManager;
023    import com.liferay.portal.kernel.log.Log;
024    import com.liferay.portal.kernel.log.LogFactoryUtil;
025    import com.liferay.portal.kernel.resiliency.spi.SPIUtil;
026    import com.liferay.portal.kernel.util.ReflectionUtil;
027    import com.liferay.portal.kernel.util.Validator;
028    import com.liferay.portal.util.PropsUtil;
029    import com.liferay.portal.util.PropsValues;
030    import com.liferay.portlet.PortalPreferencesWrapperCacheUtil;
031    
032    import java.io.Serializable;
033    
034    import java.lang.reflect.Field;
035    
036    import java.net.URL;
037    
038    import java.util.HashMap;
039    import java.util.Map;
040    
041    import javax.management.MBeanServer;
042    
043    import net.sf.ehcache.Cache;
044    import net.sf.ehcache.CacheManager;
045    import net.sf.ehcache.Ehcache;
046    import net.sf.ehcache.config.CacheConfiguration;
047    import net.sf.ehcache.config.Configuration;
048    import net.sf.ehcache.management.ManagementService;
049    import net.sf.ehcache.util.FailSafeTimer;
050    
051    /**
052     * @author Joseph Shum
053     * @author Raymond Aug??
054     * @author Michael C. Han
055     * @author Shuyang Zhou
056     * @author Edward Han
057     */
058    public class EhcachePortalCacheManager<K extends Serializable, V>
059            implements PortalCacheManager<K, V> {
060    
061            public void afterPropertiesSet() {
062                    if ((_cacheManager != null) || (_mpiOnly && SPIUtil.isSPI())) {
063                            return;
064                    }
065    
066                    String configurationPath = PropsUtil.get(_configPropertyKey);
067    
068                    if (Validator.isNull(configurationPath)) {
069                            configurationPath = _DEFAULT_CLUSTERED_EHCACHE_CONFIG_FILE;
070                    }
071    
072                    _usingDefault = configurationPath.equals(
073                            _DEFAULT_CLUSTERED_EHCACHE_CONFIG_FILE);
074    
075                    Configuration configuration = EhcacheConfigurationUtil.getConfiguration(
076                            configurationPath, _clusterAware, _usingDefault);
077    
078                    _cacheManager = CacheManagerUtil.createCacheManager(configuration);
079    
080                    FailSafeTimer failSafeTimer = _cacheManager.getTimer();
081    
082                    failSafeTimer.cancel();
083    
084                    try {
085                            Field cacheManagerTimerField = ReflectionUtil.getDeclaredField(
086                                    CacheManager.class, "cacheManagerTimer");
087    
088                            cacheManagerTimerField.set(_cacheManager, null);
089                    }
090                    catch (Exception e) {
091                            throw new RuntimeException(e);
092                    }
093    
094                    if (PropsValues.EHCACHE_PORTAL_CACHE_MANAGER_JMX_ENABLED) {
095                            _managementService = new ManagementService(
096                                    _cacheManager, _mBeanServer, _registerCacheManager,
097                                    _registerCaches, _registerCacheConfigurations,
098                                    _registerCacheStatistics);
099    
100                            _managementService.init();
101                    }
102            }
103    
104            @Override
105            public void clearAll() {
106                    _cacheManager.clearAll();
107            }
108    
109            public void destroy() throws Exception {
110                    try {
111                            _cacheManager.shutdown();
112                    }
113                    finally {
114                            if (_managementService != null) {
115                                    _managementService.dispose();
116                            }
117                    }
118            }
119    
120            @Override
121            public PortalCache<K, V> getCache(String name) {
122                    return getCache(name, false);
123            }
124    
125            @Override
126            public PortalCache<K, V> getCache(String name, boolean blocking) {
127                    PortalCache<K, V> portalCache = _ehcachePortalCaches.get(name);
128    
129                    if (portalCache == null) {
130                            synchronized (_cacheManager) {
131                                    portalCache = _ehcachePortalCaches.get(name);
132    
133                                    if (portalCache == null) {
134                                            portalCache = addCache(name, null);
135                                    }
136                            }
137                    }
138    
139                    if (PropsValues.TRANSACTIONAL_CACHE_ENABLED &&
140                            (name.startsWith(EntityCacheImpl.CACHE_NAME) ||
141                             name.startsWith(FinderCacheImpl.CACHE_NAME) ||
142                             name.equals(PortalPreferencesWrapperCacheUtil.CACHE_NAME))) {
143    
144                            portalCache = new TransactionalPortalCache<K, V>(portalCache);
145                    }
146    
147                    if (PropsValues.EHCACHE_BLOCKING_CACHE_ALLOWED && blocking) {
148                            portalCache = new BlockingPortalCache<K, V>(portalCache);
149                    }
150    
151                    return portalCache;
152            }
153    
154            public CacheManager getEhcacheManager() {
155                    return _cacheManager;
156            }
157    
158            @Override
159            public void reconfigureCaches(URL configurationURL) {
160                    Configuration configuration = EhcacheConfigurationUtil.getConfiguration(
161                            configurationURL, _clusterAware, _usingDefault);
162    
163                    Map<String, CacheConfiguration> cacheConfigurations =
164                            configuration.getCacheConfigurations();
165    
166                    for (CacheConfiguration cacheConfiguration :
167                                    cacheConfigurations.values()) {
168    
169                            Cache cache = new Cache(cacheConfiguration);
170    
171                            PortalCache<K, V> portalCache = addCache(cache.getName(), cache);
172    
173                            if (portalCache == null) {
174                                    _log.error(
175                                            "Failed to override cache " + cacheConfiguration.getName());
176                            }
177                    }
178            }
179    
180            @Override
181            public void removeCache(String name) {
182                    _ehcachePortalCaches.remove(name);
183    
184                    _cacheManager.removeCache(name);
185            }
186    
187            public void setClusterAware(boolean clusterAware) {
188                    _clusterAware = clusterAware;
189            }
190    
191            public void setConfigPropertyKey(String configPropertyKey) {
192                    _configPropertyKey = configPropertyKey;
193            }
194    
195            public void setMBeanServer(MBeanServer mBeanServer) {
196                    _mBeanServer = mBeanServer;
197            }
198    
199            public void setMpiOnly(boolean mpiOnly) {
200                    _mpiOnly = mpiOnly;
201            }
202    
203            public void setRegisterCacheConfigurations(
204                    boolean registerCacheConfigurations) {
205    
206                    _registerCacheConfigurations = registerCacheConfigurations;
207            }
208    
209            public void setRegisterCacheManager(boolean registerCacheManager) {
210                    _registerCacheManager = registerCacheManager;
211            }
212    
213            public void setRegisterCaches(boolean registerCaches) {
214                    _registerCaches = registerCaches;
215            }
216    
217            public void setRegisterCacheStatistics(boolean registerCacheStatistics) {
218                    _registerCacheStatistics = registerCacheStatistics;
219            }
220    
221            protected PortalCache<K, V> addCache(String name, Cache cache) {
222                    EhcachePortalCache<K, V> ehcachePortalCache = null;
223    
224                    synchronized (_cacheManager) {
225                            if ((cache != null) && _cacheManager.cacheExists(name)) {
226                                    if (_log.isInfoEnabled()) {
227                                            _log.info("Overriding existing cache " + name);
228                                    }
229    
230                                    _cacheManager.removeCache(name);
231                            }
232    
233                            if (cache == null) {
234                                    if (!_cacheManager.cacheExists(name)) {
235                                            _cacheManager.addCache(name);
236                                    }
237                            }
238                            else {
239                                    _cacheManager.addCache(cache);
240                            }
241    
242                            Ehcache ehcache = _cacheManager.getEhcache(name);
243    
244                            if (ehcache == null) {
245                                    return null;
246                            }
247    
248                            ehcachePortalCache = _ehcachePortalCaches.get(name);
249    
250                            if (ehcachePortalCache == null) {
251                                    ehcachePortalCache = new EhcachePortalCache<K, V>(ehcache);
252    
253                                    _ehcachePortalCaches.put(name, ehcachePortalCache);
254                            }
255                            else {
256                                    ehcachePortalCache.setEhcache(ehcache);
257                            }
258                    }
259    
260                    return ehcachePortalCache;
261            }
262    
263            private static final String _DEFAULT_CLUSTERED_EHCACHE_CONFIG_FILE =
264                    "/ehcache/liferay-multi-vm-clustered.xml";
265    
266            private static Log _log = LogFactoryUtil.getLog(
267                    EhcachePortalCacheManager.class);
268    
269            private CacheManager _cacheManager;
270            private boolean _clusterAware;
271            private String _configPropertyKey;
272            private Map<String, EhcachePortalCache<K, V>> _ehcachePortalCaches =
273                    new HashMap<String, EhcachePortalCache<K, V>>();
274            private ManagementService _managementService;
275            private MBeanServer _mBeanServer;
276            private boolean _mpiOnly;
277            private boolean _registerCacheConfigurations = true;
278            private boolean _registerCacheManager = true;
279            private boolean _registerCaches = true;
280            private boolean _registerCacheStatistics = true;
281            private boolean _usingDefault;
282    
283    }