org.apache.commons.configuration.DefaultConfigurationBuilder Maven / Gradle / Ivy
Show all versions of driver-cql-shaded 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.configuration;
import java.io.File;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.apache.commons.configuration.beanutils.BeanDeclaration;
import org.apache.commons.configuration.beanutils.BeanFactory;
import org.apache.commons.configuration.beanutils.BeanHelper;
import org.apache.commons.configuration.beanutils.DefaultBeanFactory;
import org.apache.commons.configuration.beanutils.XMLBeanDeclaration;
import org.apache.commons.configuration.event.ConfigurationErrorListener;
import org.apache.commons.configuration.event.ConfigurationListener;
import org.apache.commons.configuration.interpol.ConfigurationInterpolator;
import org.apache.commons.configuration.resolver.CatalogResolver;
import org.apache.commons.configuration.resolver.EntityRegistry;
import org.apache.commons.configuration.resolver.EntityResolverSupport;
import org.apache.commons.configuration.tree.ConfigurationNode;
import org.apache.commons.configuration.tree.DefaultExpressionEngine;
import org.apache.commons.configuration.tree.OverrideCombiner;
import org.apache.commons.configuration.tree.UnionCombiner;
import org.apache.commons.lang.text.StrLookup;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.xml.sax.EntityResolver;
/**
*
* A factory class that creates a composite configuration from an XML based
* configuration definition file.
*
*
* This class provides an easy and flexible means for loading multiple
* configuration sources and combining the results into a single configuration
* object. The sources to be loaded are defined in an XML document that can
* contain certain tags representing the different supported configuration
* classes. If such a tag is found, the corresponding {@code Configuration}
* class is instantiated and initialized using the classes of the
* {@code beanutils} package (namely
* {@link org.apache.commons.configuration.beanutils.XMLBeanDeclaration XMLBeanDeclaration}
* will be used to extract the configuration's initialization parameters, which
* allows for complex initialization scenarios).
*
*
* It is also possible to add custom tags to the configuration definition file.
* For this purpose register your own {@code ConfigurationProvider}
* implementation for your tag using the {@code addConfigurationProvider()}
* method. This provider will then be called when the corresponding custom tag
* is detected. For the default configuration classes providers are already
* registered.
*
*
* The configuration definition file has the following basic structure:
*
*
*
*
* <configuration systemProperties="properties file name">
* <header>
* <!-- Optional meta information about the composite configuration -->
* </header>
* <override>
* <!-- Declarations for override configurations -->
* </override>
* <additional>
* <!-- Declarations for union configurations -->
* </additional>
* </configuration>
*
*
*
*
* The name of the root element (here {@code configuration}) is
* arbitrary. The optional systemProperties attribute identifies the path to
* a property file containing properties that should be added to the system
* properties. If specified on the root element, the system properties are
* set before the rest of the configuration is processed.
*
*
* There are two sections (both of them are optional) for declaring
* override and additional configurations. Configurations
* in the former section are evaluated in the order of their declaration, and
* properties of configurations declared earlier hide those of configurations
* declared later. Configurations in the latter section are combined to a union
* configuration, i.e. all of their properties are added to a large hierarchical
* configuration. Configuration declarations that occur as direct children of
* the root element are treated as override declarations.
*
*
* Each configuration declaration consists of a tag whose name is associated
* with a {@code ConfigurationProvider}. This can be one of the
* predefined tags like {@code properties}, or {@code xml}, or
* a custom tag, for which a configuration provider was registered. Attributes
* and sub elements with specific initialization parameters can be added. There
* are some reserved attributes with a special meaning that can be used in every
* configuration declaration:
*
*
*
*
* Attribute
* Meaning
*
*
* {@code config-name}
* Allows to specify a name for this configuration. This name can be used
* to obtain a reference to the configuration from the resulting combined
* configuration (see below).
*
*
* {@code config-at}
* With this attribute an optional prefix can be specified for the
* properties of the corresponding configuration.
*
*
* {@code config-optional}
* Declares a configuration as optional. This means that errors that occur
* when creating the configuration are ignored. (However
* {@link org.apache.commons.configuration.event.ConfigurationErrorListener}s
* registered at the builder instance will get notified about this error: they
* receive an event of type {@code EVENT_ERR_LOAD_OPTIONAL}. The key
* property of this event contains the name of the optional configuration source
* that caused this problem.)
*
*
*
*
* The optional header section can contain some meta data about the
* created configuration itself. For instance, it is possible to set further
* properties of the {@code NodeCombiner} objects used for constructing
* the resulting configuration.
*
*
* The default configuration object returned by this builder is an instance of the
* {@link CombinedConfiguration} class. The return value of the
* {@code getConfiguration()} method can be casted to this type, and the
* {@code getConfiguration(boolean)} method directly declares
* {@code CombinedConfiguration} as return type. This allows for
* convenient access to the configuration objects maintained by the combined
* configuration (e.g. for updates of single configuration objects). It has also
* the advantage that the properties stored in all declared configuration
* objects are collected and transformed into a single hierarchical structure,
* which can be accessed using different expression engines. The actual CombinedConfiguration
* implementation can be overridden by specifying the class in the config-class
* attribute of the result element.
*
*
* A custom EntityResolver can be used for all XMLConfigurations by adding
*
* <entity-resolver config-class="EntityResolver fully qualified class name">
*
* The CatalogResolver can be used for all XMLConfiguration by adding
*
* <entity-resolver catalogFiles="comma separated list of catalog files">
*
*
*
* Additional ConfigurationProviders can be added by configuring them in the header
* section.
*
* <providers>
* <provider config-tag="tag name" config-class="provider fully qualified class name"/>
* </providers>
*
*
*
* Additional variable resolvers can be added by configuring them in the header
* section.
*
* <lookups>
* <lookup config-prefix="prefix" config-class="StrLookup fully qualified class name"/>
* </lookups>
*
*
*
* All declared override configurations are directly added to the resulting
* combined configuration. If they are given names (using the
* {@code config-name} attribute), they can directly be accessed using
* the {@code getConfiguration(String)} method of
* {@code CombinedConfiguration}. The additional configurations are
* altogether added to another combined configuration, which uses a union
* combiner. Then this union configuration is added to the resulting combined
* configuration under the name defined by the {@code ADDITIONAL_NAME}
* constant.
*
*
* Implementation note: This class is not thread-safe. Especially the
* {@code getConfiguration()} methods should be called by a single thread
* only.
*
*
* @since 1.3
* @author Commons
* Configuration team
* @version $Id: DefaultConfigurationBuilder.java 1366930 2012-07-29 20:05:36Z oheger $
*/
public class DefaultConfigurationBuilder extends XMLConfiguration implements
ConfigurationBuilder
{
/**
* Constant for the name of the additional configuration. If the
* configuration definition file contains an {@code additional}
* section, a special union configuration is created and added under this
* name to the resulting combined configuration.
*/
public static final String ADDITIONAL_NAME = DefaultConfigurationBuilder.class
.getName()
+ "/ADDITIONAL_CONFIG";
/**
* Constant for the type of error events caused by optional configurations
* that cannot be loaded.
*/
public static final int EVENT_ERR_LOAD_OPTIONAL = 51;
/** Constant for the name of the configuration bean factory. */
static final String CONFIG_BEAN_FACTORY_NAME = DefaultConfigurationBuilder.class
.getName()
+ ".CONFIG_BEAN_FACTORY_NAME";
/** Constant for the reserved name attribute. */
static final String ATTR_NAME = DefaultExpressionEngine.DEFAULT_ATTRIBUTE_START
+ XMLBeanDeclaration.RESERVED_PREFIX
+ "name"
+ DefaultExpressionEngine.DEFAULT_ATTRIBUTE_END;
/** Constant for the name of the at attribute. */
static final String ATTR_ATNAME = "at";
/** Constant for the reserved at attribute. */
static final String ATTR_AT_RES = DefaultExpressionEngine.DEFAULT_ATTRIBUTE_START
+ XMLBeanDeclaration.RESERVED_PREFIX
+ ATTR_ATNAME
+ DefaultExpressionEngine.DEFAULT_ATTRIBUTE_END;
/** Constant for the at attribute without the reserved prefix. */
static final String ATTR_AT = DefaultExpressionEngine.DEFAULT_ATTRIBUTE_START
+ ATTR_ATNAME + DefaultExpressionEngine.DEFAULT_ATTRIBUTE_END;
/** Constant for the name of the optional attribute. */
static final String ATTR_OPTIONALNAME = "optional";
/** Constant for the reserved optional attribute. */
static final String ATTR_OPTIONAL_RES = DefaultExpressionEngine.DEFAULT_ATTRIBUTE_START
+ XMLBeanDeclaration.RESERVED_PREFIX
+ ATTR_OPTIONALNAME
+ DefaultExpressionEngine.DEFAULT_ATTRIBUTE_END;
/** Constant for the optional attribute without the reserved prefix. */
static final String ATTR_OPTIONAL = DefaultExpressionEngine.DEFAULT_ATTRIBUTE_START
+ ATTR_OPTIONALNAME + DefaultExpressionEngine.DEFAULT_ATTRIBUTE_END;
/** Constant for the file name attribute. */
static final String ATTR_FILENAME = DefaultExpressionEngine.DEFAULT_ATTRIBUTE_START
+ "fileName" + DefaultExpressionEngine.DEFAULT_ATTRIBUTE_END;
/** Constant for the forceCreate attribute. */
static final String ATTR_FORCECREATE = DefaultExpressionEngine.DEFAULT_ATTRIBUTE_START
+ XMLBeanDeclaration.RESERVED_PREFIX
+ "forceCreate"
+ DefaultExpressionEngine.DEFAULT_ATTRIBUTE_END;
/**
* Constant for the tag attribute for providers.
*/
static final String KEY_SYSTEM_PROPS = "[@systemProperties]";
/** Constant for the name of the header section. */
static final String SEC_HEADER = "header";
/** Constant for an expression that selects the union configurations. */
static final String KEY_UNION = "additional";
/** An array with the names of top level configuration sections.*/
static final String[] CONFIG_SECTIONS = {
"additional", "override", SEC_HEADER
};
/**
* Constant for an expression that selects override configurations in the
* override section.
*/
static final String KEY_OVERRIDE = "override";
/**
* Constant for the key that points to the list nodes definition of the
* override combiner.
*/
static final String KEY_OVERRIDE_LIST = SEC_HEADER
+ ".combiner.override.list-nodes.node";
/**
* Constant for the key that points to the list nodes definition of the
* additional combiner.
*/
static final String KEY_ADDITIONAL_LIST = SEC_HEADER
+ ".combiner.additional.list-nodes.node";
/**
* Constant for the key for defining providers in the configuration file.
*/
static final String KEY_CONFIGURATION_PROVIDERS = SEC_HEADER
+ ".providers.provider";
/**
* Constant for the tag attribute for providers.
*/
static final String KEY_PROVIDER_KEY = XMLBeanDeclaration.ATTR_PREFIX + "tag]";
/**
* Constant for the key for defining variable resolvers
*/
static final String KEY_CONFIGURATION_LOOKUPS = SEC_HEADER
+ ".lookups.lookup";
/**
* Constant for the key for defining entity resolvers
*/
static final String KEY_ENTITY_RESOLVER = SEC_HEADER + ".entity-resolver";
/**
* Constant for the prefix attribute for lookups.
*/
static final String KEY_LOOKUP_KEY = XMLBeanDeclaration.ATTR_PREFIX + "prefix]";
/**
* Constance for the FileSystem.
*/
static final String FILE_SYSTEM = SEC_HEADER + ".fileSystem";
/**
* Constant for the key of the result declaration. This key can point to a
* bean declaration, which defines properties of the resulting combined
* configuration.
*/
static final String KEY_RESULT = SEC_HEADER + ".result";
/** Constant for the key of the combiner in the result declaration.*/
static final String KEY_COMBINER = KEY_RESULT + ".nodeCombiner";
/** Constant for the XML file extension. */
static final String EXT_XML = ".xml";
/** Constant for the provider for properties files. */
private static final ConfigurationProvider PROPERTIES_PROVIDER = new FileExtensionConfigurationProvider(
XMLPropertiesConfiguration.class, PropertiesConfiguration.class,
EXT_XML);
/** Constant for the provider for XML files. */
private static final ConfigurationProvider XML_PROVIDER = new XMLConfigurationProvider();
/** Constant for the provider for JNDI sources. */
private static final ConfigurationProvider JNDI_PROVIDER = new ConfigurationProvider(
JNDIConfiguration.class);
/** Constant for the provider for system properties. */
private static final ConfigurationProvider SYSTEM_PROVIDER = new ConfigurationProvider(
SystemConfiguration.class);
/** Constant for the provider for ini files. */
private static final ConfigurationProvider INI_PROVIDER =
new FileConfigurationProvider(HierarchicalINIConfiguration.class);
/** Constant for the provider for environment properties. */
private static final ConfigurationProvider ENV_PROVIDER =
new ConfigurationProvider(EnvironmentConfiguration.class);
/** Constant for the provider for plist files. */
private static final ConfigurationProvider PLIST_PROVIDER = new FileExtensionConfigurationProvider(
"org.apache.commons.configuration.plist.XMLPropertyListConfiguration",
"org.apache.commons.configuration.plist.PropertyListConfiguration",
EXT_XML);
/** Constant for the provider for configuration definition files.*/
private static final ConfigurationProvider BUILDER_PROVIDER = new ConfigurationBuilderProvider();
/** An array with the names of the default tags. */
private static final String[] DEFAULT_TAGS = {
"properties", "xml", "hierarchicalXml", "jndi", "system", "plist",
"configuration", "ini", "env"
};
/** An array with the providers for the default tags. */
private static final ConfigurationProvider[] DEFAULT_PROVIDERS = {
PROPERTIES_PROVIDER, XML_PROVIDER, XML_PROVIDER, JNDI_PROVIDER,
SYSTEM_PROVIDER, PLIST_PROVIDER, BUILDER_PROVIDER, INI_PROVIDER,
ENV_PROVIDER
};
/**
* The serial version UID.
*/
private static final long serialVersionUID = -3113777854714492123L;
/**
* A specialized {@code StrLookup} object which operates on the combined
* configuration constructed by this builder. This object is used as
* default lookup for {@code ConfigurationInterpolator} objects assigned to
* newly created configuration objects.
*/
private final StrLookup combinedConfigLookup = new StrLookup()
{
@Override
public String lookup(String key)
{
if (constructedConfiguration != null)
{
Object value =
constructedConfiguration.resolveContainerStore(key);
return (value != null) ? value.toString() : null;
}
return null;
}
};
/** Stores the configuration that is currently constructed.*/
private CombinedConfiguration constructedConfiguration;
/** Stores a map with the registered configuration providers. */
private final Map providers;
/** Stores the base path to the configuration sources to load. */
private String configurationBasePath;
/**
* Creates a new instance of {@code DefaultConfigurationBuilder}. A
* configuration definition file is not yet loaded. Use the diverse setter
* methods provided by file based configurations to specify the
* configuration definition file.
*/
public DefaultConfigurationBuilder()
{
super();
providers = new HashMap();
registerDefaultProviders();
registerBeanFactory();
setLogger(LogFactory.getLog(getClass()));
addErrorLogListener(); // log errors per default
}
/**
* Creates a new instance of {@code DefaultConfigurationBuilder} and
* sets the specified configuration definition file.
*
* @param file the configuration definition file
*/
public DefaultConfigurationBuilder(File file)
{
this();
setFile(file);
}
/**
* Creates a new instance of {@code DefaultConfigurationBuilder} and
* sets the specified configuration definition file.
*
* @param fileName the name of the configuration definition file
* @throws ConfigurationException if an error occurs when the file is loaded
*/
public DefaultConfigurationBuilder(String fileName)
throws ConfigurationException
{
this();
setFileName(fileName);
}
/**
* Creates a new instance of {@code DefaultConfigurationBuilder} and
* sets the specified configuration definition file.
*
* @param url the URL to the configuration definition file
* @throws ConfigurationException if an error occurs when the file is loaded
*/
public DefaultConfigurationBuilder(URL url) throws ConfigurationException
{
this();
setURL(url);
}
/**
* Returns the base path for the configuration sources to load. This path is
* used to resolve relative paths in the configuration definition file.
*
* @return the base path for configuration sources
*/
public String getConfigurationBasePath()
{
return (configurationBasePath != null) ? configurationBasePath
: getBasePath();
}
/**
* Sets the base path for the configuration sources to load. Normally a base
* path need not to be set because it is determined by the location of the
* configuration definition file to load. All relative paths in this file
* are resolved relative to this file. Setting a base path makes sense if
* such relative paths should be otherwise resolved, e.g. if the
* configuration file is loaded from the class path and all sub
* configurations it refers to are stored in a special config directory.
*
* @param configurationBasePath the new base path to set
*/
public void setConfigurationBasePath(String configurationBasePath)
{
this.configurationBasePath = configurationBasePath;
}
/**
* Adds a configuration provider for the specified tag. Whenever this tag is
* encountered in the configuration definition file this provider will be
* called to create the configuration object.
*
* @param tagName the name of the tag in the configuration definition file
* @param provider the provider for this tag
*/
public void addConfigurationProvider(String tagName,
ConfigurationProvider provider)
{
if (tagName == null)
{
throw new IllegalArgumentException("Tag name must not be null!");
}
if (provider == null)
{
throw new IllegalArgumentException("Provider must not be null!");
}
providers.put(tagName, provider);
}
/**
* Removes the configuration provider for the specified tag name.
*
* @param tagName the tag name
* @return the removed configuration provider or null if none was
* registered for that tag
*/
public ConfigurationProvider removeConfigurationProvider(String tagName)
{
return providers.remove(tagName);
}
/**
* Returns the configuration provider for the given tag.
*
* @param tagName the name of the tag
* @return the provider that was registered for this tag or null if
* there is none
*/
public ConfigurationProvider providerForTag(String tagName)
{
return providers.get(tagName);
}
/**
* Returns the configuration provided by this builder. Loads and parses the
* configuration definition file and creates instances for the declared
* configurations.
*
* @return the configuration
* @throws ConfigurationException if an error occurs
*/
public Configuration getConfiguration() throws ConfigurationException
{
return getConfiguration(true);
}
/**
* Returns the configuration provided by this builder. If the boolean
* parameter is true, the configuration definition file will be
* loaded. It will then be parsed, and instances for the declared
* configurations will be created.
*
* @param load a flag whether the configuration definition file should be
* loaded; a value of false would make sense if the file has already
* been created or its content was manipulated using some of the property
* accessor methods
* @return the configuration
* @throws ConfigurationException if an error occurs
*/
public CombinedConfiguration getConfiguration(boolean load)
throws ConfigurationException
{
if (load)
{
load();
}
initFileSystem();
initSystemProperties();
configureEntityResolver();
registerConfiguredProviders();
registerConfiguredLookups();
CombinedConfiguration result = createResultConfiguration();
constructedConfiguration = result;
List overrides = fetchTopLevelOverrideConfigs();
overrides.addAll(fetchChildConfigs(KEY_OVERRIDE));
initCombinedConfiguration(result, overrides, KEY_OVERRIDE_LIST);
List additionals = fetchChildConfigs(KEY_UNION);
if (!additionals.isEmpty())
{
CombinedConfiguration addConfig = createAdditionalsConfiguration(result);
result.addConfiguration(addConfig, ADDITIONAL_NAME);
initCombinedConfiguration(addConfig, additionals,
KEY_ADDITIONAL_LIST);
}
return result;
}
/**
* Creates the resulting combined configuration. This method is called by
* {@code getConfiguration()}. It checks whether the
* {@code header} section of the configuration definition file
* contains a {@code result} element. If this is the case, it will be
* used to initialize the properties of the newly created configuration
* object.
*
* @return the resulting configuration object
* @throws ConfigurationException if an error occurs
*/
protected CombinedConfiguration createResultConfiguration()
throws ConfigurationException
{
XMLBeanDeclaration decl = new XMLBeanDeclaration(this, KEY_RESULT, true);
CombinedConfiguration result = (CombinedConfiguration) BeanHelper
.createBean(decl, CombinedConfiguration.class);
if (getMaxIndex(KEY_COMBINER) < 0)
{
// No combiner defined => set default
result.setNodeCombiner(new OverrideCombiner());
}
return result;
}
/**
* Creates the {@code CombinedConfiguration} for the configuration
* sources in the <additional>
section. This method is
* called when the builder constructs the final configuration. It creates a
* new {@code CombinedConfiguration} and initializes some properties
* from the result configuration.
*
* @param resultConfig the result configuration (this is the configuration
* that will be returned by the builder)
* @return the {@code CombinedConfiguration} for the additional
* configuration sources
* @since 1.7
*/
protected CombinedConfiguration createAdditionalsConfiguration(
CombinedConfiguration resultConfig)
{
CombinedConfiguration addConfig =
new CombinedConfiguration(new UnionCombiner());
addConfig.setDelimiterParsingDisabled(resultConfig
.isDelimiterParsingDisabled());
addConfig.setForceReloadCheck(resultConfig.isForceReloadCheck());
addConfig.setIgnoreReloadExceptions(resultConfig
.isIgnoreReloadExceptions());
return addConfig;
}
/**
* Initializes a combined configuration for the configurations of a specific
* section. This method is called for the override and for the additional
* section (if it exists).
*
* @param config the configuration to be initialized
* @param containedConfigs the list with the declarations of the contained
* configurations
* @param keyListNodes a list with the declaration of list nodes
* @throws ConfigurationException if an error occurs
*/
protected void initCombinedConfiguration(CombinedConfiguration config,
List extends HierarchicalConfiguration> containedConfigs,
String keyListNodes) throws ConfigurationException
{
List