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