| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package org.apache.commons.configuration2.io; |
| |
| import java.io.File; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.OutputStream; |
| import java.lang.reflect.Method; |
| import java.net.MalformedURLException; |
| import java.net.URL; |
| import java.net.URLConnection; |
| import java.net.URLStreamHandler; |
| import java.util.Map; |
| |
| import org.apache.commons.configuration2.ex.ConfigurationException; |
| import org.apache.commons.configuration2.ex.ConfigurationRuntimeException; |
| import org.apache.commons.logging.Log; |
| import org.apache.commons.logging.LogFactory; |
| import org.apache.commons.vfs2.FileContent; |
| import org.apache.commons.vfs2.FileName; |
| import org.apache.commons.vfs2.FileObject; |
| import org.apache.commons.vfs2.FileSystemConfigBuilder; |
| import org.apache.commons.vfs2.FileSystemException; |
| import org.apache.commons.vfs2.FileSystemManager; |
| import org.apache.commons.vfs2.FileSystemOptions; |
| import org.apache.commons.vfs2.VFS; |
| import org.apache.commons.vfs2.provider.UriParser; |
| |
| /** |
| * FileSystem that uses <a href="https://commons.apache.org/proper/commons-vfs/">Apache Commons VFS</a>. |
| * |
| * @since 1.7 |
| */ |
| public class VFSFileSystem extends DefaultFileSystem { |
| |
| /** |
| * Stream handler required to create URL. |
| */ |
| private static final class VFSURLStreamHandler extends URLStreamHandler { |
| |
| @Override |
| protected URLConnection openConnection(final URL url) throws IOException { |
| throw new IOException("VFS URLs can only be used with VFS APIs"); |
| } |
| } |
| |
| /** The logger. */ |
| private final Log log = LogFactory.getLog(getClass()); |
| |
| public VFSFileSystem() { |
| // empty |
| } |
| |
| @Override |
| public String getBasePath(final String path) { |
| if (UriParser.extractScheme(path) == null) { |
| return super.getBasePath(path); |
| } |
| try { |
| final FileName parent = resolveURI(path).getParent(); |
| return parent != null ? parent.getURI() : null; |
| } catch (final FileSystemException fse) { |
| fse.printStackTrace(); |
| return null; |
| } |
| } |
| |
| @Override |
| public String getFileName(final String path) { |
| if (UriParser.extractScheme(path) == null) { |
| return super.getFileName(path); |
| } |
| try { |
| return resolveURI(path).getBaseName(); |
| } catch (final FileSystemException fse) { |
| fse.printStackTrace(); |
| return null; |
| } |
| } |
| |
| @Override |
| public InputStream getInputStream(final URL url) throws ConfigurationException { |
| final FileObject file; |
| try { |
| final FileSystemOptions opts = getOptions(url.getProtocol()); |
| file = getManager().resolveFile(url.toString(), opts); |
| if (!file.exists()) { |
| throw new ConfigurationException("File not found"); |
| } |
| if (!file.isFile()) { |
| throw new ConfigurationException("Cannot load a configuration from a directory"); |
| } |
| final FileContent content = file.getContent(); |
| if (content == null) { |
| final String msg = "Cannot access content of " + file.getName().getFriendlyURI(); |
| throw new ConfigurationException(msg); |
| } |
| return content.getInputStream(); |
| } catch (final FileSystemException fse) { |
| final String msg = "Unable to access " + url.toString(); |
| throw new ConfigurationException(msg, fse); |
| } |
| } |
| |
| private FileSystemManager getManager() throws FileSystemException { |
| return VFS.getManager(); |
| } |
| |
| private FileSystemOptions getOptions(final String scheme) { |
| if (scheme == null) { |
| return null; |
| } |
| final FileSystemOptions opts = new FileSystemOptions(); |
| final FileSystemConfigBuilder builder; |
| try { |
| builder = getManager().getFileSystemConfigBuilder(scheme); |
| } catch (final Exception ex) { |
| return null; |
| } |
| final FileOptionsProvider provider = getFileOptionsProvider(); |
| if (provider != null) { |
| final Map<String, Object> map = provider.getOptions(); |
| if (map == null) { |
| return null; |
| } |
| int count = 0; |
| for (final Map.Entry<String, Object> entry : map.entrySet()) { |
| try { |
| String key = entry.getKey(); |
| if (FileOptionsProvider.CURRENT_USER.equals(key)) { |
| key = "creatorName"; |
| } |
| setProperty(builder, opts, key, entry.getValue()); |
| ++count; |
| } catch (final Exception ex) { |
| // Ignore an incorrect property. |
| continue; |
| } |
| } |
| if (count > 0) { |
| return opts; |
| } |
| } |
| return null; |
| |
| } |
| |
| @Override |
| public OutputStream getOutputStream(final URL url) throws ConfigurationException { |
| try { |
| final FileSystemOptions opts = getOptions(url.getProtocol()); |
| final FileObject file = getManager().resolveFile(url.toString(), opts); |
| // throw an exception if the target URL is a directory |
| if (file == null || file.isFolder()) { |
| throw new ConfigurationException("Cannot save a configuration to a directory"); |
| } |
| final FileContent content = file.getContent(); |
| |
| if (content == null) { |
| throw new ConfigurationException("Cannot access content of " + url); |
| } |
| return content.getOutputStream(); |
| } catch (final FileSystemException fse) { |
| throw new ConfigurationException("Unable to access " + url, fse); |
| } |
| } |
| |
| @Override |
| public String getPath(final File file, final URL url, final String basePath, final String fileName) { |
| if (file != null) { |
| return super.getPath(file, url, basePath, fileName); |
| } |
| try { |
| if (url != null) { |
| final FileName name = resolveURI(url.toString()); |
| if (name != null) { |
| return name.toString(); |
| } |
| } |
| if (UriParser.extractScheme(fileName) != null) { |
| return fileName; |
| } |
| if (basePath != null) { |
| final FileName base = resolveURI(basePath); |
| return getManager().resolveName(base, fileName).getURI(); |
| } |
| final FileName name = resolveURI(fileName); |
| final FileName base = name.getParent(); |
| return getManager().resolveName(base, name.getBaseName()).getURI(); |
| } catch (final FileSystemException fse) { |
| fse.printStackTrace(); |
| return null; |
| } |
| } |
| |
| @Override |
| public URL getURL(final String basePath, final String file) throws MalformedURLException { |
| if (basePath != null && UriParser.extractScheme(basePath) == null || basePath == null && UriParser.extractScheme(file) == null) { |
| return super.getURL(basePath, file); |
| } |
| try { |
| final FileName path; |
| if (basePath != null && UriParser.extractScheme(file) == null) { |
| final FileName base = resolveURI(basePath); |
| path = getManager().resolveName(base, file); |
| } else { |
| path = resolveURI(file); |
| } |
| |
| final URLStreamHandler handler = new VFSURLStreamHandler(); |
| return new URL(null, path.getURI(), handler); |
| } catch (final FileSystemException fse) { |
| throw new ConfigurationRuntimeException("Could not parse basePath: " + basePath + " and fileName: " + file, fse); |
| } |
| } |
| |
| @Override |
| public URL locateFromURL(final String basePath, final String fileName) { |
| final String fileScheme = UriParser.extractScheme(fileName); |
| // Use DefaultFileSystem if basePath and fileName don't have a scheme. |
| if ((basePath == null || UriParser.extractScheme(basePath) == null) && fileScheme == null) { |
| return super.locateFromURL(basePath, fileName); |
| } |
| try { |
| final FileObject file; |
| // Only use the base path if the file name doesn't have a scheme. |
| if (basePath != null && fileScheme == null) { |
| final String scheme = UriParser.extractScheme(basePath); |
| final FileSystemOptions opts = getOptions(scheme); |
| FileObject base = getManager().resolveFile(basePath, opts); |
| if (base.isFile()) { |
| base = base.getParent(); |
| } |
| |
| file = getManager().resolveFile(base, fileName); |
| } else { |
| final FileSystemOptions opts = getOptions(fileScheme); |
| file = getManager().resolveFile(fileName, opts); |
| } |
| |
| if (!file.exists()) { |
| return null; |
| } |
| final FileName path = file.getName(); |
| final URLStreamHandler handler = new VFSURLStreamHandler(); |
| return new URL(null, path.getURI(), handler); |
| } catch (final FileSystemException | MalformedURLException fse) { |
| return null; |
| } |
| } |
| |
| private FileName resolveURI(final String path) throws FileSystemException { |
| return getManager().resolveURI(path); |
| } |
| |
| private void setProperty(final FileSystemConfigBuilder builder, final FileSystemOptions options, final String key, final Object value) { |
| final String methodName = "set" + key.substring(0, 1).toUpperCase() + key.substring(1); |
| final Class<?>[] paramTypes = new Class<?>[2]; |
| paramTypes[0] = FileSystemOptions.class; |
| paramTypes[1] = value.getClass(); |
| try { |
| final Method method = builder.getClass().getMethod(methodName, paramTypes); |
| final Object[] params = new Object[2]; |
| params[0] = options; |
| params[1] = value; |
| method.invoke(builder, params); |
| } catch (final Exception ex) { |
| log.warn("Cannot access property '" + key + "'! Ignoring.", ex); |
| } |
| } |
| } |