ReloadingCombinedConfigurationBuilder.java

  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. import java.util.Collection;
  19. import java.util.LinkedList;
  20. import java.util.Map;

  21. import org.apache.commons.configuration2.CombinedConfiguration;
  22. import org.apache.commons.configuration2.HierarchicalConfiguration;
  23. import org.apache.commons.configuration2.XMLConfiguration;
  24. import org.apache.commons.configuration2.builder.BuilderParameters;
  25. import org.apache.commons.configuration2.builder.ConfigurationBuilder;
  26. import org.apache.commons.configuration2.builder.ReloadingFileBasedConfigurationBuilder;
  27. import org.apache.commons.configuration2.ex.ConfigurationException;
  28. import org.apache.commons.configuration2.reloading.CombinedReloadingController;
  29. import org.apache.commons.configuration2.reloading.ReloadingController;
  30. import org.apache.commons.configuration2.reloading.ReloadingControllerSupport;

  31. /**
  32.  * <p>
  33.  * An extension of {@code CombinedConfigurationBuilder} which also supports reloading operations.
  34.  * </p>
  35.  * <p>
  36.  * This class differs from its super class in the following aspects:
  37.  * </p>
  38.  * <ul>
  39.  * <li>A {@link ReloadingController} is created which manages all child configuration builders supporting reloading
  40.  * operations.</li>
  41.  * <li>If no {@code ConfigurationBuilder} is provided for the definition configuration, a builder with reloading support
  42.  * is created.</li>
  43.  * </ul>
  44.  * <p>
  45.  * This class can be used exactly as its super class for creating combined configurations from multiple configuration
  46.  * sources. In addition, the combined reloading controller managed by an instance can be used to react on changes in one
  47.  * of these configuration sources or in the definition configuration.
  48.  * </p>
  49.  *
  50.  * @since 2.0
  51.  */
  52. public class ReloadingCombinedConfigurationBuilder extends CombinedConfigurationBuilder implements ReloadingControllerSupport {
  53.     /**
  54.      * Checks whether the passed in builder object supports reloading. If yes, its reloading controller is obtained and
  55.      * added to the given list.
  56.      *
  57.      * @param subControllers the list with sub controllers
  58.      * @param builder the builder object to be checked
  59.      */
  60.     public static void obtainReloadingController(final Collection<ReloadingController> subControllers, final Object builder) {
  61.         if (builder instanceof ReloadingControllerSupport) {
  62.             subControllers.add(((ReloadingControllerSupport) builder).getReloadingController());
  63.         }
  64.     }

  65.     /** The reloading controller used by this builder. */
  66.     private ReloadingController reloadingController;

  67.     /**
  68.      * Creates a new instance of {@code ReloadingCombinedConfigurationBuilder}. No parameters are set.
  69.      */
  70.     public ReloadingCombinedConfigurationBuilder() {
  71.     }

  72.     /**
  73.      * Creates a new instance of {@code ReloadingCombinedConfigurationBuilder} and sets the specified initialization
  74.      * parameters.
  75.      *
  76.      * @param params a map with initialization parameters
  77.      */
  78.     public ReloadingCombinedConfigurationBuilder(final Map<String, Object> params) {
  79.         super(params);
  80.     }

  81.     /**
  82.      * Creates a new instance of {@code ReloadingCombinedConfigurationBuilder} and sets the specified initialization
  83.      * parameters and the <em>allowFailOnInit</em> flag.
  84.      *
  85.      * @param params a map with initialization parameters
  86.      * @param allowFailOnInit the <em>allowFailOnInit</em> flag
  87.      */
  88.     public ReloadingCombinedConfigurationBuilder(final Map<String, Object> params, final boolean allowFailOnInit) {
  89.         super(params, allowFailOnInit);
  90.     }

  91.     /**
  92.      * {@inheritDoc} This method is overridden to adapt the return type.
  93.      */
  94.     @Override
  95.     public ReloadingCombinedConfigurationBuilder configure(final BuilderParameters... params) {
  96.         super.configure(params);
  97.         return this;
  98.     }

  99.     /**
  100.      * Creates the {@code ReloadingController} for this builder. This method is called after the result configuration has
  101.      * been created and initialized. It is called from a synchronized block. This implementation creates a
  102.      * {@link CombinedReloadingController}.
  103.      *
  104.      * @return the {@code ReloadingController} for this builder
  105.      * @throws ConfigurationException if an error occurs
  106.      */
  107.     protected ReloadingController createReloadingController() throws ConfigurationException {
  108.         final Collection<ReloadingController> subControllers = new LinkedList<>();
  109.         final ConfigurationBuilder<? extends HierarchicalConfiguration<?>> defBuilder = getDefinitionBuilder();
  110.         obtainReloadingController(subControllers, defBuilder);

  111.         getChildBuilders().forEach(b -> obtainReloadingController(subControllers, b));

  112.         final CombinedReloadingController ctrl = new CombinedReloadingController(subControllers);
  113.         ctrl.resetInitialReloadingState();
  114.         return ctrl;
  115.     }

  116.     /**
  117.      * {@inheritDoc} This implementation creates a builder for XML configurations with reloading support.
  118.      */
  119.     @Override
  120.     protected ConfigurationBuilder<? extends HierarchicalConfiguration<?>> createXMLDefinitionBuilder(final BuilderParameters builderParams) {
  121.         return new ReloadingFileBasedConfigurationBuilder<>(XMLConfiguration.class).configure(builderParams);
  122.     }

  123.     /**
  124.      * {@inheritDoc} This implementation makes sure that the reloading state of the managed reloading controller is reset.
  125.      * Note that this has to be done here and not in {@link #initResultInstance(CombinedConfiguration)} because it must be
  126.      * outside of a synchronized block; otherwise, a dead-lock situation can occur.
  127.      */
  128.     @Override
  129.     public CombinedConfiguration getConfiguration() throws ConfigurationException {
  130.         final CombinedConfiguration result = super.getConfiguration();
  131.         reloadingController.resetReloadingState();
  132.         return result;
  133.     }

  134.     /**
  135.      * {@inheritDoc} This implementation returns a {@link CombinedReloadingController} which contains sub controllers for
  136.      * all child configuration sources with reloading support. If the definition builder supports reloading, its controller
  137.      * is contained, too. Note that the combined reloading controller is initialized when the result configuration is
  138.      * created (i.e. when calling {@code getConfiguration()} for the first time). So this method does not return a
  139.      * meaningful result before.
  140.      */
  141.     @Override
  142.     public synchronized ReloadingController getReloadingController() {
  143.         return reloadingController;
  144.     }

  145.     /**
  146.      * {@inheritDoc} This implementation first calls the super method to actually initialize the result configuration. Then
  147.      * it creates the {@link CombinedReloadingController} for all child configuration sources with reloading support.
  148.      */
  149.     @Override
  150.     protected void initResultInstance(final CombinedConfiguration result) throws ConfigurationException {
  151.         super.initResultInstance(result);
  152.         if (reloadingController == null) {
  153.             reloadingController = createReloadingController();
  154.         }
  155.     }
  156. }