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