[jboss-cvs] JBossAS SVN: r76996 - in projects/vfs/trunk/src: main/java/org/jboss/virtual/plugins/context/zip and 1 other directories.

jboss-cvs-commits at lists.jboss.org jboss-cvs-commits at lists.jboss.org
Tue Aug 12 16:51:05 EDT 2008


Author: mstruk
Date: 2008-08-12 16:51:05 -0400 (Tue, 12 Aug 2008)
New Revision: 76996

Modified:
   projects/vfs/trunk/src/main/java/org/jboss/virtual/plugins/context/AbstractVFSContext.java
   projects/vfs/trunk/src/main/java/org/jboss/virtual/plugins/context/AbstractVirtualFileHandler.java
   projects/vfs/trunk/src/main/java/org/jboss/virtual/plugins/context/zip/ZipEntryContext.java
   projects/vfs/trunk/src/main/java/org/jboss/virtual/plugins/context/zip/ZipEntryHandler.java
   projects/vfs/trunk/src/test/java/org/jboss/test/virtual/test/ZipEntryVFSContextUnitTestCase.java
Log:
JBVFS-51 Lazy initialization of zip archive content to improve performance

Modified: projects/vfs/trunk/src/main/java/org/jboss/virtual/plugins/context/AbstractVFSContext.java
===================================================================
--- projects/vfs/trunk/src/main/java/org/jboss/virtual/plugins/context/AbstractVFSContext.java	2008-08-12 18:29:31 UTC (rev 76995)
+++ projects/vfs/trunk/src/main/java/org/jboss/virtual/plugins/context/AbstractVFSContext.java	2008-08-12 20:51:05 UTC (rev 76996)
@@ -164,23 +164,56 @@
       return parent.getChild(path);
    }
 
+   /**
+    * Construct a URL from a given parent and a name
+    *
+    * @param parent a parent
+    * @param name a name of the child
+    * @return URL corresponding to a child
+    * @throws IOException for any error
+    */
    public URL getChildURL(VirtualFileHandler parent, String name) throws IOException
-   {
-      StringBuilder urlStr = new StringBuilder(256);
+   {      
+      if(parent != null)
+      {
+         VFSContext parentCtx = parent.getVFSContext();
+         if (parentCtx != this)
+         {
+            if (parentCtx instanceof AbstractVFSContext)
+            {
+               return ((AbstractVFSContext) parentCtx).getChildURL(parent, name);
+            }
+            else
+            {
+               StringBuilder urlStr = new StringBuilder(512);
+               try
+               {
+                  urlStr.append(parent.toURI());
+                  if (urlStr.charAt( urlStr.length()-1) != '/')
+                     urlStr.append("/");
+
+                  urlStr.append(name);
+                  return new URL(urlStr.toString());
+               }
+               catch (URISyntaxException e)
+               {
+                  throw new RuntimeException("Failed to create child URL: " + parent + " + " + name, e);
+               }
+            }
+         }
+      }
+
+      StringBuilder urlStr = new StringBuilder(512);
       URI rootUri = getRootURI();
       urlStr.append(rootUri.getScheme())
               .append(":").append(rootUri.getPath());
+
       if(parent != null)
       {
-         String pPathName;
-         if(parent instanceof AbstractVirtualFileHandler)
-            pPathName = parent.getLocalPathName();
-         else
-            pPathName = parent.getPathName();
-
          if (urlStr.charAt( urlStr.length()-1) != '/')
             urlStr.append("/");
 
+         String pPathName = parent.getPathName();         
          if(pPathName.length() != 0)
             urlStr.append(pPathName);
 

Modified: projects/vfs/trunk/src/main/java/org/jboss/virtual/plugins/context/AbstractVirtualFileHandler.java
===================================================================
--- projects/vfs/trunk/src/main/java/org/jboss/virtual/plugins/context/AbstractVirtualFileHandler.java	2008-08-12 18:29:31 UTC (rev 76995)
+++ projects/vfs/trunk/src/main/java/org/jboss/virtual/plugins/context/AbstractVirtualFileHandler.java	2008-08-12 20:51:05 UTC (rev 76996)
@@ -615,7 +615,7 @@
       buffer.append(System.identityHashCode(this));
       buffer.append("[path=").append(getLocalPathName());
       buffer.append(" context=").append(context.getRootURI());
-      buffer.append(" real=").append(safeToURLString());
+      //buffer.append(" real=").append(safeToURLString());
       buffer.append(']');
       return buffer.toString();
    }

Modified: projects/vfs/trunk/src/main/java/org/jboss/virtual/plugins/context/zip/ZipEntryContext.java
===================================================================
--- projects/vfs/trunk/src/main/java/org/jboss/virtual/plugins/context/zip/ZipEntryContext.java	2008-08-12 18:29:31 UTC (rev 76995)
+++ projects/vfs/trunk/src/main/java/org/jboss/virtual/plugins/context/zip/ZipEntryContext.java	2008-08-12 20:51:05 UTC (rev 76996)
@@ -118,6 +118,9 @@
    /** Registry of everything that zipSource contains */
    private Map<String, EntryInfo> entries = new ConcurrentHashMap<String, EntryInfo>();
 
+   /** Have zip entries been navigated yet */
+   private InitializationStatus initStatus = InitializationStatus.NOT_INITIALIZED;
+
    /**
     * Create a new ZipEntryContext
     *
@@ -220,15 +223,10 @@
       
       setRootPeer(peer);
 
-      String name = getRootURI().toString();
+      String name = getRootURI().getPath().toString();
 
-      // cut off query string
-      int toPos = name.lastIndexOf("?");
-      if (toPos != -1)
-         name = name.substring(0, toPos);
+      int toPos = name.length();
 
-      toPos = name.length();
-
       // cut off any ending slash
       if(name.length() != 0 && name.charAt(name.length()-1) == '/')
          toPos --;
@@ -245,7 +243,8 @@
       // if zip entry exists for rootEntryPath
       entries.put("", new EntryInfo(new ZipEntryHandler(this, null, name, true), null));
 
-      initEntries();
+      // It's lazy init now
+      //initEntries();
    }
 
    /**
@@ -476,6 +475,32 @@
    }
 
    /**
+    * Perform initialization only if it hasn't been done yet
+    */
+   private synchronized void ensureEntries()
+   {
+      if (initStatus != InitializationStatus.NOT_INITIALIZED)
+         return;
+
+      try
+      {
+         initStatus = InitializationStatus.INITIALIZING;
+         initEntries();
+         initStatus = InitializationStatus.INITIALIZED;
+      }
+      catch (Exception ex)
+      {
+         RuntimeException e = new RuntimeException("Failed to read zip file: " + zipSource, ex);
+         throw e;
+      }
+      finally
+      {
+         if (initStatus == InitializationStatus.INITIALIZING)
+            initStatus = InitializationStatus.NOT_INITIALIZED;
+      }
+   }
+
+   /**
     * Mount ZipEntryContext created around extracted nested archive
     *
     * @param parent the parent
@@ -586,13 +611,18 @@
    }
 
    /**
-    * If archive has been modified, clear <em>entries</em> and re-initialize
+    * If archive has been modified, clear <em>entries</em> and re-initialize.
+    * If not initialized yet, initialize it.
     */
    private synchronized void checkIfModified()
    {
       // TODO: if zipSource represents a nested archive we should maybe delegate lastModified to its parent
-      if (zipSource.hasBeenModified())
+      if (initStatus == InitializationStatus.NOT_INITIALIZED)
       {
+         ensureEntries();
+      }
+      else if (initStatus == InitializationStatus.INITIALIZED && zipSource.hasBeenModified())
+      {
          EntryInfo rootInfo = entries.get("");
          entries = new ConcurrentHashMap<String, EntryInfo>();
          entries.put("", rootInfo);
@@ -617,7 +647,7 @@
     * @return root handler
     * @throws IOException for any error
     */
-   public VirtualFileHandler getRoot() throws IOException
+   public VirtualFileHandler getRoot()
    {
       return entries.get("").handler;
    }
@@ -635,6 +665,7 @@
          throw new IllegalArgumentException("Null parent");
 
       checkIfModified();
+
       String pathName = parent.getLocalPathName();
       if("".equals(pathName))
          pathName = name;
@@ -642,7 +673,6 @@
          pathName = pathName + "/" + name;
 
       EntryInfo ei = entries.get(pathName);
-      
       if(ei != null)
          return ei.handler;
 
@@ -698,7 +728,8 @@
       if (handler == null)
          throw new IllegalArgumentException("Null handler");
 
-      checkIfModified();
+      if (getRoot().equals(handler) == false)
+         checkIfModified();
       EntryInfo ei = entries.get(handler.getLocalPathName());
       if(ei == null)
          return 0;
@@ -721,20 +752,15 @@
       if (handler == null)
          throw new IllegalArgumentException("Null handler");
 
+      if(getRoot().equals(handler))
+         return zipSource.getSize();
+
       checkIfModified();
-      String pathName = handler.getLocalPathName();
-      EntryInfo ei = entries.get(pathName);
-      if(ei == null)
+
+      EntryInfo ei = entries.get(handler.getLocalPathName());
+      if(ei == null || ei.entry == null)
          return 0;
 
-      if(ei.entry == null)
-      {
-         if(pathName.length() == 0)
-            return zipSource.getSize();
-         else
-            return 0;
-      }
-
       return ei.entry.getSize();
    }
 
@@ -749,15 +775,14 @@
       if (handler == null)
          throw new IllegalArgumentException("Null handler");
 
+      if (getRoot().equals(handler))
+         return zipSource.exists();
+
       checkIfModified();
-      String pathName = handler.getLocalPathName();
-      EntryInfo ei = entries.get(pathName);
+      EntryInfo ei = entries.get(handler.getLocalPathName());
       if(ei == null)
          return false;
 
-      if (ei.entry == null && pathName.length() == 0)
-         return zipSource.exists();
-
       return true;
    }
 
@@ -772,9 +797,11 @@
       if (handler == null)
          throw new IllegalArgumentException("Null handler");
 
-      checkIfModified();
+      if (getRoot().equals(handler) == false)
+         checkIfModified();
+      
       EntryInfo ei = entries.get(handler.getLocalPathName());
-      if(ei == null || ei.entry == null)
+      if (ei == null || ei.entry == null)
          return false;
 
       return !ei.entry.isDirectory();
@@ -852,10 +879,12 @@
       if (handler == null)
          throw new IllegalArgumentException("Null handler");
 
+      if (getRoot().equals(handler))
+         return zipSource.getRootAsStream();
+
       checkIfModified();
 
-      String localPathName = handler.getLocalPathName();
-      EntryInfo ei = entries.get(localPathName);
+      EntryInfo ei = entries.get(handler.getLocalPathName());
 
       if (ei == null)
       {
@@ -872,13 +901,8 @@
       }
 
       if(ei.entry == null)
-      {
-         if ("".equals(localPathName))  // root
-            return zipSource.getRootAsStream();
-         else                           // directory
-            return new ByteArrayInputStream(new byte[0]);
-      }
-      
+         return new ByteArrayInputStream(new byte[0]);
+
       return zipSource.openStream(ei.entry);
    }
 
@@ -929,6 +953,7 @@
     */
    public void replaceChild(ZipEntryHandler parent, AbstractVirtualFileHandler original, VirtualFileHandler replacement)
    {
+      ensureEntries();
       EntryInfo parentEntry = entries.get(parent.getLocalPathName());
       if (parentEntry != null)
       {
@@ -1189,4 +1214,10 @@
          return Boolean.valueOf(forceString);
       }
    }
+
+   static enum InitializationStatus {
+      NOT_INITIALIZED,
+      INITIALIZING,
+      INITIALIZED
+   }
 }

Modified: projects/vfs/trunk/src/main/java/org/jboss/virtual/plugins/context/zip/ZipEntryHandler.java
===================================================================
--- projects/vfs/trunk/src/main/java/org/jboss/virtual/plugins/context/zip/ZipEntryHandler.java	2008-08-12 18:29:31 UTC (rev 76995)
+++ projects/vfs/trunk/src/main/java/org/jboss/virtual/plugins/context/zip/ZipEntryHandler.java	2008-08-12 20:51:05 UTC (rev 76996)
@@ -43,8 +43,14 @@
 public class ZipEntryHandler extends AbstractVirtualFileHandler implements StructuredVirtualFileHandler
 {
    /** The url */
-   private final URL url;
+   private URL url;
 
+   /** isLeaf */
+   private boolean isLeaf;
+
+   /** has it been initialized yet */
+   transient private boolean initialized;
+
    /**
     * Create a new ZipEntryHandler.
     *
@@ -58,31 +64,40 @@
    {
       super(context, parent, name);
 
-      url = context.getChildURL(parent, name);
+      this.isLeaf = isLeaf;
+      if(parent != null)
+      {
+         context.addChild(parent, this);
+      }
+   }
 
-      String currentUrl = url.toString();
-      int pos = currentUrl.indexOf(":/");
+   private synchronized void init()
+   {
+      if (initialized)
+         return;
+
       StringBuilder vfsUrl = new StringBuilder();
-      vfsUrl.append("vfszip:").append(currentUrl.substring(pos+1));
       try
       {
+         url = getZipEntryContext().getChildURL(getParent(), getName());
+         String currentUrl = url.toString();
+         int pos = currentUrl.indexOf(":/");
+         vfsUrl.append("vfszip:").append(currentUrl.substring(pos+1));
+
          if (isLeaf == false && vfsUrl.charAt(vfsUrl.length()-1) != '/')
             vfsUrl.append("/");
          setVfsUrl(new URL(vfsUrl.toString()));
       }
-      catch(MalformedURLException ex)
+      catch(Exception ex)
       {
          throw new RuntimeException("ASSERTION ERROR - failed to set vfsUrl: " + vfsUrl, ex );
       }
-
-      if(parent != null)
-      {
-         context.addChild(parent, this);
-      }
+      initialized = true;
    }
 
    public URI toURI() throws URISyntaxException
    {
+      init();
       return VFSUtils.toURI(url);
    }
 
@@ -171,4 +186,10 @@
    {
       return ((ZipEntryContext) getLocalVFSContext());
    }
+
+   public URL toVfsUrl()
+   {
+      init();
+      return super.getVfsUrl();
+   }
 }

Modified: projects/vfs/trunk/src/test/java/org/jboss/test/virtual/test/ZipEntryVFSContextUnitTestCase.java
===================================================================
--- projects/vfs/trunk/src/test/java/org/jboss/test/virtual/test/ZipEntryVFSContextUnitTestCase.java	2008-08-12 18:29:31 UTC (rev 76995)
+++ projects/vfs/trunk/src/test/java/org/jboss/test/virtual/test/ZipEntryVFSContextUnitTestCase.java	2008-08-12 20:51:05 UTC (rev 76996)
@@ -21,6 +21,7 @@
 */
 package org.jboss.test.virtual.test;
 
+import java.io.ByteArrayOutputStream;
 import java.io.File;
 import java.io.FileOutputStream;
 import java.io.InputStream;
@@ -29,6 +30,7 @@
 
 import junit.framework.Test;
 import org.jboss.virtual.VFS;
+import org.jboss.virtual.VFSUtils;
 import org.jboss.virtual.plugins.context.file.FileSystemContext;
 import org.jboss.virtual.plugins.context.jar.JarUtils;
 import org.jboss.virtual.plugins.context.zip.ZipEntryContext;
@@ -79,16 +81,8 @@
 
       InputStream is = url.openStream();
       OutputStream os = new FileOutputStream(tmpJar);
+      VFSUtils.copyStreamAndClose(is, os);
 
-      byte [] buff = new byte[65536];
-      int count = is.read(buff);
-      while(count != -1)
-      {
-         os.write(buff, 0, count);
-         count = is.read(buff);
-      }
-      os.close();
-
       ZipEntryContext context = new ZipEntryContext(tmpJar.toURL());
       assertTrue("context.getRoot().exists()", context.getRoot().exists());
 
@@ -109,13 +103,52 @@
       URL url = getResource("/vfs/context/jar/");
       FileSystemContext ctx = new FileSystemContext(url);
 
-      // check that vfszip is active
+      // we just do basic sanity checks
+
+      // valid archive
+
       VirtualFileHandler handler = ctx.getRoot().getChild("archive.jar");
-      assertTrue("is vfszip", "vfszip".equals(handler.toURL().getProtocol()));
+      //assertTrue("is vfszip", "vfszip".equals(handler.toURL().getProtocol()));
       assertFalse("is leaf", handler.isLeaf());
+      assertTrue("exists", handler.exists());
+      assertNotNull("pathName not null", handler.getPathName());
+      assertNotNull("name not null", handler.getName());
+      assertNotNull("parent not null", handler.getParent());
+      assertTrue("lastModified > 0", handler.getLastModified() > 0);
+      assertTrue("size > 0", handler.getSize() > 0);
+      assertNotNull("VF not null", handler.getVirtualFile());
+      assertFalse("hasBeenModified == false", handler.hasBeenModified());
+      assertFalse("hidden == false", handler.isHidden());
+      assertFalse("nested == false", handler.isNested());
+      assertNotNull("toURI not null", handler.toURI());
+      assertNotNull("toURL not null", handler.toURL());
+      assertNotNull("toVfsUrl not null", handler.toVfsUrl());
 
+      ByteArrayOutputStream memOut = new ByteArrayOutputStream();
+      VFSUtils.copyStreamAndClose(handler.openStream(), memOut);
+      assertTrue("read archive content", memOut.size() == handler.getSize());
+
+      // invalid archive
+
       handler = ctx.getRoot().getChild("notanarchive.jar");
-      assertTrue("is leaf", handler.isLeaf());
+      //assertTrue("is leaf", handler.isLeaf());
+      assertTrue("exists", handler.exists());
+      assertTrue("lastModified > 0", handler.getLastModified() > 0);
+      assertNotNull("pathName not null", handler.getPathName());
+      assertNotNull("name not null", handler.getName());
+      assertNotNull("parent not null", handler.getParent());
+      assertTrue("size > 0", handler.getSize() > 0);
+      assertNotNull("VF not null", handler.getVirtualFile());
+      assertFalse("hasBeenModified == false", handler.hasBeenModified());
+      assertFalse("hidden == false", handler.isHidden());
+      assertFalse("nested == false", handler.isNested());
+      assertNotNull("toURI not null", handler.toURI());
+      assertNotNull("toURL not null", handler.toURL());
+      assertNotNull("toVfsUrl not null", handler.toVfsUrl());
+
+      memOut = new ByteArrayOutputStream();
+      VFSUtils.copyStreamAndClose(handler.openStream(), memOut);
+      assertTrue("read archive content", memOut.size() == handler.getSize());
    }
 
    // we need to make sure this doesn't get touched before




More information about the jboss-cvs-commits mailing list