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.logging.log4j.core.config; 019 020import java.io.ByteArrayInputStream; 021import java.io.ByteArrayOutputStream; 022import java.io.File; 023import java.io.FileInputStream; 024import java.io.IOException; 025import java.io.InputStream; 026import java.net.URI; 027import java.net.URISyntaxException; 028import java.net.URL; 029import java.util.Objects; 030 031/** 032 * Represents the source for the logging configuration. 033 */ 034public class ConfigurationSource { 035 /** 036 * ConfigurationSource to use with Configurations that do not require a "real" configuration source. 037 */ 038 public static final ConfigurationSource NULL_SOURCE = new ConfigurationSource(new byte[0]); 039 040 private final File file; 041 private final URL url; 042 private final String location; 043 private final InputStream stream; 044 private final byte[] data; 045 046 /** 047 * Constructs a new {@code ConfigurationSource} with the specified input stream that originated from the specified 048 * file. 049 * 050 * @param stream the input stream 051 * @param file the file where the input stream originated 052 */ 053 public ConfigurationSource(final InputStream stream, final File file) { 054 this.stream = Objects.requireNonNull(stream, "stream is null"); 055 this.file = Objects.requireNonNull(file, "file is null"); 056 this.location = file.getAbsolutePath(); 057 this.url = null; 058 this.data = null; 059 } 060 061 /** 062 * Constructs a new {@code ConfigurationSource} with the specified input stream that originated from the specified 063 * url. 064 * 065 * @param stream the input stream 066 * @param url the URL where the input stream originated 067 */ 068 public ConfigurationSource(final InputStream stream, final URL url) { 069 this.stream = Objects.requireNonNull(stream, "stream is null"); 070 this.url = Objects.requireNonNull(url, "URL is null"); 071 this.location = url.toString(); 072 this.file = null; 073 this.data = null; 074 } 075 076 /** 077 * Constructs a new {@code ConfigurationSource} with the specified input stream. Since the stream is the only source 078 * of data, this constructor makes a copy of the stream contents. 079 * 080 * @param stream the input stream 081 * @throws IOException if an exception occurred reading from the specified stream 082 */ 083 public ConfigurationSource(final InputStream stream) throws IOException { 084 this(toByteArray(stream)); 085 } 086 087 private ConfigurationSource(final byte[] data) { 088 this.data = Objects.requireNonNull(data, "data is null"); 089 this.stream = new ByteArrayInputStream(data); 090 this.file = null; 091 this.url = null; 092 this.location = null; 093 } 094 095 /** 096 * Returns the contents of the specified {@code InputStream} as a byte array. 097 * 098 * @param inputStream the stream to read 099 * @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}