From commits-return-9000-apmail-commons-commits-archive=commons.apache.org@commons.apache.org Mon Oct 05 20:33:03 2009 Return-Path: Delivered-To: apmail-commons-commits-archive@minotaur.apache.org Received: (qmail 32706 invoked from network); 5 Oct 2009 20:33:03 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (140.211.11.3) by minotaur.apache.org with SMTP; 5 Oct 2009 20:33:03 -0000 Received: (qmail 63038 invoked by uid 500); 5 Oct 2009 20:33:02 -0000 Delivered-To: apmail-commons-commits-archive@commons.apache.org Received: (qmail 62940 invoked by uid 500); 5 Oct 2009 20:33:02 -0000 Mailing-List: contact commits-help@commons.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@commons.apache.org Delivered-To: mailing list commits@commons.apache.org Received: (qmail 62931 invoked by uid 99); 5 Oct 2009 20:33:02 -0000 Received: from nike.apache.org (HELO nike.apache.org) (192.87.106.230) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 05 Oct 2009 20:33:02 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=10.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 05 Oct 2009 20:32:58 +0000 Received: by eris.apache.org (Postfix, from userid 65534) id 9157D23888FE; Mon, 5 Oct 2009 20:32:07 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: 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/ Date: Mon, 05 Oct 2009 20:32:07 -0000 To: commits@commons.apache.org From: oheger@apache.org X-Mailer: svnmailer-1.0.8 Message-Id: <20091005203207.9157D23888FE@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org 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; + +/** + *

+ * An abstract base class for implementations of the {@code ConfigurationSource} + * interface. + *

+ *

+ * 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 + * capabilities 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}. + *

+ * + * @author Commons Configuration team + * @version $Id$ + */ +public abstract class AbstractConfigurationSource implements + ConfigurationSource +{ + /** Stores the capabilities associated with this source. */ + private final AtomicReference capabilities; + + /** + * Creates a new instance of {@code AbstractConfigurationSource}. + */ + protected AbstractConfigurationSource() + { + capabilities = new AtomicReference(); + } + + /** + * 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 the type of the capability requested + * @param cls the class of the capability interface + * @return the object implementing the desired capability or null if + * this capability is not supported + */ + public T getCapability(Class 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. Implementation note: 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 caps = new LinkedList(); + 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 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 capabilityList; + + public void clear() + { + } + + public void run() + { + } + + /** + * Appends capabilities if the list is defined. + */ + @Override + protected void appendCapabilities(Collection 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