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