[Jboss-cvs] JBossAS SVN: r56599 - in	projects/microcontainer/trunk/container/src: main/org/jboss	main/org/jboss/virtual main/org/jboss/virtual/plugins	main/org/jboss/virtual/plugins/context	main/org/jboss/virtual/plugins/context/file	main/org/jboss/virtual/plugins/context/jar	main/org/jboss/virtual/plugins/vfs	main/org/jboss/virtual/plugins/vfs/helpers	main/org/jboss/virtual/spi tests/org/jboss/test	tests/org/jboss/test/virtual tests/org/jboss/test/virtual/test
    jboss-cvs-commits at lists.jboss.org 
    jboss-cvs-commits at lists.jboss.org
       
    Wed Sep  6 07:27:18 EDT 2006
    
    
  
Author: adrian at jboss.org
Date: 2006-09-06 07:27:07 -0400 (Wed, 06 Sep 2006)
New Revision: 56599
Added:
   projects/microcontainer/trunk/container/src/main/org/jboss/virtual/
   projects/microcontainer/trunk/container/src/main/org/jboss/virtual/VFS.java
   projects/microcontainer/trunk/container/src/main/org/jboss/virtual/VFSUtils.java
   projects/microcontainer/trunk/container/src/main/org/jboss/virtual/VirtualFile.java
   projects/microcontainer/trunk/container/src/main/org/jboss/virtual/VirtualFileFilter.java
   projects/microcontainer/trunk/container/src/main/org/jboss/virtual/VirtualFileFilterWithAttributes.java
   projects/microcontainer/trunk/container/src/main/org/jboss/virtual/VirtualFileVisitor.java
   projects/microcontainer/trunk/container/src/main/org/jboss/virtual/VisitorAttributes.java
   projects/microcontainer/trunk/container/src/main/org/jboss/virtual/plugins/
   projects/microcontainer/trunk/container/src/main/org/jboss/virtual/plugins/context/
   projects/microcontainer/trunk/container/src/main/org/jboss/virtual/plugins/context/AbstractURLHandler.java
   projects/microcontainer/trunk/container/src/main/org/jboss/virtual/plugins/context/AbstractVFSContext.java
   projects/microcontainer/trunk/container/src/main/org/jboss/virtual/plugins/context/AbstractVirtualFileHandler.java
   projects/microcontainer/trunk/container/src/main/org/jboss/virtual/plugins/context/StructuredVirtualFileHandler.java
   projects/microcontainer/trunk/container/src/main/org/jboss/virtual/plugins/context/file/
   projects/microcontainer/trunk/container/src/main/org/jboss/virtual/plugins/context/file/FileHandler.java
   projects/microcontainer/trunk/container/src/main/org/jboss/virtual/plugins/context/file/FileSystemContext.java
   projects/microcontainer/trunk/container/src/main/org/jboss/virtual/plugins/context/file/FileSystemContextFactory.java
   projects/microcontainer/trunk/container/src/main/org/jboss/virtual/plugins/context/jar/
   projects/microcontainer/trunk/container/src/main/org/jboss/virtual/plugins/context/jar/AbstractJarHandler.java
   projects/microcontainer/trunk/container/src/main/org/jboss/virtual/plugins/context/jar/JarContext.java
   projects/microcontainer/trunk/container/src/main/org/jboss/virtual/plugins/context/jar/JarContextFactory.java
   projects/microcontainer/trunk/container/src/main/org/jboss/virtual/plugins/context/jar/JarEntryHandler.java
   projects/microcontainer/trunk/container/src/main/org/jboss/virtual/plugins/context/jar/JarHandler.java
   projects/microcontainer/trunk/container/src/main/org/jboss/virtual/plugins/context/jar/JarUtils.java
   projects/microcontainer/trunk/container/src/main/org/jboss/virtual/plugins/context/jar/NestedJarHandler.java
   projects/microcontainer/trunk/container/src/main/org/jboss/virtual/plugins/vfs/
   projects/microcontainer/trunk/container/src/main/org/jboss/virtual/plugins/vfs/helpers/
   projects/microcontainer/trunk/container/src/main/org/jboss/virtual/plugins/vfs/helpers/AbstractVirtualFileHandlerVisitor.java
   projects/microcontainer/trunk/container/src/main/org/jboss/virtual/plugins/vfs/helpers/AbstractVirtualFileVisitor.java
   projects/microcontainer/trunk/container/src/main/org/jboss/virtual/plugins/vfs/helpers/FilterVirtualFileVisitor.java
   projects/microcontainer/trunk/container/src/main/org/jboss/virtual/plugins/vfs/helpers/MatchAllVirtualFileFilter.java
   projects/microcontainer/trunk/container/src/main/org/jboss/virtual/plugins/vfs/helpers/PathTokenizer.java
   projects/microcontainer/trunk/container/src/main/org/jboss/virtual/plugins/vfs/helpers/SuffixMatchFilter.java
   projects/microcontainer/trunk/container/src/main/org/jboss/virtual/plugins/vfs/helpers/WrappingVirtualFileHandlerVisitor.java
   projects/microcontainer/trunk/container/src/main/org/jboss/virtual/spi/
   projects/microcontainer/trunk/container/src/main/org/jboss/virtual/spi/VFSContext.java
   projects/microcontainer/trunk/container/src/main/org/jboss/virtual/spi/VFSContextFactory.java
   projects/microcontainer/trunk/container/src/main/org/jboss/virtual/spi/VFSContextFactoryLocator.java
   projects/microcontainer/trunk/container/src/main/org/jboss/virtual/spi/VirtualFileHandler.java
   projects/microcontainer/trunk/container/src/main/org/jboss/virtual/spi/VirtualFileHandlerVisitor.java
   projects/microcontainer/trunk/container/src/tests/org/jboss/test/virtual/
   projects/microcontainer/trunk/container/src/tests/org/jboss/test/virtual/test/
   projects/microcontainer/trunk/container/src/tests/org/jboss/test/virtual/test/SimpleTest.java
   projects/microcontainer/trunk/container/src/tests/org/jboss/test/virtual/test/SundryVFSTests.java
   projects/microcontainer/trunk/container/src/tests/org/jboss/test/virtual/test/TestFileVFS.java
Log:
[JBMICROCONT-57] - Refactored VFS prototype. Needs a lot more tests!
Added: projects/microcontainer/trunk/container/src/main/org/jboss/virtual/VFS.java
===================================================================
--- projects/microcontainer/trunk/container/src/main/org/jboss/virtual/VFS.java	2006-09-06 11:18:17 UTC (rev 56598)
+++ projects/microcontainer/trunk/container/src/main/org/jboss/virtual/VFS.java	2006-09-06 11:27:07 UTC (rev 56599)
@@ -0,0 +1,269 @@
+/*
+* JBoss, Home of Professional Open Source
+* Copyright 2006, JBoss Inc., and individual contributors as indicated
+* by the @authors tag. See the copyright.txt in the distribution for a
+* full listing of individual contributors.
+*
+* This is free software; you can redistribute it and/or modify it
+* under the terms of the GNU Lesser General Public License as
+* published by the Free Software Foundation; either version 2.1 of
+* the License, or (at your option) any later version.
+*
+* This software is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public
+* License along with this software; if not, write to the Free
+* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+*/
+package org.jboss.virtual;
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.List;
+
+import org.jboss.virtual.plugins.vfs.helpers.WrappingVirtualFileHandlerVisitor;
+import org.jboss.virtual.spi.VFSContext;
+import org.jboss.virtual.spi.VFSContextFactory;
+import org.jboss.virtual.spi.VFSContextFactoryLocator;
+import org.jboss.virtual.spi.VirtualFileHandler;
+
+/**
+ * Virtual File System
+ * 
+ * @author <a href="adrian at jboss.com">Adrian Brock</a>
+ * @version $Revision: 1.1 $
+ */
+public class VFS
+{
+   /** The VFS Context */
+   private final VFSContext context;
+
+   /**
+    * Get the virtual file system for a root url
+    * 
+    * @param rootURL the root url
+    * @return the virtual file system
+    * @throws IOException if there is a problem accessing the VFS
+    * @throws IllegalArgumentException if the rootURL is null
+    */
+   public static VFS getVFS(URL rootURL) throws IOException
+   {
+      VFSContextFactory factory = VFSContextFactoryLocator.getFactory(rootURL);
+      VFSContext context = factory.getVFS(rootURL);
+      return context.getVFS();
+   }
+
+   /**
+    * Get a virtual file
+    * 
+    * @param rootURL the root url
+    * @param name the path name
+    * @return the virtual file
+    * @throws IOException if there is a problem accessing the VFS
+    * @throws IllegalArgumentException if the rootURL or name is null
+    */
+   public static VirtualFile getVirtualFile(URL rootURL, String name) throws IOException
+   {
+      VFS vfs = getVFS(rootURL);
+      return vfs.findChildFromRoot(name);
+   }
+
+   /**
+    * Create a new VFS.
+    * 
+    * @param context the context
+    * @throws IllegalArgumentException for a null context
+    */
+   public VFS(VFSContext context)
+   {
+      if (context == null)
+         throw new IllegalArgumentException("Null name");
+      this.context = context;
+   }
+   
+   /**
+    * Get the root file of this VFS
+    * 
+    * @return the root
+    * @throws IOException for any problem accessing the VFS
+    */
+   public VirtualFile getRoot() throws IOException
+   {
+      VirtualFileHandler handler = context.getRoot();
+      return handler.getVirtualFile();
+   }
+   
+   /**
+    * Get a parent
+    * 
+    * @param child the child
+    * @return the parent or null if there is no parent
+    * @throws IOException for any problem accessing the VFS (including the child does not exist)
+    * @throws IllegalArgumentException if the child is null
+    */
+   public VirtualFile getParent(VirtualFile child) throws IOException
+   {
+      if (child == null)
+         throw new IllegalArgumentException("Null parent");
+         
+      VirtualFileHandler handler = child.getHandler();
+      VirtualFileHandler parent = handler.getParent();
+      return parent.getVirtualFile();
+   }
+   
+   /**
+    * Find a child
+    * 
+    * @param parent the context file
+    * @param path the child path
+    * @return the child
+    * @throws IOException for any problem accessing the VFS (including the child does not exist)
+    * @throws IllegalArgumentException if the parent or path is null
+    */
+   public VirtualFile findChild(VirtualFile parent, String path) throws IOException
+   {
+      if (parent == null)
+         throw new IllegalArgumentException("Null parent");
+      if (path == null)
+         throw new IllegalArgumentException("Null path");
+      
+      VirtualFileHandler handler = parent.getHandler();
+      VFSContext handlerContext = handler.getVFSContext();
+      path = VFSUtils.fixName(path);
+      VirtualFileHandler result = handlerContext.findChild(handler, path);
+      return result.getVirtualFile();
+   }
+   
+   /**
+    * Find a child from the root
+    * 
+    * @param path the child path
+    * @return the child
+    * @throws IOException for any problem accessing the VFS (including the child does not exist)
+    * @throws IllegalArgumentException if the path is null
+    */
+   public VirtualFile findChildFromRoot(String path) throws IOException
+   {
+      if (path == null)
+         throw new IllegalArgumentException("Null path");
+      
+      VirtualFileHandler handler = context.getRoot();
+      path = VFSUtils.fixName(path);
+      VirtualFileHandler result = context.findChild(handler, path);
+      return result.getVirtualFile();
+   }
+   
+   /**
+    * Get the children
+    * 
+    * @return the children
+    * @throws IOException for any problem accessing the virtual file system
+    * @throws IllegalStateException if the file is closed
+    */
+   public List<VirtualFile> getChildren() throws IOException
+   {
+      return getRoot().getChildren(null);
+   }
+
+   /**
+    * Get the children
+    * 
+    * @param filter to filter the children
+    * @return the children
+    * @throws IOException for any problem accessing the virtual file system
+    * @throws IllegalStateException if the file is closed or it is not a directory
+    */
+   public List<VirtualFile> getChildren(VirtualFileFilter filter) throws IOException
+   {
+      return getRoot().getChildren(filter);
+   }
+   
+   /**
+    * Get all the children recursively<p>
+    * 
+    * This always uses {@link VisitorAttributes#RECURSE_DIRECTORIES}
+    * 
+    * @return the children
+    * @throws IOException for any problem accessing the virtual file system
+    * @throws IllegalStateException if the file is closed
+    */
+   public List<VirtualFile> getChildrenRecursively() throws IOException
+   {
+      return getRoot().getChildrenRecursively(null);
+   }
+   
+   /**
+    * Get all the children recursively<p>
+    * 
+    * This always uses {@link VisitorAttributes#RECURSE_DIRECTORIES}
+    * 
+    * @param filter to filter the children
+    * @return the children
+    * @throws IOException for any problem accessing the virtual file system
+    * @throws IllegalStateException if the file is closed or it is not a directory
+    */
+   public List<VirtualFile> getChildrenRecursively(VirtualFileFilter filter) throws IOException
+   {
+      return getRoot().getChildrenRecursively(filter);
+   }
+   
+   /**
+    * Visit the virtual file system from the root
+    * 
+    * @param visitor the visitor
+    * @throws IOException for any problem accessing the VFS
+    * @throws IllegalArgumentException if the visitor is null
+    */
+   public void visit(VirtualFileVisitor visitor) throws IOException
+   {
+      VirtualFileHandler handler = context.getRoot();
+      WrappingVirtualFileHandlerVisitor wrapper = new WrappingVirtualFileHandlerVisitor(visitor);
+      context.visit(handler, wrapper);
+   }
+
+   /**
+    * Visit the virtual file system
+    * 
+    * @param file the file
+    * @param visitor the visitor
+    * @throws IOException for any problem accessing the VFS
+    * @throws IllegalArgumentException if the file or visitor is null
+    */
+   public void visit(VirtualFile file, VirtualFileVisitor visitor) throws IOException
+   {
+      if (file == null)
+         throw new IllegalArgumentException("Null file");
+
+      VirtualFileHandler handler = file.getHandler();
+      WrappingVirtualFileHandlerVisitor wrapper = new WrappingVirtualFileHandlerVisitor(visitor);
+      VFSContext handlerContext = handler.getVFSContext();
+      handlerContext.visit(handler, wrapper);
+   }
+
+   @Override
+   public String toString()
+   {
+      return context.toString();
+   }
+
+   @Override
+   public int hashCode()
+   {
+      return context.hashCode();
+   }
+   
+   @Override
+   public boolean equals(Object obj)
+   {
+      if (obj == this)
+         return true;
+      if (obj == null || obj instanceof VFS == false)
+         return false;
+      VFS other = (VFS) obj;
+      return context.equals(other.context);
+   }
+}
Added: projects/microcontainer/trunk/container/src/main/org/jboss/virtual/VFSUtils.java
===================================================================
--- projects/microcontainer/trunk/container/src/main/org/jboss/virtual/VFSUtils.java	2006-09-06 11:18:17 UTC (rev 56598)
+++ projects/microcontainer/trunk/container/src/main/org/jboss/virtual/VFSUtils.java	2006-09-06 11:27:07 UTC (rev 56599)
@@ -0,0 +1,117 @@
+/*
+* JBoss, Home of Professional Open Source
+* Copyright 2006, JBoss Inc., and individual contributors as indicated
+* by the @authors tag. See the copyright.txt in the distribution for a
+* full listing of individual contributors.
+*
+* This is free software; you can redistribute it and/or modify it
+* under the terms of the GNU Lesser General Public License as
+* published by the Free Software Foundation; either version 2.1 of
+* the License, or (at your option) any later version.
+*
+* This software is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public
+* License along with this software; if not, write to the Free
+* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+*/
+package org.jboss.virtual;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.jar.JarFile;
+import java.util.jar.Manifest;
+
+import org.jboss.logging.Logger;
+
+/**
+ * VFS Utilities
+ * 
+ * @author <a href="adrian at jboss.com">Adrian Brock</a>
+ * @version $Revision: 1.1 $
+ */
+public class VFSUtils
+{
+   /** The log */
+   private static final Logger log = Logger.getLogger(VFSUtils.class);
+   
+   /**
+    * Get a manifest from a virtual file,
+    * assuming the virtual file is the root of an archive
+    * 
+    * @param archive the root the archive
+    * @return the manifest or null if not found
+    * @throws IOException if there is an error reading the manifest or the
+    *         virtual file is closed
+    * @throws IllegalArgumentException for a null archive or it is not an archive
+    */
+   public Manifest getManifest(VirtualFile archive) throws IOException
+   {
+      if (archive == null)
+         throw new IllegalArgumentException("Null archive");
+      if (archive.isArchive() == false)
+         throw new IllegalArgumentException("Not an archive: " + archive);
+      
+      VirtualFile manifest;
+      try
+      {
+         manifest = archive.findChild(JarFile.MANIFEST_NAME); 
+      }
+      catch (IOException ignored)
+      {
+         log.debug("Can't find manifest for " + archive);
+         return null;
+      }
+
+      InputStream stream = manifest.openStream();
+      try
+      {
+         return new Manifest(stream);
+      }
+      finally
+      {
+         try
+         {
+            stream.close();
+         }
+         catch (IOException ignored)
+         {
+         }
+      }
+   }
+   
+   /**
+    * Get a manifest from a virtual file system,
+    * assuming the root of the VFS is the root of an archive
+    * 
+    * @param archive the vfs
+    * @return the manifest or null if not found
+    * @throws IOException if there is an error reading the manifest
+    * @throws IllegalArgumentException for a null archive
+    */
+   public Manifest getManifest(VFS archive) throws IOException
+   {
+      VirtualFile root = archive.getRoot();
+      return getManifest(root);
+   }
+   
+   /**
+    * Fix a name (removes any trailing slash)
+    * 
+    * @param name the name to fix
+    * @return the fixed name
+    */
+   public static String fixName(String name)
+   {
+      int length = name.length();
+      if (length <= 1)
+         return name;
+      if (name.charAt(length-1) == '/')
+         return name.substring(0, length-1);
+      return name;
+   }
+}
Added: projects/microcontainer/trunk/container/src/main/org/jboss/virtual/VirtualFile.java
===================================================================
--- projects/microcontainer/trunk/container/src/main/org/jboss/virtual/VirtualFile.java	2006-09-06 11:18:17 UTC (rev 56598)
+++ projects/microcontainer/trunk/container/src/main/org/jboss/virtual/VirtualFile.java	2006-09-06 11:27:07 UTC (rev 56599)
@@ -0,0 +1,393 @@
+/*
+  * JBoss, Home of Professional Open Source
+  * Copyright 2005, JBoss Inc., and individual contributors as indicated
+  * by the @authors tag. See the copyright.txt in the distribution for a
+  * full listing of individual contributors.
+  *
+  * This is free software; you can redistribute it and/or modify it
+  * under the terms of the GNU Lesser General Public License as
+  * published by the Free Software Foundation; either version 2.1 of
+  * the License, or (at your option) any later version.
+  *
+  * This software is distributed in the hope that it will be useful,
+  * but WITHOUT ANY WARRANTY; without even the implied warranty of
+  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  * Lesser General Public License for more details.
+  *
+  * You should have received a copy of the GNU Lesser General Public
+  * License along with this software; if not, write to the Free
+  * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+  * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+  */
+package org.jboss.virtual ;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.jboss.util.collection.WeakSet;
+import org.jboss.virtual .plugins.vfs.helpers.FilterVirtualFileVisitor;
+import org.jboss.virtual .plugins.vfs.helpers.MatchAllVirtualFileFilter;
+import org.jboss.virtual .spi.VFSContext;
+import org.jboss.virtual .spi.VirtualFileHandler;
+
+/**
+ * A virtual file as seen by the user
+ * 
+ * @author Scott.Stark at jboss.org
+ * @author adrian at jboss.org
+ * @version $Revision: 44334 $
+ */
+public class VirtualFile
+{
+   /** The virtual file handler */
+   private final VirtualFileHandler handler;
+
+   /** Whether we are closed */
+   private AtomicBoolean closed = new AtomicBoolean(false); 
+   
+   /** The open streams */
+   private final Set<InputStream> streams = Collections.synchronizedSet(new WeakSet());
+   
+   /**
+    * Create a new VirtualFile.
+    * 
+    * @param handler the handler
+    * @throws IllegalArgumentException if the handler is null
+    */
+   public VirtualFile(VirtualFileHandler handler)
+   {
+      if (handler == null)
+         throw new IllegalArgumentException("Null handler");
+      this.handler = handler;
+   }
+
+   /**
+    * Get the virtual file handler
+    * 
+    * @return the handler
+    * @throws IllegalStateException if the file is closed
+    */
+   protected VirtualFileHandler getHandler()
+   {
+      if (closed.get())
+         throw new IllegalStateException("The virtual file is closed");
+      return handler;
+   }
+   
+   /**
+    * Get the simple VF name (X.java)
+    * 
+    * @return the simple file name
+    * @throws IllegalStateException if the file is closed
+    */
+   public String getName()
+   {
+      return getHandler().getName();
+   }
+
+   /**
+    * Get the VFS relative path name (org/jboss/X.java)
+    * 
+    * @return the VFS relative path name
+    * @throws IllegalStateException if the file is closed
+    */
+   public String getPathName()
+   {
+      return getHandler().getPathName();
+   }
+
+   /**
+    * Get the VF URL (file://root/org/jboss/X.java)
+    * 
+    * @return the full URL to the VF in the VFS.
+    * @throws MalformedURLException if a url cannot be parsed
+    * @throws IllegalStateException if the file is closed
+    */
+   public URL toURL() throws MalformedURLException
+   {
+      return getHandler().toURL();
+   }
+
+   /**
+    * When the file was last modified
+    * 
+    * @return the last modified time
+    * @throws IOException for any problem accessing the virtual file system
+    * @throws IllegalStateException if the file is closed
+    */
+   public long getLastModified() throws IOException
+   {
+      return getHandler().getLastModified();
+   }
+   
+   /**
+    * Get the size
+    * 
+    * @return the size
+    * @throws IOException for any problem accessing the virtual file system
+    * @throws IllegalStateException if the file is closed
+    */
+   public long getSize() throws IOException
+   {
+      return getHandler().getSize();
+   }
+
+   /**
+    * Whether it is a directory
+    * 
+    * @return true if a directory.
+    * @throws IOException for any problem accessing the virtual file system
+    * @throws IllegalStateException if the file is closed
+    */
+   public boolean isDirectory() throws IOException
+   {
+      return getHandler().isDirectory();
+   }
+
+   /**
+    * Whether it is a simple file
+    * 
+    * @return true if a simple file.
+    * @throws IOException for any problem accessing the virtual file system
+    * @throws IllegalStateException if the file is closed
+    */
+   public boolean isFile() throws IOException
+   {
+      return getHandler().isFile();
+   }
+   
+   /**
+    * Whether it is an archive
+    * 
+    * @return true when an archive
+    * @throws IOException for any problem accessing the virtual file system
+    * @throws IllegalStateException if the file is closed
+    */
+   public boolean isArchive() throws IOException
+   {
+      return getHandler().isArchive();
+   }
+   
+   /**
+    * Whether it is hidden
+    * 
+    * @return true when hidden
+    * @throws IOException for any problem accessing the virtual file system
+    * @throws IllegalStateException if the file is closed
+    */
+   public boolean isHidden() throws IOException
+   {
+      return getHandler().isHidden();
+   }
+
+   /**
+    * Access the file contents.
+    * 
+    * @return an InputStream for the file contents.
+    * @throws IOException for any error accessing the file system 
+    * @throws IllegalStateException if the file is closed
+    */
+   public InputStream openStream() throws IOException
+   {
+      InputStream result = getHandler().openStream();
+      streams.add(result);
+      return result;
+   }
+
+   /**
+    * Close the streams
+    */
+   public void closeStreams()
+   {
+      // Close the streams
+      for (InputStream stream : streams)
+      {
+         if (stream != null)
+         {
+            try
+            {
+               stream.close();
+            }
+            catch (IOException ignored)
+            {
+            }
+         }
+      }
+      streams.clear();
+   }
+
+   /**
+    * Close the file resources (stream, etc.)
+    */
+   public void close()
+   {
+      if (closed.getAndSet(true) == false)
+      {
+         closeStreams();
+         handler.close();
+      }
+   }
+   
+   /**
+    * Get the VFS instance for this virtual file
+    * 
+    * @return the VFS
+    * @throws IllegalStateException if the file is closed
+    */
+   public VFS getVFS()
+   {
+      VFSContext context = getHandler().getVFSContext();
+      return context.getVFS();
+   }
+   
+   /**
+    * Get the parent
+    * 
+    * @return the parent
+    * @throws IOException for any problem accessing the virtual file system
+    * @throws IllegalStateException if the file is closed
+    */
+   public VirtualFile getParent() throws IOException
+   {
+      VirtualFileHandler parent = getHandler().getParent();
+      return parent.getVirtualFile();
+   }
+   
+   /**
+    * Get the children
+    * 
+    * @return the children
+    * @throws IOException for any problem accessing the virtual file system
+    * @throws IllegalStateException if the file is closed
+    */
+   public List<VirtualFile> getChildren() throws IOException
+   {
+      return getChildren(null);
+   }
+
+   /**
+    * Get the children
+    * 
+    * @param filter to filter the children
+    * @return the children
+    * @throws IOException for any problem accessing the virtual file system
+    * @throws IllegalStateException if the file is closed or it is not a directory
+    */
+   public List<VirtualFile> getChildren(VirtualFileFilter filter) throws IOException
+   {
+      if (isDirectory() == false)
+         throw new IllegalStateException("Not a directory: " + this);
+
+      if (filter == null)
+         filter = MatchAllVirtualFileFilter.INSTANCE;
+      FilterVirtualFileVisitor visitor = new FilterVirtualFileVisitor(filter, null);
+      visit(visitor);
+      return visitor.getMatched();
+   }
+   
+   /**
+    * Get all the children recursively<p>
+    * 
+    * This always uses {@link VisitorAttributes#RECURSE_DIRECTORIES}
+    * 
+    * @return the children
+    * @throws IOException for any problem accessing the virtual file system
+    * @throws IllegalStateException if the file is closed
+    */
+   public List<VirtualFile> getChildrenRecursively() throws IOException
+   {
+      return getChildrenRecursively(null);
+   }
+   
+   /**
+    * Get all the children recursively<p>
+    * 
+    * This always uses {@link VisitorAttributes#RECURSE_DIRECTORIES}
+    * 
+    * @param filter to filter the children
+    * @return the children
+    * @throws IOException for any problem accessing the virtual file system
+    * @throws IllegalStateException if the file is closed or it is not a directory
+    */
+   public List<VirtualFile> getChildrenRecursively(VirtualFileFilter filter) throws IOException
+   {
+      if (isDirectory() == false)
+         throw new IllegalStateException("Not a directory: " + this);
+
+      if (filter == null)
+         filter = MatchAllVirtualFileFilter.INSTANCE;
+      FilterVirtualFileVisitor visitor = new FilterVirtualFileVisitor(filter, VisitorAttributes.RECURSE_DIRECTORIES);
+      visit(visitor);
+      return visitor.getMatched();
+   }
+   
+   /**
+    * Visit the virtual file system
+    * 
+    * @param visitor the visitor
+    * @throws IOException for any problem accessing the virtual file system
+    * @throws IllegalArgumentException if the visitor is null
+    * @throws IllegalStateException if the file is closed or it is not a directory
+    */
+   public void visit(VirtualFileVisitor visitor) throws IOException
+   {
+      if (isDirectory() == false)
+         throw new IllegalStateException("Not a directory: " + this);
+      getVFS().visit(this, visitor);
+   }
+
+   /**
+    * Find a child
+    * 
+    * @param path the path 
+    * @return the child
+    * @throws IOException for any problem accessing the VFS (including the child does not exist)
+    * @throws IllegalArgumentException if the path is null
+    * @throws IllegalStateException if the file is closed or it is not a directory
+    */
+   public VirtualFile findChild(String path) throws IOException
+   {
+      VirtualFileHandler handler = getHandler();
+      if (handler.isDirectory() == false)
+         throw new IllegalStateException("Not a directory: " + this);
+
+      path = VFSUtils.fixName(path);
+      VirtualFileHandler child = handler.findChild(path);
+      return child.getVirtualFile();
+   }
+
+   @Override
+   public String toString()
+   {
+      return handler.toString();
+   }
+
+   @Override
+   public int hashCode()
+   {
+      return handler.hashCode();
+   }
+   
+   @Override
+   public boolean equals(Object obj)
+   {
+      if (obj == this)
+         return true;
+      if (obj == null || obj instanceof VirtualFile == false)
+         return false;
+      VirtualFile other = (VirtualFile) obj;
+      return handler.equals(other.handler);
+   }
+   
+   @Override
+   protected void finalize() throws Throwable
+   {
+      close();
+   }
+}
Added: projects/microcontainer/trunk/container/src/main/org/jboss/virtual/VirtualFileFilter.java
===================================================================
--- projects/microcontainer/trunk/container/src/main/org/jboss/virtual/VirtualFileFilter.java	2006-09-06 11:18:17 UTC (rev 56598)
+++ projects/microcontainer/trunk/container/src/main/org/jboss/virtual/VirtualFileFilter.java	2006-09-06 11:27:07 UTC (rev 56599)
@@ -0,0 +1,40 @@
+/*
+* JBoss, Home of Professional Open Source
+* Copyright 2005, JBoss Inc., and individual contributors as indicated
+* by the @authors tag. See the copyright.txt in the distribution for a
+* full listing of individual contributors.
+*
+* This is free software; you can redistribute it and/or modify it
+* under the terms of the GNU Lesser General Public License as
+* published by the Free Software Foundation; either version 2.1 of
+* the License, or (at your option) any later version.
+*
+* This software is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public
+* License along with this software; if not, write to the Free
+* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+*/
+package org.jboss.virtual;
+
+/**
+ * A filter for virtual files
+ *
+ * @author <a href="mailto:bill at jboss.org">Bill Burke</a>
+ * @author adrian at jboss.org
+ * @version $Revision: 44334 $
+ */
+public interface VirtualFileFilter
+{
+   /**
+    * Match the virtual file
+    * 
+    * @param file the virtual file
+    * @return true when it matches
+    */
+   boolean accepts(VirtualFile file);
+}
Added: projects/microcontainer/trunk/container/src/main/org/jboss/virtual/VirtualFileFilterWithAttributes.java
===================================================================
--- projects/microcontainer/trunk/container/src/main/org/jboss/virtual/VirtualFileFilterWithAttributes.java	2006-09-06 11:18:17 UTC (rev 56598)
+++ projects/microcontainer/trunk/container/src/main/org/jboss/virtual/VirtualFileFilterWithAttributes.java	2006-09-06 11:27:07 UTC (rev 56599)
@@ -0,0 +1,38 @@
+/*
+* JBoss, Home of Professional Open Source
+* Copyright 2005, JBoss Inc., and individual contributors as indicated
+* by the @authors tag. See the copyright.txt in the distribution for a
+* full listing of individual contributors.
+*
+* This is free software; you can redistribute it and/or modify it
+* under the terms of the GNU Lesser General Public License as
+* published by the Free Software Foundation; either version 2.1 of
+* the License, or (at your option) any later version.
+*
+* This software is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public
+* License along with this software; if not, write to the Free
+* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+*/
+package org.jboss.virtual;
+
+/**
+ * A filter for virtual files with attributes
+ *
+ * @author adrian at jboss.org
+ * @version $Revision: 44334 $
+ */
+public interface VirtualFileFilterWithAttributes extends VirtualFileFilter
+{
+   /**
+    * Get the attributes for this filter
+    * 
+    * @return the attributes
+    */
+   VisitorAttributes getAttributes();
+}
Added: projects/microcontainer/trunk/container/src/main/org/jboss/virtual/VirtualFileVisitor.java
===================================================================
--- projects/microcontainer/trunk/container/src/main/org/jboss/virtual/VirtualFileVisitor.java	2006-09-06 11:18:17 UTC (rev 56598)
+++ projects/microcontainer/trunk/container/src/main/org/jboss/virtual/VirtualFileVisitor.java	2006-09-06 11:27:07 UTC (rev 56599)
@@ -0,0 +1,45 @@
+/*
+* JBoss, Home of Professional Open Source
+* Copyright 2006, JBoss Inc., and individual contributors as indicated
+* by the @authors tag. See the copyright.txt in the distribution for a
+* full listing of individual contributors.
+*
+* This is free software; you can redistribute it and/or modify it
+* under the terms of the GNU Lesser General Public License as
+* published by the Free Software Foundation; either version 2.1 of
+* the License, or (at your option) any later version.
+*
+* This software is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public
+* License along with this software; if not, write to the Free
+* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+*/
+package org.jboss.virtual;
+
+/**
+ * Visits a virtual file and its children
+ * 
+ * @author <a href="adrian at jboss.com">Adrian Brock</a>
+ * @version $Revision: 1.1 $
+ */
+public interface VirtualFileVisitor
+{
+   /**
+    * Get the search attribues for this visitor
+    * 
+    * @return the attributes
+    */
+   VisitorAttributes getAttributes();
+   
+   /**
+    * Visit a virtual file
+    * 
+    * @param virtualFile the virtual file being visited
+    */
+   void visit(VirtualFile virtualFile);
+}
Added: projects/microcontainer/trunk/container/src/main/org/jboss/virtual/VisitorAttributes.java
===================================================================
--- projects/microcontainer/trunk/container/src/main/org/jboss/virtual/VisitorAttributes.java	2006-09-06 11:18:17 UTC (rev 56598)
+++ projects/microcontainer/trunk/container/src/main/org/jboss/virtual/VisitorAttributes.java	2006-09-06 11:27:07 UTC (rev 56599)
@@ -0,0 +1,228 @@
+/*
+* JBoss, Home of Professional Open Source
+* Copyright 2006, JBoss Inc., and individual contributors as indicated
+* by the @authors tag. See the copyright.txt in the distribution for a
+* full listing of individual contributors.
+*
+* This is free software; you can redistribute it and/or modify it
+* under the terms of the GNU Lesser General Public License as
+* published by the Free Software Foundation; either version 2.1 of
+* the License, or (at your option) any later version.
+*
+* This software is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public
+* License along with this software; if not, write to the Free
+* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+*/
+package org.jboss.virtual;
+
+/**
+ * Attributes used when visiting a virtual file system
+ * 
+ * @author <a href="adrian at jboss.com">Adrian Brock</a>
+ * @version $Revision: 1.1 $
+ */
+public class VisitorAttributes
+{
+   /** The default attributes */
+   public static final VisitorAttributes DEFAULT = new ImmutableVisitorAttributes();
+
+   /** No directories */
+   public static final VisitorAttributes NO_DIRECTORIES = new ImmutableVisitorAttributes(false, false);
+
+   /** Recurse directories */
+   public static final VisitorAttributes RECURSE_DIRECTORIES = new ImmutableVisitorAttributes(true, true);
+
+   /** Recurse but don't visit directories */
+   public static final VisitorAttributes RECURSE_NO_DIRECTORIES = new ImmutableVisitorAttributes(false, true);
+   
+   /** Whether to include the root */
+   private boolean includeRoot = false;
+
+   /** Whether to include directories */
+   private boolean includeDirectories = true;
+
+   /** Whether to recurse directories */
+   private boolean recurseDirectories = false;
+
+   /** Whether to ignore individual file errors */
+   private boolean ignoreErrors = false;
+
+   /** Whether to ignore hidden files */
+   private boolean ignoreHidden = true;
+   
+   /**
+    * Whether to include the directories<p>
+    * 
+    * Default: true
+    * 
+    * @return the includeDirectories.
+    */
+   public boolean isIncludeDirectories()
+   {
+      return includeDirectories;
+   }
+
+   /**
+    * Set the includeDirectories.
+    * 
+    * @param includeDirectories the includeDirectories.
+    * @throws IllegalStateException if you attempt to modify one of the preconfigured static values of this class
+    */
+   public void setIncludeDirectories(boolean includeDirectories)
+   {
+      this.includeDirectories = includeDirectories;
+   }
+
+   /**
+    * Whether to recurse into directories<p>
+    * 
+    * Default: false
+    * 
+    * @return the recurseDirectories.
+    */
+   public boolean isRecurseDirectories()
+   {
+      return recurseDirectories;
+   }
+
+   /**
+    * Set the recurseDirectories.
+    * 
+    * @param recurseDirectories the recurseDirectories.
+    * @throws IllegalStateException if you attempt to modify one of the preconfigured static values of this class
+    */
+   public void setRecurseDirectories(boolean recurseDirectories)
+   {
+      this.recurseDirectories = recurseDirectories;
+   }
+
+   /**
+    * Whether to include the root of the visit<p>
+    * 
+    * Default: false
+    * 
+    * @return the includeRoot.
+    */
+   public boolean isIncludeRoot()
+   {
+      return includeRoot;
+   }
+
+   /**
+    * Set the includeRoot.
+    * 
+    * @param includeRoot the includeRoot.
+    * @throws IllegalStateException if you attempt to modify one of the preconfigured static values of this class
+    */
+   public void setIncludeRoot(boolean includeRoot)
+   {
+      this.includeRoot = includeRoot;
+   }
+
+   /**
+    * Whether to ignore individual errors<p>
+    * 
+    * Default: true
+    * 
+    * @return the ignoreErrors.
+    */
+   public boolean isIgnoreErrors()
+   {
+      return ignoreErrors;
+   }
+
+   /**
+    * Set the ignoreErrors.
+    * 
+    * @param ignoreErrors the ignoreErrors.
+    * @throws IllegalStateException if you attempt to modify one of the preconfigured static values of this class
+    */
+   public void setIgnoreErrors(boolean ignoreErrors)
+   {
+      this.ignoreErrors = ignoreErrors;
+   }
+
+   /**
+    * Whether to ignore hidden files<p>
+    * 
+    * Default: true
+    * 
+    * @return the ignoreHidden.
+    */
+   public boolean isIgnoreHidden()
+   {
+      return ignoreHidden;
+   }
+
+   /**
+    * Set the ignoreHidden.
+    * 
+    * @param ignoreHidden the ignoreHidden.
+    * @throws IllegalStateException if you attempt to modify one of the preconfigured static values of this class
+    */
+   public void setIgnoreHidden(boolean ignoreHidden)
+   {
+      this.ignoreHidden = ignoreHidden;
+   }
+
+   /**
+    * Immutable version of the attribues
+    */
+   private static class ImmutableVisitorAttributes extends VisitorAttributes
+   {
+      /**
+       * Create a new ImmutableVirtualFileVisitorAttributes with default values
+       */
+      public ImmutableVisitorAttributes()
+      {
+      }
+      
+      /**
+       * Create a new ImmutableVirtualFileVisitorAttributes.
+       * 
+       * @param includeDirectories whether to include directories 
+       * @param recurseDirectories whether to recurse into directories
+       */
+      public ImmutableVisitorAttributes(boolean includeDirectories, boolean recurseDirectories)
+      {
+         super.setIncludeDirectories(includeDirectories);
+         super.setRecurseDirectories(recurseDirectories);
+      }
+      
+      @Override
+      public void setIncludeDirectories(boolean includeDirectories)
+      {
+         throw new IllegalStateException("The preconfigured attributes are immutable");
+      }
+
+      @Override
+      public void setIncludeRoot(boolean includeRoot)
+      {
+         throw new IllegalStateException("The preconfigured attributes are immutable");
+      }
+
+      @Override
+      public void setRecurseDirectories(boolean recurseDirectories)
+      {
+         throw new IllegalStateException("The preconfigured attributes are immutable");
+      }
+
+      @Override
+      public void setIgnoreErrors(boolean ignoreErrors)
+      {
+         throw new IllegalStateException("The preconfigured attributes are immutable");
+      }
+
+      @Override
+      public void setIgnoreHidden(boolean ignoreHidden)
+      {
+         throw new IllegalStateException("The preconfigured attributes are immutable");
+      }
+   }
+}
Added: projects/microcontainer/trunk/container/src/main/org/jboss/virtual/plugins/context/AbstractURLHandler.java
===================================================================
--- projects/microcontainer/trunk/container/src/main/org/jboss/virtual/plugins/context/AbstractURLHandler.java	2006-09-06 11:18:17 UTC (rev 56598)
+++ projects/microcontainer/trunk/container/src/main/org/jboss/virtual/plugins/context/AbstractURLHandler.java	2006-09-06 11:27:07 UTC (rev 56599)
@@ -0,0 +1,112 @@
+/*
+* JBoss, Home of Professional Open Source
+* Copyright 2006, JBoss Inc., and individual contributors as indicated
+* by the @authors tag. See the copyright.txt in the distribution for a
+* full listing of individual contributors.
+*
+* This is free software; you can redistribute it and/or modify it
+* under the terms of the GNU Lesser General Public License as
+* published by the Free Software Foundation; either version 2.1 of
+* the License, or (at your option) any later version.
+*
+* This software is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public
+* License along with this software; if not, write to the Free
+* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+*/
+package org.jboss.virtual.plugins.context;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.net.URLConnection;
+
+import org.jboss.virtual.spi.VFSContext;
+import org.jboss.virtual.spi.VirtualFileHandler;
+
+/**
+ * URLHandler.
+ * 
+ * @author <a href="adrian at jboss.com">Adrian Brock</a>
+ * @version $Revision: 1.1 $
+ */
+public abstract class AbstractURLHandler extends AbstractVirtualFileHandler
+{
+   /** The url */
+   private final URL url;
+   
+   /**
+    * Create a newURLHandler.
+    * 
+    * @param context the context
+    * @param parent the parent
+    * @param url the url
+    * @param name the name
+    * @throws IllegalArgumentException for a null context, vfsPath or url
+    */
+   public AbstractURLHandler(VFSContext context, VirtualFileHandler parent, URL url, String name)
+   {
+      super(context, parent, name);
+      if (url == null)
+         throw new IllegalArgumentException("Null url");
+      this.url = url;
+   }
+   
+   /**
+    * Get the url
+    * 
+    * @return the url
+    */
+   public URL getURL()
+   {
+      return url;
+   }
+
+   public long getLastModified() throws IOException
+   {
+      checkClosed();
+      URLConnection c = url.openConnection();
+      return c.getLastModified();
+   }
+
+   public long getSize() throws IOException
+   {
+      checkClosed();
+      URLConnection c = url.openConnection();
+      return c.getContentLength();
+   }
+
+   public boolean isArchive() throws IOException
+   {
+      checkClosed();
+      return false;
+   }
+
+   public boolean isFile() throws IOException
+   {
+      checkClosed();
+      return isDirectory() == false;
+   }
+
+   public boolean isHidden() throws IOException
+   {
+      checkClosed();
+      return false;
+   }
+
+   public InputStream openStream() throws IOException
+   {
+      checkClosed();
+      return url.openStream();
+   }
+
+   public URL toURL()
+   {
+      return url;
+   }
+}
Added: projects/microcontainer/trunk/container/src/main/org/jboss/virtual/plugins/context/AbstractVFSContext.java
===================================================================
--- projects/microcontainer/trunk/container/src/main/org/jboss/virtual/plugins/context/AbstractVFSContext.java	2006-09-06 11:18:17 UTC (rev 56598)
+++ projects/microcontainer/trunk/container/src/main/org/jboss/virtual/plugins/context/AbstractVFSContext.java	2006-09-06 11:27:07 UTC (rev 56599)
@@ -0,0 +1,200 @@
+/*
+* JBoss, Home of Professional Open Source
+* Copyright 2006, JBoss Inc., and individual contributors as indicated
+* by the @authors tag. See the copyright.txt in the distribution for a
+* full listing of individual contributors.
+*
+* This is free software; you can redistribute it and/or modify it
+* under the terms of the GNU Lesser General Public License as
+* published by the Free Software Foundation; either version 2.1 of
+* the License, or (at your option) any later version.
+*
+* This software is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public
+* License along with this software; if not, write to the Free
+* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+*/
+package org.jboss.virtual.plugins.context;
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.List;
+
+import org.jboss.logging.Logger;
+import org.jboss.virtual.VFS;
+import org.jboss.virtual.VisitorAttributes;
+import org.jboss.virtual.spi.VFSContext;
+import org.jboss.virtual.spi.VirtualFileHandler;
+import org.jboss.virtual.spi.VirtualFileHandlerVisitor;
+
+/**
+ * AbstractVFSContext.
+ * 
+ * @author <a href="adrian at jboss.com">Adrian Brock</a>
+ * @version $Revision: 1.1 $
+ */
+public abstract class AbstractVFSContext implements VFSContext
+{
+   /** The log */
+   protected final Logger log = Logger.getLogger(getClass());
+   
+   /** The VFS wrapper */
+   private VFS vfs;
+   
+   /** The root url */
+   private final URL rootURL;
+   
+   /**
+    * Create a new AbstractVFSContext.
+    * 
+    * @param rootURL the root url
+    * @throws IllegalArgumentException if rootURL is null
+    */
+   protected AbstractVFSContext(URL rootURL)
+   {
+      if (rootURL == null)
+         throw new IllegalArgumentException("Null rootURL");
+      this.rootURL = rootURL;
+   }
+
+   public VFS getVFS()
+   {
+      if (vfs == null)
+         vfs = new VFS(this);
+      return vfs;
+   }
+
+   public URL getRootURL()
+   {
+      return rootURL;
+   }
+
+   public List<VirtualFileHandler> getChildren(VirtualFileHandler parent, boolean ignoreErrors) throws IOException
+   {
+      if (parent == null)
+         throw new IllegalArgumentException("Null parent");
+      return parent.getChildren(ignoreErrors);
+   }
+
+   public VirtualFileHandler findChild(VirtualFileHandler parent, String path) throws IOException
+   {
+      if (parent == null)
+         throw new IllegalArgumentException("Null parent");
+      if (path == null)
+         throw new IllegalArgumentException("Null path");
+      return parent.findChild(path);
+   }
+
+   public void visit(VirtualFileHandler handler, VirtualFileHandlerVisitor visitor) throws IOException
+   {
+      if (handler == null)
+         throw new IllegalArgumentException("Null handler");
+      if (visitor == null)
+         throw new IllegalArgumentException("Null visitor");
+      
+      VisitorAttributes attributes = visitor.getAttributes();
+      boolean includeRoot = attributes.isIncludeRoot();
+      boolean includeDirs = attributes.isIncludeDirectories();
+      boolean recurseDirs = attributes.isRecurseDirectories();
+      boolean ignoreErrors = attributes.isIgnoreErrors();
+      boolean ignoreHidden = attributes.isIgnoreHidden();
+
+      visit(handler, visitor, includeRoot, includeDirs, recurseDirs, ignoreErrors, ignoreHidden);
+   }
+
+   /**
+    * Visit. the file system, recursive death checking is left to the visitor
+    * or otherwise a stack overflow.
+    * 
+    * @param handler the reference handler
+    * @param visitor the visitor
+    * @param includeRoot whether to visit the root
+    * @param includeDirs whether to visit directories
+    * @param recurseDirs whether to recurse into directories
+    * @param ignoreErrors whether to ignore errors
+    * @param ignoreHidden whether to ignore hidden files
+    * @throws IOException for any problem accessing the virtual file system
+    */
+   protected void visit(VirtualFileHandler handler, VirtualFileHandlerVisitor visitor, boolean includeRoot, boolean includeDirs, boolean recurseDirs, boolean ignoreErrors, boolean ignoreHidden) throws IOException
+   {
+      // Visit the root when asked
+      if (includeRoot)
+         visitor.visit(handler);
+      
+      // Visit the children
+      List<VirtualFileHandler> children;
+      try
+      {
+          children = getChildren(handler, ignoreErrors);
+      }
+      catch (IOException e)
+      {
+         if (ignoreErrors == false)
+            throw e;
+         log.trace("Ignored: " + e);
+         return;
+      }
+      
+      // Look through each child
+      for (VirtualFileHandler child : children)
+      {
+         // Ignore hidden if asked
+         if (ignoreHidden && child.isHidden())
+            continue;
+         
+         // Exclude directories if asked
+         boolean isDirectory = child.isDirectory();
+         if (includeDirs || isDirectory == false)
+            visitor.visit(child);
+         
+         // Recurse into directories when asked
+         if (recurseDirs && isDirectory)
+         {
+            try
+            {
+               visit(child, visitor, false, includeDirs, recurseDirs, ignoreErrors, ignoreHidden);
+            }
+            catch (StackOverflowError e)
+            {
+               log.debug("Original: " + child, e);
+               throw new IOException("Stack overflow, the file system is too complicated? " + child);
+            }
+         }
+      }
+   }
+   
+   @Override
+   public String toString()
+   {
+      StringBuilder buffer = new StringBuilder();
+      buffer.append(getClass().getSimpleName());
+      buffer.append('@');
+      buffer.append(System.identityHashCode(this));
+      buffer.append('[');
+      buffer.append(rootURL);
+      buffer.append(']');
+      return buffer.toString();
+   }
+   
+   @Override
+   public int hashCode()
+   {
+      return rootURL.hashCode();
+   }
+
+   @Override
+   public boolean equals(Object obj)
+   {
+      if (this == obj)
+         return true;
+      if (obj == null || obj instanceof VFSContext == false)
+         return false;
+      VFSContext other = (VFSContext) obj;
+      return rootURL.equals(other.getRootURL());
+   }
+}
Added: projects/microcontainer/trunk/container/src/main/org/jboss/virtual/plugins/context/AbstractVirtualFileHandler.java
===================================================================
--- projects/microcontainer/trunk/container/src/main/org/jboss/virtual/plugins/context/AbstractVirtualFileHandler.java	2006-09-06 11:18:17 UTC (rev 56598)
+++ projects/microcontainer/trunk/container/src/main/org/jboss/virtual/plugins/context/AbstractVirtualFileHandler.java	2006-09-06 11:27:07 UTC (rev 56599)
@@ -0,0 +1,309 @@
+/*
+* JBoss, Home of Professional Open Source
+* Copyright 2006, JBoss Inc., and individual contributors as indicated
+* by the @authors tag. See the copyright.txt in the distribution for a
+* full listing of individual contributors.
+*
+* This is free software; you can redistribute it and/or modify it
+* under the terms of the GNU Lesser General Public License as
+* published by the Free Software Foundation; either version 2.1 of
+* the License, or (at your option) any later version.
+*
+* This software is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public
+* License along with this software; if not, write to the Free
+* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+*/
+package org.jboss.virtual.plugins.context;
+
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.jboss.logging.Logger;
+import org.jboss.virtual.VFSUtils;
+import org.jboss.virtual.VirtualFile;
+import org.jboss.virtual.plugins.vfs.helpers.PathTokenizer;
+import org.jboss.virtual.spi.VFSContext;
+import org.jboss.virtual.spi.VirtualFileHandler;
+
+/**
+ * AbstractVirtualFileHandler.
+ * 
+ * @author <a href="adrian at jboss.com">Adrian Brock</a>
+ * @version $Revision: 1.1 $
+ */
+public abstract class AbstractVirtualFileHandler implements VirtualFileHandler
+{
+   /** The log */
+   protected final Logger log = Logger.getLogger(getClass());
+   
+   /** The VFS context */
+   private final VFSContext context;
+   
+   /** The parent */
+   private final VirtualFileHandler parent;
+
+   /** The name */
+   private final String name;
+   
+   /** The vfsPath */
+   private String vfsPath;
+
+   /** The reference count */
+   private AtomicInteger references = new AtomicInteger(0);
+   
+   /**
+    * Create a new handler
+    * 
+    * @param context the context
+    * @param parent the parent
+    * @param name the name
+    * @throws IllegalArgumentException if the context or name is null;
+    */
+   protected AbstractVirtualFileHandler(VFSContext context, VirtualFileHandler parent, String name)
+   {
+      if (context == null)
+         throw new IllegalArgumentException("Null context");
+      if (name == null)
+         throw new IllegalArgumentException("Null name");
+      this.context = context;
+      this.parent = parent;
+      this.name = VFSUtils.fixName(name);
+   }
+
+   public String getName()
+   {
+      return name;
+   }
+
+   public String getPathName()
+   {
+      if (vfsPath == null)
+      {
+         StringBuilder pathName = new StringBuilder();
+         initPath(pathName);
+         vfsPath = pathName.toString();
+      }
+      return vfsPath;
+   }
+
+   /**
+    * Initialise the path into the path name
+    * 
+    * @param pathName the path name
+    * @return whether it added anything
+    */
+   private boolean initPath(StringBuilder pathName)
+   {
+      if (parent != null)
+      {
+         if (parent instanceof AbstractVirtualFileHandler)
+         {
+            AbstractVirtualFileHandler handler = (AbstractVirtualFileHandler) parent;
+            if (handler.initPath(pathName))
+               pathName.append('/');
+         }
+         else
+         {
+            pathName.append(parent.getPathName());
+         }
+         pathName.append(getName());
+         return true;
+      }
+      return false;
+   }
+   
+   public VirtualFile getVirtualFile()
+   {
+      checkClosed();
+      increment();
+      return new VirtualFile(this);
+   }
+   
+   public VirtualFileHandler getParent()
+   {
+      checkClosed();
+      return parent;
+   }
+   
+   public VFSContext getVFSContext()
+   {
+      checkClosed();
+      return context;
+   }
+
+   /**
+    * Increment the reference count
+    * 
+    * @return the resulting count
+    */
+   private int increment()
+   {
+      return references.incrementAndGet();
+   }
+
+   /**
+    * Decrement the reference count
+    * 
+    * @return the resulting count
+    */
+   private int decrement()
+   {
+      return references.decrementAndGet();
+   }
+
+   /**
+    * Check whether we are closed
+    * 
+    * @throws IllegalStateException when closed
+    */
+   protected void checkClosed() throws IllegalStateException 
+   {
+      if (references.get() < 0)
+         throw new IllegalStateException("Closed " + this);
+   }
+   
+   public void close() 
+   {
+      if (decrement() == 0)
+         doClose();
+   }
+
+   /**
+    * The real close
+    */
+   protected void doClose()
+   {
+      // nothing
+   }
+
+   /**
+    * Structured implementation of find child
+    * 
+    * @param path the path
+    * @return the handler
+    * @throws IOException for any error accessing the virtual file system
+    * @throws IllegalArgumentException for a null name
+    */
+   public VirtualFileHandler structuredFindChild(String path) throws IOException
+   {
+      checkClosed();
+
+      // Parse the path
+      String[] tokens = PathTokenizer.getTokens(path);
+      if (tokens == null || tokens.length == 0)
+         return this;
+
+      // Go through each context starting from ours 
+      // check the parent contexts are directories
+      VirtualFileHandler current = this;
+      for (int i = 0; i < tokens.length; ++i)
+      {
+         if (current.isDirectory() == false)
+            throw new IOException("Not a directory: " + current);
+         if (current instanceof StructuredVirtualFileHandler)
+         {
+            StructuredVirtualFileHandler structured = (StructuredVirtualFileHandler) current;
+            current = structured.createChildHandler(tokens[i]);
+         }
+         else
+         {
+            String remainingPath = PathTokenizer.getRemainingPath(tokens, i);
+            return current.findChild(remainingPath);
+         }
+      }
+      
+      // The last one is the result
+      return current;
+   }
+
+   /**
+    * Simple implementation of findChild
+    * 
+    * @param path the path
+    * @return the handler
+    * @throws IOException for any error accessing the virtual file system
+    * @throws IllegalArgumentException for a null name
+    */
+   public VirtualFileHandler simpleFindChild(String path) throws IOException
+   {
+      if (path == null)
+         throw new IllegalArgumentException("Null path");
+
+      if (path.length() == 0)
+         return this;
+
+      List<VirtualFileHandler> children = getChildren(false);
+      for (VirtualFileHandler child : children)
+      {
+         if (child.getName().equals(path))
+            return child;
+      }
+      throw new IOException("Child not found " + path + " for " + this);
+   }
+
+   @Override
+   public String toString()
+   {
+      StringBuilder buffer = new StringBuilder();
+      buffer.append(getClass().getSimpleName());
+      buffer.append('@');
+      buffer.append(System.identityHashCode(this));
+      buffer.append("[path=").append(getPathName());
+      buffer.append(" context=").append(getVFSContext());
+      buffer.append(" real=").append(safeToURLString());
+      buffer.append(']');
+      return buffer.toString();
+   }
+   
+   @Override
+   public int hashCode()
+   {
+      return getPathName().hashCode();
+   }
+
+   @Override
+   public boolean equals(Object obj)
+   {
+      if (this == obj)
+         return true;
+      if (obj == null || obj instanceof VirtualFileHandler == false)
+         return false;
+      VirtualFileHandler other = (VirtualFileHandler) obj;
+      if (getVFSContext().equals(other.getVFSContext()) == false)
+         return false;
+      if (getPathName().equals(other.getPathName()) == false)
+         return false;
+      return true;
+   }
+
+   @Override
+   protected void finalize() throws Throwable
+   {
+      close();
+   }
+   
+   /**
+    * Safely get a url version of the string
+    * 
+    * @return the string or unknown if there is an error
+    */
+   private String safeToURLString()
+   {
+      try
+      {
+         return toURL().toString();
+      }
+      catch (MalformedURLException ignored)
+      {
+         return "<unknown>";
+      }
+   }
+}
Added: projects/microcontainer/trunk/container/src/main/org/jboss/virtual/plugins/context/StructuredVirtualFileHandler.java
===================================================================
--- projects/microcontainer/trunk/container/src/main/org/jboss/virtual/plugins/context/StructuredVirtualFileHandler.java	2006-09-06 11:18:17 UTC (rev 56598)
+++ projects/microcontainer/trunk/container/src/main/org/jboss/virtual/plugins/context/StructuredVirtualFileHandler.java	2006-09-06 11:27:07 UTC (rev 56599)
@@ -0,0 +1,46 @@
+/*
+* JBoss, Home of Professional Open Source
+* Copyright 2006, JBoss Inc., and individual contributors as indicated
+* by the @authors tag. See the copyright.txt in the distribution for a
+* full listing of individual contributors.
+*
+* This is free software; you can redistribute it and/or modify it
+* under the terms of the GNU Lesser General Public License as
+* published by the Free Software Foundation; either version 2.1 of
+* the License, or (at your option) any later version.
+*
+* This software is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public
+* License along with this software; if not, write to the Free
+* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+*/
+package org.jboss.virtual.plugins.context;
+
+import java.io.IOException;
+
+import org.jboss.virtual.spi.VirtualFileHandler;
+
+/**
+ * A handler that has structure, i.e. you want
+ * to go through the path in individual elements
+ * 
+ * @author <a href="adrian at jboss.com">Adrian Brock</a>
+ * @version $Revision: 1.1 $
+ */
+public interface StructuredVirtualFileHandler
+{
+   /**
+    * Create a virtual file context
+    * 
+    * @param name the name
+    * @return the handler
+    * @throws IOException for any error accessing the virtual file system
+    * @throws IllegalArgumentException for a null name
+    */
+   VirtualFileHandler createChildHandler(String name) throws IOException;
+}
Added: projects/microcontainer/trunk/container/src/main/org/jboss/virtual/plugins/context/file/FileHandler.java
===================================================================
--- projects/microcontainer/trunk/container/src/main/org/jboss/virtual/plugins/context/file/FileHandler.java	2006-09-06 11:18:17 UTC (rev 56598)
+++ projects/microcontainer/trunk/container/src/main/org/jboss/virtual/plugins/context/file/FileHandler.java	2006-09-06 11:27:07 UTC (rev 56599)
@@ -0,0 +1,160 @@
+/*
+* JBoss, Home of Professional Open Source
+* Copyright 2006, JBoss Inc., and individual contributors as indicated
+* by the @authors tag. See the copyright.txt in the distribution for a
+* full listing of individual contributors.
+*
+* This is free software; you can redistribute it and/or modify it
+* under the terms of the GNU Lesser General Public License as
+* published by the Free Software Foundation; either version 2.1 of
+* the License, or (at your option) any later version.
+*
+* This software is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public
+* License along with this software; if not, write to the Free
+* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+*/
+package org.jboss.virtual.plugins.context.file;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.jboss.virtual.plugins.context.AbstractURLHandler;
+import org.jboss.virtual.plugins.context.StructuredVirtualFileHandler;
+import org.jboss.virtual.plugins.context.jar.JarUtils;
+import org.jboss.virtual.spi.VirtualFileHandler;
+
+/**
+ * FileHandler.
+ * 
+ * @author <a href="adrian at jboss.com">Adrian Brock</a>
+ * @version $Revision: 1.1 $
+ */
+public class FileHandler extends AbstractURLHandler implements StructuredVirtualFileHandler
+{
+   /** The file */
+   private final File file;
+   
+   /**
+    * Create a new FileHandler.
+    * 
+    * @param context the context
+    * @param parent the parent
+    * @param file the file
+    * @param url the url
+    * @throws IOException for an error accessing the file system
+    * @throws IllegalArgumentException for a null context, url or vfsPath
+    */
+   public FileHandler(FileSystemContext context, VirtualFileHandler parent, File file, URL url) throws IOException
+   {
+      super(context, parent, url, file.getName());
+
+      this.file = file;
+      if (file.exists() == false)
+         throw new FileNotFoundException("File does not exist: " + file.getCanonicalPath());
+   }
+
+   @Override
+   public FileSystemContext getVFSContext()
+   {
+      return (FileSystemContext) super.getVFSContext();
+   }
+   
+   /**
+    * Get the file for this file handler
+    * 
+    * @return the file
+    */
+   protected File getFile()
+   {
+      checkClosed();
+      return file;
+   }
+   
+   @Override
+   public long getLastModified()
+   {
+      return getFile().lastModified();
+   }
+
+   @Override
+   public long getSize()
+   {
+      return getFile().length();
+   }
+
+   public boolean isArchive()
+   {
+      if (isDirectory() == false)
+         return false;
+      return JarUtils.isArchive(getName());
+   }
+
+   public boolean isDirectory()
+   {
+      return getFile().isDirectory();
+   }
+
+   public boolean isFile()
+   {
+      return getFile().isFile();
+   }
+
+   public boolean isHidden()
+   {
+      return getFile().isHidden();
+   }
+
+   public List<VirtualFileHandler> getChildren(boolean ignoreErrors) throws IOException
+   {
+      File parent = getFile();
+      File[] files = parent.listFiles();
+      if (files == null)
+         throw new IOException("Error listing files: " + parent.getCanonicalPath());
+      if (files.length == 0)
+         return Collections.emptyList();
+
+      FileSystemContext context = getVFSContext();
+      
+      List<VirtualFileHandler> result = new ArrayList<VirtualFileHandler>();
+      for (File file : files)
+      {
+         try
+         {
+            VirtualFileHandler handler = context.createVirtualFileHandler(this, file);
+            result.add(handler);
+         }
+         catch (IOException e)
+         {
+            if (ignoreErrors)
+               log.trace("Ignored: " + e);
+            else
+               throw e;
+         }
+      }
+      return result;
+   }
+
+   public VirtualFileHandler findChild(String path) throws IOException
+   {
+      return structuredFindChild(path);
+   }
+
+   public VirtualFileHandler createChildHandler(String name) throws IOException
+   {
+      FileSystemContext context = getVFSContext();
+      File parentFile = getFile();
+      File child = new File(parentFile, name);
+      return context.createVirtualFileHandler(this, child);
+   }
+}
Added: projects/microcontainer/trunk/container/src/main/org/jboss/virtual/plugins/context/file/FileSystemContext.java
===================================================================
--- projects/microcontainer/trunk/container/src/main/org/jboss/virtual/plugins/context/file/FileSystemContext.java	2006-09-06 11:18:17 UTC (rev 56598)
+++ projects/microcontainer/trunk/container/src/main/org/jboss/virtual/plugins/context/file/FileSystemContext.java	2006-09-06 11:27:07 UTC (rev 56599)
@@ -0,0 +1,172 @@
+/*
+* JBoss, Home of Professional Open Source
+* Copyright 2006, JBoss Inc., and individual contributors as indicated
+* by the @authors tag. See the copyright.txt in the distribution for a
+* full listing of individual contributors.
+*
+* This is free software; you can redistribute it and/or modify it
+* under the terms of the GNU Lesser General Public License as
+* published by the Free Software Foundation; either version 2.1 of
+* the License, or (at your option) any later version.
+*
+* This software is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public
+* License along with this software; if not, write to the Free
+* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+*/
+package org.jboss.virtual.plugins.context.file;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URL;
+
+import org.jboss.virtual.VirtualFile;
+import org.jboss.virtual.plugins.context.AbstractVFSContext;
+import org.jboss.virtual.plugins.context.jar.JarHandler;
+import org.jboss.virtual.plugins.context.jar.JarUtils;
+import org.jboss.virtual.spi.VirtualFileHandler;
+
+/**
+ * FileSystemContext.
+ * 
+ * @author <a href="adrian at jboss.com">Adrian Brock</a>
+ * @version $Revision: 1.1 $
+ */
+public class FileSystemContext extends AbstractVFSContext
+{
+   /** The root file */
+   private final VirtualFileHandler root;
+   
+   /** A reference to the virtual file of the root to stop it getting closed */
+   private final VirtualFile rootFile;
+   
+   /**
+    * Get the file for a url
+    * 
+    * @param url the url
+    * @return the file
+    * @throws IOException for any error accessing the file system
+    * @throws IllegalArgumentException for a null url
+    */
+   private static File getFile(URL url) throws IOException
+   {
+      if (url == null)
+         throw new IllegalArgumentException("Null url");
+      
+      return new File(url.getPath());
+   }
+   
+   /**
+    * Get the url for a file
+    * 
+    * @param file the file
+    * @return the url
+    * @throws IOException for any error accessing the file system
+    * @throws IllegalArgumentException for a null file
+    */
+   private static URL getFileURL(File file) throws IOException
+   {
+      if (file == null)
+         throw new IllegalArgumentException("Null file");
+      return file.toURL();
+   }
+   
+   /**
+    * Create a new FileSystemContext.
+    * 
+    * @param rootURL the root url
+    * @throws IOException for an error accessing the file system
+    */
+   public FileSystemContext(URL rootURL) throws IOException
+   {
+      this(rootURL, getFile(rootURL));
+   }
+   
+   /**
+    * Create a new FileSystemContext.
+    * 
+    * @param file the root file
+    * @throws IOException for an error accessing the file system
+    * @throws IllegalArgumentException for a null file
+    */
+   public FileSystemContext(File file) throws IOException
+   {
+      this(getFileURL(file), file);
+   }
+   
+   /**
+    * Create a new FileSystemContext.
+    * 
+    * @param rootURL the root url
+    * @param file the file
+    * @throws IOException for an error accessing the file system
+    */
+   private FileSystemContext(URL rootURL, File file) throws IOException
+   {
+      super(rootURL);
+      root = createVirtualFileHandler(null, file);
+      rootFile = root.getVirtualFile();
+   }
+
+   public VirtualFileHandler getRoot() throws IOException
+   {
+      return root;
+   }
+
+   /**
+    * Create a new virtual file handler
+    * 
+    * @param parent the parent
+    * @param file the file
+    * @return the handler
+    * @throws IOException for any error accessing the file system
+    * @throws IllegalArgumentException for a null file
+    */
+   public VirtualFileHandler createVirtualFileHandler(VirtualFileHandler parent, File file) throws IOException
+   {
+      if (file == null)
+         throw new IllegalArgumentException("Null file");
+      
+      URL fileURL = getFileURL(file);
+      if (file.isFile() && JarUtils.isArchive(file.getName()))
+      {
+         URL url = JarUtils.createJarURL(fileURL);
+         String name = file.getName();
+         return new JarHandler(this, parent, url, name);
+      }
+      return createVirtualFileHandler(parent, file, fileURL);
+   }
+
+   /**
+    * Create a new virtual file handler
+    * 
+    * @param parent the parent
+    * @param file the file
+    * @param url the url
+    * @return the handler
+    * @throws IOException for any error accessing the file system
+    * @throws IllegalArgumentException for a null file
+    */
+   public VirtualFileHandler createVirtualFileHandler(VirtualFileHandler parent, File file, URL url) throws IOException
+   {
+      if (file == null)
+         throw new IllegalArgumentException("Null file");
+      if (url == null)
+         throw new IllegalArgumentException("Null url");
+      
+      return new FileHandler(this, parent, file, url);
+   }
+   
+   @Override
+   protected void finalize() throws Throwable
+   {
+      if (rootFile != null)
+         rootFile.close();
+      super.finalize();
+   }
+}
Added: projects/microcontainer/trunk/container/src/main/org/jboss/virtual/plugins/context/file/FileSystemContextFactory.java
===================================================================
--- projects/microcontainer/trunk/container/src/main/org/jboss/virtual/plugins/context/file/FileSystemContextFactory.java	2006-09-06 11:18:17 UTC (rev 56598)
+++ projects/microcontainer/trunk/container/src/main/org/jboss/virtual/plugins/context/file/FileSystemContextFactory.java	2006-09-06 11:27:07 UTC (rev 56599)
@@ -0,0 +1,51 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2005, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.virtual.plugins.context.file;
+
+import java.net.URL;
+import java.io.IOException;
+
+import org.jboss.virtual.spi.VFSContext;
+import org.jboss.virtual.spi.VFSContextFactory;
+
+/**
+ * A file system context factory
+ * 
+ * @author Scott.Stark at jboss.org
+ * @author adrian at jboss.org
+ * @version $Revision: 44217 $
+ */
+public class FileSystemContextFactory implements VFSContextFactory
+{
+   /** The protocols supported */
+   private static final String[] PROTOCOLS = { "file" };
+
+   public String[] getProtocols()
+   {
+      return PROTOCOLS;
+   }
+
+   public VFSContext getVFS(URL root) throws IOException
+   {
+      return new FileSystemContext(root);
+   }
+}
Added: projects/microcontainer/trunk/container/src/main/org/jboss/virtual/plugins/context/jar/AbstractJarHandler.java
===================================================================
--- projects/microcontainer/trunk/container/src/main/org/jboss/virtual/plugins/context/jar/AbstractJarHandler.java	2006-09-06 11:18:17 UTC (rev 56598)
+++ projects/microcontainer/trunk/container/src/main/org/jboss/virtual/plugins/context/jar/AbstractJarHandler.java	2006-09-06 11:27:07 UTC (rev 56599)
@@ -0,0 +1,209 @@
+/*
+* JBoss, Home of Professional Open Source
+* Copyright 2006, JBoss Inc., and individual contributors as indicated
+* by the @authors tag. See the copyright.txt in the distribution for a
+* full listing of individual contributors.
+*
+* This is free software; you can redistribute it and/or modify it
+* under the terms of the GNU Lesser General Public License as
+* published by the Free Software Foundation; either version 2.1 of
+* the License, or (at your option) any later version.
+*
+* This software is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public
+* License along with this software; if not, write to the Free
+* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+*/
+package org.jboss.virtual.plugins.context.jar;
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+
+import org.jboss.virtual.plugins.context.AbstractURLHandler;
+import org.jboss.virtual.spi.VFSContext;
+import org.jboss.virtual.spi.VirtualFileHandler;
+
+/**
+ * AbstractJarHandler.
+ * 
+ * @author <a href="adrian at jboss.com">Adrian Brock</a>
+ * @version $Revision: 1.1 $
+ */
+public class AbstractJarHandler extends AbstractURLHandler
+{
+   /** The jar file */
+   private JarFile jar;
+
+   /** The jar entries */
+   private List<VirtualFileHandler> entries;
+   
+   /**
+    * Get a jar entry name
+    * 
+    * @param entry the entry
+    * @return the name
+    * @throws IllegalArgumentException for a null entry
+    */
+   protected static String getEntryName(JarEntry entry)
+   {
+      if (entry == null)
+         throw new IllegalArgumentException("Null entry");
+      return entry.getName();
+   }
+   
+   /**
+    * Create a new JarHandler.
+    * 
+    * @param context the context
+    * @param parent the parent
+    * @param url the url
+    * @param name the name
+    * @throws IOException for an error accessing the file system
+    * @throws IllegalArgumentException for a null context, url or vfsPath
+    */
+   protected AbstractJarHandler(VFSContext context, VirtualFileHandler parent, URL url, String name) throws IOException
+   {
+      super(context, parent, url, name);
+   }
+
+   /**
+    * Get the jar.
+    * 
+    * @return the jar.
+    */
+   public JarFile getJar()
+   {
+      return jar;
+   }
+
+   /**
+    * Initialise the jar file
+    * 
+    * @param jarFile the jar file
+    * @throws IOException for any error reading the jar file
+    * @throws IllegalArgumentException for a null jarFile
+    */
+   protected void initJarFile(JarFile jarFile) throws IOException
+   {
+      if (this.jar != null)
+         throw new IllegalStateException("jarFile has already been set");
+
+      this.jar = jarFile;
+
+      Enumeration<JarEntry> enumeration = jar.entries();
+      if (enumeration.hasMoreElements() == false)
+      {
+         entries = Collections.emptyList();
+         return;
+      }
+      
+      entries = new ArrayList<VirtualFileHandler>();
+      while (enumeration.hasMoreElements())
+      {
+         JarEntry entry = enumeration.nextElement();
+         VirtualFileHandler handler = createVirtualFileHandler(this, entry);
+         entries.add(handler);
+      }
+   }
+   
+   protected void doClose()
+   {
+      /* TODO Figure out why this breaks things randomly
+      try
+      {
+         if (jar != null)
+            jar.close();
+      }
+      catch (IOException ignored)
+      {
+      }
+      */
+   }
+
+   public boolean isArchive()
+   {
+      checkClosed();
+      return true;
+   }
+
+   public boolean isDirectory()
+   {
+      checkClosed();
+      return true;
+   }
+
+   public List<VirtualFileHandler> getChildren(boolean ignoreErrors) throws IOException
+   {
+      checkClosed();
+      return entries;
+   }
+
+   public VirtualFileHandler findChild(String path) throws IOException
+   {
+      if (path == null)
+         throw new IllegalArgumentException("Null path");
+
+      if (path.length() == 0)
+         return this;
+      
+      List<VirtualFileHandler> children = getChildren(false);
+      for (VirtualFileHandler child : children)
+      {
+         // Try a simple match
+         String name = child.getName();
+         if (name.equals(path))
+            return child;
+         
+         // Try a partial match on a nested jar
+         if (child.isArchive() && path.startsWith(name))
+         {
+            String remainingPath = path.substring(name.length()+1);
+            return child.findChild(remainingPath);
+         }
+      }
+      throw new IOException("Child not found " + path + " for " + this);
+   }
+
+   /**
+    * Create a new virtual file handler
+    * 
+    * @param parent the parent
+    * @param entry the entry
+    * @return the handler
+    * @throws IOException for any error accessing the file system
+    * @throws IllegalArgumentException for a null parent or entry
+    */
+   public VirtualFileHandler createVirtualFileHandler(VirtualFileHandler parent, JarEntry entry) throws IOException
+   {
+      if (parent == null)
+         throw new IllegalArgumentException("Null parent");
+      if (entry == null)
+         throw new IllegalArgumentException("Null entry");
+
+      // Question: Why doesn't this work properly?
+      // URL url = new URL(parent.toURL(), entry.getName());
+      StringBuilder buffer = new StringBuilder();
+      buffer.append(parent.toURL());
+      if (buffer.charAt(buffer.length()-1) != '/')
+         buffer.append('/');
+      buffer.append(entry.getName());
+      URL url = new URL(buffer.toString());
+
+      VFSContext context = parent.getVFSContext();
+      
+      if (JarUtils.isArchive(entry.getName()))
+         return new NestedJarHandler(context, parent, jar, entry, url);
+      return new JarEntryHandler(context, parent, jar, entry, url);
+   }
+}
Added: projects/microcontainer/trunk/container/src/main/org/jboss/virtual/plugins/context/jar/JarContext.java
===================================================================
--- projects/microcontainer/trunk/container/src/main/org/jboss/virtual/plugins/context/jar/JarContext.java	2006-09-06 11:18:17 UTC (rev 56598)
+++ projects/microcontainer/trunk/container/src/main/org/jboss/virtual/plugins/context/jar/JarContext.java	2006-09-06 11:27:07 UTC (rev 56599)
@@ -0,0 +1,96 @@
+/*
+* JBoss, Home of Professional Open Source
+* Copyright 2006, JBoss Inc., and individual contributors as indicated
+* by the @authors tag. See the copyright.txt in the distribution for a
+* full listing of individual contributors.
+*
+* This is free software; you can redistribute it and/or modify it
+* under the terms of the GNU Lesser General Public License as
+* published by the Free Software Foundation; either version 2.1 of
+* the License, or (at your option) any later version.
+*
+* This software is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public
+* License along with this software; if not, write to the Free
+* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+*/
+package org.jboss.virtual.plugins.context.jar;
+
+import java.io.IOException;
+import java.net.URL;
+
+import org.jboss.virtual.VirtualFile;
+import org.jboss.virtual.plugins.context.AbstractVFSContext;
+import org.jboss.virtual.spi.VirtualFileHandler;
+
+/**
+ * JarContext.
+ * 
+ * @author Scott.Stark at jboss.org
+ * @author <a href="adrian at jboss.com">Adrian Brock</a>
+ * @version $Revision: 1.1 $
+ */
+public class JarContext extends AbstractVFSContext
+{
+   /** The root file */
+   private final VirtualFileHandler root;
+   
+   /** A reference to the virtual file of the root to stop it getting closed */
+   private final VirtualFile rootFile;
+   
+   /**
+    * Create a new JarContext.
+    * 
+    * @param rootURL the root url
+    * @throws IOException for an error accessing the file system
+    */
+   public JarContext(URL rootURL) throws IOException
+   {
+      super(rootURL);
+      root = createVirtualFileHandler(null, rootURL);
+      rootFile = root.getVirtualFile();
+   }
+
+   public VirtualFileHandler getRoot() throws IOException
+   {
+      return root;
+   }
+
+   /**
+    * Create a new virtual file handler
+    * 
+    * @param parent the parent
+    * @param url the url
+    * @return the handler
+    * @throws IOException for any error accessing the file system
+    * @throws IllegalArgumentException for a null entry or url
+    */
+   public VirtualFileHandler createVirtualFileHandler(VirtualFileHandler parent, URL url) throws IOException
+   {
+      if (url == null)
+         throw new IllegalArgumentException("Null url");
+
+      String name = url.toString();
+      int index = name.indexOf('!');
+      if (index != -1)
+         name = name.substring(0, index);
+      index = name.lastIndexOf('/');
+      if (index != -1 && index < name.length()-1)
+         name = name.substring(index+1);
+      
+      return new JarHandler(this, parent, url, name);
+   }
+   
+   @Override
+   protected void finalize() throws Throwable
+   {
+      if (rootFile != null)
+         rootFile.close();
+      super.finalize();
+   }
+}
Added: projects/microcontainer/trunk/container/src/main/org/jboss/virtual/plugins/context/jar/JarContextFactory.java
===================================================================
--- projects/microcontainer/trunk/container/src/main/org/jboss/virtual/plugins/context/jar/JarContextFactory.java	2006-09-06 11:18:17 UTC (rev 56598)
+++ projects/microcontainer/trunk/container/src/main/org/jboss/virtual/plugins/context/jar/JarContextFactory.java	2006-09-06 11:27:07 UTC (rev 56599)
@@ -0,0 +1,51 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2005, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.virtual.plugins.context.jar;
+
+import java.net.URL;
+import java.io.IOException;
+
+import org.jboss.virtual.spi.VFSContext;
+import org.jboss.virtual.spi.VFSContextFactory;
+
+/**
+ * A jar context factory
+ * 
+ * @author Scott.Stark at jboss.org
+ * @author adrian at jboss.org
+ * @version $Revision: 44217 $
+ */
+public class JarContextFactory implements VFSContextFactory
+{
+   /** The protocols supported */
+   private static final String[] PROTOCOLS = { "jar" };
+
+   public String[] getProtocols()
+   {
+      return PROTOCOLS;
+   }
+
+   public VFSContext getVFS(URL root) throws IOException
+   {
+      return new JarContext(root);
+   }
+}
Added: projects/microcontainer/trunk/container/src/main/org/jboss/virtual/plugins/context/jar/JarEntryHandler.java
===================================================================
--- projects/microcontainer/trunk/container/src/main/org/jboss/virtual/plugins/context/jar/JarEntryHandler.java	2006-09-06 11:18:17 UTC (rev 56598)
+++ projects/microcontainer/trunk/container/src/main/org/jboss/virtual/plugins/context/jar/JarEntryHandler.java	2006-09-06 11:27:07 UTC (rev 56599)
@@ -0,0 +1,135 @@
+/*
+* JBoss, Home of Professional Open Source
+* Copyright 2006, JBoss Inc., and individual contributors as indicated
+* by the @authors tag. See the copyright.txt in the distribution for a
+* full listing of individual contributors.
+*
+* This is free software; you can redistribute it and/or modify it
+* under the terms of the GNU Lesser General Public License as
+* published by the Free Software Foundation; either version 2.1 of
+* the License, or (at your option) any later version.
+*
+* This software is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public
+* License along with this software; if not, write to the Free
+* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+*/
+package org.jboss.virtual.plugins.context.jar;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.Collections;
+import java.util.List;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+
+import org.jboss.virtual.plugins.context.AbstractURLHandler;
+import org.jboss.virtual.spi.VFSContext;
+import org.jboss.virtual.spi.VirtualFileHandler;
+
+/**
+ * JarEntryHandler.
+ * 
+ * @author <a href="adrian at jboss.com">Adrian Brock</a>
+ * @version $Revision: 1.1 $
+ */
+public class JarEntryHandler extends AbstractURLHandler
+{
+   /** The jar file */
+   private final JarFile jar;
+   
+   /** The jar entry */
+   private final JarEntry entry;
+
+   
+   
+   /**
+    * Create a new JarHandler.
+    * 
+    * @param context the context
+    * @param parent the parent
+    * @param jar the jar file
+    * @param entry the entry
+    * @param url the url
+    * @throws IOException for an error accessing the file system
+    * @throws IllegalArgumentException for a null context, url, jar or entry
+    */
+   public JarEntryHandler(VFSContext context, VirtualFileHandler parent, JarFile jar, JarEntry entry, URL url) throws IOException
+   {
+      super(context, parent, url, AbstractJarHandler.getEntryName(entry));
+      if (jar == null)
+         throw new IllegalArgumentException("Null jar");
+      
+      this.jar = jar;
+      this.entry = entry;
+   }
+   
+   /**
+    * Get the entry
+    * 
+    * @return the file
+    */
+   protected JarEntry getEntry()
+   {
+      checkClosed();
+      return entry;
+   }
+   
+   @Override
+   public long getLastModified()
+   {
+      return getEntry().getTime();
+   }
+
+   @Override
+   public long getSize()
+   {
+      return getEntry().getSize();
+   }
+
+   public boolean isArchive()
+   {
+      checkClosed();
+      return false;
+   }
+
+   public boolean isDirectory()
+   {
+      return getEntry().isDirectory();
+   }
+
+   public boolean isFile()
+   {
+      return isDirectory() == false;
+   }
+
+   public boolean isHidden()
+   {
+      checkClosed();
+      return false;
+   }
+
+   @Override
+   public InputStream openStream() throws IOException
+   {
+      return jar.getInputStream(getEntry());
+   }
+
+   public List<VirtualFileHandler> getChildren(boolean ignoreErrors) throws IOException
+   {
+      checkClosed();
+      return Collections.emptyList();
+   }
+
+   public VirtualFileHandler findChild(String path) throws IOException
+   {
+      checkClosed();
+      throw new IOException("A JarEntry has no children: " + path + " for " + this);
+   }
+}
Added: projects/microcontainer/trunk/container/src/main/org/jboss/virtual/plugins/context/jar/JarHandler.java
===================================================================
--- projects/microcontainer/trunk/container/src/main/org/jboss/virtual/plugins/context/jar/JarHandler.java	2006-09-06 11:18:17 UTC (rev 56598)
+++ projects/microcontainer/trunk/container/src/main/org/jboss/virtual/plugins/context/jar/JarHandler.java	2006-09-06 11:27:07 UTC (rev 56599)
@@ -0,0 +1,66 @@
+/*
+* JBoss, Home of Professional Open Source
+* Copyright 2006, JBoss Inc., and individual contributors as indicated
+* by the @authors tag. See the copyright.txt in the distribution for a
+* full listing of individual contributors.
+*
+* This is free software; you can redistribute it and/or modify it
+* under the terms of the GNU Lesser General Public License as
+* published by the Free Software Foundation; either version 2.1 of
+* the License, or (at your option) any later version.
+*
+* This software is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public
+* License along with this software; if not, write to the Free
+* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+*/
+package org.jboss.virtual.plugins.context.jar;
+
+import java.io.IOException;
+import java.net.JarURLConnection;
+import java.net.URL;
+
+import org.jboss.virtual.spi.VFSContext;
+import org.jboss.virtual.spi.VirtualFileHandler;
+
+/**
+ * JarHandler.
+ * 
+ * @author <a href="adrian at jboss.com">Adrian Brock</a>
+ * @version $Revision: 1.1 $
+ */
+public class JarHandler extends AbstractJarHandler
+{
+   /**
+    * Create a new JarHandler.
+    * 
+    * @param context the context
+    * @param parent the parent
+    * @param url the url
+    * @param name the name
+    * @throws IOException for an error accessing the file system
+    * @throws IllegalArgumentException for a null context, url or vfsPath
+    */
+   public JarHandler(VFSContext context, VirtualFileHandler parent, URL url, String name) throws IOException
+   {
+      super(context, parent, url, name);
+
+      try
+      {
+         JarURLConnection connection =  (JarURLConnection) url.openConnection();
+         initJarFile(connection.getJarFile());
+      }
+      catch (IOException original)
+      {
+         // Fix the context of the error message
+         IOException e = new IOException("Error opening jar file: " + url + " reason=" + original.getMessage());
+         e.setStackTrace(original.getStackTrace());
+         throw e;
+      }
+   }
+}
Added: projects/microcontainer/trunk/container/src/main/org/jboss/virtual/plugins/context/jar/JarUtils.java
===================================================================
--- projects/microcontainer/trunk/container/src/main/org/jboss/virtual/plugins/context/jar/JarUtils.java	2006-09-06 11:18:17 UTC (rev 56598)
+++ projects/microcontainer/trunk/container/src/main/org/jboss/virtual/plugins/context/jar/JarUtils.java	2006-09-06 11:27:07 UTC (rev 56599)
@@ -0,0 +1,119 @@
+/*
+* JBoss, Home of Professional Open Source
+* Copyright 2006, JBoss Inc., and individual contributors as indicated
+* by the @authors tag. See the copyright.txt in the distribution for a
+* full listing of individual contributors.
+*
+* This is free software; you can redistribute it and/or modify it
+* under the terms of the GNU Lesser General Public License as
+* published by the Free Software Foundation; either version 2.1 of
+* the License, or (at your option) any later version.
+*
+* This software is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public
+* License along with this software; if not, write to the Free
+* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+*/
+package org.jboss.virtual.plugins.context.jar;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Set;
+import java.util.concurrent.CopyOnWriteArraySet;
+
+/**
+ * JarUtils.
+ * 
+ * @author <a href="adrian at jboss.com">Adrian Brock</a>
+ * @version $Revision: 1.1 $
+ */
+public class JarUtils
+{
+   /** The jar suffixes */
+   private static Set<String> jarSuffixes = new CopyOnWriteArraySet<String>();
+
+   // Initialise known suffixes
+   static
+   {
+      jarSuffixes.add(".ear");
+      jarSuffixes.add(".jar");
+      jarSuffixes.add(".rar");
+      jarSuffixes.add(".war");
+      jarSuffixes.add(".sar");
+      jarSuffixes.add(".har");
+   }
+
+   /**
+    * Add a jar suffix
+    * 
+    * @param suffix the suffix
+    * @return true when added
+    * @throws IllegalArgumentException for a null suffix
+    */
+   public static boolean addJarSuffix(String suffix)
+   {
+      if (suffix == null)
+         throw new IllegalArgumentException("Null suffix");
+      return jarSuffixes.add(suffix);
+   }
+
+   /**
+    * Remove a jar suffix
+    * 
+    * @param suffix the suffix
+    * @return true when removed
+    * @throws IllegalArgumentException for a null suffix
+    */
+   public static boolean removeJarSuffix(String suffix)
+   {
+      if (suffix == null)
+         throw new IllegalArgumentException("Null suffix");
+      return jarSuffixes.remove(suffix);
+   }
+
+   /**
+    * Utilities
+    */
+   private JarUtils()
+   {
+   }
+   
+   /**
+    * Whether this is an archive
+    *
+    * @param name the name
+    * @return true when an archive
+    * @throws IllegalArgumentException for a null name
+    */
+   public static boolean isArchive(String name)
+   {
+      if (name == null)
+         throw new IllegalArgumentException("Null name");
+      
+      int index = name.lastIndexOf('.');
+      if (index == -1)
+         return false;
+      String suffix = name.substring(index);
+      return jarSuffixes.contains(suffix);
+   }
+   
+   /**
+    * Create a jar url from a normal url
+    * 
+    * @param url the normal url
+    * @return the jar url
+    * @throws MalformedURLException if the url is malformed
+    * @throws IllegalArgumentException for a null url
+    */
+   public static URL createJarURL(URL url) throws MalformedURLException
+   {
+      if (url == null)
+         throw new IllegalArgumentException("Null url");
+      return new URL("jar:" + url + "!/");
+   }
+}
Added: projects/microcontainer/trunk/container/src/main/org/jboss/virtual/plugins/context/jar/NestedJarHandler.java
===================================================================
--- projects/microcontainer/trunk/container/src/main/org/jboss/virtual/plugins/context/jar/NestedJarHandler.java	2006-09-06 11:18:17 UTC (rev 56598)
+++ projects/microcontainer/trunk/container/src/main/org/jboss/virtual/plugins/context/jar/NestedJarHandler.java	2006-09-06 11:27:07 UTC (rev 56599)
@@ -0,0 +1,151 @@
+/*
+* JBoss, Home of Professional Open Source
+* Copyright 2006, JBoss Inc., and individual contributors as indicated
+* by the @authors tag. See the copyright.txt in the distribution for a
+* full listing of individual contributors.
+*
+* This is free software; you can redistribute it and/or modify it
+* under the terms of the GNU Lesser General Public License as
+* published by the Free Software Foundation; either version 2.1 of
+* the License, or (at your option) any later version.
+*
+* This software is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public
+* License along with this software; if not, write to the Free
+* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+*/
+package org.jboss.virtual.plugins.context.jar;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+
+import org.jboss.virtual.spi.VFSContext;
+import org.jboss.virtual.spi.VirtualFileHandler;
+
+/**
+ * Nested Jar Handler.
+ * 
+ * @author <a href="adrian at jboss.com">Adrian Brock</a>
+ * @version $Revision: 1.1 $
+ */
+public class NestedJarHandler extends AbstractJarHandler
+{
+   /** The jar entry */
+   private JarEntry entry;
+   
+   /**
+    * Create a temporary jar
+    * 
+    * @param parentJar the jar
+    * @param entry the jar entry
+    * @return the jar file
+    * @throws IOException for any error
+    */
+   private static JarFile createTempJar(JarFile parentJar, JarEntry entry) throws IOException
+   {
+      File temp = File.createTempFile("nestedjar", null);
+      temp.deleteOnExit();
+
+      InputStream inputStream = parentJar.getInputStream(entry);
+      try
+      {
+         FileOutputStream outputStream = new FileOutputStream(temp);
+         try
+         {
+            byte[] buffer = new byte[8096];
+            int read = inputStream.read(buffer);
+            while (read != -1)
+            {
+               outputStream.write(buffer, 0, read);
+               read = inputStream.read(buffer);
+            }
+         }
+         finally
+         {
+            outputStream.close();
+         }
+      }
+      finally
+      {
+         try
+         {
+            inputStream.close();
+         }
+         catch (IOException ignored)
+         {
+         }
+      }
+      
+      return new JarFile(temp);
+   }
+   
+   /**
+    * Create a new NestedJarHandler.
+    * 
+    * @param context the context
+    * @param parent the parent
+    * @param parentJar the parent jar file
+    * @param entry the jar entry
+    * @param url the url
+    * @throws IOException for an error accessing the file system
+    * @throws IllegalArgumentException for a null context, url or vfsPath
+    */
+   public NestedJarHandler(VFSContext context, VirtualFileHandler parent, JarFile parentJar, JarEntry entry, URL url) throws IOException
+   {
+      super(context, parent, url, getEntryName(entry));
+
+      
+      try
+      {
+         initJarFile(createTempJar(parentJar, entry));
+      }
+      catch (IOException original)
+      {
+         // Fix the context of the error message
+         IOException e = new IOException("Error opening jar file: " + url + " reason=" + original.getMessage());
+         e.setStackTrace(original.getStackTrace());
+         throw e;
+      }
+      
+      this.entry = entry;
+   }
+   
+   /**
+    * Get the entry
+    * 
+    * @return the file
+    */
+   protected JarEntry getEntry()
+   {
+      checkClosed();
+      return entry;
+   }
+
+   @Override
+   public long getLastModified() throws IOException
+   {
+      return getEntry().getTime();
+   }
+
+   @Override
+   public long getSize() throws IOException
+   {
+      return getEntry().getSize();
+   }
+
+   @Override
+   public InputStream openStream() throws IOException
+   {
+      return getJar().getInputStream(getEntry());
+   }
+}
Added: projects/microcontainer/trunk/container/src/main/org/jboss/virtual/plugins/vfs/helpers/AbstractVirtualFileHandlerVisitor.java
===================================================================
--- projects/microcontainer/trunk/container/src/main/org/jboss/virtual/plugins/vfs/helpers/AbstractVirtualFileHandlerVisitor.java	2006-09-06 11:18:17 UTC (rev 56598)
+++ projects/microcontainer/trunk/container/src/main/org/jboss/virtual/plugins/vfs/helpers/AbstractVirtualFileHandlerVisitor.java	2006-09-06 11:27:07 UTC (rev 56599)
@@ -0,0 +1,62 @@
+/*
+* JBoss, Home of Professional Open Source
+* Copyright 2006, JBoss Inc., and individual contributors as indicated
+* by the @authors tag. See the copyright.txt in the distribution for a
+* full listing of individual contributors.
+*
+* This is free software; you can redistribute it and/or modify it
+* under the terms of the GNU Lesser General Public License as
+* published by the Free Software Foundation; either version 2.1 of
+* the License, or (at your option) any later version.
+*
+* This software is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public
+* License along with this software; if not, write to the Free
+* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+*/
+package org.jboss.virtual.plugins.vfs.helpers;
+
+import org.jboss.virtual.VisitorAttributes;
+import org.jboss.virtual.spi.VirtualFileHandlerVisitor;
+
+/**
+ * AbstractVirtualFileVisitor.
+ * 
+ * @author <a href="adrian at jboss.com">Adrian Brock</a>
+ * @version $Revision: 1.1 $
+ */
+public abstract class AbstractVirtualFileHandlerVisitor implements VirtualFileHandlerVisitor
+{
+   private final VisitorAttributes attributes;
+
+   /**
+    * Create a new AbstractVirtualFileVisitor using the default visitor attributes
+    */
+   protected AbstractVirtualFileHandlerVisitor()
+   {
+      this(VisitorAttributes.DEFAULT);
+   }
+
+   /**
+    * Create a new AbstractVirtualFileVisitor using the default visitor attributes
+    * 
+    * @param attributes the attributes
+    * @throws IllegalArgumentException if the attributes are null
+    */
+   protected AbstractVirtualFileHandlerVisitor(VisitorAttributes attributes)
+   {
+      if (attributes == null)
+         throw new IllegalArgumentException("Null attributes");
+      this.attributes = attributes;
+   }
+   
+   public VisitorAttributes getAttributes()
+   {
+      return attributes;
+   }
+}
Added: projects/microcontainer/trunk/container/src/main/org/jboss/virtual/plugins/vfs/helpers/AbstractVirtualFileVisitor.java
===================================================================
--- projects/microcontainer/trunk/container/src/main/org/jboss/virtual/plugins/vfs/helpers/AbstractVirtualFileVisitor.java	2006-09-06 11:18:17 UTC (rev 56598)
+++ projects/microcontainer/trunk/container/src/main/org/jboss/virtual/plugins/vfs/helpers/AbstractVirtualFileVisitor.java	2006-09-06 11:27:07 UTC (rev 56599)
@@ -0,0 +1,61 @@
+/*
+* JBoss, Home of Professional Open Source
+* Copyright 2006, JBoss Inc., and individual contributors as indicated
+* by the @authors tag. See the copyright.txt in the distribution for a
+* full listing of individual contributors.
+*
+* This is free software; you can redistribute it and/or modify it
+* under the terms of the GNU Lesser General Public License as
+* published by the Free Software Foundation; either version 2.1 of
+* the License, or (at your option) any later version.
+*
+* This software is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public
+* License along with this software; if not, write to the Free
+* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+*/
+package org.jboss.virtual.plugins.vfs.helpers;
+
+import org.jboss.virtual.VirtualFileVisitor;
+import org.jboss.virtual.VisitorAttributes;
+
+/**
+ * AbstractVirtualFileVisitor.
+ * 
+ * @author <a href="adrian at jboss.com">Adrian Brock</a>
+ * @version $Revision: 1.1 $
+ */
+public abstract class AbstractVirtualFileVisitor implements VirtualFileVisitor
+{
+   private final VisitorAttributes attributes;
+
+   /**
+    * Create a new AbstractVirtualFileVisitor using the default visitor attributes
+    */
+   protected AbstractVirtualFileVisitor()
+   {
+      this(null);
+   }
+
+   /**
+    * Create a new AbstractVirtualFileVisitor using the default visitor attributes
+    * 
+    * @param attributes the attributes, uses the default if null
+    */
+   protected AbstractVirtualFileVisitor(VisitorAttributes attributes)
+   {
+      if (attributes == null)
+         attributes = VisitorAttributes.DEFAULT;
+      this.attributes = attributes;
+   }
+   
+   public VisitorAttributes getAttributes()
+   {
+      return attributes;
+   }
+}
Added: projects/microcontainer/trunk/container/src/main/org/jboss/virtual/plugins/vfs/helpers/FilterVirtualFileVisitor.java
===================================================================
--- projects/microcontainer/trunk/container/src/main/org/jboss/virtual/plugins/vfs/helpers/FilterVirtualFileVisitor.java	2006-09-06 11:18:17 UTC (rev 56598)
+++ projects/microcontainer/trunk/container/src/main/org/jboss/virtual/plugins/vfs/helpers/FilterVirtualFileVisitor.java	2006-09-06 11:27:07 UTC (rev 56599)
@@ -0,0 +1,118 @@
+/*
+* JBoss, Home of Professional Open Source
+* Copyright 2006, JBoss Inc., and individual contributors as indicated
+* by the @authors tag. See the copyright.txt in the distribution for a
+* full listing of individual contributors.
+*
+* This is free software; you can redistribute it and/or modify it
+* under the terms of the GNU Lesser General Public License as
+* published by the Free Software Foundation; either version 2.1 of
+* the License, or (at your option) any later version.
+*
+* This software is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public
+* License along with this software; if not, write to the Free
+* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+*/
+package org.jboss.virtual.plugins.vfs.helpers;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.jboss.virtual.VirtualFile;
+import org.jboss.virtual.VirtualFileFilter;
+import org.jboss.virtual.VirtualFileFilterWithAttributes;
+import org.jboss.virtual.VisitorAttributes;
+
+/**
+ * A visitor based on a virtual file filter
+ * 
+ * @author <a href="adrian at jboss.com">Adrian Brock</a>
+ * @version $Revision: 1.1 $
+ */
+public class FilterVirtualFileVisitor extends AbstractVirtualFileVisitor
+{
+   /** The filter */
+   private final VirtualFileFilter filter;
+   
+   /** What is matched */
+   private List<VirtualFile> matched;
+
+   /**
+    * Check the attributes
+    * 
+    * @param filter the filter
+    * @param attributes the attributes
+    * @return the attributes
+    * @throws IllegalArgumentException for a null filter
+    */
+   private static VisitorAttributes checkAttributes(VirtualFileFilter filter, VisitorAttributes attributes)
+   {
+      if (filter == null)
+         throw new IllegalArgumentException("Null filter");
+
+      // Specified
+      if (attributes != null)
+         return attributes;
+      
+      // From the filter
+      if (filter instanceof VirtualFileFilterWithAttributes)
+         return ((VirtualFileFilterWithAttributes) filter).getAttributes();
+      
+      // It will use the default
+      return null;
+   }
+   
+   /**
+    * Create a new FilterVirtualFileVisitor with default attributes
+    * 
+    * @param filter the filter
+    * @throws IllegalArgumentException if the filter is null
+    */
+   public FilterVirtualFileVisitor(VirtualFileFilter filter)
+   {
+      this(filter, null);
+   }
+   
+   /**
+    * Create a new FilterVirtualFileVisitor.
+    * 
+    * @param filter the filter
+    * @param attributes the attributes, uses the default if null
+    * @throws IllegalArgumentException if the filter is null
+    */
+   public FilterVirtualFileVisitor(VirtualFileFilter filter, VisitorAttributes attributes)
+   {
+      super(checkAttributes(filter, attributes));
+      this.filter = filter;
+   }
+
+   /**
+    * Get the matched files
+    * 
+    * @return the matched files
+    */
+   public List<VirtualFile> getMatched()
+   {
+      if (matched == null)
+         return Collections.emptyList();
+      else
+         return matched;
+   }
+   
+   public void visit(VirtualFile virtualFile)
+   {
+      if (filter.accepts(virtualFile))
+      {
+         if (matched == null)
+            matched = new ArrayList<VirtualFile>();
+         matched.add(virtualFile);
+      }
+   }
+}
Added: projects/microcontainer/trunk/container/src/main/org/jboss/virtual/plugins/vfs/helpers/MatchAllVirtualFileFilter.java
===================================================================
--- projects/microcontainer/trunk/container/src/main/org/jboss/virtual/plugins/vfs/helpers/MatchAllVirtualFileFilter.java	2006-09-06 11:18:17 UTC (rev 56598)
+++ projects/microcontainer/trunk/container/src/main/org/jboss/virtual/plugins/vfs/helpers/MatchAllVirtualFileFilter.java	2006-09-06 11:27:07 UTC (rev 56599)
@@ -0,0 +1,49 @@
+/*
+* JBoss, Home of Professional Open Source
+* Copyright 2006, JBoss Inc., and individual contributors as indicated
+* by the @authors tag. See the copyright.txt in the distribution for a
+* full listing of individual contributors.
+*
+* This is free software; you can redistribute it and/or modify it
+* under the terms of the GNU Lesser General Public License as
+* published by the Free Software Foundation; either version 2.1 of
+* the License, or (at your option) any later version.
+*
+* This software is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public
+* License along with this software; if not, write to the Free
+* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+*/
+package org.jboss.virtual.plugins.vfs.helpers;
+
+import org.jboss.virtual.VirtualFile;
+import org.jboss.virtual.VirtualFileFilter;
+
+/**
+ * MatchAllVirtualFileFilter.
+ * 
+ * @author <a href="adrian at jboss.com">Adrian Brock</a>
+ * @version $Revision: 1.1 $
+ */
+public class MatchAllVirtualFileFilter implements VirtualFileFilter
+{
+   /** The instance */
+   public static final MatchAllVirtualFileFilter INSTANCE = new MatchAllVirtualFileFilter();
+
+   /**
+    * Singleton 
+    */
+   private MatchAllVirtualFileFilter()
+   {
+   }
+   
+   public boolean accepts(VirtualFile file)
+   {
+      return true;
+   }
+}
Added: projects/microcontainer/trunk/container/src/main/org/jboss/virtual/plugins/vfs/helpers/PathTokenizer.java
===================================================================
--- projects/microcontainer/trunk/container/src/main/org/jboss/virtual/plugins/vfs/helpers/PathTokenizer.java	2006-09-06 11:18:17 UTC (rev 56598)
+++ projects/microcontainer/trunk/container/src/main/org/jboss/virtual/plugins/vfs/helpers/PathTokenizer.java	2006-09-06 11:27:07 UTC (rev 56599)
@@ -0,0 +1,101 @@
+/*
+* JBoss, Home of Professional Open Source
+* Copyright 2006, JBoss Inc., and individual contributors as indicated
+* by the @authors tag. See the copyright.txt in the distribution for a
+* full listing of individual contributors.
+*
+* This is free software; you can redistribute it and/or modify it
+* under the terms of the GNU Lesser General Public License as
+* published by the Free Software Foundation; either version 2.1 of
+* the License, or (at your option) any later version.
+*
+* This software is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public
+* License along with this software; if not, write to the Free
+* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+*/
+package org.jboss.virtual.plugins.vfs.helpers;
+
+import java.util.StringTokenizer;
+
+/**
+ * PathTokenizer.
+ * 
+ * @author <a href="adrian at jboss.com">Adrian Brock</a>
+ * @version $Revision: 1.1 $
+ */
+public class PathTokenizer
+{
+   /**
+    * Utility class
+    */
+   private PathTokenizer()
+   {
+   }
+   
+   /**
+    * Get the tokens
+    * 
+    * @param path the path
+    * @return the tokens or null if the path is empty
+    * @throws IllegalArgumentException if the path is null, it is empty or it is a relative path
+    */
+   public static String[] getTokens(String path)
+   {
+      if (path == null)
+         throw new IllegalArgumentException("Null path");
+
+      StringTokenizer tokenizer = new StringTokenizer(path, "/");
+      int count = tokenizer.countTokens();
+      if (count == 0)
+         return null;
+
+      String[] tokens = new String[count];
+      int i = 0;
+      while (tokenizer.hasMoreTokens())
+      {
+         String token = tokenizer.nextToken();
+
+         if (token.equals(""))
+            throw new IllegalArgumentException("A path element is empty: " + path);
+         if (token.equals(".") || token.equals(".."))
+            throw new IllegalArgumentException("Reverse paths are not allowed (containing a . or ..), use getParent(): " + path);
+
+         tokens[i++] = token;
+      }
+      return tokens;
+   }
+   
+   /**
+    * Get the remaining path from some tokens
+    * 
+    * @param tokens the tokens
+    * @param i the current location
+    * @return the remaining path
+    * @throws IllegalArgumentException for null tokens or i is out of range
+    */
+   public static String getRemainingPath(String[] tokens, int i)
+   {
+      if (tokens == null)
+         throw new IllegalArgumentException("Null tokens");
+      if (i < 0 || i >= tokens.length)
+         throw new IllegalArgumentException("i is not in the range of tokens: 0" + (tokens.length-1));
+      
+      if (i == tokens.length-1)
+         return tokens[tokens.length-1];
+      
+      StringBuilder buffer = new StringBuilder();
+      for (; i < tokens.length-1; ++i)
+      {
+         buffer.append(tokens[i]);
+         buffer.append("/");
+      }
+      buffer.append(tokens[tokens.length-1]);
+      return buffer.toString();
+   }
+}
Added: projects/microcontainer/trunk/container/src/main/org/jboss/virtual/plugins/vfs/helpers/SuffixMatchFilter.java
===================================================================
--- projects/microcontainer/trunk/container/src/main/org/jboss/virtual/plugins/vfs/helpers/SuffixMatchFilter.java	2006-09-06 11:18:17 UTC (rev 56598)
+++ projects/microcontainer/trunk/container/src/main/org/jboss/virtual/plugins/vfs/helpers/SuffixMatchFilter.java	2006-09-06 11:27:07 UTC (rev 56599)
@@ -0,0 +1,82 @@
+/*
+  * JBoss, Home of Professional Open Source
+  * Copyright 2005, JBoss Inc., and individual contributors as indicated
+  * by the @authors tag. See the copyright.txt in the distribution for a
+  * full listing of individual contributors.
+  *
+  * This is free software; you can redistribute it and/or modify it
+  * under the terms of the GNU Lesser General Public License as
+  * published by the Free Software Foundation; either version 2.1 of
+  * the License, or (at your option) any later version.
+  *
+  * This software is distributed in the hope that it will be useful,
+  * but WITHOUT ANY WARRANTY; without even the implied warranty of
+  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  * Lesser General Public License for more details.
+  *
+  * You should have received a copy of the GNU Lesser General Public
+  * License along with this software; if not, write to the Free
+  * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+  * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+  */
+package org.jboss.virtual.plugins.vfs.helpers;
+
+import org.jboss.virtual.VirtualFile;
+import org.jboss.virtual.VirtualFileFilterWithAttributes;
+import org.jboss.virtual.VisitorAttributes;
+
+/**
+ * Matches a suffix recursively
+ * 
+ * @author Scott.Stark at jboss.org
+ * @author adrian at jboss.org
+ * @version $Revision: 44223 $
+ */
+public class SuffixMatchFilter implements VirtualFileFilterWithAttributes
+{
+   /** The suffix */
+   private String suffix;
+   
+   /** The attributes */
+   private VisitorAttributes attributes;
+   
+   /**
+    * Create a new SuffixMatchVisitor,
+    * using {@link VisitorAttributes#RECURSE_NO_DIRECTORIES}
+    * 
+    * @param suffix the suffix
+    * @throws IllegalArgumentException for a null suffix
+    */
+   public SuffixMatchFilter(String suffix)
+   {
+      this(suffix, null);
+   }
+   
+   /**
+    * Create a new SuffixMatchVisitor.
+    * 
+    * @param suffix the suffix
+    * @param attributes the attributes, pass null to use {@link VisitorAttributes#RECURSE_NO_DIRECTORIES}
+    * @throws IllegalArgumentException for a null suffix
+    */
+   public SuffixMatchFilter(String suffix, VisitorAttributes attributes)
+   {
+      if (suffix == null)
+         throw new IllegalArgumentException("Null suffix");
+      this.suffix = suffix;
+      if (attributes == null)
+         attributes = VisitorAttributes.RECURSE_NO_DIRECTORIES;
+      this.attributes = attributes;
+   }
+   
+   public VisitorAttributes getAttributes()
+   {
+      return attributes;
+   }
+
+   public boolean accepts(VirtualFile file)
+   {
+      String name = file.getName();
+      return name.endsWith(suffix);
+   }
+}
Added: projects/microcontainer/trunk/container/src/main/org/jboss/virtual/plugins/vfs/helpers/WrappingVirtualFileHandlerVisitor.java
===================================================================
--- projects/microcontainer/trunk/container/src/main/org/jboss/virtual/plugins/vfs/helpers/WrappingVirtualFileHandlerVisitor.java	2006-09-06 11:18:17 UTC (rev 56598)
+++ projects/microcontainer/trunk/container/src/main/org/jboss/virtual/plugins/vfs/helpers/WrappingVirtualFileHandlerVisitor.java	2006-09-06 11:27:07 UTC (rev 56599)
@@ -0,0 +1,64 @@
+/*
+* JBoss, Home of Professional Open Source
+* Copyright 2006, JBoss Inc., and individual contributors as indicated
+* by the @authors tag. See the copyright.txt in the distribution for a
+* full listing of individual contributors.
+*
+* This is free software; you can redistribute it and/or modify it
+* under the terms of the GNU Lesser General Public License as
+* published by the Free Software Foundation; either version 2.1 of
+* the License, or (at your option) any later version.
+*
+* This software is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public
+* License along with this software; if not, write to the Free
+* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+*/
+package org.jboss.virtual.plugins.vfs.helpers;
+
+import org.jboss.virtual.VirtualFile;
+import org.jboss.virtual.VirtualFileVisitor;
+import org.jboss.virtual.VisitorAttributes;
+import org.jboss.virtual.spi.VirtualFileHandler;
+import org.jboss.virtual.spi.VirtualFileHandlerVisitor;
+
+/**
+ * A handler visitor that wraps a normal file visitor
+ * 
+ * @author <a href="adrian at jboss.com">Adrian Brock</a>
+ * @version $Revision: 1.1 $
+ */
+public class WrappingVirtualFileHandlerVisitor implements VirtualFileHandlerVisitor
+{
+   /** The wrapped visitor */
+   private final VirtualFileVisitor visitor;
+   
+   /**
+    * Create a new WrappingVirtualFileHandlerVisitor.
+    * 
+    * @param visitor the visitor
+    * @throws IllegalArgumentException if the visitor is null
+    */
+   public WrappingVirtualFileHandlerVisitor(VirtualFileVisitor visitor)
+   {
+      if (visitor == null)
+         throw new IllegalArgumentException("Null visitor");
+      this.visitor = visitor;
+   }
+   
+   public VisitorAttributes getAttributes()
+   {
+      return visitor.getAttributes();
+   }
+
+   public void visit(VirtualFileHandler handler)
+   {
+      VirtualFile file  = handler.getVirtualFile();
+      visitor.visit(file);
+   }
+}
Added: projects/microcontainer/trunk/container/src/main/org/jboss/virtual/spi/VFSContext.java
===================================================================
--- projects/microcontainer/trunk/container/src/main/org/jboss/virtual/spi/VFSContext.java	2006-09-06 11:18:17 UTC (rev 56598)
+++ projects/microcontainer/trunk/container/src/main/org/jboss/virtual/spi/VFSContext.java	2006-09-06 11:27:07 UTC (rev 56599)
@@ -0,0 +1,93 @@
+/*
+  * JBoss, Home of Professional Open Source
+  * Copyright 2005, JBoss Inc., and individual contributors as indicated
+  * by the @authors tag. See the copyright.txt in the distribution for a
+  * full listing of individual contributors.
+  *
+  * This is free software; you can redistribute it and/or modify it
+  * under the terms of the GNU Lesser General Public License as
+  * published by the Free Software Foundation; either version 2.1 of
+  * the License, or (at your option) any later version.
+  *
+  * This software is distributed in the hope that it will be useful,
+  * but WITHOUT ANY WARRANTY; without even the implied warranty of
+  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  * Lesser General Public License for more details.
+  *
+  * You should have received a copy of the GNU Lesser General Public
+  * License along with this software; if not, write to the Free
+  * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+  * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+  */
+package org.jboss.virtual.spi;
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.List;
+
+import org.jboss.virtual.VFS;
+
+/** 
+ * A virtual file context
+ * 
+ * @author Scott.Stark at jboss.org
+ * @author adrian at jboss.org
+ * @version $Revision: 55466 $
+ */
+public interface VFSContext
+{
+   /**
+    * Get the root url
+    * 
+    * @return the root url
+    */
+   URL getRootURL();
+   
+   
+   /**
+    * Get the VFS for this context
+    * 
+    * @return the vfs
+    */
+   VFS getVFS();
+   
+   /**
+    * Return the root virtual file
+    * 
+    * @return the root
+    * @throws IOException for any problem accessing the VFS
+    */
+   VirtualFileHandler getRoot() throws IOException;
+   
+   /**
+    * Get the children
+    * 
+    * @param parent the parent
+    * @param ignoreErrors whether to ignore errors
+    * @return the children
+    * @throws IOException for any problem accessing the VFS
+    * @throws IllegalArgumentException for a null parent
+    */
+   List<VirtualFileHandler> getChildren(VirtualFileHandler parent, boolean ignoreErrors) throws IOException;
+   
+   /**
+    * Find a child
+    * 
+    * @param parent the parent
+    * @param path the path
+    * @return the child
+    * @throws IOException for any problem accessing the VFS
+    * @throws IllegalArgumentException for a null parent or name
+    */
+   VirtualFileHandler findChild(VirtualFileHandler parent, String path) throws IOException;
+   
+   /**
+    * Visit the virtual file system
+    * 
+    * @param handler the reference handler
+    * @param visitor the visitor
+    * @throws IOException for any error
+    * @throws IllegalArgumentException if the handler or visitor is null
+    */
+   void visit(VirtualFileHandler handler, VirtualFileHandlerVisitor visitor) throws IOException;
+}
Added: projects/microcontainer/trunk/container/src/main/org/jboss/virtual/spi/VFSContextFactory.java
===================================================================
--- projects/microcontainer/trunk/container/src/main/org/jboss/virtual/spi/VFSContextFactory.java	2006-09-06 11:18:17 UTC (rev 56598)
+++ projects/microcontainer/trunk/container/src/main/org/jboss/virtual/spi/VFSContextFactory.java	2006-09-06 11:27:07 UTC (rev 56599)
@@ -0,0 +1,51 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2005, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.virtual.spi;
+
+import java.net.URL;
+import java.io.IOException;
+
+/**
+ * The entry point to obtaining a VFSContext for a given URL root mount point
+ *
+ * @author Scott.Stark at jboss.org
+ * @author adrian at jboss.org
+ * @version $Revision: 44217 $
+ */
+public interface VFSContextFactory
+{
+   /**
+    * Get the URL protocols this factory supports
+    * 
+    * @return list of supported protocols.
+    */
+   String[] getProtocols();
+
+   /**
+    * Obtain a vfs context for the given root url.
+    * 
+    * @param rootURL - the URL for the root of the virtual context
+    * @return the vfs context
+    * @throws IOException - thrown if the root cannot be opened/accessed
+    */
+   VFSContext getVFS(URL rootURL) throws IOException;
+}
Added: projects/microcontainer/trunk/container/src/main/org/jboss/virtual/spi/VFSContextFactoryLocator.java
===================================================================
--- projects/microcontainer/trunk/container/src/main/org/jboss/virtual/spi/VFSContextFactoryLocator.java	2006-09-06 11:18:17 UTC (rev 56598)
+++ projects/microcontainer/trunk/container/src/main/org/jboss/virtual/spi/VFSContextFactoryLocator.java	2006-09-06 11:27:07 UTC (rev 56599)
@@ -0,0 +1,323 @@
+/*
+  * JBoss, Home of Professional Open Source
+  * Copyright 2005, JBoss Inc., and individual contributors as indicated
+  * by the @authors tag. See the copyright.txt in the distribution for a
+  * full listing of individual contributors.
+  *
+  * This is free software; you can redistribute it and/or modify it
+  * under the terms of the GNU Lesser General Public License as
+  * published by the Free Software Foundation; either version 2.1 of
+  * the License, or (at your option) any later version.
+  *
+  * This software is distributed in the hope that it will be useful,
+  * but WITHOUT ANY WARRANTY; without even the implied warranty of
+  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  * Lesser General Public License for more details.
+  *
+  * You should have received a copy of the GNU Lesser General Public
+  * License along with this software; if not, write to the Free
+  * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+  * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+  */
+package org.jboss.virtual.spi;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.URL;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Enumeration;
+import java.util.Map;
+import java.util.StringTokenizer;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.jboss.logging.Logger;
+import org.jboss.virtual.plugins.context.file.FileSystemContextFactory;
+import org.jboss.virtual.plugins.context.jar.JarContextFactory;
+
+/**
+ * A singleton factory for locating VFSContextFactory instances given VFS root URLs.
+ * 
+ * @author Scott.Stark at jboss.org
+ * @author adrian at jboss.org
+ * @version $Revision: 45764 $
+ */
+public class VFSContextFactoryLocator
+{
+   /** The log */
+   private static final Logger log = Logger.getLogger(VFSContextFactoryLocator.class); 
+   
+   /** The VSFactory mapped keyed by the VFS protocol string */
+   private static final Map<String, VFSContextFactory> factoryByProtocol = new ConcurrentHashMap<String, VFSContextFactory>();
+   
+   /** The system property that defines the default file factory */
+   public static final String DEFAULT_FACTORY_PROPERTY = VFSContextFactory.class.getName();
+   
+   /** The path used to load services from the classpath */
+   public static final String SERVICES_PATH = "META-INF/services/" + VFSContextFactory.class.getName();
+   
+   /** Has the default initialzation been performed */
+   private static boolean initialized = false;
+
+   /**
+    * Register a new VFSContextFactory
+    * 
+    * @param factory the factory
+    * @throws IllegalArgumentException if the factory is null or the factory
+    *         returns a null or no protocols
+    * @throws IllegalStateException if one of the protocols is already registered
+    */
+   public synchronized static void registerFactory(VFSContextFactory factory)
+   {
+      if (factory == null)
+         throw new IllegalArgumentException("Null VFSContextFactory");
+
+      String[] protocols = factory.getProtocols();
+      if (protocols == null || protocols.length == 0)
+         throw new IllegalArgumentException("VFSContextFactory trying to register null or no protocols: " + factory);
+      
+      for (String protocol : protocols)
+      {
+         if (protocol == null)
+            throw new IllegalArgumentException("VFSContextFactory try to register a null protocol: " + factory + " protocols=" + Arrays.asList(protocols));
+         VFSContextFactory other = factoryByProtocol.get(protocol);
+         if (other != null)
+            throw new IllegalStateException("VFSContextFactory: " + other + " already registered for protocol: " + protocol);
+      }
+
+      boolean trace = log.isTraceEnabled();
+      for (String protocol : protocols)
+      {
+         factoryByProtocol.put(protocol, factory);
+         if (trace)
+            log.trace("Registered " + factory + " for protocol: " + protocol);
+      }
+   }
+
+   /**
+    * Unregister a VFSContextFactory
+    * 
+    * @param factory the factory
+    * @return false when not registered
+    * @throws IllegalArgumentException if the factory is null
+    */
+   public synchronized static boolean unregisterFactory(VFSContextFactory factory)
+   {
+      if (factory == null)
+         throw new IllegalArgumentException("Null VFSContextFactory");
+
+      ArrayList<String> protocols = new ArrayList<String>();
+      for (Map.Entry<String, VFSContextFactory> entry : factoryByProtocol.entrySet())
+      {
+         if (factory == entry.getValue())
+            protocols.add(entry.getKey());
+      }
+
+      boolean trace = log.isTraceEnabled();
+      for (String protocol : protocols)
+      {
+         factoryByProtocol.remove(protocol);
+         if (trace)
+            log.trace("Unregistered " + factory + " for protocol: " + protocol);
+      }
+      
+      return protocols.isEmpty() == false;
+   }
+
+   /**
+    * Return the VFSContextFactory for the VFS mount point specified by the rootURL.
+    *  
+    * @param rootURL - the URL to a VFS root
+    * @return the VFSContextFactory capable of handling the rootURL. This will be null
+    * if there is no factory registered for the rootURL protocol.
+    * @throws IllegalArgumentException if the rootURL is null
+    */
+   public static VFSContextFactory getFactory(URL rootURL)
+   {
+      if (rootURL == null)
+         throw new IllegalArgumentException("Null rootURL");
+      
+      init();
+      String protocol = rootURL.getProtocol();
+      return factoryByProtocol.get(protocol);
+   }
+
+   /**
+    * Initialises the default VFSContextFactorys<p>
+    * 
+    * <ol>
+    * <li>Look for META-INF/services/org.jboss.virtual.spi.VFSContextFactory
+    * <li>Look at the system property org.jboss.virtual.spi.VFSContextFactory for a comma
+    *     seperated list of factories
+    * <li>Register default loaders when not done by the above mechanisms.
+    * </ol>
+    */
+   private static synchronized void init()
+   {
+      // Somebody beat us to it?
+      if (initialized)
+         return;
+      
+      // Try to locate from services files
+      ClassLoader loader = AccessController.doPrivileged(new GetContextClassLoader());
+      Enumeration<URL> urls = AccessController.doPrivileged(new EnumerateServices());
+      if (urls != null)
+      {
+         while (urls.hasMoreElements())
+         {
+            URL url = urls.nextElement();
+            
+            VFSContextFactory[] factories = loadFactories(url, loader);
+            for (VFSContextFactory factory : factories)
+            {
+               try
+               {
+                  registerFactory(factory);
+               }
+               catch (Exception e)
+               {
+                  log.warn("Error registering factory from " + url, e);
+               }
+            }
+         }
+      }
+
+      String defaultFactoryNames = AccessController.doPrivileged(new GetDefaultFactories());
+      if (defaultFactoryNames != null)
+      {
+         StringTokenizer tokenizer = new StringTokenizer(defaultFactoryNames, ",");
+         while (tokenizer.hasMoreTokens())
+         {
+            String factoryName = tokenizer.nextToken();
+            VFSContextFactory factory = createVFSContextFactory(loader, factoryName, " from system property.");
+            if (factory != null)
+               registerFactory(factory);
+         }
+      }
+
+      // No file protocol, use the default 
+      if (factoryByProtocol.containsKey("file") == false)
+         registerFactory(new FileSystemContextFactory());
+
+      // No jar protocol, use the default 
+      if (factoryByProtocol.containsKey("jar") == false)
+         registerFactory(new JarContextFactory());
+
+      initialized = true;
+   }
+   
+   /**
+    * Load the VFSFactory classes found in the service file
+    * 
+    * @param serviceURL the service url
+    * @param loader the class loader
+    * @return A possibly zero length array of the VFSFactory instances
+    *    loaded from the serviceURL
+    */
+   private static VFSContextFactory[] loadFactories(URL serviceURL, ClassLoader loader)
+   {
+      ArrayList<VFSContextFactory> temp = new ArrayList<VFSContextFactory>();
+      try
+      {
+         InputStream is = serviceURL.openStream();
+         try
+         {
+            BufferedReader br = new BufferedReader(new InputStreamReader(is));
+            String line;
+            while ( (line = br.readLine()) != null )
+            {
+               if (line.startsWith("#") == true)
+                  continue;
+               String[] classes = line.split("\\s+|#.*");
+               for (int n = 0; n < classes.length; n ++)
+               {
+                  String name = classes[n];
+                  if (name.length() == 0)
+                     continue;
+                  VFSContextFactory factory = createVFSContextFactory(loader, name, " defined in " + serviceURL);
+                  if (factory != null)
+                     temp.add(factory);
+               }
+            }
+         }
+         finally
+         {
+            is.close();
+         }
+      }
+      catch(Exception e)
+      {
+         log.warn("Error parsing " + serviceURL, e);
+      }
+
+      VFSContextFactory[] factories = new VFSContextFactory[temp.size()];
+      return temp.toArray(factories);
+   }
+   
+   /**
+    * Create a vfs context factory
+    * 
+    * @param cl the classloader
+    * @param className the class name
+    * @return the vfs context factory
+    */
+   private static VFSContextFactory createVFSContextFactory(ClassLoader cl, String className, String context)
+   {
+      try
+      {
+         Class factoryClass = cl.loadClass(className);
+         return (VFSContextFactory) factoryClass.newInstance();
+      }
+      catch (Exception e)
+      {
+         log.warn("Error creating VFSContextFactory " + className + " " + context, e);
+         return null;
+      }
+   }
+   
+   /**
+    * Get the context classloader
+    */
+   private static class GetContextClassLoader implements PrivilegedAction<ClassLoader>
+   {
+      public ClassLoader run()
+      {
+         return Thread.currentThread().getContextClassLoader();
+      }
+   }
+   
+   /**
+    * Get the default file factory class name
+    */
+   private static class GetDefaultFactories implements PrivilegedAction<String>
+   {
+      public String run()
+      {
+         return System.getProperty(DEFAULT_FACTORY_PROPERTY);
+      }
+   }
+   
+   /**
+    * Enumerates the services
+    */
+   private static class EnumerateServices implements PrivilegedAction<Enumeration<URL>>
+   {
+      public Enumeration<URL> run()
+      {
+         ClassLoader cl = Thread.currentThread().getContextClassLoader();
+         try
+         {
+            return cl.getResources(SERVICES_PATH);
+         }
+         catch (IOException e)
+         {
+            log.warn("Error retrieving " + SERVICES_PATH, e);
+            return null;
+         }
+      }
+   }
+}
Added: projects/microcontainer/trunk/container/src/main/org/jboss/virtual/spi/VirtualFileHandler.java
===================================================================
--- projects/microcontainer/trunk/container/src/main/org/jboss/virtual/spi/VirtualFileHandler.java	2006-09-06 11:18:17 UTC (rev 56598)
+++ projects/microcontainer/trunk/container/src/main/org/jboss/virtual/spi/VirtualFileHandler.java	2006-09-06 11:27:07 UTC (rev 56599)
@@ -0,0 +1,175 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2005, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.virtual.spi;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.List;
+
+import org.jboss.virtual.VirtualFile;
+
+/**
+ * A virtual file handler
+ * 
+ * @author Scott.Stark at jboss.org
+ * @author
+ * @version $Revision: 44334 $
+ */
+public interface VirtualFileHandler
+{
+   /**
+    * Get the simple VF name (X.java)
+    * 
+    * @return the simple file name
+    */
+   String getName();
+
+   /**
+    * Get the VFS relative path name (org/jboss/X.java)
+    * 
+    * @return the VFS relative path name
+    */
+   String getPathName();
+
+   /**
+    * Get the VF URL (file://root/org/jboss/X.java)
+    * 
+    * @return the full URL to the VF in the VFS.
+    * @throws MalformedURLException if a url cannot be parsed
+    */
+   URL toURL() throws MalformedURLException;
+
+   /**
+    * When the file was last modified
+    * 
+    * @return the last modified time
+    * @throws IOException for any problem accessing the virtual file system
+    * @throws IllegalStateException if closed
+    */
+   long getLastModified() throws IOException;
+   
+   /**
+    * Get the size
+    * 
+    * @return the size
+    * @throws IOException for any problem accessing the virtual file system
+    * @throws IllegalStateException if closed
+    */
+   long getSize() throws IOException;
+
+   /**
+    * Whether it is a directory
+    * 
+    * @return true if a directory.
+    * @throws IOException for any problem accessing the virtual file system
+    * @throws IllegalStateException if closed
+    */
+   boolean isDirectory() throws IOException;
+
+   /**
+    * Whether it is a simple file
+    * 
+    * @return true if a simple file.
+    * @throws IOException for any problem accessing the virtual file system
+    * @throws IllegalStateException if closed
+    */
+   boolean isFile() throws IOException;
+   
+   /**
+    * Whether it is an archive
+    * 
+    * @return the archive
+    * @throws IOException for any problem accessing the virtual file system
+    * @throws IllegalStateException if closed
+    */
+   boolean isArchive() throws IOException;
+
+   /**
+    * Whether it is hidden
+    * 
+    * @return true if hidden.
+    * @throws IOException for any problem accessing the virtual file system
+    * @throws IllegalStateException if closed
+    */
+   boolean isHidden() throws IOException;
+
+   /**
+    * Access the file contents.
+    * 
+    * @return An InputStream for the file contents.
+    * @throws IOException for any problem accessing the virtual file system
+    * @throws IllegalStateException if closed
+    */
+   InputStream openStream() throws IOException;
+
+   /**
+    * Get the parent
+    * 
+    * @return the parent
+    * @throws IOException for an error accessing the file system
+    * @throws IllegalStateException if closed
+    */
+   VirtualFileHandler getParent() throws IOException;
+
+   /**
+    * Get the children
+    * 
+    * @param ignoreErrors whether to ignore errors
+    * @return the children
+    * @throws IOException for an error accessing the file system
+    * @throws IllegalStateException if closed
+    */
+   List<VirtualFileHandler> getChildren(boolean ignoreErrors) throws IOException;
+
+   /**
+    * Find a child
+    * 
+    * @param path the path
+    * @return the child
+    * @throws IOException for an error accessing the file system (or the child doesn't exist)
+    * @throws IllegalStateException if closed
+    */
+   VirtualFileHandler findChild(String path) throws IOException;
+
+   /**
+    * Get the VFSContext this file belongs to
+    * 
+    * @return the context
+    * @throws IllegalStateException if closed
+    */
+   VFSContext getVFSContext();
+
+   /**
+    * Get the virtual file wrapper
+    * 
+    * @return the wrapper
+    * @throws IllegalStateException if closed
+    */
+   VirtualFile getVirtualFile();
+   
+   /**
+    * Close the resources
+    */
+   void close();
+}
Added: projects/microcontainer/trunk/container/src/main/org/jboss/virtual/spi/VirtualFileHandlerVisitor.java
===================================================================
--- projects/microcontainer/trunk/container/src/main/org/jboss/virtual/spi/VirtualFileHandlerVisitor.java	2006-09-06 11:18:17 UTC (rev 56598)
+++ projects/microcontainer/trunk/container/src/main/org/jboss/virtual/spi/VirtualFileHandlerVisitor.java	2006-09-06 11:27:07 UTC (rev 56599)
@@ -0,0 +1,47 @@
+/*
+* JBoss, Home of Professional Open Source
+* Copyright 2006, JBoss Inc., and individual contributors as indicated
+* by the @authors tag. See the copyright.txt in the distribution for a
+* full listing of individual contributors.
+*
+* This is free software; you can redistribute it and/or modify it
+* under the terms of the GNU Lesser General Public License as
+* published by the Free Software Foundation; either version 2.1 of
+* the License, or (at your option) any later version.
+*
+* This software is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public
+* License along with this software; if not, write to the Free
+* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+*/
+package org.jboss.virtual.spi;
+
+import org.jboss.virtual.VisitorAttributes;
+
+/**
+ * Visits a virtual file and its children
+ * 
+ * @author <a href="adrian at jboss.com">Adrian Brock</a>
+ * @version $Revision: 1.1 $
+ */
+public interface VirtualFileHandlerVisitor
+{
+   /**
+    * Get the search attribues for this visitor
+    * 
+    * @return the attributes
+    */
+   VisitorAttributes getAttributes();
+   
+   /**
+    * Visit a virtual file
+    * 
+    * @param handler the virtual file handler being visited
+    */
+   void visit(VirtualFileHandler handler);
+}
Added: projects/microcontainer/trunk/container/src/tests/org/jboss/test/virtual/test/SimpleTest.java
===================================================================
--- projects/microcontainer/trunk/container/src/tests/org/jboss/test/virtual/test/SimpleTest.java	2006-09-06 11:18:17 UTC (rev 56598)
+++ projects/microcontainer/trunk/container/src/tests/org/jboss/test/virtual/test/SimpleTest.java	2006-09-06 11:27:07 UTC (rev 56599)
@@ -0,0 +1,49 @@
+/*
+* JBoss, Home of Professional Open Source
+* Copyright 2006, JBoss Inc., and individual contributors as indicated
+* by the @authors tag. See the copyright.txt in the distribution for a
+* full listing of individual contributors.
+*
+* This is free software; you can redistribute it and/or modify it
+* under the terms of the GNU Lesser General Public License as
+* published by the Free Software Foundation; either version 2.1 of
+* the License, or (at your option) any later version.
+*
+* This software is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public
+* License along with this software; if not, write to the Free
+* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+*/
+package org.jboss.test.virtual.test;
+
+import java.net.URL;
+
+import org.jboss.test.BaseTestCase;
+import org.jboss.virtual.VFS;
+import org.jboss.virtual.VirtualFile;
+
+public class SimpleTest extends BaseTestCase
+{
+   public SimpleTest(String name)
+   {
+      super(name);
+   }
+
+   public void testSomething() throws Exception
+   {
+      VFS vfs = VFS.getVFS(new URL("file:/home/ejort/jboss-4.0/testsuite/output/lib"));
+      VirtualFile root = vfs.findChildFromRoot("jbosstest-web.ear");
+      System.out.println(root);
+
+      VirtualFile test = root.findChild("jbosstest-web.war/WEB-INF/lib/jbosstest-web-libservlet.jar/");
+      System.out.println(test);
+      
+      test = root.findChild("jbosstest-web.war/WEB-INF/lib/jbosstest-web-libservlet.jar/org/jboss/test/web/servlets/lib/SimpleServlet.class");
+      System.out.println(test);
+   }
+}
Added: projects/microcontainer/trunk/container/src/tests/org/jboss/test/virtual/test/SundryVFSTests.java
===================================================================
--- projects/microcontainer/trunk/container/src/tests/org/jboss/test/virtual/test/SundryVFSTests.java	2006-09-06 11:18:17 UTC (rev 56598)
+++ projects/microcontainer/trunk/container/src/tests/org/jboss/test/virtual/test/SundryVFSTests.java	2006-09-06 11:27:07 UTC (rev 56599)
@@ -0,0 +1,80 @@
+/*
+* JBoss, Home of Professional Open Source
+* Copyright 2006, JBoss Inc., and individual contributors as indicated
+* by the @authors tag. See the copyright.txt in the distribution for a
+* full listing of individual contributors.
+*
+* This is free software; you can redistribute it and/or modify it
+* under the terms of the GNU Lesser General Public License as
+* published by the Free Software Foundation; either version 2.1 of
+* the License, or (at your option) any later version.
+*
+* This software is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public
+* License along with this software; if not, write to the Free
+* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+*/
+package org.jboss.test.virtual.test;
+
+import java.net.URL;
+
+import org.jboss.test.BaseTestCase;
+import org.jboss.virtual.VFS;
+import org.jboss.virtual.VirtualFile;
+import org.jboss.virtual.plugins.context.jar.JarUtils;
+
+/**
+ * SundryVFSTests.
+ * 
+ * @author <a href="adrian at jboss.com">Adrian Brock</a>
+ * @version $Revision: 1.1 $
+ */
+public class SundryVFSTests extends BaseTestCase
+{
+   public SundryVFSTests(String name)
+   {
+      super(name);
+   }
+
+   protected VirtualFile getVirtualFile(String root, String path) throws Exception
+   {
+      URL url = getResource(root);
+      assertNotNull(url);
+      return VFS.getVirtualFile(url, path);
+   }
+   
+   public void testBrokenContext() throws Exception
+   {
+      VirtualFile file = getVirtualFile("/vfs/sundry", "jar/archive.jar");
+      log.debug(file.getName() + " " + file);
+      assertTrue("Should be an archive", file.isArchive());
+      file = file.findChild("empty");
+      log.debug(file.getName() + " " + file);
+   }
+   
+   public void testArchive() throws Exception
+   {
+      VirtualFile file = getVirtualFile("/vfs/sundry/", "jar/archive.jar");
+      log.debug(file.getName() + " " + file);
+      assertTrue("Should be an archive", file.isArchive());
+      file = file.findChild("empty");
+      log.debug(file.getName() + " " + file);
+   }
+   
+   public void testArchive2() throws Exception
+   {
+      URL url = getResource("/vfs/sundry/jar/archive.jar");
+      url = JarUtils.createJarURL(url);
+      VFS vfs = VFS.getVFS(url);
+      VirtualFile file = vfs.getRoot();
+      log.debug(file.getName() + " " + file);
+      assertTrue("Should be an archive", file.isArchive());
+      file = file.findChild("empty");
+      log.debug(file.getName() + " " + file);
+   }
+}
Added: projects/microcontainer/trunk/container/src/tests/org/jboss/test/virtual/test/TestFileVFS.java
===================================================================
--- projects/microcontainer/trunk/container/src/tests/org/jboss/test/virtual/test/TestFileVFS.java	2006-09-06 11:18:17 UTC (rev 56598)
+++ projects/microcontainer/trunk/container/src/tests/org/jboss/test/virtual/test/TestFileVFS.java	2006-09-06 11:27:07 UTC (rev 56599)
@@ -0,0 +1,399 @@
+/*
+* JBoss, the OpenSource J2EE webOS
+*
+* Distributable under LGPL license.
+* See terms of license at gnu.org.
+*/
+package org.jboss.test.virtual.test;
+
+import java.io.File;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.HashSet;
+import java.util.List;
+import java.util.jar.Attributes;
+import java.util.jar.Manifest;
+
+import org.jboss.test.BaseTestCase;
+import org.jboss.virtual.VFS;
+import org.jboss.virtual.VirtualFile;
+import org.jboss.virtual.plugins.vfs.helpers.SuffixMatchFilter;
+import org.jboss.virtual.spi.VFSContextFactory;
+import org.jboss.virtual.spi.VFSContextFactoryLocator;
+
+/**
+ * Tests of the VFS implementation
+ * 
+ * @author Scott.Stark at jboss.org
+ * @author adrian at jboss.org
+ * @version $Revision: 55523 $
+ */
+public class TestFileVFS extends BaseTestCase
+{
+   public TestFileVFS(String name)
+   {
+      super(name);
+   }
+
+   /**
+    * Test that a VFSContextFactory can be created from the testcase CodeSource url
+    * @throws Exception
+    */
+   public void testVFSContextFactory()
+      throws Exception
+   {
+      URL root = getClass().getProtectionDomain().getCodeSource().getLocation();
+      VFSContextFactory factory = VFSContextFactoryLocator.getFactory(root);
+      assertTrue("VFSContextFactory(CodeSource.Location) != null", factory != null);
+   }
+
+   /**
+    * Test that NestedJarFromStream can provide access to nested jar content
+    * @throws Exception
+    */
+   /*
+   public void testInnerJarFile()
+      throws Exception
+   {
+      MemoryMXBean mem = ManagementFactory.getMemoryMXBean();
+      log.info("Starting heap usage: "+mem.getHeapMemoryUsage());
+
+      // this expects to be run with a working dir of the container root
+      File outerJar = new File("output/lib/outer.jar");
+      assertTrue(outerJar.getAbsolutePath()+" exists", outerJar.exists());
+      JarFile jf = new JarFile(outerJar);
+
+      JarEntry jar1 = jf.getJarEntry("jar1.jar");
+      URL jar1URL = new URL(outerJar.toURL(), "jar1.jar");
+      ZipInputStream jis1 = new ZipInputStream(jf.getInputStream(jar1));
+      NestedJarFromStream njfs = new NestedJarFromStream(jis1, jar1URL, "/jar1.jar", jar1);
+      NestedJarFromStream.JarEntryContents e1 = njfs.getEntry("org/jboss/test/vfs/support/jar1/ClassInJar1.class");
+      assertNotNull(e1);
+      log.info("org/jboss/test/vfs/support/CommonClass.class: "+e1);
+      NestedJarFromStream.JarEntryContents mfe1 = njfs.getEntry("META-INF/MANIFEST.MF");
+      assertNotNull("jar1!/META-INF/MANIFEST.MF", mfe1);
+      InputStream mfIS = mfe1.openStream();
+      Manifest mf = new Manifest(mfIS);
+      Attributes mainAttrs = mf.getMainAttributes();
+      String version = mainAttrs.getValue(Attributes.Name.SPECIFICATION_TITLE);
+      assertEquals("jar1", version);
+      mfIS.close();
+      njfs.close();
+
+      JarEntry jar2 = jf.getJarEntry("jar2.jar");
+      URL jar2URL = new URL(outerJar.toURL(), "jar2.jar");
+      ZipInputStream jis2 = new ZipInputStream(jf.getInputStream(jar2));
+      NestedJarFromStream njfs2 = new NestedJarFromStream(jis2, jar2URL, "/jar2.jar", jar2);
+      NestedJarFromStream.JarEntryContents e2 = njfs2.getEntry("org/jboss/test/vfs/support/jar2/ClassInJar2.class");
+      assertNotNull(e2);
+      log.info("org/jboss/test/vfs/support/CommonClass.class: "+e2);
+      NestedJarFromStream.JarEntryContents mfe2 = njfs2.getEntry("META-INF/MANIFEST.MF");
+      assertNotNull("jar2!/META-INF/MANIFEST.MF", mfe2);
+      InputStream mf2IS = mfe2.openStream();
+      Manifest mf2 = new Manifest(mf2IS);
+      Attributes mainAttrs2 = mf2.getMainAttributes();
+      String version2 = mainAttrs2.getValue(Attributes.Name.SPECIFICATION_TITLE);
+      assertEquals("jar2", version2);
+      mf2IS.close();
+      njfs2.close();
+      log.info("Ending heap usage: "+mem.getHeapMemoryUsage());
+   }
+   */
+
+   /**
+    * Basic tests of accessing resources in a jar
+    * @throws Exception
+    */
+   public void testFindResource()
+      throws Exception
+   {
+      // this expects to be run with a working dir of the container root
+      File outerJar = new File("output/lib/outer.jar");
+      URL rootURL = outerJar.getParentFile().toURL();
+      VFS vfs = VFS.getVFS(rootURL);
+      VirtualFile jar = vfs.findChildFromRoot("outer.jar");
+      assertTrue("outer.jar != null", jar != null);
+
+      /*
+      ArrayList<String> searchCtx = new ArrayList<String>();
+      searchCtx.add("outer.jar");
+      VirtualFile metaInf = vfs.resolveFile("META-INF/MANIFEST.MF", searchCtx);
+      */
+      VirtualFile metaInf = jar.findChild("META-INF/MANIFEST.MF");
+      assertTrue("META-INF/MANIFEST.MF != null", metaInf != null);
+      InputStream mfIS = metaInf.openStream();
+      assertTrue("META-INF/MANIFEST.MF.openStream != null", mfIS != null);
+      Manifest mf = new Manifest(mfIS);
+      Attributes mainAttrs = mf.getMainAttributes();
+      String version = mainAttrs.getValue(Attributes.Name.SPECIFICATION_VERSION);
+      assertEquals("1.0.0.GA", version);
+      mfIS.close();
+   }
+
+   public void testFindResourceUnpackedJar()
+      throws Exception
+   {
+      // this expects to be run with a working dir of the container root
+      File outerJar = new File("output/lib/unpacked-outer.jar");
+      URL rootURL = outerJar.getParentFile().toURL();
+      VFS vfs = VFS.getVFS(rootURL);
+      VirtualFile jar = vfs.findChildFromRoot("unpacked-outer.jar");
+      assertTrue("unpacked-outer.jar != null", jar != null);
+
+      /**
+      ArrayList<String> searchCtx = new ArrayList<String>();
+      searchCtx.add("unpacked-outer.jar");
+      VirtualFile metaInf = vfs.resolveFile("META-INF/MANIFEST.MF", searchCtx);
+      */
+      VirtualFile metaInf = jar.findChild("META-INF/MANIFEST.MF");
+      assertTrue("META-INF/MANIFEST.MF != null", metaInf != null);
+      InputStream mfIS = metaInf.openStream();
+      assertTrue("META-INF/MANIFEST.MF.openStream != null", mfIS != null);
+      Manifest mf = new Manifest(mfIS);
+      Attributes mainAttrs = mf.getMainAttributes();
+      String version = mainAttrs.getValue(Attributes.Name.SPECIFICATION_VERSION);
+      assertEquals("1.0.0.GA", version);
+      mfIS.close();
+   }
+
+   /**
+    * Test simple file resolution without search contexts
+    * @throws Exception
+    */
+   public void testResolveFile()
+      throws Exception
+   {
+      log.info("+++ testResolveFile, cwd="+(new File(".").getCanonicalPath()));
+      // this expects to be run with a working dir of the container root
+      File outerJarFile = new File("output/lib/outer.jar");
+      URL rootURL = outerJarFile.getParentFile().toURL();
+      VFS vfs = VFS.getVFS(rootURL);
+
+      // Check resolving the root file
+      VirtualFile root = vfs.findChildFromRoot("");
+      assertEquals("root name", "lib", root.getName());
+      assertEquals("root path", "", root.getPathName());
+      assertTrue("root isDirectory", root.isDirectory());
+
+      // Find the outer.jar
+      VirtualFile outerJar = vfs.findChildFromRoot("outer.jar");
+      assertNotNull("outer.jar", outerJar);
+      assertEquals("outer.jar name", "outer.jar", outerJar.getName());
+      assertEquals("outer.jar path", "outer.jar", outerJar.getPathName());
+      
+      VirtualFile outerJarMF = vfs.findChildFromRoot("outer.jar/META-INF/MANIFEST.MF");
+      assertNotNull("outer.jar/META-INF/MANIFEST.MF", outerJarMF);
+
+      // Test a non-canonical path
+      outerJarFile = new File("output/resources/../lib/outer.jar");
+      rootURL = outerJarFile.getParentFile().toURL();
+      // Check resolving the root file
+      root = vfs.findChildFromRoot("");
+      assertEquals("root name", "lib", root.getName());
+      assertEquals("root path", "", root.getPathName());
+      assertTrue("root isDirectory", root.isDirectory());
+   }
+
+   /**
+    * Validate resolving a .class file given a set of search contexts in the
+    * vfs that make up a classpath.
+    * 
+    * @throws Exception
+    */
+   public void testResolveClassFileInClassPath()
+      throws Exception
+   {
+      log.info("+++ testResolveFile, cwd="+(new File(".").getCanonicalPath()));
+      // this expects to be run with a working dir of the container root
+      File libFile = new File("output/lib");
+      URL rootURL = libFile.toURL();
+      VFS vfs = VFS.getVFS(rootURL);
+      
+      // Find ClassInJar1.class
+      VirtualFile vf = vfs.findChildFromRoot("jar1.jar"); 
+      VirtualFile c1 = vf.findChild("org/jboss/test/vfs/support/jar1/ClassInJar1.class");
+      assertNotNull("ClassInJar1.class VF", c1);
+      log.debug("Found ClassInJar1.class: "+c1);
+
+      // Find ClassInJar1$InnerClass.class
+      VirtualFile c1i = vf.findChild("org/jboss/test/vfs/support/jar1/ClassInJar1$InnerClass.class");
+      assertNotNull("ClassInJar1$InnerClass.class VF", c1i);
+      log.debug("Found ClassInJar1$InnerClass.class: "+c1i);
+
+      // Find ClassInJar2.class
+      vf = vfs.findChildFromRoot("jar2.jar");
+      VirtualFile c2 = vf.findChild("org/jboss/test/vfs/support/jar2/ClassInJar2.class");
+      assertNotNull("ClassInJar2.class VF", c2);
+      log.debug("Found ClassInJar2.class: "+c2);
+   }
+
+   public void testResolveFileInUnpackedJar()
+      throws Exception
+   {
+      log.info("+++ testResolveFileInUnpackedJar, cwd="+(new File(".").getCanonicalPath()));
+      // this expects to be run with a working dir of the container root
+      File outerJarFile = new File("output/lib/unpacked-outer.jar");
+      URL rootURL = outerJarFile.getParentFile().toURL();
+      VFS vfs = VFS.getVFS(rootURL);
+
+      // Check resolving the root file
+      VirtualFile root = vfs.findChildFromRoot("");
+      assertEquals("root name", "lib", root.getName());
+      assertEquals("root path", "", root.getPathName());
+      assertTrue("root isDirectory", root.isDirectory());
+
+      // Find the outer.jar
+      VirtualFile outerJar = vfs.findChildFromRoot("unpacked-outer.jar");
+      assertNotNull("unpacked-outer.jar", outerJar);
+      assertEquals("unpacked-outer.jar name", "unpacked-outer.jar", outerJar.getName());
+      assertEquals("unpacked-outer.jar path", "unpacked-outer.jar", outerJar.getPathName());
+      
+      VirtualFile outerJarMF = vfs.findChildFromRoot("unpacked-outer.jar/META-INF/MANIFEST.MF");
+      assertNotNull("unpacked-outer.jar/META-INF/MANIFEST.MF", outerJarMF);
+
+      // Test a non-canonical path
+      outerJarFile = new File("output/resources/../lib/unpacked-outer.jar");
+      rootURL = outerJarFile.getParentFile().toURL();
+      // Check resolving the root file
+      root = vfs.findChildFromRoot("");
+      assertEquals("root name", "lib", root.getName());
+      assertEquals("root path", "", root.getPathName());
+      assertTrue("root isDirectory", root.isDirectory());
+   }
+
+   /**
+    * Test file resolution with nested jars
+    * @throws Exception
+    */
+   public void testInnerJar()
+      throws Exception
+   {
+      // this expects to be run with a working dir of the container root
+      File outerJar = new File("output/lib/outer.jar");
+      URL rootURL = outerJar.getParentFile().toURL();
+      VFS vfs = VFS.getVFS(rootURL);
+      VirtualFile inner = vfs.findChildFromRoot("outer.jar/jar1.jar");
+      log.info("IsFile: "+inner.isFile());
+      log.info(inner.getLastModified());
+      List<VirtualFile> contents = inner.getChildren();
+      // META-INF/*, org/jboss/test/vfs/support/jar1/* at least
+      assertTrue("jar1.jar children.length("+contents.size()+") >= 2", contents.size() >= 2);
+      for(VirtualFile vf : contents)
+      {
+         log.info("  "+vf.getName());
+      }
+      VirtualFile vf = vfs.findChildFromRoot("outer.jar/jar1.jar");
+      VirtualFile jar1MF = vf.findChild("META-INF/MANIFEST.MF");
+      InputStream mfIS = jar1MF.openStream();
+      Manifest mf = new Manifest(mfIS);
+      Attributes mainAttrs = mf.getMainAttributes();
+      String version = mainAttrs.getValue(Attributes.Name.SPECIFICATION_TITLE);
+      assertEquals("jar1", version);
+      mfIS.close();
+   }
+
+   /**
+    * Test a scan of the outer.jar vfs to locate all .class files
+    * @throws Exception
+    */
+   public void testClassScan()
+      throws Exception
+   {
+      // this expects to be run with a working dir of the container root
+      File outerJarFile = new File("output/lib/outer.jar");
+      URL rootURL = outerJarFile.toURL();
+      VFS vfs = VFS.getVFS(rootURL);
+
+      HashSet<String> expectedClasses = new HashSet<String>();
+      expectedClasses.add("jar1.jar/org/jboss/test/vfs/support/jar1/ClassInJar1.class");
+      expectedClasses.add("jar1.jar/org/jboss/test/vfs/support/jar1/ClassInJar1$InnerClass.class");
+      expectedClasses.add("jar2.jar/org/jboss/test/vfs/support/jar2/ClassInJar2.class");
+      expectedClasses.add("org/jboss/test/vfs/support/CommonClass.class");
+      SuffixMatchFilter classVisitor = new SuffixMatchFilter(".class");
+      List<VirtualFile> classes = vfs.getChildren(classVisitor);
+      int count = 0;
+      for (VirtualFile cf : classes)
+      {
+         String path = cf.getPathName();
+         if( path.endsWith(".class") )
+         {
+            assertTrue(path, expectedClasses.contains(path));
+            count ++;
+         }
+      }
+      assertEquals("There were 4 classes", 4, count);
+   }
+
+   /**
+    * Test the serialization of VirtualFiles
+    * @throws Exception
+    */
+   /*
+   public void testVFSerialization()
+      throws Exception
+   {
+      File tmpRoot = File.createTempFile("vfs", ".root");
+      tmpRoot.delete();
+      tmpRoot.mkdir();
+      tmpRoot.deleteOnExit();
+      File tmp = new File(tmpRoot, "vfs.ser");
+      tmp.deleteOnExit();
+      log.info("+++ testVFSerialization, tmp="+tmp.getCanonicalPath());
+      URL rootURL = tmpRoot.toURL();
+      VFSContextFactory factory = VFSContextFactoryLocator.getFactory(rootURL);
+      ReadOnlyVFS vfs = factory.getVFS(rootURL);
+      VirtualFile tmpVF = vfs.resolveFile("vfs.ser");
+      FileOutputStream fos = new FileOutputStream(tmp);
+      ObjectOutputStream oos = new ObjectOutputStream(fos);
+      oos.writeObject(tmpVF);
+      oos.close();
+
+      FileInputStream fis = new FileInputStream(tmp);
+      ObjectInputStream ois = new ObjectInputStream(fis);
+      VirtualFile tmpVF2 = (VirtualFile) ois.readObject();
+      ois.close();
+      long lastModified = tmpVF.getLastModified();
+      long size = tmpVF.getSize();
+      String name = tmpVF.getName();
+      String pathName = tmpVF.getPathName();
+      URL url = tmpVF.toURL();
+
+      assertEquals("name", name, tmpVF2.getName());
+      assertEquals("pathName", pathName, tmpVF2.getPathName());
+      assertEquals("lastModified", lastModified, tmpVF2.getLastModified());
+      assertEquals("size", size, tmpVF2.getSize());
+      assertEquals("url", url, tmpVF2.toURL());
+   }
+   */
+
+   /**
+    * Test that the URL of a VFS corresponding to a directory ends in '/' so that
+    * URLs created relative to it are under the directory.
+    * 
+    * @throws Exception
+    */
+   /*
+   public void testDirURLs()
+      throws Exception
+   {
+      // this expects to be run with a working dir of the container root
+      File libFile = new File("output/lib");
+      URL rootURL = libFile.toURL();
+      VFSContextFactory factory = VFSContextFactoryLocator.getFactory(rootURL);
+      ReadOnlyVFS vfs = factory.getVFS(rootURL);
+
+      // Use the unpacked-outer.jar in output/lib
+      VirtualFile outerJar = vfs.resolveFile("unpacked-outer.jar");
+      URL outerURL = outerJar.toURL();
+      log.debug("outerURL: "+outerURL);
+      assertTrue(outerURL+" ends in '/'", outerURL.getPath().endsWith("/"));
+      // Validate that jar1 is under unpacked-outer.jar
+      URL jar1URL = new URL(outerURL, "jar1.jar");
+      log.debug("jar1URL: "+jar1URL+", path="+jar1URL.getPath());
+      assertTrue("jar1URL path ends in unpacked-outer.jar/jar1.jar",
+            jar1URL.getPath().endsWith("unpacked-outer.jar/jar1.jar"));
+      VirtualFile jar1 = outerJar.findChild("jar1.jar");
+      assertEquals("jar1URL == VF.toURL()", jar1URL, jar1.toURL());
+   }
+   */
+}
    
    
More information about the jboss-cvs-commits
mailing list