    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.io;
    018
    019import java.net.URL;
    020import java.util.Objects;
    021
    022/**
    023 * <p>
    024 * A class describing the location of a file.
    025 * </p>
    026 * <p>
    027 * An instance of this class provides information for locating and accessing a file. The file location can be defined
    028 * </p>
    029 * <ul>
    030 * <li>as a URL; this identifies a file in a unique way</li>
    031 * <li>as a combination of base path and file name; if this variant is used, there may be an additional location step
    032 * required in order to identify the referenced file (for instance, the file name may be interpreted as the name of a
    033 * resource to be loaded from class path).</li>
    034 * </ul>
    035 * <p>
    036 * In addition, other properties are available which are also needed for loading or saving a file, like the underlying
    037 * {@link FileSystem}. The encoding to be used when accessing the represented data is also part of the data contained in
    038 * an instance; if no encoding is set explicitly, the platform's default encoding is used.
    039 * <p>
    040 * Instances of this class are immutable and thus can be safely shared between arbitrary components. {@link FileHandler}
    041 * also uses an instance to reference the associated file. Instances are created using a <em>builder</em>.
    042 * {@link FileLocatorUtils} offers convenience methods for obtaining such a builder.
    043 * </p>
    044 *
    045 * @since 2.0
    046 */
    047public final class FileLocator {
    048
    049    /**
    050     * A typical <em>builder</em> implementation for creating {@code FileLocator} objects. An instance of this class is
    051     * returned by the {@code fileLocator()} method of {link FileLocatorUtils}. It can be used to define the various
    052     * components of the {@code FileLocator} object. By calling {@code create()} the new immutable {@code FileLocator}
    053     * instance is created.
    054     */
    055    public static final class FileLocatorBuilder {
    056
    057        /** The base path. */
    058        private String basePath;
    059
    060        /** The encoding. */
    061        private String encoding;
    062
    063        /** The file name. */
    064        private String fileName;
    065
    066        /** The file system. */
    067        private FileSystem fileSystem;
    068
    069        /** The location strategy. */
    070        private FileLocationStrategy locationStrategy;
    071
    072        /** The URL. */
    073        private URL sourceURL;
    074
    075        /** The URL connection options. */
    076        private URLConnectionOptions urlConnectionOptions;
    077
    078        /**
    079         * Creates a new instance of {@code FileLocatorBuilder} and initializes the builder's properties from the passed in
    080         * {@code FileLocator} object.
    081         *
    082         * @param src the source {@code FileLocator} (may be <strong>null</strong>)
    083         */
    084        FileLocatorBuilder(final FileLocator src) {
    085            if (src != null) {
    086                initBuilder(src);
    087            }
    088        }
    089
    090        /**
    091         * Specifies the base path of the new {@code FileLocator}.
    092         *
    093         * @param path the base path
    094         * @return a reference to this builder for method chaining
    095         */
    096        public FileLocatorBuilder basePath(final String path) {
    097            basePath = path;
    098            return this;
    099        }
    100
    101        /**
    102         * Creates a new immutable {@code FileLocatorImpl} object based on the properties set so far for this builder.
    103         *
    104         * @return the newly created {@code FileLocator} object, never null.
    105         */
    106        public FileLocator create() {
    107            return new FileLocator(this);
    108        }
    109
    110        /**
    111         * Specifies the encoding of the new {@code FileLocator}.
    112         *
    113         * @param enc the encoding
    114         * @return a reference to this builder for method chaining
    115         */
    116        public FileLocatorBuilder encoding(final String enc) {
    117            encoding = enc;
    118            return this;
    119        }
    120
    121        /**
    122         * Specifies the file name of the new {@code FileLocator}.
    123         *
    124         * @param name the file name
    125         * @return a reference to this builder for method chaining
    126         */
    127        public FileLocatorBuilder fileName(final String name) {
    128            fileName = name;
    129            return this;
    130        }
    131
    132        /**
    133         * Specifies the {@code FileSystem} of the new {@code FileLocator}.
    134         *
    135         * @param fs the {@code FileSystem}
    136         * @return a reference to this builder for method chaining
    137         */
    138        public FileLocatorBuilder fileSystem(final FileSystem fs) {
    139            fileSystem = fs;
    140            return this;
    141        }
    142
    143        /**
    144         * Initializes the properties of this builder from the passed in locator object.
    145         *
    146         * @param src the source {@code FileLocator}
    147         */
    148        private void initBuilder(final FileLocator src) {
    149            basePath = src.getBasePath();
    150            fileName = src.getFileName();
    151            sourceURL = src.getSourceURL();
    152            urlConnectionOptions = src.getURLConnectionOptions();
    153            encoding = src.getEncoding();
    154            fileSystem = src.getFileSystem();
    155            locationStrategy = src.getLocationStrategy();
    156        }
    157
    158        /**
    159         * Specifies the {@code FileLocationStrategy} to be used when the referenced file is to be located.
    160         *
    161         * @param strategy the {@code FileLocationStrategy}
    162         * @return a reference to this builder for method chaining
    163         */
    164        public FileLocatorBuilder locationStrategy(final FileLocationStrategy strategy) {
    165            locationStrategy = strategy;
    166            return this;
    167        }
    168
    169        /**
    170         * Specifies the source URL of the new {@code FileLocator}.
    171         *
    172         * @param url the source URL
    173         * @return a reference to this builder for method chaining
    174         */
    175        public FileLocatorBuilder sourceURL(final URL url) {
    176            this.sourceURL = url;
    177            return this;
    178        }
    179
    180        /**
    181         * Specifies the source URL connection options of the new {@code FileLocator}.
    182         *
    183         * @param urlConnectionOptions the source URL connection options.
    184         * @return a reference to this builder for method chaining
    185         */
    186        public FileLocatorBuilder urlConnectionOptions(final URLConnectionOptions urlConnectionOptions) {
    187            this.urlConnectionOptions = urlConnectionOptions;
    188            return this;
    189
    190        }
    191    }
    192
    193    /** The base path. */
    194    private final String basePath;
    195
    196    /** The encoding. */
    197    private final String encoding;
    198
    199    /** The file name. */
    200    private final String fileName;
    201
    202    /** The file system. */
    203    private final FileSystem fileSystem;
    204
    205    /** The file location strategy. */
    206    private final FileLocationStrategy locationStrategy;
    207
    208    /** The source URL. */
    209    private final URL sourceURL;
    210
    211    /** The source URL connection options. */
    212    private final URLConnectionOptions urlConnectionOptions;
    213
    214    /**
    215     * Creates a new instance of {@code FileLocatorImpl} and initializes it from the given builder instance
    216     *
    217     * @param builder the builder
    218     */
    219    public FileLocator(final FileLocatorBuilder builder) {
    220        fileName = builder.fileName;
    221        basePath = builder.basePath;
    222        sourceURL = builder.sourceURL;
    223        urlConnectionOptions = builder.urlConnectionOptions;
    224        encoding = builder.encoding;
    225        fileSystem = builder.fileSystem;
    226        locationStrategy = builder.locationStrategy;
    227    }
    228
    229    /**
    230     * Compares this object with another one. Two instances of {@code FileLocatorImpl} are considered equal if all of their
    231     * properties are equal.
    232     *
    233     * @param obj the object to compare to
    234     * @return a flag whether these objects are equal
    235     */
    236    @Override
    237    public boolean equals(final Object obj) {
    238        if (this == obj) {
    239            return true;
    240        }
    241        if (!(obj instanceof FileLocator)) {
    242            return false;
    243        }
    244        final FileLocator other = (FileLocator) obj;
    245        return Objects.equals(basePath, other.basePath) && Objects.equals(encoding, other.encoding) && Objects.equals(fileName, other.fileName)
    246            && Objects.equals(fileSystem, other.fileSystem) && Objects.equals(locationStrategy, other.locationStrategy)
    247            && Objects.equals(sourceURL, other.sourceURL) && Objects.equals(urlConnectionOptions, other.urlConnectionOptions);
    248    }
    249
    250    /**
    251     * Gets the base path stored in this locator or <strong>null</strong> if it is undefined.
    252     *
    253     * @return the base path
    254     */
    255    public String getBasePath() {
    256        return basePath;
    257    }
    258
    259    /**
    260     * Gets the encoding stored in this locator or <strong>null</strong> if it is undefined.
    261     *
    262     * @return the encoding
    263     */
    264    public String getEncoding() {
    265        return encoding;
    266    }
    267
    268    /**
    269     * Gets the file name stored in this locator or <strong>null</strong> if it is undefined.
    270     *
    271     * @return the file name
    272     */
    273    public String getFileName() {
    274        return fileName;
    275    }
    276
    277    /**
    278     * Gets the {@code FileSystem} to be used for accessing the file referenced by this locator or <strong>null</strong> if it is
    279     * undefined.
    280     *
    281     * @return the {@code FileSystem}
    282     */
    283    public FileSystem getFileSystem() {
    284        return fileSystem;
    285    }
    286
    287    /**
    288     * Gets the {@code FileLocationStrategy} to be used for locating the referenced file. If no specific
    289     * {@code FileLocationStrategy} has been set, result is <strong>null</strong>. This means that the default strategy should be
    290     * used.
    291     *
    292     * @return the {@code FileLocationStrategy} to be used
    293     */
    294    public FileLocationStrategy getLocationStrategy() {
    295        return locationStrategy;
    296    }
    297
    298    /**
    299     * Gets the URL pointing to the referenced source file or <strong>null</strong> if it is undefined.
    300     *
    301     * @return the source URL
    302     */
    303    public URL getSourceURL() {
    304        return sourceURL;
    305    }
    306
    307    /**
    308     * Gets the URLConnectionOptions
    309     *
    310     * @return the URLConnectionOptions
    311     */
    312    public URLConnectionOptions getURLConnectionOptions() {
    313        return urlConnectionOptions;
    314    }
    315
    316    /**
    317     * Returns a hash code for this object.
    318     *
    319     * @return a hash code for this object
    320     */
    321    @Override
    322    public int hashCode() {
    323        return Objects.hash(basePath, encoding, fileName, fileSystem, locationStrategy, sourceURL, urlConnectionOptions);
    324    }
    325
    326    @Override
    327    public String toString() {
    328        return "FileLocator [basePath=" + basePath + ", encoding=" + encoding + ", fileName=" + fileName + ", fileSystem=" + fileSystem + ", locationStrategy="
    329            + locationStrategy + ", sourceURL=" + sourceURL + ", urlConnectionOptions=" + urlConnectionOptions + "]";
    330    }
    331}