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 */ 017package org.apache.commons.configuration; 018 019import java.io.File; 020import java.io.FileNotFoundException; 021import java.io.FileOutputStream; 022import java.io.IOException; 023import java.io.InputStream; 024import java.io.OutputStream; 025import java.net.HttpURLConnection; 026import java.net.MalformedURLException; 027import java.net.URL; 028import java.net.URLConnection; 029 030import org.apache.commons.logging.Log; 031import 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 */ 039public 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}