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