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 2009/10/05 22:32:07 UTC
svn commit: r821996 - in
/commons/proper/configuration/branches/configuration2_experimental/src:
main/java/org/apache/commons/configuration2/base/
test/java/org/apache/commons/configuration2/base/
Author: oheger
Date: Mon Oct 5 20:32:07 2009
New Revision: 821996
URL: http://svn.apache.org/viewvc?rev=821996&view=rev
Log:
Added a new abstract base class for ConfigurationSource implementations.
Added:
commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/base/AbstractConfigurationSource.java (with props)
commons/proper/configuration/branches/configuration2_experimental/src/test/java/org/apache/commons/configuration2/base/TestAbstractConfigurationSource.java (with props)
Added: commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/base/AbstractConfigurationSource.java
URL: http://svn.apache.org/viewvc/commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/base/AbstractConfigurationSource.java?rev=821996&view=auto
==============================================================================
--- commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/base/AbstractConfigurationSource.java (added)
+++ commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/base/AbstractConfigurationSource.java Mon Oct 5 20:32:07 2009
@@ -0,0 +1,164 @@
+/*
+ * 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.base;
+
+import java.util.Collection;
+import java.util.LinkedList;
+import java.util.concurrent.atomic.AtomicReference;
+
+/**
+ * <p>
+ * An abstract base class for implementations of the {@code ConfigurationSource}
+ * interface.
+ * </p>
+ * <p>
+ * This class can be used as super class to simplify the implementation of a
+ * concrete {@code ConfigurationSource}. It already provides basic
+ * implementations of some of the methods defined by the {@code
+ * ConfigurationSource} interface. Especially the handling of
+ * <em>capabilities</em> is fully implemented. Derived classes can hook into
+ * this mechanism by defining custom capabilities in the
+ * {@link #appendCapabilities(Collection)} method. Optional methods, e.g. the
+ * methods for registering event listeners, are implemented by throwing an
+ * {@code UnsupportedOperationException}.
+ * </p>
+ *
+ * @author Commons Configuration team
+ * @version $Id$
+ */
+public abstract class AbstractConfigurationSource implements
+ ConfigurationSource
+{
+ /** Stores the capabilities associated with this source. */
+ private final AtomicReference<Capabilities> capabilities;
+
+ /**
+ * Creates a new instance of {@code AbstractConfigurationSource}.
+ */
+ protected AbstractConfigurationSource()
+ {
+ capabilities = new AtomicReference<Capabilities>();
+ }
+
+ /**
+ * Adds a {@code ConfigurationSourceListener} to this object. This is just a
+ * dummy implementation that throws a {@code UnsupportedOperationException}.
+ *
+ * @param l the listener to be added
+ */
+ public void addConfigurationSourceListener(ConfigurationSourceListener l)
+ {
+ throw new UnsupportedOperationException("Not implemented!");
+ }
+
+ /**
+ * Returns the capability of the the specified type. This implementation
+ * delegates to a {@link Capabilities} object maintained internally which is
+ * created on first access by {@link #createCapabilities()}. It takes care
+ * for proper synchronization.
+ *
+ * @param <T> the type of the capability requested
+ * @param cls the class of the capability interface
+ * @return the object implementing the desired capability or <b>null</b> if
+ * this capability is not supported
+ */
+ public <T> T getCapability(Class<T> cls)
+ {
+ return getCapabilities().getCapability(cls);
+ }
+
+ /**
+ * Removes the specified {@code ConfigurationSourceListener} from this
+ * object. This is just a dummy implementation that throws a {@code
+ * UnsupportedOperationException}.
+ *
+ * @param l the listener to be removed
+ */
+ public boolean removeConfigurationSourceListener(
+ ConfigurationSourceListener l)
+ {
+ throw new UnsupportedOperationException("Not implemented!");
+ }
+
+ /**
+ * Returns the {@code Capabilities} object that manages the capabilities
+ * supported by this {@code ConfigurationSource}. The object is created on
+ * first access. <em>Implementation note:</em> For synchronizing access to
+ * the {@code Capabilities} object an atomic variable is used. If no object
+ * has been created yet, {@link #createCapabilities()} is called. If this
+ * method is called by multiple threads, it is possible that
+ * {@link #createCapabilities()} is invoked multiple times. However, it is
+ * ensured that this method always returns the same {@code Capabilities}
+ * instance.
+ *
+ * @return the {@code Capabilities} object associated with this {@code
+ * ConfigurationSource}
+ */
+ protected Capabilities getCapabilities()
+ {
+ Capabilities caps = capabilities.get();
+
+ if (caps == null)
+ {
+ Capabilities capsNew = createCapabilities();
+ if (capabilities.compareAndSet(null, capsNew))
+ {
+ caps = capsNew;
+ }
+ else
+ {
+ caps = capabilities.get();
+ }
+ }
+
+ return caps;
+ }
+
+ /**
+ * Creates a {@code Capabilities} object for managing the capabilities
+ * supported by this {@code ConfigurationSource}. This method is called by
+ * {@link #getCapability(Class)} on first access. This implementation calls
+ * {@link #appendCapabilities(Collection)} to obtain a list of additional
+ * capabilities. Then it creates a {@code Capabilities} instance with this
+ * list and this {@code ConfigurationSource} object as owner.
+ *
+ * @return the {@code Capabilities} supported by this {@code
+ * ConfigurationSource}
+ */
+ protected Capabilities createCapabilities()
+ {
+ Collection<Capability> caps = new LinkedList<Capability>();
+ appendCapabilities(caps);
+ return new Capabilities(this, caps);
+ }
+
+ /**
+ * Creates additional {@code Capability} objects and adds them to the passed
+ * in list. This method can be overridden by derived classes to add {@code
+ * Capability} instances to the internal capability management for
+ * interfaces that are not implemented by this object. This base
+ * implementation is empty. Classes overriding this method should always
+ * call the super method to ensure that capabilities of the base classes do
+ * not get lost.
+ *
+ * @param caps a collection for adding additional {@code Capability}
+ * instances
+ */
+ protected void appendCapabilities(Collection<Capability> caps)
+ {
+ }
+}
Propchange: commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/base/AbstractConfigurationSource.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/base/AbstractConfigurationSource.java
------------------------------------------------------------------------------
svn:keywords = Date Author Id Revision HeadURL
Propchange: commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/base/AbstractConfigurationSource.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: commons/proper/configuration/branches/configuration2_experimental/src/test/java/org/apache/commons/configuration2/base/TestAbstractConfigurationSource.java
URL: http://svn.apache.org/viewvc/commons/proper/configuration/branches/configuration2_experimental/src/test/java/org/apache/commons/configuration2/base/TestAbstractConfigurationSource.java?rev=821996&view=auto
==============================================================================
--- commons/proper/configuration/branches/configuration2_experimental/src/test/java/org/apache/commons/configuration2/base/TestAbstractConfigurationSource.java (added)
+++ commons/proper/configuration/branches/configuration2_experimental/src/test/java/org/apache/commons/configuration2/base/TestAbstractConfigurationSource.java Mon Oct 5 20:32:07 2009
@@ -0,0 +1,201 @@
+/*
+ * 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.base;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.concurrent.CountDownLatch;
+
+import junit.framework.TestCase;
+
+import org.easymock.EasyMock;
+
+/**
+ * Test class for {@code AbstractConfigurationSource}.
+ *
+ * @author Commons Configuration team
+ * @version $Id$
+ */
+public class TestAbstractConfigurationSource extends TestCase
+{
+ /** The source to be tested. */
+ private AbstractConfigurationSourceTestImpl source;
+
+ @Override
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+ source = new AbstractConfigurationSourceTestImpl();
+ }
+
+ /**
+ * Tries to add a configuration listener. This is not supported.
+ */
+ public void testAddConfigurationListener()
+ {
+ ConfigurationSourceListener l = EasyMock
+ .createMock(ConfigurationSourceListener.class);
+ EasyMock.replay(l);
+ try
+ {
+ source.addConfigurationSourceListener(l);
+ fail("Could add a listener!");
+ }
+ catch (UnsupportedOperationException uoex)
+ {
+ EasyMock.verify(l);
+ }
+ }
+
+ /**
+ * Tries to remove a configuration listener. This is not supported.
+ */
+ public void testRemoveConfigurationListener()
+ {
+ ConfigurationSourceListener l = EasyMock
+ .createMock(ConfigurationSourceListener.class);
+ EasyMock.replay(l);
+ try
+ {
+ source.removeConfigurationSourceListener(l);
+ fail("Could remove a listener!");
+ }
+ catch (UnsupportedOperationException uoex)
+ {
+ EasyMock.verify(l);
+ }
+ }
+
+ /**
+ * Tests whether capabilities from implemented interfaces can be queried.
+ */
+ public void testGetCapabilityImplemented()
+ {
+ assertEquals("Wrong source capability", source, source
+ .getCapability(ConfigurationSource.class));
+ assertEquals("Wrong runnable capability", source, source
+ .getCapability(Runnable.class));
+ }
+
+ /**
+ * Tests whether capabilities provided by appendCapabilities() can be
+ * queried.
+ */
+ public void testGetCapabilityProvided()
+ {
+ Runnable r = EasyMock.createNiceMock(Runnable.class);
+ source.capabilityList = Collections.singleton(new Capability(
+ Runnable.class, r));
+ assertEquals("Wrong runnable capability", r, source
+ .getCapability(Runnable.class));
+ }
+
+ /**
+ * Tests whether the capabilities object is created once and cached.
+ */
+ public void testGetCapabilitiesCached()
+ {
+ Capabilities caps = source.getCapabilities();
+ assertNotNull("No capabilities", caps);
+ assertSame("Different instance", caps, source.getCapabilities());
+ }
+
+ /**
+ * Tests concurrent access to the capabilities.
+ */
+ public void testGetCapabilitiesMultiThreaded() throws InterruptedException
+ {
+ final int threadCount = 64;
+ CountDownLatch latch = new CountDownLatch(1);
+ CapabilitiesTestThread[] threads = new CapabilitiesTestThread[threadCount];
+ for (int i = 0; i < threadCount; i++)
+ {
+ threads[i] = new CapabilitiesTestThread(latch);
+ threads[i].start();
+ }
+ latch.countDown(); // start all threads
+ Capabilities caps = source.getCapabilities();
+ for (CapabilitiesTestThread t : threads)
+ {
+ t.join();
+ assertSame("Different capabilities", caps, t.caps);
+ }
+ }
+
+ /**
+ * A concrete test implementation of {@code AbstractConfigurationSource}.
+ */
+ private static class AbstractConfigurationSourceTestImpl extends
+ AbstractConfigurationSource implements Runnable
+ {
+ /** A list with capabilities to be added to the capabilities object. */
+ Collection<Capability> capabilityList;
+
+ public void clear()
+ {
+ }
+
+ public void run()
+ {
+ }
+
+ /**
+ * Appends capabilities if the list is defined.
+ */
+ @Override
+ protected void appendCapabilities(Collection<Capability> caps)
+ {
+ super.appendCapabilities(caps);
+ if (capabilityList != null)
+ {
+ caps.addAll(capabilityList);
+ }
+ }
+ }
+
+ /**
+ * A test thread class for testing concurrent access to the source's
+ * capabilities.
+ */
+ private class CapabilitiesTestThread extends Thread
+ {
+ /** The latch for synchronizing the start. */
+ private final CountDownLatch startLatch;
+
+ /** The capabilities obtained from the source. */
+ Capabilities caps;
+
+ public CapabilitiesTestThread(CountDownLatch latch)
+ {
+ startLatch = latch;
+ }
+
+ @Override
+ public void run()
+ {
+ try
+ {
+ startLatch.await();
+ caps = source.getCapabilities();
+ }
+ catch (InterruptedException iex)
+ {
+ // fall through
+ }
+ }
+ }
+}
Propchange: commons/proper/configuration/branches/configuration2_experimental/src/test/java/org/apache/commons/configuration2/base/TestAbstractConfigurationSource.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: commons/proper/configuration/branches/configuration2_experimental/src/test/java/org/apache/commons/configuration2/base/TestAbstractConfigurationSource.java
------------------------------------------------------------------------------
svn:keywords = Date Author Id Revision HeadURL
Propchange: commons/proper/configuration/branches/configuration2_experimental/src/test/java/org/apache/commons/configuration2/base/TestAbstractConfigurationSource.java
------------------------------------------------------------------------------
svn:mime-type = text/plain