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.kernel.cache.BlockingPortalCache;
019    import com.liferay.portal.kernel.cache.PortalCache;
020    import com.liferay.portal.kernel.cache.PortalCacheManager;
021    import com.liferay.portal.kernel.log.Log;
022    import com.liferay.portal.kernel.log.LogFactoryUtil;
023    import com.liferay.portal.kernel.resiliency.spi.SPIUtil;
024    import com.liferay.portal.kernel.util.CharPool;
025    import com.liferay.portal.kernel.util.ReflectionUtil;
026    import com.liferay.portal.kernel.util.StringUtil;
027    import com.liferay.portal.kernel.util.Validator;
028    import com.liferay.portal.util.PropsUtil;
029    import com.liferay.portal.util.PropsValues;
030    
031    import java.io.Serializable;
032    
033    import java.lang.reflect.Field;
034    
035    import java.net.URL;
036    
037    import java.util.HashMap;
038    import java.util.Map;
039    
040    import javax.management.MBeanServer;
041    
042    import net.sf.ehcache.Cache;
043    import net.sf.ehcache.CacheManager;
044    import net.sf.ehcache.Ehcache;
045    import net.sf.ehcache.config.CacheConfiguration;
046    import net.sf.ehcache.config.Configuration;
047    import net.sf.ehcache.management.ManagementService;
048    import net.sf.ehcache.util.FailSafeTimer;
049    
050    /**
051     * @author Joseph Shum
052     * @author Raymond Aug??
053     * @author Michael C. Han
054     * @author Shuyang Zhou
055     * @author Edward Han
056     */
057    public class EhcachePortalCacheManager<K extends Serializable, V>
058            implements PortalCacheManager<K, V> {
059    
060            public void afterPropertiesSet() {
061                    if ((_cacheManager != null) || (_mpiOnly && SPIUtil.isSPI())) {
062                            return;
063                    }
064    
065                    String configurationPath = PropsUtil.get(_configPropertyKey);
066    
067                    if (Validator.isNull(configurationPath)) {
068                            configurationPath = _DEFAULT_CLUSTERED_EHCACHE_CONFIG_FILE;
069                    }
070    
071                    _usingDefault = configurationPath.equals(
072                            _DEFAULT_CLUSTERED_EHCACHE_CONFIG_FILE);
073    
074                    Configuration configuration = EhcacheConfigurationUtil.getConfiguration(
075                            configurationPath, _clusterAware, _usingDefault);
076    
077                    _cacheManager = CacheManagerUtil.createCacheManager(configuration);
078    
079                    FailSafeTimer failSafeTimer = _cacheManager.getTimer();
080    
081                    failSafeTimer.cancel();
082    
083                    try {
084                            Field cacheManagerTimerField = ReflectionUtil.getDeclaredField(
085                                    CacheManager.class, "cacheManagerTimer");
086    
087                            cacheManagerTimerField.set(_cacheManager, null);
088                    }
089                    catch (Exception e) {
090                            throw new RuntimeException(e);
091                    }
092    
093                    if (PropsValues.EHCACHE_PORTAL_CACHE_MANAGER_JMX_ENABLED) {
094                            _managementService = new ManagementService(
095                                    _cacheManager, _mBeanServer, _registerCacheManager,
096                                    _registerCaches, _registerCacheConfigurations,
097                                    _registerCacheStatistics);
098    
099                            _managementService.init();
100                    }
101            }
102    
103            @Override
104            public void clearAll() {
105                    _cacheManager.clearAll();
106            }
107    
108            public void destroy() throws Exception {
109                    try {
110                            _ehcachePortalCaches.clear();
111                            _portalCaches.clear();
112    
113                            _cacheManager.shutdown();
114                    }
115                    finally {
116                            if (_managementService != null) {
117                                    _managementService.dispose();
118                            }
119                    }
120            }
121    
122            @Override
123            public PortalCache<K, V> getCache(String name) {
124                    return getCache(name, false);
125            }
126    
127            @Override
128            public PortalCache<K, V> getCache(String name, boolean blocking) {
129                    PortalCache<K, V> portalCache = _portalCaches.get(name);
130    
131                    if (portalCache == null) {
132                            synchronized (_cacheManager) {
133                                    portalCache = _portalCaches.get(name);
134    
135                                    if (portalCache == null) {
136                                            portalCache = addCache(name, null);
137    
138                                            if (PropsValues.TRANSACTIONAL_CACHE_ENABLED &&
139                                                    isTransactionalPortalCache(name)) {
140    
141                                                    portalCache = new TransactionalPortalCache<K, V>(
142                                                            portalCache);
143                                            }
144    
145                                            if (PropsValues.EHCACHE_BLOCKING_CACHE_ALLOWED &&
146                                                    blocking) {
147    
148                                                    portalCache = new BlockingPortalCache<K, V>(
149                                                            portalCache);
150                                            }
151    
152                                            _portalCaches.put(name, portalCache);
153                                    }
154                            }
155                    }
156    
157                    return portalCache;
158            }
159    
160            public CacheManager getEhcacheManager() {
161                    return _cacheManager;
162            }
163    
164            @Override
165            public void reconfigureCaches(URL configurationURL) {
166                    Configuration configuration = EhcacheConfigurationUtil.getConfiguration(
167                            configurationURL, _clusterAware, _usingDefault);
168    
169                    Map<String, CacheConfiguration> cacheConfigurations =
170                            configuration.getCacheConfigurations();
171    
172                    for (CacheConfiguration cacheConfiguration :
173                                    cacheConfigurations.values()) {
174    
175                            Cache cache = new Cache(cacheConfiguration);
176    
177                            PortalCache<K, V> portalCache = addCache(cache.getName(), cache);
178    
179                            if (portalCache == null) {
180                                    _log.error(
181                                            "Failed to override cache " + cacheConfiguration.getName());
182                            }
183                    }
184            }
185    
186            @Override
187            public void removeCache(String name) {
188                    _cacheManager.removeCache(name);
189                    _ehcachePortalCaches.remove(name);
190                    _portalCaches.remove(name);
191            }
192    
193            public void setClusterAware(boolean clusterAware) {
194                    _clusterAware = clusterAware;
195            }
196    
197            public void setConfigPropertyKey(String configPropertyKey) {
198                    _configPropertyKey = configPropertyKey;
199            }
200    
201            public void setMBeanServer(MBeanServer mBeanServer) {
202                    _mBeanServer = mBeanServer;
203            }
204    
205            public void setMpiOnly(boolean mpiOnly) {
206                    _mpiOnly = mpiOnly;
207            }
208    
209            public void setRegisterCacheConfigurations(
210                    boolean registerCacheConfigurations) {
211    
212                    _registerCacheConfigurations = registerCacheConfigurations;
213            }
214    
215            public void setRegisterCacheManager(boolean registerCacheManager) {
216                    _registerCacheManager = registerCacheManager;
217            }
218    
219            public void setRegisterCaches(boolean registerCaches) {
220                    _registerCaches = registerCaches;
221            }
222    
223            public void setRegisterCacheStatistics(boolean registerCacheStatistics) {
224                    _registerCacheStatistics = registerCacheStatistics;
225            }
226    
227            protected PortalCache<K, V> addCache(String name, Cache cache) {
228                    EhcachePortalCache<K, V> ehcachePortalCache = null;
229    
230                    synchronized (_cacheManager) {
231                            if ((cache != null) && _cacheManager.cacheExists(name)) {
232                                    if (_log.isInfoEnabled()) {
233                                            _log.info("Overriding existing cache " + name);
234                                    }
235    
236                                    _cacheManager.removeCache(name);
237                            }
238    
239                            if (cache == null) {
240                                    if (!_cacheManager.cacheExists(name)) {
241                                            _cacheManager.addCache(name);
242                                    }
243                            }
244                            else {
245                                    _cacheManager.addCache(cache);
246                            }
247    
248                            Ehcache ehcache = _cacheManager.getEhcache(name);
249    
250                            if (ehcache == null) {
251                                    return null;
252                            }
253    
254                            ehcachePortalCache = _ehcachePortalCaches.get(name);
255    
256                            if (ehcachePortalCache == null) {
257                                    ehcachePortalCache = new EhcachePortalCache<K, V>(ehcache);
258    
259                                    _ehcachePortalCaches.put(name, ehcachePortalCache);
260                            }
261                            else {
262                                    ehcachePortalCache.setEhcache(ehcache);
263                            }
264                    }
265    
266                    return ehcachePortalCache;
267            }
268    
269            protected boolean isTransactionalPortalCache(String name) {
270                    for (String namePattern : PropsValues.TRANSACTIONAL_CACHE_NAMES) {
271                            if (StringUtil.wildcardMatches(
272                                            name, namePattern, CharPool.QUESTION, CharPool.STAR,
273                                            CharPool.PERCENT, true)) {
274    
275                                    return true;
276                            }
277                    }
278    
279                    return false;
280            }
281    
282            private static final String _DEFAULT_CLUSTERED_EHCACHE_CONFIG_FILE =
283                    "/ehcache/liferay-multi-vm-clustered.xml";
284    
285            private static Log _log = LogFactoryUtil.getLog(
286                    EhcachePortalCacheManager.class);
287    
288            private CacheManager _cacheManager;
289            private boolean _clusterAware;
290            private String _configPropertyKey;
291            private Map<String, EhcachePortalCache<K, V>> _ehcachePortalCaches =
292                    new HashMap<String, EhcachePortalCache<K, V>>();
293            private ManagementService _managementService;
294            private MBeanServer _mBeanServer;
295            private boolean _mpiOnly;
296            private Map<String, PortalCache<K, V>> _portalCaches =
297                    new HashMap<String, PortalCache<K, V>>();
298            private boolean _registerCacheConfigurations = true;
299            private boolean _registerCacheManager = true;
300            private boolean _registerCaches = true;
301            private boolean _registerCacheStatistics = true;
302            private boolean _usingDefault;
303    
304    }