    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 */
    017
    018package org.apache.commons.collections4.properties;
    019
    020import java.io.File;
    021import java.io.FileInputStream;
    022import java.io.FileNotFoundException;
    023import java.io.IOException;
    024import java.io.InputStream;
    025import java.io.Reader;
    026import java.net.URI;
    027import java.net.URL;
    028import java.nio.file.Files;
    029import java.nio.file.Path;
    030import java.nio.file.Paths;
    031import java.util.Objects;
    032import java.util.Properties;
    033
    034/**
    035 * Subclasses create and load {@link Properties} and subclasses of {@link Properties} like {@link SortedProperties}.
    036 *
    037 * @param <T> {@link Properties} or a subclass like {@link SortedProperties}.
    038 * @see Properties
    039 * @since 4.4
    040 */
    041public abstract class AbstractPropertiesFactory<T extends Properties> {
    042
    043    /**
    044     * Enumerates property formats.
    045     *
    046     * @since 4.5.0-M1
    047     */
    048    public enum PropertyFormat {
    049
    050        /** Properties file format. */
    051        PROPERTIES,
    052
    053        /** XML file format. */
    054        XML;
    055
    056        static PropertyFormat toPropertyFormat(final String fileName) {
    057            return Objects.requireNonNull(fileName, "fileName").endsWith(".xml") ? XML : PROPERTIES;
    058        }
    059    }
    060
    061    /**
    062     * Constructs an instance.
    063     */
    064    protected AbstractPropertiesFactory() {
    065        // no init.
    066    }
    067
    068    /**
    069     * Subclasses override to provide customized properties instances.
    070     *
    071     * @return a new Properties instance.
    072     */
    073    protected abstract T createProperties();
    074
    075    /**
    076     * Creates and loads properties from the given file.
    077     *
    078     * @param classLoader the class loader to use to get the named resource.
    079     * @param name        the location of the properties file.
    080     * @return a new properties object.
    081     * @throws IOException              Thrown if an error occurred reading the input stream.
    082     * @throws IllegalArgumentException Thrown if the input contains a malformed Unicode escape sequence.
    083     */
    084    public T load(final ClassLoader classLoader, final String name) throws IOException {
    085        try (InputStream inputStream = classLoader.getResourceAsStream(name)) {
    086            return load(inputStream, PropertyFormat.toPropertyFormat(name));
    087        }
    088    }
    089
    090    /**
    091     * Creates and loads properties from the given file.
    092     *
    093     * @param file the location of the properties file.
    094     * @return a new properties object.
    095     * @throws IOException              Thrown if an error occurred reading the input stream.
    096     * @throws IllegalArgumentException Thrown if the input contains a malformed Unicode escape sequence.
    097     * @throws FileNotFoundException    Thrown if the file does not exist, is a directory, or cannot be opened for
    098     *                                  reading.
    099     * @throws SecurityException        Thrown if a security manager's {@code checkRead} method denies read access to
    100     *                                  the file.
    101     */
    102    public T load(final File file) throws FileNotFoundException, IOException {
    103        try (FileInputStream inputStream = new FileInputStream(file)) {
    104            return load(inputStream, PropertyFormat.toPropertyFormat(file.getName()));
    105        }
    106    }
    107
    108    /**
    109     * Creates and loads properties from the given input stream.
    110     *
    111     * @param inputStream the location of the properties file.
    112     * @return a new properties object.
    113     * @throws IOException              Thrown if an error occurred reading the input stream.
    114     * @throws IllegalArgumentException Thrown if the input contains a malformed Unicode escape sequence.
    115     */
    116    public T load(final InputStream inputStream) throws IOException {
    117        if (inputStream == null) {
    118            return null;
    119        }
    120        final T properties = createProperties();
    121        properties.load(inputStream);
    122        return properties;
    123    }
    124
    125    /**
    126     * Creates and loads properties from the given input stream.
    127     *
    128     * @param inputStream the location of the properties file.
    129     * @param propertyFormat The format of the given file.
    130     * @return a new properties object.
    131     * @throws IOException              Thrown if an error occurred reading the input stream.
    132     * @throws IllegalArgumentException Thrown if the input contains a malformed Unicode escape sequence.
    133     * @since 4.5.0-M1
    134     */
    135    public T load(final InputStream inputStream, final PropertyFormat propertyFormat) throws IOException {
    136        if (inputStream == null) {
    137            return null;
    138        }
    139        final T properties = createProperties();
    140        if (propertyFormat == PropertyFormat.XML) {
    141            properties.loadFromXML(inputStream);
    142        } else {
    143            properties.load(inputStream);
    144        }
    145        return properties;
    146    }
    147
    148    /**
    149     * Creates and loads properties from the given path.
    150     *
    151     * @param path the location of the properties file.
    152     * @return a new properties object.
    153     * @throws IOException              Thrown if an error occurred reading the input stream.
    154     * @throws IllegalArgumentException Thrown if the input contains a malformed Unicode escape sequence.
    155     */
    156    public T load(final Path path) throws IOException {
    157        try (InputStream inputStream = Files.newInputStream(path)) {
    158            return load(inputStream, PropertyFormat.toPropertyFormat(Objects.toString(path.getFileName(), null)));
    159        }
    160    }
    161
    162    /**
    163     * Creates and loads properties from the given reader.
    164     *
    165     * @param reader the location of the properties file.
    166     * @return a new properties object.
    167     * @throws IOException              Thrown if an error occurred reading the input stream.
    168     * @throws IllegalArgumentException Thrown if the input contains a malformed Unicode escape sequence.
    169     */
    170    public T load(final Reader reader) throws IOException {
    171        final T properties = createProperties();
    172        properties.load(reader);
    173        return properties;
    174    }
    175
    176    /**
    177     * Creates and loads properties from the given file name.
    178     *
    179     * @param name the location of the properties file.
    180     * @return a new properties object.
    181     * @throws IOException              Thrown if an error occurred reading the input stream.
    182     * @throws IllegalArgumentException Thrown if the input contains a malformed Unicode escape sequence.
    183     */
    184    public T load(final String name) throws IOException {
    185        try (FileInputStream inputStream = new FileInputStream(name)) {
    186            return load(inputStream, PropertyFormat.toPropertyFormat(name));
    187        }
    188    }
    189
    190    /**
    191     * Creates and loads properties from the given URI.
    192     *
    193     * @param uri the location of the properties file.
    194     * @return a new properties object.
    195     * @throws IOException              Thrown if an error occurred reading the input stream.
    196     * @throws IllegalArgumentException Thrown if the input contains a malformed Unicode escape sequence.
    197     */
    198    public T load(final URI uri) throws IOException {
    199        return load(Paths.get(uri));
    200    }
    201
    202    /**
    203     * Creates and loads properties from the given URL.
    204     *
    205     * @param url the location of the properties file.
    206     * @return a new properties object.
    207     * @throws IOException              Thrown if an error occurred reading the input stream.
    208     * @throws IllegalArgumentException Thrown if the input contains a malformed Unicode escape sequence.
    209     */
    210    public T load(final URL url) throws IOException {
    211        try (InputStream inputStream = url.openStream()) {
    212            return load(inputStream, PropertyFormat.toPropertyFormat(url.getFile()));
    213        }
    214    }
    215
    216}