Author: oheger
Date: Sun Dec 30 18:55:22 2012
New Revision: 1426974

URL: http://svn.apache.org/viewvc?rev=1426974&view=rev
Log:
Added new CombinedReloadingController class.

Added:
    
commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/reloading/CombinedReloadingController.java
   (with props)
    
commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/reloading/TestCombinedReloadingController.java
   (with props)
Modified:
    
commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/reloading/TestPeriodicReloadingTrigger.java

Added: 
commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/reloading/CombinedReloadingController.java
URL: 
http://svn.apache.org/viewvc/commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/reloading/CombinedReloadingController.java?rev=1426974&view=auto
==============================================================================
--- 
commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/reloading/CombinedReloadingController.java
 (added)
+++ 
commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/reloading/CombinedReloadingController.java
 Sun Dec 30 18:55:22 2012
@@ -0,0 +1,150 @@
+/*
+ * 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.reloading;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+/**
+ * <p>
+ * A specialized {@code ReloadingController} implementation which manages an
+ * arbitrary number of other {@code ReloadingController} objects.
+ * </p>
+ * <p>
+ * This class can be used to handle multiple simple controllers for reload
+ * operations as a single object. As a usage example consider a combined
+ * configuration containing a number of configuration sources of which some
+ * support reloading. In this scenario all {@code ReloadingController} 
instances
+ * for the reloading-enabled sources can be added to a
+ * {@code CombinedReloadingController}. Then by triggering the combined
+ * controller a reload check is performed on all child sources.
+ * </p>
+ * <p>
+ * This class is a typical implementation of the <em>composite pattern</em>. An
+ * instance is constructed with a collection of sub {@code ReloadingController}
+ * objects. Its operations are implemented by delegating to all child
+ * controllers.
+ * </p>
+ *
+ * @version $Id$
+ * @since 2.0
+ */
+public class CombinedReloadingController extends ReloadingController
+{
+    /**
+     * Creates a new instance of {@code CombinedReloadingController} and
+     * initializes it with the {@code ReloadingController} objects to be
+     * managed.
+     *
+     * @param subCtrls the collection with sub {@code ReloadingController}s
+     *        (must not be <b>null</b> or contain <b>null</b> entries)
+     * @throws IllegalArgumentException if the passed in collection is
+     *         <b>null</b> or contains <b>null</b> entries
+     */
+    public CombinedReloadingController(
+            Collection<? extends ReloadingController> subCtrls)
+    {
+        super(createDetector(subCtrls));
+    }
+
+    /**
+     * Creates a specialized detector object which manages the passed in sub
+     * controllers. The collection with controllers is also checked for
+     * validity.
+     *
+     * @param subCtrls the collection with sub controllers
+     * @return the {@code ReloadingDetector} to be used by the combined
+     *         controller
+     * @throws IllegalArgumentException if the passed in collection is
+     *         <b>null</b> or contains <b>null</b> entries
+     */
+    private static ReloadingDetector createDetector(
+            Collection<? extends ReloadingController> subCtrls)
+    {
+        if (subCtrls == null)
+        {
+            throw new IllegalArgumentException(
+                    "Collection with sub controllers must not be null!");
+        }
+        Collection<ReloadingController> ctrls =
+                new ArrayList<ReloadingController>(subCtrls);
+        for (ReloadingController rc : ctrls)
+        {
+            if (rc == null)
+            {
+                throw new IllegalArgumentException(
+                        "Collection with sub controllers contains a null 
entry!");
+            }
+        }
+
+        return new MultiReloadingControllerDetector(ctrls);
+    }
+
+    /**
+     * A specialized implementation of the {@code ReloadingDetector} interface
+     * which operates on a collection of {@code ReloadingController} objects.
+     * The methods defined by the {@code ReloadingDetector} interface are
+     * delegated to the managed controllers.
+     */
+    private static class MultiReloadingControllerDetector implements
+            ReloadingDetector
+    {
+        /** Stores the managed sub controllers. */
+        private final Collection<ReloadingController> controllers;
+
+        /**
+         * Creates a new instance of {@code MultiReloadingControllerDetector}
+         * and sets the managed controllers.
+         *
+         * @param ctrls a collection with the managed controllers
+         */
+        public MultiReloadingControllerDetector(
+                Collection<ReloadingController> ctrls)
+        {
+            controllers = ctrls;
+        }
+
+        /**
+         * {@inheritDoc} This implementation delegates to the managed
+         * controllers. If one of them returns <b>true</b> from its check
+         * method, iteration is aborted, and result is <b>true</b>.
+         */
+        public boolean isReloadingRequired()
+        {
+            for (ReloadingController rc : controllers)
+            {
+                if (rc.checkForReloading(null) || rc.isInReloadingState())
+                {
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        /**
+         * {@inheritDoc} This implementation resets the reloading state on all
+         * managed controllers.
+         */
+        public void reloadingPerformed()
+        {
+            for (ReloadingController rc : controllers)
+            {
+                rc.resetReloadingState();
+            }
+        }
+    }
+}

Propchange: 
commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/reloading/CombinedReloadingController.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: 
commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/reloading/CombinedReloadingController.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: 
commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/reloading/CombinedReloadingController.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: 
commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/reloading/TestCombinedReloadingController.java
URL: 
http://svn.apache.org/viewvc/commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/reloading/TestCombinedReloadingController.java?rev=1426974&view=auto
==============================================================================
--- 
commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/reloading/TestCombinedReloadingController.java
 (added)
+++ 
commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/reloading/TestCombinedReloadingController.java
 Sun Dec 30 18:55:22 2012
@@ -0,0 +1,180 @@
+/*
+ * 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.reloading;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+
+import org.easymock.EasyMock;
+import org.junit.Test;
+
+/**
+ * Test class for {@code CombinedReloadingController}.
+ *
+ * @version $Id$
+ */
+public class TestCombinedReloadingController
+{
+    /** An array with mock objects for the sub controllers. */
+    private ReloadingController[] subControllers;
+
+    /**
+     * Creates an array with mock objects for sub controllers.
+     */
+    private void initSubControllers()
+    {
+        subControllers = new ReloadingController[3];
+        for (int i = 0; i < subControllers.length; i++)
+        {
+            subControllers[i] = EasyMock.createMock(ReloadingController.class);
+        }
+    }
+
+    /**
+     * Replays the mocks for the sub controllers.
+     */
+    private void replaySubControllers()
+    {
+        EasyMock.replay((Object[]) subControllers);
+    }
+
+    /**
+     * Verifies the mocks for the sub controllers.
+     */
+    private void verifySubSontrollers()
+    {
+        EasyMock.verify((Object[]) subControllers);
+    }
+
+    /**
+     * Creates a test instance with default settings.
+     *
+     * @return the test instance
+     */
+    private CombinedReloadingController setUpController()
+    {
+        initSubControllers();
+        List<ReloadingController> lstCtrls =
+                new ArrayList<ReloadingController>(
+                        Arrays.asList(subControllers));
+        CombinedReloadingController result =
+                new CombinedReloadingController(lstCtrls);
+        // check whether a defensive copy is created
+        lstCtrls.clear();
+        return result;
+    }
+
+    /**
+     * Tries to create an instance without a collection.
+     */
+    @Test(expected = IllegalArgumentException.class)
+    public void testInitNull()
+    {
+        new CombinedReloadingController(null);
+    }
+
+    /**
+     * Tries to create an instance with a collection containing a null entry.
+     */
+    @Test(expected = IllegalArgumentException.class)
+    public void testInitNullEntries()
+    {
+        initSubControllers();
+        Collection<ReloadingController> ctrls =
+                new ArrayList<ReloadingController>(
+                        Arrays.asList(subControllers));
+        ctrls.add(null);
+        new CombinedReloadingController(ctrls);
+    }
+
+    /**
+     * Tests a check for a reloading operation which results in true.
+     */
+    @Test
+    public void testCheckForReloadingTrue()
+    {
+        CombinedReloadingController ctrl = setUpController();
+        EasyMock.expect(subControllers[0].checkForReloading(null)).andReturn(
+                Boolean.FALSE);
+        EasyMock.expect(subControllers[0].isInReloadingState()).andReturn(
+                Boolean.FALSE);
+        EasyMock.expect(subControllers[1].checkForReloading(null)).andReturn(
+                Boolean.TRUE);
+        replaySubControllers();
+        assertTrue("Wrong result", ctrl.checkForReloading("someData"));
+        verifySubSontrollers();
+    }
+
+    /**
+     * Tests a reloading check if a sub controller is already in reloading
+     * state.
+     */
+    @Test
+    public void testCheckForReloadingTrueAlreadyInReloadingState()
+    {
+        CombinedReloadingController ctrl = setUpController();
+        EasyMock.expect(subControllers[0].checkForReloading(null)).andReturn(
+                Boolean.FALSE);
+        EasyMock.expect(subControllers[0].isInReloadingState()).andReturn(
+                Boolean.TRUE);
+        replaySubControllers();
+        assertTrue("Wrong result", ctrl.checkForReloading("someData"));
+        verifySubSontrollers();
+    }
+
+    /**
+     * Tests a check for a reloading operation which results in false.
+     */
+    @Test
+    public void testCheckForReloadingFalse()
+    {
+        CombinedReloadingController ctrl = setUpController();
+        for (ReloadingController rc : subControllers)
+        {
+            EasyMock.expect(rc.checkForReloading(null))
+                    .andReturn(Boolean.FALSE);
+            EasyMock.expect(rc.isInReloadingState()).andReturn(Boolean.FALSE);
+        }
+        replaySubControllers();
+        assertFalse("Wrong result", ctrl.checkForReloading("someParam"));
+        verifySubSontrollers();
+    }
+
+    /**
+     * Tests whether the reloading state can be reset.
+     */
+    @Test
+    public void testResetReloadingState()
+    {
+        CombinedReloadingController ctrl = setUpController();
+        EasyMock.expect(subControllers[0].checkForReloading(null)).andReturn(
+                Boolean.TRUE);
+        for (ReloadingController rc : subControllers)
+        {
+            rc.resetReloadingState();
+        }
+        replaySubControllers();
+        ctrl.checkForReloading(null);
+        ctrl.resetReloadingState();
+        verifySubSontrollers();
+    }
+}

Propchange: 
commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/reloading/TestCombinedReloadingController.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: 
commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/reloading/TestCombinedReloadingController.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: 
commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/reloading/TestCombinedReloadingController.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: 
commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/reloading/TestPeriodicReloadingTrigger.java
URL: 
http://svn.apache.org/viewvc/commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/reloading/TestPeriodicReloadingTrigger.java?rev=1426974&r1=1426973&r2=1426974&view=diff
==============================================================================
--- 
commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/reloading/TestPeriodicReloadingTrigger.java
 (original)
+++ 
commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/reloading/TestPeriodicReloadingTrigger.java
 Sun Dec 30 18:55:22 2012
@@ -146,7 +146,8 @@ public class TestPeriodicReloadingTrigge
                         return future;
                     }
                 });
-        controller.checkForReloading(CTRL_PARAM);
+        EasyMock.expect(controller.checkForReloading(CTRL_PARAM)).andReturn(
+                Boolean.FALSE);
         EasyMock.replay(future, controller, executor);
         PeriodicReloadingTrigger trigger = createTrigger();
         trigger.start();


Reply via email to