org.apache.commons.configuration2.DynamicCombinedConfiguration Maven / Gradle / Ivy
Show all versions of commons-configuration2 Show documentation
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.configuration2;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import org.apache.commons.configuration2.event.Event;
import org.apache.commons.configuration2.event.EventListener;
import org.apache.commons.configuration2.event.EventType;
import org.apache.commons.configuration2.interpol.ConfigurationInterpolator;
import org.apache.commons.configuration2.interpol.Lookup;
import org.apache.commons.configuration2.io.ConfigurationLogger;
import org.apache.commons.configuration2.tree.ExpressionEngine;
import org.apache.commons.configuration2.tree.ImmutableNode;
import org.apache.commons.configuration2.tree.NodeCombiner;
/**
*
* DynamicCombinedConfiguration allows a set of CombinedConfigurations to be
* used.
*
*
* Each CombinedConfiguration is referenced by a key that is dynamically
* constructed from a key pattern on each call. The key pattern will be resolved
* using the configured ConfigurationInterpolator.
*
*
* This Configuration implementation uses the configured {@code Synchronizer} to
* guard itself against concurrent access. If there are multiple threads
* accessing an instance concurrently, a fully functional {@code Synchronizer}
* implementation (e.g. {@code ReadWriteSynchronizer}) has to be used to ensure
* consistency and to avoid exceptions. The {@code Synchronizer} assigned to an
* instance is also passed to child configuration objects when they are created.
*
*
* @since 1.6
* @version $Id: DynamicCombinedConfiguration.java 1735895 2016-03-20 18:40:47Z oheger $
*/
public class DynamicCombinedConfiguration extends CombinedConfiguration
{
/**
* Stores the current configuration for each involved thread. This value is
* set at the beginning of an operation and removed at the end.
*/
private static final ThreadLocal CURRENT_CONFIG =
new ThreadLocal();
/** The CombinedConfigurations */
private final ConcurrentMap configs =
new ConcurrentHashMap();
/** Stores a list with the contained configurations. */
private final List configurations = new ArrayList();
/** Stores a map with the named configurations. */
private final Map namedConfigurations =
new HashMap();
/** The key pattern for the CombinedConfiguration map */
private String keyPattern;
/** Stores the combiner. */
private NodeCombiner nodeCombiner;
/** The name of the logger to use for each CombinedConfiguration */
private String loggerName = DynamicCombinedConfiguration.class.getName();
/** The object for handling variable substitution in key patterns. */
private final ConfigurationInterpolator localSubst;
/**
* Creates a new instance of {@code DynamicCombinedConfiguration} and
* initializes the combiner to be used.
*
* @param comb the node combiner (can be null, then a union combiner
* is used as default)
*/
public DynamicCombinedConfiguration(NodeCombiner comb)
{
super();
setNodeCombiner(comb);
initLogger(new ConfigurationLogger(DynamicCombinedConfiguration.class));
localSubst = initLocalInterpolator();
}
/**
* Creates a new instance of {@code DynamicCombinedConfiguration} that uses
* a union combiner.
*
* @see org.apache.commons.configuration2.tree.UnionCombiner
*/
public DynamicCombinedConfiguration()
{
super();
initLogger(new ConfigurationLogger(DynamicCombinedConfiguration.class));
localSubst = initLocalInterpolator();
}
public void setKeyPattern(String pattern)
{
this.keyPattern = pattern;
}
public String getKeyPattern()
{
return this.keyPattern;
}
/**
* Set the name of the Logger to use on each CombinedConfiguration.
* @param name The Logger name.
*/
public void setLoggerName(String name)
{
this.loggerName = name;
}
/**
* Returns the node combiner that is used for creating the combined node
* structure.
*
* @return the node combiner
*/
@Override
public NodeCombiner getNodeCombiner()
{
return nodeCombiner;
}
/**
* Sets the node combiner. This object will be used when the combined node
* structure is to be constructed. It must not be null, otherwise an
* {@code IllegalArgumentException} exception is thrown. Changing the
* node combiner causes an invalidation of this combined configuration, so
* that the new combiner immediately takes effect.
*
* @param nodeCombiner the node combiner
*/
@Override
public void setNodeCombiner(NodeCombiner nodeCombiner)
{
if (nodeCombiner == null)
{
throw new IllegalArgumentException(
"Node combiner must not be null!");
}
this.nodeCombiner = nodeCombiner;
invalidateAll();
}
/**
* Adds a new configuration to this combined configuration. It is possible
* (but not mandatory) to give the new configuration a name. This name must
* be unique, otherwise a {@code ConfigurationRuntimeException} will
* be thrown. With the optional {@code at} argument you can specify
* where in the resulting node structure the content of the added
* configuration should appear. This is a string that uses dots as property
* delimiters (independent on the current expression engine). For instance
* if you pass in the string {@code "database.tables"},
* all properties of the added configuration will occur in this branch.
*
* @param config the configuration to add (must not be null)
* @param name the name of this configuration (can be null)
* @param at the position of this configuration in the combined tree (can be
* null)
*/
@Override
public void addConfiguration(Configuration config, String name,
String at)
{
beginWrite(true);
try
{
ConfigData cd = new ConfigData(config, name, at);
configurations.add(cd);
if (name != null)
{
namedConfigurations.put(name, config);
}
// clear cache of all child configurations
configs.clear();
}
finally
{
endWrite();
}
}
/**
* Returns the number of configurations that are contained in this combined
* configuration.
*
* @return the number of contained configurations
*/
@Override
public int getNumberOfConfigurations()
{
beginRead(false);
try
{
return configurations.size();
}
finally
{
endRead();
}
}
/**
* Returns the configuration at the specified index. The contained
* configurations are numbered in the order they were added to this combined
* configuration. The index of the first configuration is 0.
*
* @param index the index
* @return the configuration at this index
*/
@Override
public Configuration getConfiguration(int index)
{
beginRead(false);
try
{
ConfigData cd = configurations.get(index);
return cd.getConfiguration();
}
finally
{
endRead();
}
}
/**
* Returns the configuration with the given name. This can be null
* if no such configuration exists.
*
* @param name the name of the configuration
* @return the configuration with this name
*/
@Override
public Configuration getConfiguration(String name)
{
beginRead(false);
try
{
return namedConfigurations.get(name);
}
finally
{
endRead();
}
}
/**
* Returns a set with the names of all configurations contained in this
* combined configuration. Of course here are only these configurations
* listed, for which a name was specified when they were added.
*
* @return a set with the names of the contained configurations (never
* null)
*/
@Override
public Set getConfigurationNames()
{
beginRead(false);
try
{
return namedConfigurations.keySet();
}
finally
{
endRead();
}
}
/**
* Removes the configuration with the specified name.
*
* @param name the name of the configuration to be removed
* @return the removed configuration (null if this configuration
* was not found)
*/
@Override
public Configuration removeConfiguration(String name)
{
Configuration conf = getConfiguration(name);
if (conf != null)
{
removeConfiguration(conf);
}
return conf;
}
/**
* Removes the specified configuration from this combined configuration.
*
* @param config the configuration to be removed
* @return a flag whether this configuration was found and could be removed
*/
@Override
public boolean removeConfiguration(Configuration config)
{
beginWrite(false);
try
{
for (int index = 0; index < getNumberOfConfigurations(); index++)
{
if (configurations.get(index).getConfiguration() == config)
{
removeConfigurationAt(index);
return true;
}
}
return false;
}
finally
{
endWrite();
}
}
/**
* Removes the configuration at the specified index.
*
* @param index the index
* @return the removed configuration
*/
@Override
public Configuration removeConfigurationAt(int index)
{
beginWrite(false);
try
{
ConfigData cd = configurations.remove(index);
if (cd.getName() != null)
{
namedConfigurations.remove(cd.getName());
}
return cd.getConfiguration();
}
finally
{
endWrite();
}
}
@Override
protected void addPropertyInternal(String key, Object value)
{
this.getCurrentConfig().addProperty(key, value);
}
@Override
protected void clearInternal()
{
if (configs != null)
{
this.getCurrentConfig().clear();
}
}
@Override
protected void clearPropertyDirect(String key)
{
this.getCurrentConfig().clearProperty(key);
}
@Override
protected boolean containsKeyInternal(String key)
{
return this.getCurrentConfig().containsKey(key);
}
@Override
public BigDecimal getBigDecimal(String key, BigDecimal defaultValue)
{
return this.getCurrentConfig().getBigDecimal(key, defaultValue);
}
@Override
public BigDecimal getBigDecimal(String key)
{
return this.getCurrentConfig().getBigDecimal(key);
}
@Override
public BigInteger getBigInteger(String key, BigInteger defaultValue)
{
return this.getCurrentConfig().getBigInteger(key, defaultValue);
}
@Override
public BigInteger getBigInteger(String key)
{
return this.getCurrentConfig().getBigInteger(key);
}
@Override
public boolean getBoolean(String key, boolean defaultValue)
{
return this.getCurrentConfig().getBoolean(key, defaultValue);
}
@Override
public Boolean getBoolean(String key, Boolean defaultValue)
{
return this.getCurrentConfig().getBoolean(key, defaultValue);
}
@Override
public boolean getBoolean(String key)
{
return this.getCurrentConfig().getBoolean(key);
}
@Override
public byte getByte(String key, byte defaultValue)
{
return this.getCurrentConfig().getByte(key, defaultValue);
}
@Override
public Byte getByte(String key, Byte defaultValue)
{
return this.getCurrentConfig().getByte(key, defaultValue);
}
@Override
public byte getByte(String key)
{
return this.getCurrentConfig().getByte(key);
}
@Override
public double getDouble(String key, double defaultValue)
{
return this.getCurrentConfig().getDouble(key, defaultValue);
}
@Override
public Double getDouble(String key, Double defaultValue)
{
return this.getCurrentConfig().getDouble(key, defaultValue);
}
@Override
public double getDouble(String key)
{
return this.getCurrentConfig().getDouble(key);
}
@Override
public float getFloat(String key, float defaultValue)
{
return this.getCurrentConfig().getFloat(key, defaultValue);
}
@Override
public Float getFloat(String key, Float defaultValue)
{
return this.getCurrentConfig().getFloat(key, defaultValue);
}
@Override
public float getFloat(String key)
{
return this.getCurrentConfig().getFloat(key);
}
@Override
public int getInt(String key, int defaultValue)
{
return this.getCurrentConfig().getInt(key, defaultValue);
}
@Override
public int getInt(String key)
{
return this.getCurrentConfig().getInt(key);
}
@Override
public Integer getInteger(String key, Integer defaultValue)
{
return this.getCurrentConfig().getInteger(key, defaultValue);
}
@Override
protected Iterator getKeysInternal()
{
return this.getCurrentConfig().getKeys();
}
@Override
protected Iterator getKeysInternal(String prefix)
{
return this.getCurrentConfig().getKeys(prefix);
}
@Override
public List