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 }