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