Created
November 22, 2013 14:29
-
-
Save mp911de/7600734 to your computer and use it in GitHub Desktop.
Cached Apache Commons XML Configuration
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import org.apache.commons.configuration.HierarchicalConfiguration; | |
import org.apache.commons.configuration.SubnodeConfiguration; | |
import org.junit.Test; | |
import static org.junit.Assert.assertEquals; | |
/** | |
* @author <a href="mailto:mpaluch@paluch.biz">Mark Paluch</a> | |
* @since 22.11.13 14:48 | |
*/ | |
public abstract class AbstractConfigurationTest | |
{ | |
@Test | |
public void testStrings() throws Exception | |
{ | |
HierarchicalConfiguration configuration = getConfiguration(); | |
long start = System.currentTimeMillis(); | |
int iterations = getIterations(); | |
for (int i = 0; i < iterations; i++) | |
{ | |
configuration.getString("string"); | |
} | |
long finish = System.currentTimeMillis(); | |
System.out.println("Duration testStrings: " + (finish - start)); | |
} | |
@Test | |
public void testSubnodeConfiguration() throws Exception | |
{ | |
HierarchicalConfiguration configuration = getConfiguration(); | |
long start = System.currentTimeMillis(); | |
int iterations = getIterations(); | |
for (int i = 0; i < iterations; i++) | |
{ | |
SubnodeConfiguration subnodeConfiguration = configuration.configurationAt("strings"); | |
int result = subnodeConfiguration.getInt("integer"); | |
assertEquals(1234, result); | |
} | |
long finish = System.currentTimeMillis(); | |
System.out.println("Duration testSubnodeConfiguration: " + (finish - start)); | |
} | |
@Test | |
public void testInteger() throws Exception | |
{ | |
HierarchicalConfiguration configuration = getConfiguration(); | |
long start = System.currentTimeMillis(); | |
int iterations = getIterations(); | |
for (int i = 0; i < iterations; i++) | |
{ | |
configuration.getInt("integer"); | |
} | |
long finish = System.currentTimeMillis(); | |
System.out.println("Duration testInteger: " + (finish - start)); | |
} | |
@Test | |
public void testStringArrays() throws Exception | |
{ | |
HierarchicalConfiguration configuration = getConfiguration(); | |
long start = System.currentTimeMillis(); | |
int iterations = getIterations(); | |
for (int i = 0; i < iterations; i++) | |
{ | |
String[] result = configuration.getStringArray("strings/string"); | |
assertEquals(5, result.length); | |
} | |
long finish = System.currentTimeMillis(); | |
System.out.println("Duration testStringArrays: " + (finish - start)); | |
} | |
public abstract HierarchicalConfiguration getConfiguration(); | |
public abstract int getIterations(); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import com.google.common.base.Function; | |
import com.google.common.cache.CacheBuilder; | |
import com.google.common.cache.CacheLoader; | |
import com.google.common.cache.LoadingCache; | |
import com.google.common.util.concurrent.UncheckedExecutionException; | |
import org.apache.commons.configuration.HierarchicalConfiguration; | |
import org.apache.commons.configuration.SubnodeConfiguration; | |
import org.apache.commons.configuration.event.ConfigurationEvent; | |
import org.apache.commons.configuration.tree.ConfigurationNode; | |
import java.util.List; | |
import java.util.Properties; | |
import java.util.concurrent.ExecutionException; | |
public class CachedSubnodeConfiguration extends SubnodeConfiguration implements UnderlyingConfigurationAccessor | |
{ | |
private transient LoadingCache<String, CacheEntry<Object>> propertyCache; | |
private transient LoadingCache<ConfigurationNode, SubnodeConfiguration> subnodeCache; | |
private transient LoadingCache<String, CacheEntry<SubnodeConfiguration>> configurationAtCache; | |
private transient LoadingCache<String, List<HierarchicalConfiguration>> configurationsAtCache; | |
private transient LoadingCache<String, CacheEntry<Properties>> propertiesCache; | |
public CachedSubnodeConfiguration(HierarchicalConfiguration parent, ConfigurationNode root) | |
{ | |
super(parent, root); | |
initialize(); | |
} | |
private void initialize() | |
{ | |
subnodeCache = createCache(CacheFunctions.loadSubnode(this)); | |
propertyCache = createCache(CacheFunctions.loadProperty(this)); | |
configurationAtCache = createCache(CacheFunctions.loadConfigurationAt(this, this)); | |
configurationsAtCache = createCache(CacheFunctions.loadConfigurationsAt(this, this)); | |
propertiesCache = createCache(CacheFunctions.loadProperties(this)); | |
} | |
private LoadingCache createCache(Function loadFunction) | |
{ | |
return CacheBuilder.newBuilder().build(CacheLoader.from(loadFunction)); | |
} | |
@Override | |
protected SubnodeConfiguration createSubnodeConfiguration(ConfigurationNode node) | |
{ | |
try | |
{ | |
return subnodeCache.get(node); | |
} catch (UncheckedExecutionException e) | |
{ | |
if (e.getCause() instanceof RuntimeException) | |
{ | |
throw (RuntimeException) e.getCause(); | |
} | |
throw e; | |
} catch (ExecutionException e) | |
{ | |
if (e.getCause() instanceof RuntimeException) | |
{ | |
throw (RuntimeException) e.getCause(); | |
} | |
throw new IllegalStateException(e); | |
} | |
} | |
@Override | |
public List<HierarchicalConfiguration> configurationsAt(String key) | |
{ | |
try | |
{ | |
return configurationsAtCache.get(key); | |
} catch (UncheckedExecutionException e) | |
{ | |
if (e.getCause() instanceof RuntimeException) | |
{ | |
throw (RuntimeException) e.getCause(); | |
} | |
throw e; | |
} catch (ExecutionException e) | |
{ | |
if (e.getCause() instanceof RuntimeException) | |
{ | |
throw (RuntimeException) e.getCause(); | |
} | |
throw new IllegalStateException(e); | |
} | |
} | |
@Override | |
public SubnodeConfiguration configurationAt(String key, boolean supportUpdates) | |
{ | |
try | |
{ | |
return configurationAtCache.get(key).get(); | |
} catch (UncheckedExecutionException e) | |
{ | |
if (e.getCause() instanceof RuntimeException) | |
{ | |
throw (RuntimeException) e.getCause(); | |
} | |
throw e; | |
} catch (ExecutionException e) | |
{ | |
if (e.getCause() instanceof RuntimeException) | |
{ | |
throw (RuntimeException) e.getCause(); | |
} | |
throw new IllegalStateException(e); | |
} | |
} | |
@Override | |
public Object getProperty(String key) | |
{ | |
try | |
{ | |
return propertyCache.get(key).get(); | |
} catch (UncheckedExecutionException e) | |
{ | |
if (e.getCause() instanceof RuntimeException) | |
{ | |
throw (RuntimeException) e.getCause(); | |
} | |
throw e; | |
} catch (ExecutionException e) | |
{ | |
if (e.getCause() instanceof RuntimeException) | |
{ | |
throw (RuntimeException) e.getCause(); | |
} | |
throw new IllegalStateException(e); | |
} | |
} | |
@Override | |
public Properties getProperties(String key) | |
{ | |
try | |
{ | |
return propertiesCache.get(key).get(); | |
} catch (UncheckedExecutionException e) | |
{ | |
if (e.getCause() instanceof RuntimeException) | |
{ | |
throw (RuntimeException) e.getCause(); | |
} | |
throw e; | |
} catch (ExecutionException e) | |
{ | |
if (e.getCause() instanceof RuntimeException) | |
{ | |
throw (RuntimeException) e.getCause(); | |
} | |
throw new IllegalStateException(e); | |
} | |
} | |
@Override | |
public Object getUnderlyingProperty(String input) | |
{ | |
return super.getProperty(input); | |
} | |
@Override | |
public Properties getUnderlyingProperties(String input) | |
{ | |
return super.getProperties(input); | |
} | |
@Override | |
public List<HierarchicalConfiguration> underlyingConfigurationsAt(String input) | |
{ | |
return super.configurationsAt(input); | |
} | |
@Override | |
public HierarchicalConfiguration underlyingConfigurationAt(String input) | |
{ | |
return super.configurationAt(input, false); | |
} | |
@Override | |
protected void subnodeConfigurationChanged(ConfigurationEvent event) | |
{ | |
super.subnodeConfigurationChanged(event); | |
subnodeCache.invalidateAll(); | |
propertyCache.invalidateAll(); | |
configurationAtCache.invalidateAll(); | |
configurationsAtCache.invalidateAll(); | |
propertiesCache.invalidateAll(); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import com.google.common.base.Function; | |
import com.google.common.cache.CacheBuilder; | |
import com.google.common.cache.CacheLoader; | |
import com.google.common.cache.LoadingCache; | |
import com.google.common.util.concurrent.UncheckedExecutionException; | |
import org.apache.commons.configuration.ConfigurationException; | |
import org.apache.commons.configuration.HierarchicalConfiguration; | |
import org.apache.commons.configuration.SubnodeConfiguration; | |
import org.apache.commons.configuration.XMLConfiguration; | |
import org.apache.commons.configuration.event.ConfigurationEvent; | |
import org.apache.commons.configuration.tree.ConfigurationNode; | |
import java.io.File; | |
import java.net.URL; | |
import java.util.List; | |
import java.util.Properties; | |
import java.util.concurrent.ExecutionException; | |
public class CachedXmlConfiguration extends XMLConfiguration implements UnderlyingConfigurationAccessor | |
{ | |
private transient LoadingCache<String, CacheEntry<Object>> propertyCache; | |
private transient LoadingCache<ConfigurationNode, SubnodeConfiguration> subnodeCache; | |
private transient LoadingCache<String, CacheEntry<SubnodeConfiguration>> configurationAtCache; | |
private transient LoadingCache<String, List<HierarchicalConfiguration>> configurationsAtCache; | |
private transient LoadingCache<String, CacheEntry<Properties>> propertiesCache; | |
public CachedXmlConfiguration() | |
{ | |
super(); | |
initialize(); | |
} | |
public CachedXmlConfiguration(HierarchicalConfiguration c) | |
{ | |
super(c); | |
initialize(); | |
} | |
public CachedXmlConfiguration(String fileName) throws ConfigurationException | |
{ | |
super(fileName); | |
initialize(); | |
} | |
public CachedXmlConfiguration(File file) throws ConfigurationException | |
{ | |
super(file); | |
initialize(); | |
} | |
public CachedXmlConfiguration(URL url) throws ConfigurationException | |
{ | |
super(url); | |
initialize(); | |
} | |
private void initialize() | |
{ | |
subnodeCache = createCache(CacheFunctions.loadSubnode(this)); | |
propertyCache = createCache(CacheFunctions.loadProperty(this)); | |
configurationAtCache = createCache(CacheFunctions.loadConfigurationAt(this, this)); | |
configurationsAtCache = createCache(CacheFunctions.loadConfigurationsAt(this, this)); | |
propertiesCache = createCache(CacheFunctions.loadProperties(this)); | |
} | |
private LoadingCache createCache(Function loadFunction) | |
{ | |
return CacheBuilder.newBuilder().build(CacheLoader.from(loadFunction)); | |
} | |
@Override | |
protected SubnodeConfiguration createSubnodeConfiguration(ConfigurationNode node) | |
{ | |
try | |
{ | |
return subnodeCache.get(node); | |
} catch (UncheckedExecutionException e) | |
{ | |
if (e.getCause() instanceof RuntimeException) | |
{ | |
throw (RuntimeException) e.getCause(); | |
} | |
throw e; | |
} catch (ExecutionException e) | |
{ | |
if (e.getCause() instanceof RuntimeException) | |
{ | |
throw (RuntimeException) e.getCause(); | |
} | |
throw new IllegalStateException(e); | |
} | |
} | |
@Override | |
public List<HierarchicalConfiguration> configurationsAt(String key) | |
{ | |
try | |
{ | |
return configurationsAtCache.get(key); | |
} catch (UncheckedExecutionException e) | |
{ | |
if (e.getCause() instanceof RuntimeException) | |
{ | |
throw (RuntimeException) e.getCause(); | |
} | |
throw e; | |
} catch (ExecutionException e) | |
{ | |
if (e.getCause() instanceof RuntimeException) | |
{ | |
throw (RuntimeException) e.getCause(); | |
} | |
throw new IllegalStateException(e); | |
} | |
} | |
@Override | |
public SubnodeConfiguration configurationAt(String key, boolean supportUpdates) | |
{ | |
try | |
{ | |
return configurationAtCache.get(key).get(); | |
} catch (UncheckedExecutionException e) | |
{ | |
if (e.getCause() instanceof RuntimeException) | |
{ | |
throw (RuntimeException) e.getCause(); | |
} | |
throw e; | |
} catch (ExecutionException e) | |
{ | |
if (e.getCause() instanceof RuntimeException) | |
{ | |
throw (RuntimeException) e.getCause(); | |
} | |
throw new IllegalStateException(e); | |
} | |
} | |
@Override | |
public Object getProperty(String key) | |
{ | |
try | |
{ | |
return propertyCache.get(key).get(); | |
} catch (UncheckedExecutionException e) | |
{ | |
if (e.getCause() instanceof RuntimeException) | |
{ | |
throw (RuntimeException) e.getCause(); | |
} | |
throw e; | |
} catch (ExecutionException e) | |
{ | |
if (e.getCause() instanceof RuntimeException) | |
{ | |
throw (RuntimeException) e.getCause(); | |
} | |
throw new IllegalStateException(e); | |
} | |
} | |
@Override | |
public Properties getProperties(String key) | |
{ | |
try | |
{ | |
return propertiesCache.get(key).get(); | |
} catch (UncheckedExecutionException e) | |
{ | |
if (e.getCause() instanceof RuntimeException) | |
{ | |
throw (RuntimeException) e.getCause(); | |
} | |
throw e; | |
} catch (ExecutionException e) | |
{ | |
if (e.getCause() instanceof RuntimeException) | |
{ | |
throw (RuntimeException) e.getCause(); | |
} | |
throw new IllegalStateException(e); | |
} | |
} | |
@Override | |
public Object getUnderlyingProperty(String input) | |
{ | |
return super.getProperty(input); | |
} | |
@Override | |
public Properties getUnderlyingProperties(String input) | |
{ | |
return super.getProperties(input); | |
} | |
@Override | |
public List<HierarchicalConfiguration> underlyingConfigurationsAt(String input) | |
{ | |
return super.configurationsAt(input); | |
} | |
@Override | |
public HierarchicalConfiguration underlyingConfigurationAt(String input) | |
{ | |
return super.configurationAt(input, false); | |
} | |
@Override | |
public void configurationChanged(ConfigurationEvent event) | |
{ | |
super.configurationChanged(event); | |
subnodeCache.invalidateAll(); | |
propertyCache.invalidateAll(); | |
configurationAtCache.invalidateAll(); | |
configurationsAtCache.invalidateAll(); | |
propertiesCache.invalidateAll(); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import org.apache.commons.configuration.HierarchicalConfiguration; | |
import org.apache.commons.configuration.XMLConfiguration; | |
import org.apache.commons.configuration.tree.xpath.XPathExpressionEngine; | |
import org.junit.Before; | |
/** | |
* @author <a href="mailto:mpaluch@paluch.biz">Mark Paluch</a> | |
* @since 22.11.13 14:54 | |
*/ | |
public class CachedXmlConfigurationTest extends AbstractConfigurationTest | |
{ | |
private HierarchicalConfiguration hierarchicalConfiguration; | |
@Before | |
public void before() throws Exception | |
{ | |
hierarchicalConfiguration = new CachedXmlConfiguration(getClass().getResource("/test-config.xml")); | |
hierarchicalConfiguration.setExpressionEngine(new XPathExpressionEngine()); | |
} | |
@Override | |
public HierarchicalConfiguration getConfiguration() | |
{ | |
return hierarchicalConfiguration; | |
} | |
@Override | |
public int getIterations() | |
{ | |
return 1000; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* @author <a href="mailto:mpaluch@paluch.biz">Mark Paluch</a> | |
* @since 19.11.13 13:13 | |
*/ | |
public class CacheEntry<T> { | |
private T object; | |
public CacheEntry(T object) { | |
this.object = object; | |
} | |
public T get() { | |
return object; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import com.google.common.base.Function; | |
import org.apache.commons.configuration.HierarchicalConfiguration; | |
import org.apache.commons.configuration.SubnodeConfiguration; | |
import org.apache.commons.configuration.tree.ConfigurationNode; | |
import java.util.ArrayList; | |
import java.util.List; | |
import java.util.Properties; | |
public class CacheFunctions | |
{ | |
private CacheFunctions() | |
{ | |
} | |
public static Function<ConfigurationNode, SubnodeConfiguration> loadSubnode(final HierarchicalConfiguration parent) | |
{ | |
return new Function<ConfigurationNode, SubnodeConfiguration>() | |
{ | |
@Override | |
public SubnodeConfiguration apply(ConfigurationNode input) | |
{ | |
return new CachedSubnodeConfiguration(parent, input); | |
} | |
}; | |
} | |
public static Function<String, CacheEntry<Object>> loadProperty(final UnderlyingConfigurationAccessor datasource) | |
{ | |
return new Function<String, CacheEntry<Object>>() | |
{ | |
@Override | |
public CacheEntry<Object> apply(String input) | |
{ | |
return new CacheEntry<Object>(datasource.getUnderlyingProperty(input)); | |
} | |
}; | |
} | |
public static Function<String, CacheEntry<Properties>> loadProperties( | |
final UnderlyingConfigurationAccessor datasource) | |
{ | |
return new Function<String, CacheEntry<Properties>>() | |
{ | |
@Override | |
public CacheEntry<Properties> apply(String input) | |
{ | |
return new CacheEntry<Properties>(datasource.getUnderlyingProperties(input)); | |
} | |
}; | |
} | |
public static Function<String, List<HierarchicalConfiguration>> loadConfigurationsAt( | |
final HierarchicalConfiguration parent, final UnderlyingConfigurationAccessor datasource) | |
{ | |
return new Function<String, List<HierarchicalConfiguration>>() | |
{ | |
@Override | |
public List<HierarchicalConfiguration> apply(String input) | |
{ | |
List<HierarchicalConfiguration> hierarchicalConfigurations = | |
datasource.underlyingConfigurationsAt(input); | |
List<HierarchicalConfiguration> result = new ArrayList<HierarchicalConfiguration>(); | |
for (HierarchicalConfiguration hierarchicalConfiguration : hierarchicalConfigurations) | |
{ | |
CachedSubnodeConfiguration cachedSubnodeConfiguration = | |
new CachedSubnodeConfiguration(parent, hierarchicalConfiguration.getRootNode()); | |
result.add(cachedSubnodeConfiguration); | |
} | |
return result; | |
} | |
}; | |
} | |
public static Function<String, CacheEntry<SubnodeConfiguration>> loadConfigurationAt( | |
final HierarchicalConfiguration parent, final UnderlyingConfigurationAccessor datasource) | |
{ | |
return new Function<String, CacheEntry<SubnodeConfiguration>>() | |
{ | |
@Override | |
public CacheEntry<SubnodeConfiguration> apply(String input) | |
{ | |
HierarchicalConfiguration hierarchicalConfiguration = datasource.underlyingConfigurationAt(input); | |
SubnodeConfiguration result = | |
new CachedSubnodeConfiguration(parent, hierarchicalConfiguration.getRootNode()); | |
return new CacheEntry<SubnodeConfiguration>(result); | |
} | |
}; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="UTF-8"?> | |
<project xmlns="http://maven.apache.org/POM/4.0.0" | |
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | |
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | |
<modelVersion>4.0.0</modelVersion> | |
<groupId>config</groupId> | |
<artifactId>config</artifactId> | |
<version>1.0-SNAPSHOT</version> | |
<dependencies> | |
<dependency> | |
<groupId>junit</groupId> | |
<artifactId>junit</artifactId> | |
<version>4.11</version> | |
</dependency> | |
<dependency> | |
<groupId>commons-configuration</groupId> | |
<artifactId>commons-configuration</artifactId> | |
<version>1.8</version> | |
</dependency> | |
<dependency> | |
<groupId>commons-jxpath</groupId> | |
<artifactId>commons-jxpath</artifactId> | |
<version>1.3</version> | |
</dependency> | |
<dependency> | |
<groupId>com.google.guava</groupId> | |
<artifactId>guava</artifactId> | |
<version>15.0</version> | |
</dependency> | |
</dependencies> | |
</project> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<test> | |
<string>fasdfasdfasdf</string> | |
<boolean>true</boolean> | |
<integer>1234</integer> | |
<strings> | |
<string>s1</string> | |
<string>s2</string> | |
<string>s3</string> | |
<string>s4</string> | |
<string>s5</string> | |
<integer>1234</integer> | |
</strings> | |
</test> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import org.apache.commons.configuration.HierarchicalConfiguration; | |
import java.util.List; | |
import java.util.Properties; | |
public interface UnderlyingConfigurationAccessor | |
{ | |
Object getUnderlyingProperty(String input); | |
Properties getUnderlyingProperties(String input); | |
List<HierarchicalConfiguration> underlyingConfigurationsAt(String input); | |
HierarchicalConfiguration underlyingConfigurationAt(String input); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import org.apache.commons.configuration.HierarchicalConfiguration; | |
import org.apache.commons.configuration.XMLConfiguration; | |
import org.apache.commons.configuration.tree.xpath.XPathExpressionEngine; | |
import org.junit.Before; | |
/** | |
* @author <a href="mailto:mpaluch@paluch.biz">Mark Paluch</a> | |
* @since 22.11.13 14:54 | |
*/ | |
public class XmlConfigurationTest extends AbstractConfigurationTest | |
{ | |
private HierarchicalConfiguration hierarchicalConfiguration; | |
@Before | |
public void before() throws Exception | |
{ | |
hierarchicalConfiguration = new XMLConfiguration(getClass().getResource("/test-config.xml")); | |
hierarchicalConfiguration.setExpressionEngine(new XPathExpressionEngine()); | |
} | |
@Override | |
public HierarchicalConfiguration getConfiguration() | |
{ | |
return hierarchicalConfiguration; | |
} | |
@Override | |
public int getIterations() | |
{ | |
return 1000; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment