    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
    018    package org.apache.logging.log4j.core.config;
    019
    020    import java.io.ByteArrayInputStream;
    021    import java.io.ByteArrayOutputStream;
    022    import java.io.File;
    023    import java.io.FileInputStream;
    024    import java.io.IOException;
    025    import java.io.InputStream;
    026    import java.net.URL;
    027
    028    import org.apache.logging.log4j.core.util.Assert;
    029
    030    /**
    031     * Represents the source for the logging configuration.
    032     */
    033    public class ConfigurationSource {
    034        public static final ConfigurationSource NULL_SOURCE = new ConfigurationSource(new byte[0]);
    035
    036        private final File file;
    037        private final URL url;
    038        private final String location;
    039        private final InputStream stream;
    040        private final byte[] data;
    041
    042        /**
    043         * Returns the contents of the specified {@code InputStream} as a byte array.
    044         *
    045         * @param inputStream the stream to read
    046         * @return the contents of the specified stream
    047         * @throws IOException if a problem occurred reading from the stream
    048         */
    049        private static byte[] toByteArray(final InputStream inputStream) throws IOException {
    050            final int buffSize = Math.max(4096, inputStream.available());
    051            final ByteArrayOutputStream contents = new ByteArrayOutputStream(buffSize);
    052            final byte[] buff = new byte[buffSize];
    053
    054            int length = inputStream.read(buff);
    055            while (length > 0) {
    056                contents.write(buff, 0, length);
    057                length = inputStream.read(buff);
    058            }
    059            return contents.toByteArray();
    060        }
    061
    062        /**
    063         * Constructs a new {@code ConfigurationSource} with the specified input stream. Since the stream is the only source
    064         * of data, this constructor makes a copy of the stream contents.
    065         *
    066         * @param stream the input stream
    067         * @throws IOException if an exception occurred reading from the specified stream
    068         */
    069        public ConfigurationSource(final InputStream stream) throws IOException {
    070            this(toByteArray(stream));
    071        }
    072
    073        private ConfigurationSource(final byte[] data) {
    074            this.data = Assert.requireNonNull(data, "data is null");
    075            this.stream = new ByteArrayInputStream(data);
    076            this.file = null;
    077            this.url = null;
    078            this.location = null;
    079        }
    080
    081        /**
    082         * Constructs a new {@code ConfigurationSource} with the specified input stream that originated from the specified
    083         * file.
    084         *
    085         * @param stream the input stream
    086         * @param file the file where the input stream originated
    087         */
    088        public ConfigurationSource(final InputStream stream, final File file) {
    089            this.stream = Assert.requireNonNull(stream, "stream is null");
    090            this.file = Assert.requireNonNull(file, "file is null");
    091            this.location = file.getAbsolutePath();
    092            this.url = null;
    093            this.data = null;
    094        }
    095
    096        /**
    097         * Constructs a new {@code ConfigurationSource} with the specified input stream that originated from the specified
    098         * url.
    099         *
    100         * @param stream the input stream
    101         * @param url the URL where the input stream originated
    102         */
    103        public ConfigurationSource(final InputStream stream, final URL url) {
    104            this.stream = Assert.requireNonNull(stream, "stream is null");
    105            this.url = Assert.requireNonNull(url, "URL is null");
    106            this.location = url.toString();
    107            this.file = null;
    108            this.data = null;
    109        }
    110
    111        /**
    112         * Returns the file configuration source, or {@code null} if this configuration source is based on an URL or has
    113         * neither a file nor an URL.
    114         *
    115         * @return the configuration source file, or {@code null}
    116         */
    117        public File getFile() {
    118            return file;
    119        }
    120
    121        /**
    122         * Returns the configuration source URL, or {@code null} if this configuration source is based on a file or has
    123         * neither a file nor an URL.
    124         *
    125         * @return the configuration source URL, or {@code null}
    126         */
    127        public URL getURL() {
    128            return url;
    129        }
    130
    131        /**
    132         * Returns a string describing the configuration source file or URL, or {@code null} if this configuration source
    133         * has neither a file nor an URL.
    134         *
    135         * @return a string describing the configuration source file or URL, or {@code null}
    136         */
    137        public String getLocation() {
    138            return location;
    139        }
    140
    141        /**
    142         * Returns the input stream that this configuration source was constructed with.
    143         *
    144         * @return the input stream that this configuration source was constructed with.
    145         */
    146        public InputStream getInputStream() {
    147            return stream;
    148        }
    149
    150        /**
    151         * Returns a new {@code ConfigurationSource} whose input stream is reset to the beginning.
    152         *
    153         * @return a new {@code ConfigurationSource}
    154         * @throws IOException if a problem occurred while opening the new input stream
    155         */
    156        public ConfigurationSource resetInputStream() throws IOException {
    157            if (file != null) {
    158                return new ConfigurationSource(new FileInputStream(file), file);
    159            } else if (url != null) {
    160                return new ConfigurationSource(url.openStream(), url);
    161            } else {
    162                return new ConfigurationSource(data);
    163            }
    164        }
    165
    166        @Override
    167        public String toString() {
    168            if (location != null) {
    169                return location;
    170            }
    171            if (this == NULL_SOURCE) {
    172                return "NULL_SOURCE";
    173            }
    174            final int length = data == null ? -1 : data.length;
    175            return "stream (" + length + " bytes, unknown location)";
    176        }
    177    }