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