    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 *     https://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
    048    /** Constant for the key in the parameters map used by this class. */
    049    private static final String PARAM_KEY = RESERVED_PARAMETER_PREFIX + "fileBased";
    050
    051    /** Property name for the reloading refresh delay. */
    052    private static final String PROP_REFRESH_DELAY = "reloadingRefreshDelay";
    053
    054    /** Property name of the reloading detector factory. */
    055    private static final String PROP_DETECTOR_FACTORY = "reloadingDetectorFactory";
    056
    057    /**
    058     * Creates a new {@code FileBasedBuilderParametersImpl} object from the content of the given map. While
    059     * {@code fromParameters()} expects that an object already exists and is stored in the given map, this method creates a
    060     * new instance based on the content of the map. The map can contain properties of a {@code FileHandler} and some
    061     * additional settings which are stored directly in the newly created object. If the map is <strong>null</strong>, an
    062     * uninitialized instance is returned.
    063     *
    064     * @param map the map with properties (must not be <strong>null</strong>)
    065     * @return the newly created instance
    066     * @throws ClassCastException if the map contains invalid data
    067     */
    068    public static FileBasedBuilderParametersImpl fromMap(final Map<String, ?> map) {
    069        final FileBasedBuilderParametersImpl params = new FileBasedBuilderParametersImpl(FileHandler.fromMap(map));
    070        if (map != null) {
    071            params.setReloadingRefreshDelay((Long) map.get(PROP_REFRESH_DELAY));
    072            params.setReloadingDetectorFactory((ReloadingDetectorFactory) map.get(PROP_DETECTOR_FACTORY));
    073        }
    074        return params;
    075    }
    076
    077    /**
    078     * Looks up an instance of this class in the specified parameters map. This is equivalent to
    079     * {@code fromParameters(params, false};}
    080     *
    081     * @param params the map with parameters (must not be <strong>null</strong>
    082     * @return the instance obtained from the map or <strong>null</strong>
    083     * @throws IllegalArgumentException if the map is <strong>null</strong>
    084     */
    085    public static FileBasedBuilderParametersImpl fromParameters(final Map<String, ?> params) {
    086        return fromParameters(params, false);
    087    }
    088
    089    /**
    090     * Looks up an instance of this class in the specified parameters map and optionally creates a new one if none is found.
    091     * This method can be used to obtain an instance of this class which has been stored in a parameters map. It is
    092     * compatible with the {@code getParameters()} method.
    093     *
    094     * @param params the map with parameters (must not be <strong>null</strong>
    095     * @param createIfMissing determines the behavior if no instance is found in the map; if <strong>true</strong>, a new instance
    096     *        with default settings is created; if <strong>false</strong>, <strong>null</strong> is returned
    097     * @return the instance obtained from the map or <strong>null</strong>
    098     * @throws IllegalArgumentException if the map is <strong>null</strong>
    099     */
    100    public static FileBasedBuilderParametersImpl fromParameters(final Map<String, ?> params, final boolean createIfMissing) {
    101        if (params == null) {
    102            throw new IllegalArgumentException("Parameters map must not be null.");
    103        }
    104
    105        FileBasedBuilderParametersImpl instance = (FileBasedBuilderParametersImpl) params.get(PARAM_KEY);
    106        if (instance == null && createIfMissing) {
    107            instance = new FileBasedBuilderParametersImpl();
    108        }
    109        return instance;
    110    }
    111
    112    /**
    113     * Stores the associated file handler for the location of the configuration.
    114     */
    115    private FileHandler fileHandler;
    116
    117    /** The factory for reloading detectors. */
    118    private ReloadingDetectorFactory reloadingDetectorFactory;
    119
    120    /** The refresh delay for reloading support. */
    121    private Long reloadingRefreshDelay;
    122
    123    /**
    124     * Creates a new instance of {@code FileBasedBuilderParametersImpl} with an uninitialized {@code FileHandler} object.
    125     */
    126    public FileBasedBuilderParametersImpl() {
    127        this(null);
    128    }
    129
    130    /**
    131     * Creates a new instance of {@code FileBasedBuilderParametersImpl} and associates it with the given {@code FileHandler}
    132     * object. If the handler is <strong>null</strong>, a new handler instance is created.
    133     *
    134     * @param handler the associated {@code FileHandler} (can be <strong>null</strong>)
    135     */
    136    public FileBasedBuilderParametersImpl(final FileHandler handler) {
    137        fileHandler = handler != null ? handler : new FileHandler();
    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 <strong>null</strong> 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 <strong>null</strong> 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}