From 3dfa6d4fc1347ae83b2d037741e437b860b65d90 Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Mon, 25 Mar 2013 08:50:26 +0100 Subject: [PATCH] added CacheConfigurationReader for GuavaCacheManager --- .../scm/cache/CacheConfigurationReader.java | 294 ++++++++++++++++++ .../sonia/scm/cache/CacheConfigurations.java | 108 +++++++ .../scm/cache/CacheManagerConfiguration.java | 28 +- .../scm/cache/EhCacheConfigurationReader.java | 42 +-- 4 files changed, 435 insertions(+), 37 deletions(-) create mode 100644 scm-webapp/src/main/java/sonia/scm/cache/CacheConfigurationReader.java create mode 100644 scm-webapp/src/main/java/sonia/scm/cache/CacheConfigurations.java diff --git a/scm-webapp/src/main/java/sonia/scm/cache/CacheConfigurationReader.java b/scm-webapp/src/main/java/sonia/scm/cache/CacheConfigurationReader.java new file mode 100644 index 0000000000..a295ef8c33 --- /dev/null +++ b/scm-webapp/src/main/java/sonia/scm/cache/CacheConfigurationReader.java @@ -0,0 +1,294 @@ +/** + * Copyright (c) 2010, Sebastian Sdorra All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. 2. Redistributions in + * binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. 3. Neither the name of SCM-Manager; + * nor the names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * http://bitbucket.org/sdorra/scm-manager + * + */ + + + +package sonia.scm.cache; + +//~--- non-JDK imports -------------------------------------------------------- + +import com.google.common.annotations.VisibleForTesting; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Maps; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import sonia.scm.SCMContext; + +//~--- JDK imports ------------------------------------------------------------ + +import java.io.File; + +import java.net.MalformedURLException; +import java.net.URL; + +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import javax.xml.bind.JAXBContext; +import javax.xml.bind.JAXBException; + +/** + * + * @author Sebastian Sdorra + */ +public class CacheConfigurationReader +{ + + /** Field description */ + private static final String DEFAULT = "/config/cache.xml"; + + /** Field description */ + private static final String MANUAL_RESOURCE = + "ext".concat(File.separator).concat("cache.xml"); + + /** Field description */ + private static final String MODULE_RESOURCES = "/META-INF/scm/cache.xml"; + + /** + * the logger for CacheConfigurationReader + */ + private static final Logger logger = + LoggerFactory.getLogger(CacheConfigurationReader.class); + + //~--- constructors --------------------------------------------------------- + + /** + * Constructs ... + * + */ + public CacheConfigurationReader() + { + try + { + this.context = JAXBContext.newInstance(CacheManagerConfiguration.class); + } + catch (JAXBException ex) + { + throw new CacheException( + "could not create jaxb context for cache configuration", ex); + } + } + + //~--- methods -------------------------------------------------------------- + + /** + * Method description + * + * + * @return + */ + public CacheManagerConfiguration read() + { + URL defaultConfigUrl = getDefaultResource(); + + if (defaultConfigUrl == null) + { + throw new IllegalStateException( + "could not find default cache configuration"); + } + + CacheManagerConfiguration config = readConfiguration(defaultConfigUrl, + true); + + Iterator it = getModuleResources(); + + while (it.hasNext()) + { + CacheManagerConfiguration moduleConfig = readConfiguration(it.next(), + false); + + if (moduleConfig != null) + { + config = merge(config, moduleConfig); + } + } + + File manualFile = getManualFileResource(); + + if (manualFile.exists()) + { + try + { + CacheManagerConfiguration manualConfig = + readConfiguration(manualFile.toURI().toURL(), false); + + config = merge(config, manualConfig); + } + catch (MalformedURLException ex) + { + logger.error("malformed url", ex); + } + } + else + { + logger.warn("could not find manual configuration at {}", manualFile); + } + + return config; + } + + //~--- get methods ---------------------------------------------------------- + + /** + * Method description + * + * + * @return + */ + @VisibleForTesting + protected URL getDefaultResource() + { + return CacheConfigurationReader.class.getResource(DEFAULT); + } + + /** + * Method description + * + * + * @return + */ + @VisibleForTesting + protected File getManualFileResource() + { + return new File(SCMContext.getContext().getBaseDirectory(), + MANUAL_RESOURCE); + } + + /** + * Method description + * + * + * @param path + * + * @return + */ + @VisibleForTesting + protected Iterator getModuleResources() + { + return CacheConfigurations.findModuleResources( + EhCacheConfigurationReader.class, MODULE_RESOURCES); + } + + //~--- methods -------------------------------------------------------------- + + /** + * Method description + * + * + * @param caches + * + * @return + */ + private Map createNamedCacheMap( + List caches) + { + Map map = Maps.newLinkedHashMap(); + + for (NamedCacheConfiguration ncc : caches) + { + map.put(ncc.getName(), ncc); + } + + return map; + } + + /** + * Method description + * + * + * @param config + * @param other + * + * @return + */ + private CacheManagerConfiguration merge(CacheManagerConfiguration config, + CacheManagerConfiguration other) + { + CacheConfiguration defaultCache = config.getDefaultCache(); + Map namedCaches = + createNamedCacheMap(config.getCaches()); + + if (other.getDefaultCache() != null) + { + defaultCache = other.getDefaultCache(); + } + + List otherNamedCaches = other.getCaches(); + + for (NamedCacheConfiguration ncc : otherNamedCaches) + { + namedCaches.put(ncc.getName(), ncc); + } + + return new CacheManagerConfiguration(defaultCache, + ImmutableList.copyOf(namedCaches.values())); + } + + /** + * Method description + * + * + * @param url + * @param fail + * + * @return + */ + private CacheManagerConfiguration readConfiguration(URL url, boolean fail) + { + CacheManagerConfiguration config = null; + + try + { + config = + (CacheManagerConfiguration) context.createUnmarshaller().unmarshal(url); + } + catch (JAXBException ex) + { + if (fail) + { + throw new CacheException("could not unmarshall cache configuration", + ex); + } + else + { + logger.warn("could not unmarshall cache configuration", ex); + } + } + + return config; + } + + //~--- fields --------------------------------------------------------------- + + /** Field description */ + private JAXBContext context; +} diff --git a/scm-webapp/src/main/java/sonia/scm/cache/CacheConfigurations.java b/scm-webapp/src/main/java/sonia/scm/cache/CacheConfigurations.java new file mode 100644 index 0000000000..1b7689d497 --- /dev/null +++ b/scm-webapp/src/main/java/sonia/scm/cache/CacheConfigurations.java @@ -0,0 +1,108 @@ +/** + * Copyright (c) 2010, Sebastian Sdorra All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. 2. Redistributions in + * binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. 3. Neither the name of SCM-Manager; + * nor the names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * http://bitbucket.org/sdorra/scm-manager + * + */ + + + +package sonia.scm.cache; + +//~--- non-JDK imports -------------------------------------------------------- + +import com.google.common.collect.Iterators; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +//~--- JDK imports ------------------------------------------------------------ + +import java.io.IOException; + +import java.net.URL; + +import java.util.Enumeration; +import java.util.Iterator; + +/** + * + * @author Sebastian Sdorra + */ +public class CacheConfigurations +{ + + /** + * the logger for CacheConfigurations + */ + private static final Logger logger = + LoggerFactory.getLogger(CacheConfigurations.class); + + //~--- methods -------------------------------------------------------------- + + /** + * Method description + * + * + * @param loadingClass + * @param resource + * + * @return + */ + public static Iterator findModuleResources(Class loadingClass, + String resource) + { + Iterator it = null; + + try + { + ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); + + if (classLoader == null) + { + classLoader = loadingClass.getClassLoader(); + } + + Enumeration enm = classLoader.getResources(resource); + + if (enm != null) + { + it = Iterators.forEnumeration(enm); + } + + } + catch (IOException ex) + { + logger.error("could not read module resources", ex); + } + + if (it == null) + { + it = Iterators.emptyIterator(); + } + + return it; + } +} diff --git a/scm-webapp/src/main/java/sonia/scm/cache/CacheManagerConfiguration.java b/scm-webapp/src/main/java/sonia/scm/cache/CacheManagerConfiguration.java index 8d49bdd149..e0d8c8b4d4 100644 --- a/scm-webapp/src/main/java/sonia/scm/cache/CacheManagerConfiguration.java +++ b/scm-webapp/src/main/java/sonia/scm/cache/CacheManagerConfiguration.java @@ -33,6 +33,7 @@ package sonia.scm.cache; //~--- JDK imports ------------------------------------------------------------ +import java.util.Collections; import java.util.List; import javax.xml.bind.annotation.XmlAccessType; @@ -49,6 +50,28 @@ import javax.xml.bind.annotation.XmlRootElement; public class CacheManagerConfiguration { + /** + * Constructs ... + * + */ + public CacheManagerConfiguration() {} + + /** + * Constructs ... + * + * + * @param defaultCache + * @param caches + */ + public CacheManagerConfiguration(CacheConfiguration defaultCache, + List caches) + { + this.defaultCache = defaultCache; + this.caches = caches; + } + + //~--- get methods ---------------------------------------------------------- + /** * Method description * @@ -57,6 +80,9 @@ public class CacheManagerConfiguration */ public List getCaches() { + if ( caches == null ){ + caches = Collections.EMPTY_LIST; + } return caches; } @@ -78,6 +104,6 @@ public class CacheManagerConfiguration private List caches; /** Field description */ - @XmlElement(name = "cache") + @XmlElement(name = "defaultCache") private CacheConfiguration defaultCache; } diff --git a/scm-webapp/src/main/java/sonia/scm/cache/EhCacheConfigurationReader.java b/scm-webapp/src/main/java/sonia/scm/cache/EhCacheConfigurationReader.java index bac0ced9a5..bf3051cb3f 100644 --- a/scm-webapp/src/main/java/sonia/scm/cache/EhCacheConfigurationReader.java +++ b/scm-webapp/src/main/java/sonia/scm/cache/EhCacheConfigurationReader.java @@ -35,13 +35,13 @@ package sonia.scm.cache; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Objects; -import com.google.common.collect.Iterators; import com.google.common.collect.Maps; import com.google.common.io.Closeables; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.w3c.dom.Attr; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NamedNodeMap; @@ -55,13 +55,11 @@ import sonia.scm.SCMContext; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; -import java.io.IOException; import java.io.InputStream; import java.net.MalformedURLException; import java.net.URL; -import java.util.Enumeration; import java.util.Iterator; import java.util.Map; @@ -73,7 +71,6 @@ import javax.xml.transform.Transformer; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; -import org.w3c.dom.Attr; /** * @@ -90,10 +87,10 @@ public class EhCacheConfigurationReader /** Field description */ private static final String MANUAL_RESOURCE = - "ext".concat(File.separator).concat("cache.xml"); + "ext".concat(File.separator).concat("ehcache.xml"); /** Field description */ - private static final String MODULE_RESOURCES = "/META-INF/scm/cache.xml"; + private static final String MODULE_RESOURCES = "/META-INF/scm/ehcache.xml"; /** * the logger for EhCacheConfigurationReader @@ -209,36 +206,8 @@ public class EhCacheConfigurationReader @VisibleForTesting protected Iterator getModuleResources() { - Iterator it = null; - - try - { - ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); - - if (classLoader == null) - { - classLoader = EhCacheConfigurationReader.class.getClassLoader(); - } - - Enumeration enm = classLoader.getResources(MODULE_RESOURCES); - - if (enm != null) - { - it = Iterators.forEnumeration(enm); - } - - } - catch (IOException ex) - { - logger.error("could not read cache module resources", ex); - } - - if (it == null) - { - it = Iterators.emptyIterator(); - } - - return it; + return CacheConfigurations.findModuleResources( + EhCacheConfigurationReader.class, MODULE_RESOURCES); } //~--- methods -------------------------------------------------------------- @@ -296,6 +265,7 @@ public class EhCacheConfigurationReader for (Attr attribute : attributeMap.values()) { Attr mergedAttr = (Attr) merged.adoptNode(attribute); + rootEl.setAttributeNode(mergedAttr); }