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 package org.apache.commons.configuration;
018
019 import java.io.File;
020 import java.io.FileNotFoundException;
021 import java.io.FileOutputStream;
022 import java.io.IOException;
023 import java.io.InputStream;
024 import java.io.OutputStream;
025 import java.net.HttpURLConnection;
026 import java.net.MalformedURLException;
027 import java.net.URL;
028 import java.net.URLConnection;
029
030 import org.apache.commons.logging.Log;
031 import org.apache.commons.logging.LogFactory;
032
033 /**
034 * FileSystem that uses java.io.File or HttpClient
035 * @since 1.7
036 * @author <a
037 * href="http://commons.apache.org/configuration/team-list.html">Commons Configuration team</a>
038 */
039 public class DefaultFileSystem extends FileSystem
040 {
041 /**
042 * The Log for diagnostic messages.
043 */
044 private Log log = LogFactory.getLog(DefaultFileSystem.class);
045
046 @Override
047 public InputStream getInputStream(String basePath, String fileName)
048 throws ConfigurationException
049 {
050 try
051 {
052 URL url = ConfigurationUtils.locate(this, basePath, fileName);
053
054 if (url == null)
055 {
056 throw new ConfigurationException("Cannot locate configuration source " + fileName);
057 }
058 return getInputStream(url);
059 }
060 catch (ConfigurationException e)
061 {
062 throw e;
063 }
064 catch (Exception e)
065 {
066 throw new ConfigurationException("Unable to load the configuration file " + fileName, e);
067 }
068 }
069
070 @Override
071 public InputStream getInputStream(URL url) throws ConfigurationException
072 {
073 // throw an exception if the target URL is a directory
074 File file = ConfigurationUtils.fileFromURL(url);
075 if (file != null && file.isDirectory())
076 {
077 throw new ConfigurationException("Cannot load a configuration from a directory");
078 }
079
080 try
081 {
082 return url.openStream();
083 }
084 catch (Exception e)
085 {
086 throw new ConfigurationException("Unable to load the configuration from the URL " + url, e);
087 }
088 }
089
090 @Override
091 public OutputStream getOutputStream(URL url) throws ConfigurationException
092 {
093 // file URLs have to be converted to Files since FileURLConnection is
094 // read only (http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4191800)
095 File file = ConfigurationUtils.fileFromURL(url);
096 if (file != null)
097 {
098 return getOutputStream(file);
099 }
100 else
101 {
102 // for non file URLs save through an URLConnection
103 OutputStream out;
104 try
105 {
106 URLConnection connection = url.openConnection();
107 connection.setDoOutput(true);
108
109 // use the PUT method for http URLs
110 if (connection instanceof HttpURLConnection)
111 {
112 HttpURLConnection conn = (HttpURLConnection) connection;
113 conn.setRequestMethod("PUT");
114 }
115
116 out = connection.getOutputStream();
117
118 // check the response code for http URLs and throw an exception if an error occured
119 if (connection instanceof HttpURLConnection)
120 {
121 out = new HttpOutputStream(out, (HttpURLConnection) connection);
122 }
123 return out;
124 }
125 catch (IOException e)
126 {
127 throw new ConfigurationException("Could not save to URL " + url, e);
128 }
129 }
130 }
131
132 @Override
133 public OutputStream getOutputStream(File file) throws ConfigurationException
134 {
135 try
136 {
137 // create the file if necessary
138 createPath(file);
139 return new FileOutputStream(file);
140 }
141 catch (FileNotFoundException e)
142 {
143 throw new ConfigurationException("Unable to save to file " + file, e);
144 }
145 }
146
147 @Override
148 public String getPath(File file, URL url, String basePath, String fileName)
149 {
150 String path = null;
151 // if resource was loaded from jar file may be null
152 if (file != null)
153 {
154 path = file.getAbsolutePath();
155 }
156
157 // try to see if file was loaded from a jar
158 if (path == null)
159 {
160 if (url != null)
161 {
162 path = url.getPath();
163 }
164 else
165 {
166 try
167 {
168 path = getURL(basePath, fileName).getPath();
169 }
170 catch (Exception e)
171 {
172 // simply ignore it and return null
173 if (log.isDebugEnabled())
174 {
175 log.debug(String.format("Could not determine URL for "
176 + "basePath = %s, fileName = %s.", basePath,
177 fileName), e);
178 }
179 }
180 }
181 }
182
183 return path;
184 }
185
186 @Override
187 public String getBasePath(String path)
188 {
189 URL url;
190 try
191 {
192 url = getURL(null, path);
193 return ConfigurationUtils.getBasePath(url);
194 }
195 catch (Exception e)
196 {
197 return null;
198 }
199 }
200
201 @Override
202 public String getFileName(String path)
203 {
204 URL url;
205 try
206 {
207 url = getURL(null, path);
208 return ConfigurationUtils.getFileName(url);
209 }
210 catch (Exception e)
211 {
212 return null;
213 }
214 }
215
216
217 @Override
218 public URL getURL(String basePath, String file) throws MalformedURLException
219 {
220 File f = new File(file);
221 if (f.isAbsolute()) // already absolute?
222 {
223 return ConfigurationUtils.toURL(f);
224 }
225
226 try
227 {
228 if (basePath == null)
229 {
230 return new URL(file);
231 }
232 else
233 {
234 URL base = new URL(basePath);
235 return new URL(base, file);
236 }
237 }
238 catch (MalformedURLException uex)
239 {
240 return ConfigurationUtils.toURL(ConfigurationUtils.constructFile(basePath, file));
241 }
242 }
243
244
245 @Override
246 public URL locateFromURL(String basePath, String fileName)
247 {
248 try
249 {
250 URL url;
251 if (basePath == null)
252 {
253 return new URL(fileName);
254 //url = new URL(name);
255 }
256 else
257 {
258 URL baseURL = new URL(basePath);
259 url = new URL(baseURL, fileName);
260
261 // check if the file exists
262 InputStream in = null;
263 try
264 {
265 in = url.openStream();
266 }
267 finally
268 {
269 if (in != null)
270 {
271 in.close();
272 }
273 }
274 return url;
275 }
276 }
277 catch (IOException e)
278 {
279 if (log.isDebugEnabled())
280 {
281 log.debug("Could not locate file " + fileName + " at " + basePath + ": " + e.getMessage());
282 }
283 return null;
284 }
285 }
286
287 /**
288 * Create the path to the specified file.
289 *
290 * @param file the target file
291 */
292 private void createPath(File file)
293 {
294 if (file != null)
295 {
296 // create the path to the file if the file doesn't exist
297 if (!file.exists())
298 {
299 File parent = file.getParentFile();
300 if (parent != null && !parent.exists())
301 {
302 parent.mkdirs();
303 }
304 }
305 }
306 }
307 /**
308 * Wraps the output stream so errors can be detected in the HTTP response.
309 * @since 1.7
310 * @author <a
311 * href="http://commons.apache.org/configuration/team-list.html">Commons Configuration team</a>
312 */
313 private static class HttpOutputStream extends VerifiableOutputStream
314 {
315 /** The wrapped OutputStream */
316 private final OutputStream stream;
317
318 /** The HttpURLConnection */
319 private final HttpURLConnection connection;
320
321 public HttpOutputStream(OutputStream stream, HttpURLConnection connection)
322 {
323 this.stream = stream;
324 this.connection = connection;
325 }
326
327 @Override
328 public void write(byte[] bytes) throws IOException
329 {
330 stream.write(bytes);
331 }
332
333 @Override
334 public void write(byte[] bytes, int i, int i1) throws IOException
335 {
336 stream.write(bytes, i, i1);
337 }
338
339 @Override
340 public void flush() throws IOException
341 {
342 stream.flush();
343 }
344
345 @Override
346 public void close() throws IOException
347 {
348 stream.close();
349 }
350
351 @Override
352 public void write(int i) throws IOException
353 {
354 stream.write(i);
355 }
356
357 @Override
358 public String toString()
359 {
360 return stream.toString();
361 }
362
363 @Override
364 public void verify() throws IOException
365 {
366 if (connection.getResponseCode() >= HttpURLConnection.HTTP_BAD_REQUEST)
367 {
368 throw new IOException("HTTP Error " + connection.getResponseCode()
369 + " " + connection.getResponseMessage());
370 }
371 }
372 }
373 }