001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *     http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.commons.configuration2.builder.combined;
018
019import java.util.ArrayList;
020import java.util.Collection;
021import java.util.Collections;
022import java.util.Map;
023import java.util.Set;
024
025import org.apache.commons.configuration2.FileBasedConfiguration;
026import org.apache.commons.configuration2.builder.FileBasedConfigurationBuilder;
027import org.apache.commons.configuration2.builder.ReloadingFileBasedConfigurationBuilder;
028import org.apache.commons.configuration2.ex.ConfigurationException;
029import org.apache.commons.configuration2.reloading.CombinedReloadingController;
030import org.apache.commons.configuration2.reloading.ReloadingController;
031import org.apache.commons.configuration2.reloading.ReloadingControllerSupport;
032
033/**
034 * <p>
035 * A specialized {@code MultiFileConfigurationBuilder} implementation which adds
036 * support for reloading.
037 * </p>
038 * <p>
039 * This class - as its super class - allows operating on multiple configuration
040 * files whose file names are determined using a file name pattern and a
041 * {@code ConfigurationInterpolator} object. It provides the following
042 * additional features:
043 * </p>
044 * <ul>
045 * <li>Configuration builder for managed configurations have reloading support.
046 * So reloading is possible for all configuration sources loaded by this builder
047 * instance.</li>
048 * <li>A {@link ReloadingController} is provided which can be used to trigger
049 * reload checks on all managed configurations.</li>
050 * </ul>
051 * <p>
052 * Although this builder manages an arbitrary number of child configurations, to
053 * clients only a single configuration is visible - the one selected by the
054 * evaluation of the file name pattern. Builder reset notifications triggered by
055 * the reloading mechanism do not really take this fact into account; they are
056 * not limited to the currently selected child configuration, but occur for each
057 * of the managed configuration.
058 * </p>
059 *
060 * @since 2.0
061 * @param <T> the concrete type of {@code Configuration} objects created by this
062 *        builder
063 */
064public class ReloadingMultiFileConfigurationBuilder<T extends FileBasedConfiguration>
065        extends MultiFileConfigurationBuilder<T> implements
066        ReloadingControllerSupport
067{
068    /** The reloading controller used by this builder. */
069    private final ReloadingController reloadingController =
070            createReloadingController();
071
072    /**
073     * Creates a new instance of {@code ReloadingMultiFileConfigurationBuilder}
074     * and sets initialization parameters and a flag whether initialization
075     * failures should be ignored.
076     *
077     * @param resCls the result configuration class
078     * @param params a map with initialization parameters
079     * @param allowFailOnInit a flag whether initialization errors should be
080     *        ignored
081     * @throws IllegalArgumentException if the result class is <b>null</b>
082     */
083    public ReloadingMultiFileConfigurationBuilder(final Class<T> resCls,
084            final Map<String, Object> params, final boolean allowFailOnInit)
085    {
086        super(resCls, params, allowFailOnInit);
087    }
088
089    /**
090     * Creates a new instance of {@code ReloadingMultiFileConfigurationBuilder}
091     * and sets initialization parameters.
092     *
093     * @param resCls the result configuration class
094     * @param params a map with initialization parameters
095     * @throws IllegalArgumentException if the result class is <b>null</b>
096     */
097    public ReloadingMultiFileConfigurationBuilder(final Class<T> resCls,
098            final Map<String, Object> params)
099    {
100        super(resCls, params);
101    }
102
103    /**
104     * Creates a new instance of {@code ReloadingMultiFileConfigurationBuilder}
105     * without setting initialization parameters.
106     *
107     * @param resCls the result configuration class
108     * @throws IllegalArgumentException if the result class is <b>null</b>
109     */
110    public ReloadingMultiFileConfigurationBuilder(final Class<T> resCls)
111    {
112        super(resCls);
113    }
114
115    /**
116     * {@inheritDoc} This implementation returns a special
117     * {@code ReloadingController} that delegates to the reloading controllers
118     * of the managed builders created so far.
119     */
120    @Override
121    public ReloadingController getReloadingController()
122    {
123        return reloadingController;
124    }
125
126    /**
127     * {@inheritDoc} This implementation returns a file-based configuration
128     * builder with reloading support.
129     */
130    @Override
131    protected FileBasedConfigurationBuilder<T> createManagedBuilder(
132            final String fileName, final Map<String, Object> params)
133            throws ConfigurationException
134    {
135        return new ReloadingFileBasedConfigurationBuilder<>(getResultClass(),
136                params, isAllowFailOnInit());
137    }
138
139    /**
140     * Creates the reloading controller used by this builder. This method
141     * creates a specialized {@link CombinedReloadingController} which operates
142     * on the reloading controllers of the managed builders created so far.
143     *
144     * @return the newly created {@code ReloadingController}
145     */
146    private ReloadingController createReloadingController()
147    {
148        final Set<ReloadingController> empty = Collections.emptySet();
149        return new CombinedReloadingController(empty)
150        {
151            @Override
152            public Collection<ReloadingController> getSubControllers()
153            {
154                final Collection<FileBasedConfigurationBuilder<T>> builders =
155                        getManagedBuilders().values();
156                final Collection<ReloadingController> controllers =
157                        new ArrayList<>(builders.size());
158                for (final FileBasedConfigurationBuilder<T> b : builders)
159                {
160                    controllers.add(((ReloadingControllerSupport) b)
161                            .getReloadingController());
162                }
163                return controllers;
164            }
165        };
166    }
167}