| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package org.apache.commons.configuration2.builder.combined; |
| |
| import java.util.Collection; |
| import java.util.LinkedList; |
| import java.util.Map; |
| |
| import org.apache.commons.configuration2.CombinedConfiguration; |
| import org.apache.commons.configuration2.HierarchicalConfiguration; |
| import org.apache.commons.configuration2.XMLConfiguration; |
| import org.apache.commons.configuration2.builder.BuilderParameters; |
| import org.apache.commons.configuration2.builder.ConfigurationBuilder; |
| import org.apache.commons.configuration2.builder.ReloadingFileBasedConfigurationBuilder; |
| import org.apache.commons.configuration2.ex.ConfigurationException; |
| import org.apache.commons.configuration2.reloading.CombinedReloadingController; |
| import org.apache.commons.configuration2.reloading.ReloadingController; |
| import org.apache.commons.configuration2.reloading.ReloadingControllerSupport; |
| |
| /** |
| * <p> |
| * An extension of {@code CombinedConfigurationBuilder} which also supports reloading operations. |
| * </p> |
| * <p> |
| * This class differs from its super class in the following aspects: |
| * </p> |
| * <ul> |
| * <li>A {@link ReloadingController} is created which manages all child configuration builders supporting reloading |
| * operations.</li> |
| * <li>If no {@code ConfigurationBuilder} is provided for the definition configuration, a builder with reloading support |
| * is created.</li> |
| * </ul> |
| * <p> |
| * This class can be used exactly as its super class for creating combined configurations from multiple configuration |
| * sources. In addition, the combined reloading controller managed by an instance can be used to react on changes in one |
| * of these configuration sources or in the definition configuration. |
| * </p> |
| * |
| * @since 2.0 |
| */ |
| public class ReloadingCombinedConfigurationBuilder extends CombinedConfigurationBuilder implements ReloadingControllerSupport { |
| /** |
| * Checks whether the passed in builder object supports reloading. If yes, its reloading controller is obtained and |
| * added to the given list. |
| * |
| * @param subControllers the list with sub controllers |
| * @param builder the builder object to be checked |
| */ |
| public static void obtainReloadingController(final Collection<ReloadingController> subControllers, final Object builder) { |
| if (builder instanceof ReloadingControllerSupport) { |
| subControllers.add(((ReloadingControllerSupport) builder).getReloadingController()); |
| } |
| } |
| |
| /** The reloading controller used by this builder. */ |
| private ReloadingController reloadingController; |
| |
| /** |
| * Creates a new instance of {@code ReloadingCombinedConfigurationBuilder}. No parameters are set. |
| */ |
| public ReloadingCombinedConfigurationBuilder() { |
| } |
| |
| /** |
| * Creates a new instance of {@code ReloadingCombinedConfigurationBuilder} and sets the specified initialization |
| * parameters. |
| * |
| * @param params a map with initialization parameters |
| */ |
| public ReloadingCombinedConfigurationBuilder(final Map<String, Object> params) { |
| super(params); |
| } |
| |
| /** |
| * Creates a new instance of {@code ReloadingCombinedConfigurationBuilder} and sets the specified initialization |
| * parameters and the <em>allowFailOnInit</em> flag. |
| * |
| * @param params a map with initialization parameters |
| * @param allowFailOnInit the <em>allowFailOnInit</em> flag |
| */ |
| public ReloadingCombinedConfigurationBuilder(final Map<String, Object> params, final boolean allowFailOnInit) { |
| super(params, allowFailOnInit); |
| } |
| |
| /** |
| * {@inheritDoc} This method is overridden to adapt the return type. |
| */ |
| @Override |
| public ReloadingCombinedConfigurationBuilder configure(final BuilderParameters... params) { |
| super.configure(params); |
| return this; |
| } |
| |
| /** |
| * Creates the {@code ReloadingController} for this builder. This method is called after the result configuration has |
| * been created and initialized. It is called from a synchronized block. This implementation creates a |
| * {@link CombinedReloadingController}. |
| * |
| * @return the {@code ReloadingController} for this builder |
| * @throws ConfigurationException if an error occurs |
| */ |
| protected ReloadingController createReloadingController() throws ConfigurationException { |
| final Collection<ReloadingController> subControllers = new LinkedList<>(); |
| final ConfigurationBuilder<? extends HierarchicalConfiguration<?>> defBuilder = getDefinitionBuilder(); |
| obtainReloadingController(subControllers, defBuilder); |
| |
| getChildBuilders().forEach(b -> obtainReloadingController(subControllers, b)); |
| |
| final CombinedReloadingController ctrl = new CombinedReloadingController(subControllers); |
| ctrl.resetInitialReloadingState(); |
| return ctrl; |
| } |
| |
| /** |
| * {@inheritDoc} This implementation creates a builder for XML configurations with reloading support. |
| */ |
| @Override |
| protected ConfigurationBuilder<? extends HierarchicalConfiguration<?>> createXMLDefinitionBuilder(final BuilderParameters builderParams) { |
| return new ReloadingFileBasedConfigurationBuilder<>(XMLConfiguration.class).configure(builderParams); |
| } |
| |
| /** |
| * {@inheritDoc} This implementation makes sure that the reloading state of the managed reloading controller is reset. |
| * Note that this has to be done here and not in {@link #initResultInstance(CombinedConfiguration)} because it must be |
| * outside of a synchronized block; otherwise, a dead-lock situation can occur. |
| */ |
| @Override |
| public CombinedConfiguration getConfiguration() throws ConfigurationException { |
| final CombinedConfiguration result = super.getConfiguration(); |
| reloadingController.resetReloadingState(); |
| return result; |
| } |
| |
| /** |
| * {@inheritDoc} This implementation returns a {@link CombinedReloadingController} which contains sub controllers for |
| * all child configuration sources with reloading support. If the definition builder supports reloading, its controller |
| * is contained, too. Note that the combined reloading controller is initialized when the result configuration is |
| * created (i.e. when calling {@code getConfiguration()} for the first time). So this method does not return a |
| * meaningful result before. |
| */ |
| @Override |
| public synchronized ReloadingController getReloadingController() { |
| return reloadingController; |
| } |
| |
| /** |
| * {@inheritDoc} This implementation first calls the super method to actually initialize the result configuration. Then |
| * it creates the {@link CombinedReloadingController} for all child configuration sources with reloading support. |
| */ |
| @Override |
| protected void initResultInstance(final CombinedConfiguration result) throws ConfigurationException { |
| super.initResultInstance(result); |
| if (reloadingController == null) { |
| reloadingController = createReloadingController(); |
| } |
| } |
| } |