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