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();