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