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;
018
019import java.io.File;
020import java.net.URL;
021import java.util.Map;
022
023import org.apache.commons.configuration2.io.FileHandler;
024import org.apache.commons.configuration2.io.FileLocationStrategy;
025import org.apache.commons.configuration2.io.FileSystem;
026
027/**
028 * <p>
029 * An implementation of {@code BuilderParameters} which contains parameters
030 * related to {@code Configuration} implementations that are loaded from files.
031 * </p>
032 * <p>
033 * The parameters defined here are interpreted by builder implementations that
034 * can deal with file-based configurations. Note that these parameters are
035 * typically no initialization properties of configuration objects (i.e. they
036 * are not passed to set methods after the creation of the result
037 * configuration). Rather, the parameters object is stored as a whole in the
038 * builder's map with initialization parameters and can be accessed from there.
039 * </p>
040 * <p>
041 * This class is not thread-safe. It is intended that an instance is constructed
042 * and initialized by a single thread during configuration of a
043 * {@code ConfigurationBuilder}.
044 * </p>
045 *
046 * @since 2.0
047 */
048public class FileBasedBuilderParametersImpl extends BasicBuilderParameters
049        implements FileBasedBuilderProperties<FileBasedBuilderParametersImpl>
050{
051    /** Constant for the key in the parameters map used by this class. */
052    private static final String PARAM_KEY = RESERVED_PARAMETER_PREFIX
053            + "fileBased";
054
055    /** Property name for the reloading refresh delay. */
056    private static final String PROP_REFRESH_DELAY = "reloadingRefreshDelay";
057
058    /** Property name of the reloading detector factory. */
059    private static final String PROP_DETECTOR_FACTORY =
060            "reloadingDetectorFactory";
061
062    /**
063     * Stores the associated file handler for the location of the configuration.
064     */
065    private FileHandler fileHandler;
066
067    /** The factory for reloading detectors. */
068    private ReloadingDetectorFactory reloadingDetectorFactory;
069
070    /** The refresh delay for reloading support. */
071    private Long reloadingRefreshDelay;
072
073    /**
074     * Creates a new instance of {@code FileBasedBuilderParametersImpl} with an
075     * uninitialized {@code FileHandler} object.
076     */
077    public FileBasedBuilderParametersImpl()
078    {
079        this(null);
080    }
081
082    /**
083     * Creates a new instance of {@code FileBasedBuilderParametersImpl} and
084     * associates it with the given {@code FileHandler} object. If the handler
085     * is <b>null</b>, a new handler instance is created.
086     *
087     * @param handler the associated {@code FileHandler} (can be <b>null</b>)
088     */
089    public FileBasedBuilderParametersImpl(final FileHandler handler)
090    {
091        fileHandler = handler != null ? handler : new FileHandler();
092    }
093
094    /**
095     * Looks up an instance of this class in the specified parameters map. This
096     * is equivalent to {@code fromParameters(params, false};}
097     *
098     * @param params the map with parameters (must not be <b>null</b>
099     * @return the instance obtained from the map or <b>null</b>
100     * @throws IllegalArgumentException if the map is <b>null</b>
101     */
102    public static FileBasedBuilderParametersImpl fromParameters(
103            final Map<String, ?> params)
104    {
105        return fromParameters(params, false);
106    }
107
108    /**
109     * Looks up an instance of this class in the specified parameters map and
110     * optionally creates a new one if none is found. This method can be used to
111     * obtain an instance of this class which has been stored in a parameters
112     * map. It is compatible with the {@code getParameters()} method.
113     *
114     * @param params the map with parameters (must not be <b>null</b>
115     * @param createIfMissing determines the behavior if no instance is found in
116     *        the map; if <b>true</b>, a new instance with default settings is
117     *        created; if <b>false</b>, <b>null</b> is returned
118     * @return the instance obtained from the map or <b>null</b>
119     * @throws IllegalArgumentException if the map is <b>null</b>
120     */
121    public static FileBasedBuilderParametersImpl fromParameters(
122            final Map<String, ?> params, final boolean createIfMissing)
123    {
124        if (params == null)
125        {
126            throw new IllegalArgumentException(
127                    "Parameters map must not be null!");
128        }
129
130        FileBasedBuilderParametersImpl instance =
131                (FileBasedBuilderParametersImpl) params.get(PARAM_KEY);
132        if (instance == null && createIfMissing)
133        {
134            instance = new FileBasedBuilderParametersImpl();
135        }
136        return instance;
137    }
138
139    /**
140     * Creates a new {@code FileBasedBuilderParametersImpl} object from the
141     * content of the given map. While {@code fromParameters()} expects that an
142     * object already exists and is stored in the given map, this method creates
143     * a new instance based on the content of the map. The map can contain
144     * properties of a {@code FileHandler} and some additional settings which
145     * are stored directly in the newly created object. If the map is
146     * <b>null</b>, an uninitialized instance is returned.
147     *
148     * @param map the map with properties (must not be <b>null</b>)
149     * @return the newly created instance
150     * @throws ClassCastException if the map contains invalid data
151     */
152    public static FileBasedBuilderParametersImpl fromMap(final Map<String, ?> map)
153    {
154        final FileBasedBuilderParametersImpl params =
155                new FileBasedBuilderParametersImpl(FileHandler.fromMap(map));
156        if (map != null)
157        {
158            params.setReloadingRefreshDelay((Long) map.get(PROP_REFRESH_DELAY));
159            params.setReloadingDetectorFactory((ReloadingDetectorFactory) map
160                    .get(PROP_DETECTOR_FACTORY));
161        }
162        return params;
163    }
164
165    /**
166     * {@inheritDoc} This implementation takes some properties defined in this
167     * class into account.
168     */
169    @Override
170    public void inheritFrom(final Map<String, ?> source)
171    {
172        super.inheritFrom(source);
173
174        final FileBasedBuilderParametersImpl srcParams = fromParameters(source);
175        if (srcParams != null)
176        {
177            setFileSystem(srcParams.getFileHandler().getFileSystem());
178            setLocationStrategy(
179                    srcParams.getFileHandler().getLocationStrategy());
180            if (srcParams.getFileHandler().getEncoding() != null)
181            {
182                setEncoding(srcParams.getFileHandler().getEncoding());
183            }
184            if (srcParams.getReloadingDetectorFactory() != null)
185            {
186                setReloadingDetectorFactory(
187                        srcParams.getReloadingDetectorFactory());
188            }
189            if (srcParams.getReloadingRefreshDelay() != null)
190            {
191                setReloadingRefreshDelay(srcParams.getReloadingRefreshDelay());
192            }
193        }
194    }
195
196    /**
197     * Returns the {@code FileHandler} managed by this object. This object is
198     * updated every time the file location is changed.
199     *
200     * @return the managed {@code FileHandler}
201     */
202    public FileHandler getFileHandler()
203    {
204        return fileHandler;
205    }
206
207    /**
208     * Returns the refresh delay for reload operations. Result may be
209     * <b>null</b> if this value has not been set.
210     *
211     * @return the reloading refresh delay
212     */
213    public Long getReloadingRefreshDelay()
214    {
215        return reloadingRefreshDelay;
216    }
217
218    @Override
219    public FileBasedBuilderParametersImpl setReloadingRefreshDelay(
220            final Long reloadingRefreshDelay)
221    {
222        this.reloadingRefreshDelay = reloadingRefreshDelay;
223        return this;
224    }
225
226    /**
227     * Returns the {@code ReloadingDetectorFactory}. Result may be <b>null</b>
228     * which means that the default factory is to be used.
229     *
230     * @return the {@code ReloadingDetectorFactory}
231     */
232    public ReloadingDetectorFactory getReloadingDetectorFactory()
233    {
234        return reloadingDetectorFactory;
235    }
236
237    @Override
238    public FileBasedBuilderParametersImpl setReloadingDetectorFactory(
239            final ReloadingDetectorFactory reloadingDetectorFactory)
240    {
241        this.reloadingDetectorFactory = reloadingDetectorFactory;
242        return this;
243    }
244
245    @Override
246    public FileBasedBuilderParametersImpl setFile(final File file)
247    {
248        getFileHandler().setFile(file);
249        return this;
250    }
251
252    @Override
253    public FileBasedBuilderParametersImpl setURL(final URL url)
254    {
255        getFileHandler().setURL(url);
256        return this;
257    }
258
259    @Override
260    public FileBasedBuilderParametersImpl setPath(final String path)
261    {
262        getFileHandler().setPath(path);
263        return this;
264    }
265
266    @Override
267    public FileBasedBuilderParametersImpl setFileName(final String name)
268    {
269        getFileHandler().setFileName(name);
270        return this;
271    }
272
273    @Override
274    public FileBasedBuilderParametersImpl setBasePath(final String path)
275    {
276        getFileHandler().setBasePath(path);
277        return this;
278    }
279
280    @Override
281    public FileBasedBuilderParametersImpl setFileSystem(final FileSystem fs)
282    {
283        getFileHandler().setFileSystem(fs);
284        return this;
285    }
286
287    @Override
288    public FileBasedBuilderParametersImpl setLocationStrategy(
289            final FileLocationStrategy strategy)
290    {
291        getFileHandler().setLocationStrategy(strategy);
292        return this;
293    }
294
295    @Override
296    public FileBasedBuilderParametersImpl setEncoding(final String enc)
297    {
298        getFileHandler().setEncoding(enc);
299        return this;
300    }
301
302    /**
303     * {@inheritDoc} This implementation returns a map which contains this
304     * object itself under a specific key. The static {@code fromParameters()}
305     * method can be used to extract an instance from a parameters map. Of
306     * course, the properties inherited from the base class are also added to
307     * the result map.
308     */
309    @Override
310    public Map<String, Object> getParameters()
311    {
312        final Map<String, Object> params = super.getParameters();
313        params.put(PARAM_KEY, this);
314        return params;
315    }
316
317    /**
318     * {@inheritDoc} This implementation also creates a copy of the
319     * {@code FileHandler}.
320     */
321    @Override
322    public FileBasedBuilderParametersImpl clone()
323    {
324        final FileBasedBuilderParametersImpl copy =
325                (FileBasedBuilderParametersImpl) super.clone();
326        copy.fileHandler =
327                new FileHandler(fileHandler.getContent(), fileHandler);
328        return copy;
329    }
330}