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

jboss-cvs-commits at lists.jboss.org jboss-cvs-commits at lists.jboss.org
Thu May 29 20:08:06 EDT 2008


Author: mstruk
Date: 2008-05-29 20:08:06 -0400 (Thu, 29 May 2008)
New Revision: 73826

Added:
   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/ZipStreamWrapper.java
   projects/vfs/branches/jar-alter-work/src/main/java/org/jboss/virtual/plugins/context/zip/ZipWrapper.java
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/file/FileSystemContext.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/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/test/java/org/jboss/test/virtual/test/FileVFSUnitTestCase.java
Log:
Added noCopy support, fixed some bugs, added system prop switches: jboss.vfs.forceVfsJar and jboss.vfs.forceNoReaper

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-05-29 23:28:29 UTC (rev 73825)
+++ projects/vfs/branches/jar-alter-work/src/main/java/org/jboss/virtual/VFSUtils.java	2008-05-30 00:08:06 UTC (rev 73826)
@@ -78,6 +78,16 @@
    public static final String FORCE_COPY_KEY = "jboss.vfs.forceCopy";
    public static final String USE_COPY_QUERY = "useCopyJarHandler";
 
+   /**
+    * Key used to force fallback from vfszip (default) to vfsjar
+    */
+   public static final String FORCE_VFS_JAR_KEY = "jboss.vfs.forceVfsJar";
+
+   /**
+    * 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";
+
    private static File tempDir;
 
    private static class GetTempDir implements PrivilegedAction<File>

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-05-29 23:28:29 UTC (rev 73825)
+++ projects/vfs/branches/jar-alter-work/src/main/java/org/jboss/virtual/plugins/context/file/FileSystemContext.java	2008-05-30 00:08:06 UTC (rev 73826)
@@ -27,6 +27,8 @@
 import java.net.URI;
 import java.net.URISyntaxException;
 import java.net.URL;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
 import java.util.List;
 import java.util.Properties;
 
@@ -35,19 +37,36 @@
 import org.jboss.virtual.plugins.context.AbstractVFSContext;
 import org.jboss.virtual.plugins.context.DelegatingHandler;
 import org.jboss.virtual.plugins.context.zip.ZipEntryContext;
+import org.jboss.virtual.plugins.context.jar.JarHandler;
 import org.jboss.virtual.plugins.context.jar.JarUtils;
 import org.jboss.virtual.spi.LinkInfo;
 import org.jboss.virtual.spi.VirtualFileHandler;
+import org.jboss.logging.Logger;
 
 /**
  * FileSystemContext.
  * 
  * @author <a href="adrian at jboss.com">Adrian Brock</a>
  * @author <a href="ales.justin at jboss.com">Ales Justin</a>
+ * @author <a href="strukelj at parsek.net">Marko Strukelj</a>
  * @version $Revision: 1.1 $
  */
 public class FileSystemContext extends AbstractVFSContext
 {
+
+   private static final Logger log = Logger.getLogger(ZipEntryContext.class);
+
+   /** true if forcing fallback to vfsjar from default vfszip */
+   private static boolean forceVfsJar;
+
+   static
+   {
+      forceVfsJar = AccessController.doPrivileged(new CheckForceVfsJar());
+
+      if (forceVfsJar)
+         log.warn("VFS forced fallback to vfsjar is enabled.");
+   }
+
    /** The root file */
    private final VirtualFileHandler root;
    
@@ -189,15 +208,23 @@
       String name = file.getName();
       if (file.isFile() && JarUtils.isArchive(name))
       {
-         try
+         if (forceVfsJar)
          {
-            //return new JarHandler(this, parent, file, file.toURL(), name);
-            DelegatingHandler delegator = mountZipFS(parent, name, file);
-            return delegator;
+            return new JarHandler(this, parent, file, file.toURL(), name);
          }
-         catch (Exception e)
+         else
          {
-            log.debug("Exception while trying to handle file (" + name + ") as a jar: " + e.getMessage());
+            try
+            {
+               DelegatingHandler delegator = mountZipFS(parent, name, file);
+               return delegator;
+            }
+            catch (Exception e)
+            {
+               IOException ex = new IOException("Exception while trying to handle file (" + name + ") through ZipEntryContext: ");
+               ex.initCause(e);
+               throw ex;
+            }
          }
       }
       return createVirtualFileHandler(parent, file, getFileURI(file));
@@ -294,4 +321,14 @@
          rootFile.close();
       super.finalize();
    }
+
+   private static class CheckForceVfsJar implements PrivilegedAction<Boolean>
+   {
+      public Boolean run()
+      {
+         String forceString = System.getProperty(VFSUtils.FORCE_VFS_JAR_KEY, "false");
+         return Boolean.valueOf(forceString);
+      }
+   }
+
 }

Added: 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	                        (rev 0)
+++ projects/vfs/branches/jar-alter-work/src/main/java/org/jboss/virtual/plugins/context/zip/SizeLimitedInputStream.java	2008-05-30 00:08:06 UTC (rev 73826)
@@ -0,0 +1,62 @@
+package org.jboss.virtual.plugins.context.zip;
+
+import java.io.InputStream;
+import java.io.IOException;
+
+/**
+ * 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 $
+ */
+
+public class SizeLimitedInputStream extends InputStream
+{
+
+	private InputStream in;
+
+   private int togo;
+
+	public SizeLimitedInputStream(InputStream ins, int size)
+   {
+		this.in = ins;
+		this.togo = size;
+	}
+
+	public int read() throws IOException
+   {
+		int b = -1;
+		if (togo > 0)
+      {
+			b = in.read();
+			if (b != -1)
+            togo--;
+		}
+		return b;
+	}
+
+	public int read(byte [] buf) throws IOException
+   {
+		return read(buf, 0, buf.length);
+	}
+
+	public int read(byte [] buf, int offs, int len) throws IOException
+   {
+		int rc = -1;
+
+		if (togo > 0)
+      {
+			rc = togo < len ? togo : len;
+			rc = in.read(buf, offs, rc);
+			if (rc != -1)
+            togo -= rc;
+		}
+
+		return rc;
+	}
+
+	public void close() throws IOException
+   {
+		in.close();
+	}
+}
\ No newline at end of file

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-05-29 23:28:29 UTC (rev 73825)
+++ projects/vfs/branches/jar-alter-work/src/main/java/org/jboss/virtual/plugins/context/zip/ZipEntryContext.java	2008-05-30 00:08:06 UTC (rev 73826)
@@ -1,20 +1,36 @@
 package org.jboss.virtual.plugins.context.zip;
 
+import org.jboss.logging.Logger;
+import org.jboss.virtual.VFSUtils;
 import org.jboss.virtual.plugins.context.AbstractVFSContext;
 import org.jboss.virtual.plugins.context.AbstractVirtualFileHandler;
 import org.jboss.virtual.plugins.context.DelegatingHandler;
 import org.jboss.virtual.plugins.context.jar.JarUtils;
 import org.jboss.virtual.spi.VirtualFileHandler;
 
-import java.io.*;
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
 import java.net.MalformedURLException;
-import java.net.URI;
 import java.net.URISyntaxException;
 import java.net.URL;
-import java.util.*;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+import java.util.UUID;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.zip.ZipEntry;
-import java.util.zip.ZipFile;
 
 /**
  * VFSContext exposing a zip archive file as a virtual file system
@@ -25,16 +41,24 @@
 
 public class ZipEntryContext extends AbstractVFSContext
 {
+
+   private static final Logger log = Logger.getLogger(ZipEntryContext.class);
+
+   private static boolean forceCopy;
+
    static
    {
       deleteTmpDirContents();
+
+      forceCopy = AccessController.doPrivileged(new CheckForceCopy());
+
+      if (forceCopy)
+         log.info("VFS force nested jars copy-mode is enabled.");
    }
 
-   /** File representing a zip archive that is virtualized with this context */
-   private File rootFile;
 
    /** ZipFile opened around rootFile */
-   private ZipFileWrapper zipFile;
+   private ZipWrapper zipFile;
 
    /** Entry path representing a context root */
    private String rootEntryPath = "";
@@ -63,13 +87,13 @@
     * @param rootURL - file or jar:file url
     * @param autoClean - true if file represented by rootURL should be deleted after this context is closed
     * @throws URISyntaxException
-    * @throws IOException
+    * @throws java.io.IOException
     */
    public ZipEntryContext(URL rootURL, boolean autoClean) throws URISyntaxException, IOException
    {
-      super(fixUrl(rootURL));
+      super(VFSUtils.toURI(fixUrl(rootURL)));
       this.autoClean = autoClean;
-      init(rootURL, null);
+      init(rootURL, null, null);
    }
 
    /**
@@ -79,7 +103,7 @@
     * @param peer - file handler in another context through which this context is being mounted
     * @param localRootUrl - file or jar:file url
     * @throws URISyntaxException
-    * @throws IOException
+    * @throws java.io.IOException
     */
    public ZipEntryContext(URL rootURL, VirtualFileHandler peer, URL localRootUrl) throws URISyntaxException, IOException
    {
@@ -98,19 +122,44 @@
     */
    public ZipEntryContext(URL rootURL, VirtualFileHandler peer, URL localRootUrl, boolean autoClean) throws URISyntaxException, IOException
    {
-      super(fixUrl(rootURL));
+      super(VFSUtils.toURI(fixUrl(rootURL)));
       this.autoClean = autoClean;
-      init(localRootUrl, peer);
+      init(localRootUrl, peer, null);
    }
 
-   private void init(URL localRootURL, VirtualFileHandler peer) throws IOException, URISyntaxException
+   /**
+    * Create a new ZipEntryContext being 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 autoClean - true if file represented by localRootURL should be deleted after this context is closed
+    * @throws URISyntaxException
+    * @throws IOException
+    */
+   public ZipEntryContext(URL rootURL, VirtualFileHandler peer, ZipWrapper zipWrapper, boolean autoClean) throws URISyntaxException, IOException
    {
-      initFileAndPath(localRootURL);
+      super(VFSUtils.toURI(fixUrl(rootURL)));
+      this.autoClean = autoClean;
+      init(null, peer, zipWrapper);
+   }
 
-      if(!rootFile.isFile())
-         throw new RuntimeException("File not found: " + rootFile);
 
-      zipFile = new ZipFileWrapper(rootFile);
+   private void init(URL localRootURL, VirtualFileHandler peer, ZipWrapper zipWrapper) throws IOException, URISyntaxException
+   {
+
+      if (zipWrapper == null)
+      {
+         if (localRootURL == null)
+            throw new IllegalArgumentException("No ZipWrapper specified and localRootURL is null");
+         String rootPath = initRootAndPath(localRootURL);
+         zipFile = new ZipFileWrapper(VFSUtils.toURI(new URL(rootPath)), autoClean);
+      }
+      else
+      {
+         zipFile = zipWrapper;
+      }
+      
       setRootPeer(peer);
 
       String name = getRootURI().toString();   // rootFile.getName()
@@ -139,7 +188,7 @@
       if (peer != null)
          return peer.getName();
       else
-         return rootFile.getName();
+         return zipFile.getName();
    }
 
    private synchronized void initEntries() throws IOException, URISyntaxException
@@ -150,10 +199,10 @@
       // this way we ensure that parent entries are processed before child entries
 
       HashMap<String, ZipEntry> relevant = new HashMap<String, ZipEntry>();
-      ZipFile zFile = zipFile.acquire();
+      zipFile.acquire();
       try
       {
-         Enumeration<? extends ZipEntry> zipEntries = zFile.entries();
+         Enumeration<? extends ZipEntry> zipEntries = zipFile.entries();
          while(zipEntries.hasMoreElements())
          {
             ZipEntry ent = zipEntries.nextElement();
@@ -182,18 +231,35 @@
 
             if(ent.isDirectory() == false && JarUtils.isArchive(ent.getName()))
             {
-               // extract it to temp dir
-               File dest = new File(getTempDir() + "/" + getTempFileName(ent.getName()));
-               dest.getParentFile().mkdirs();  // ensure parent exists
-               InputStream is = zipFile.openStream(ent);
-               OutputStream os = new BufferedOutputStream(new FileOutputStream(dest));
-               copyStreamAndClose(is, os);
+               boolean useCopyMode = forceCopy;
+               if (useCopyMode == false)
+               {
+                  String flag = getOptions().get(VFSUtils.USE_COPY_QUERY);
+                  useCopyMode = Boolean.valueOf(flag);
+               }
 
-               // mount FS
-               DelegatingHandler delegator = mountZipFS(parent, name, dest);
+               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);
+                  OutputStream os = new BufferedOutputStream(new FileOutputStream(dest));
+                  copyStreamAndClose(is, os);
 
-               entries.put(delegator.getLocalPathName(), new EntryInfo(delegator, ent));
-               addChild(parent, delegator);
+                  // mount FS
+                  DelegatingHandler delegator = mountZipFS(parent, name, dest);
+
+                  entries.put(delegator.getLocalPathName(), new EntryInfo(delegator, ent));
+                  addChild(parent, delegator);
+               }
+               else
+               {
+                  DelegatingHandler delegator = mountZipStreamFS(parent, name, zipFile.openStream(ent));
+
+                  entries.put(delegator.getLocalPathName(), new EntryInfo(delegator, ent));
+                  addChild(parent, delegator);
+               }
             }
             else
             {
@@ -229,6 +295,25 @@
       return delegator;
    }
 
+   protected DelegatingHandler mountZipStreamFS(VirtualFileHandler parent, String name, InputStream zipStream) throws IOException, URISyntaxException
+   {
+      DelegatingHandler delegator = new DelegatingHandler(this, parent, name);
+      ZipStreamWrapper wrapper = new ZipStreamWrapper(zipStream, name, parent.getLastModified());
+
+      URL delegatorUrl = null;
+
+      if (parent != null)
+         delegatorUrl = getChildURL(parent, name);
+
+      ZipEntryContext ctx = new ZipEntryContext(delegatorUrl, delegator, wrapper, false);
+
+      VirtualFileHandler handler = ctx.getRoot();
+      delegator.setDelegate(handler);
+
+      return delegator;
+   }
+
+
    private EntryInfo makeDummyParent(String parentPath) throws IOException
    {
       // get grand parent first
@@ -245,7 +330,7 @@
       return ei;
    }
 
-   private void initFileAndPath(URL localRootUrl)
+   private String initRootAndPath(URL localRootUrl)
    {
       String filePath = localRootUrl.toString();
       String zipPath = filePath;
@@ -259,19 +344,11 @@
             rootEntryPath += "/";
       }
 
-      try
-      {
-         // find where schema ends - all schemas when you have wrapping ...
-         pos= zipPath.indexOf(":/");
-         filePath = "file:" + zipPath.substring(pos+1);
-         rootFile = new File(new URI(filePath));
-         if (autoClean)
-            rootFile.deleteOnExit();
-      }
-      catch(Exception ex)
-      {
-         throw new RuntimeException("ASSERTION ERROR - Could not create URI: " + filePath, ex);
-      }
+      // find where schema ends - all schemas when you have wrapping - i.e. jar:file:/ ...
+      pos= zipPath.indexOf(":/");
+      filePath = "file:" + zipPath.substring(pos+1);
+
+      return filePath;
    }
 
    public VirtualFileHandler getRoot() throws IOException
@@ -281,8 +358,8 @@
 
    private synchronized void checkIfModified()
    {
-      // our rootFile may be a derivative - the extracted insides of another archive
-      // if RootContextInfo is available - delegate to it
+      // 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())
       {
@@ -298,11 +375,10 @@
             }
             catch(Exception ex)
             {
-               log.warn("Failed to reinitialize context: " + getRootURI());
+               log.warn("IGNORING: Failed to reinitialize context: " + getRootURI(), ex);
             }
          }
       }
-
    }
 
    public VirtualFileHandler getChild(ZipEntryHandler parent, String name)
@@ -322,7 +398,6 @@
       return null;
    }
 
-
    public List<VirtualFileHandler> getChildren(VirtualFileHandler parent, boolean ignoreErrors) throws IOException
    {
       if (parent == null)
@@ -344,7 +419,6 @@
       return Collections.emptyList();
    }
 
-
    public long getLastModified(ZipEntryHandler handler)
    {
       checkIfModified();
@@ -353,7 +427,7 @@
          return 0;
 
       if(ei.entry == null) {
-         return rootFile.lastModified();
+         return zipFile.getLastModified();
       }
 
       return ei.entry.getTime();
@@ -370,7 +444,7 @@
       if(ei.entry == null)
       {
          if(pathName.length() == 0)
-            return rootFile.length();
+            return zipFile.getSize();
          else
             return 0;
       }
@@ -412,7 +486,7 @@
          }
          catch(Exception ex)
          {
-            throw new RuntimeException("ASSERTION ERROR - uri generation failed for ZipEntryHandler: " + handler);
+            throw new RuntimeException("ASSERTION ERROR - uri generation failed for ZipEntryHandler: " + handler, ex);
          }
          throw new FileNotFoundException(uriStr);
 
@@ -420,7 +494,7 @@
 
       if(ei.entry == null)
       {
-         return new FileInputStream(rootFile); 
+         return zipFile.getRootAsStream(); 
       }
       
       return zipFile.openStream(ei.entry);
@@ -442,8 +516,6 @@
       try
       {
          zipFile.close();
-         if (autoClean)
-            rootFile.delete();
       }
       catch (Exception ex)
       {
@@ -548,6 +620,43 @@
    //   Helper methods
    //
 
+
+
+   /**
+    * Copy input stream to output stream and close them both
+    * @param is
+    * @param os
+    * @throws IOException
+    */
+   static void copyStreamAndClose(InputStream is, OutputStream os) throws IOException
+   {
+      try
+      {
+         byte [] buff = new byte[65536];
+         int count = is.read(buff);
+         while(count != -1)
+         {
+            os.write(buff, 0, count);
+            count = is.read(buff);
+         }
+      }
+      finally
+      {
+         if(is != null)
+         {
+            try {
+               is.close();
+            }
+            catch(Exception ex)
+            {
+               // ignore
+            }
+         }
+         os.close();
+      }
+   }
+
+
    private static URL fixUrl(URL rootURL) throws MalformedURLException
    {
       if (!"vfszip".equals(rootURL.getProtocol()))
@@ -593,33 +702,6 @@
       return ret;
    }
 
-   private static void copyStreamAndClose(InputStream is, OutputStream os) throws IOException
-   {
-      try
-      {
-         byte [] buff = new byte[65536];
-         int count = is.read(buff);
-         while(count != -1)
-         {
-            os.write(buff, 0, count);
-            count = is.read(buff);
-         }
-      }
-      finally
-      {
-         if(is != null)
-         {
-            try {
-               is.close();
-            }
-            catch(Exception ex)
-            {
-               // ignore
-            }
-         }
-         os.close();
-      }
-   }
 
 
    // TODO: the following two methods are a quick and dirty strategy for temp file name and path
@@ -657,4 +739,13 @@
 
    }
 
+
+   private static class CheckForceCopy implements PrivilegedAction<Boolean>
+   {
+      public Boolean run()
+      {
+         String forceString = System.getProperty(VFSUtils.FORCE_COPY_KEY, "false");
+         return Boolean.valueOf(forceString);
+      }
+   }
 }

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-05-29 23:28:29 UTC (rev 73825)
+++ projects/vfs/branches/jar-alter-work/src/main/java/org/jboss/virtual/plugins/context/zip/ZipFileLockReaper.java	2008-05-30 00:08:06 UTC (rev 73826)
@@ -139,7 +139,7 @@
                catch(Exception ex)
                {
                   // ignore the exception
-                  log.debug("Failed to close ZipFile: ", ex);
+                  log.debug("IGNORING: Failed to close ZipFile: ", ex);
                }
             }
          }

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-05-29 23:28:29 UTC (rev 73825)
+++ projects/vfs/branches/jar-alter-work/src/main/java/org/jboss/virtual/plugins/context/zip/ZipFileWrapper.java	2008-05-30 00:08:06 UTC (rev 73826)
@@ -1,12 +1,21 @@
 package org.jboss.virtual.plugins.context.zip;
 
 import org.jboss.logging.Logger;
+import org.jboss.virtual.VFSUtils;
 
 import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.InputStream;
+import java.net.URI;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.Enumeration;
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipFile;
+
+
 /**
  * ZipFileWrapper releases and reacquires an underlying ZipFile as necessary
  *
@@ -14,47 +23,55 @@
  * @version $Revision: 1.0 $
  */
 
-public class ZipFileWrapper
+class ZipFileWrapper extends ZipWrapper
 {
    private static final Logger log = Logger.getLogger(ZipFileWrapper.class);
 
-   private File file;
 
-   private ZipFile zipFile;
+   private static boolean forceNoReaper;
 
-   private long lastUsed;
+   static
+   {
+      forceNoReaper = AccessController.doPrivileged(new CheckNoReaper());
 
-   private long lastModified;
+      if (forceNoReaper)
+         log.info("VFS forced no-reaper-mode is enabled.");
 
-   private long lastChecked;
+   }
 
-   private int refCount = 0;
 
+   private File file;
+
+   private ZipFile zipFile;
+
+   private boolean autoClean;
+
    // used for debugging stream leaks
    //ConcurrentLinkedQueue<ZipEntryInputStream> streams = new ConcurrentLinkedQueue<ZipEntryInputStream>();
 
 
-   public ZipFileWrapper(File archive)
+   ZipFileWrapper(File archive, boolean autoClean)
    {
-      file = archive;
-      lastModified = file.lastModified();
+      init(archive, autoClean);
    }
 
-   boolean hasBeenModified()
+
+   ZipFileWrapper(URI rootPathURI, boolean autoClean)
    {
-      long now = System.currentTimeMillis();
-      if (now - lastChecked < 1000)
-         return false;
+      File rootFile = new File(rootPathURI);
+      if(!rootFile.isFile())
+         throw new RuntimeException("File not found: " + rootFile);
 
-      lastChecked = now;
-      long lm = file.lastModified();
-      if (lm != lastModified)
-      {
-         lastModified = lm;
-         return true;
-      }
+      init(rootFile, autoClean);
+   }
 
-      return false;
+   private void init(File archive, boolean autoClean)
+   {
+      file = archive;
+      lastModified = file.lastModified();
+      this.autoClean = autoClean;
+      if (autoClean)
+         file.deleteOnExit();
    }
 
    boolean exists()
@@ -62,22 +79,28 @@
       return file.isFile();
    }
 
-   long getLastUsed()
+   long getLastModified()
    {
-      return lastUsed;
+      return file.lastModified();
    }
 
-   int getReferenceCount()
+   String getName()
    {
-      return refCount;
+      return file.getName();
    }
 
+   long getSize()
+   {
+      return file.length();
+   }
+
    private ZipFile ensureZipFile() throws IOException
    {
       if (zipFile == null)
       {
          zipFile = new ZipFile(file);
-         ZipFileLockReaper.getInstance().register(this);
+         if (forceNoReaper == false)
+            ZipFileLockReaper.getInstance().register(this);
       }
 
       return zipFile;
@@ -85,16 +108,17 @@
 
    synchronized void closeZipFile() throws IOException
    {
-      if (zipFile != null && refCount <= 0)
+      if (zipFile != null && getReferenceCount() <= 0)
       {
          ZipFile zf = zipFile;
          zipFile = null;
          zf.close();
-         ZipFileLockReaper.getInstance().unregister(this);
+         if (forceNoReaper == false)
+            ZipFileLockReaper.getInstance().unregister(this);
       }
    }
 
-   synchronized ZipEntryInputStream openStream(ZipEntry ent) throws IOException
+   synchronized InputStream openStream(ZipEntry ent) throws IOException
    {
       ensureZipFile();
       InputStream is = zipFile.getInputStream(ent);
@@ -103,35 +127,39 @@
       // debugging code
       //streams.add(zis);
 
-      refCount++;
-      lastUsed = System.currentTimeMillis();
+      incrementRef();
       return zis;
    }
 
 
-   synchronized void release()
+   InputStream getRootAsStream() throws FileNotFoundException
    {
-      refCount--;
-      if (refCount <= 0)
-      {
+      return new FileInputStream(file);
+   }
+
+
+   synchronized void acquire() throws IOException
+   {
+      ensureZipFile();
+      incrementRef();
+   }
+
+   synchronized void release() {
+      super.release();
+      if (forceNoReaper)
          try
          {
-            lastUsed = System.currentTimeMillis();
-            // let the reaper do its job
-            //closeZipFile();
+            closeZipFile();
          }
          catch(Exception ex)
          {
             log.warn("Failed to release file: " + file);
          }
-      }
    }
 
-   synchronized ZipFile acquire() throws IOException
+   synchronized Enumeration<? extends ZipEntry> entries() throws IOException
    {
-      ZipFile ret = ensureZipFile();
-      refCount++;
-      return ret;
+      return ensureZipFile().entries();
    }
 
    void close()
@@ -142,12 +170,25 @@
       }
       catch(Exception ex)
       {
-         log.warn("Failed to release file: " + file);
+         log.warn("IGNORING: Failed to release file: " + file, ex);
       }
+
+      if (autoClean)
+         file.delete();
    }
 
    public String toString()
    {
       return super.toString() + " - " + file.getAbsolutePath();
    }
+
+
+   private static class CheckNoReaper implements PrivilegedAction<Boolean>
+   {
+      public Boolean run()
+      {
+         String forceString = System.getProperty(VFSUtils.FORCE_NO_REAPER_KEY, "false");
+         return Boolean.valueOf(forceString);
+      }
+   }
 }

Added: 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	                        (rev 0)
+++ projects/vfs/branches/jar-alter-work/src/main/java/org/jboss/virtual/plugins/context/zip/ZipStreamWrapper.java	2008-05-30 00:08:06 UTC (rev 73826)
@@ -0,0 +1,142 @@
+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
+ *
+ * @author <a href="strukelj at parsek.net">Marko Strukelj</a>
+ * @version $Revision: 1.0 $
+ */
+class ZipStreamWrapper extends ZipWrapper
+{
+   /** Raw zip archive loaded in memory */
+   private byte [] zipBytes;
+
+   /** Name of an underlying file */
+   private String name;
+
+   /**
+    * @param zipStream
+    * @param lastModified passed by zip stream provider. We're not aware of zip source so we can not detect it was changed
+    * @throws IOException
+    */
+   ZipStreamWrapper(InputStream zipStream, String name, long lastModified) throws IOException
+   {
+      // read the contents into memory buffer
+      ByteArrayOutputStream bout = new ByteArrayOutputStream();
+      ZipEntryContext.copyStreamAndClose(zipStream, bout);
+      zipBytes = bout.toByteArray();
+
+      // TODO - delegate file meta info operations to parent?
+      this.name = name;
+      this.lastModified = lastModified;
+   }
+
+   boolean exists()
+   {
+      return true;
+   }
+
+   long getLastModified()
+   {
+      return lastModified;
+   }
+
+   String getName()
+   {
+      return name;
+   }
+
+   long getSize()
+   {
+      return zipBytes.length;
+   }
+
+   InputStream openStream(ZipEntry ent) throws IOException
+   {
+      ZipInputStream zis = new ZipInputStream(new ByteArrayInputStream(zipBytes));
+
+      // first find the entry
+      ZipEntry entry = zis.getNextEntry();
+      while(entry != null)
+      {
+         if(entry.getName().equals(ent.getName()))
+            break;
+         entry = zis.getNextEntry();
+      }
+      if(entry == null)
+         throw new IOException("Failed to find nested jar entry: " + ent.getName() + " in zip stream: " + this.name);
+
+
+      // now read it
+      return new SizeLimitedInputStream(zis, (int) entry.getSize());
+   }
+
+   InputStream getRootAsStream() throws FileNotFoundException
+   {
+      return new ByteArrayInputStream(zipBytes);
+   }
+
+   void acquire() throws IOException
+   {
+   }
+
+   Enumeration<? extends ZipEntry> entries() throws IOException
+   {
+      return new ZipStreamEnumeration(new ZipInputStream(new ByteArrayInputStream(zipBytes)));
+   }
+
+
+
+   void close()
+   {
+      zipBytes = null;
+   }
+
+   public String toString()
+   {
+      return super.toString() + " - " + name;
+   }
+
+
+
+   class ZipStreamEnumeration implements Enumeration
+   {
+      private ZipInputStream zis;
+
+      private ZipEntry entry;
+
+      ZipStreamEnumeration(ZipInputStream zis) throws IOException
+      {
+         this.zis = zis;
+         entry = zis.getNextEntry();
+      }
+
+      public boolean hasMoreElements()
+      {
+         return entry != null;
+      }
+
+      public Object nextElement()
+      {
+         Object ret = entry;
+         try
+         {
+            entry = zis.getNextEntry();
+         }
+         catch (IOException ex)
+         {
+            throw new RuntimeException("Failed to retrieve next entry from zip stream", ex);
+         }
+
+         return ret;
+      }
+   }
+
+}

Added: 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	                        (rev 0)
+++ projects/vfs/branches/jar-alter-work/src/main/java/org/jboss/virtual/plugins/context/zip/ZipWrapper.java	2008-05-30 00:08:06 UTC (rev 73826)
@@ -0,0 +1,92 @@
+package org.jboss.virtual.plugins.context.zip;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.FileNotFoundException;
+import java.util.zip.ZipEntry;
+import java.util.Enumeration;
+
+/**
+ * ZipWrapper represents abstracted access to zip resource
+ *
+ * @author <a href="strukelj at parsek.net">Marko Strukelj</a>
+ * @version $Revision: 1.0 $
+ */
+
+abstract class ZipWrapper
+{
+
+   protected long lastModified;
+
+   protected long lastChecked;
+
+   private long lastUsed;
+
+   private int refCount = 0;
+
+
+
+   
+   boolean hasBeenModified()
+   {
+      long now = System.currentTimeMillis();
+      if (now - lastChecked < 1000)
+         return false;
+
+      lastChecked = now;
+      long lm = getLastModified();
+      if (lm != lastModified)
+      {
+         lastModified = lm;
+         return true;
+      }
+
+      return false;
+   }
+
+   long getLastUsed()
+   {
+      return lastUsed;
+   }
+
+
+   int getReferenceCount()
+   {
+      return refCount;
+   }
+
+   void incrementRef()
+   {
+      refCount++;
+      lastUsed = System.currentTimeMillis();
+   }
+
+
+   abstract void acquire() throws IOException;
+
+   synchronized void release()
+   {
+      refCount--;
+      if (refCount <= 0)
+      {
+         lastUsed = System.currentTimeMillis();
+      }
+   }
+
+
+   abstract long getLastModified();
+
+   abstract String getName();
+
+   abstract boolean exists();
+
+   abstract long getSize();
+   
+   abstract Enumeration<? extends ZipEntry> entries() throws IOException;
+
+   abstract InputStream openStream(ZipEntry ent) throws IOException;
+
+   abstract InputStream getRootAsStream() throws FileNotFoundException;
+
+   abstract void close();
+}

Modified: projects/vfs/branches/jar-alter-work/src/test/java/org/jboss/test/virtual/test/FileVFSUnitTestCase.java
===================================================================
--- projects/vfs/branches/jar-alter-work/src/test/java/org/jboss/test/virtual/test/FileVFSUnitTestCase.java	2008-05-29 23:28:29 UTC (rev 73825)
+++ projects/vfs/branches/jar-alter-work/src/test/java/org/jboss/test/virtual/test/FileVFSUnitTestCase.java	2008-05-30 00:08:06 UTC (rev 73826)
@@ -1244,7 +1244,7 @@
       assertNotNull("tstjar != null", tstjar);
       URI uri = tstjar.toURI();
       URI expectedURI = new URI("vfs"+rootURL.toString()+"/path%20with%20spaces/tst.jar");
-      assertEquals(uri, expectedURI);
+      assertEquals(uri.getPath(), expectedURI.getPath());
    }
 
    public static void main(String[] args) throws Exception




More information about the jboss-cvs-commits mailing list