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.builder.combined; 018 019import java.util.Collection; 020import java.util.LinkedList; 021import java.util.Map; 022 023import org.apache.commons.configuration2.CombinedConfiguration; 024import org.apache.commons.configuration2.Configuration; 025import org.apache.commons.configuration2.HierarchicalConfiguration; 026import org.apache.commons.configuration2.XMLConfiguration; 027import org.apache.commons.configuration2.builder.BuilderParameters; 028import org.apache.commons.configuration2.builder.ConfigurationBuilder; 029import org.apache.commons.configuration2.builder.ReloadingFileBasedConfigurationBuilder; 030import org.apache.commons.configuration2.ex.ConfigurationException; 031import org.apache.commons.configuration2.reloading.CombinedReloadingController; 032import org.apache.commons.configuration2.reloading.ReloadingController; 033import org.apache.commons.configuration2.reloading.ReloadingControllerSupport; 034 035/** 036 * <p> 037 * An extension of {@code CombinedConfigurationBuilder} which also supports 038 * reloading operations. 039 * </p> 040 * <p> 041 * This class differs from its super class in the following aspects: 042 * </p> 043 * <ul> 044 * <li>A {@link ReloadingController} is created which manages all child 045 * configuration builders supporting reloading operations.</li> 046 * <li>If no {@code ConfigurationBuilder} is provided for the definition 047 * configuration, a builder with reloading support is created.</li> 048 * </ul> 049 * <p> 050 * This class can be used exactly as its super class for creating combined 051 * configurations from multiple configuration sources. In addition, the combined 052 * reloading controller managed by an instance can be used to react on changes 053 * in one of these configuration sources or in the definition configuration. 054 * </p> 055 * 056 * @version $Id: ReloadingCombinedConfigurationBuilder.java 1842194 2018-09-27 22:24:23Z ggregory $ 057 * @since 2.0 058 */ 059public class ReloadingCombinedConfigurationBuilder extends 060 CombinedConfigurationBuilder implements ReloadingControllerSupport 061{ 062 /** The reloading controller used by this builder. */ 063 private ReloadingController reloadingController; 064 065 /** 066 * Creates a new instance of {@code ReloadingCombinedConfigurationBuilder}. 067 * No parameters are set. 068 */ 069 public ReloadingCombinedConfigurationBuilder() 070 { 071 super(); 072 } 073 074 /** 075 * Creates a new instance of {@code ReloadingCombinedConfigurationBuilder} 076 * and sets the specified initialization parameters and the 077 * <em>allowFailOnInit</em> flag. 078 * 079 * @param params a map with initialization parameters 080 * @param allowFailOnInit the <em>allowFailOnInit</em> flag 081 */ 082 public ReloadingCombinedConfigurationBuilder(final Map<String, Object> params, 083 final boolean allowFailOnInit) 084 { 085 super(params, allowFailOnInit); 086 } 087 088 /** 089 * Creates a new instance of {@code ReloadingCombinedConfigurationBuilder} 090 * and sets the specified initialization parameters. 091 * 092 * @param params a map with initialization parameters 093 */ 094 public ReloadingCombinedConfigurationBuilder(final Map<String, Object> params) 095 { 096 super(params); 097 } 098 099 /** 100 * {@inheritDoc} This method is overridden to adapt the return type. 101 */ 102 @Override 103 public ReloadingCombinedConfigurationBuilder configure(final BuilderParameters... params) 104 { 105 super.configure(params); 106 return this; 107 } 108 109 /** 110 * {@inheritDoc} This implementation returns a 111 * {@link CombinedReloadingController} which contains sub controllers for 112 * all child configuration sources with reloading support. If the definition 113 * builder supports reloading, its controller is contained, too. Note that 114 * the combined reloading controller is initialized when the result 115 * configuration is created (i.e. when calling {@code getConfiguration()} 116 * for the first time). So this method does not return a meaningful result 117 * before. 118 */ 119 @Override 120 public synchronized ReloadingController getReloadingController() 121 { 122 return reloadingController; 123 } 124 125 /** 126 * {@inheritDoc} This implementation makes sure that the reloading state of 127 * the managed reloading controller is reset. Note that this has to be done 128 * here and not in {@link #initResultInstance(CombinedConfiguration)} 129 * because it must be outside of a synchronized block; otherwise, a 130 * dead-lock situation can occur. 131 */ 132 @Override 133 public CombinedConfiguration getConfiguration() throws ConfigurationException 134 { 135 final CombinedConfiguration result = super.getConfiguration(); 136 reloadingController.resetReloadingState(); 137 return result; 138 } 139 140 /** 141 * {@inheritDoc} This implementation creates a builder for XML 142 * configurations with reloading support. 143 */ 144 @Override 145 protected ConfigurationBuilder<? extends HierarchicalConfiguration<?>> createXMLDefinitionBuilder( 146 final BuilderParameters builderParams) 147 { 148 return new ReloadingFileBasedConfigurationBuilder<>( 149 XMLConfiguration.class).configure(builderParams); 150 } 151 152 /** 153 * {@inheritDoc} This implementation first calls the super method to 154 * actually initialize the result configuration. Then it creates the 155 * {@link CombinedReloadingController} for all child configuration sources 156 * with reloading support. 157 */ 158 @Override 159 protected void initResultInstance(final CombinedConfiguration result) 160 throws ConfigurationException 161 { 162 super.initResultInstance(result); 163 if (reloadingController == null) 164 { 165 reloadingController = createReloadingController(); 166 } 167 } 168 169 /** 170 * Creates the {@code ReloadingController} for this builder. This method is 171 * called after the result configuration has been created and initialized. 172 * It is called from a synchronized block. This implementation creates a 173 * {@link CombinedReloadingController}. 174 * 175 * @return the {@code ReloadingController} for this builder 176 * @throws ConfigurationException if an error occurs 177 */ 178 protected ReloadingController createReloadingController() 179 throws ConfigurationException 180 { 181 final Collection<ReloadingController> subControllers = 182 new LinkedList<>(); 183 final ConfigurationBuilder<? extends HierarchicalConfiguration<?>> defBuilder = 184 getDefinitionBuilder(); 185 obtainReloadingController(subControllers, defBuilder); 186 187 for (final ConfigurationBuilder<? extends Configuration> b : getChildBuilders()) 188 { 189 obtainReloadingController(subControllers, b); 190 } 191 192 final CombinedReloadingController ctrl = 193 new CombinedReloadingController(subControllers); 194 ctrl.resetInitialReloadingState(); 195 return ctrl; 196 } 197 198 /** 199 * Checks whether the passed in builder object supports reloading. If yes, 200 * its reloading controller is obtained and added to the given list. 201 * 202 * @param subControllers the list with sub controllers 203 * @param builder the builder object to be checked 204 */ 205 public static void obtainReloadingController( 206 final Collection<ReloadingController> subControllers, final Object builder) 207 { 208 if (builder instanceof ReloadingControllerSupport) 209 { 210 subControllers.add(((ReloadingControllerSupport) builder) 211 .getReloadingController()); 212 } 213 } 214}