MultiFileConfigurationBuilderProvider.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.Arrays;

  19. import org.apache.commons.configuration2.Configuration;
  20. import org.apache.commons.configuration2.ConfigurationUtils;
  21. import org.apache.commons.configuration2.HierarchicalConfiguration;
  22. import org.apache.commons.configuration2.builder.BuilderConfigurationWrapperFactory;
  23. import org.apache.commons.configuration2.builder.BuilderConfigurationWrapperFactory.EventSourceSupport;
  24. import org.apache.commons.configuration2.builder.ConfigurationBuilder;
  25. import org.apache.commons.configuration2.event.Event;
  26. import org.apache.commons.configuration2.event.EventListener;
  27. import org.apache.commons.configuration2.event.EventType;
  28. import org.apache.commons.configuration2.ex.ConfigurationException;
  29. import org.apache.commons.configuration2.reloading.ReloadingController;
  30. import org.apache.commons.configuration2.reloading.ReloadingControllerSupport;

  31. /**
  32.  * <p>
  33.  * A specialized {@code ConfigurationBuilderProvider} implementation for integrating
  34.  * {@link MultiFileConfigurationBuilder} with {@code CombinedConfigurationBuilder}.
  35.  * </p>
  36.  * <p>
  37.  * When using a configuration source managed by {@code MultiFileConfigurationBuilder} it is not sufficient to store the
  38.  * configuration once obtained from the builder in the resulting combined configuration. Rather, it has to be ensured
  39.  * that each access to this configuration queries the builder anew so that it can evaluate its file pattern and return a
  40.  * different configuration if necessary. Therefore, this class returns a specialized wrapper over a
  41.  * {@code MultiFileConfigurationBuilder} which returns a configuration wrapping the builder; so accessing the
  42.  * configuration's properties actually calls back to the builder. This constellation is compatible with the way
  43.  * {@code DynamicCombinedConfiguration} manages its data.
  44.  * </p>
  45.  *
  46.  * @since 2.0
  47.  */
  48. public class MultiFileConfigurationBuilderProvider extends BaseConfigurationBuilderProvider {
  49.     /**
  50.      * A wrapper builder implementation which also provides a {@code ReloadingController}. This class assumes that the
  51.      * wrapped builder implements {@code ReloadingControllerSupport}. So the reloading controller can be obtained from this
  52.      * object.
  53.      */
  54.     private static final class ReloadableWrapperBuilder extends WrapperBuilder implements ReloadingControllerSupport {
  55.         /** The object for obtaining the reloading controller. */
  56.         private final ReloadingControllerSupport ctrlSupport;

  57.         /**
  58.          * Creates a new instance of {@code ReloadableWrapperBuilder}.
  59.          *
  60.          * @param conf the managed configuration
  61.          * @param bldr the underlying builder (must implement {@code ReloadingControllerSupport})
  62.          */
  63.         public ReloadableWrapperBuilder(final Configuration conf, final ConfigurationBuilder<? extends Configuration> bldr) {
  64.             super(conf, bldr);
  65.             ctrlSupport = (ReloadingControllerSupport) bldr;
  66.         }

  67.         @Override
  68.         public ReloadingController getReloadingController() {
  69.             return ctrlSupport.getReloadingController();
  70.         }
  71.     }

  72.     /**
  73.      * A simple wrapper implementation of the {@code ConfigurationBuilder} interface which returns a fix configuration and
  74.      * delegates to another builder for event listener management.
  75.      */
  76.     private static class WrapperBuilder implements ConfigurationBuilder<Configuration> {
  77.         /** The configuration managed by this builder. */
  78.         private final Configuration configuration;

  79.         /** The builder to which this instance delegates. */
  80.         private final ConfigurationBuilder<? extends Configuration> builder;

  81.         /**
  82.          * Creates a new instance of {@code WrapperBuilder}.
  83.          *
  84.          * @param conf the managed configuration
  85.          * @param bldr the underlying builder
  86.          */
  87.         public WrapperBuilder(final Configuration conf, final ConfigurationBuilder<? extends Configuration> bldr) {
  88.             configuration = conf;
  89.             builder = bldr;
  90.         }

  91.         @Override
  92.         public <T extends Event> void addEventListener(final EventType<T> eventType, final EventListener<? super T> listener) {
  93.             builder.addEventListener(eventType, listener);
  94.         }

  95.         @Override
  96.         public Configuration getConfiguration() throws ConfigurationException {
  97.             return configuration;
  98.         }

  99.         @Override
  100.         public <T extends Event> boolean removeEventListener(final EventType<T> eventType, final EventListener<? super T> listener) {
  101.             return builder.removeEventListener(eventType, listener);
  102.         }
  103.     }

  104.     /** Constant for the name of the builder class. */
  105.     private static final String BUILDER_CLASS = "org.apache.commons.configuration2.builder.combined.MultiFileConfigurationBuilder";

  106.     /** Constant for the name of the reloading builder class. */
  107.     private static final String RELOADING_BUILDER_CLASS = "org.apache.commons.configuration2.builder.combined.ReloadingMultiFileConfigurationBuilder";

  108.     /** Constant for the name of the parameters class. */
  109.     private static final String PARAM_CLASS = "org.apache.commons.configuration2.builder.combined.MultiFileBuilderParametersImpl";

  110.     /**
  111.      * Creates the {@code ConfigurationBuilder} to be returned by this provider. This is a very simple implementation which
  112.      * always returns the same wrapper configuration instance. The handling of builder listeners is delegated to the wrapped
  113.      * {@code MultiFileConfigurationBuilder}. If reloading is support, the builder returned by this method also implements
  114.      * the {@link ReloadingControllerSupport} interface.
  115.      *
  116.      * @param multiBuilder the {@code MultiFileConfigurationBuilder}
  117.      * @param wrapConfig the configuration to be returned
  118.      * @return the wrapper builder
  119.      */
  120.     private static ConfigurationBuilder<? extends Configuration> createWrapperBuilder(final ConfigurationBuilder<? extends Configuration> multiBuilder,
  121.         final Configuration wrapConfig) {
  122.         if (multiBuilder instanceof ReloadingControllerSupport) {
  123.             return new ReloadableWrapperBuilder(wrapConfig, multiBuilder);
  124.         }
  125.         return new WrapperBuilder(wrapConfig, multiBuilder);
  126.     }

  127.     /**
  128.      * Creates a new instance of {@code MultiFileConfigurationBuilderProvider} and sets the name of the configuration class
  129.      * to be returned by {@code MultiFileConfigurationBuilder}.
  130.      *
  131.      * @param configCls the name of the managed configuration class
  132.      * @param paramCls the name of the class of the parameters object to configure the managed configuration
  133.      */
  134.     public MultiFileConfigurationBuilderProvider(final String configCls, final String paramCls) {
  135.         super(BUILDER_CLASS, RELOADING_BUILDER_CLASS, configCls, Arrays.asList(paramCls, PARAM_CLASS));
  136.     }

  137.     /**
  138.      * Creates a configuration which wraps the specified builder.
  139.      *
  140.      * @param builder the builder
  141.      * @return the wrapping configuration
  142.      */
  143.     // It is safe to disable any type checks because we manually determine
  144.     // the interface class to be passed to BuilderConfigurationWrapperFactory
  145.     @SuppressWarnings({"unchecked", "rawtypes"})
  146.     private Configuration createWrapperConfiguration(final ConfigurationBuilder builder) {
  147.         final Class<?> configClass = ConfigurationUtils.loadClassNoEx(getConfigurationClass());
  148.         final Class ifcClass = HierarchicalConfiguration.class.isAssignableFrom(configClass) ? HierarchicalConfiguration.class : Configuration.class;
  149.         return (Configuration) BuilderConfigurationWrapperFactory.createBuilderConfigurationWrapper(ifcClass, builder, EventSourceSupport.BUILDER);
  150.     }

  151.     /**
  152.      * {@inheritDoc} This implementation lets the super class create a fully configured builder. Then it returns a special
  153.      * wrapper around it.
  154.      */
  155.     @Override
  156.     public ConfigurationBuilder<? extends Configuration> getConfigurationBuilder(final ConfigurationDeclaration decl) throws ConfigurationException {
  157.         final ConfigurationBuilder<? extends Configuration> multiBuilder = super.getConfigurationBuilder(decl);
  158.         final Configuration wrapConfig = createWrapperConfiguration(multiBuilder);
  159.         return createWrapperBuilder(multiBuilder, wrapConfig);
  160.     }
  161. }