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