You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by oh...@apache.org on 2013/01/13 22:16:41 UTC
svn commit: r1432744 - in /commons/proper/configuration/trunk/src:
main/java/org/apache/commons/configuration/builder/combined/
test/java/org/apache/commons/configuration/builder/combined/
Author: oheger
Date: Sun Jan 13 21:16:40 2013
New Revision: 1432744
URL: http://svn.apache.org/viewvc?rev=1432744&view=rev
Log:
Added MultiFileConfigurationBuilder (as a replacement for MultiFileHierarchicalConfiguration).
Added:
commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/builder/combined/MultiFileConfigurationBuilder.java (with props)
commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/builder/combined/TestMultiFileConfigurationBuilder.java (with props)
Added: commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/builder/combined/MultiFileConfigurationBuilder.java
URL: http://svn.apache.org/viewvc/commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/builder/combined/MultiFileConfigurationBuilder.java?rev=1432744&view=auto
==============================================================================
--- commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/builder/combined/MultiFileConfigurationBuilder.java (added)
+++ commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/builder/combined/MultiFileConfigurationBuilder.java Sun Jan 13 21:16:40 2013
@@ -0,0 +1,377 @@
+/*
+ * 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.builder.combined;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration.ConfigurationException;
+import org.apache.commons.configuration.FileBasedConfiguration;
+import org.apache.commons.configuration.builder.BasicBuilderParameters;
+import org.apache.commons.configuration.builder.BasicConfigurationBuilder;
+import org.apache.commons.configuration.builder.BuilderListener;
+import org.apache.commons.configuration.builder.BuilderParameters;
+import org.apache.commons.configuration.builder.ConfigurationBuilder;
+import org.apache.commons.configuration.builder.FileBasedBuilderParametersImpl;
+import org.apache.commons.configuration.builder.FileBasedConfigurationBuilder;
+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.lang3.concurrent.ConcurrentUtils;
+
+/**
+ * <p>
+ * A specialized {@code ConfigurationBuilder} implementation providing access to
+ * multiple file-based configurations based on a file name pattern.
+ * </p>
+ * <p>
+ * This builder class is initialized with a pattern string and a
+ * {@link ConfigurationInterpolator} object. Each time a configuration is
+ * requested, the pattern is evaluated against the
+ * {@code ConfigurationInterpolator} (so all variables are replaced by their
+ * current values). The resulting string is interpreted as a file name for a
+ * configuration file to be loaded. For example, providing a pattern of
+ * <em>file:///opt/config/${product}/${client}/config.xml</em> will result in
+ * <em>product</em> and <em>client</em> being resolved on every call. By storing
+ * configuration files in a corresponding directory structure, specialized
+ * configuration files associated with a specific product and client can be
+ * loaded. Thus an application can be made multi-tenant in a transparent way.
+ * </p>
+ * <p>
+ * This builder class keeps a map with configuration builders for configurations
+ * already loaded. The {@code getConfiguration()} method first evaluates the
+ * pattern string and checks whether a builder for the resulting file name is
+ * available. If yes, it is queried for its configuration. Otherwise, a new
+ * file-based configuration builder is created now and initialized.
+ * </p>
+ * <p>
+ * Configuration of an instance happens in the usual way for configuration
+ * builders. A {@link MultiFileBuilderParametersImpl} parameters object is
+ * expected which must contain a file name pattern string and a
+ * {@code ConfigurationInterpolator}. Other properties of this parameters object
+ * are used to initialize the builders for managed configurations.
+ * </p>
+ *
+ * @version $Id$
+ * @since 2.0
+ * @param <T> the concrete type of {@code Configuration} objects created by this
+ * builder
+ */
+public class MultiFileConfigurationBuilder<T extends FileBasedConfiguration>
+ extends BasicConfigurationBuilder<T>
+{
+ /**
+ * Constant for the name of the key referencing the
+ * {@code ConfigurationInterpolator} in this builder's parameters.
+ */
+ private static final String KEY_INTERPOLATOR = "interpolator";
+
+ /** A cache for already created managed builders. */
+ private final ConcurrentMap<String, FileBasedConfigurationBuilder<T>> managedBuilders =
+ new ConcurrentHashMap<String, FileBasedConfigurationBuilder<T>>();
+
+ /**
+ * A specialized builder listener which gets registered at all managed
+ * builders. This listener just propagates notifications from managed
+ * builders to the listeners registered at this
+ * {@code MultiFileConfigurationBuilder}.
+ */
+ private final BuilderListener managedBuilderDelegationListener =
+ new BuilderListener()
+ {
+ public void builderReset(
+ ConfigurationBuilder<? extends Configuration> builder)
+ {
+ resetResult();
+ }
+ };
+
+ /**
+ * Creates a new instance of {@code MultiFileConfigurationBuilder} and sets
+ * initialization parameters and a flag whether initialization failures
+ * should be ignored.
+ *
+ * @param resCls the result configuration class
+ * @param params a map with initialization parameters
+ * @param allowFailOnInit a flag whether initialization errors should be
+ * ignored
+ * @throws IllegalArgumentException if the result class is <b>null</b>
+ */
+ public MultiFileConfigurationBuilder(Class<T> resCls,
+ Map<String, Object> params, boolean allowFailOnInit)
+ {
+ super(resCls, params, allowFailOnInit);
+ }
+
+ /**
+ * Creates a new instance of {@code MultiFileConfigurationBuilder} and sets
+ * initialization parameters.
+ *
+ * @param resCls the result configuration class
+ * @param params a map with initialization parameters
+ * @throws IllegalArgumentException if the result class is <b>null</b>
+ */
+ public MultiFileConfigurationBuilder(Class<T> resCls,
+ Map<String, Object> params)
+ {
+ super(resCls, params);
+ }
+
+ /**
+ * Creates a new instance of {@code MultiFileConfigurationBuilder} without
+ * setting initialization parameters.
+ *
+ * @param resCls the result configuration class
+ * @throws IllegalArgumentException if the result class is <b>null</b>
+ */
+ public MultiFileConfigurationBuilder(Class<T> resCls)
+ {
+ super(resCls);
+ }
+
+ /**
+ * {@inheritDoc} This implementation evaluates the file name pattern using
+ * the configured {@code ConfigurationInterpolator}. If this file has
+ * already been loaded, the corresponding builder is accessed. Otherwise, a
+ * new builder is created for loading this configuration file.
+ */
+ @Override
+ public T getConfiguration() throws ConfigurationException
+ {
+ Map<String, Object> params = getParameters();
+ MultiFileBuilderParametersImpl multiParams =
+ MultiFileBuilderParametersImpl.fromParameters(params, true);
+ if (multiParams.getFilePattern() == null)
+ {
+ throw new ConfigurationException("No file name pattern is set!");
+ }
+ String fileName = constructFileName(params, multiParams);
+
+ FileBasedConfigurationBuilder<T> builder =
+ managedBuilders.get(fileName);
+ if (builder == null)
+ {
+ builder =
+ createInitializedManagedBuilder(fileName,
+ createManagedBuilderParameters(params, multiParams));
+ FileBasedConfigurationBuilder<T> newBuilder =
+ ConcurrentUtils.putIfAbsent(managedBuilders, fileName,
+ builder);
+ if (newBuilder == builder)
+ {
+ initListeners(newBuilder);
+ }
+ else
+ {
+ builder = newBuilder;
+ }
+ }
+
+ return builder.getConfiguration();
+ }
+
+ /**
+ * {@inheritDoc} This implementation ensures that the listener is also added
+ * at managed configuration builders.
+ */
+ @Override
+ public synchronized BasicConfigurationBuilder<T> addConfigurationListener(
+ ConfigurationListener l)
+ {
+ super.addConfigurationListener(l);
+ for (FileBasedConfigurationBuilder<T> b : managedBuilders.values())
+ {
+ b.addConfigurationListener(l);
+ }
+ return this;
+ }
+
+ /**
+ * {@inheritDoc} This implementation ensures that the listener is also
+ * removed from managed configuration builders.
+ */
+ @Override
+ public synchronized BasicConfigurationBuilder<T> removeConfigurationListener(
+ ConfigurationListener l)
+ {
+ super.removeConfigurationListener(l);
+ for (FileBasedConfigurationBuilder<T> b : managedBuilders.values())
+ {
+ b.removeConfigurationListener(l);
+ }
+ return this;
+ }
+
+ /**
+ * {@inheritDoc} This implementation ensures that the listener is also added
+ * at managed configuration builders.
+ */
+ @Override
+ public synchronized BasicConfigurationBuilder<T> addErrorListener(
+ ConfigurationErrorListener l)
+ {
+ super.addErrorListener(l);
+ for (FileBasedConfigurationBuilder<T> b : managedBuilders.values())
+ {
+ b.addErrorListener(l);
+ }
+ return this;
+ }
+
+ /**
+ * {@inheritDoc} This implementation ensures that the listener is also
+ * removed from managed configuration builders.
+ */
+ @Override
+ public synchronized BasicConfigurationBuilder<T> removeErrorListener(
+ ConfigurationErrorListener l)
+ {
+ super.removeErrorListener(l);
+ for (FileBasedConfigurationBuilder<T> b : managedBuilders.values())
+ {
+ b.removeErrorListener(l);
+ }
+ return this;
+ }
+
+ /**
+ * {@inheritDoc} This implementation clears the cache with all managed
+ * builders.
+ */
+ @Override
+ public synchronized void resetParameters()
+ {
+ for (FileBasedConfigurationBuilder<T> b : managedBuilders.values())
+ {
+ b.removeBuilderListener(managedBuilderDelegationListener);
+ }
+ managedBuilders.clear();
+ super.resetParameters();
+ }
+
+ /**
+ * Determines the file name of a configuration based on the file name
+ * pattern. This method is called on every access to this builder's
+ * configuration. It obtains the {@link ConfigurationInterpolator} from this
+ * builder's parameters and uses it to interpolate the file name pattern.
+ *
+ * @param paramsMap the map with the current parameters of this builder
+ * @param multiParams the parameters object for this builder
+ * @return the name of the configuration file to be loaded
+ */
+ protected String constructFileName(Map<String, Object> paramsMap,
+ MultiFileBuilderParametersImpl multiParams)
+ {
+ ConfigurationInterpolator ci =
+ BasicBuilderParameters.fetchInterpolator(paramsMap);
+ // TODO Make this more generic, handle missing CI
+ return String.valueOf(ci.interpolate(multiParams.getFilePattern()));
+ }
+
+ /**
+ * Creates a builder for a managed configuration. This method is called
+ * whenever a configuration for a file name is requested which has not yet
+ * been loaded. The passed in map with parameters is populated from this
+ * builder's configuration (i.e. the basic parameters plus the optional
+ * parameters for managed builders). This base implementation creates a
+ * standard builder for file-based configurations. Derived classes may
+ * override it to create special purpose builders.
+ *
+ * @param fileName the name of the file to be loaded
+ * @param params a map with initialization parameters for the new builder
+ * @return the newly created builder instance
+ * @throws ConfigurationException if an error occurs
+ */
+ protected FileBasedConfigurationBuilder<T> createManagedBuilder(
+ String fileName, Map<String, Object> params)
+ throws ConfigurationException
+ {
+ return new FileBasedConfigurationBuilder<T>(getResultClass(), params,
+ isAllowFailOnInit());
+ }
+
+ /**
+ * Creates a fully initialized builder for a managed configuration. This
+ * method is called by {@code getConfiguration()} whenever a configuration
+ * file is requested which has not yet been loaded. This implementation
+ * delegates to {@code createManagedBuilder()} for actually creating the
+ * builder object. Then it sets the location to the configuration file.
+ *
+ * @param fileName the name of the file to be loaded
+ * @param params a map with initialization parameters for the new builder
+ * @return the newly created and initialized builder instance
+ * @throws ConfigurationException if an error occurs
+ */
+ protected FileBasedConfigurationBuilder<T> createInitializedManagedBuilder(
+ String fileName, Map<String, Object> params)
+ throws ConfigurationException
+ {
+ FileBasedConfigurationBuilder<T> managedBuilder =
+ createManagedBuilder(fileName, params);
+ managedBuilder.getFileHandler().setFileName(fileName);
+ return managedBuilder;
+ }
+
+ /**
+ * Registers event listeners at the passed in newly created managed builder.
+ * This method registers a special {@code BuilderListener} which propagates
+ * builder events to listeners registered at this builder. In addition,
+ * {@code ConfigurationListener} and {@code ConfigurationErrorListener}
+ * objects are registered at the new builder.
+ *
+ * @param newBuilder the builder to be initialized
+ */
+ private void initListeners(FileBasedConfigurationBuilder<T> newBuilder)
+ {
+ copyEventListeners(newBuilder);
+ newBuilder.addBuilderListener(managedBuilderDelegationListener);
+ }
+
+ /**
+ * Creates a map with parameters for a new managed configuration builder.
+ * This method merges the basic parameters set for this builder with the
+ * specific parameters object for managed builders (if provided).
+ *
+ * @param params the parameters of this builder
+ * @param multiParams the parameters object for this builder
+ * @return the parameters for a new managed builder
+ */
+ private static Map<String, Object> createManagedBuilderParameters(
+ Map<String, Object> params,
+ MultiFileBuilderParametersImpl multiParams)
+ {
+ Map<String, Object> newParams = new HashMap<String, Object>(params);
+ newParams.remove(KEY_INTERPOLATOR);
+ BuilderParameters managedBuilderParameters =
+ multiParams.getManagedBuilderParameters();
+ if (managedBuilderParameters != null)
+ {
+ newParams.putAll(managedBuilderParameters.getParameters());
+ }
+
+ // ensure that file-based parameters are available
+ if (FileBasedBuilderParametersImpl.fromParameters(newParams) == null)
+ {
+ newParams.putAll(new FileBasedBuilderParametersImpl()
+ .getParameters());
+ }
+ return newParams;
+ }
+}
Propchange: commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/builder/combined/MultiFileConfigurationBuilder.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/builder/combined/MultiFileConfigurationBuilder.java
------------------------------------------------------------------------------
svn:keywords = Date Author Id Revision HeadURL
Propchange: commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/builder/combined/MultiFileConfigurationBuilder.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/builder/combined/TestMultiFileConfigurationBuilder.java
URL: http://svn.apache.org/viewvc/commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/builder/combined/TestMultiFileConfigurationBuilder.java?rev=1432744&view=auto
==============================================================================
--- commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/builder/combined/TestMultiFileConfigurationBuilder.java (added)
+++ commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/builder/combined/TestMultiFileConfigurationBuilder.java Sun Jan 13 21:16:40 2013
@@ -0,0 +1,429 @@
+/*
+ * 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.builder.combined;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+import org.apache.commons.configuration.ConfigurationException;
+import org.apache.commons.configuration.XMLConfiguration;
+import org.apache.commons.configuration.builder.BasicBuilderParameters;
+import org.apache.commons.configuration.builder.BuilderListener;
+import org.apache.commons.configuration.builder.BuilderParameters;
+import org.apache.commons.configuration.builder.FileBasedConfigurationBuilder;
+import org.apache.commons.configuration.builder.XMLBuilderParametersImpl;
+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.interpol.DefaultLookups;
+import org.apache.commons.configuration.tree.ExpressionEngine;
+import org.apache.commons.configuration.tree.xpath.XPathExpressionEngine;
+import org.easymock.EasyMock;
+import org.junit.After;
+import org.junit.Test;
+import org.xml.sax.SAXParseException;
+
+/**
+ * Test class for {@code MultiFileConfigurationBuilder}.
+ *
+ * @version $Id$
+ */
+public class TestMultiFileConfigurationBuilder
+{
+ /** The system property which selects a sub configuration. */
+ private static final String PROP = "Id";
+
+ /** The pattern for file names. */
+ private static String PATTERN =
+ "target/test-classes/testMultiConfiguration_${sys:Id}.xml";
+
+ @After
+ public void tearDown() throws Exception
+ {
+ System.getProperties().remove(PROP);
+ }
+
+ /**
+ * Sets a system property for accessing a specific configuration file from
+ * the test builder.
+ *
+ * @param id the ID of the managed configuration to load
+ */
+ private static void switchToConfig(String id)
+ {
+ System.setProperty(PROP, id);
+ }
+
+ /**
+ * Selects a specific configuration to be obtained from the builder.
+ *
+ * @param index the index of the configuration to be accessed (valid indices
+ * are 1-3)
+ */
+ private static void switchToConfig(int index)
+ {
+ switchToConfig("100" + index);
+ }
+
+ /**
+ * Creates a {@code ConfigurationInterpolator} to be used by tests. This
+ * object contains a lookup for system properties.
+ *
+ * @return the new {@code ConfigurationInterpolator}
+ */
+ private static ConfigurationInterpolator createInterpolator()
+ {
+ ConfigurationInterpolator ci = new ConfigurationInterpolator();
+ ci.registerLookup(DefaultLookups.SYSTEM_PROPERTIES.getPrefix(),
+ DefaultLookups.SYSTEM_PROPERTIES.getLookup());
+ return ci;
+ }
+
+ /**
+ * Creates a parameters object with default settings for a test builder
+ * instance.
+ *
+ * @param managedParams the parameters for managed configurations
+ * @return the test parameters
+ */
+ private static BasicBuilderParameters createTestBuilderParameters(
+ BuilderParameters managedParams)
+ {
+ return new MultiFileBuilderParametersImpl().setFilePattern(PATTERN)
+ .setManagedBuilderParameters(managedParams)
+ .setInterpolator(createInterpolator());
+ }
+
+ /**
+ * Creates a test builder object with default settings.
+ *
+ * @param managedParams the parameters for managed configurations
+ * @return the test instance
+ */
+ private static MultiFileConfigurationBuilder<XMLConfiguration> createTestBuilder(
+ BuilderParameters managedParams)
+ {
+ MultiFileConfigurationBuilder<XMLConfiguration> builder =
+ new MultiFileConfigurationBuilder<XMLConfiguration>(
+ XMLConfiguration.class);
+ builder.configure(createTestBuilderParameters(managedParams));
+ return builder;
+ }
+
+ /**
+ * Creates a test builder instance which allows access to the managed
+ * builders created by it. The returned builder instance overrides the
+ * method for creating managed builders. It stores newly created builders in
+ * the passed in collection.
+ *
+ * @param managedBuilders a collection in which to store managed builders
+ * @return the test builder instance
+ */
+ private static MultiFileConfigurationBuilder<XMLConfiguration> createBuilderWithAccessToManagedBuilders(
+ final Collection<FileBasedConfigurationBuilder<XMLConfiguration>> managedBuilders)
+ {
+ MultiFileConfigurationBuilder<XMLConfiguration> builder =
+ new MultiFileConfigurationBuilder<XMLConfiguration>(
+ XMLConfiguration.class)
+ {
+ @Override
+ protected FileBasedConfigurationBuilder<XMLConfiguration> createInitializedManagedBuilder(
+ String fileName,
+ java.util.Map<String, Object> params)
+ throws ConfigurationException
+ {
+ FileBasedConfigurationBuilder<XMLConfiguration> result =
+ super.createInitializedManagedBuilder(fileName,
+ params);
+ managedBuilders.add(result);
+ return result;
+ }
+ };
+ builder.configure(createTestBuilderParameters(null));
+ return builder;
+ }
+
+ /**
+ * Tests whether access to multiple configurations works.
+ */
+ @Test
+ public void testGetConfiguration() throws ConfigurationException
+ {
+ MultiFileConfigurationBuilder<XMLConfiguration> builder =
+ createTestBuilder(null);
+ String key = "rowsPerPage";
+ switchToConfig(1);
+ assertEquals("Wrong property (1)", 15, builder.getConfiguration()
+ .getInt(key));
+ switchToConfig(2);
+ assertEquals("Wrong property (2)", 25, builder.getConfiguration()
+ .getInt(key));
+ switchToConfig(3);
+ assertEquals("Wrong property (3)", 35, builder.getConfiguration()
+ .getInt(key));
+ }
+
+ /**
+ * Tests whether a managed configuration is properly initialized.
+ */
+ @Test
+ public void testManagedConfigurationSettings()
+ throws ConfigurationException
+ {
+ MultiFileConfigurationBuilder<XMLConfiguration> builder =
+ new MultiFileConfigurationBuilder<XMLConfiguration>(
+ XMLConfiguration.class);
+ ExpressionEngine engine = new XPathExpressionEngine();
+ BuilderParameters xmlParams =
+ new XMLBuilderParametersImpl().setExpressionEngine(engine)
+ .setListDelimiter(';');
+ MultiFileBuilderParametersImpl params =
+ new MultiFileBuilderParametersImpl().setFilePattern(PATTERN)
+ .setManagedBuilderParameters(xmlParams);
+ ConfigurationInterpolator ci = createInterpolator();
+ params.setInterpolator(ci).setListDelimiter('#');
+ builder.configure(params);
+ switchToConfig(1);
+ XMLConfiguration config = builder.getConfiguration();
+ assertSame("Wrong expression engine", engine,
+ config.getExpressionEngine());
+ assertEquals("Wrong list delimiter", ';', config.getListDelimiter());
+ assertNotSame("Interpolator was copied", ci, config.getInterpolator());
+ }
+
+ /**
+ * Tests whether XML schema validation can be enabled.
+ */
+ @Test
+ public void testSchemaValidationError() throws ConfigurationException
+ {
+ MultiFileConfigurationBuilder<XMLConfiguration> builder =
+ createTestBuilder(new XMLBuilderParametersImpl().setValidating(
+ true).setSchemaValidation(true));
+ switchToConfig("2001");
+ try
+ {
+ builder.getConfiguration();
+ fail("No exception thrown");
+ }
+ catch (ConfigurationException ex)
+ {
+ Throwable cause = ex.getCause();
+ while (cause != null && !(cause instanceof SAXParseException))
+ {
+ cause = cause.getCause();
+ }
+ assertTrue("SAXParseException was not thrown",
+ cause instanceof SAXParseException);
+ }
+ }
+
+ /**
+ * Tests the behavior if a configuration is accessed which cannot be
+ * located.
+ */
+ @Test(expected = ConfigurationException.class)
+ public void testFileNotFound() throws ConfigurationException
+ {
+ switchToConfig("unknown configuration ID");
+ createTestBuilder(null).getConfiguration();
+ }
+
+ /**
+ * Tests whether exceptions when creating configurations can be suppressed.
+ */
+ @Test
+ public void testFileNotFoundAllowFailOnInit() throws ConfigurationException
+ {
+ BasicBuilderParameters params = createTestBuilderParameters(null);
+ MultiFileConfigurationBuilder<XMLConfiguration> builder =
+ new MultiFileConfigurationBuilder<XMLConfiguration>(
+ XMLConfiguration.class, params.getParameters(), true);
+ switchToConfig("unknown configuration ID");
+ XMLConfiguration config = builder.getConfiguration();
+ assertTrue("Got content", config.isEmpty());
+ }
+
+ /**
+ * Tests whether a missing file name pattern causes an exception.
+ */
+ @Test(expected = ConfigurationException.class)
+ public void testNoPattern() throws ConfigurationException
+ {
+ BasicBuilderParameters params =
+ new MultiFileBuilderParametersImpl()
+ .setInterpolator(createInterpolator());
+ MultiFileConfigurationBuilder<XMLConfiguration> builder =
+ new MultiFileConfigurationBuilder<XMLConfiguration>(
+ XMLConfiguration.class, params.getParameters(), true);
+ switchToConfig(1);
+ builder.getConfiguration();
+ }
+
+ /**
+ * Tests whether configuration listeners are handled correctly.
+ */
+ @Test
+ public void testAddConfigurationListener() throws ConfigurationException
+ {
+ ConfigurationListener l1 =
+ EasyMock.createMock(ConfigurationListener.class);
+ ConfigurationListener l2 =
+ EasyMock.createMock(ConfigurationListener.class);
+ EasyMock.replay(l1, l2);
+ MultiFileConfigurationBuilder<XMLConfiguration> builder =
+ createTestBuilder(null);
+ assertSame("Wrong result", builder,
+ builder.addConfigurationListener(l1));
+ switchToConfig(1);
+ XMLConfiguration config = builder.getConfiguration();
+ assertTrue("Listener not added", config.getConfigurationListeners()
+ .contains(l1));
+ builder.addConfigurationListener(l2);
+ assertTrue("Listener 2 not added", config.getConfigurationListeners()
+ .contains(l2));
+ builder.removeConfigurationListener(l2);
+ assertFalse("Listener not removed", config.getConfigurationListeners()
+ .contains(l2));
+ switchToConfig(2);
+ XMLConfiguration config2 = builder.getConfiguration();
+ assertFalse("Listener not globally removed", config2
+ .getConfigurationListeners().contains(l2));
+ }
+
+ /**
+ * Tests whether error listeners are handled correctly.
+ */
+ @Test
+ public void testAddErrorListener() throws ConfigurationException
+ {
+ ConfigurationErrorListener l1 =
+ EasyMock.createMock(ConfigurationErrorListener.class);
+ ConfigurationErrorListener l2 =
+ EasyMock.createMock(ConfigurationErrorListener.class);
+ EasyMock.replay(l1, l2);
+ MultiFileConfigurationBuilder<XMLConfiguration> builder =
+ createTestBuilder(null);
+ assertSame("Wrong result", builder, builder.addErrorListener(l1));
+ switchToConfig(1);
+ XMLConfiguration config = builder.getConfiguration();
+ assertTrue("Listener not added", config.getErrorListeners()
+ .contains(l1));
+ builder.addErrorListener(l2);
+ assertTrue("Listener 2 not added",
+ config.getErrorListeners().contains(l2));
+ builder.removeErrorListener(l2);
+ assertFalse("Listener not removed", config.getErrorListeners()
+ .contains(l2));
+ switchToConfig(2);
+ XMLConfiguration config2 = builder.getConfiguration();
+ assertFalse("Listener not globally removed", config2
+ .getErrorListeners().contains(l2));
+ }
+
+ /**
+ * Tests whether managed builders are cached.
+ */
+ @Test
+ public void testCaching() throws ConfigurationException
+ {
+ Collection<FileBasedConfigurationBuilder<XMLConfiguration>> managedBuilders =
+ new ArrayList<FileBasedConfigurationBuilder<XMLConfiguration>>();
+ MultiFileConfigurationBuilder<XMLConfiguration> builder =
+ createBuilderWithAccessToManagedBuilders(managedBuilders);
+ switchToConfig(1);
+ builder.getConfiguration();
+ assertEquals("Wrong number of managed builders (1)", 1,
+ managedBuilders.size());
+ builder.getConfiguration();
+ assertEquals("Wrong number of managed builders (2)", 1,
+ managedBuilders.size());
+ switchToConfig(2);
+ builder.getConfiguration();
+ assertEquals("Wrong number of managed builders (3)", 2,
+ managedBuilders.size());
+ }
+
+ /**
+ * Tests whether a reset of the builder configuration also flushes the
+ * cache.
+ */
+ @Test
+ public void testCachingWithReset() throws ConfigurationException
+ {
+ Collection<FileBasedConfigurationBuilder<XMLConfiguration>> managedBuilders =
+ new ArrayList<FileBasedConfigurationBuilder<XMLConfiguration>>();
+ MultiFileConfigurationBuilder<XMLConfiguration> builder =
+ createBuilderWithAccessToManagedBuilders(managedBuilders);
+ switchToConfig(1);
+ builder.getConfiguration();
+ builder.resetParameters();
+ builder.configure(createTestBuilderParameters(null));
+ builder.getConfiguration();
+ assertEquals("Wrong number of managed builders", 2,
+ managedBuilders.size());
+ }
+
+ /**
+ * Tests whether builder listeners are handled correctly.
+ */
+ @Test
+ public void testBuilderListener() throws ConfigurationException
+ {
+ BuilderListener listener = EasyMock.createMock(BuilderListener.class);
+ Collection<FileBasedConfigurationBuilder<XMLConfiguration>> managedBuilders =
+ new ArrayList<FileBasedConfigurationBuilder<XMLConfiguration>>();
+ MultiFileConfigurationBuilder<XMLConfiguration> builder =
+ createBuilderWithAccessToManagedBuilders(managedBuilders);
+ listener.builderReset(builder);
+ EasyMock.replay(listener);
+ switchToConfig(1);
+ builder.addBuilderListener(listener);
+ builder.getConfiguration();
+ managedBuilders.iterator().next().resetResult();
+ EasyMock.verify(listener);
+ }
+
+ /**
+ * Tests whether listeners at managed builders are removed when the cache is
+ * cleared.
+ */
+ @Test
+ public void testRemoveBuilderListenerOnReset()
+ throws ConfigurationException
+ {
+ BuilderListener listener = EasyMock.createMock(BuilderListener.class);
+ Collection<FileBasedConfigurationBuilder<XMLConfiguration>> managedBuilders =
+ new ArrayList<FileBasedConfigurationBuilder<XMLConfiguration>>();
+ MultiFileConfigurationBuilder<XMLConfiguration> builder =
+ createBuilderWithAccessToManagedBuilders(managedBuilders);
+ EasyMock.replay(listener);
+ switchToConfig(1);
+ builder.addBuilderListener(listener);
+ builder.getConfiguration();
+ builder.resetParameters();
+ managedBuilders.iterator().next().resetResult();
+ EasyMock.verify(listener);
+ }
+}
Propchange: commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/builder/combined/TestMultiFileConfigurationBuilder.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/builder/combined/TestMultiFileConfigurationBuilder.java
------------------------------------------------------------------------------
svn:keywords = Date Author Id Revision HeadURL
Propchange: commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/builder/combined/TestMultiFileConfigurationBuilder.java
------------------------------------------------------------------------------
svn:mime-type = text/plain