View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements. See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache license, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License. You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the license for the specific language governing permissions and
15   * limitations under the license.
16   */
17  
18  package org.apache.logging.log4j.core.config;
19  
20  import java.io.ByteArrayInputStream;
21  import java.io.ByteArrayOutputStream;
22  import java.io.File;
23  import java.io.FileInputStream;
24  import java.io.IOException;
25  import java.io.InputStream;
26  import java.net.URI;
27  import java.net.URISyntaxException;
28  import java.net.URL;
29  import java.util.Objects;
30  
31  /**
32   * Represents the source for the logging configuration.
33   */
34  public class ConfigurationSource {
35      /**
36       * ConfigurationSource to use with Configurations that do not require a "real" configuration source.
37       */
38      public static final ConfigurationSource NULL_SOURCE = new ConfigurationSource(new byte[0]);
39  
40      private final File file;
41      private final URL url;
42      private final String location;
43      private final InputStream stream;
44      private final byte[] data;
45  
46      /**
47       * Constructs a new {@code ConfigurationSource} with the specified input stream that originated from the specified
48       * file.
49       *
50       * @param stream the input stream
51       * @param file the file where the input stream originated
52       */
53      public ConfigurationSource(final InputStream stream, final File file) {
54          this.stream = Objects.requireNonNull(stream, "stream is null");
55          this.file = Objects.requireNonNull(file, "file is null");
56          this.location = file.getAbsolutePath();
57          this.url = null;
58          this.data = null;
59      }
60  
61      /**
62       * Constructs a new {@code ConfigurationSource} with the specified input stream that originated from the specified
63       * url.
64       *
65       * @param stream the input stream
66       * @param url the URL where the input stream originated
67       */
68      public ConfigurationSource(final InputStream stream, final URL url) {
69          this.stream = Objects.requireNonNull(stream, "stream is null");
70          this.url = Objects.requireNonNull(url, "URL is null");
71          this.location = url.toString();
72          this.file = null;
73          this.data = null;
74      }
75  
76      /**
77       * Constructs a new {@code ConfigurationSource} with the specified input stream. Since the stream is the only source
78       * of data, this constructor makes a copy of the stream contents.
79       *
80       * @param stream the input stream
81       * @throws IOException if an exception occurred reading from the specified stream
82       */
83      public ConfigurationSource(final InputStream stream) throws IOException {
84          this(toByteArray(stream));
85      }
86  
87      private ConfigurationSource(final byte[] data) {
88          this.data = Objects.requireNonNull(data, "data is null");
89          this.stream = new ByteArrayInputStream(data);
90          this.file = null;
91          this.url = null;
92          this.location = null;
93      }
94  
95      /**
96       * Returns the contents of the specified {@code InputStream} as a byte array.
97       *
98       * @param inputStream the stream to read
99       * @return the contents of the specified stream
100      * @throws IOException if a problem occurred reading from the stream
101      */
102     private static byte[] toByteArray(final InputStream inputStream) throws IOException {
103         final int buffSize = Math.max(4096, inputStream.available());
104         final ByteArrayOutputStream contents = new ByteArrayOutputStream(buffSize);
105         final byte[] buff = new byte[buffSize];
106 
107         int length = inputStream.read(buff);
108         while (length > 0) {
109             contents.write(buff, 0, length);
110             length = inputStream.read(buff);
111         }
112         return contents.toByteArray();
113     }
114 
115     /**
116      * Returns the file configuration source, or {@code null} if this configuration source is based on an URL or has
117      * neither a file nor an URL.
118      *
119      * @return the configuration source file, or {@code null}
120      */
121     public File getFile() {
122         return file;
123     }
124 
125     /**
126      * Returns the configuration source URL, or {@code null} if this configuration source is based on a file or has
127      * neither a file nor an URL.
128      *
129      * @return the configuration source URL, or {@code null}
130      */
131     public URL getURL() {
132         return url;
133     }
134 
135     /**
136      * Returns a URI representing the configuration resource or null if it cannot be determined.
137      * @return The URI.
138      */
139     public URI getURI() {
140         URI sourceURI = null;
141         if (url != null) {
142             try {
143                 sourceURI = url.toURI();
144             } catch (final URISyntaxException ex) {
145                     /* Ignore the exception */
146             }
147         }
148         if (sourceURI == null && file != null) {
149             sourceURI = file.toURI();
150         }
151         if (sourceURI == null && location != null) {
152             try {
153                 sourceURI = new URI(location);
154             } catch (final URISyntaxException ex) {
155                 // Assume the scheme was missing.
156                 try {
157                     sourceURI = new URI("file://" + location);
158                 } catch (final URISyntaxException uriEx) {
159                     /* Ignore the exception */
160                 }
161             }
162         }
163         return sourceURI;
164     }
165 
166     /**
167      * Returns a string describing the configuration source file or URL, or {@code null} if this configuration source
168      * has neither a file nor an URL.
169      *
170      * @return a string describing the configuration source file or URL, or {@code null}
171      */
172     public String getLocation() {
173         return location;
174     }
175 
176     /**
177      * Returns the input stream that this configuration source was constructed with.
178      *
179      * @return the input stream that this configuration source was constructed with.
180      */
181     public InputStream getInputStream() {
182         return stream;
183     }
184 
185     /**
186      * Returns a new {@code ConfigurationSource} whose input stream is reset to the beginning.
187      *
188      * @return a new {@code ConfigurationSource}
189      * @throws IOException if a problem occurred while opening the new input stream
190      */
191     public ConfigurationSource resetInputStream() throws IOException {
192         if (file != null) {
193             return new ConfigurationSource(new FileInputStream(file), file);
194         } else if (url != null) {
195             return new ConfigurationSource(url.openStream(), url);
196         } else {
197             return new ConfigurationSource(data);
198         }
199     }
200 
201     @Override
202     public String toString() {
203         if (location != null) {
204             return location;
205         }
206         if (this == NULL_SOURCE) {
207             return "NULL_SOURCE";
208         }
209         final int length = data == null ? -1 : data.length;
210         return "stream (" + length + " bytes, unknown location)";
211     }
212 }