1 /***
2 * Copyright (c) 2003, 2004, Chess iT
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without modification,
6 * are permitted provided that the following conditions are met:
7 *
8 * - Redistributions of source code must retain the above copyright notice, this
9 * list of conditions and the following disclaimer.
10 *
11 * - Redistributions in binary form must reproduce the above copyright notice,
12 * this list of conditions and the following disclaimer in the documentation
13 * and/or other materials provided with the distribution.
14 *
15 * - Neither the name of Chess iT, nor the names of its contributors may be used
16 * to endorse or promote products derived from this software without specific
17 * prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
23 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 *
31 */
32 package nl.chess.it.util.config.resolv;
33
34 import java.io.BufferedInputStream;
35 import java.io.ByteArrayInputStream;
36 import java.io.File;
37 import java.io.FileInputStream;
38 import java.io.IOException;
39 import java.io.InputStream;
40 import java.net.URL;
41 import java.util.ArrayList;
42 import java.util.List;
43 import java.util.Properties;
44
45 import nl.chess.it.util.config.ConfigurationException;
46
47 /***
48 * Opens a file or URL which name is given in an environment variable. Two situations can occur:
49 * <ul>
50 * <li>file is okay and readable: {@link #getSourceDescription()}and {@link #getProperties()}are
51 * garantueed to be not null</li>
52 * <li>file is not usable or cannot be read: {@link #getSourceDescription()}and
53 * {@link #getProperties()}might be null</li>
54 * </ul>
55 * <b>Note: </b> this class is still in development; the external interface might change (slightly)
56 * later.
57 *
58 * @author Guus Bosman (Chess-iT)
59 */
60 public class ConfigurationResolverEnvironmentVariable {
61
62 private Exception exception;
63 private String sourceDescription;
64 private Properties properties;
65
66 public ConfigurationResolverEnvironmentVariable(final String key) {
67 String fileName = System.getProperty(key);
68 if (fileName == null) {
69 exception = new ConfigurationException(
70 "no property for configuration file or URL was given as JVM argument. Please add the following to the java.exe startup command: -D"
71 + key + "=<location of file>");
72 return;
73 }
74 boolean isURL = false;
75 try {
76 new URL(fileName);
77 isURL = true;
78 } catch (Exception e) {
79
80 isURL = false;
81 }
82 if (isURL) {
83 String interpretedURLName = null;
84 Properties tmpProperties = new Properties();
85 try {
86 URL url = new URL(fileName);
87 interpretedURLName = url.toExternalForm();
88
89 byte[] bytes = readEntireFileContents(url.openStream());
90
91 InputStream is = new ByteArrayInputStream(bytes);
92
93 PropertyInputStreamValidator.validate(is);
94
95 is.reset();
96 tmpProperties.load(is);
97 } catch (Exception e) {
98 exception = new ConfigurationException("environment property '" + key + "' had value '" + fileName
99 + "', which I interpreted as url '" + interpretedURLName
100 + "' but this can't be used to read the configuration from: " + e.getMessage(), e);
101 return;
102 }
103
104 sourceDescription = "url " + interpretedURLName + " (from environment property '" + key + "')";
105 properties = tmpProperties;
106 } else {
107 File file = new File(fileName);
108 String interpretedFileName = null;
109 Properties tmpProperties = new Properties();
110 try {
111 interpretedFileName = file.getCanonicalPath();
112
113 FileInputStream is = new FileInputStream(file);
114 PropertyInputStreamValidator.validate(is);
115
116 is = new FileInputStream(file);
117 tmpProperties.load(is);
118 } catch (Exception e) {
119 exception = new ConfigurationException("environment property '" + key + "' had value '" + fileName
120 + "', which I interpreted as '" + interpretedFileName
121 + "' but this can't be used to read the configuration from: " + e.getMessage(), e);
122 return;
123 }
124
125 sourceDescription = "file " + interpretedFileName + " (from environment property '" + key + "')";
126 properties = tmpProperties;
127 }
128
129 }
130
131 /***
132 * Returns the Exception that occurred while reading from the environment variable (if any).
133 *
134 * @return Might be <code>null</code>.
135 */
136 public Exception getException() {
137 return exception;
138 }
139
140 /***
141 * Description of the file or URL read.
142 *
143 * @return If {@link #getException()}was not null then this might be <code>null</code>.
144 */
145 public String getSourceDescription() {
146 return sourceDescription;
147 }
148
149 /***
150 * Returns Properties object for configuration
151 *
152 * @return If {@link #getException()}was not null then this might be <code>null</code>.
153 */
154 public Properties getProperties() {
155 return properties;
156 }
157
158 /***
159 * Reads a file into a byte-array. When an Exception is thrown the inputstream will always be
160 * closed. Memory expensive method, use only with limited size of InputStreams.
161 *
162 * @param toRead the file to be read
163 * @return a file data byte-array
164 * @throws NullPointerException If toRead is <code>null</code>.
165 * @throws IOException if reading the file fails somehow
166 */
167 private static byte[] readEntireFileContents(InputStream toRead) throws IOException {
168 if (toRead == null) {
169 throw new NullPointerException("toRead cannot be null here.");
170 }
171
172 InputStream in = null;
173 byte[] buf = null;
174
175 /***
176 * A large buffer for reading from the InputStream. The larger the better as it increases
177 * the speed in which the file can be read.
178 */
179 int bufLen = 10000 * 1024;
180
181 try {
182 in = new BufferedInputStream(toRead);
183 buf = new byte[bufLen];
184
185 byte[] tmp = null;
186 int len = 0;
187 List data = new ArrayList();
188
189 while ((len = in.read(buf, 0, bufLen)) != -1) {
190 tmp = new byte[len];
191 System.arraycopy(buf, 0, tmp, 0, len);
192 data.add(tmp);
193 }
194
195 len = 0;
196
197 /***
198 * Trivial case.
199 */
200 if (data.size() == 1) {
201 return (byte[]) data.get(0);
202 }
203
204 for (int i = 0; i < data.size(); i++)
205 len += ((byte[]) data.get(i)).length;
206
207 /***
208 * The result.
209 */
210 buf = new byte[len];
211 len = 0;
212
213 for (int i = 0; i < data.size(); i++) {
214 tmp = (byte[]) data.get(i);
215 System.arraycopy(tmp, 0, buf, len, tmp.length);
216 len += tmp.length;
217 }
218 } finally {
219 if (in != null) {
220 try {
221 in.close();
222 } catch (Exception e) {
223 throw new RuntimeException(e);
224 }
225 }
226 }
227
228 return buf;
229 }
230 }