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