[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