001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.commons.configuration2.reloading; 018 019import java.util.ArrayList; 020import java.util.Collection; 021import java.util.Collections; 022 023/** 024 * <p> 025 * A specialized {@code ReloadingController} implementation which manages an 026 * arbitrary number of other {@code ReloadingController} objects. 027 * </p> 028 * <p> 029 * This class can be used to handle multiple simple controllers for reload 030 * operations as a single object. As a usage example consider a combined 031 * configuration containing a number of configuration sources of which some 032 * support reloading. In this scenario all {@code ReloadingController} instances 033 * for the reloading-enabled sources can be added to a 034 * {@code CombinedReloadingController}. Then by triggering the combined 035 * controller a reload check is performed on all child sources. 036 * </p> 037 * <p> 038 * This class is a typical implementation of the <em>composite pattern</em>. An 039 * instance is constructed with a collection of sub {@code ReloadingController} 040 * objects. Its operations are implemented by delegating to all child 041 * controllers. 042 * </p> 043 * <p> 044 * This class expects the managed controller objects to be passed to the 045 * constructor. From this list a defensive copy is created so that it cannot be 046 * changed later on. Derived classes can override the 047 * {@link #getSubControllers()} method if they need another way to handle child 048 * controllers (e.g. a more dynamic way). However, they are then responsible to 049 * ensure a safe access to this list in a multi-threaded environment. 050 * </p> 051 * 052 * @version $Id: CombinedReloadingController.java 1842194 2018-09-27 22:24:23Z ggregory $ 053 * @since 2.0 054 */ 055public class CombinedReloadingController extends ReloadingController 056{ 057 /** Constant for a dummy reloading detector. */ 058 private static final ReloadingDetector DUMMY = 059 new MultiReloadingControllerDetector(null); 060 061 /** The collection with managed reloading controllers. */ 062 private final Collection<ReloadingController> controllers; 063 064 /** The reloading detector used by this instance. */ 065 private final ReloadingDetector detector; 066 067 /** 068 * Creates a new instance of {@code CombinedReloadingController} and 069 * initializes it with the {@code ReloadingController} objects to be 070 * managed. 071 * 072 * @param subCtrls the collection with sub {@code ReloadingController}s 073 * (must not be <b>null</b> or contain <b>null</b> entries) 074 * @throws IllegalArgumentException if the passed in collection is 075 * <b>null</b> or contains <b>null</b> entries 076 */ 077 public CombinedReloadingController( 078 final Collection<? extends ReloadingController> subCtrls) 079 { 080 super(DUMMY); 081 controllers = checkManagedControllers(subCtrls); 082 detector = new MultiReloadingControllerDetector(this); 083 } 084 085 /** 086 * Returns a (unmodifiable) collection with the sub controllers managed by 087 * this combined controller. 088 * 089 * @return a collection with sub controllers 090 */ 091 public Collection<ReloadingController> getSubControllers() 092 { 093 return controllers; 094 } 095 096 /** 097 * {@inheritDoc} This implementation returns a special reloading detector 098 * which operates on all managed controllers. 099 */ 100 @Override 101 public ReloadingDetector getDetector() 102 { 103 return detector; 104 } 105 106 /** 107 * Resets the reloading state of all managed sub controllers 108 * unconditionally. This method is intended to be called after the creation 109 * of an instance. It may be the case that some of the sub controllers are 110 * already in reloading state, so their state is out of sync with this 111 * controller's global reloading state. This method ensures that the 112 * reloading state of all sub controllers is reset. 113 */ 114 public void resetInitialReloadingState() 115 { 116 getDetector().reloadingPerformed(); 117 } 118 119 /** 120 * Checks the collection with the passed in sub controllers and creates a 121 * defensive copy. 122 * 123 * @param subCtrls the collection with sub controllers 124 * @return a copy of the collection to be stored in the newly created 125 * instance 126 * @throws IllegalArgumentException if the passed in collection is 127 * <b>null</b> or contains <b>null</b> entries 128 */ 129 private static Collection<ReloadingController> checkManagedControllers( 130 final Collection<? extends ReloadingController> subCtrls) 131 { 132 if (subCtrls == null) 133 { 134 throw new IllegalArgumentException( 135 "Collection with sub controllers must not be null!"); 136 } 137 final Collection<ReloadingController> ctrls = 138 new ArrayList<>(subCtrls); 139 for (final ReloadingController rc : ctrls) 140 { 141 if (rc == null) 142 { 143 throw new IllegalArgumentException( 144 "Collection with sub controllers contains a null entry!"); 145 } 146 } 147 148 return Collections.unmodifiableCollection(ctrls); 149 } 150 151 /** 152 * A specialized implementation of the {@code ReloadingDetector} interface 153 * which operates on a collection of {@code ReloadingController} objects. 154 * The methods defined by the {@code ReloadingDetector} interface are 155 * delegated to the managed controllers. 156 */ 157 private static class MultiReloadingControllerDetector implements 158 ReloadingDetector 159 { 160 /** A reference to the owning combined reloading controller. */ 161 private final CombinedReloadingController owner; 162 163 /** 164 * Creates a new instance of {@code MultiReloadingControllerDetector}. 165 * 166 * @param o the owner 167 */ 168 public MultiReloadingControllerDetector(final CombinedReloadingController o) 169 { 170 owner = o; 171 } 172 173 /** 174 * {@inheritDoc} This implementation delegates to the managed 175 * controllers. For all of them the {@code checkForReloading()} 176 * method is called, giving them the chance to trigger a reload if 177 * necessary. If one of these calls returns <b>true</b>, the result of 178 * this method is <b>true</b>, otherwise <b>false</b>. 179 */ 180 @Override 181 public boolean isReloadingRequired() 182 { 183 boolean result = false; 184 for (final ReloadingController rc : owner.getSubControllers()) 185 { 186 if (rc.checkForReloading(null)) 187 { 188 result = true; 189 } 190 } 191 return result; 192 } 193 194 /** 195 * {@inheritDoc} This implementation resets the reloading state on all 196 * managed controllers. 197 */ 198 @Override 199 public void reloadingPerformed() 200 { 201 for (final ReloadingController rc : owner.getSubControllers()) 202 { 203 rc.resetReloadingState(); 204 } 205 } 206 } 207}