4 Replies Latest reply on Feb 25, 2005 4:42 PM by starksm64

    VFS and ClassLoader interaction

    starksm64

      After looking at some existing VFS libraries and thinking about how class loading should be interacting with the VFS, I'm thinking a much simplified VFS api and URI based class loader that uses the VFS is what is needed. The two basic constructs are simply:

      package io;
      
      import java.net.URI;
      import java.util.List;
      import java.io.FileNotFoundException;
      
      
      /** Prototype for a read-only VFS where virtual files are represented by URIs.
       * A VFS is a tree of URIs segmented into paths by URI protocol.
       *
       * @author Scott.Stark@jboss.org
       * @version $Revision: 1.2 $
       */
      public interface ReadOnlyVFS
      {
       /**
       * Locate a file in the VFS given its URI path.
       *
       * @param path - the absolute path to the virtual file (file:/root/deploy/x.ear)
       * @return the matching VirtualFile
       * @throws FileNotFoundException throw if the path could not be resolved
       */
       public VirtualFile resolveFile(URI path)
       throws FileNotFoundException;
      
       /**
       * Locate a file in the VFS given a relative URI path and contexts in
       * the VFS to search from.
       *
       * @param path - a relative URI path (x.ear)
       * @param searchContexts - the absolute paths in the VFS of the contexts to search from
       * @return the matching VirtualFile
       * @throws FileNotFoundException throw if the path could not be resolved
       */
       public VirtualFile resolveFile(String path, List<URI> searchContexts)
       throws FileNotFoundException;
      
       /**
       * Find all files in the VFS matching the relative URI path.
       * @param path - a relative URI path (x.ear)
       * @return A possibly empty list of matching files
       */
       public List<VirtualFile> resolveFiles(String path);
       /**
       * Locate all files in the VFS given a relative URI path and contexts in
       * the VFS to search from.
       *
       * @param path - a relative URI path (x.ear)
       * @param searchContexts - the absolute paths in the VFS of the contexts to search from
       * @return A possibly empty list of matching files
       * @return A possibly empty list of matching files
       */
       public List<VirtualFile> resolveFiles(String path, List<URI> searchContexts);
      
      }
      
      


      /*
      * JBoss, the OpenSource J2EE webOS
      *
      * Distributable under LGPL license.
      * See terms of license at gnu.org.
      */
      package io;
      
      import java.security.SecureClassLoader;
      import java.net.URL;
      import java.net.URI;
      import java.net.MalformedURLException;
      import java.util.Enumeration;
      import java.util.ArrayList;
      import java.util.Arrays;
      import java.util.Vector;
      import java.util.jar.JarFile;
      import java.util.jar.JarEntry;
      import java.io.IOException;
      import java.io.ByteArrayOutputStream;
      import java.io.InputStream;
      
      /** A class loader that obtains classes and resources from a VFS.
       *
       * @author Scott.Stark@jboss.org
       * @version $Revision:$
       */
      public class VFSClassLoader extends SecureClassLoader
      {
       /**
       * Create a class loader given a search path and VFS
       * @param uris - the paths from the VFS that make up the class loader path
       * @param vfs - the VFS used to resolve and load classes and resources
       */
       public VFSClassLoader(URI[] uris, ReadOnlyVFS vfs)
       {
      ...
       }
      
       /**
       * Find and define the given java class
       *
       * @param name - the binary class name
       * @return the defined Class object
       * @throws ClassNotFoundException thrown if the class could not be found
       * or defined
       */
       protected Class<?> findClass(String name) throws ClassNotFoundException
       {
      ...
       }
      
       /**
       * Search for the resource in the VFS contraining the search to the
       * class loader paths.
       * @param name - the resource name
       * @return the resource URL if found, null otherwise
       */
       public URL findResource(String name)
       {
      ...
       }
      
       /**
       * Search for the resource in the VFS contraining the search to the
       * class loader paths.
       * @param name - the resource name
       * @return A possibly empty enumeration of the matching resources
       */
       public Enumeration<URL> findResources(String name) throws IOException
       {
      ..
       }
      }
      
      


      Some issues that are still not clear to me are:

      1. As I see it the existing DomainClassLoader needs to be layered on top of the VFS and could extend VFSClassLoader. Perhaps the DomainClassLoader should just encompass the VFS.

      2. One thing I want to get away from is the need to copy deployments. The two big issues requiring this currently are buggy URLClassLoader behavior, and nested jars. The first we can address with our own VFSClassLoader. The second requires a custom jar protocol handler that allows for nested jar URLs and the ability to traverse the nested zip streams efficiently. Whether this can be done efficiently and there are other issues that end up forcing unpacking of copies remains to be seen.


        • 1. Re: VFS and ClassLoader interaction

          First, I'm not especially tied to the DomainClassLoader.

          The main thing I need is a notion of dynamic package availabilty
          so the bean or deployment can say:

          <demand type="package">org.jboss.xxx</demand>
          
          it could also be specialized as
          
          <requires-packages>org.jboss.xxx,org.jboss.yyy</requires-packages>
          


          Then the bean is not attempted to be described (class analysed)
          until the package(s) is deployed.

          I achieved this in the prototype by making the classloader architecture
          register itself as KernelRegistryFactory for dependency checking.

          NOTE: The explicity demand is only intended for classes unknown
          to the BeanMetaData. i.e. it should be done automatically for the package
          of the bean class, etc.

          • 2. Re: VFS and ClassLoader interaction

            I think I mentioned this before, but I will repeat it anyway...

            I did at one point start to write a replacement for URLClassLoader
            to workaround Sun's bugs.
            Most of the work is just delegating to URLHandlers (which would obviously
            be replaced by the VFS in the current discussion).

            However, I couldn't find an open source implementation of the "encryption"
            used to sign jars.

            The other reason I wanted such an implementation was so we can do signing
            of unpacked deployments (the signing is currently only checked on packed jar files).

            • 3. Re: VFS and ClassLoader interaction
              starksm64

              Bouncycastle has all that is needed if its not in the bundled jce classes yet (and I think it is). It will be simple to create our own jar signing tool that is compatible with the default one. I have been thinking about needing to augment the build process anyway with a more advanced indexing tool that would get rid of the current runtime processing of at least the distribution jars as they are loaded.

              I'll look at merging the VFS notions with the existing classes and create testcases around signing, security, nested jars, file and http filesystems and single domain classpath ordering as the basis for really knowing what the classloading should look like. Beyond that, interaction of domains and exclusion of certain classes from being overriden by child domains needs to be flushed out.

              • 4. Re: VFS and ClassLoader interaction
                starksm64

                One other minor note on the current Set getPackages() method signature of DomainClassLoader. This precludes the DomainClassLoader implementation from being a subclass of ClassLoader due to its Package[] getPackages() method. We might as well use that signature as I don't see a reason to disallow the DomainClassLoader implementation from being a ClassLoader.