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