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.IOException; 021import java.io.InputStream; 022import java.io.OutputStream; 023import java.lang.reflect.Method; 024import java.net.MalformedURLException; 025import java.net.URL; 026import java.net.URLConnection; 027import java.net.URLStreamHandler; 028import java.util.Map; 029 030import org.apache.commons.configuration2.ex.ConfigurationException; 031import org.apache.commons.configuration2.ex.ConfigurationRuntimeException; 032import org.apache.commons.logging.Log; 033import org.apache.commons.logging.LogFactory; 034import org.apache.commons.vfs2.FileContent; 035import org.apache.commons.vfs2.FileName; 036import org.apache.commons.vfs2.FileObject; 037import org.apache.commons.vfs2.FileSystemConfigBuilder; 038import org.apache.commons.vfs2.FileSystemException; 039import org.apache.commons.vfs2.FileSystemManager; 040import org.apache.commons.vfs2.FileSystemOptions; 041import org.apache.commons.vfs2.FileType; 042import org.apache.commons.vfs2.VFS; 043import org.apache.commons.vfs2.provider.UriParser; 044 045/** 046 * FileSystem that uses Commons VFS 047 * @since 1.7 048 * @author <a 049 * href="http://commons.apache.org/configuration/team-list.html">Commons Configuration team</a> 050 * @version $Id: VFSFileSystem.java 1674561 2015-04-18 19:08:11Z oheger $ 051 */ 052public class VFSFileSystem extends DefaultFileSystem 053{ 054 /** The logger. */ 055 private final Log log = LogFactory.getLog(getClass()); 056 057 public VFSFileSystem() 058 { 059 } 060 061 @Override 062 public InputStream getInputStream(URL url) throws ConfigurationException 063 { 064 FileObject file; 065 try 066 { 067 FileSystemOptions opts = getOptions(url.getProtocol()); 068 file = (opts == null) ? VFS.getManager().resolveFile(url.toString()) 069 : VFS.getManager().resolveFile(url.toString(), opts); 070 if (file.getType() != FileType.FILE) 071 { 072 throw new ConfigurationException("Cannot load a configuration from a directory"); 073 } 074 FileContent content = file.getContent(); 075 if (content == null) 076 { 077 String msg = "Cannot access content of " + file.getName().getFriendlyURI(); 078 throw new ConfigurationException(msg); 079 } 080 return content.getInputStream(); 081 } 082 catch (FileSystemException fse) 083 { 084 String msg = "Unable to access " + url.toString(); 085 throw new ConfigurationException(msg, fse); 086 } 087 } 088 089 @Override 090 public OutputStream getOutputStream(URL url) throws ConfigurationException 091 { 092 try 093 { 094 FileSystemOptions opts = getOptions(url.getProtocol()); 095 FileSystemManager fsManager = VFS.getManager(); 096 FileObject file = (opts == null) ? fsManager.resolveFile(url.toString()) 097 : fsManager.resolveFile(url.toString(), opts); 098 // throw an exception if the target URL is a directory 099 if (file == null || file.getType() == FileType.FOLDER) 100 { 101 throw new ConfigurationException("Cannot save a configuration to a directory"); 102 } 103 FileContent content = file.getContent(); 104 105 if (content == null) 106 { 107 throw new ConfigurationException("Cannot access content of " + url); 108 } 109 return content.getOutputStream(); 110 } 111 catch (FileSystemException fse) 112 { 113 throw new ConfigurationException("Unable to access " + url, fse); 114 } 115 } 116 117 @Override 118 public String getPath(File file, URL url, String basePath, String fileName) 119 { 120 if (file != null) 121 { 122 return super.getPath(file, url, basePath, fileName); 123 } 124 try 125 { 126 FileSystemManager fsManager = VFS.getManager(); 127 if (url != null) 128 { 129 FileName name = fsManager.resolveURI(url.toString()); 130 if (name != null) 131 { 132 return name.toString(); 133 } 134 } 135 136 if (UriParser.extractScheme(fileName) != null) 137 { 138 return fileName; 139 } 140 else if (basePath != null) 141 { 142 FileName base = fsManager.resolveURI(basePath); 143 return fsManager.resolveName(base, fileName).getURI(); 144 } 145 else 146 { 147 FileName name = fsManager.resolveURI(fileName); 148 FileName base = name.getParent(); 149 return fsManager.resolveName(base, name.getBaseName()).getURI(); 150 } 151 } 152 catch (FileSystemException fse) 153 { 154 fse.printStackTrace(); 155 return null; 156 } 157 } 158 159 @Override 160 public String getBasePath(String path) 161 { 162 if (UriParser.extractScheme(path) == null) 163 { 164 return super.getBasePath(path); 165 } 166 try 167 { 168 FileSystemManager fsManager = VFS.getManager(); 169 FileName name = fsManager.resolveURI(path); 170 return name.getParent().getURI(); 171 } 172 catch (FileSystemException fse) 173 { 174 fse.printStackTrace(); 175 return null; 176 } 177 } 178 179 @Override 180 public String getFileName(String path) 181 { 182 if (UriParser.extractScheme(path) == null) 183 { 184 return super.getFileName(path); 185 } 186 try 187 { 188 FileSystemManager fsManager = VFS.getManager(); 189 FileName name = fsManager.resolveURI(path); 190 return name.getBaseName(); 191 } 192 catch (FileSystemException fse) 193 { 194 fse.printStackTrace(); 195 return null; 196 } 197 } 198 199 @Override 200 public URL getURL(String basePath, String file) throws MalformedURLException 201 { 202 if ((basePath != null && UriParser.extractScheme(basePath) == null) 203 || (basePath == null && UriParser.extractScheme(file) == null)) 204 { 205 return super.getURL(basePath, file); 206 } 207 try 208 { 209 FileSystemManager fsManager = VFS.getManager(); 210 211 FileName path; 212 if (basePath != null && UriParser.extractScheme(file) == null) 213 { 214 FileName base = fsManager.resolveURI(basePath); 215 path = fsManager.resolveName(base, file); 216 } 217 else 218 { 219 path = fsManager.resolveURI(file); 220 } 221 222 URLStreamHandler handler = new VFSURLStreamHandler(path); 223 return new URL(null, path.getURI(), handler); 224 } 225 catch (FileSystemException fse) 226 { 227 throw new ConfigurationRuntimeException("Could not parse basePath: " + basePath 228 + " and fileName: " + file, fse); 229 } 230 } 231 232 @Override 233 public URL locateFromURL(String basePath, String fileName) 234 { 235 String fileScheme = UriParser.extractScheme(fileName); 236 237 // Use DefaultFileSystem if basePath and fileName don't have a scheme. 238 if ((basePath == null || UriParser.extractScheme(basePath) == null) && fileScheme == null) 239 { 240 return super.locateFromURL(basePath, fileName); 241 } 242 try 243 { 244 FileSystemManager fsManager = VFS.getManager(); 245 246 FileObject file; 247 // Only use the base path if the file name doesn't have a scheme. 248 if (basePath != null && fileScheme == null) 249 { 250 String scheme = UriParser.extractScheme(basePath); 251 FileSystemOptions opts = (scheme != null) ? getOptions(scheme) : null; 252 FileObject base = (opts == null) ? fsManager.resolveFile(basePath) 253 : fsManager.resolveFile(basePath, opts); 254 if (base.getType() == FileType.FILE) 255 { 256 base = base.getParent(); 257 } 258 259 file = fsManager.resolveFile(base, fileName); 260 } 261 else 262 { 263 FileSystemOptions opts = (fileScheme != null) ? getOptions(fileScheme) : null; 264 file = (opts == null) ? fsManager.resolveFile(fileName) 265 : fsManager.resolveFile(fileName, opts); 266 } 267 268 if (!file.exists()) 269 { 270 return null; 271 } 272 FileName path = file.getName(); 273 URLStreamHandler handler = new VFSURLStreamHandler(path); 274 return new URL(null, path.getURI(), handler); 275 } 276 catch (FileSystemException fse) 277 { 278 return null; 279 } 280 catch (MalformedURLException ex) 281 { 282 return null; 283 } 284 } 285 286 private FileSystemOptions getOptions(String scheme) 287 { 288 FileSystemOptions opts = new FileSystemOptions(); 289 FileSystemConfigBuilder builder; 290 try 291 { 292 builder = VFS.getManager().getFileSystemConfigBuilder(scheme); 293 } 294 catch (Exception ex) 295 { 296 return null; 297 } 298 FileOptionsProvider provider = getFileOptionsProvider(); 299 if (provider != null) 300 { 301 Map<String, Object> map = provider.getOptions(); 302 if (map == null) 303 { 304 return null; 305 } 306 int count = 0; 307 for (Map.Entry<String, Object> entry : map.entrySet()) 308 { 309 try 310 { 311 String key = entry.getKey(); 312 if (FileOptionsProvider.CURRENT_USER.equals(key)) 313 { 314 key = "creatorName"; 315 } 316 setProperty(builder, opts, key, entry.getValue()); 317 ++count; 318 } 319 catch (Exception ex) 320 { 321 // Ignore an incorrect property. 322 continue; 323 } 324 } 325 if (count > 0) 326 { 327 return opts; 328 } 329 } 330 return null; 331 332 } 333 334 private void setProperty(FileSystemConfigBuilder builder, FileSystemOptions options, 335 String key, Object value) 336 { 337 String methodName = "set" + key.substring(0, 1).toUpperCase() + key.substring(1); 338 Class<?>[] paramTypes = new Class<?>[2]; 339 paramTypes[0] = FileSystemOptions.class; 340 paramTypes[1] = value.getClass(); 341 342 try 343 { 344 Method method = builder.getClass().getMethod(methodName, paramTypes); 345 Object[] params = new Object[2]; 346 params[0] = options; 347 params[1] = value; 348 method.invoke(builder, params); 349 } 350 catch (Exception ex) 351 { 352 log.warn("Cannot access property '" + key + "'! Ignoring.", ex); 353 } 354 355 } 356 357 /** 358 * Stream handler required to create URL. 359 */ 360 private static class VFSURLStreamHandler extends URLStreamHandler 361 { 362 /** The Protocol used */ 363 private final String protocol; 364 365 public VFSURLStreamHandler(FileName file) 366 { 367 this.protocol = file.getScheme(); 368 } 369 370 @Override 371 protected URLConnection openConnection(URL url) throws IOException 372 { 373 throw new IOException("VFS URLs can only be used with VFS APIs"); 374 } 375 } 376}