Author: oheger
Date: Wed Oct 3 19:18:11 2012
New Revision: 1393698
URL: http://svn.apache.org/viewvc?rev=1393698&view=rev
Log:
Initial implementation of BasicConfigurationBuilder.
Added:
commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/builder/BasicConfigurationBuilder.java
(with props)
commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/builder/TestBasicConfigurationBuilder.java
(with props)
Added:
commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/builder/BasicConfigurationBuilder.java
URL:
http://svn.apache.org/viewvc/commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/builder/BasicConfigurationBuilder.java?rev=1393698&view=auto
==============================================================================
---
commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/builder/BasicConfigurationBuilder.java
(added)
+++
commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/builder/BasicConfigurationBuilder.java
Wed Oct 3 19:18:11 2012
@@ -0,0 +1,416 @@
+/*
+ * 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;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration.ConfigurationException;
+import org.apache.commons.configuration.ConfigurationRuntimeException;
+import org.apache.commons.configuration.beanutils.BeanDeclaration;
+import org.apache.commons.configuration.beanutils.BeanHelper;
+
+/**
+ * <p>
+ * An implementation of the {@code ConfigurationBuilder} interface which is
able
+ * to create different concrete {@code Configuration} implementations based on
+ * reflection.
+ * </p>
+ * <p>
+ * When constructing an instance of this class the concrete
+ * {@code Configuration} implementation class has to be provided. Then
+ * properties for the new {@code Configuration} instance can be set. The first
+ * call to {@code getConfiguration()} creates and initializes the new
+ * {@code Configuration} object. It is cached and returned by subsequent calls.
+ * This cache - and also the initialization properties set so far - can be
+ * flushed by calling one of the {@code reset()} methods. That way other
+ * {@code Configuration} instances with different properties can be created.
+ * </p>
+ * <p>
+ * There are multiple options for setting up a {@code
BasicConfigurationBuilder}
+ * instance:
+ * <ul>
+ * <li>All initialization properties can be set in one or multiple calls of the
+ * {@code configure()} method. In each call an arbitrary number of
+ * {@link BuilderParameters} objects can be passed. The API allows method
+ * chaining and is intended to be used from Java code.</li>
+ * <li>If builder instances are created by other means - e.g. using a
dependency
+ * injection framework -, the fluent API approach may not be suitable. For
those
+ * use cases it is also possible to pass in all initialization parameters as a
+ * map. The keys of the map have to match initialization properties of the
+ * {@code Configuration} object to be created, the values are the corresponding
+ * property values. For instance, the key <em>throwExceptionOnMissing</em> in
+ * the map will cause the method {@code setThrowExceptionOnMissing()} on the
+ * {@code Configuration} object to be called with the corresponding value as
+ * parameter.</li>
+ * </ul>
+ * </p>
+ * <p>
+ * This class is thread-safe. Multiple threads can modify initialization
+ * properties and call {@code getConfiguration()}. However, the intended use
+ * case is that the builder is configured by a single thread first. Then
+ * {@code getConfiguration()} can be called concurrently, and it is guaranteed
+ * that always the same {@code Configuration} instance is returned until the
+ * builder is reset.
+ * </p>
+ *
+ * @version $Id$
+ * @since 2.0
+ * @param <T> the concrete type of {@code Configuration} objects created by
this
+ * builder
+ */
+public class BasicConfigurationBuilder<T extends Configuration> implements
+ ConfigurationBuilder<T>
+{
+ /** The class of the objects produced by this builder instance. */
+ private final Class<T> resultClass;
+
+ /** The map with current initialization parameters. */
+ private Map<String, Object> parameters;
+
+ /** The current bean declaration. */
+ private BeanDeclaration resultDeclaration;
+
+ /** The result object of this builder. */
+ private volatile T result;
+
+ /**
+ * Creates a new instance of {@code BasicConfigurationBuilder} and
+ * initializes it with the given result class. No initialization properties
+ * are set.
+ *
+ * @param resCls the result class (must not be <b>null</b>
+ * @throws IllegalArgumentException if the result class is <b>null</b>
+ */
+ public BasicConfigurationBuilder(Class<T> resCls)
+ {
+ this(resCls, null);
+ }
+
+ /**
+ * Creates a new instance of {@code BasicConfigurationBuilder} and
+ * initializes it with the given result class and an initial set of builder
+ * parameters. The map with parameters may be <b>null</b>, in this case no
+ * initialization parameters are set.
+ *
+ * @param resCls the result class (must not be <b>null</b>
+ * @param params a map with initialization parameters
+ * @throws IllegalArgumentException if the result class is <b>null</b>
+ */
+ public BasicConfigurationBuilder(Class<T> resCls, Map<String, Object>
params)
+ {
+ if (resCls == null)
+ {
+ throw new IllegalArgumentException("Result class must not be
null!");
+ }
+
+ resultClass = resCls;
+ updateParameters(params);
+ }
+
+ /**
+ * Returns the result class of this builder. The objects produced by this
+ * builder have the class returned here.
+ *
+ * @return the result class of this builder
+ */
+ public Class<T> getResultClass()
+ {
+ return resultClass;
+ }
+
+ /**
+ * Sets the initialization parameters of this builder. Already existing
+ * parameters are replaced by the content of the given map.
+ *
+ * @param params the new initialization parameters of this builder; can be
+ * <b>null</b>, then all initialization parameters are removed
+ * @return a reference to this builder for method chaining
+ */
+ public synchronized BasicConfigurationBuilder<T> setParameters(
+ Map<String, Object> params)
+ {
+ updateParameters(params);
+ return this;
+ }
+
+ /**
+ * Adds the content of the given map to the already existing initialization
+ * parameters.
+ *
+ * @param params the map with additional initialization parameters; may be
+ * <b>null</b>, then this call has no effect
+ * @return a reference to this builder for method chaining
+ */
+ public synchronized BasicConfigurationBuilder<T> addParameters(
+ Map<String, Object> params)
+ {
+ Map<String, Object> newParams =
+ new HashMap<String, Object>(getParameters());
+ if (params != null)
+ {
+ newParams.putAll(params);
+ }
+ updateParameters(newParams);
+ return this;
+ }
+
+ /**
+ * Appends the content of the specified {@code BuilderParameters} objects
to
+ * the current initialization parameters. Calling this method multiple
times
+ * will create a union of the parameters provided.
+ *
+ * @param params an arbitrary number of objects with builder parameters
+ * @return a reference to this builder for method chaining
+ * @throws NullPointerException if a <b>null</b> array is passed
+ */
+ public BasicConfigurationBuilder<T> configure(BuilderParameters... params)
+ {
+ Map<String, Object> newParams = new HashMap<String, Object>();
+ for (BuilderParameters p : params)
+ {
+ newParams.putAll(p.getParameters());
+ }
+
+ return setParameters(newParams);
+ }
+
+ /**
+ * {@inheritDoc} This implementation creates the result configuration on
+ * first access. Later invocations return the same object until this
builder
+ * is reset. The double-check idiom for lazy initialization is used (Bloch,
+ * Effective Java, item 71).
+ */
+ public T getConfiguration() throws ConfigurationException
+ {
+ T resObj = result;
+ if (resObj == null)
+ {
+ synchronized (this)
+ {
+ resObj = result;
+ if (resObj == null)
+ {
+ result = resObj = createResult();
+ }
+ }
+ }
+ return resObj;
+ }
+
+ /**
+ * Clears an existing result object. An invocation of this method causes a
+ * new {@code Configuration} object to be created the next time
+ * {@link #getConfiguration()} is called.
+ */
+ public synchronized void resetResult()
+ {
+ result = null;
+ resultDeclaration = null;
+ }
+
+ /**
+ * Removes all initialization parameters of this builder. This method can
be
+ * called if this builder is to be reused for creating result objects with
a
+ * different configuration.
+ */
+ public void resetParameters()
+ {
+ setParameters(null);
+ }
+
+ /**
+ * Resets this builder. This is a convenience method which combines calls
to
+ * {@link #resetResult()} and {@link #resetParameters()}.
+ */
+ public synchronized void reset()
+ {
+ resetParameters();
+ resetResult();
+ }
+
+ /**
+ * Creates a new, initialized result object. This method is called by
+ * {@code getConfiguration()} if no valid result object exists. This base
+ * implementation performs two steps:
+ * <ul>
+ * <li>{@code createResultInstance()} is called to create a new,
+ * uninitialized result object.</li>
+ * <li>{@code initResultInstance()} is called to process all initialization
+ * parameters.</li>
+ * </ul>
+ * Note that this method is called in a synchronized block.
+ *
+ * @return the newly created result object
+ * @throws ConfigurationException if an error occurs
+ */
+ protected T createResult() throws ConfigurationException
+ {
+ T resObj = createResultInstance();
+ initResultInstance(resObj);
+ return resObj;
+ }
+
+ /**
+ * Creates the new, uninitialized result object. This is the first step of
+ * the process of producing a result object for this builder. This
+ * implementation uses the {@link BeanHelper} class to create a new object
+ * based on the {@link BeanDeclaration} returned by
+ * {@link #getResultDeclaration()}. Note: This method is invoked in a
+ * synchronized block.
+ *
+ * @return the newly created, yet uninitialized result object
+ * @throws ConfigurationException if an exception occurs
+ */
+ protected T createResultInstance() throws ConfigurationException
+ {
+ return getResultClass().cast(
+ BeanHelper.createBean(getResultDeclaration()));
+ }
+
+ /**
+ * Initializes a newly created result object. This is the second step of
the
+ * process of producing a result object for this builder. This
+ * implementation uses the {@link BeanHelper} class to initialize the
+ * object's property based on the {@link BeanDeclaration} returned by
+ * {@link #getResultDeclaration()}. Note: This method is invoked in a
+ * synchronized block
+ *
+ * @param obj the object to be initialized
+ * @throws ConfigurationException if an error occurs
+ */
+ protected void initResultInstance(T obj) throws ConfigurationException
+ {
+ BeanHelper.initBean(obj, getResultDeclaration());
+ }
+
+ /**
+ * Returns the {@code BeanDeclaration} that is used to create and
initialize
+ * result objects. The declaration is created on first access (by invoking
+ * {@link #createResultDeclaration(Map)}) based on the current
+ * initialization parameters.
+ *
+ * @return the {@code BeanDeclaration} for dynamically creating a result
+ * object
+ */
+ protected synchronized final BeanDeclaration getResultDeclaration()
+ {
+ if (resultDeclaration == null)
+ {
+ resultDeclaration = createResultDeclaration(getParameters());
+ checkResultClass(resultDeclaration);
+ }
+ return resultDeclaration;
+ }
+
+ /**
+ * Returns a (unmodifiable) map with the current initialization parameters
+ * set for this builder. The map is populated with the parameters set using
+ * the various configuration options.
+ *
+ * @return a map with the current set of initialization parameters
+ */
+ protected synchronized final Map<String, Object> getParameters()
+ {
+ if (parameters != null)
+ {
+ return parameters;
+ }
+ return Collections.emptyMap();
+ }
+
+ /**
+ * Creates a new {@code BeanDeclaration} which is used for creating new
+ * result objects dynamically. This implementation creates a specialized
+ * {@code BeanDeclaration} object that is initialized from the given map of
+ * initialization parameters. The {@code BeanDeclaration} must be
+ * initialized with the result class of this builder, otherwise exceptions
+ * will be thrown when the result object is created. Note: This method is
+ * invoked in a synchronized block.
+ *
+ * @param params a snapshot of the current initialization parameters
+ * @return the {@code BeanDeclaration} for creating result objects
+ */
+ protected BeanDeclaration createResultDeclaration(
+ final Map<String, Object> params)
+ {
+ return new BeanDeclaration()
+ {
+ public Map<String, Object> getNestedBeanDeclarations()
+ {
+ // no nested beans
+ return Collections.emptyMap();
+ }
+
+ public Map<String, Object> getBeanProperties()
+ {
+ // the properties are equivalent to the parameters
+ return params;
+ }
+
+ public Object getBeanFactoryParameter()
+ {
+ return null;
+ }
+
+ public String getBeanFactoryName()
+ {
+ return null;
+ }
+
+ public String getBeanClassName()
+ {
+ return getResultClass().getName();
+ }
+ };
+ }
+
+ /**
+ * Replaces the current map with parameters by a new one.
+ *
+ * @param newParams the map with new parameters (may be <b>null</b>)
+ */
+ private void updateParameters(Map<String, Object> newParams)
+ {
+ Map<String, Object> map = new HashMap<String, Object>();
+ if (newParams != null)
+ {
+ map.putAll(newParams);
+ }
+ parameters = Collections.unmodifiableMap(map);
+ }
+
+ /**
+ * Checks whether the bean class of the given {@code BeanDeclaration}
equals
+ * this builder's result class. This is done to ensure that only objects of
+ * the expected result class are created.
+ *
+ * @param decl the declaration to be checked
+ * @throws ConfigurationRuntimeException if an invalid bean class is
+ * detected
+ */
+ private void checkResultClass(BeanDeclaration decl)
+ {
+ if (!getResultClass().getName().equals(decl.getBeanClassName()))
+ {
+ throw new ConfigurationRuntimeException("Unexpected bean class: "
+ + decl.getBeanClassName());
+ }
+ }
+}
Propchange:
commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/builder/BasicConfigurationBuilder.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange:
commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/builder/BasicConfigurationBuilder.java
------------------------------------------------------------------------------
svn:keywords = Date Author Id Revision HeadURL
Propchange:
commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/builder/BasicConfigurationBuilder.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added:
commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/builder/TestBasicConfigurationBuilder.java
URL:
http://svn.apache.org/viewvc/commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/builder/TestBasicConfigurationBuilder.java?rev=1393698&view=auto
==============================================================================
---
commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/builder/TestBasicConfigurationBuilder.java
(added)
+++
commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/builder/TestBasicConfigurationBuilder.java
Wed Oct 3 19:18:11 2012
@@ -0,0 +1,365 @@
+/*
+ * 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;
+
+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 java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration.ConfigurationException;
+import org.apache.commons.configuration.ConfigurationRuntimeException;
+import org.apache.commons.configuration.PropertiesConfiguration;
+import org.apache.commons.configuration.beanutils.BeanDeclaration;
+import org.easymock.EasyMock;
+import org.junit.Test;
+
+/**
+ * Test class for {@code BasicConfigurationBuilder}.
+ *
+ * @version $Id$
+ */
+public class TestBasicConfigurationBuilder
+{
+ /**
+ * Tries to create an instance without a result class.
+ */
+ @Test(expected = IllegalArgumentException.class)
+ public void testInitNoClass()
+ {
+ Class<Configuration> cls = null;
+ new BasicConfigurationBuilder<Configuration>(cls);
+ }
+
+ /**
+ * Creates a map with test initialization parameters.
+ *
+ * @return the map with parameters
+ */
+ private static Map<String, Object> createTestParameters()
+ {
+ Map<String, Object> params = new HashMap<String, Object>();
+ params.put("throwExceptionOnMissing", Boolean.TRUE);
+ params.put("delimiterParsingDisabled", Boolean.TRUE);
+ params.put("listDelimiter", Character.valueOf('.'));
+ return params;
+ }
+
+ /**
+ * Tests whether initialization parameters can be passed to the
constructor.
+ */
+ @Test
+ public void testInitWithParameters()
+ {
+ Map<String, Object> params = createTestParameters();
+ BasicConfigurationBuilder<PropertiesConfiguration> builder =
+ new BasicConfigurationBuilder<PropertiesConfiguration>(
+ PropertiesConfiguration.class, params);
+ Map<String, Object> params2 =
+ new HashMap<String, Object>(builder.getParameters());
+ assertEquals("Wrong parameters", createTestParameters(), params2);
+ }
+
+ /**
+ * Tests whether a copy of the passed in parameters is created.
+ */
+ @Test
+ public void testInitWithParametersDefensiveCopy()
+ {
+ Map<String, Object> params = createTestParameters();
+ BasicConfigurationBuilder<PropertiesConfiguration> builder =
+ new BasicConfigurationBuilder<PropertiesConfiguration>(
+ PropertiesConfiguration.class, params);
+ params.put("anotherParameter", "value");
+ Map<String, Object> params2 =
+ new HashMap<String, Object>(builder.getParameters());
+ assertEquals("Wrong parameters", createTestParameters(), params2);
+ }
+
+ /**
+ * Tests whether null parameters are handled correctly.
+ */
+ @Test
+ public void testInitWithParametersNull()
+ {
+ BasicConfigurationBuilder<PropertiesConfiguration> builder =
+ new BasicConfigurationBuilder<PropertiesConfiguration>(
+ PropertiesConfiguration.class, null);
+ assertTrue("Got parameters", builder.getParameters().isEmpty());
+ }
+
+ /**
+ * Tests that the map with parameters cannot be modified.
+ */
+ @Test(expected = UnsupportedOperationException.class)
+ public void testGetParametersModify()
+ {
+ BasicConfigurationBuilder<PropertiesConfiguration> builder =
+ new BasicConfigurationBuilder<PropertiesConfiguration>(
+ PropertiesConfiguration.class, createTestParameters());
+ builder.getParameters().clear();
+ }
+
+ /**
+ * Tests whether parameters can be set using the configure() method.
+ */
+ @Test
+ public void testConfigure()
+ {
+ BasicConfigurationBuilder<PropertiesConfiguration> builder =
+ new BasicConfigurationBuilder<PropertiesConfiguration>(
+ PropertiesConfiguration.class)
+ .configure(new BasicBuilderParameters()
+ .setDelimiterParsingDisabled(true)
+ .setListDelimiter('.')
+ .setThrowExceptionOnMissing(true));
+ Map<String, Object> params2 =
+ new HashMap<String, Object>(builder.getParameters());
+ assertEquals("Wrong parameters", createTestParameters(), params2);
+ }
+
+ /**
+ * Tests whether new parameters can be set to replace existing ones.
+ */
+ @Test
+ public void testSetParameters()
+ {
+ Map<String, Object> params1 = new HashMap<String, Object>();
+ params1.put("someParameter", "value");
+ BasicConfigurationBuilder<PropertiesConfiguration> builder =
+ new BasicConfigurationBuilder<PropertiesConfiguration>(
+ PropertiesConfiguration.class, params1);
+ assertSame("Wrong result", builder,
+ builder.setParameters(createTestParameters()));
+ Map<String, Object> params2 =
+ new HashMap<String, Object>(builder.getParameters());
+ assertEquals("Wrong parameters", createTestParameters(), params2);
+ }
+
+ /**
+ * Tests whether additional parameters can be added.
+ */
+ @Test
+ public void testAddParameters()
+ {
+ BasicConfigurationBuilder<PropertiesConfiguration> builder =
+ new BasicConfigurationBuilder<PropertiesConfiguration>(
+ PropertiesConfiguration.class, createTestParameters());
+ Map<String, Object> params = createTestParameters();
+ params.put("anotherParameter", "value");
+ assertSame("Wrong result", builder, builder.addParameters(params));
+ Map<String, Object> params2 = builder.getParameters();
+ assertTrue("No original parameters",
+ params2.keySet().containsAll(createTestParameters().keySet()));
+ assertEquals("Additional parameter not found", "value",
+ params2.get("anotherParameter"));
+ }
+
+ /**
+ * Tests whether null parameters are handled correctly by addParameters().
+ */
+ @Test
+ public void testAddParametersNull()
+ {
+ BasicConfigurationBuilder<PropertiesConfiguration> builder =
+ new BasicConfigurationBuilder<PropertiesConfiguration>(
+ PropertiesConfiguration.class, createTestParameters());
+ Map<String, Object> params = builder.getParameters();
+ builder.addParameters(null);
+ assertEquals("Parameters changed", params, builder.getParameters());
+ }
+
+ /**
+ * Tests whether all parameters can be reset.
+ */
+ @Test
+ public void testResetParameters()
+ {
+ BasicConfigurationBuilder<PropertiesConfiguration> builder =
+ new BasicConfigurationBuilder<PropertiesConfiguration>(
+ PropertiesConfiguration.class, createTestParameters());
+ builder.resetParameters();
+ assertTrue("Still got parameters", builder.getParameters().isEmpty());
+ }
+
+ /**
+ * Tests whether the builder can create a correctly initialized
+ * configuration object.
+ */
+ @Test
+ public void testGetConfiguration() throws ConfigurationException
+ {
+ PropertiesConfiguration config =
+ new BasicConfigurationBuilder<PropertiesConfiguration>(
+ PropertiesConfiguration.class).configure(
+ new BasicBuilderParameters().setListDelimiter('*')
+ .setThrowExceptionOnMissing(true))
+ .getConfiguration();
+ assertTrue("Delimiter parsing not disabled",
+ config.isDelimiterParsingDisabled());
+ assertTrue("Wrong exception flag", config.isThrowExceptionOnMissing());
+ assertEquals("Wrong list delimiter", '*', config.getListDelimiter());
+ }
+
+ /**
+ * Tests whether the builder can be accessed by multiple threads and that
+ * only a single result object is produced.
+ */
+ @Test
+ public void testGetConfigurationConcurrently() throws Exception
+ {
+ final int threadCount = 32;
+ CountDownLatch startLatch = new CountDownLatch(1);
+ CountDownLatch endLatch = new CountDownLatch(threadCount);
+ ConfigurationBuilder<?> builder =
+ new BasicConfigurationBuilder<PropertiesConfiguration>(
+ PropertiesConfiguration.class);
+ AccessBuilderThread[] threads = new AccessBuilderThread[threadCount];
+ for (int i = 0; i < threadCount; i++)
+ {
+ threads[i] = new AccessBuilderThread(startLatch, endLatch,
builder);
+ threads[i].start();
+ }
+ startLatch.countDown();
+ assertTrue("Timeout", endLatch.await(5, TimeUnit.SECONDS));
+ Set<Object> results = new HashSet<Object>();
+ for (AccessBuilderThread t : threads)
+ {
+ results.add(t.result);
+ }
+ assertEquals("Wrong number of result objects", 1, results.size());
+ }
+
+ /**
+ * Tests whether a reset of the result object can be performed.
+ */
+ @Test
+ public void testResetResult() throws ConfigurationException
+ {
+ BasicConfigurationBuilder<PropertiesConfiguration> builder =
+ new BasicConfigurationBuilder<PropertiesConfiguration>(
+ PropertiesConfiguration.class, createTestParameters());
+ PropertiesConfiguration config = builder.getConfiguration();
+ builder.resetResult();
+ PropertiesConfiguration config2 = builder.getConfiguration();
+ assertNotSame("No new result", config, config2);
+ assertTrue("Wrong property", config2.isThrowExceptionOnMissing());
+ }
+
+ /**
+ * Tests a full reset of the builder.
+ */
+ @Test
+ public void testReset() throws ConfigurationException
+ {
+ BasicConfigurationBuilder<PropertiesConfiguration> builder =
+ new BasicConfigurationBuilder<PropertiesConfiguration>(
+ PropertiesConfiguration.class, createTestParameters());
+ PropertiesConfiguration config = builder.getConfiguration();
+ builder.reset();
+ PropertiesConfiguration config2 = builder.getConfiguration();
+ assertNotSame("No new result", config, config2);
+ assertFalse("Parameters not reset",
config2.isThrowExceptionOnMissing());
+ }
+
+ /**
+ * Tests whether a check for the correct bean class is made.
+ */
+ @Test(expected = ConfigurationRuntimeException.class)
+ public void testGetResultDeclarationInvalidBeanClass()
+ throws ConfigurationException
+ {
+ BasicConfigurationBuilder<PropertiesConfiguration> builder =
+ new BasicConfigurationBuilder<PropertiesConfiguration>(
+ PropertiesConfiguration.class, createTestParameters())
+ {
+ @Override
+ protected BeanDeclaration createResultDeclaration(
+ Map<String, Object> params)
+ {
+ BeanDeclaration decl =
+ EasyMock.createMock(BeanDeclaration.class);
+ EasyMock.expect(decl.getBeanClassName())
+ .andReturn(Object.class.getName()).anyTimes();
+ EasyMock.replay(decl);
+ return decl;
+ }
+ };
+ builder.getConfiguration();
+ }
+
+ /**
+ * A test thread class for testing whether the builder's result object can
+ * be requested concurrently.
+ */
+ private static class AccessBuilderThread extends Thread
+ {
+ /** A latch for controlling the start of the thread. */
+ private final CountDownLatch startLatch;
+
+ /** A latch for controlling the end of the thread. */
+ private final CountDownLatch endLatch;
+
+ /** The builder to be accessed. */
+ private final ConfigurationBuilder<?> builder;
+
+ /** The result object obtained from the builder. */
+ private volatile Object result;
+
+ /**
+ * Creates a new instance of {@code AccessBuilderThread}.
+ *
+ * @param lstart the latch for controlling the thread start
+ * @param lend the latch for controlling the thread end
+ * @param bldr the builder to be tested
+ */
+ public AccessBuilderThread(CountDownLatch lstart, CountDownLatch lend,
+ ConfigurationBuilder<?> bldr)
+ {
+ startLatch = lstart;
+ endLatch = lend;
+ builder = bldr;
+ }
+
+ @Override
+ public void run()
+ {
+ try
+ {
+ startLatch.await();
+ result = builder.getConfiguration();
+ }
+ catch (Exception ex)
+ {
+ result = ex;
+ }
+ finally
+ {
+ endLatch.countDown();
+ }
+ }
+ }
+}
Propchange:
commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/builder/TestBasicConfigurationBuilder.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange:
commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/builder/TestBasicConfigurationBuilder.java
------------------------------------------------------------------------------
svn:keywords = Date Author Id Revision HeadURL
Propchange:
commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/builder/TestBasicConfigurationBuilder.java
------------------------------------------------------------------------------
svn:mime-type = text/plain