[jboss-cvs] JBossAS SVN: r97658 - in projects/jboss-deployers/branches/vfs3/deployers-vfs/src: main/java/org/jboss/deployers/vfs/plugins/structure/jar and 1 other directories.

jboss-cvs-commits at lists.jboss.org jboss-cvs-commits at lists.jboss.org
Wed Dec 9 21:48:22 EST 2009


Author: johnbailey
Date: 2009-12-09 21:48:22 -0500 (Wed, 09 Dec 2009)
New Revision: 97658

Added:
   projects/jboss-deployers/branches/vfs3/deployers-vfs/src/main/java/org/jboss/deployers/vfs/plugins/structure/VFSHandleRegistry.java
   projects/jboss-deployers/branches/vfs3/deployers-vfs/src/test/java/org/jboss/test/deployers/vfs/structure/VFSHandleRegistryTest.java
Modified:
   projects/jboss-deployers/branches/vfs3/deployers-vfs/src/main/java/org/jboss/deployers/vfs/plugins/structure/AbstractVFSDeploymentContext.java
   projects/jboss-deployers/branches/vfs3/deployers-vfs/src/main/java/org/jboss/deployers/vfs/plugins/structure/jar/JARStructure.java
Log:
[JBAS-7362] Introduced basic VFS Handle Registry for managing and cleaning up mount handles

Modified: projects/jboss-deployers/branches/vfs3/deployers-vfs/src/main/java/org/jboss/deployers/vfs/plugins/structure/AbstractVFSDeploymentContext.java
===================================================================
--- projects/jboss-deployers/branches/vfs3/deployers-vfs/src/main/java/org/jboss/deployers/vfs/plugins/structure/AbstractVFSDeploymentContext.java	2009-12-10 02:37:38 UTC (rev 97657)
+++ projects/jboss-deployers/branches/vfs3/deployers-vfs/src/main/java/org/jboss/deployers/vfs/plugins/structure/AbstractVFSDeploymentContext.java	2009-12-10 02:48:22 UTC (rev 97658)
@@ -451,6 +451,16 @@
    {
       return new AbstractVFSDeploymentUnit(this);
    }
+   
+   @Override
+   public void cleanup()
+   {
+      if(VFSHandleRegistry.isMounted(root)) 
+      {
+         VFSHandleRegistry.cleanup(root);
+      }
+      super.cleanup();
+   }
 
    @SuppressWarnings("unchecked")
    public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException

Added: projects/jboss-deployers/branches/vfs3/deployers-vfs/src/main/java/org/jboss/deployers/vfs/plugins/structure/VFSHandleRegistry.java
===================================================================
--- projects/jboss-deployers/branches/vfs3/deployers-vfs/src/main/java/org/jboss/deployers/vfs/plugins/structure/VFSHandleRegistry.java	                        (rev 0)
+++ projects/jboss-deployers/branches/vfs3/deployers-vfs/src/main/java/org/jboss/deployers/vfs/plugins/structure/VFSHandleRegistry.java	2009-12-10 02:48:22 UTC (rev 97658)
@@ -0,0 +1,233 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2009, 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.deployers.vfs.plugins.structure;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.Executors;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.jboss.vfs.TempFileProvider;
+import org.jboss.vfs.VFS;
+import org.jboss.vfs.VFSUtils;
+import org.jboss.vfs.VirtualFile;
+import org.jboss.vfs.util.PathTokenizer;
+
+/**
+ * Registry used to manage handles to mounted Virtual FileSystems.  
+ *  
+ * @author <a href="jbailey at redhat.com">John Bailey</a>
+ */
+public class VFSHandleRegistry
+{
+   /*
+    * Simple handle with no side effects. 
+    */
+   private static final Closeable NO_OP_HANDLE = new Closeable()
+   {
+      public void close() throws IOException
+      {
+      }
+   };
+
+   /* Root entry in the tree. */
+   private static final RegistryEntry rootEntry = new RegistryEntry();
+
+   /**
+    * Private constructor
+    */
+   private VFSHandleRegistry()
+   {
+   }
+
+   /** 
+    * Determine if the provided {@link VirtualFile} has been mounted.
+    */
+   public static boolean isMounted(VirtualFile virtualFile)
+   {
+      return getEntry(virtualFile).isMounted();
+   }
+
+   /**
+    * Add a registry entry for the provided {@link VirtualFile} and attache the handle
+    * 
+    * @param virtualFile
+    * @param handle
+    */
+   public static void addHandle(VirtualFile virtualFile, Closeable handle)
+   {
+      getEntry(virtualFile).setHandle(handle);
+   }
+
+   /**
+    * Get a handle for the provided {@link VirtualFile}.  If the entry is already mounted
+    * a the reference count will be incremented and a a handle will be returned.  If the entry 
+    * is not mounted, the entry will be mounted based on they type of {@link VirtualFile} provided. 
+    * Files will be mounted as a Zip archive, and directories will register a no-op handle.  
+    *  
+    * @param virtualFile
+    * @return a handle to the {@link VirtualFile}
+    * @throws IOException
+    */
+   public static Closeable getHandleFor(VirtualFile virtualFile) throws IOException
+   {
+      RegistryEntry entry = getEntry(virtualFile);
+      if (!entry.isMounted())
+      {
+         Closeable handle = null;
+         if (virtualFile.isFile())
+         {
+            handle = VFS.mountZip(virtualFile, virtualFile, getTempFileProvider(virtualFile.getName()));
+         }
+         else
+         {
+            handle = NO_OP_HANDLE;
+         }
+         addHandle(virtualFile, handle);
+      }
+      return entry.aquireReference();
+   }
+
+   /**
+    * Recursively cleanup all mounted handles starting at the provided {@link VirtualFile} location.
+    * 
+    * @param virtualFile
+    */
+   public static void cleanup(VirtualFile virtualFile)
+   {
+      RegistryEntry startEntry = getEntry(virtualFile);
+      Collection<RegistryEntry> entries = startEntry.getEntriesRecursive();
+      for (RegistryEntry entry : entries)
+      {
+         entry.cleanup();
+      }
+   }
+
+   /**
+    * Get the entry from the tree creating the entry if not present.
+    * 
+    * @param virtualFile
+    * @return
+    */
+   private static RegistryEntry getEntry(VirtualFile virtualFile)
+   {
+      if (virtualFile == null)
+      {
+         throw new IllegalArgumentException("A valid VirtualFile is required.");
+      }
+      return rootEntry.find(virtualFile);
+   }
+
+   private static TempFileProvider getTempFileProvider(String name) throws IOException
+   {
+      return TempFileProvider.create(name, Executors.newSingleThreadScheduledExecutor());
+   }
+
+   static class RegistryEntry
+   {
+      private final ConcurrentMap<String, RegistryEntry> children = new ConcurrentHashMap<String, RegistryEntry>();
+
+      private Closeable handle;
+
+      private final AtomicInteger refCount = new AtomicInteger();
+
+      Collection<RegistryEntry> getChildren()
+      {
+         return Collections.unmodifiableCollection(children.values());
+      }
+
+      RegistryEntry find(VirtualFile file)
+      {
+         return find(PathTokenizer.getTokens(file.getPathName()));
+      }
+
+      RegistryEntry find(List<String> path)
+      {
+         if (path.isEmpty())
+         {
+            return this;
+         }
+         String current = path.remove(0);
+         children.putIfAbsent(current, new RegistryEntry());
+         RegistryEntry childEntry = children.get(current);
+         return childEntry.find(path);
+      }
+
+      void setHandle(Closeable handle)
+      {
+         this.handle = handle;
+      }
+
+      void cleanup()
+      {
+         VFSUtils.safeClose(handle);
+         handle = null;
+         refCount.set(0);
+      }
+
+      boolean isMounted()
+      {
+         return handle != null;
+      }
+
+      Collection<RegistryEntry> getEntriesRecursive()
+      {
+         List<RegistryEntry> allHandles = new LinkedList<RegistryEntry>();
+         collectEntries(this, allHandles);
+         return allHandles;
+      }
+
+      void collectEntries(RegistryEntry registryEntry, List<RegistryEntry> entries)
+      {
+         for (RegistryEntry childEntry : registryEntry.getChildren())
+         {
+            collectEntries(childEntry, entries);
+         }
+         entries.add(registryEntry);
+      }
+
+      Closeable aquireReference()
+      {
+         refCount.incrementAndGet();
+         return new Reference();
+      }
+
+      class Reference implements Closeable
+      {
+         public void close() throws IOException
+         {
+            if (refCount.decrementAndGet() == 0)
+            {
+               cleanup();
+            }
+
+         }
+      }
+
+   }
+}

Modified: projects/jboss-deployers/branches/vfs3/deployers-vfs/src/main/java/org/jboss/deployers/vfs/plugins/structure/jar/JARStructure.java
===================================================================
--- projects/jboss-deployers/branches/vfs3/deployers-vfs/src/main/java/org/jboss/deployers/vfs/plugins/structure/jar/JARStructure.java	2009-12-10 02:37:38 UTC (rev 97657)
+++ projects/jboss-deployers/branches/vfs3/deployers-vfs/src/main/java/org/jboss/deployers/vfs/plugins/structure/jar/JARStructure.java	2009-12-10 02:48:22 UTC (rev 97658)
@@ -21,9 +21,11 @@
 */
 package org.jboss.deployers.vfs.plugins.structure.jar;
 
+import java.io.Closeable;
 import java.util.Set;
 import java.util.Collections;
 import java.util.HashSet;
+import java.util.concurrent.Executors;
 
 import org.jboss.beans.metadata.api.annotations.Install;
 import org.jboss.beans.metadata.api.annotations.Uninstall;
@@ -31,7 +33,11 @@
 import org.jboss.deployers.spi.deployer.matchers.JarExtensionProvider;
 import org.jboss.deployers.spi.structure.ContextInfo;
 import org.jboss.deployers.vfs.plugins.structure.AbstractVFSStructureDeployer;
+import org.jboss.deployers.vfs.plugins.structure.VFSHandleRegistry;
 import org.jboss.deployers.vfs.spi.structure.StructureContext;
+import org.jboss.vfs.TempFileProvider;
+import org.jboss.vfs.VFS;
+import org.jboss.vfs.VFSUtils;
 import org.jboss.vfs.VirtualFile;
 
 /**
@@ -101,27 +107,23 @@
          suffixes.remove(extension);
    }
 
-   private boolean isArchive(String name) {
-      int i = name.length() - 1;
-      for (;;) {
-         i = name.lastIndexOf('.', i);
-         if (i == -1) {
-            return false;
-         }
-         if (suffixes.contains(name.substring(i))) {
-            return true;
-         }
-      }
+   private boolean isArchive(String name)
+   {
+      int idx = name.lastIndexOf('.');
+      if (idx == -1)
+         return false;
+      return suffixes.contains(name.substring(idx).toLowerCase());
    }
 
    public boolean determineStructure(StructureContext structureContext) throws DeploymentException
    {
       ContextInfo context = null;
       VirtualFile file = structureContext.getFile();
+      Closeable handle = null;
+      boolean valid = true;
       try
       {
          boolean trace = log.isTraceEnabled();
-
          if (isLeaf(file) == false)
          {
             // For non top level directories that don't look like jars
@@ -155,6 +157,13 @@
          }
          else if (isArchive(file.getName()))
          {
+            if(!VFSHandleRegistry.isMounted(file)) 
+            {
+               // Need to mount the archive.
+               handle = VFS.mountZip(file, file, TempFileProvider.create(file.getName(), Executors.newSingleThreadScheduledExecutor()));
+               VFSHandleRegistry.addHandle(file, handle);
+            }
+            
             if (trace)
                log.trace("... ok - its an archive or at least pretending to be.");
          }
@@ -165,8 +174,6 @@
             return false;
          }
 
-         boolean valid = true;
-
          if (isSupportsCandidateAnnotations())
          {
             StructureContext parentContext = structureContext.getParentContext();
@@ -193,11 +200,19 @@
       }
       catch (Exception e)
       {
+         valid = false;
          // Remove the invalid context
          if(context != null)
             structureContext.removeChild(context);
 
          throw DeploymentException.rethrowAsDeploymentException("Error determining structure: " + file.getName(), e);
       }
+      finally 
+      {
+         if(!valid) 
+         {
+            VFSUtils.safeClose(handle);  
+         }
+      }
    }
 }

Added: projects/jboss-deployers/branches/vfs3/deployers-vfs/src/test/java/org/jboss/test/deployers/vfs/structure/VFSHandleRegistryTest.java
===================================================================
--- projects/jboss-deployers/branches/vfs3/deployers-vfs/src/test/java/org/jboss/test/deployers/vfs/structure/VFSHandleRegistryTest.java	                        (rev 0)
+++ projects/jboss-deployers/branches/vfs3/deployers-vfs/src/test/java/org/jboss/test/deployers/vfs/structure/VFSHandleRegistryTest.java	2009-12-10 02:48:22 UTC (rev 97658)
@@ -0,0 +1,187 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2009, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.test.deployers.vfs.structure;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.jboss.deployers.vfs.plugins.structure.VFSHandleRegistry;
+import org.jboss.test.BaseTestCase;
+import org.jboss.vfs.VFS;
+import org.jboss.vfs.VirtualFile;
+
+/**
+ * Test for {@link VFSHandleRegistry}  
+ *  
+ * @author <a href="jbailey at redhat.com">John Bailey</a>
+ */
+public class VFSHandleRegistryTest extends BaseTestCase
+{
+   private static final Closeable DEFAULT_NO_OP_HANDLE = createNoOpTestHandle();
+
+   public VFSHandleRegistryTest(String name)
+   {
+      super(name);
+   }
+
+   public void testRegister() throws Exception
+   {
+      VirtualFile virtualFile = VFS.getChild("test/path/test.ear");
+
+      VFSHandleRegistry.addHandle(virtualFile, DEFAULT_NO_OP_HANDLE);
+      assertTrue(VFSHandleRegistry.isMounted(virtualFile));
+   }
+
+   public void testCleanup() throws Exception
+   {
+      VirtualFile virtualFile = VFS.getChild("test/path/test.ear");
+      
+      TestHandle handle = createNoOpTestHandle();
+      
+      VFSHandleRegistry.addHandle(virtualFile, handle);
+      assertTrue(VFSHandleRegistry.isMounted(virtualFile));
+
+      VFSHandleRegistry.cleanup(virtualFile);
+      
+      assertTrue(handle.isClosed());
+      assertFalse(VFSHandleRegistry.isMounted(virtualFile));
+   }
+
+   public void testCleanupWithChildren() throws Exception
+   {
+      final List<Closeable> handles = new ArrayList<Closeable>();
+
+      Callback callback = new Callback()
+      {
+         public void call(TestHandle handle)
+         {
+            handles.add(handle);
+         }
+      };
+
+      TestHandle earHandle = createTestHandle(callback);
+
+      VirtualFile earVirtualFile = VFS.getChild("test/path/test.ear");
+      VFSHandleRegistry.addHandle(earVirtualFile, earHandle);
+
+      TestHandle warHandle = createTestHandle(callback);
+
+      VirtualFile warVirtualFile = VFS.getChild("test/path/test.ear/test.war");
+      VFSHandleRegistry.addHandle(warVirtualFile, warHandle);
+
+      TestHandle jarHandle = createTestHandle(callback);
+
+      VirtualFile jarVirtualFile = VFS.getChild("test/path/test.ear/test.war/WEB-INF/lib/test.jar");
+      VFSHandleRegistry.addHandle(jarVirtualFile, jarHandle);
+
+      assertFalse(jarHandle.isClosed());
+      assertFalse(warHandle.isClosed());
+      assertFalse(earHandle.isClosed());
+
+      VFSHandleRegistry.cleanup(earVirtualFile);
+
+      assertTrue(jarHandle.isClosed());
+      assertTrue(warHandle.isClosed());
+      assertTrue(earHandle.isClosed());
+
+      assertEquals(jarHandle, handles.get(0));
+      assertEquals(warHandle, handles.get(1));
+      assertEquals(earHandle, handles.get(2));
+   }
+
+   public void testReferenceCounting() throws Exception
+   {
+      VirtualFile virtualFile = VFS.getChild("test/path/test.jar");
+      Closeable handleOne = VFSHandleRegistry.getHandleFor(virtualFile);
+      assertTrue(VFSHandleRegistry.isMounted(virtualFile));
+      Closeable handleTwo = VFSHandleRegistry.getHandleFor(virtualFile);
+      handleOne.close();
+      assertTrue(VFSHandleRegistry.isMounted(virtualFile));
+      handleTwo.close();
+      assertFalse(VFSHandleRegistry.isMounted(virtualFile));
+   }
+   
+   public void testAutoMount() throws Exception {
+      VirtualFile file = getVirtualFile("/structure/jar/indirectory/archive.jar");
+      assertTrue(file.isFile());
+      Closeable handleOne = VFSHandleRegistry.getHandleFor(file);
+      assertTrue(VFSHandleRegistry.isMounted(file));
+      assertTrue(file.isDirectory());
+      handleOne.close();
+      assertTrue(file.isFile());
+   }
+
+   private static TestHandle createTestHandle(Callback callback)
+   {
+      return new TestHandle(callback);
+   }
+   
+   private static TestHandle createNoOpTestHandle()
+   {
+      return new TestHandle(new Callback()
+      {
+         public void call(TestHandle handle)
+         {
+            
+         }
+      });
+   }
+   
+   protected VirtualFile getVirtualFile(String path) throws Exception
+   {
+      URL url = getResource(path);
+      VirtualFile rootFile = VFS.getChild(url);
+      return rootFile;
+   }
+
+   private static class TestHandle implements Closeable
+   {
+      private boolean closed;
+
+      private final Callback callback;
+
+      public TestHandle(Callback callback)
+      {
+         super();
+         this.callback = callback;
+      }
+
+      public void close() throws IOException
+      {
+         closed = true;
+         callback.call(this);
+      }
+
+      public boolean isClosed()
+      {
+         return closed;
+      }
+   }
+
+   private static interface Callback
+   {
+      void call(TestHandle handle);
+   }
+}




More information about the jboss-cvs-commits mailing list