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