1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 package org.apache.commons.configuration2.builder.combined; 18 19 import java.util.Collection; 20 import java.util.LinkedList; 21 import java.util.Map; 22 23 import org.apache.commons.configuration2.CombinedConfiguration; 24 import org.apache.commons.configuration2.HierarchicalConfiguration; 25 import org.apache.commons.configuration2.XMLConfiguration; 26 import org.apache.commons.configuration2.builder.BuilderParameters; 27 import org.apache.commons.configuration2.builder.ConfigurationBuilder; 28 import org.apache.commons.configuration2.builder.ReloadingFileBasedConfigurationBuilder; 29 import org.apache.commons.configuration2.ex.ConfigurationException; 30 import org.apache.commons.configuration2.reloading.CombinedReloadingController; 31 import org.apache.commons.configuration2.reloading.ReloadingController; 32 import org.apache.commons.configuration2.reloading.ReloadingControllerSupport; 33 34 /** 35 * <p> 36 * An extension of {@code CombinedConfigurationBuilder} which also supports reloading operations. 37 * </p> 38 * <p> 39 * This class differs from its super class in the following aspects: 40 * </p> 41 * <ul> 42 * <li>A {@link ReloadingController} is created which manages all child configuration builders supporting reloading 43 * operations.</li> 44 * <li>If no {@code ConfigurationBuilder} is provided for the definition configuration, a builder with reloading support 45 * is created.</li> 46 * </ul> 47 * <p> 48 * This class can be used exactly as its super class for creating combined configurations from multiple configuration 49 * sources. In addition, the combined reloading controller managed by an instance can be used to react on changes in one 50 * of these configuration sources or in the definition configuration. 51 * </p> 52 * 53 * @since 2.0 54 */ 55 public class ReloadingCombinedConfigurationBuilder extends CombinedConfigurationBuilder implements ReloadingControllerSupport { 56 /** The reloading controller used by this builder. */ 57 private ReloadingController reloadingController; 58 59 /** 60 * Creates a new instance of {@code ReloadingCombinedConfigurationBuilder}. No parameters are set. 61 */ 62 public ReloadingCombinedConfigurationBuilder() { 63 } 64 65 /** 66 * Creates a new instance of {@code ReloadingCombinedConfigurationBuilder} and sets the specified initialization 67 * parameters and the <em>allowFailOnInit</em> flag. 68 * 69 * @param params a map with initialization parameters 70 * @param allowFailOnInit the <em>allowFailOnInit</em> flag 71 */ 72 public ReloadingCombinedConfigurationBuilder(final Map<String, Object> params, final boolean allowFailOnInit) { 73 super(params, allowFailOnInit); 74 } 75 76 /** 77 * Creates a new instance of {@code ReloadingCombinedConfigurationBuilder} and sets the specified initialization 78 * parameters. 79 * 80 * @param params a map with initialization parameters 81 */ 82 public ReloadingCombinedConfigurationBuilder(final Map<String, Object> params) { 83 super(params); 84 } 85 86 /** 87 * {@inheritDoc} This method is overridden to adapt the return type. 88 */ 89 @Override 90 public ReloadingCombinedConfigurationBuilder configure(final BuilderParameters... params) { 91 super.configure(params); 92 return this; 93 } 94 95 /** 96 * {@inheritDoc} This implementation returns a {@link CombinedReloadingController} which contains sub controllers for 97 * all child configuration sources with reloading support. If the definition builder supports reloading, its controller 98 * is contained, too. Note that the combined reloading controller is initialized when the result configuration is 99 * created (i.e. when calling {@code getConfiguration()} for the first time). So this method does not return a 100 * meaningful result before. 101 */ 102 @Override 103 public synchronized ReloadingController getReloadingController() { 104 return reloadingController; 105 } 106 107 /** 108 * {@inheritDoc} This implementation makes sure that the reloading state of the managed reloading controller is reset. 109 * Note that this has to be done here and not in {@link #initResultInstance(CombinedConfiguration)} because it must be 110 * outside of a synchronized block; otherwise, a dead-lock situation can occur. 111 */ 112 @Override 113 public CombinedConfiguration getConfiguration() throws ConfigurationException { 114 final CombinedConfiguration result = super.getConfiguration(); 115 reloadingController.resetReloadingState(); 116 return result; 117 } 118 119 /** 120 * {@inheritDoc} This implementation creates a builder for XML configurations with reloading support. 121 */ 122 @Override 123 protected ConfigurationBuilder<? extends HierarchicalConfiguration<?>> createXMLDefinitionBuilder(final BuilderParameters builderParams) { 124 return new ReloadingFileBasedConfigurationBuilder<>(XMLConfiguration.class).configure(builderParams); 125 } 126 127 /** 128 * {@inheritDoc} This implementation first calls the super method to actually initialize the result configuration. Then 129 * it creates the {@link CombinedReloadingController} for all child configuration sources with reloading support. 130 */ 131 @Override 132 protected void initResultInstance(final CombinedConfiguration result) throws ConfigurationException { 133 super.initResultInstance(result); 134 if (reloadingController == null) { 135 reloadingController = createReloadingController(); 136 } 137 } 138 139 /** 140 * Creates the {@code ReloadingController} for this builder. This method is called after the result configuration has 141 * been created and initialized. It is called from a synchronized block. This implementation creates a 142 * {@link CombinedReloadingController}. 143 * 144 * @return the {@code ReloadingController} for this builder 145 * @throws ConfigurationException if an error occurs 146 */ 147 protected ReloadingController createReloadingController() throws ConfigurationException { 148 final Collection<ReloadingController> subControllers = new LinkedList<>(); 149 final ConfigurationBuilder<? extends HierarchicalConfiguration<?>> defBuilder = getDefinitionBuilder(); 150 obtainReloadingController(subControllers, defBuilder); 151 152 getChildBuilders().forEach(b -> obtainReloadingController(subControllers, b)); 153 154 final CombinedReloadingController ctrl = new CombinedReloadingController(subControllers); 155 ctrl.resetInitialReloadingState(); 156 return ctrl; 157 } 158 159 /** 160 * Checks whether the passed in builder object supports reloading. If yes, its reloading controller is obtained and 161 * added to the given list. 162 * 163 * @param subControllers the list with sub controllers 164 * @param builder the builder object to be checked 165 */ 166 public static void obtainReloadingController(final Collection<ReloadingController> subControllers, final Object builder) { 167 if (builder instanceof ReloadingControllerSupport) { 168 subControllers.add(((ReloadingControllerSupport) builder).getReloadingController()); 169 } 170 } 171 }