[jboss-cvs] JBossAS SVN: r73900 - in projects/vfs/branches/jar-alter-work/src: main/java/org/jboss/virtual/plugins/context and 3 other directories.

jboss-cvs-commits at lists.jboss.org jboss-cvs-commits at lists.jboss.org
Sun Jun 1 12:17:46 EDT 2008


Author: mstruk
Date: 2008-06-01 12:17:45 -0400 (Sun, 01 Jun 2008)
New Revision: 73900

Modified:
   projects/vfs/branches/jar-alter-work/src/main/java/org/jboss/virtual/VFSUtils.java
   projects/vfs/branches/jar-alter-work/src/main/java/org/jboss/virtual/plugins/context/AbstractVFSContext.java
   projects/vfs/branches/jar-alter-work/src/main/java/org/jboss/virtual/plugins/context/file/FileSystemContext.java
   projects/vfs/branches/jar-alter-work/src/main/java/org/jboss/virtual/plugins/context/zip/SizeLimitedInputStream.java
   projects/vfs/branches/jar-alter-work/src/main/java/org/jboss/virtual/plugins/context/zip/ZipEntryContext.java
   projects/vfs/branches/jar-alter-work/src/main/java/org/jboss/virtual/plugins/context/zip/ZipEntryContextFactory.java
   projects/vfs/branches/jar-alter-work/src/main/java/org/jboss/virtual/plugins/context/zip/ZipEntryHandler.java
   projects/vfs/branches/jar-alter-work/src/main/java/org/jboss/virtual/plugins/context/zip/ZipEntryInputStream.java
   projects/vfs/branches/jar-alter-work/src/main/java/org/jboss/virtual/plugins/context/zip/ZipFileLockReaper.java
   projects/vfs/branches/jar-alter-work/src/main/java/org/jboss/virtual/plugins/context/zip/ZipFileWrapper.java
   projects/vfs/branches/jar-alter-work/src/main/java/org/jboss/virtual/plugins/context/zip/ZipStreamWrapper.java
   projects/vfs/branches/jar-alter-work/src/main/java/org/jboss/virtual/plugins/context/zip/ZipWrapper.java
   projects/vfs/branches/jar-alter-work/src/test/java/org/jboss/test/virtual/test/ZipEntryVFSContextUnitTestCase.java
Log:
Added noReaper URL query parameter, bug fixes, code cleanup, comments and javadoc

Modified: projects/vfs/branches/jar-alter-work/src/main/java/org/jboss/virtual/VFSUtils.java
===================================================================
--- projects/vfs/branches/jar-alter-work/src/main/java/org/jboss/virtual/VFSUtils.java	2008-06-01 09:13:34 UTC (rev 73899)
+++ projects/vfs/branches/jar-alter-work/src/main/java/org/jboss/virtual/VFSUtils.java	2008-06-01 16:17:45 UTC (rev 73900)
@@ -87,6 +87,7 @@
     * Key used to turn off reaper mode in vfszip - forcing synchronous (slower) handling of files
     */
    public static final String FORCE_NO_REAPER_KEY = "jboss.vfs.forceNoReaper";
+   public static final String NO_REAPER_QUERY = "noReaper";
 
    private static File tempDir;
 
@@ -99,7 +100,7 @@
       }
    }
 
-   private synchronized static File getTempDirectory()
+   public synchronized static File getTempDirectory()
    {
       if (tempDir == null)
       {

Modified: projects/vfs/branches/jar-alter-work/src/main/java/org/jboss/virtual/plugins/context/AbstractVFSContext.java
===================================================================
--- projects/vfs/branches/jar-alter-work/src/main/java/org/jboss/virtual/plugins/context/AbstractVFSContext.java	2008-06-01 09:13:34 UTC (rev 73899)
+++ projects/vfs/branches/jar-alter-work/src/main/java/org/jboss/virtual/plugins/context/AbstractVFSContext.java	2008-06-01 16:17:45 UTC (rev 73900)
@@ -151,8 +151,11 @@
          else
             pPathName = parent.getPathName();
 
+         if (urlStr.charAt( urlStr.length()-1) != '/')
+            urlStr.append("/");
+
          if(pPathName.length() != 0)
-            urlStr.append("/").append(pPathName);
+            urlStr.append(pPathName);
 
          if (urlStr.charAt( urlStr.length()-1) != '/')
             urlStr.append("/");

Modified: projects/vfs/branches/jar-alter-work/src/main/java/org/jboss/virtual/plugins/context/file/FileSystemContext.java
===================================================================
--- projects/vfs/branches/jar-alter-work/src/main/java/org/jboss/virtual/plugins/context/file/FileSystemContext.java	2008-06-01 09:13:34 UTC (rev 73899)
+++ projects/vfs/branches/jar-alter-work/src/main/java/org/jboss/virtual/plugins/context/file/FileSystemContext.java	2008-06-01 16:17:45 UTC (rev 73900)
@@ -45,6 +45,11 @@
 
 /**
  * FileSystemContext.
+ *
+ * Jar archives are processed through {@link org.jboss.virtual.plugins.context.zip.ZipEntryContext}.
+ *
+ * To switch back to {@link org.jboss.virtual.plugins.context.jar.JarHandler}
+ * set a system property <em>jboss.vfs.forceVfsJar=true</em> 
  * 
  * @author <a href="adrian at jboss.com">Adrian Brock</a>
  * @author <a href="ales.justin at jboss.com">Ales Justin</a>

Modified: projects/vfs/branches/jar-alter-work/src/main/java/org/jboss/virtual/plugins/context/zip/SizeLimitedInputStream.java
===================================================================
--- projects/vfs/branches/jar-alter-work/src/main/java/org/jboss/virtual/plugins/context/zip/SizeLimitedInputStream.java	2008-06-01 09:13:34 UTC (rev 73899)
+++ projects/vfs/branches/jar-alter-work/src/main/java/org/jboss/virtual/plugins/context/zip/SizeLimitedInputStream.java	2008-06-01 16:17:45 UTC (rev 73900)
@@ -1,3 +1,24 @@
+/*
+* 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.zip;
 
 import java.io.InputStream;
@@ -4,8 +25,11 @@
 import java.io.IOException;
 
 /**
- * SizeLimitedInputStream - signals EOF when the specified number of bytes have been read from the underlying stream
+ * SizeLimitedInputStream
  *
+ * Signals EOF when the specified number of bytes
+ * have been read from the underlying stream
+ *
  * @author <a href="strukelj at parsek.net">Marko Strukelj</a>
  * @version $Revision: 1.0 $
  */

Modified: projects/vfs/branches/jar-alter-work/src/main/java/org/jboss/virtual/plugins/context/zip/ZipEntryContext.java
===================================================================
--- projects/vfs/branches/jar-alter-work/src/main/java/org/jboss/virtual/plugins/context/zip/ZipEntryContext.java	2008-06-01 09:13:34 UTC (rev 73899)
+++ projects/vfs/branches/jar-alter-work/src/main/java/org/jboss/virtual/plugins/context/zip/ZipEntryContext.java	2008-06-01 16:17:45 UTC (rev 73900)
@@ -1,3 +1,24 @@
+/*
+* 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.zip;
 
 import org.jboss.logging.Logger;
@@ -33,8 +54,28 @@
 import java.util.zip.ZipEntry;
 
 /**
- * VFSContext exposing a zip archive file as a virtual file system
+ * <tt>ZipEntryContext</tt> implements a {@link org.jboss.virtual.spi.VFSContext}
+ * that exposes a zip archive as a virtual file system.
  *
+ * Zip archive can be in a form of a file or a stream.
+ *
+ * Nested archives are processed through this same class.
+ * By default nested archives are cached in memory and mounted as new
+ * instances of <tt>ZipEntryContext</tt> with <tt>ZipStremWrapper</tt> as a source.
+ * If system property <em>jboss.vfs.forceCopy=true</em> is specified,
+ * or URL query parameter <em>forceCopy=true</em> is present,
+ * nested archives are extracted into a temp directory before being
+ * mounted as new instances of <tt>ZipEntryContext</tt>.
+ *
+ * This context implementation has two modes of releasing file locks.
+ * <em>Asynchronous</em> mode is the default one since it is better performant.
+ * To switch this to <em>synchronous</em> mode a system property
+ * <em>jboss.vfs.forceNoReaper=true</em> can be specified or URL query parameter
+ * <em>noReaper=true</em> can be included in context URL.
+ *
+ * This context implementation is a replacement for
+ * {@link org.jboss.virtual.plugins.context.jar.JarContext}.
+ *
  * @author <a href="strukelj at parsek.net">Marko Strukelj</a>
  * @version $Revision: 1.0 $
  */
@@ -44,6 +85,7 @@
 
    private static final Logger log = Logger.getLogger(ZipEntryContext.class);
 
+   /** Global setting for nested archive processing mode: copy or no-copy (default) */
    private static boolean forceCopy;
 
    static
@@ -57,18 +99,19 @@
    }
 
 
-   /** ZipFile opened around rootFile */
-   private ZipWrapper zipFile;
+   /** Abstracted access to zip archive - either ZipFileWrapper or ZipStreamWrapper */
+   private ZipWrapper zipSource;
 
-   /** Entry path representing a context root */
+   /** Entry path representing a context root - archive root is not necessarily a context root */
    private String rootEntryPath = "";
 
-   /** Auto clean signals if rootFile should be deleted after closing the context */
+   /** AutoClean signals if zip archive should be deleted after closing the context - true for nested archives */
    private boolean autoClean = false;
 
-   /** Entries in a hierarchy */
+   /** Registry of everything that zipSource contains */
    private ConcurrentHashMap<String, EntryInfo> entries = new ConcurrentHashMap<String, EntryInfo>();
 
+
    /**
     * Create a new ZipEntryContext
     *
@@ -97,7 +140,7 @@
    }
 
    /**
-    * Create a new ZipEntryContext being mounted into another context
+    * Create a new ZipEntryContext to be mounted into another context
     *
     * @param rootURL - url representing this context within another context
     * @param peer - file handler in another context through which this context is being mounted
@@ -111,7 +154,7 @@
    }
 
    /**
-    * Create a new ZipEntryContext being mounted into another context
+    * Create a new ZipEntryContext to be mounted into another context
     *
     * @param rootURL - url representing this context within another context
     * @param peer - file handler in another context through which this context is being mounted
@@ -128,11 +171,11 @@
    }
 
    /**
-    * Create a new ZipEntryContext being mounted into another context
+    * Create a new ZipEntryContext to be mounted into another context
     *
     * @param rootURL - url representing this context within another context
     * @param peer - file handler in another context through which this context is being mounted
-    * @param zipWrapper - zip archive as abstracted wrapper
+    * @param zipWrapper - abstracted zip archive source
     * @param autoClean - true if file represented by localRootURL should be deleted after this context is closed
     * @throws URISyntaxException
     * @throws IOException
@@ -144,7 +187,15 @@
       init(null, peer, zipWrapper);
    }
 
-
+   /**
+    * Extra initialization that couldn't fit inside constructors
+    *
+    * @param localRootURL
+    * @param peer
+    * @param zipWrapper
+    * @throws IOException
+    * @throws URISyntaxException
+    */
    private void init(URL localRootURL, VirtualFileHandler peer, ZipWrapper zipWrapper) throws IOException, URISyntaxException
    {
 
@@ -152,45 +203,64 @@
       {
          if (localRootURL == null)
             throw new IllegalArgumentException("No ZipWrapper specified and localRootURL is null");
+
+         // initialize rootEntryPath and get archive file path
          String rootPath = initRootAndPath(localRootURL);
-         zipFile = new ZipFileWrapper(VFSUtils.toURI(new URL(rootPath)), autoClean);
+
+         String noReaper = getOptions().get(VFSUtils.NO_REAPER_QUERY);
+         zipSource = new ZipFileWrapper(VFSUtils.toURI(new URL(rootPath)), autoClean, Boolean.valueOf(noReaper));
       }
       else
       {
-         zipFile = zipWrapper;
+         zipSource = zipWrapper;
       }
       
       setRootPeer(peer);
 
-      String name = getRootURI().toString();   // rootFile.getName()
+      String name = getRootURI().toString();
       int toPos = name.length();
+
+      // cut off any ending slash
       if(name.length() != 0 && name.charAt(name.length()-1) == '/')
          toPos --;
 
+      // name is last path component
       int namePos = name.lastIndexOf("/", toPos-1);
       name = name.substring(namePos+1, toPos);
       
+      // cut off any ending exclamation
       if(name.length() != 0 && name.charAt(name.length()-1) == '!')
          name = name.substring(0, name.length()-1);
 
-      // init initial root that will be overwritten if it exists as ZipEntry
-      // root represents the zip file itself so we treat it as leaf as far as
-      // URL not ending with / for non-directories goes
+      // init initial root EntryInfo that will be overwritten
+      // if zip entry exists for rootEntryPath
       entries.put("", new EntryInfo(new ZipEntryHandler(this, null, name, true), null));
 
       initEntries();
       ZipEntryContextFactory.registerContext(this);
    }
 
+   /**
+    * Returns archive file name - if this is a top-level ZipEntryContext.
+    * Otherwise it returns the last component of URL.
+    *
+    * @return name
+    */
    public String getName()
    {
       VirtualFileHandler peer = getRootPeer();
       if (peer != null)
          return peer.getName();
       else
-         return zipFile.getName();
+         return zipSource.getName();
    }
 
+   /**
+    * Iterate through zip archive entries, compose a tree structure of archive's content
+    *
+    * @throws IOException
+    * @throws URISyntaxException
+    */
    private synchronized void initEntries() throws IOException, URISyntaxException
    {
 
@@ -199,10 +269,12 @@
       // this way we ensure that parent entries are processed before child entries
 
       HashMap<String, ZipEntry> relevant = new HashMap<String, ZipEntry>();
-      zipFile.acquire();
+      zipSource.acquire();
       try
       {
-         Enumeration<? extends ZipEntry> zipEntries = zipFile.entries();
+         Enumeration<? extends ZipEntry> zipEntries = zipSource.entries();
+
+         // zoom-in on entries under rootEntryPath - ignoring the rest
          while(zipEntries.hasMoreElements())
          {
             ZipEntry ent = zipEntries.nextElement();
@@ -238,28 +310,32 @@
                   useCopyMode = Boolean.valueOf(flag);
                }
 
+               DelegatingHandler delegator;
+
                if (useCopyMode)
                {
                   // extract it to temp dir
                   File dest = new File(getTempDir() + "/" + getTempFileName(ent.getName()));
-                  dest.getParentFile().mkdirs();  // ensure parent exists
-                  InputStream is = zipFile.openStream(ent);
+                  dest.deleteOnExit();
+
+                  // ensure parent exists
+                  dest.getParentFile().mkdirs();
+
+                  InputStream is = zipSource.openStream(ent);
                   OutputStream os = new BufferedOutputStream(new FileOutputStream(dest));
                   copyStreamAndClose(is, os);
 
-                  // mount FS
-                  DelegatingHandler delegator = mountZipFS(parent, name, dest);
-
-                  entries.put(delegator.getLocalPathName(), new EntryInfo(delegator, ent));
-                  addChild(parent, delegator);
+                  // mount another instance of ZipEntryContext
+                  delegator = mountZipFile(parent, name, dest);
                }
                else
                {
-                  DelegatingHandler delegator = mountZipStreamFS(parent, name, zipFile.openStream(ent));
+                  // mount another instance of ZipEntryContext
+                  delegator = mountZipStream(parent, name, zipSource.openStream(ent));
+               }
 
-                  entries.put(delegator.getLocalPathName(), new EntryInfo(delegator, ent));
-                  addChild(parent, delegator);
-               }
+               entries.put(delegator.getLocalPathName(), new EntryInfo(delegator, ent));
+               addChild(parent, delegator);
             }
             else
             {
@@ -271,12 +347,22 @@
       }
       finally
       {
-         zipFile.release();
+         zipSource.release();
       }
 
    }
 
-   protected DelegatingHandler mountZipFS(VirtualFileHandler parent, String name, File file) throws IOException, URISyntaxException
+   /**
+    * Mount ZipEntryContext created around extracted nested archive
+    *
+    * @param parent
+    * @param name
+    * @param file
+    * @return
+    * @throws IOException
+    * @throws URISyntaxException
+    */
+   protected DelegatingHandler mountZipFile(VirtualFileHandler parent, String name, File file) throws IOException, URISyntaxException
    {
       DelegatingHandler delegator = new DelegatingHandler(this, parent, name);
       URL fileUrl = file.toURL();
@@ -284,18 +370,25 @@
 
       if (parent != null)
          delegatorUrl = getChildURL(parent, name);
-         //delegatorUrl = new URL(VFSUtils.getChildURLString(parent.toURL(), name));
 
-
       ZipEntryContext ctx = new ZipEntryContext(delegatorUrl, delegator, fileUrl, true);
-
       VirtualFileHandler handler = ctx.getRoot();
       delegator.setDelegate(handler);
 
       return delegator;
    }
 
-   protected DelegatingHandler mountZipStreamFS(VirtualFileHandler parent, String name, InputStream zipStream) throws IOException, URISyntaxException
+   /**
+    * Mount ZipEntryContext created around ZipStreamWrapper
+    *
+    * @param parent
+    * @param name
+    * @param zipStream
+    * @return
+    * @throws IOException
+    * @throws URISyntaxException
+    */
+   protected DelegatingHandler mountZipStream(VirtualFileHandler parent, String name, InputStream zipStream) throws IOException, URISyntaxException
    {
       DelegatingHandler delegator = new DelegatingHandler(this, parent, name);
       ZipStreamWrapper wrapper = new ZipStreamWrapper(zipStream, name, parent.getLastModified());
@@ -306,14 +399,19 @@
          delegatorUrl = getChildURL(parent, name);
 
       ZipEntryContext ctx = new ZipEntryContext(delegatorUrl, delegator, wrapper, false);
-
       VirtualFileHandler handler = ctx.getRoot();
       delegator.setDelegate(handler);
 
       return delegator;
    }
 
-
+   /**
+    * Zip archives sometimes don't contain directory entries - only leaf entries
+    *
+    * @param parentPath
+    * @return
+    * @throws IOException
+    */
    private EntryInfo makeDummyParent(String parentPath) throws IOException
    {
       // get grand parent first
@@ -330,6 +428,12 @@
       return ei;
    }
 
+   /**
+    * Initialize rootEntryPath and return archive file path
+    *
+    * @param localRootUrl
+    * @return
+    */
    private String initRootAndPath(URL localRootUrl)
    {
       String filePath = localRootUrl.toString();
@@ -344,45 +448,54 @@
             rootEntryPath += "/";
       }
 
-      // find where schema ends - all schemas when you have wrapping - i.e. jar:file:/ ...
+      // find where url protocol ends - i.e. jar:file:/ ...
       pos= zipPath.indexOf(":/");
-      filePath = "file:" + zipPath.substring(pos+1);
+      filePath = zipPath.substring(pos+1);
 
-      return filePath;
+      // cut out url query part if present
+      int queryStart = filePath.indexOf("?");
+      if (queryStart != -1)
+         filePath = filePath.substring(0, queryStart);
+       
+      return "file:" + filePath;
    }
 
-   public VirtualFileHandler getRoot() throws IOException
-   {
-      return entries.get("").handler;
-   }
-
+   /**
+    * If archive has been modified, clear <em>entries</em> and re-initialize
+    */
    private synchronized void checkIfModified()
    {
-      // TODO: our rootFile may be a derivative - the extracted insides of another archive
-      // In that case we should delegate lastModified to its parent
-      // otherwise work on the file directly
-      if (zipFile.hasBeenModified())
+      // TODO: if zipSource represents a nested archive we should maybe delegate lastModified to its parent
+      if (zipSource.hasBeenModified())
       {
          EntryInfo rootInfo = entries.get("");
          entries = new ConcurrentHashMap<String, EntryInfo>();
          entries.put("", rootInfo);
 
-         if (zipFile.exists())
+         if (zipSource.exists())
          {
             try
             {
                initEntries();
             }
-            catch(Exception ex)
+            catch(Exception ignored)
             {
-               log.warn("IGNORING: Failed to reinitialize context: " + getRootURI(), ex);
+               log.warn("IGNORING: Failed to reinitialize context: " + getRootURI(), ignored);
             }
          }
       }
    }
 
+   public VirtualFileHandler getRoot() throws IOException
+   {
+      return entries.get("").handler;
+   }
+
    public VirtualFileHandler getChild(ZipEntryHandler parent, String name)
    {
+      if (parent == null)
+         throw new IllegalArgumentException("Null parent");
+
       checkIfModified();
       String pathName = parent.getLocalPathName();
       if("".equals(pathName))
@@ -421,13 +534,16 @@
 
    public long getLastModified(ZipEntryHandler handler)
    {
+      if (handler == null)
+         throw new IllegalArgumentException("Null handler");
+
       checkIfModified();
       EntryInfo ei = entries.get(handler.getLocalPathName());
       if(ei == null)
          return 0;
 
       if(ei.entry == null) {
-         return zipFile.getLastModified();
+         return zipSource.getLastModified();
       }
 
       return ei.entry.getTime();
@@ -435,6 +551,9 @@
 
    public long getSize(ZipEntryHandler handler)
    {
+      if (handler == null)
+         throw new IllegalArgumentException("Null handler");
+
       checkIfModified();
       String pathName = handler.getLocalPathName();
       EntryInfo ei = entries.get(pathName);
@@ -444,7 +563,7 @@
       if(ei.entry == null)
       {
          if(pathName.length() == 0)
-            return zipFile.getSize();
+            return zipSource.getSize();
          else
             return 0;
       }
@@ -454,16 +573,26 @@
 
    public boolean exists(ZipEntryHandler handler)
    {
+      if (handler == null)
+         throw new IllegalArgumentException("Null handler");
+
       checkIfModified();
-      EntryInfo ei = entries.get(handler.getLocalPathName());
+      String pathName = handler.getLocalPathName();
+      EntryInfo ei = entries.get(pathName);
       if(ei == null)
          return false;
 
+      if (ei.entry == null && pathName.length() == 0)
+         return zipSource.exists();
+
       return true;
    }
 
    public boolean isLeaf(ZipEntryHandler handler)
    {
+      if (handler == null)
+         throw new IllegalArgumentException("Null handler");
+
       checkIfModified();
       EntryInfo ei = entries.get(handler.getLocalPathName());
       if(ei == null || ei.entry == null)
@@ -474,6 +603,9 @@
 
    public InputStream openStream(ZipEntryHandler handler) throws IOException
    {
+      if (handler == null)
+         throw new IllegalArgumentException("Null handler");
+
       checkIfModified();
       EntryInfo ei = entries.get(handler.getLocalPathName());
 
@@ -494,14 +626,20 @@
 
       if(ei.entry == null)
       {
-         return zipFile.getRootAsStream(); 
+         return zipSource.getRootAsStream();
       }
       
-      return zipFile.openStream(ei.entry);
+      return zipSource.openStream(ei.entry);
    }
 
    public void addChild(AbstractVirtualFileHandler parent, AbstractVirtualFileHandler child)
    {
+      if (parent == null)
+         throw new IllegalArgumentException("Null parent");
+
+      if (child == null)
+         throw new IllegalArgumentException("Null child");
+
       EntryInfo parentEntry = entries.get(parent.getLocalPathName());
       if (parentEntry != null)
          parentEntry.add(child);
@@ -515,11 +653,12 @@
    {
       try
       {
-         zipFile.close();
+         super.finalize();
+         zipSource.close();
       }
-      catch (Exception ex)
+      catch (Throwable ignored)
       {
-         // ignore
+         log.debug("IGNORING: Failed to close zip source: " + zipSource, ignored);
       }
    }
 
@@ -559,7 +698,7 @@
 
 
    /**
-    *  Internal data structure, holding ZipEntries and child handlers for every handler in this context
+    *  Internal data structure holding meta information of a virtual file in this context
     */
    static class EntryInfo
    {
@@ -609,13 +748,30 @@
       public synchronized void add(AbstractVirtualFileHandler child)
       {
          if (children == null)
+         {
             children = new LinkedList<AbstractVirtualFileHandler>();
+         }
+         else
+         {
+            // if a child exists with this name already, remove it
+            Iterator<AbstractVirtualFileHandler> it = children.iterator();
+            while (it.hasNext())
+            {
+               AbstractVirtualFileHandler handler = it.next();
+               if (handler.getName().equals(child.getName()))
+               {
+                  it.remove();
+                  break;
+               }
+            }
+         }
 
          children.add(child);
       }
    }
 
 
+
    //
    //   Helper methods
    //
@@ -624,6 +780,7 @@
 
    /**
     * Copy input stream to output stream and close them both
+    *
     * @param is
     * @param os
     * @throws IOException
@@ -647,19 +804,24 @@
             try {
                is.close();
             }
-            catch(Exception ex)
+            catch(Exception ignored)
             {
-               // ignore
             }
          }
          os.close();
       }
    }
 
-
+   /**
+    * Make sure url protocol is <em>vfszip</em>
+    *
+    * @param rootURL
+    * @return
+    * @throws MalformedURLException
+    */
    private static URL fixUrl(URL rootURL) throws MalformedURLException
    {
-      if (!"vfszip".equals(rootURL.getProtocol()))
+      if ("vfszip".equals(rootURL.getProtocol()) == false)
       {
          String url = rootURL.toString();
          int pos = url.indexOf(":/");
@@ -671,6 +833,12 @@
       return rootURL;
    }
 
+   /**
+    * Break to path + name
+    *
+    * @param pathName
+    * @return
+    */
    public static String [] splitParentChild(String pathName)
    {
       if(pathName.length() == 0)
@@ -703,23 +871,34 @@
    }
 
 
-
-   // TODO: the following two methods are a quick and dirty strategy for temp file name and path
+   /**
+    * Temporary files naming scheme
+    *
+    * @param name
+    * @return
+    */
    private static String getTempFileName(String name)
    {
       int delim = name.lastIndexOf("/");
       if (delim != -1)
          name = name.substring(delim+1);
-      return UUID.randomUUID().toString() + "_" + name;
+      return UUID.randomUUID().toString().substring(0, 18) + "_" + name;
    }
 
+   /**
+    * Use VFS's temp directory and make 'vfs-nested' sub-directory inside it for our purposes
+    *
+    * @return
+    */
    private static String getTempDir()
    {
-      File dir = new File(System.getProperty("jboss.server.temp.dir"), "vfs.tmp");
-      //dir.mkdirs();
+      File dir = new File(VFSUtils.getTempDirectory(), "vfs-nested.tmp");
       return dir.toString();
    }
 
+   /**
+    * Delete first-level files only, don't drill down
+    */
    private static void deleteTmpDirContents()
    {
       try
@@ -732,9 +911,8 @@
                file.delete();
          }
       }
-      catch(Exception ex)
+      catch(Exception ignored)
       {
-        // ignore
       }
 
    }

Modified: projects/vfs/branches/jar-alter-work/src/main/java/org/jboss/virtual/plugins/context/zip/ZipEntryContextFactory.java
===================================================================
--- projects/vfs/branches/jar-alter-work/src/main/java/org/jboss/virtual/plugins/context/zip/ZipEntryContextFactory.java	2008-06-01 09:13:34 UTC (rev 73899)
+++ projects/vfs/branches/jar-alter-work/src/main/java/org/jboss/virtual/plugins/context/zip/ZipEntryContextFactory.java	2008-06-01 16:17:45 UTC (rev 73900)
@@ -1,3 +1,24 @@
+/*
+* 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.zip;
 
 import org.jboss.virtual.plugins.context.AbstractContextFactory;
@@ -20,11 +41,15 @@
 
 public class ZipEntryContextFactory extends AbstractContextFactory
 {
+   /** registry of all ZipEntryContext instances */
+   private static Map<String, ZipEntryContext> ctxCache = new ConcurrentHashMap<String, ZipEntryContext>();
 
-   public static Map<String, ZipEntryContext> ctxCache = new ConcurrentHashMap<String, ZipEntryContext>();
-
+   /** singleton */
    private static ZipEntryContextFactory instance = new ZipEntryContextFactory();
 
+   /**
+    * ZipEntryContextFactory registers two url protocols: <em>zip</em> and <em>vfszip</em>
+    */
    public ZipEntryContextFactory()
    {
       super("zip", "vfszip");  // "jar", "vfsjar",  
@@ -35,6 +60,13 @@
       return getVFS(rootURI.toURL());
    }
 
+   /**
+    * Find a best matching existing ZipEntryContext, or create a new one if none matches.
+    *
+    * @param rootURL
+    * @return
+    * @throws IOException
+    */
    public VFSContext getVFS(URL rootURL) throws IOException
    {
       String key = rootURL.toString();
@@ -74,8 +106,8 @@
          throw e;
       }
 
-      // no need to put a newly created context into ctxCache
-      // it's constructor does that by calling registerContext
+      // ZipEntryContext registers newly created context with this factory
+      // by calling registerContext() which puts a newly created context into ctxCache
       
       return ctx;
    }

Modified: projects/vfs/branches/jar-alter-work/src/main/java/org/jboss/virtual/plugins/context/zip/ZipEntryHandler.java
===================================================================
--- projects/vfs/branches/jar-alter-work/src/main/java/org/jboss/virtual/plugins/context/zip/ZipEntryHandler.java	2008-06-01 09:13:34 UTC (rev 73899)
+++ projects/vfs/branches/jar-alter-work/src/main/java/org/jboss/virtual/plugins/context/zip/ZipEntryHandler.java	2008-06-01 16:17:45 UTC (rev 73900)
@@ -1,3 +1,24 @@
+/*
+* 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.zip;
 
 import org.jboss.virtual.VFSUtils;

Modified: projects/vfs/branches/jar-alter-work/src/main/java/org/jboss/virtual/plugins/context/zip/ZipEntryInputStream.java
===================================================================
--- projects/vfs/branches/jar-alter-work/src/main/java/org/jboss/virtual/plugins/context/zip/ZipEntryInputStream.java	2008-06-01 09:13:34 UTC (rev 73899)
+++ projects/vfs/branches/jar-alter-work/src/main/java/org/jboss/virtual/plugins/context/zip/ZipEntryInputStream.java	2008-06-01 16:17:45 UTC (rev 73900)
@@ -1,3 +1,24 @@
+/*
+* 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.zip;
 
 import java.io.IOException;
@@ -2,7 +23,9 @@
 import java.io.InputStream;
-import java.util.zip.ZipEntry;
 
 /**
- * InputStream that wraps an InputStream retrieved from ZipFile.getInputStream(entry)
+ * ZipEntryInputStream is part of ZipFileWrapper implementation.
  *
+ * It wraps the stream retrieved from ZipFile.getInputStream(entry)
+ * and releases the underlying ZipFileWrapper when detecting end of use.
+ *
  * @author <a href="strukelj at parsek.net">Marko Strukelj</a>
@@ -21,6 +44,9 @@
 
    ZipEntryInputStream(ZipFileWrapper zipWrapper, InputStream is) throws IOException
    {
+      if (is == null)
+         throw new IllegalArgumentException("Input stream is null");
+      
       this.zipWrapper = zipWrapper;
       delegate = is;
    }
@@ -146,9 +172,8 @@
       {
          close();
       }
-      catch(IOException ex)
+      catch(IOException ignored)
       {
-         // ignore
       }
    }
 

Modified: projects/vfs/branches/jar-alter-work/src/main/java/org/jboss/virtual/plugins/context/zip/ZipFileLockReaper.java
===================================================================
--- projects/vfs/branches/jar-alter-work/src/main/java/org/jboss/virtual/plugins/context/zip/ZipFileLockReaper.java	2008-06-01 09:13:34 UTC (rev 73899)
+++ projects/vfs/branches/jar-alter-work/src/main/java/org/jboss/virtual/plugins/context/zip/ZipFileLockReaper.java	2008-06-01 16:17:45 UTC (rev 73900)
@@ -1,3 +1,24 @@
+/*
+* 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.zip;
 
 import org.jboss.logging.Logger;
@@ -8,7 +29,7 @@
 import java.util.concurrent.ConcurrentLinkedQueue;
 
 /**
- * Monitoring object that closes ZipFiles when they haven't been used for a while
+ * A monitoring object that closes ZipFiles when they haven't been used for a while
  *
  * @author <a href="strukelj at parsek.net">Marko Strukelj</a>
  * @version $Revision: 1.0 $
@@ -16,7 +37,6 @@
 
 public class ZipFileLockReaper
 {
-   /** Logger */
    private static final Logger log = Logger.getLogger(ZipFileLockReaper.class);
 
    /**
@@ -28,7 +48,7 @@
    /** Timer thread period */
    private static final int TIMER_PERIOD = 1000;
 
-   /** If timer finds out there are no open ZipFiles for a while it shuts down until some are (re)opened */
+   /** If timer finds out there haven't been any ZipFiles open for a while it shuts down until some are (re)opened */
    private static final int TIMER_UNUSED_PERIOD = 30000;
 
    /** There is only one instance that serves all ZipFileWrappers */
@@ -136,10 +156,9 @@
                   w.closeZipFile();
                   log.debug("Asynchronously closed an unused ZipFile: " + w);
                }
-               catch(Exception ex)
+               catch(Exception ignored)
                {
-                  // ignore the exception
-                  log.debug("IGNORING: Failed to close ZipFile: ", ex);
+                  log.debug("IGNORING: Failed to close ZipFile: " + w, ignored);
                }
             }
          }

Modified: projects/vfs/branches/jar-alter-work/src/main/java/org/jboss/virtual/plugins/context/zip/ZipFileWrapper.java
===================================================================
--- projects/vfs/branches/jar-alter-work/src/main/java/org/jboss/virtual/plugins/context/zip/ZipFileWrapper.java	2008-06-01 09:13:34 UTC (rev 73899)
+++ projects/vfs/branches/jar-alter-work/src/main/java/org/jboss/virtual/plugins/context/zip/ZipFileWrapper.java	2008-06-01 16:17:45 UTC (rev 73900)
@@ -1,3 +1,24 @@
+/*
+* 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.zip;
 
 import org.jboss.logging.Logger;
@@ -17,8 +38,10 @@
 
 
 /**
- * ZipFileWrapper releases and reacquires an underlying ZipFile as necessary
+ * ZipFileWrapper - for abstracted access to zip files on disk
  *
+ * It releases and reacquires the underlying ZipFile as necessary
+ *
  * @author <a href="strukelj at parsek.net">Marko Strukelj</a>
  * @version $Revision: 1.0 $
  */
@@ -39,25 +62,31 @@
 
    }
 
-
    private File file;
 
+   /** zip inflater wrapped around file */
    private ZipFile zipFile;
 
+   /** true for extracted nested jars that we want removed when this wrapper is closed */
    private boolean autoClean;
 
+   /** true if noReaper mode is forced on a per-instance basis */
+   private boolean noReaperOverride;
+
    // used for debugging stream leaks
    //ConcurrentLinkedQueue<ZipEntryInputStream> streams = new ConcurrentLinkedQueue<ZipEntryInputStream>();
 
 
-   ZipFileWrapper(File archive, boolean autoClean)
+   ZipFileWrapper(File archive, boolean autoClean, boolean noReaperOverride)
    {
+      this.noReaperOverride = noReaperOverride;
       init(archive, autoClean);
    }
 
 
-   ZipFileWrapper(URI rootPathURI, boolean autoClean)
+   ZipFileWrapper(URI rootPathURI, boolean autoClean, boolean noReaperOverride)
    {
+      this.noReaperOverride = noReaperOverride;
       File rootFile = new File(rootPathURI);
       if(!rootFile.isFile())
          throw new RuntimeException("File not found: " + rootFile);
@@ -65,6 +94,12 @@
       init(rootFile, autoClean);
    }
 
+   /**
+    * Extra initialization that didn't fit in constructors
+    *
+    * @param archive
+    * @param autoClean
+    */
    private void init(File archive, boolean autoClean)
    {
       file = archive;
@@ -99,7 +134,7 @@
       if (zipFile == null)
       {
          zipFile = new ZipFile(file);
-         if (forceNoReaper == false)
+         if (forceNoReaper == false && noReaperOverride == false)
             ZipFileLockReaper.getInstance().register(this);
       }
 
@@ -113,7 +148,7 @@
          ZipFile zf = zipFile;
          zipFile = null;
          zf.close();
-         if (forceNoReaper == false)
+         if (forceNoReaper == false && noReaperOverride == false)
             ZipFileLockReaper.getInstance().unregister(this);
       }
    }
@@ -122,6 +157,9 @@
    {
       ensureZipFile();
       InputStream is = zipFile.getInputStream(ent);
+      if (is == null)
+         throw new IOException("Entry no longer available: " + ent.getName() + " in file " + file);
+      
       ZipEntryInputStream zis = new ZipEntryInputStream(this, is);
 
       // debugging code
@@ -146,7 +184,7 @@
 
    synchronized void release() {
       super.release();
-      if (forceNoReaper)
+      if (forceNoReaper || noReaperOverride)
          try
          {
             closeZipFile();
@@ -168,9 +206,9 @@
       {
          closeZipFile();
       }
-      catch(Exception ex)
+      catch(Exception ignored)
       {
-         log.warn("IGNORING: Failed to release file: " + file, ex);
+         log.warn("IGNORING: Failed to release file: " + file, ignored);
       }
 
       if (autoClean)

Modified: projects/vfs/branches/jar-alter-work/src/main/java/org/jboss/virtual/plugins/context/zip/ZipStreamWrapper.java
===================================================================
--- projects/vfs/branches/jar-alter-work/src/main/java/org/jboss/virtual/plugins/context/zip/ZipStreamWrapper.java	2008-06-01 09:13:34 UTC (rev 73899)
+++ projects/vfs/branches/jar-alter-work/src/main/java/org/jboss/virtual/plugins/context/zip/ZipStreamWrapper.java	2008-06-01 16:17:45 UTC (rev 73900)
@@ -1,14 +1,33 @@
+/*
+* 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.zip;
 
-import org.jboss.virtual.plugins.context.zip.SizeLimitedInputStream;
-
 import java.io.*;
 import java.util.Enumeration;
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipInputStream;
 
 /**
- * ZipStreamWrapper - abstracted access to in-memory zip file
+ * ZipStreamWrapper - for abstracted access to in-memory zip file
  *
  * @author <a href="strukelj at parsek.net">Marko Strukelj</a>
  * @version $Revision: 1.0 $
@@ -18,12 +37,15 @@
    /** Raw zip archive loaded in memory */
    private byte [] zipBytes;
 
-   /** Name of an underlying file */
+   /** Name */
    private String name;
 
    /**
+    * ZipStreamWrapper is not aware of actual zip source so it can not detect
+    * if it's been modified, like ZipFileWrapper does.
+    *
     * @param zipStream
-    * @param lastModified passed by zip stream provider. We're not aware of zip source so we can not detect it was changed
+    * @param lastModified passed by zip stream provider - constant value
     * @throws IOException
     */
    ZipStreamWrapper(InputStream zipStream, String name, long lastModified) throws IOException
@@ -74,7 +96,7 @@
          throw new IOException("Failed to find nested jar entry: " + ent.getName() + " in zip stream: " + this.name);
 
 
-      // now read it
+      // then read it
       return new SizeLimitedInputStream(zis, (int) entry.getSize());
    }
 
@@ -93,7 +115,6 @@
    }
 
 
-
    void close()
    {
       zipBytes = null;

Modified: projects/vfs/branches/jar-alter-work/src/main/java/org/jboss/virtual/plugins/context/zip/ZipWrapper.java
===================================================================
--- projects/vfs/branches/jar-alter-work/src/main/java/org/jboss/virtual/plugins/context/zip/ZipWrapper.java	2008-06-01 09:13:34 UTC (rev 73899)
+++ projects/vfs/branches/jar-alter-work/src/main/java/org/jboss/virtual/plugins/context/zip/ZipWrapper.java	2008-06-01 16:17:45 UTC (rev 73900)
@@ -1,3 +1,24 @@
+/*
+* 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.zip;
 
 import java.io.IOException;
@@ -7,7 +28,7 @@
 import java.util.Enumeration;
 
 /**
- * ZipWrapper represents abstracted access to zip resource
+ * ZipWrapper represents abstracted access to zip archive
  *
  * @author <a href="strukelj at parsek.net">Marko Strukelj</a>
  * @version $Revision: 1.0 $
@@ -16,17 +37,24 @@
 abstract class ZipWrapper
 {
 
+   /** last known modifyTime of the zip source */
    protected long lastModified;
 
-   protected long lastChecked;
+   /** timestamp of last call to getLastModified()
+    * it's an expensive call - we don't do it more then once every second */
+   private long lastChecked;
 
+   /** last known activity */
    private long lastUsed;
 
+   /** number of streams currently open on this wrapper */
    private int refCount = 0;
 
 
 
-   
+   /**
+    * Returns true if underlying source's lastModified time has changed since previous call
+    */
    boolean hasBeenModified()
    {
       long now = System.currentTimeMillis();
@@ -49,7 +77,11 @@
       return lastUsed;
    }
 
-
+   /**
+    * Returns the number of streams currently open
+    *
+    * @return
+    */
    int getReferenceCount()
    {
       return refCount;
@@ -62,8 +94,6 @@
    }
 
 
-   abstract void acquire() throws IOException;
-
    synchronized void release()
    {
       refCount--;
@@ -73,6 +103,7 @@
       }
    }
 
+   abstract void acquire() throws IOException;
 
    abstract long getLastModified();
 

Modified: projects/vfs/branches/jar-alter-work/src/test/java/org/jboss/test/virtual/test/ZipEntryVFSContextUnitTestCase.java
===================================================================
--- projects/vfs/branches/jar-alter-work/src/test/java/org/jboss/test/virtual/test/ZipEntryVFSContextUnitTestCase.java	2008-06-01 09:13:34 UTC (rev 73899)
+++ projects/vfs/branches/jar-alter-work/src/test/java/org/jboss/test/virtual/test/ZipEntryVFSContextUnitTestCase.java	2008-06-01 16:17:45 UTC (rev 73900)
@@ -24,12 +24,14 @@
 import junit.framework.Test;
 import junit.framework.TestSuite;
 import org.jboss.virtual.VFS;
-import org.jboss.virtual.plugins.context.file.FileSystemContext;
-import org.jboss.virtual.plugins.context.jar.JarContext;
 import org.jboss.virtual.plugins.context.jar.JarUtils;
 import org.jboss.virtual.plugins.context.zip.ZipEntryContext;
 import org.jboss.virtual.spi.VFSContext;
 
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.io.OutputStream;
 import java.net.URL;
 
 /**
@@ -103,4 +105,37 @@
       assertEquals("", context.getRoot().getPathName());
    }
 
+   /**
+    * Test detection of underlying jar file removal through exists()
+    *
+    * @throws Exception
+    */
+   public void testRootExists() throws Exception
+   {
+      URL url = getResource("/vfs/test/outer.jar");
+      File tmpJar = File.createTempFile("vfstest", ".jar");
+
+      InputStream is = url.openStream();
+      OutputStream os = new FileOutputStream(tmpJar);
+
+      byte [] buff = new byte[65536];
+      int count = is.read(buff);
+      while(count != -1)
+      {
+         os.write(buff, 0, count);
+         count = is.read(buff);
+      }
+      os.close();
+
+      // use noReaper so that the underlying file is not locked
+      // when we try to delete it
+      String jarUrl = tmpJar.toURL().toString() + "?noReaper=true";
+      ZipEntryContext context = new ZipEntryContext(new URL(jarUrl));
+      assertTrue("context.getRoot().exists()", context.getRoot().exists());
+
+      boolean isDeleted = tmpJar.delete();
+      assertTrue("delete tmp file: " + tmpJar, isDeleted);
+
+      assertFalse("context.getRoot().exists()", context.getRoot().exists());
+   }
 }
\ No newline at end of file




More information about the jboss-cvs-commits mailing list