CombinedBuilderParametersImpl.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.ArrayList;
  19. import java.util.Collection;
  20. import java.util.Collections;
  21. import java.util.HashMap;
  22. import java.util.LinkedList;
  23. import java.util.Map;

  24. import org.apache.commons.configuration2.ConfigurationUtils;
  25. import org.apache.commons.configuration2.HierarchicalConfiguration;
  26. import org.apache.commons.configuration2.builder.BasicBuilderParameters;
  27. import org.apache.commons.configuration2.builder.BuilderParameters;
  28. import org.apache.commons.configuration2.builder.ConfigurationBuilder;
  29. import org.apache.commons.configuration2.builder.DefaultParametersHandler;
  30. import org.apache.commons.configuration2.builder.DefaultParametersManager;

  31. /**
  32.  * <p>
  33.  * A specialized parameters object for a {@link CombinedConfigurationBuilder}.
  34.  * </p>
  35.  * <p>
  36.  * This class defines methods for setting properties for customizing a builder for combined configurations. Note that
  37.  * some of these properties can also be set in the configuration definition file. If this is the case, the settings in
  38.  * the definition file override the content of this object.
  39.  * </p>
  40.  * <p>
  41.  * This class is not thread-safe. It is intended that an instance is constructed and initialized by a single thread
  42.  * during configuration of a {@code ConfigurationBuilder}.
  43.  * </p>
  44.  *
  45.  * @since 2.0
  46.  */
  47. public class CombinedBuilderParametersImpl extends BasicBuilderParameters implements CombinedBuilderProperties<CombinedBuilderParametersImpl> {
  48.     /** Constant for the key in the parameters map used by this class. */
  49.     private static final String PARAM_KEY = RESERVED_PARAMETER_PREFIX + CombinedBuilderParametersImpl.class.getName();

  50.     /**
  51.      * Looks up an instance of this class in the specified parameters map. This is equivalent to
  52.      * {@code fromParameters(params, false);}
  53.      *
  54.      * @param params the map with parameters (must not be <strong>null</strong>
  55.      * @return the instance obtained from the map or <strong>null</strong>
  56.      * @throws NullPointerException if the map is <strong>null</strong>
  57.      */
  58.     public static CombinedBuilderParametersImpl fromParameters(final Map<String, ?> params) {
  59.         return fromParameters(params, false);
  60.     }

  61.     /**
  62.      * Looks up an instance of this class in the specified parameters map and optionally creates a new one if none is found.
  63.      * This method can be used to obtain an instance of this class which has been stored in a parameters map. It is
  64.      * compatible with the {@code getParameters()} method.
  65.      *
  66.      * @param params the map with parameters (must not be <strong>null</strong>
  67.      * @param createIfMissing determines the behavior if no instance is found in the map; if <strong>true</strong>, a new instance
  68.      *        with default settings is created; if <strong>false</strong>, <strong>null</strong> is returned
  69.      * @return the instance obtained from the map or <strong>null</strong>
  70.      * @throws NullPointerException if the map is <strong>null</strong>
  71.      */
  72.     public static CombinedBuilderParametersImpl fromParameters(final Map<String, ?> params, final boolean createIfMissing) {
  73.         CombinedBuilderParametersImpl result = (CombinedBuilderParametersImpl) params.get(PARAM_KEY);
  74.         if (result == null && createIfMissing) {
  75.             result = new CombinedBuilderParametersImpl();
  76.         }
  77.         return result;
  78.     }

  79.     /** The definition configuration builder. */
  80.     private ConfigurationBuilder<? extends HierarchicalConfiguration<?>> definitionBuilder;

  81.     /** A parameters object for the definition configuration builder. */
  82.     private BuilderParameters definitionBuilderParameters;

  83.     /** A map with registered configuration builder providers. */
  84.     private final Map<String, ConfigurationBuilderProvider> providers;

  85.     /** A list with default parameters for child configuration sources. */
  86.     private final Collection<BuilderParameters> childParameters;

  87.     /** The manager for default handlers. */
  88.     private DefaultParametersManager childDefaultParametersManager;

  89.     /** The base path for configuration sources to be loaded. */
  90.     private String basePath;

  91.     /** A flag whether settings should be inherited by child builders. */
  92.     private boolean inheritSettings;

  93.     /**
  94.      * Creates a new instance of {@code CombinedBuilderParametersImpl}.
  95.      */
  96.     public CombinedBuilderParametersImpl() {
  97.         providers = new HashMap<>();
  98.         childParameters = new LinkedList<>();
  99.         inheritSettings = true;
  100.     }

  101.     /**
  102.      * {@inheritDoc} This implementation also clones the parameters object for the definition builder if possible.
  103.      */
  104.     @Override
  105.     public CombinedBuilderParametersImpl clone() {
  106.         final CombinedBuilderParametersImpl copy = (CombinedBuilderParametersImpl) super.clone();
  107.         copy.setDefinitionBuilderParameters((BuilderParameters) ConfigurationUtils.cloneIfPossible(getDefinitionBuilderParameters()));
  108.         return copy;
  109.     }

  110.     /**
  111.      * Gets the base path for relative names of configuration sources. Result may be <strong>null</strong> if no base path has been
  112.      * set.
  113.      *
  114.      * @return the base path for resolving relative file names
  115.      */
  116.     public String getBasePath() {
  117.         return basePath;
  118.     }

  119.     /**
  120.      * Gets the {@code DefaultParametersManager} object for initializing parameter objects for child configuration
  121.      * sources. This method never returns <strong>null</strong>. If no manager was set, a new instance is created right now.
  122.      *
  123.      * @return the {@code DefaultParametersManager} for child configuration sources
  124.      */
  125.     public DefaultParametersManager getChildDefaultParametersManager() {
  126.         if (childDefaultParametersManager == null) {
  127.             childDefaultParametersManager = new DefaultParametersManager();
  128.         }
  129.         return childDefaultParametersManager;
  130.     }

  131.     /**
  132.      * Gets a collection with default parameter objects for child configuration sources. This collection contains the
  133.      * same objects (in the same order) that were passed to {@code addChildParameters()}. The returned collection is a
  134.      * defensive copy; it can be modified, but this has no effect on the parameters stored in this object.
  135.      *
  136.      * @return a map with default parameters for child sources
  137.      */
  138.     public Collection<? extends BuilderParameters> getDefaultChildParameters() {
  139.         return new ArrayList<>(childParameters);
  140.     }

  141.     /**
  142.      * Gets the {@code ConfigurationBuilder} object for obtaining the definition configuration.
  143.      *
  144.      * @return the definition {@code ConfigurationBuilder}
  145.      */
  146.     public ConfigurationBuilder<? extends HierarchicalConfiguration<?>> getDefinitionBuilder() {
  147.         return definitionBuilder;
  148.     }

  149.     /**
  150.      * Gets the parameters object for the definition configuration builder if present.
  151.      *
  152.      * @return the parameters object for the definition configuration builder or <strong>null</strong>
  153.      */
  154.     public BuilderParameters getDefinitionBuilderParameters() {
  155.         return definitionBuilderParameters;
  156.     }

  157.     /**
  158.      * {@inheritDoc} This implementation returns a map which contains this object itself under a specific key. The static
  159.      * {@code fromParameters()} method can be used to extract an instance from a parameters map.
  160.      */
  161.     @Override
  162.     public Map<String, Object> getParameters() {
  163.         final Map<String, Object> params = super.getParameters();
  164.         params.put(PARAM_KEY, this);
  165.         return params;
  166.     }

  167.     /**
  168.      * Gets an (unmodifiable) map with the currently registered {@code ConfigurationBuilderProvider} objects.
  169.      *
  170.      * @return the map with {@code ConfigurationBuilderProvider} objects (the keys are the tag names)
  171.      */
  172.     public Map<String, ConfigurationBuilderProvider> getProviders() {
  173.         return Collections.unmodifiableMap(providers);
  174.     }

  175.     /**
  176.      * {@inheritDoc} This implementation additionally copies some properties defined by this class.
  177.      */
  178.     @Override
  179.     public void inheritFrom(final Map<String, ?> source) {
  180.         super.inheritFrom(source);

  181.         final CombinedBuilderParametersImpl srcParams = fromParameters(source);
  182.         if (srcParams != null) {
  183.             setChildDefaultParametersManager(srcParams.getChildDefaultParametersManager());
  184.             setInheritSettings(srcParams.isInheritSettings());
  185.         }
  186.     }

  187.     /**
  188.      * Returns the current value of the flag that controls whether the settings of the parent combined configuration builder
  189.      * should be inherited by its child configurations.
  190.      *
  191.      * @return the flag whether settings should be inherited by child configurations
  192.      */
  193.     public boolean isInheritSettings() {
  194.         return inheritSettings;
  195.     }

  196.     /**
  197.      * Returns the {@code ConfigurationBuilderProvider} which is registered for the specified tag name or <strong>null</strong> if
  198.      * there is no registration for this tag.
  199.      *
  200.      * @param tagName the tag name
  201.      * @return the provider registered for this tag or <strong>null</strong>
  202.      */
  203.     public ConfigurationBuilderProvider providerForTag(final String tagName) {
  204.         return providers.get(tagName);
  205.     }

  206.     /**
  207.      * {@inheritDoc} This implementation registers the passed in handler at an internal {@link DefaultParametersManager}
  208.      * instance. If none was set, a new instance is created now.
  209.      */
  210.     @Override
  211.     public <D> CombinedBuilderParametersImpl registerChildDefaultsHandler(final Class<D> paramClass, final DefaultParametersHandler<? super D> handler) {
  212.         getChildDefaultParametersManager().registerDefaultsHandler(paramClass, handler);
  213.         return this;
  214.     }

  215.     /**
  216.      * {@inheritDoc} This implementation registers the passed in handler at an internal {@link DefaultParametersManager}
  217.      * instance. If none was set, a new instance is created now.
  218.      */
  219.     @Override
  220.     public <D> CombinedBuilderParametersImpl registerChildDefaultsHandler(final Class<D> paramClass, final DefaultParametersHandler<? super D> handler,
  221.         final Class<?> startClass) {
  222.         getChildDefaultParametersManager().registerDefaultsHandler(paramClass, handler, startClass);
  223.         return this;
  224.     }

  225.     /**
  226.      * Registers all {@code ConfigurationBuilderProvider}s in the given parameters object which have not yet been
  227.      * registered. This method works like the method with the same name, but the map with providers is obtained from the
  228.      * passed in parameters object.
  229.      *
  230.      * @param params the parameters object from which to copy providers(must not be <strong>null</strong>)
  231.      * @return a reference to this object for method chaining
  232.      * @throws IllegalArgumentException if the source parameters object is <strong>null</strong>
  233.      */
  234.     public CombinedBuilderParametersImpl registerMissingProviders(final CombinedBuilderParametersImpl params) {
  235.         if (params == null) {
  236.             throw new IllegalArgumentException("Source parameters must not be null!");
  237.         }
  238.         return registerMissingProviders(params.getProviders());
  239.     }

  240.     /**
  241.      * Registers all {@code ConfigurationBuilderProvider}s in the given map to this object which have not yet been
  242.      * registered. This method is mainly used for internal purposes: a {@code CombinedConfigurationBuilder} takes the
  243.      * providers contained in a parameters object and adds all standard providers. This way it is possible to override a
  244.      * standard provider by registering a provider object for the same tag name at the parameters object.
  245.      *
  246.      * @param providers a map with tag names and corresponding providers (must not be <strong>null</strong> or contain <strong>null</strong>
  247.      *        entries)
  248.      * @return a reference to this object for method chaining
  249.      * @throws IllegalArgumentException if the map with providers is <strong>null</strong> or contains <strong>null</strong> entries
  250.      */
  251.     public CombinedBuilderParametersImpl registerMissingProviders(final Map<String, ConfigurationBuilderProvider> providers) {
  252.         if (providers == null) {
  253.             throw new IllegalArgumentException("Map with providers must not be null!");
  254.         }
  255.         providers.forEach((k, v) -> {
  256.             if (!this.providers.containsKey(k)) {
  257.                 registerProvider(k, v);
  258.             }
  259.         });
  260.         return this;
  261.     }

  262.     /**
  263.      * Registers the given {@code ConfigurationBuilderProvider} for the specified tag name. This means that whenever this
  264.      * tag is encountered in a configuration definition file, the corresponding builder provider is invoked.
  265.      *
  266.      * @param tagName the name of the tag (must not be <strong>null</strong>)
  267.      * @param provider the {@code ConfigurationBuilderProvider} (must not be <strong>null</strong>)
  268.      * @return a reference to this object for method chaining
  269.      * @throws IllegalArgumentException if a required parameter is missing
  270.      */
  271.     @Override
  272.     public CombinedBuilderParametersImpl registerProvider(final String tagName, final ConfigurationBuilderProvider provider) {
  273.         if (tagName == null) {
  274.             throw new IllegalArgumentException("Tag name must not be null!");
  275.         }
  276.         if (provider == null) {
  277.             throw new IllegalArgumentException("Provider must not be null!");
  278.         }

  279.         providers.put(tagName, provider);
  280.         return this;
  281.     }

  282.     /**
  283.      * Sets the base path for this combined configuration builder. Normally it it not necessary to set the base path
  284.      * explicitly. Per default, relative file names of configuration sources are resolved based on the location of the
  285.      * definition file. If this is not desired or if the definition configuration is loaded by a different means, the base
  286.      * path for relative file names can be specified using this method.
  287.      *
  288.      * @param path the base path for resolving relative file names
  289.      * @return a reference to this object for method chaining
  290.      */
  291.     @Override
  292.     public CombinedBuilderParametersImpl setBasePath(final String path) {
  293.         basePath = path;
  294.         return this;
  295.     }

  296.     /**
  297.      * {@inheritDoc} This implementation stores the passed in manager object. An already existing manager object (either
  298.      * explicitly set or created on demand) is overridden. This also removes all default handlers registered before!
  299.      */
  300.     @Override
  301.     public CombinedBuilderParametersImpl setChildDefaultParametersManager(final DefaultParametersManager manager) {
  302.         childDefaultParametersManager = manager;
  303.         return this;
  304.     }

  305.     /**
  306.      * Sets the {@code ConfigurationBuilder} for the definition configuration. This is the configuration which contains the
  307.      * configuration sources that form the combined configuration.
  308.      *
  309.      * @param builder the definition {@code ConfigurationBuilder}
  310.      * @return a reference to this object for method chaining
  311.      */
  312.     @Override
  313.     public CombinedBuilderParametersImpl setDefinitionBuilder(final ConfigurationBuilder<? extends HierarchicalConfiguration<?>> builder) {
  314.         definitionBuilder = builder;
  315.         return this;
  316.     }

  317.     /**
  318.      * Sets the parameters object for the definition configuration builder. This property is evaluated only if the
  319.      * definition configuration builder is not set explicitly (using the {@link #setDefinitionBuilder(ConfigurationBuilder)}
  320.      * method). In this case, a builder for an XML configuration is created and configured with this parameters object.
  321.      *
  322.      * @param params the parameters object for the definition configuration builder
  323.      * @return a reference to this object for method chaining
  324.      */
  325.     @Override
  326.     public CombinedBuilderParametersImpl setDefinitionBuilderParameters(final BuilderParameters params) {
  327.         definitionBuilderParameters = params;
  328.         return this;
  329.     }

  330.     @Override
  331.     public CombinedBuilderParametersImpl setInheritSettings(final boolean inheritSettings) {
  332.         this.inheritSettings = inheritSettings;
  333.         return this;
  334.     }
  335. }