DO NOT REPLY [Bug 35198] New: - [VFS] [PATCH] StandardFileSystemManager configure to use classloader URL object

classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

DO NOT REPLY [Bug 35198] New: - [VFS] [PATCH] StandardFileSystemManager configure to use classloader URL object

Bugzilla from bugzilla@apache.org
DO NOT REPLY TO THIS EMAIL, BUT PLEASE POST YOUR BUG?
RELATED COMMENTS THROUGH THE WEB INTERFACE AVAILABLE AT
<http://issues.apache.org/bugzilla/show_bug.cgi?id=35198>.
ANY REPLY MADE TO THIS MESSAGE WILL NOT BE COLLECTED AND?
INSERTED IN THE BUG DATABASE.

http://issues.apache.org/bugzilla/show_bug.cgi?id=35198

           Summary: [VFS] [PATCH] StandardFileSystemManager configure to use
                    classloader URL object
           Product: Commons
           Version: unspecified
          Platform: Other
        OS/Version: Linux
            Status: NEW
          Severity: normal
          Priority: P2
         Component: VFS
        AssignedTo: [hidden email]
        ReportedBy: [hidden email]


I'm writing an application with an OSGi framework that embeds VFS as a loadable
bundle. In the StandardFileSystem manager a call is made to get the
CONFIG_RESOURCE using getResource() in the classloader. The URL however is
converted to its external form before the call to config. Since it's in the
framework the URL is of the form bundle:// which causes the thing to upchuck
when the DocumentBuilder object tries to parse it. If instead a URL was used and
openStream to get an InputStream called, everything works fine. Below is the
source of the modified version with the configUri as a URL object.


/*
 * Copyright 2002-2005 The Apache Software Foundation.
 *
 * Licensed 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.vfs.impl;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.commons.vfs.FileSystemException;
import org.apache.commons.vfs.VfsLog;
import org.apache.commons.vfs.provider.FileProvider;
import org.apache.commons.vfs.util.Messages;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.net.URL;
import java.net.MalformedURLException;
import java.util.ArrayList;
import java.util.StringTokenizer;
import java.util.jar.JarFile;
import java.util.jar.JarEntry;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;

/**
 * A {@link org.apache.commons.vfs.FileSystemManager} that configures itself
 * from an XML (Default: providers.xml) configuration file.<br>
 * 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 <a href="mailto:[hidden email]">Adam Murdoch</a>
 * @version $Revision: 170205 $ $Date: 2005-05-15 08:21:59Z $
 */
public class StandardFileSystemManager
    extends DefaultFileSystemManager
{
    private Log log = LogFactory.getLog(StandardFileSystemManager.class);

    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.
     */
    public void setConfiguration(final String configUri)
    {
        try
        {
            this.configUri = new URL(configUri);
        }
        catch (MalformedURLException e)
        {
            log.warn(e.getLocalizedMessage(), e);
        }
    }

    /**
     * Sets the ClassLoader to use to load the providers.  Default is to
     * use the ClassLoader that loaded this class.
     */
    public void setClassLoader(final ClassLoader classLoader)
    {
        this.classLoader = classLoader;
    }

    /**
     * Initializes this manager.  Adds the providers and replicator.
     */
    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);

        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();

        // Initialise super-class
        super.init();
    }

    /**
     * Scans the classpath to find any droped plugin.<br />
     * The plugin-description has to be in /META-INF/vfs-providers.xml
     */
    protected void configurePlugins() throws FileSystemException
    {
        String classpath = System.getProperty("java.class.path");
        if (classpath == null)
        {
            // huh? why should that be?
            return;
        }
       
        StringTokenizer st = new StringTokenizer(classpath, File.pathSeparator,
false);
        while (st.hasMoreTokens())
        {
            String path = st.nextToken();

            if (path.length() > 4 &&
path.substring(path.length()-4).toLowerCase().equals(".jar"))
            {
                try
                {
                    JarFile jarFile = new JarFile(path);
                    JarEntry jarEntry = jarFile.getJarEntry(PLUGIN_CONFIG_RESOURCE);
                    if (jarEntry != null)
                    {
                        InputStream configStream = null;
                        try
                        {
                            configStream = jarFile.getInputStream(jarEntry);
                            configure(jarEntry.getName(), configStream);
                        }
                        finally
                        {
                            if (configStream != null)
                            {
                                configStream.close();
                            }
                        }
                    }
                }
                catch (FileSystemException e)
                {
                    // VFS exception - rethrow
                    // Need to do this as FileSystemException extends IOException
                    throw e;
                }
                catch (IOException e)
                {
                    // Maybe a damaged jar? Complain about but continue ...
                    log.warn(e.getLocalizedMessage(), e);
                }
            }
            else
            {
                File config = new File(path, PLUGIN_CONFIG_RESOURCE);
                if (config.exists() && config.canRead())
                {
                    try
                    {
                      configure(config.toURL());
                    }
                    catch (MalformedURLException e)
                    {
                      log.warn(e.getLocalizedMessage(), e);
                    }
                }
            }
        }
    }

    protected DefaultFileReplicator createDefaultFileReplicator()
    {
        return new DefaultFileReplicator();
    }

    /**
     * Configures this manager from an XML configuration file.
     */
    private void configure(final URL configUri) throws FileSystemException
    {
        try
        {
            // Load up the config
            // TODO - validate
            final DocumentBuilder builder = createDocumentBuilder();
            final Element config =
builder.parse(configUri.openStream()).getDocumentElement();

            configure(config);
        }
        catch (final Exception e)
        {
            throw new FileSystemException("vfs.impl/load-config.error",
configUri.toString(), e);
        }
    }

    /**
     * Configures this manager from an XML configuration file.
     */
    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
     */
    private DocumentBuilder createDocumentBuilder() throws
ParserConfigurationException
    {
        final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        factory.setIgnoringElementContentWhitespace(true);
        factory.setIgnoringComments(true);
        factory.setExpandEntityReferences(true);
        final DocumentBuilder builder = factory.newDocumentBuilder();
        return builder;
    }

    /**
     * Configures this manager from an parsed XML configuration file
     */
    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 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.
     */
    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.
     */
    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.
     */
    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(), log, 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(), log, msg);
                return;
            }
        }

        // Create and register the provider
        final FileProvider provider = createProvider(classname);
        final String[] schemas = getSchemas(providerDef);
        if (schemas.length > 0)
        {
            addProvider(schemas, provider);
        }

        // Set as default, if required
        if (isDefault)
        {
            setDefaultProvider(provider);
        }
    }

    /**
     * Tests if a class is available.
     */
    private boolean findClass(final String className)
    {
        try
        {
            classLoader.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 (String[]) 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 (String[]) 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 (String[]) schemas.toArray(new String[schemas.size()]);
    }

    /**
     * Creates a provider.
     */
    private FileProvider createProvider(final String providerClassName)
        throws FileSystemException
    {
        try
        {
            final Class providerClass = classLoader.loadClass(providerClassName);
            return (FileProvider) providerClass.newInstance();
        }
        catch (final Exception e)
        {
            throw new FileSystemException("vfs.impl/create-provider.error",
providerClassName, e);
        }
    }
}

--
Configure bugmail: http://issues.apache.org/bugzilla/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
You are the assignee for the bug, or are watching the assignee.

---------------------------------------------------------------------
To unsubscribe, e-mail: [hidden email]
For additional commands, e-mail: [hidden email]