BasicConfigurationBuilder.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;

  18. import java.util.Collection;
  19. import java.util.Collections;
  20. import java.util.HashMap;
  21. import java.util.Map;

  22. import org.apache.commons.configuration2.ConfigurationUtils;
  23. import org.apache.commons.configuration2.ImmutableConfiguration;
  24. import org.apache.commons.configuration2.Initializable;
  25. import org.apache.commons.configuration2.beanutils.BeanDeclaration;
  26. import org.apache.commons.configuration2.beanutils.BeanHelper;
  27. import org.apache.commons.configuration2.beanutils.ConstructorArg;
  28. import org.apache.commons.configuration2.event.Event;
  29. import org.apache.commons.configuration2.event.EventListener;
  30. import org.apache.commons.configuration2.event.EventListenerList;
  31. import org.apache.commons.configuration2.event.EventListenerRegistrationData;
  32. import org.apache.commons.configuration2.event.EventSource;
  33. import org.apache.commons.configuration2.event.EventType;
  34. import org.apache.commons.configuration2.ex.ConfigurationException;
  35. import org.apache.commons.configuration2.ex.ConfigurationRuntimeException;
  36. import org.apache.commons.configuration2.reloading.ReloadingController;

  37. /**
  38.  * <p>
  39.  * An implementation of the {@code ConfigurationBuilder} interface which is able to create different concrete
  40.  * {@code ImmutableConfiguration} implementations based on reflection.
  41.  * </p>
  42.  * <p>
  43.  * When constructing an instance of this class the concrete {@code ImmutableConfiguration} implementation class has to
  44.  * be provided. Then properties for the new {@code ImmutableConfiguration} instance can be set. The first call to
  45.  * {@code getConfiguration()} creates and initializes the new {@code ImmutableConfiguration} object. It is cached and
  46.  * returned by subsequent calls. This cache - and also the initialization properties set so far - can be flushed by
  47.  * calling one of the {@code reset()} methods. That way other {@code ImmutableConfiguration} instances with different
  48.  * properties can be created.
  49.  * </p>
  50.  * <p>
  51.  * If the newly created {@code ImmutableConfiguration} object implements the {@code Initializable} interface, its
  52.  * {@code initialize()} method is called after all initialization properties have been set. This way a concrete
  53.  * implementation class can perform arbitrary initialization steps.
  54.  * </p>
  55.  * <p>
  56.  * There are multiple options for setting up a {@code BasicConfigurationBuilder} instance:
  57.  * </p>
  58.  * <ul>
  59.  * <li>All initialization properties can be set in one or multiple calls of the {@code configure()} method. In each call
  60.  * an arbitrary number of {@link BuilderParameters} objects can be passed. The API allows method chaining and is
  61.  * intended to be used from Java code.</li>
  62.  * <li>If builder instances are created by other means - for example using a dependency injection framework -, the fluent API
  63.  * approach may not be suitable. For those use cases it is also possible to pass in all initialization parameters as a
  64.  * map. The keys of the map have to match initialization properties of the {@code ImmutableConfiguration} object to be
  65.  * created, the values are the corresponding property values. For instance, the key <em>throwExceptionOnMissing</em> in
  66.  * the map will cause the method {@code setThrowExceptionOnMissing()} on the {@code ImmutableConfiguration} object to be
  67.  * called with the corresponding value as parameter.</li>
  68.  * </ul>
  69.  * <p>
  70.  * A builder instance can be constructed with an <em>allowFailOnInit</em> flag. If set to <strong>true</strong>,
  71.  * exceptions during initialization of the configuration are ignored; in such a case an empty configuration object is
  72.  * returned. A use case for this flag is a scenario in which a configuration is optional and created on demand the first
  73.  * time configuration data is to be stored. Consider an application that stores user-specific configuration data in the
  74.  * user's home directory: When started for the first time by a new user there is no configuration file; so it makes
  75.  * sense to start with an empty configuration object. On application exit, settings can be stored in this object and
  76.  * written to the associated file. Then they are available on next application start.
  77.  * </p>
  78.  * <p>
  79.  * This class is thread-safe. Multiple threads can modify initialization properties and call {@code getConfiguration()}.
  80.  * However, the intended use case is that the builder is configured by a single thread first. Then
  81.  * {@code getConfiguration()} can be called concurrently, and it is guaranteed that always the same
  82.  * {@code ImmutableConfiguration} instance is returned until the builder is reset.
  83.  * </p>
  84.  *
  85.  * @param <T> the concrete type of {@code ImmutableConfiguration} objects created by this builder
  86.  * @since 2.0
  87.  */
  88. public class BasicConfigurationBuilder<T extends ImmutableConfiguration> implements ConfigurationBuilder<T> {
  89.     /**
  90.      * Registers an event listener at an event source object.
  91.      *
  92.      * @param evSrc the event source
  93.      * @param regData the registration data object
  94.      * @param <E> the type of the event listener
  95.      */
  96.     private static <E extends Event> void registerListener(final EventSource evSrc, final EventListenerRegistrationData<E> regData) {
  97.         evSrc.addEventListener(regData.getEventType(), regData.getListener());
  98.     }

  99.     /**
  100.      * Removes an event listener from an event source object.
  101.      *
  102.      * @param evSrc the event source
  103.      * @param regData the registration data object
  104.      * @param <E> the type of the event listener
  105.      */
  106.     private static <E extends Event> void removeListener(final EventSource evSrc, final EventListenerRegistrationData<E> regData) {
  107.         evSrc.removeEventListener(regData.getEventType(), regData.getListener());
  108.     }

  109.     /** The class of the objects produced by this builder instance. */
  110.     private final Class<? extends T> resultClass;

  111.     /** An object managing the event listeners registered at this builder. */
  112.     private final EventListenerList eventListeners;

  113.     /** A flag whether exceptions on initializing configurations are allowed. */
  114.     private final boolean allowFailOnInit;

  115.     /** The map with current initialization parameters. */
  116.     private Map<String, Object> parameters;

  117.     /** The current bean declaration. */
  118.     private BeanDeclaration resultDeclaration;

  119.     /** The result object of this builder. */
  120.     private volatile T result;

  121.     /**
  122.      * Creates a new instance of {@code BasicConfigurationBuilder} and initializes it with the given result class. No
  123.      * initialization properties are set.
  124.      *
  125.      * @param resCls the result class (must not be <strong>null</strong>)
  126.      * @throws IllegalArgumentException if the result class is <strong>null</strong>
  127.      */
  128.     public BasicConfigurationBuilder(final Class<? extends T> resCls) {
  129.         this(resCls, null);
  130.     }

  131.     /**
  132.      * Creates a new instance of {@code BasicConfigurationBuilder} and initializes it with the given result class and an
  133.      * initial set of builder parameters. The <em>allowFailOnInit</em> flag is set to <strong>false</strong>.
  134.      *
  135.      * @param resCls the result class (must not be <strong>null</strong>)
  136.      * @param params a map with initialization parameters
  137.      * @throws IllegalArgumentException if the result class is <strong>null</strong>
  138.      */
  139.     public BasicConfigurationBuilder(final Class<? extends T> resCls, final Map<String, Object> params) {
  140.         this(resCls, params, false);
  141.     }

  142.     /**
  143.      * Creates a new instance of {@code BasicConfigurationBuilder} and initializes it with the given result class, an
  144.      * initial set of builder parameters, and the <em>allowFailOnInit</em> flag. The map with parameters may be <strong>null</strong>,
  145.      * in this case no initialization parameters are set.
  146.      *
  147.      * @param resCls the result class (must not be <strong>null</strong>)
  148.      * @param params a map with initialization parameters
  149.      * @param allowFailOnInit a flag whether exceptions on initializing a newly created {@code ImmutableConfiguration}
  150.      *        object are allowed
  151.      * @throws IllegalArgumentException if the result class is <strong>null</strong>
  152.      */
  153.     public BasicConfigurationBuilder(final Class<? extends T> resCls, final Map<String, Object> params, final boolean allowFailOnInit) {
  154.         if (resCls == null) {
  155.             throw new IllegalArgumentException("Result class must not be null!");
  156.         }

  157.         resultClass = resCls;
  158.         this.allowFailOnInit = allowFailOnInit;
  159.         eventListeners = new EventListenerList();
  160.         updateParameters(params);
  161.     }

  162.     /**
  163.      * {@inheritDoc} This implementation also takes care that the event listener is added to the managed configuration
  164.      * object.
  165.      *
  166.      * @throws IllegalArgumentException if the event type or the listener is <strong>null</strong>
  167.      */
  168.     @Override
  169.     public <E extends Event> void addEventListener(final EventType<E> eventType, final EventListener<? super E> listener) {
  170.         installEventListener(eventType, listener);
  171.     }

  172.     /**
  173.      * Adds the content of the given map to the already existing initialization parameters.
  174.      *
  175.      * @param params the map with additional initialization parameters; may be <strong>null</strong>, then this call has no effect
  176.      * @return a reference to this builder for method chaining
  177.      */
  178.     public synchronized BasicConfigurationBuilder<T> addParameters(final Map<String, Object> params) {
  179.         final Map<String, Object> newParams = new HashMap<>(getParameters());
  180.         if (params != null) {
  181.             newParams.putAll(params);
  182.         }
  183.         updateParameters(newParams);
  184.         return this;
  185.     }

  186.     /**
  187.      * Checks whether the class of the result configuration is compatible with this builder's result class. This is done to
  188.      * ensure that only objects of the expected result class are created.
  189.      *
  190.      * @param inst the result instance to be checked
  191.      * @throws ConfigurationRuntimeException if an invalid result class is detected
  192.      */
  193.     private void checkResultInstance(final Object inst) {
  194.         if (!getResultClass().isInstance(inst)) {
  195.             throw new ConfigurationRuntimeException("Incompatible result object: " + inst);
  196.         }
  197.     }

  198.     /**
  199.      * Appends the content of the specified {@code BuilderParameters} objects to the current initialization parameters.
  200.      * Calling this method multiple times will create a union of the parameters provided.
  201.      *
  202.      * @param params an arbitrary number of objects with builder parameters
  203.      * @return a reference to this builder for method chaining
  204.      * @throws NullPointerException if a <strong>null</strong> array is passed
  205.      */
  206.     public BasicConfigurationBuilder<T> configure(final BuilderParameters... params) {
  207.         final Map<String, Object> newParams = new HashMap<>();
  208.         for (final BuilderParameters p : params) {
  209.             newParams.putAll(p.getParameters());
  210.             handleEventListenerProviders(p);
  211.         }
  212.         return setParameters(newParams);
  213.     }

  214.     /**
  215.      * Connects this builder with a {@code ReloadingController}. With this method support for reloading can be added to an
  216.      * arbitrary builder object. Event listeners are registered at the reloading controller and this builder with connect
  217.      * both objects:
  218.      * <ul>
  219.      * <li>When the reloading controller detects that a reload is required, the builder's {@link #resetResult()} method is
  220.      * called; so the managed result object is invalidated.</li>
  221.      * <li>When a new result object has been created the controller's reloading state is reset, so that new changes can be
  222.      * detected again.</li>
  223.      * </ul>
  224.      *
  225.      * @param controller the {@code ReloadingController} to connect to (must not be <strong>null</strong>)
  226.      * @throws IllegalArgumentException if the controller is <strong>null</strong>
  227.      */
  228.     public final void connectToReloadingController(final ReloadingController controller) {
  229.         if (controller == null) {
  230.             throw new IllegalArgumentException("ReloadingController must not be null!");
  231.         }
  232.         ReloadingBuilderSupportListener.connect(this, controller);
  233.     }

  234.     /**
  235.      * Copies all {@code EventListener} objects registered at this builder to the specified target configuration builder.
  236.      * This method is intended to be used by derived classes which support inheritance of their properties to other builder
  237.      * objects.
  238.      *
  239.      * @param target the target configuration builder (must not be <strong>null</strong>)
  240.      * @throws NullPointerException if the target builder is <strong>null</strong>
  241.      */
  242.     protected synchronized void copyEventListeners(final BasicConfigurationBuilder<?> target) {
  243.         copyEventListeners(target, eventListeners);
  244.     }

  245.     /**
  246.      * Copies all event listeners in the specified list to the specified target configuration builder. This method is
  247.      * intended to be used by derived classes which have to deal with managed configuration builders that need to be
  248.      * initialized with event listeners.
  249.      *
  250.      * @param target the target configuration builder (must not be <strong>null</strong>)
  251.      * @param listeners the event listeners to be copied over
  252.      * @throws NullPointerException if the target builder is <strong>null</strong>
  253.      */
  254.     protected void copyEventListeners(final BasicConfigurationBuilder<?> target, final EventListenerList listeners) {
  255.         target.eventListeners.addAll(listeners);
  256.     }

  257.     /**
  258.      * Creates a new, initialized result object. This method is called by {@code getConfiguration()} if no valid result
  259.      * object exists. This base implementation performs two steps:
  260.      * <ul>
  261.      * <li>{@code createResultInstance()} is called to create a new, uninitialized result object.</li>
  262.      * <li>{@code initResultInstance()} is called to process all initialization parameters.</li>
  263.      * </ul>
  264.      * It also evaluates the <em>allowFailOnInit</em> flag, i.e. if initialization causes an exception and this flag is set,
  265.      * the exception is ignored, and the newly created, uninitialized configuration is returned. Note that this method is
  266.      * called in a synchronized block.
  267.      *
  268.      * @return the newly created result object
  269.      * @throws ConfigurationException if an error occurs
  270.      */
  271.     protected T createResult() throws ConfigurationException {
  272.         final T resObj = createResultInstance();

  273.         try {
  274.             initResultInstance(resObj);
  275.         } catch (final ConfigurationException cex) {
  276.             if (!isAllowFailOnInit()) {
  277.                 throw cex;
  278.             }
  279.         }

  280.         return resObj;
  281.     }

  282.     /**
  283.      * Creates a new {@code BeanDeclaration} which is used for creating new result objects dynamically. This implementation
  284.      * creates a specialized {@code BeanDeclaration} object that is initialized from the given map of initialization
  285.      * parameters. The {@code BeanDeclaration} must be initialized with the result class of this builder, otherwise
  286.      * exceptions will be thrown when the result object is created. Note: This method is invoked in a synchronized block.
  287.      *
  288.      * @param params a snapshot of the current initialization parameters
  289.      * @return the {@code BeanDeclaration} for creating result objects
  290.      * @throws ConfigurationException if an error occurs
  291.      */
  292.     protected BeanDeclaration createResultDeclaration(final Map<String, Object> params) throws ConfigurationException {
  293.         return new BeanDeclaration() {
  294.             @Override
  295.             public String getBeanClassName() {
  296.                 return getResultClass().getName();
  297.             }

  298.             @Override
  299.             public String getBeanFactoryName() {
  300.                 return null;
  301.             }

  302.             @Override
  303.             public Object getBeanFactoryParameter() {
  304.                 return null;
  305.             }

  306.             @Override
  307.             public Map<String, Object> getBeanProperties() {
  308.                 // the properties are equivalent to the parameters
  309.                 return params;
  310.             }

  311.             @Override
  312.             public Collection<ConstructorArg> getConstructorArgs() {
  313.                 // no constructor arguments
  314.                 return Collections.emptySet();
  315.             }

  316.             @Override
  317.             public Map<String, Object> getNestedBeanDeclarations() {
  318.                 // no nested beans
  319.                 return Collections.emptyMap();
  320.             }
  321.         };
  322.     }

  323.     /**
  324.      * Creates the new, uninitialized result object. This is the first step of the process of producing a result object for
  325.      * this builder. This implementation uses the {@link BeanHelper} class to create a new object based on the
  326.      * {@link BeanDeclaration} returned by {@link #getResultDeclaration()}. Note: This method is invoked in a synchronized
  327.      * block.
  328.      *
  329.      * @return the newly created, yet uninitialized result object
  330.      * @throws ConfigurationException if an exception occurs
  331.      */
  332.     protected T createResultInstance() throws ConfigurationException {
  333.         final Object bean = fetchBeanHelper().createBean(getResultDeclaration());
  334.         checkResultInstance(bean);
  335.         return getResultClass().cast(bean);
  336.     }

  337.     /**
  338.      * Obtains the {@code BeanHelper} object to be used when dealing with bean declarations. This method checks whether this
  339.      * builder was configured with a specific {@code BeanHelper} instance. If so, this instance is used. Otherwise, the
  340.      * default {@code BeanHelper} is returned.
  341.      *
  342.      * @return the {@code BeanHelper} to be used
  343.      */
  344.     protected final BeanHelper fetchBeanHelper() {
  345.         final BeanHelper helper = BasicBuilderParameters.fetchBeanHelper(getParameters());
  346.         return helper != null ? helper : BeanHelper.INSTANCE;
  347.     }

  348.     /**
  349.      * Returns an {@code EventSource} for the current result object. If there is no current result or if it does not extend
  350.      * {@code EventSource}, a dummy event source is returned.
  351.      *
  352.      * @return the {@code EventSource} for the current result object
  353.      */
  354.     private EventSource fetchEventSource() {
  355.         return ConfigurationUtils.asEventSource(result, true);
  356.     }

  357.     /**
  358.      * Sends the specified builder event to all registered listeners.
  359.      *
  360.      * @param event the event to be fired
  361.      */
  362.     protected void fireBuilderEvent(final ConfigurationBuilderEvent event) {
  363.         eventListeners.fire(event);
  364.     }

  365.     /**
  366.      * {@inheritDoc} This implementation creates the result configuration on first access. Later invocations return the same
  367.      * object until this builder is reset. The double-check idiom for lazy initialization is used (Bloch, Effective Java,
  368.      * item 71).
  369.      */
  370.     @Override
  371.     public T getConfiguration() throws ConfigurationException {
  372.         fireBuilderEvent(new ConfigurationBuilderEvent(this, ConfigurationBuilderEvent.CONFIGURATION_REQUEST));

  373.         T resObj = result;
  374.         boolean created = false;
  375.         if (resObj == null) {
  376.             synchronized (this) {
  377.                 resObj = result;
  378.                 if (resObj == null) {
  379.                     result = resObj = createResult();
  380.                     created = true;
  381.                 }
  382.             }
  383.         }

  384.         if (created) {
  385.             fireBuilderEvent(new ConfigurationBuilderResultCreatedEvent(this, ConfigurationBuilderResultCreatedEvent.RESULT_CREATED, resObj));
  386.         }
  387.         return resObj;
  388.     }

  389.     /**
  390.      * Gets a map with initialization parameters where all parameters starting with the reserved prefix have been
  391.      * filtered out.
  392.      *
  393.      * @return the filtered parameters map
  394.      */
  395.     private Map<String, Object> getFilteredParameters() {
  396.         final Map<String, Object> filteredMap = new HashMap<>(getParameters());
  397.         filteredMap.keySet().removeIf(key -> key.startsWith(BuilderParameters.RESERVED_PARAMETER_PREFIX));
  398.         return filteredMap;
  399.     }

  400.     /**
  401.      * Gets a (unmodifiable) map with the current initialization parameters set for this builder. The map is populated
  402.      * with the parameters set using the various configuration options.
  403.      *
  404.      * @return a map with the current set of initialization parameters
  405.      */
  406.     protected final synchronized Map<String, Object> getParameters() {
  407.         if (parameters != null) {
  408.             return parameters;
  409.         }
  410.         return Collections.emptyMap();
  411.     }

  412.     /**
  413.      * Gets the result class of this builder. The objects produced by this builder have the class returned here.
  414.      *
  415.      * @return the result class of this builder
  416.      */
  417.     public Class<? extends T> getResultClass() {
  418.         return resultClass;
  419.     }

  420.     /**
  421.      * Gets the {@code BeanDeclaration} that is used to create and initialize result objects. The declaration is created
  422.      * on first access (by invoking {@link #createResultDeclaration(Map)}) based on the current initialization parameters.
  423.      *
  424.      * @return the {@code BeanDeclaration} for dynamically creating a result object
  425.      * @throws ConfigurationException if an error occurs
  426.      */
  427.     protected final synchronized BeanDeclaration getResultDeclaration() throws ConfigurationException {
  428.         if (resultDeclaration == null) {
  429.             resultDeclaration = createResultDeclaration(getFilteredParameters());
  430.         }
  431.         return resultDeclaration;
  432.     }

  433.     /**
  434.      * Checks whether the specified parameters object implements the {@code EventListenerProvider} interface. If so, the
  435.      * event listeners it provides are added to this builder.
  436.      *
  437.      * @param params the parameters object
  438.      */
  439.     private void handleEventListenerProviders(final BuilderParameters params) {
  440.         if (params instanceof EventListenerProvider) {
  441.             eventListeners.addAll(((EventListenerProvider) params).getListeners());
  442.         }
  443.     }

  444.     /**
  445.      * Performs special initialization of the result object. This method is called after parameters have been set on a newly
  446.      * created result instance. If supported by the result class, the {@code initialize()} method is now called.
  447.      *
  448.      * @param obj the newly created result object
  449.      */
  450.     private void handleInitializable(final T obj) {
  451.         if (obj instanceof Initializable) {
  452.             ((Initializable) obj).initialize();
  453.         }
  454.     }

  455.     /**
  456.      * Initializes a newly created result object. This is the second step of the process of producing a result object for
  457.      * this builder. This implementation uses the {@link BeanHelper} class to initialize the object's property based on the
  458.      * {@link BeanDeclaration} returned by {@link #getResultDeclaration()}. Note: This method is invoked in a synchronized
  459.      * block. This is required because internal state is accessed. Sub classes must not call this method without proper
  460.      * synchronization.
  461.      *
  462.      * @param obj the object to be initialized
  463.      * @throws ConfigurationException if an error occurs
  464.      */
  465.     protected void initResultInstance(final T obj) throws ConfigurationException {
  466.         fetchBeanHelper().initBean(obj, getResultDeclaration());
  467.         registerEventListeners(obj);
  468.         handleInitializable(obj);
  469.     }

  470.     /**
  471.      * Adds the specified event listener to this object. This method is called by {@code addEventListener()}, it does the
  472.      * actual listener registration. Because it is final it can be called by sub classes in the constructor if there is
  473.      * already the need to register an event listener.
  474.      *
  475.      * @param eventType the event type object
  476.      * @param listener the listener to be registered
  477.      * @param <E> the event type
  478.      */
  479.     protected final <E extends Event> void installEventListener(final EventType<E> eventType, final EventListener<? super E> listener) {
  480.         fetchEventSource().addEventListener(eventType, listener);
  481.         eventListeners.addEventListener(eventType, listener);
  482.     }

  483.     /**
  484.      * Returns the <em>allowFailOnInit</em> flag. See the header comment for information about this flag.
  485.      *
  486.      * @return the <em>allowFailOnInit</em> flag
  487.      */
  488.     public boolean isAllowFailOnInit() {
  489.         return allowFailOnInit;
  490.     }

  491.     /**
  492.      * Registers the available event listeners at the given object. This method is called for each result object created by
  493.      * the builder.
  494.      *
  495.      * @param obj the object to initialize
  496.      */
  497.     private void registerEventListeners(final T obj) {
  498.         final EventSource evSrc = ConfigurationUtils.asEventSource(obj, true);
  499.         eventListeners.getRegistrations().forEach(regData -> registerListener(evSrc, regData));
  500.     }

  501.     /**
  502.      * {@inheritDoc} This implementation also takes care that the event listener is removed from the managed configuration
  503.      * object.
  504.      */
  505.     @Override
  506.     public <E extends Event> boolean removeEventListener(final EventType<E> eventType, final EventListener<? super E> listener) {
  507.         fetchEventSource().removeEventListener(eventType, listener);
  508.         return eventListeners.removeEventListener(eventType, listener);
  509.     }

  510.     /**
  511.      * Removes all available event listeners from the given result object. This method is called when the result of this
  512.      * builder is reset. Then the old managed configuration should no longer generate events.
  513.      *
  514.      * @param obj the affected result object
  515.      */
  516.     private void removeEventListeners(final T obj) {
  517.         final EventSource evSrc = ConfigurationUtils.asEventSource(obj, true);
  518.         eventListeners.getRegistrations().forEach(regData -> removeListener(evSrc, regData));
  519.     }

  520.     /**
  521.      * Resets this builder. This is a convenience method which combines calls to {@link #resetResult()} and
  522.      * {@link #resetParameters()}.
  523.      */
  524.     public synchronized void reset() {
  525.         resetParameters();
  526.         resetResult();
  527.     }

  528.     /**
  529.      * Removes all initialization parameters of this builder. This method can be called if this builder is to be reused for
  530.      * creating result objects with a different configuration.
  531.      */
  532.     public void resetParameters() {
  533.         setParameters(null);
  534.     }

  535.     /**
  536.      * Clears an existing result object. An invocation of this method causes a new {@code ImmutableConfiguration} object to
  537.      * be created the next time {@link #getConfiguration()} is called.
  538.      */
  539.     public void resetResult() {
  540.         final T oldResult;
  541.         synchronized (this) {
  542.             oldResult = result;
  543.             result = null;
  544.             resultDeclaration = null;
  545.         }

  546.         if (oldResult != null) {
  547.             removeEventListeners(oldResult);
  548.         }
  549.         fireBuilderEvent(new ConfigurationBuilderEvent(this, ConfigurationBuilderEvent.RESET));
  550.     }

  551.     /**
  552.      * Sets the initialization parameters of this builder. Already existing parameters are replaced by the content of the
  553.      * given map.
  554.      *
  555.      * @param params the new initialization parameters of this builder; can be <strong>null</strong>, then all initialization
  556.      *        parameters are removed
  557.      * @return a reference to this builder for method chaining
  558.      */
  559.     public synchronized BasicConfigurationBuilder<T> setParameters(final Map<String, Object> params) {
  560.         updateParameters(params);
  561.         return this;
  562.     }

  563.     /**
  564.      * Replaces the current map with parameters by a new one.
  565.      *
  566.      * @param newParams the map with new parameters (may be <strong>null</strong>)
  567.      */
  568.     private void updateParameters(final Map<String, Object> newParams) {
  569.         final Map<String, Object> map = new HashMap<>();
  570.         if (newParams != null) {
  571.             map.putAll(newParams);
  572.         }
  573.         parameters = Collections.unmodifiableMap(map);
  574.     }
  575. }