/* * 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.vfs2.impl; import java.io.IOException; import java.io.InputStream; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import java.util.Enumeration; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import org.apache.commons.vfs2.CacheStrategy; import org.apache.commons.vfs2.FileSystemException; import org.apache.commons.vfs2.VfsLog; import org.apache.commons.vfs2.operations.FileOperationProvider; import org.apache.commons.vfs2.provider.FileProvider; import org.apache.commons.vfs2.util.Messages; import org.w3c.dom.Element; import org.w3c.dom.NodeList; /** * A {@link org.apache.commons.vfs2.FileSystemManager} that configures itself * from an XML (Default: providers.xml) configuration file.
* Certain providers are only loaded and available if the dependend library is in your * classpath. You have to configure your debugging facility to log "debug" messages to see * if a provider was skipped due to "unresolved externals". * * @author Commons VFS team */ public class StandardFileSystemManager extends DefaultFileSystemManager { private static final String CONFIG_RESOURCE = "providers.xml"; private static final String PLUGIN_CONFIG_RESOURCE = "META-INF/vfs-providers.xml"; private URL configUri; private ClassLoader classLoader; /** * Sets the configuration file for this manager. * @param configUri The URI for this manager. */ public void setConfiguration(final String configUri) { try { setConfiguration(new URL(configUri)); } catch (MalformedURLException e) { getLogger().warn(e.getLocalizedMessage(), e); } } /** * Sets the configuration file for this manager. * @param configUri The URI forthis manager. */ public void setConfiguration(final URL configUri) { this.configUri = configUri; } /** * Sets the ClassLoader to use to load the providers. Default is to * use the ClassLoader that loaded this class. * @param classLoader The ClassLoader. */ public void setClassLoader(final ClassLoader classLoader) { this.classLoader = classLoader; } /** * Initializes this manager. Adds the providers and replicator. * @throws FileSystemException if an error occurs. */ @Override public void init() throws FileSystemException { // Set the replicator and temporary file store (use the same component) final DefaultFileReplicator replicator = createDefaultFileReplicator(); setReplicator(new PrivilegedFileReplicator(replicator)); setTemporaryFileStore(replicator); /* replaced by findClassLoader if (classLoader == null) { // Use default classloader classLoader = getClass().getClassLoader(); } */ if (configUri == null) { // Use default config final URL url = getClass().getResource(CONFIG_RESOURCE); if (url == null) { throw new FileSystemException("vfs.impl/find-config-file.error", CONFIG_RESOURCE); } configUri = url; } // Configure configure(configUri); // Configure Plugins configurePlugins(); setCacheStrategy(CacheStrategy.ON_CALL); // Initialise super-class super.init(); } /** * Scans the classpath to find any droped plugin.
* The plugin-description has to be in /META-INF/vfs-providers.xml * @throws FileSystemException if an error occurs. */ protected void configurePlugins() throws FileSystemException { ClassLoader cl = findClassLoader(); Enumeration enumResources; try { enumResources = cl.getResources(PLUGIN_CONFIG_RESOURCE); } catch (IOException e) { throw new FileSystemException(e); } while (enumResources.hasMoreElements()) { URL url = enumResources.nextElement(); configure(url); } } private ClassLoader findClassLoader() { if (classLoader != null) { return classLoader; } ClassLoader cl = Thread.currentThread().getContextClassLoader(); if (cl == null) { cl = getClass().getClassLoader(); } return cl; } protected DefaultFileReplicator createDefaultFileReplicator() { return new DefaultFileReplicator(); } /** * Configures this manager from an XML configuration file. * @param configUri The URI of the configuration. * @throws FileSystemException if an error occus. */ private void configure(final URL configUri) throws FileSystemException { InputStream configStream = null; try { // Load up the config // TODO - validate /* final DocumentBuilder builder = createDocumentBuilder(); configStream = configUri.openStream(); final Element config = builder.parse(configStream).getDocumentElement(); configure(config); */ hardCodedConfiguration(); } catch (final Exception e) { throw new FileSystemException("vfs.impl/load-config.error", configUri.toString(), e); } finally { if (configStream != null) { try { configStream.close(); } catch (IOException e) { getLogger().warn(e.getLocalizedMessage(), e); } } } } private void hardCodedConfiguration() throws FileSystemException { //addProvider(providerClassName, schemas, ifAvailableClasses, ifAvailableSchemas, isDefault); addProvider("org.apache.commons.vfs2.provider.url.UrlFileProvider", null, null, null, true); addProvider("org.apache.commons.vfs2.provider.local.DefaultLocalFileProvider", new String[]{"file"}, null, null, false); addProvider("org.apache.commons.vfs2.provider.zip.ZipFileProvider", new String[]{"zip"}, null, null, false); addProvider("org.apache.commons.vfs2.provider.tar.TarFileProvider", new String[]{"tar"}, new String[] {"org.apache.commons.vfs2.provider.tar.TarInputStream"}, null, false); addProvider("org.apache.commons.vfs2.provider.bzip2.Bzip2FileProvider", new String[]{"bz2"}, new String[] {"org.apache.commons.vfs2.provider.bzip2.CBZip2InputStream"}, null, false); addProvider("org.apache.commons.vfs2.provider.gzip.GzipFileProvider", new String[]{"gz"}, null, null, false); addProvider("org.apache.commons.vfs2.provider.jar.JarFileProvider", new String[]{"jar", "sar", "ear", "par", "ejb3", "war"}, null, null, false); addProvider("org.apache.commons.vfs2.provider.temp.TemporaryFileProvider", new String[]{"tmp"}, null, null, false); addProvider("org.apache.commons.vfs2.provider.ftp.FtpFileProvider", new String[]{"ftp"}, new String[] {"org.apache.commons.net.ftp.FTPFile"}, null, false); addProvider("org.apache.commons.vfs2.provider.ftps.FtpsFileProvider", new String[]{"ftps"}, new String[] {"org.apache.commons.net.ftp.FTPFile"}, null, false); addProvider("org.apache.commons.vfs2.provider.http.HttpFileProvider", new String[]{"http"}, new String[] {"org.apache.commons.httpclient.HttpClient"}, null, false); addProvider("org.apache.commons.vfs2.provider.https.HttpsFileProvider", new String[]{"https"}, new String[] {"org.apache.commons.httpclient.HttpClient"}, null, false); addProvider("org.apache.commons.vfs2.provider.sftp.SftpFileProvider", new String[]{"sftp"}, new String[] {"javax.crypto.Cipher","com.jcraft.jsch.JSch"}, null, false); addProvider("org.apache.commons.vfs2.provider.res.ResourceFileProvider", new String[]{"res"}, null, null, false); addProvider("org.apache.commons.vfs2.provider.webdav.WebdavFileProvider", new String[]{"webdav"}, new String[] {"org.apache.commons.httpclient.HttpClient", "org.apache.jackrabbit.webdav.client.methods.DavMethod"}, null, false); addProvider("org.apache.commons.vfs2.provider.tar.TarFileProvider", new String[]{"tbz2"}, null, new String[] {"bz2", "tar"}, false); addProvider("org.apache.commons.vfs2.provider.ram.RamFileProvider", new String[]{"ram"}, null, null, false); addMimeTypeMap("application/zip", "zip"); addMimeTypeMap("application/x-tar", "tar"); addMimeTypeMap("application/x-gzip", "gz"); addExtensionMap("zip", "zip"); addExtensionMap("tar", "tar"); addExtensionMap("jar", "jar"); addExtensionMap("bz2", "bz2"); addExtensionMap("gz", "gz"); addExtensionMap("tgz", "tar"); addExtensionMap("tbz2", "tar"); addExtensionMap("jar", "jar"); } private void addProvider(String providerClassName, String[] schemas, String[] requiredClasses, String[] requiredSchemes, boolean isDefault) throws FileSystemException { // Make sure all required schemes are available if (requiredSchemes != null) for (int i = 0; i < requiredSchemes.length; i++) { final String requiredScheme = requiredSchemes[i]; if (!hasProvider(requiredScheme)) { final String msg = Messages.getString("vfs.impl/skipping-provider-scheme.debug", new String[]{providerClassName, requiredScheme}); VfsLog.debug(getLogger(), getLogger(), msg); return; } } // Make sure all required classes are in classpath if (requiredClasses != null) for (int i = 0; i < requiredClasses.length; i++) { final String requiredClass = requiredClasses[i]; if (!findClass(requiredClass)) { final String msg = Messages.getString("vfs.impl/skipping-provider.debug", new String[]{providerClassName, requiredClass}); VfsLog.debug(getLogger(), getLogger(), msg); return; } } // Create and register the provider final FileProvider provider = (FileProvider) createInstance(providerClassName); if (schemas != null && schemas.length > 0) { addProvider(schemas, provider); } // Set as default, if required if (isDefault) { setDefaultProvider(provider); } } /** * Configures this manager from an XML configuration file. * @param configUri The URI of the configuration. * @param configStream An InputStream containing the configuration. * @throws FileSystemException if an error occurs. */ @SuppressWarnings("unused") private void configure(final String configUri, final InputStream configStream) throws FileSystemException { try { // Load up the config // TODO - validate final DocumentBuilder builder = createDocumentBuilder(); final Element config = builder.parse(configStream).getDocumentElement(); configure(config); } catch (final Exception e) { throw new FileSystemException("vfs.impl/load-config.error", configUri, e); } } /** * Configure and create a DocumentBuilder * @return A DocumentBuilder for the configuration. * @throws ParserConfigurationException if an error occurs. */ private DocumentBuilder createDocumentBuilder() throws ParserConfigurationException { final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); factory.setIgnoringElementContentWhitespace(true); factory.setIgnoringComments(true); factory.setExpandEntityReferences(true); return factory.newDocumentBuilder(); } /** * Configures this manager from an parsed XML configuration file * @param config The configuration Element. * @throws FileSystemException if an error occurs. */ private void configure(final Element config) throws FileSystemException { // Add the providers final NodeList providers = config.getElementsByTagName("provider"); final int count = providers.getLength(); for (int i = 0; i < count; i++) { final Element provider = (Element) providers.item(i); addProvider(provider, false); } // Add the operation providers final NodeList operationProviders = config.getElementsByTagName("operationProvider"); for (int i = 0; i < operationProviders.getLength(); i++) { final Element operationProvider = (Element) operationProviders.item(i); addOperationProvider(operationProvider); } // Add the default provider final NodeList defProviders = config.getElementsByTagName("default-provider"); if (defProviders.getLength() > 0) { final Element provider = (Element) defProviders.item(0); addProvider(provider, true); } // Add the mime-type maps final NodeList mimeTypes = config.getElementsByTagName("mime-type-map"); for (int i = 0; i < mimeTypes.getLength(); i++) { final Element map = (Element) mimeTypes.item(i); addMimeTypeMap(map); } // Add the extension maps final NodeList extensions = config.getElementsByTagName("extension-map"); for (int i = 0; i < extensions.getLength(); i++) { final Element map = (Element) extensions.item(i); addExtensionMap(map); } } /** * Adds an extension map. * @param map containing the Elements. */ private void addExtensionMap(final Element map) { final String extension = map.getAttribute("extension"); final String scheme = map.getAttribute("scheme"); if (scheme != null && scheme.length() > 0) { addExtensionMap(extension, scheme); } } /** * Adds a mime-type map. * @param map containing the Elements. */ private void addMimeTypeMap(final Element map) { final String mimeType = map.getAttribute("mime-type"); final String scheme = map.getAttribute("scheme"); addMimeTypeMap(mimeType, scheme); } /** * Adds a provider from a provider definition. * @param providerDef the provider definition * @param isDefault true if the default should be used. * @throws FileSystemException if an error occurs. */ private void addProvider(final Element providerDef, final boolean isDefault) throws FileSystemException { final String classname = providerDef.getAttribute("class-name"); // Make sure all required schemes are available final String[] requiredSchemes = getRequiredSchemes(providerDef); for (int i = 0; i < requiredSchemes.length; i++) { final String requiredScheme = requiredSchemes[i]; if (!hasProvider(requiredScheme)) { final String msg = Messages.getString("vfs.impl/skipping-provider-scheme.debug", new String[]{classname, requiredScheme}); VfsLog.debug(getLogger(), getLogger(), msg); return; } } // Make sure all required classes are in classpath final String[] requiredClasses = getRequiredClasses(providerDef); for (int i = 0; i < requiredClasses.length; i++) { final String requiredClass = requiredClasses[i]; if (!findClass(requiredClass)) { final String msg = Messages.getString("vfs.impl/skipping-provider.debug", new String[]{classname, requiredClass}); VfsLog.debug(getLogger(), getLogger(), msg); return; } } // Create and register the provider final FileProvider provider = (FileProvider) createInstance(classname); final String[] schemas = getSchemas(providerDef); if (schemas.length > 0) { addProvider(schemas, provider); } // Set as default, if required if (isDefault) { setDefaultProvider(provider); } } /** * Adds a operationProvider from a operationProvider definition. */ private void addOperationProvider(final Element providerDef) throws FileSystemException { final String classname = providerDef.getAttribute("class-name"); // Attach only to available schemas final String[] schemas = getSchemas(providerDef); for (int i = 0; i < schemas.length; i++) { final String schema = schemas[i]; if (hasProvider(schema)) { final FileOperationProvider operationProvider = (FileOperationProvider) createInstance(classname); addOperationProvider(schema, operationProvider); } } } /** * Tests if a class is available. */ private boolean findClass(final String className) { try { findClassLoader().loadClass(className); return true; } catch (final ClassNotFoundException e) { return false; } } /** * Extracts the required classes from a provider definition. */ private String[] getRequiredClasses(final Element providerDef) { final ArrayList classes = new ArrayList(); final NodeList deps = providerDef.getElementsByTagName("if-available"); final int count = deps.getLength(); for (int i = 0; i < count; i++) { final Element dep = (Element) deps.item(i); String className = dep.getAttribute("class-name"); if (className != null && className.length() > 0) { classes.add(className); } } return classes.toArray(new String[classes.size()]); } /** * Extracts the required schemes from a provider definition. */ private String[] getRequiredSchemes(final Element providerDef) { final ArrayList schemes = new ArrayList(); final NodeList deps = providerDef.getElementsByTagName("if-available"); final int count = deps.getLength(); for (int i = 0; i < count; i++) { final Element dep = (Element) deps.item(i); String scheme = dep.getAttribute("scheme"); if (scheme != null && scheme.length() > 0) { schemes.add(scheme); } } return schemes.toArray(new String[schemes.size()]); } /** * Extracts the schema names from a provider definition. */ private String[] getSchemas(final Element provider) { final ArrayList schemas = new ArrayList(); final NodeList schemaElements = provider.getElementsByTagName("scheme"); final int count = schemaElements.getLength(); for (int i = 0; i < count; i++) { final Element scheme = (Element) schemaElements.item(i); schemas.add(scheme.getAttribute("name")); } return schemas.toArray(new String[schemas.size()]); } /** * Creates a provider. */ private Object createInstance(final String className) throws FileSystemException { try { final Class clazz = findClassLoader().loadClass(className); return clazz.newInstance(); } catch (final Exception e) { throw new FileSystemException("vfs.impl/create-provider.error", className, e); } } }