[jboss-cvs] JBossAS SVN: r90753 - in projects/vfs/branches/dml-zip-rework: src/main/java/org/jboss/virtual and 5 other directories.
jboss-cvs-commits at lists.jboss.org
jboss-cvs-commits at lists.jboss.org
Wed Jul 1 21:28:50 EDT 2009
Author: david.lloyd at jboss.com
Date: 2009-07-01 21:28:49 -0400 (Wed, 01 Jul 2009)
New Revision: 90753
Added:
projects/vfs/branches/dml-zip-rework/src/main/java/org/jboss/virtual/LongestMatchComparator.java
projects/vfs/branches/dml-zip-rework/src/main/java/org/jboss/virtual/TempFileProvider.java
projects/vfs/branches/dml-zip-rework/src/main/java/org/jboss/virtual/spi/
projects/vfs/branches/dml-zip-rework/src/main/java/org/jboss/virtual/spi/FileSystem.java
projects/vfs/branches/dml-zip-rework/src/main/java/org/jboss/virtual/spi/RealFileSystem.java
projects/vfs/branches/dml-zip-rework/src/main/java/org/jboss/virtual/spi/ZipFileSystem.java
Removed:
projects/vfs/branches/dml-zip-rework/src/main/java/org/jboss/virtual/AssembledDirectory.java
projects/vfs/branches/dml-zip-rework/src/main/java/org/jboss/virtual/MemoryFileFactory.java
Modified:
projects/vfs/branches/dml-zip-rework/pom.xml
projects/vfs/branches/dml-zip-rework/src/main/java/org/jboss/virtual/VFS.java
projects/vfs/branches/dml-zip-rework/src/main/java/org/jboss/virtual/VFSUtils.java
projects/vfs/branches/dml-zip-rework/src/main/java/org/jboss/virtual/VirtualFile.java
projects/vfs/branches/dml-zip-rework/src/main/java/org/jboss/virtual/plugins/vfs/helpers/PathTokenizer.java
projects/vfs/branches/dml-zip-rework/src/main/java/org/jboss/virtual/protocol/vfs/Handler.java
projects/vfs/branches/dml-zip-rework/src/main/java/org/jboss/virtual/protocol/vfsmemory/Handler.java
projects/vfs/branches/dml-zip-rework/src/test/java/org/jboss/test/virtual/test/AssembledContextTestCase.java
projects/vfs/branches/dml-zip-rework/src/test/java/org/jboss/test/virtual/test/FileVFSUnitTestCase.java
projects/vfs/branches/dml-zip-rework/src/test/java/org/jboss/test/virtual/test/MemoryTestCase.java
Log:
Simplified implementation
Modified: projects/vfs/branches/dml-zip-rework/pom.xml
===================================================================
--- projects/vfs/branches/dml-zip-rework/pom.xml 2009-07-01 22:28:40 UTC (rev 90752)
+++ projects/vfs/branches/dml-zip-rework/pom.xml 2009-07-02 01:28:49 UTC (rev 90753)
@@ -8,7 +8,7 @@
<groupId>org.jboss</groupId>
<artifactId>jboss-vfs</artifactId>
<packaging>jar</packaging>
- <version>2.2.0-SNAPSHOT</version>
+ <version>3.0.0-SNAPSHOT</version>
<name>JBoss VFS</name>
<url>http://www.jboss.org</url>
<description>A VFS library</description>
Deleted: projects/vfs/branches/dml-zip-rework/src/main/java/org/jboss/virtual/AssembledDirectory.java
===================================================================
--- projects/vfs/branches/dml-zip-rework/src/main/java/org/jboss/virtual/AssembledDirectory.java 2009-07-01 22:28:40 UTC (rev 90752)
+++ projects/vfs/branches/dml-zip-rework/src/main/java/org/jboss/virtual/AssembledDirectory.java 2009-07-02 01:28:49 UTC (rev 90753)
@@ -1,590 +0,0 @@
-/*
-* 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;
-
-import java.io.IOException;
-import java.net.URL;
-import java.net.URISyntaxException;
-import java.util.List;
-import java.util.regex.Pattern;
-
-import org.jboss.virtual.plugins.context.jar.JarUtils;
-import org.jboss.virtual.plugins.vfs.helpers.FilterVirtualFileVisitor;
-import org.jboss.virtual.plugins.vfs.helpers.SuffixesExcludeFilter;
-
-/**
- * Extension of VirtualFile that represents a virtual directory that can be composed of arbitrary files and resources
- * spread throughout the file system or embedded in jar files.
- *
- * @author <a href="bill at jboss.com">Bill Burke</a>
- * @author <a href="ales.justin at jboss.com">Ales Justin</a>
- * @version $Revision: 1.1 $
- */
-public class AssembledDirectory extends VirtualFile
-{
- /** No jars file filter */
- private static final VirtualFileFilter noJars = new SuffixesExcludeFilter(JarUtils.getSuffixes());
- /** The directory */
- private AssembledDirectoryHandler directory;
-
- public AssembledDirectory(AssembledDirectoryHandler handler)
- {
- super(handler);
- directory = handler;
- }
-
- /**
- * Create assembled directory.
- *
- * @param name context's name
- * @param rootName root name
- * @return new assembled directory instance
- * @throws IOException for any IO error
- * @throws URISyntaxException for any URI error
- */
- public static AssembledDirectory createAssembledDirectory(String name, String rootName) throws IOException, URISyntaxException
- {
- AssembledContext context = new AssembledContext(name, rootName);
- return context.getRoot().getVirtualFile();
- }
-
- /**
- * Add files recursively from root, using the no jars filter.
- *
- * @param root the root
- * @throws IOException for any error
- */
- public void addPath(VirtualFile root) throws IOException
- {
- addPath(root, noJars);
- }
-
- /**
- * Add files recursively from root, using the filter.
- *
- * @param root the root
- * @param recurseFilter the recurse filter
- * @throws IOException for any error
- */
- public void addPath(VirtualFile root, VirtualFileFilter recurseFilter) throws IOException
- {
- final VisitorAttributes va = new VisitorAttributes();
- va.setLeavesOnly(true);
- va.setRecurseFilter(recurseFilter);
-
- VirtualFileVisitor visitor = new VirtualFileVisitor()
- {
- public VisitorAttributes getAttributes()
- {
- return va;
- }
-
- public void visit(VirtualFile virtualFile)
- {
- mkdirs(virtualFile.getPathName()).addChild(virtualFile);
- }
- };
- root.visit(visitor);
- }
-
- /**
- * Find the underlying .class file representing this class and create it within this directory, along with
- * its packages.
- *
- * So, if you added com.acme.Customer class, then a directory structure com/acme would be created
- * and an entry in the acme directory would be the .class file.
- *
- * @param clazz the class
- */
- public void addClass(Class<?> clazz)
- {
- if (clazz == null)
- throw new IllegalArgumentException("Null clazz");
-
- addClass(clazz.getName(), clazz.getClassLoader());
- }
-
- /**
- * Find the underlying .class file representing this class and create it within this directory, along with
- * its packages.
- *
- * So, if you added com.acme.Customer class, then a directory structure com/acme would be created
- * and an entry in the acme directory would be the .class file.
- *
- * @param className the class name
- */
- public void addClass(String className)
- {
- addClass(className, Thread.currentThread().getContextClassLoader());
- }
-
- /**
- * Find the underlying .class file representing this class and create it within this directory, along with
- * its packages.
- *
- * So, if you added com.acme.Customer class, then a directory structure com/acme would be created
- * and an entry in the acme directory would be the .class file.
- *
- * @param className the class name
- * @param loader ClassLoader to look for class resource
- */
- public void addClass(String className, ClassLoader loader)
- {
- if (className == null)
- throw new IllegalArgumentException("Null className");
- if (loader == null)
- throw new IllegalArgumentException("Null loader");
-
- String resource = className.replace('.', '/') + ".class";
- URL url = loader.getResource(resource);
- if (url == null)
- throw new RuntimeException("Could not find resource: " + resource);
-
- AssembledDirectory p = mkdirs(resource);
- p.addResource(resource, loader);
- }
-
- /**
- * Make any directories for the give path to a file.
- *
- * @param path must be a path to a file as last element in path does not have a directory created
- * @return directory file will live in
- */
- public AssembledDirectory mkdirs(String path)
- {
- if (path == null)
- throw new IllegalArgumentException("Null path");
-
- String[] pkgs = path.split("/");
- AssembledDirectoryHandler dir = directory;
- for (int i = 0; i < pkgs.length - 1; i++)
- {
- AssembledDirectoryHandler next = (AssembledDirectoryHandler) dir.findChild(pkgs[i]);
- if (next == null)
- {
- try
- {
- next = new AssembledDirectoryHandler(dir.getVFSContext(), dir, pkgs[i]);
- }
- catch (IOException e)
- {
- throw new RuntimeException(e);
- }
- dir.addChild(next);
- }
- dir = next;
- }
- return dir.getVirtualFile();
- }
-
- /**
- * Locate the .class resource of baseResource. From this resource, determine the base of the resource
- * i.e. what jar or classpath directory it lives in.
- *
- * Once the base of the resource is found, scan all files recursively within the base using the include and exclude
- * patterns. A mirror file structure will be created within this AssembledDirectory. Ths is very useful when you
- * want to create a virtual jar that contains a subset of .class files in your classpath.
- *
- * The include/exclude patterns follow the Ant file pattern matching syntax. See ant.apache.org for more details.
- *
- * @param baseResource the base resource
- * @param includes the includes
- * @param excludes the excludes
- */
- public void addResources(Class<?> baseResource, String[] includes, String[] excludes)
- {
- if (baseResource == null)
- throw new IllegalArgumentException("Null base resource");
-
- String resource = baseResource.getName().replace('.', '/') + ".class";
- addResources(resource, includes, excludes, baseResource.getClassLoader());
- }
-
- /**
- * From the baseResource, determine the base of that resource
- * i.e. what jar or classpath directory it lives in. The Thread.currentThread().getContextClassloader() will be used
- *
- * Once the base of the resource is found, scan all files recursively within the base using the include and exclude
- * patterns. A mirror file structure will be created within this AssembledDirectory. Ths is very useful when you
- * want to create a virtual jar that contains a subset of .class files in your classpath.
- *
- * The include/exclude patterns follow the Ant file pattern matching syntax. See ant.apache.org for more details.
- *
- * @param baseResource the base resource
- * @param includes the includes
- * @param excludes the excludes
- */
- public void addResources(String baseResource, final String[] includes, final String[] excludes)
- {
- if (baseResource == null)
- throw new IllegalArgumentException("Null base resource");
-
- addResources(baseResource, includes, excludes, Thread.currentThread().getContextClassLoader());
- }
-
- /**
- * From the baseResource, determine the base of that resource
- * i.e. what jar or classpath directory it lives in. The loader parameter will be used to find the resource.
- *
- * Once the base of the resource is found, scan all files recursively within the base using the include and exclude
- * patterns. A mirror file structure will be created within this AssembledDirectory. Ths is very useful when you
- * want to create a virtual jar that contains a subset of .class files in your classpath.
- *
- * The include/exclude patterns follow the Ant file pattern matching syntax. See ant.apache.org for more details.
- *
- * @param baseResource the base resource
- * @param includes the includes
- * @param excludes the excludes
- * @param loader the loader
- */
- public void addResources(String baseResource, final String[] includes, final String[] excludes, ClassLoader loader)
- {
- if (baseResource == null)
- throw new IllegalArgumentException("Null baseResource");
- if (loader == null)
- throw new IllegalArgumentException("Null loader");
-
- URL url = loader.getResource(baseResource);
- if (url == null)
- throw new RuntimeException("Could not find baseResource: " + baseResource);
-
- String urlString = url.toString();
- int idx = urlString.lastIndexOf(baseResource);
- urlString = urlString.substring(0, idx);
- try
- {
- url = new URL(urlString);
- VirtualFile parent = VFS.getRoot(url);
-
- VisitorAttributes va = new VisitorAttributes();
- va.setLeavesOnly(true);
- va.setRecurseFilter(noJars);
-
- VirtualFileFilter filter = new VirtualFileFilter()
- {
- public boolean accepts(VirtualFile file)
- {
- boolean matched = false;
- String path = file.getPathName();
- for (String include : includes)
- {
- if (antMatch(path, include))
- {
- matched = true;
- break;
- }
- }
- if (matched == false)
- return false;
- if (excludes != null)
- {
- for (String exclude : excludes)
- {
- if (antMatch(path, exclude))
- return false;
- }
- }
- return true;
- }
- };
-
- FilterVirtualFileVisitor visitor = new FilterVirtualFileVisitor(filter, va);
- parent.visit(visitor);
- List<VirtualFile> files = visitor.getMatched();
- for (VirtualFile vf : files)
- {
- mkdirs(vf.getPathName()).addChild(vf);
- }
- }
- catch (IOException e)
- {
- throw new RuntimeException(e);
- }
- }
-
- /**
- * Create a regular expression pattern from an Ant file matching pattern
- *
- * @param matcher the matcher pattern
- * @return the pattern instance
- */
- public static Pattern getPattern(String matcher)
- {
- if (matcher == null)
- throw new IllegalArgumentException("Null matcher");
-
- matcher = matcher.replace(".", "\\.");
- matcher = matcher.replace("*", ".*");
- matcher = matcher.replace("?", ".{1}");
- return Pattern.compile(matcher);
- }
-
- /**
- * Determine whether a given file path matches an Ant pattern.
- *
- * @param path the path
- * @param expression the expression
- * @return true if we match
- */
- public static boolean antMatch(String path, String expression)
- {
- if (path == null)
- throw new IllegalArgumentException("Null path");
- if (expression == null)
- throw new IllegalArgumentException("Null expression");
- if (path.startsWith("/")) path = path.substring(1);
- if (expression.endsWith("/")) expression += "**";
- String[] paths = path.split("/");
- String[] expressions = expression.split("/");
-
- int x = 0, p;
- Pattern pattern = getPattern(expressions[0]);
-
- for (p = 0; p < paths.length && x < expressions.length; p++)
- {
- if (expressions[x].equals("**"))
- {
- do
- {
- x++;
- } while (x < expressions.length && expressions[x].equals("**"));
- if (x == expressions.length)
- return true; // "**" with nothing after it
- pattern = getPattern(expressions[x]);
- }
- String element = paths[p];
- if (pattern.matcher(element).matches())
- {
- x++;
- if (x < expressions.length)
- {
- pattern = getPattern(expressions[x]);
- }
- }
- else if (!(x > 0 && expressions[x - 1].equals("**"))) // our previous isn't "**"
- {
- return false;
- }
- }
- if (p < paths.length)
- return false;
- if (x < expressions.length)
- return false;
- return true;
- }
-
- /**
- * Add a VirtualFile as a child to this AssembledDirectory.
- *
- * @param vf the virtual file
- * @return the file
- */
- public VirtualFile addChild(VirtualFile vf)
- {
- if (vf == null)
- throw new IllegalArgumentException("Null virtual file");
-
- return directory.addChild(vf.getHandler()).getVirtualFile();
- }
-
- /**
- * Add a VirtualFile as a child to this AssembledDirectory. This file will be added
- * under a new aliased name.
- *
- * @param vf the virtual file
- * @param newName the new name
- * @return new file
- */
- public VirtualFile addChild(VirtualFile vf, String newName)
- {
- try
- {
- AssembledFileHandler handler = new AssembledFileHandler(directory.getVFSContext(), directory, newName, vf.getHandler());
- directory.addChild(handler);
- return handler.getVirtualFile();
- }
- catch (IOException e)
- {
- throw new RuntimeException(e);
- }
- }
-
- /**
- * Add a classloader found resource to as a child to this AssembledDirectory. The base file name of the
- * resource will be used as the child's name.
- *
- * Thread.currentThread.getCOntextClassLoader() will be used to load the resource.
- *
- * @param resource the resource
- * @return the file
- */
- public VirtualFile addResource(String resource)
- {
- return addResource(resource, Thread.currentThread().getContextClassLoader());
- }
-
- /**
- * Add a classloader found resource to as a child to this AssembledDirectory. The newName parameter will be used
- * as the name of the child.
- *
- * Thread.currentThread.getCOntextClassLoader() will be used to load the resource.
- *
- * @param resource the resource
- * @param newName the new name
- * @return the file
- */
- public VirtualFile addResource(String resource, String newName)
- {
- return addResource(resource, Thread.currentThread().getContextClassLoader(), newName);
- }
-
- /**
- * Add a classloader found resource to as a child to this AssembledDirectory. The base file name of the
- * resource will be used as the child's name.
- *
- * The loader parameter will be used to load the resource.
- *
- * @param resource the resource
- * @param loader the loader
- * @return the file
- */
- public VirtualFile addResource(String resource, ClassLoader loader)
- {
- if (resource == null)
- throw new IllegalArgumentException("Null resource");
- if (loader == null)
- throw new IllegalArgumentException("Null loader");
-
- URL url = loader.getResource(resource);
- if (url == null)
- throw new RuntimeException("Could not find resource: " + resource);
-
- return addResource(url);
- }
-
- /**
- * Add a resource identified by the URL as a child to this AssembledDirectory.
- *
- * @param url the url
- * @return the file
- */
- public VirtualFile addResource(URL url)
- {
- if (url == null)
- throw new IllegalArgumentException("Null url");
-
- try
- {
- VirtualFile vf = VFS.getRoot(url);
- return addChild(vf);
- }
- catch (IOException e)
- {
- throw new RuntimeException(e);
- }
- }
-
- /**
- * Add a classloader found resource to as a child to this AssembledDirectory. The newName parameter will be used
- * as the name of the child.
- *
- * The loader parameter will be used to load the resource.
- *
- * @param resource the resource
- * @param loader the loader
- * @param newName the new name
- * @return the file
- */
- public VirtualFile addResource(String resource, ClassLoader loader, String newName)
- {
- if (resource == null)
- throw new IllegalArgumentException("Null resource");
- if (loader == null)
- throw new IllegalArgumentException("Null loader");
- if (newName == null)
- throw new IllegalArgumentException("Null newName");
-
- URL url = loader.getResource(resource);
- if (url == null)
- throw new RuntimeException("Could not find resource: " + resource);
-
- try
- {
- VirtualFile vf = VFS.getRoot(url);
- return addChild(vf, newName);
- }
- catch (IOException e)
- {
- throw new RuntimeException(e);
- }
- }
-
- /**
- * Add raw bytes as a file to this assembled directory
- *
- * @param bytes the bytes
- * @param name the name
- * @return the file
- */
- public VirtualFile addBytes(byte[] bytes, String name)
- {
- if (bytes == null)
- throw new IllegalArgumentException("Null bytes");
- if (name == null)
- throw new IllegalArgumentException("Null name");
-
- ByteArrayHandler handler;
- try
- {
- handler = new ByteArrayHandler(directory.getVFSContext(), directory, name, bytes);
- }
- catch (IOException e)
- {
- throw new RuntimeException(e);
- }
- directory.addChild(handler);
- return handler.getVirtualFile();
- }
-
- /**
- * Create a directory within this directory.
- *
- * @param name the name
- * @return the directory
- */
- public AssembledDirectory mkdir(String name)
- {
- if (name == null)
- throw new IllegalArgumentException("Null name");
-
- try
- {
- AssembledDirectoryHandler handler = new AssembledDirectoryHandler(directory.getVFSContext(), directory, name);
- directory.addChild(handler);
- return new AssembledDirectory(handler);
- }
- catch (IOException e)
- {
- throw new RuntimeException(e);
- }
- }
-}
Added: projects/vfs/branches/dml-zip-rework/src/main/java/org/jboss/virtual/LongestMatchComparator.java
===================================================================
--- projects/vfs/branches/dml-zip-rework/src/main/java/org/jboss/virtual/LongestMatchComparator.java (rev 0)
+++ projects/vfs/branches/dml-zip-rework/src/main/java/org/jboss/virtual/LongestMatchComparator.java 2009-07-02 01:28:49 UTC (rev 90753)
@@ -0,0 +1,108 @@
+/*
+ * 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.virtual;
+
+import java.util.Comparator;
+import java.util.Iterator;
+import java.io.Serializable;
+
+/**
+ * A comparator which sorts longer values before their shorter initial sublists.
+ *
+ * @param <E> the element type
+ * @param <C> the collection type
+ */
+final class LongestMatchComparator<E, C extends Iterable<E>> implements Comparator<C>, Serializable
+{
+ private static final long serialVersionUID = 954089122568817323L;
+
+ private final Comparator<E> comparator;
+
+ private LongestMatchComparator(Comparator<E> comparator)
+ {
+ this.comparator = comparator;
+ }
+
+ /**
+ * Create a new instance.
+ *
+ * @param comparator the element comparator
+ * @param <E> the element type
+ * @param <C> the collection type
+ * @return the new collection comparator
+ */
+ static <E, C extends Iterable<E>> Comparator<C> create(Comparator<E> comparator) {
+ return new LongestMatchComparator<E, C>(comparator);
+ }
+
+ /**
+ * Create a new instance which uses the native ordering of the element type.
+ *
+ * @param <E> the element type
+ * @param <C> the collection type
+ * @return the new collection comparator
+ */
+ static <E extends Comparable<? super E>, C extends Iterable<E>> Comparator<C> create() {
+ return new LongestMatchComparator<E, C>(NativeComparator.<E>getInstance());
+ }
+
+ /** {@inheritDoc} */
+ public int compare(C o1, C o2)
+ {
+ final Comparator<E> comparator = this.comparator;
+ final Iterator<E> i1 = o1.iterator();
+ final Iterator<E> i2 = o2.iterator();
+ while (i1.hasNext() && i2.hasNext()) {
+ final E t1 = i1.next();
+ final E t2 = i2.next();
+ final int c = comparator.compare(t1, t2);
+ if (c != 0) {
+ return c;
+ }
+ }
+ return i1.hasNext() ? -1 : i2.hasNext() ? 1 : 0;
+ }
+
+ /**
+ * A native-order comparator.
+ *
+ * @param <E>
+ */
+ private static final class NativeComparator<E extends Comparable<? super E>> implements Comparator<E>, Serializable
+ {
+ private static final long serialVersionUID = -4198283451912738802L;
+
+ /** {@inheritDoc} */
+ public int compare(E o1, E o2)
+ {
+ return o1.compareTo(o2);
+ }
+
+ private static final NativeComparator INSTANCE = new NativeComparator();
+
+ @SuppressWarnings({ "unchecked" })
+ private static <E extends Comparable<? super E>> Comparator<E> getInstance() {
+ return INSTANCE;
+ }
+ }
+}
Deleted: projects/vfs/branches/dml-zip-rework/src/main/java/org/jboss/virtual/MemoryFileFactory.java
===================================================================
--- projects/vfs/branches/dml-zip-rework/src/main/java/org/jboss/virtual/MemoryFileFactory.java 2009-07-01 22:28:40 UTC (rev 90752)
+++ projects/vfs/branches/dml-zip-rework/src/main/java/org/jboss/virtual/MemoryFileFactory.java 2009-07-02 01:28:49 UTC (rev 90753)
@@ -1,115 +0,0 @@
-/*
-* 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;
-
-import java.io.IOException;
-import java.net.URI;
-import java.net.URL;
-
-/**
- * Memory VFS API.
- *
- * @author <a href="mailto:ales.justin at jboss.com">Ales Justin</a>
- */
-public class MemoryFileFactory
-{
- private static final MemoryContextFactory factory = MemoryContextFactory.getInstance();
-
- /**
- * Find host's VFS.
- *
- * @param host the host
- * @return host's vfs
- */
- public static VFS find(String host)
- {
- return factory.find(host);
- }
-
- /**
- * Create the memory root.
- *
- * @param uri the uri
- * @return root's vfs
- * @throws IOException for any error
- */
- public static VFS createRoot(URI uri) throws IOException
- {
- return createRoot(uri.toURL());
- }
-
- /**
- * Create root vfs.
- *
- * @param url the url
- * @return root's vfs
- */
- public static VFS createRoot(URL url)
- {
- return factory.createRoot(url).getVFS();
- }
-
- /**
- * Create memory directory.
- *
- * @param url the url
- * @return vfs directory
- */
- public static VirtualFile createDirectory(URL url)
- {
- return factory.createDirectory(url);
- }
-
- /**
- * Put file.
- *
- * @param url the url
- * @param contents the contents
- * @return vfs file
- */
- public static VirtualFile putFile(URL url, byte[] contents)
- {
- return factory.putFile(url, contents);
- }
-
- /**
- * Delete root.
- *
- * @param url the url
- * @return true if deleted
- */
- public static boolean deleteRoot(URL url)
- {
- return factory.deleteRoot(url);
- }
-
- /**
- * Delete.
- *
- * @param url the url
- * @return true if deleted
- */
- public static boolean delete(URL url)
- {
- return factory.delete(url);
- }
-}
Added: projects/vfs/branches/dml-zip-rework/src/main/java/org/jboss/virtual/TempFileProvider.java
===================================================================
--- projects/vfs/branches/dml-zip-rework/src/main/java/org/jboss/virtual/TempFileProvider.java (rev 0)
+++ projects/vfs/branches/dml-zip-rework/src/main/java/org/jboss/virtual/TempFileProvider.java 2009-07-02 01:28:49 UTC (rev 90753)
@@ -0,0 +1,186 @@
+/*
+ * 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.virtual;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.Closeable;
+import java.io.InputStream;
+import java.io.FileOutputStream;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * A provider for temporary physical files and directories.
+ */
+public final class TempFileProvider implements Closeable
+{
+ private static final String TMP_DIR_PROPERTY = "jboss.server.temp.dir";
+ private static final File TMP_ROOT;
+
+ static {
+ final String configTmpDir = System.getProperty(TMP_DIR_PROPERTY);
+ try
+ {
+ TMP_ROOT = configTmpDir == null ? File.createTempFile("jboss-vfs-temp", "") : new File(configTmpDir, "vfs");
+ TMP_ROOT.mkdirs();
+ }
+ catch (IOException e)
+ {
+ throw new RuntimeException("Can't set up temp file provider", e);
+ }
+ }
+
+ /**
+ * Create a temporary file provider for a given type.
+ *
+ * @param providerType the provider type string (used as a prefix in the temp file dir name)
+ * @return the new provider
+ * @throws IOException if an I/O error occurs
+ */
+ public static TempFileProvider create(String providerType, ScheduledExecutorService executor) throws IOException
+ {
+ return new TempFileProvider(File.createTempFile(providerType, "", TMP_ROOT), 0, executor);
+ }
+
+ /**
+ * Create a temporary file provider for a given type and hash depth. The hash depth is used to limit the number
+ * of files in a single directory.
+ *
+ * @param providerType the provider type string (used as a prefix in the temp file dir name)
+ * @param hashDepth the hash directory tree depth
+ * @return the new provider
+ * @throws IOException if an I/O error occurs
+ */
+ public static TempFileProvider create(String providerType, int hashDepth, ScheduledExecutorService executor) throws IOException
+ {
+ return new TempFileProvider(File.createTempFile(providerType, "", TMP_ROOT), hashDepth, executor);
+ }
+
+ private final File providerRoot;
+ private final int hashDepth;
+ private final ScheduledExecutorService executor;
+
+ private TempFileProvider(File providerRoot, int hashDepth, ScheduledExecutorService executor)
+ {
+ this.providerRoot = providerRoot;
+ this.executor = executor;
+ if (hashDepth < 0 || hashDepth > 4) {
+ throw new IllegalArgumentException("Bad hashDepth");
+ }
+ this.hashDepth = hashDepth;
+ }
+
+ /**
+ * Create a temp file within this provider.
+ *
+ * @param originalName the original file name
+ * @return the temporary file
+ * @throws IOException if an error occurs
+ */
+ public File createTempFile(String originalName) throws IOException {
+ return createTempFile(originalName, originalName.hashCode());
+ }
+
+ /**
+ * Create a temp file within this provider, using an alternate hash code.
+ *
+ * @param originalName the original file name
+ * @param hashCode the hash code to use
+ * @return the temporary file
+ * @throws IOException if an error occurs
+ */
+ public File createTempFile(String originalName, int hashCode) throws IOException {
+ File root = providerRoot;
+ for (int i = 0; i < hashDepth; i ++) {
+ final int dc = hashCode & 0x7f;
+ root = new File(root, dc < 16 ? "0" + Integer.toHexString(dc) : Integer.toHexString(dc));
+ root.mkdir();
+ hashCode >>= 7;
+ }
+ return File.createTempFile("", "-" + originalName, root);
+ }
+
+ /**
+ * Create a temp file within this provider, using an alternate hash code, and prepopulating the file from the given
+ * input stream.
+ *
+ * @param originalName the original file name
+ * @param hashCode the hash code to use
+ * @param sourceData the source input stream to use
+ * @return the temporary file
+ * @throws IOException if an error occurs
+ */
+ public File createTempFile(String originalName, int hashCode, InputStream sourceData) throws IOException {
+ final File tempFile = createTempFile(originalName, hashCode);
+ boolean ok = false;
+ try {
+ final FileOutputStream fos = new FileOutputStream(tempFile);
+ try {
+ VFSUtils.copyStream(sourceData, fos);
+ fos.close();
+ sourceData.close();
+ return tempFile;
+ } finally {
+ VFSUtils.safeClose(fos);
+ }
+ } finally {
+ VFSUtils.safeClose(sourceData);
+ if (! ok) {
+ tempFile.delete();
+ }
+ }
+ }
+
+ /**
+ * Close this provider and delete any temp files associated with it.
+ */
+ public void close() throws IOException
+ {
+ final Runnable task = new Runnable()
+ {
+ public void run()
+ {
+ if (! recursiveDelete(providerRoot)) {
+ executor.schedule(this, 30L, TimeUnit.SECONDS);
+ }
+ }
+ };
+ task.run();
+ }
+
+ private static boolean recursiveDelete(File root) {
+ boolean ok = true;
+ if (root.isDirectory()) {
+ final File[] files = root.listFiles();
+ for (File file : files)
+ {
+ ok &= recursiveDelete(file);
+ }
+ return ok && (root.delete() || ! root.exists());
+ } else {
+ ok &= root.delete() || ! root.exists();
+ }
+ return ok;
+ }
+}
Modified: projects/vfs/branches/dml-zip-rework/src/main/java/org/jboss/virtual/VFS.java
===================================================================
--- projects/vfs/branches/dml-zip-rework/src/main/java/org/jboss/virtual/VFS.java 2009-07-01 22:28:40 UTC (rev 90752)
+++ projects/vfs/branches/dml-zip-rework/src/main/java/org/jboss/virtual/VFS.java 2009-07-02 01:28:49 UTC (rev 90753)
@@ -22,12 +22,19 @@
package org.jboss.virtual;
import java.io.IOException;
+import java.io.Closeable;
import java.net.URI;
import java.net.URL;
import java.util.List;
+import java.util.Collections;
+import java.util.Map;
import org.jboss.logging.Logger;
-import org.jboss.virtual.plugins.vfs.helpers.WrappingVirtualFileHandlerVisitor;
+import org.jboss.util.collection.ConcurrentNavigableMap;
+import org.jboss.util.collection.ConcurrentSkipListMap;
+import org.jboss.virtual.spi.RealFileSystem;
+import org.jboss.virtual.spi.FileSystem;
+import org.jboss.virtual.plugins.vfs.helpers.PathTokenizer;
/**
* Virtual File System
@@ -42,25 +49,20 @@
/** The log */
private static final Logger log = Logger.getLogger(VFS.class);
- /** The VFS Context */
- private final VFSContext context;
+ private final ConcurrentNavigableMap<List<String>, Mount> activeMounts = new ConcurrentSkipListMap<List<String>, Mount>(LongestMatchComparator.<String, List<String>>create());
+ private final VirtualFile rootVirtualFile;
static
{
init();
}
- /**
- * Create a new VFS.
- *
- * @param context the context
- * @throws IllegalArgumentException for a null context
- */
- public VFS(VFSContext context)
+ public VFS()
{
- if (context == null)
- throw new IllegalArgumentException("Null name");
- this.context = context;
+ // By default, there's a root mount which points to the "real" FS
+ final List<String> emptyList = Collections.<String>emptyList();
+ activeMounts.put(emptyList, new Mount(RealFileSystem.ROOT_INSTANCE, emptyList));
+ rootVirtualFile = new VirtualFile(this, Collections.<String>emptyList(), "");
}
/**
@@ -80,255 +82,59 @@
pkgs += "|org.jboss.virtual.protocol";
System.setProperty("java.protocol.handler.pkgs", pkgs);
}
- org.jboss.virtual.plugins.context.VfsArchiveBrowserFactory factory = org.jboss.virtual.plugins.context.VfsArchiveBrowserFactory.INSTANCE;
- // keep this until AOP and HEM uses VFS internally instead of the stupid ArchiveBrowser crap.
- org.jboss.util.file.ArchiveBrowser.factoryFinder.put("vfsfile", factory);
- org.jboss.util.file.ArchiveBrowser.factoryFinder.put("vfszip", factory);
- org.jboss.util.file.ArchiveBrowser.factoryFinder.put("vfsjar", factory);
- org.jboss.util.file.ArchiveBrowser.factoryFinder.put("vfs", factory);
+// org.jboss.virtual.plugins.context.VfsArchiveBrowserFactory factory = org.jboss.virtual.plugins.context.VfsArchiveBrowserFactory.INSTANCE;
+// // keep this until AOP and HEM uses VFS internally instead of the stupid ArchiveBrowser crap.
+// org.jboss.util.file.ArchiveBrowser.factoryFinder.put("vfsfile", factory);
+// org.jboss.util.file.ArchiveBrowser.factoryFinder.put("vfszip", factory);
+// org.jboss.util.file.ArchiveBrowser.factoryFinder.put("vfsjar", factory);
+// org.jboss.util.file.ArchiveBrowser.factoryFinder.put("vfs", factory);
}
/**
- * Get the vfs context.
+ * Mount a filesystem on a mount point in the VFS. The mount point is any valid file name, existant or non-existant.
+ * If a relative path is given, it will be treated as relative to the VFS root.
*
- * This is package protected method.
- * Same as VirtualFile::getHandler.
- *
- * @return the vfs context
+ * @param mountPoint the mount point
+ * @param fileSystem the file system to mount
+ * @return a handle which can be used to unmount the filesystem
+ * @throws IOException if an I/O error occurs, such as a filesystem already being mounted at the given mount point
*/
- VFSContext getContext()
- {
- return context;
- }
-
- /**
- * Set exception handler.
- *
- * @param exceptionHandler the exception handler.
- */
- public void setExceptionHandler(ExceptionHandler exceptionHandler)
- {
- context.setExceptionHandler(exceptionHandler);
- }
-
- /**
- * Cleanup any resources tied to this file.
- * e.g. vfs cache
- *
- * @param file the file
- */
- static void cleanup(VirtualFile file)
- {
- VirtualFileHandler fileHandler = file.getHandler();
- VFSContext context = fileHandler.getVFSContext();
-
- try
- {
- context.cleanupTempInfo(fileHandler.getPathName());
+ public Closeable mount(String mountPoint, FileSystem fileSystem) throws IOException {
+ final List<String> realMountPoint = PathTokenizer.applySpecialPaths(PathTokenizer.getTokens(mountPoint));
+ final Mount mount = new Mount(fileSystem, realMountPoint);
+ if (activeMounts.putIfAbsent(realMountPoint, mount) == null) {
+ throw new IOException("Filsystem already mounted at mount point \"" + mountPoint + "\"");
}
- catch (Exception e)
- {
- log.debug("Exception cleaning temp info, file=" + file, e);
- }
-
- try
- {
- VirtualFileHandler contextHandler = context.getRoot();
- // the file is the context root, hence possible registry candidate
- if (fileHandler.equals(contextHandler))
- {
- VFSRegistry registry = VFSRegistry.getInstance();
- registry.removeContext(context);
- }
- }
- catch (Exception e)
- {
- log.debug("Exception removing cached context, file=" + file, e);
- }
+ return mount;
}
/**
- * Get the virtual file system for a root uri
- *
- * @param rootURI the root URI
- * @return the virtual file system
- * @throws IOException if there is a problem accessing the VFS
- * @throws IllegalArgumentException if the rootURL is null
- */
- public static VFS getVFS(URI rootURI) throws IOException
- {
- VFSContextFactory factory = VFSContextFactoryLocator.getFactory(rootURI);
- if (factory == null)
- throw new IOException("No context factory for " + rootURI);
-
- VFSContext context = factory.getVFS(rootURI);
- VFSRegistry.getInstance().addContext(context);
- return context.getVFS();
- }
-
- /**
- * Create new root
+ * Find a virtual file.
*
- * @param rootURI the root url
- * @return the virtual file
- * @throws IOException if there is a problem accessing the VFS
- * @throws IllegalArgumentException if the rootURL
- */
- public static VirtualFile createNewRoot(URI rootURI) throws IOException
- {
- VFS vfs = getVFS(rootURI);
- return vfs.getRoot();
- }
-
- /**
- * Get the root virtual file
- *
- * @param rootURI the root uri
- * @return the virtual file
- * @throws IOException if there is a problem accessing the VFS
- * @throws IllegalArgumentException if the rootURL is null
- */
- public static VirtualFile getRoot(URI rootURI) throws IOException
- {
- VFSRegistry registry = VFSRegistry.getInstance();
- VirtualFile file = registry.getFile(rootURI);
- return (file != null) ? file : createNewRoot(rootURI);
- }
-
- /**
- * Get a virtual file
- *
- * @param rootURI the root uri
- * @param name the path name
- * @return the virtual file
- * @throws IOException if there is a problem accessing the VFS
- * @throws IllegalArgumentException if the rootURL or name is null
- */
- @SuppressWarnings("deprecation")
- public static VirtualFile getVirtualFile(URI rootURI, String name) throws IOException
- {
- VirtualFile root = getRoot(rootURI);
- return root.findChild(name);
- }
-
- /**
- * Get the virtual file system for a root url
- *
- * @param rootURL the root url
- * @return the virtual file system
- * @throws IOException if there is a problem accessing the VFS
- * @throws IllegalArgumentException if the rootURL is null
- */
- public static VFS getVFS(URL rootURL) throws IOException
- {
- VFSContextFactory factory = VFSContextFactoryLocator.getFactory(rootURL);
- if (factory == null)
- throw new IOException("No context factory for " + rootURL);
-
- VFSContext context = factory.getVFS(rootURL);
- VFSRegistry.getInstance().addContext(context);
- return context.getVFS();
- }
-
- /**
- * Create new root
- *
- * @param rootURL the root url
- * @return the virtual file
- * @throws IOException if there is a problem accessing the VFS
- * @throws IllegalArgumentException if the rootURL
- */
- public static VirtualFile createNewRoot(URL rootURL) throws IOException
- {
- VFS vfs = getVFS(rootURL);
- return vfs.getRoot();
- }
-
- /**
- * Get the root virtual file
- *
- * @param rootURL the root url
- * @return the virtual file
- * @throws IOException if there is a problem accessing the VFS
- * @throws IllegalArgumentException if the rootURL
- */
- public static VirtualFile getRoot(URL rootURL) throws IOException
- {
- VFSRegistry registry = VFSRegistry.getInstance();
- VirtualFile file = registry.getFile(rootURL);
- return (file != null) ? file : createNewRoot(rootURL);
- }
-
- /**
- * Get a virtual file
- *
- * @param rootURL the root url
- * @param name the path name
- * @return the virtual file
- * @throws IOException if there is a problem accessing the VFS
- * @throws IllegalArgumentException if the rootURL or name is null
- */
- @SuppressWarnings("deprecation")
- public static VirtualFile getVirtualFile(URL rootURL, String name) throws IOException
- {
- VirtualFile root = getRoot(rootURL);
- return root.findChild(name);
- }
-
- /**
- * Get the root file of this VFS
- *
- * @return the root
- * @throws IOException for any problem accessing the VFS
- */
- public VirtualFile getRoot() throws IOException
- {
- VirtualFileHandler handler = context.getRoot();
- return handler.getVirtualFile();
- }
-
- /**
- * Find a child from the root
- *
* @param path the child path
* @return the child
- * @throws IOException for any problem accessing the VFS (including the child does not exist)
+ * @throws IOException for any problem accessing the VFS
* @throws IllegalArgumentException if the path is null
- * @deprecated use getChild, and handle null if not found
*/
- @Deprecated
- public VirtualFile findChild(String path) throws IOException
+ public VirtualFile getChild(String path) throws IOException
{
if (path == null)
throw new IllegalArgumentException("Null path");
-
- VirtualFileHandler handler = context.getRoot();
- VirtualFileHandler result = context.getChild(handler, VFSUtils.fixName(path));
- if (result == null)
- {
- List<VirtualFileHandler> children = handler.getChildren(true);
- throw new IOException("Child not found " + path + " for " + handler + ", available children: " + children);
- }
- return result.getVirtualFile();
+ final List<String> realPath = PathTokenizer.applySpecialPaths(PathTokenizer.getTokens(path));
+ final String realPathString = PathTokenizer.getRemainingPath(realPath, 0);
+ return new VirtualFile(this, realPath, realPathString);
}
-
+
/**
- * Get a child
- *
- * @param path the child path
- * @return the child or <code>null</code> if not found
- * @throws IOException if a real problem occurs
- */
- public VirtualFile getChild(String path) throws IOException
+ * Get the root virtual file for this VFS instance.
+ *
+ * @return the root virtual file
+ */
+ public VirtualFile getRootVirtualFile()
{
- if (path == null)
- throw new IllegalArgumentException("Null path");
-
- VirtualFileHandler handler = context.getRoot();
- VirtualFileHandler result = context.getChild(handler, VFSUtils.fixName(path));
- return result != null ? result.getVirtualFile() : null;
+ return rootVirtualFile;
}
-
+
/**
* Get the children
*
@@ -337,7 +143,7 @@
*/
public List<VirtualFile> getChildren() throws IOException
{
- return getRoot().getChildren(null);
+ return getRootVirtualFile().getChildren(null);
}
/**
@@ -349,7 +155,7 @@
*/
public List<VirtualFile> getChildren(VirtualFileFilter filter) throws IOException
{
- return getRoot().getChildren(filter);
+ return getRootVirtualFile().getChildren(filter);
}
/**
@@ -362,7 +168,7 @@
*/
public List<VirtualFile> getChildrenRecursively() throws IOException
{
- return getRoot().getChildrenRecursively(null);
+ return getRootVirtualFile().getChildrenRecursively(null);
}
/**
@@ -376,7 +182,7 @@
*/
public List<VirtualFile> getChildrenRecursively(VirtualFileFilter filter) throws IOException
{
- return getRoot().getChildrenRecursively(filter);
+ return getRootVirtualFile().getChildrenRecursively(filter);
}
/**
@@ -388,12 +194,7 @@
*/
public void visit(VirtualFileVisitor visitor) throws IOException
{
- VirtualFileHandler handler = context.getRoot();
- if (handler.isLeaf() == false)
- {
- WrappingVirtualFileHandlerVisitor wrapper = new WrappingVirtualFileHandlerVisitor(visitor);
- context.visit(handler, wrapper);
- }
+ visitor.visit(rootVirtualFile);
}
/**
@@ -409,32 +210,52 @@
if (file == null)
throw new IllegalArgumentException("Null file");
- VirtualFileHandler handler = file.getHandler();
- WrappingVirtualFileHandlerVisitor wrapper = new WrappingVirtualFileHandlerVisitor(visitor);
- VFSContext handlerContext = handler.getVFSContext();
- handlerContext.visit(handler, wrapper);
+ if (file.getVFS() != this)
+ throw new IllegalArgumentException("Virtual file from foreign VFS");
+
+ visitor.visit(file);
}
- @Override
- public String toString()
+ /**
+ * Get the enclosing mounted FileSystem for the given path.
+ *
+ * @param pathTokens the path tokens
+ * @return the filesystem
+ */
+ Mount getMount(List<String> pathTokens)
{
- return context.toString();
+ final Map.Entry<List<String>, Mount> entry = activeMounts.floorEntry(pathTokens);
+ return entry.getValue();
}
- @Override
- public int hashCode()
- {
- return context.hashCode();
+ /**
+ * The mount representation. This instance represents a binding between a position in the virtual filesystem and
+ * the backing filesystem implementation; the same {@code FileSystem} may be mounted in more than one place, however
+ * only one {@code FileSystem} may be bound to a specific path at a time.
+ */
+ final class Mount implements Closeable {
+ private final FileSystem fileSystem;
+ private final List<String> realMountPoint;
+
+ private Mount(FileSystem fileSystem, List<String> realMountPoint)
+ {
+ this.fileSystem = fileSystem;
+ this.realMountPoint = realMountPoint;
+ }
+
+ public void close() throws IOException
+ {
+ activeMounts.remove(realMountPoint, this);
+ }
+
+ FileSystem getFileSystem()
+ {
+ return fileSystem;
+ }
+
+ List<String> getRealMountPoint()
+ {
+ return realMountPoint;
+ }
}
-
- @Override
- public boolean equals(Object obj)
- {
- if (obj == this)
- return true;
- if (obj == null || obj instanceof VFS == false)
- return false;
- VFS other = (VFS) obj;
- return context.equals(other.context);
- }
}
Modified: projects/vfs/branches/dml-zip-rework/src/main/java/org/jboss/virtual/VFSUtils.java
===================================================================
--- projects/vfs/branches/dml-zip-rework/src/main/java/org/jboss/virtual/VFSUtils.java 2009-07-01 22:28:40 UTC (rev 90752)
+++ projects/vfs/branches/dml-zip-rework/src/main/java/org/jboss/virtual/VFSUtils.java 2009-07-02 01:28:49 UTC (rev 90753)
@@ -31,18 +31,15 @@
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLDecoder;
-import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
-import java.util.Properties;
import java.util.StringTokenizer;
import java.util.jar.Attributes;
import java.util.jar.JarFile;
import java.util.jar.Manifest;
import org.jboss.logging.Logger;
-import org.jboss.util.StringPropertyReplacer;
import org.jboss.util.collection.CollectionsFactory;
/**
@@ -60,51 +57,7 @@
/** The default encoding */
private static final String DEFAULT_ENCODING = "UTF-8";
- /** The link */
- public static final String VFS_LINK_INFIX = ".vfslink";
-
- /** The link properties */
- public static final String VFS_LINK_PROPERTIES_SUFFIX = ".vfslink.properties";
-
- /** The link name */
- public static final String VFS_LINK_NAME = "vfs.link.name";
- /** The link target */
- public static final String VFS_LINK_TARGET = "vfs.link.target";
-
/**
- * The system no force copy key / query
- */
- 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";
- public static final String NO_REAPER_QUERY = "noReaper";
-
- /**
- * Key used to force case sensitive path checking in vfsfile
- */
- public static final String FORCE_CASE_SENSITIVE_KEY = "jboss.vfs.forceCaseSensitive";
- public static final String CASE_SENSITIVE_QUERY = "caseSensitive";
-
- /**
- * Key used to turn on memory optimizations - less cache use at the expense of performance
- */
- public static final String OPTIMIZE_FOR_MEMORY_KEY = "jboss.vfs.optimizeForMemory";
-
- /**
- * Key used to determine VFS Cache impl
- */
- public static final String VFS_CACHE_KEY = "jboss.vfs.cache";
-
- /**
* Constant representing the URL file protocol
*/
public static final String FILE_PROTOCOL = "file";
@@ -112,15 +65,8 @@
/** Standard separator for JAR URL */
public static final String JAR_URL_SEPARATOR = "!/";
- /** The temp marker flag */
- public static final String IS_TEMP_FILE = "IS_TEMP_FILE";
-
- /**
- * Stop cache.
- */
- public static void stopCache()
+ private VFSUtils()
{
- VFSCacheFactory.getInstance().stop();
}
/**
@@ -274,24 +220,6 @@
}
/**
- * Get a manifest from a virtual file system,
- * assuming the root of the VFS is the root of an archive
- *
- * @param archive the vfs
- * @return the manifest or null if not found
- * @throws IOException if there is an error reading the manifest
- * @throws IllegalArgumentException for a null archive
- */
- public static Manifest getManifest(VFS archive) throws IOException
- {
- if (archive == null)
- throw new IllegalArgumentException("Null vfs archive");
-
- VirtualFile root = archive.getRoot();
- return getManifest(root);
- }
-
- /**
* Fix a name (removes any trailing slash)
*
* @param name the name to fix
@@ -387,85 +315,6 @@
}
/**
- * Does a vf name contain the VFS link prefix
- * @param name - the name portion of a virtual file
- * @return true if the name starts with VFS_LINK_PREFIX, false otherwise
- */
- public static boolean isLink(String name)
- {
- if (name == null)
- throw new IllegalArgumentException("Null name");
-
- return name.indexOf(VFS_LINK_INFIX) >= 0;
- }
-
- /**
- * Read the link information from the stream based on the type as determined
- * from the name suffix.
- *
- * @param is - input stream to the link file contents
- * @param name - the name of the virtual file representing the link
- * @param props the propertes
- * @return a list of the links read from the stream
- * @throws IOException on failure to read/parse the stream
- * @throws URISyntaxException for an error parsing a URI
- */
- public static List<LinkInfo> readLinkInfo(InputStream is, String name, Properties props)
- throws IOException, URISyntaxException
- {
- if (name == null)
- throw new IllegalArgumentException("Null name");
-
- if(name.endsWith(VFS_LINK_PROPERTIES_SUFFIX))
- {
- List<LinkInfo> info = new ArrayList<LinkInfo>();
- parseLinkProperties(is, info, props);
- return info;
- }
- else
- throw new UnsupportedEncodingException("Unknown link format: " + name);
- }
-
- /**
- * Parse a properties link file
- *
- * @param is - input stream to the link file contents
- * @param info the link infos
- * @param props the propertes
- * @throws IOException on failure to read/parse the stream
- * @throws URISyntaxException for an error parsing a URI
- */
- public static void parseLinkProperties(InputStream is, List<LinkInfo> info, Properties props)
- throws IOException, URISyntaxException
- {
- if (is == null)
- throw new IllegalArgumentException("Null input stream");
- if (info == null)
- throw new IllegalArgumentException("Null info");
- if (props == null)
- throw new IllegalArgumentException("Null properties");
-
- props.load(is);
- // Iterate over the property tuples
- for(int n = 0; ; n ++)
- {
- String nameKey = VFS_LINK_NAME + "." + n;
- String name = props.getProperty(nameKey);
- String uriKey = VFS_LINK_TARGET + "." + n;
- String uri = props.getProperty(uriKey);
- // End when the value is null since a link may not have a name
- if (uri == null)
- {
- break;
- }
- // Replace any system property references
- uri = StringPropertyReplacer.replaceProperties(uri);
- LinkInfo link = new LinkInfo(name, new URI(uri));
- info.add(link);
- }
- }
-
- /**
* Deal with urls that may include spaces.
*
* @param url the url
@@ -505,374 +354,6 @@
}
/**
- * Get the options for this file.
- *
- * @param file the file
- * @return options map
- */
- private static Options getOptions(VirtualFile file)
- {
- if (file == null)
- throw new IllegalArgumentException("Null file");
-
- VirtualFileHandler handler = file.getHandler();
- VFSContext context = handler.getVFSContext();
- return context.getOptions();
- }
-
- /**
- * Get the options for this vfs.
- *
- * @param vfs the vfs
- * @return options map
- */
- private static Options getOptions(VFS vfs)
- {
- if (vfs == null)
- throw new IllegalArgumentException("Null vfs");
-
- VFSContext context = vfs.getContext();
- return context.getOptions();
- }
-
- /**
- * Get the option.
- *
- * @param file the file
- * @param key the option key
- * @return key's option
- */
- public static String getOption(VirtualFile file, String key)
- {
- Object option = getOption(file, key, Object.class);
- return option != null ? option.toString() : null;
- }
-
- /**
- * Get the option.
- *
- * @param vfs the vfs
- * @param key the option key
- * @return key's option
- */
- public static String getOption(VFS vfs, String key)
- {
- Object option = getOption(vfs, key, Object.class);
- return option != null ? option.toString() : null;
- }
-
- /**
- * Get the option.
- *
- * @param <T> exact type
- * @param file the file
- * @param key the option key
- * @param exactType the exact type
- * @return key's option
- */
- public static <T> T getOption(VirtualFile file, String key, Class<T> exactType)
- {
- Options options = getOptions(file);
- return options != null ? options.getOption(key, exactType) : null;
- }
-
- /**
- * Get the option.
- *
- * @param <T> exact type
- * @param vfs the vfs
- * @param key the option key
- * @param exactType the exact type
- * @return key's option
- */
- public static <T> T getOption(VFS vfs, String key, Class<T> exactType)
- {
- Options options = getOptions(vfs);
- return options != null ? options.getOption(key, exactType) : null;
- }
-
- /**
- * Enable option.
- *
- * @param file the file
- * @param optionName option name
- */
- protected static void enableOption(VirtualFile file, String optionName)
- {
- Options options = getOptions(file);
- if (options == null)
- throw new IllegalArgumentException("Cannot enable " + optionName + " on null options: " + file);
-
- options.addOption(optionName, Boolean.TRUE);
- }
-
- /**
- * Disable option.
- *
- * @param file the file
- * @param optionName option name
- */
- protected static void disableOption(VirtualFile file, String optionName)
- {
- Options options = getOptions(file);
- if (options == null)
- throw new IllegalArgumentException("Cannot disable " + optionName + " on null options: " + file);
-
- options.removeOption(optionName);
- }
-
- /**
- * Enable option.
- *
- * @param vfs the vfs
- * @param optionName option name
- */
- protected static void enableOption(VFS vfs, String optionName)
- {
- Options options = getOptions(vfs);
- if (options == null)
- throw new IllegalArgumentException("Cannot enable " + optionName + " on null options: " + vfs);
-
- options.addOption(optionName, Boolean.TRUE);
- }
-
- /**
- * Disable option.
- *
- * @param vfs the vfs
- * @param optionName option name
- */
- protected static void disableOption(VFS vfs, String optionName)
- {
- Options options = getOptions(vfs);
- if (options == null)
- throw new IllegalArgumentException("Cannot disable " + optionName + " on null options: " + vfs);
-
- options.removeOption(optionName);
- }
-
- /**
- * Enable copy for file param.
- *
- * @param file the file
- */
- public static void enableCopy(VirtualFile file)
- {
- enableOption(file, USE_COPY_QUERY);
- }
-
- /**
- * Disable copy for file param.
- *
- * @param file the file
- */
- public static void disableCopy(VirtualFile file)
- {
- disableOption(file, USE_COPY_QUERY);
- }
-
- /**
- * Enable copy for vfs param.
- *
- * @param vfs the vfs
- */
- public static void enableCopy(VFS vfs)
- {
- enableOption(vfs, USE_COPY_QUERY);
- }
-
- /**
- * Disable copy for vfs param.
- *
- * @param vfs the vfs
- */
- public static void disableCopy(VFS vfs)
- {
- disableOption(vfs, USE_COPY_QUERY);
- }
-
- /**
- * Enable reaper for file param.
- *
- * @param file the file
- */
- public static void enableNoReaper(VirtualFile file)
- {
- enableOption(file, NO_REAPER_QUERY);
- }
-
- /**
- * Disable reaper for file param.
- *
- * @param file the file
- */
- public static void disableNoReaper(VirtualFile file)
- {
- disableOption(file, NO_REAPER_QUERY);
- }
-
- /**
- * Enable reaper for vfs param.
- *
- * @param vfs the vfs
- */
- public static void enableNoReaper(VFS vfs)
- {
- enableOption(vfs, NO_REAPER_QUERY);
- }
-
- /**
- * Disable reaper for vfs param.
- *
- * @param vfs the vfs
- */
- public static void disableNoReaper(VFS vfs)
- {
- disableOption(vfs, NO_REAPER_QUERY);
- }
-
- /**
- * Enable case sensitive for file param.
- *
- * @param file the file
- */
- public static void enableCaseSensitive(VirtualFile file)
- {
- enableOption(file, CASE_SENSITIVE_QUERY);
- }
-
- /**
- * Disable case sensitive for file param.
- *
- * @param file the file
- */
- public static void disableCaseSensitive(VirtualFile file)
- {
- disableOption(file, CASE_SENSITIVE_QUERY);
- }
-
- /**
- * Enable case sensitive for vfs param.
- *
- * @param vfs the vfs
- */
- public static void enableCaseSensitive(VFS vfs)
- {
- enableOption(vfs, CASE_SENSITIVE_QUERY);
- }
-
- /**
- * Disable case sensitive for vfs param.
- *
- * @param vfs the vfs
- */
- public static void disableCaseSensitive(VFS vfs)
- {
- disableOption(vfs, CASE_SENSITIVE_QUERY);
- }
-
- /**
- * Is the virtual file temporary.
- *
- * @param file the file
- * @return true if temporary, false otherwise
- */
- public static boolean isTemporaryFile(VirtualFile file)
- {
- Options options = getOptions(file);
- return options.getBooleanOption(IS_TEMP_FILE);
- }
-
- /**
- * Unpack the nested artifact under file param.
- *
- * @param file the file to unpack
- * @return unpacked file
- * @throws IOException for any io error
- * @throws URISyntaxException for any uri error
- */
- public static VirtualFile unpack(VirtualFile file) throws IOException, URISyntaxException
- {
- log.warn("Using unpack modification is not yet fully supported - rewire-ing issues.");
- return copy(file, UnpackCopyMechanism.INSTANCE);
- }
-
- /**
- * Force explode.
- * Explode archives or nested entries.
- *
- * @param file the file to explode
- * @return exploded file
- * @throws IOException for any io error
- * @throws URISyntaxException for any uri error
- */
- public static VirtualFile explode(VirtualFile file) throws IOException, URISyntaxException
- {
- return copy(file, ExplodedCopyMechanism.INSTANCE);
- }
-
- /**
- * Create temp.
- *
- * @param file the file to temp
- * @return temp file
- * @throws IOException for any io error
- * @throws URISyntaxException for any uri error
- */
- public static VirtualFile temp(VirtualFile file) throws IOException, URISyntaxException
- {
- return copy(file, TempCopyMechanism.INSTANCE);
- }
-
- /**
- * Unjar.
- *
- * @param file the file to unjar
- * @return temp file
- * @throws IOException for any io error
- * @throws URISyntaxException for any uri error
- */
- public static VirtualFile unjar(VirtualFile file) throws IOException, URISyntaxException
- {
- return copy(file, UnjarCopyMechanism.INSTANCE);
- }
-
- /**
- * Create temp.
- *
- * @param file the file to unpack/explode
- * @param mechanism the copy mechanism
- * @return temp file
- * @throws IOException for any io error
- * @throws URISyntaxException for any uri error
- */
- protected static VirtualFile copy(VirtualFile file, CopyMechanism mechanism) throws IOException, URISyntaxException
- {
- if (file == null)
- throw new IllegalArgumentException("Null file");
- if (mechanism == null)
- throw new IllegalArgumentException("Null copy mechanism");
-
- return mechanism.copy(file, file.getHandler());
- }
-
- /**
- * Is file handle nested.
- *
- * @param file the file handle to check
- * @return true if file/dir is nested otherwise false
- * @throws IOException for any error
- */
- public static boolean isNestedFile(VirtualFile file) throws IOException
- {
- if (file == null)
- throw new IllegalArgumentException("Null file");
-
- VirtualFileHandler handler = file.getHandler();
- return handler.isNested();
- }
-
- /**
* Copy input stream to output stream and close them both
*
* @param is input stream
@@ -918,182 +399,59 @@
}
/**
- * Get spec compatilbe url from virtual file.
+ * Get the virtual URL for a virtual file. This URL can be used to access the virtual file; however, taking the
+ * file part of the URL and attempting to use it with the {@link java.io.File} class may fail if the file is not
+ * present on the physical filesystem, and in general should not be attempted.
*
* @param file the virtual file
- * @return spec compatible url
- * @throws Exception for any error
+ * @return the URL
+ * @throws MalformedURLException if the file cannot be coerced into a URL for some reason
*/
- public static URL getCompatibleURL(VirtualFile file) throws Exception
+ public static URL getVirtualURL(VirtualFile file) throws MalformedURLException
{
- return getCompatibleResource(file, URL_CREATOR);
+ // todo: specify the URL handler directly as a minor optimization
+ return new URL("file", "", -1, file.getPathName());
}
/**
- * Get spec compatilbe uri from virtual file.
+ * Get the virtual URI for a virtual file.
*
* @param file the virtual file
- * @return spec compatible uri
- * @throws Exception for any error
+ * @return the URI
+ * @throws URISyntaxException if the file cannot be coerced into a URI for some reason
*/
- public static URI getCompatibleURI(VirtualFile file) throws Exception
+ public static URI getVirtualURI(VirtualFile file) throws URISyntaxException
{
- return getCompatibleResource(file, URI_CREATOR);
+ return new URI("file", "", file.getPathName(), null);
}
/**
- * Create new compatible resource.
+ * Get a physical URL for a virtual file. See the warnings on the {@link VirtualFile#getPhysicalFile()} method
+ * before using this method.
*
* @param file the virtual file
- * @param creator resoruce creator
- * @return new resource
- * @throws Exception for any error
- * @param <T> exact resource type
+ * @return the physical file URL
+ * @throws IOException if an I/O error occurs getting the physical file
*/
- private static <T> T getCompatibleResource(VirtualFile file, ResourceCreator<T> creator) throws Exception
+ public static URL getPhysicalURL(VirtualFile file) throws IOException
{
- if (file == null)
- throw new IllegalArgumentException("Null file");
- if (creator == null)
- throw new IllegalArgumentException("Null creator");
-
- if (isNestedFile(file))
- {
- return creator.getNestedResource(file);
- }
- else
- {
- // is not nested, so direct VFS resource is not an option
- return creator.getRealResource(file);
- }
+ return getPhysicalURI(file).toURL();
}
/**
- * @param <T> exact resource type
- */
- private static interface ResourceCreator<T>
- {
- /**
- * Get resource from virtual file.
- *
- * @param file the virtual file
- * @return resource instance from file
- * @throws Exception for any error
- */
- T getNestedResource(VirtualFile file) throws Exception;
-
- /**
- * Get real resource from virtual file.
- *
- * @param file the virtual file
- * @return resource instance from file
- * @throws Exception for any error
- */
- T getRealResource(VirtualFile file) throws Exception;
- }
-
- private static final ResourceCreator<URL> URL_CREATOR = new ResourceCreator<URL>()
- {
- public URL getNestedResource(VirtualFile file) throws Exception
- {
- return file.toURL();
- }
-
- public URL getRealResource(VirtualFile file) throws Exception
- {
- return getRealURL(file);
- }
- };
-
- private static final ResourceCreator<URI> URI_CREATOR = new ResourceCreator<URI>()
- {
- public URI getNestedResource(VirtualFile file) throws Exception
- {
- return file.toURI();
- }
-
- public URI getRealResource(VirtualFile file) throws Exception
- {
- return toURI(getRealURL(file));
- }
- };
-
- /**
- * Get real url.
- * The closest thing that doesn't need the vfs url handlers.
+ * Get a physical URI for a virtual file. See the warnings on the {@link VirtualFile#getPhysicalFile()} method
+ * before using this method.
*
* @param file the virtual file
- * @return real url
- * @throws IOException for any error
- * @throws URISyntaxException for any uri syntac error
+ * @return the physical file URL
+ * @throws IOException if an I/O error occurs getting the physical file
*/
- public static URL getRealURL(VirtualFile file) throws IOException, URISyntaxException
+ public static URI getPhysicalURI(VirtualFile file) throws IOException
{
- VirtualFileHandler handler = file.getHandler();
- return handler.getRealURL();
+ return file.getPhysicalFile().toURI();
}
/**
- * Get relative path.
- *
- * @param context the vfs context
- * @param uri the uri
- * @return uri's relative path to context's root
- */
- public static String getRelativePath(VFSContext context, URI uri)
- {
- String uriPath = stripProtocol(uri);
- String contextKey = getKey(context);
- return uriPath.substring(contextKey.length());
- }
-
- /**
- * Strip protocol from url string.
- *
- * @param uri the uri
- * @return uri's path string
- */
- public static String stripProtocol(URI uri)
- {
- String path = uri.getPath();
- if(path == null)
- {
- String s = uri.toString();
- if(s.startsWith("jar:file:"))
- path = s.substring("jar:file:".length()).replaceFirst("!/", "/") + "/";
- }
- if (path != null && path.length() > 0)
- {
- StringBuilder sb = new StringBuilder(path);
-
- if (sb.charAt(0) != '/')
- sb.insert(0, '/');
- if (sb.charAt(sb.length() - 1) != '/')
- sb.append('/');
-
- path = sb.toString();
- }
- else
- {
- path = "/";
- }
-
- return path;
- }
-
- /**
- * Get path key.
- *
- * @param context the vfs context
- * @return contex's root path w/o protocol
- */
- public static String getKey(VFSContext context)
- {
- URI uri = context.getRootURI();
- return stripProtocol(uri);
- }
-
- /**
* Safely close some resource without throwing an exception. Any exception will be logged at TRACE level.
*
* @param c the resource
Modified: projects/vfs/branches/dml-zip-rework/src/main/java/org/jboss/virtual/VirtualFile.java
===================================================================
--- projects/vfs/branches/dml-zip-rework/src/main/java/org/jboss/virtual/VirtualFile.java 2009-07-01 22:28:40 UTC (rev 90752)
+++ projects/vfs/branches/dml-zip-rework/src/main/java/org/jboss/virtual/VirtualFile.java 2009-07-02 01:28:49 UTC (rev 90753)
@@ -19,26 +19,24 @@
* 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 ;
+package org.jboss.virtual;
import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
-import java.net.MalformedURLException;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.net.URL;
+import java.io.File;
import java.util.Collections;
import java.util.List;
-import java.util.Set;
-import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.ArrayList;
import org.jboss.virtual.plugins.vfs.helpers.FilterVirtualFileVisitor;
import org.jboss.virtual.plugins.vfs.helpers.MatchAllVirtualFileFilter;
-import org.jboss.util.collection.WeakSet;
+import org.jboss.virtual.plugins.vfs.helpers.PathTokenizer;
/**
- * A virtual file as seen by the user
+ * A virtual file. This is a symbolic reference to a location in the virtual file system hierarchy. Holding a
+ * {@code VirtualFile} instance gives no guarantees as to the presence or immutability of the referenced file or
+ * any of its parent path elements.
*
* @author Scott.Stark at jboss.org
* @author adrian at jboss.org
@@ -48,126 +46,64 @@
public class VirtualFile implements Serializable
{
private static final long serialVersionUID = 1L;
+ private final String path;
+ private final String name;
+ private final List<String> tokens;
+ private final VFS vfs;
- /** The virtual file handler */
- private final VirtualFileHandler handler;
-
- /** Whether we are closed */
- private final AtomicBoolean closed = new AtomicBoolean(false);
-
- /** The open streams */
- private transient Set<InputStream> streams;
-
- /**
- * Create a new VirtualFile.
- *
- * @param handler the handler
- * @throws IllegalArgumentException if the handler is null
- */
- public VirtualFile(VirtualFileHandler handler)
+ VirtualFile(VFS vfs, List<String> realPath, String realPathString)
{
- if (handler == null)
- throw new IllegalArgumentException("Null handler");
-
- this.handler = handler;
+ path = realPathString;
+ final int size = realPath.size();
+ name = size == 0 ? "" : realPath.get(size - 1);
+ tokens = realPath;
+ this.vfs = vfs;
}
/**
- * Get the virtual file handler
- *
- * @return the handler
- * @throws IllegalStateException if the file is closed or cleaned
- */
- VirtualFileHandler getHandler()
- {
- if (closed.get())
- throw new IllegalStateException("The virtual file is closed");
-
- return handler;
- }
-
- /**
* Get the simple VF name (X.java)
*
* @return the simple file name
- * @throws IllegalStateException if the file is closed
*/
public String getName()
{
- return getHandler().getName();
+ return name;
}
/**
* Get the VFS relative path name (org/jboss/X.java)
*
* @return the VFS relative path name
- * @throws IllegalStateException if the file is closed
*/
public String getPathName()
{
- return getHandler().getPathName();
+ return path;
}
/**
- * Get the VF URL (file://root/org/jboss/X.java)
- *
- * @return the full URL to the VF in the VFS.
- * @throws MalformedURLException if a url cannot be parsed
- * @throws URISyntaxException if a uri cannot be parsed
- * @throws IllegalStateException if the file is closed
- */
- public URL toURL() throws MalformedURLException, URISyntaxException
- {
- return getHandler().toVfsUrl();
- }
-
- /**
- * Get the VF URI (file://root/org/jboss/X.java)
- *
- * @return the full URI to the VF in the VFS.
- * @throws URISyntaxException if a uri cannot be parsed
- * @throws IllegalStateException if the file is closed
- * @throws MalformedURLException for a bad url
- */
- public URI toURI() throws MalformedURLException, URISyntaxException
- {
- return VFSUtils.toURI(toURL());
- }
-
- /**
* When the file was last modified
*
* @return the last modified time
* @throws IOException for any problem accessing the virtual file system
- * @throws IllegalStateException if the file is closed
*/
public long getLastModified() throws IOException
{
- return getHandler().getLastModified();
+ final List<String> tokens = this.tokens;
+ final VFS.Mount mount = vfs.getMount(tokens);
+ return mount.getFileSystem().getLastModified(tokens.subList(mount.getRealMountPoint().size(), tokens.size()));
}
/**
- * Returns true if the file has been modified since this method was last called
- * Last modified time is initialized at handler instantiation.
- *
- * @return true if modifed, false otherwise
- * @throws IOException for any error
- */
- public boolean hasBeenModified() throws IOException
- {
- return getHandler().hasBeenModified();
- }
-
- /**
* Get the size
*
* @return the size
* @throws IOException for any problem accessing the virtual file system
- * @throws IllegalStateException if the file is closed
*/
public long getSize() throws IOException
{
- return getHandler().getSize();
+ final List<String> tokens = this.tokens;
+ final VFS.Mount mount = vfs.getMount(tokens);
+ return mount.getFileSystem().getSize(tokens.subList(mount.getRealMountPoint().size(), tokens.size()));
}
/**
@@ -177,7 +113,9 @@
*/
public boolean exists() throws IOException
{
- return getHandler().exists();
+ final List<String> tokens = this.tokens;
+ final VFS.Mount mount = vfs.getMount(tokens);
+ return mount.getFileSystem().exists(tokens.subList(mount.getRealMountPoint().size(), tokens.size()));
}
/**
@@ -186,34 +124,25 @@
*
* @return true if a simple file.
* @throws IOException for any problem accessing the virtual file system
- * @throws IllegalStateException if the file is closed
+ * @deprecated use {@link #isDirectory()} instead
*/
+ @Deprecated
public boolean isLeaf() throws IOException
{
- return getHandler().isLeaf();
+ return ! isDirectory();
}
/**
- * Is the file archive.
- *
- * @return true if archive, false otherwise
- * @throws IOException for any error
- */
- public boolean isArchive() throws IOException
- {
- return getHandler().isArchive();
- }
-
- /**
- * Whether it is hidden
+ * Determine whether the named virtual file is a directory.
*
- * @return true when hidden
- * @throws IOException for any problem accessing the virtual file system
- * @throws IllegalStateException if the file is closed
+ * @return {@code true} if it is a directory, {@code false} otherwise
+ * @throws IOException if an I/O error occurs
*/
- public boolean isHidden() throws IOException
+ public boolean isDirectory() throws IOException
{
- return getHandler().isHidden();
+ final List<String> tokens = this.tokens;
+ final VFS.Mount mount = vfs.getMount(tokens);
+ return mount.getFileSystem().isDirectory(tokens.subList(mount.getRealMountPoint().size(), tokens.size()));
}
/**
@@ -221,76 +150,15 @@
*
* @return an InputStream for the file contents.
* @throws IOException for any error accessing the file system
- * @throws IllegalStateException if the file is closed
*/
public InputStream openStream() throws IOException
{
- InputStream result = getHandler().openStream();
- checkStreams();
- streams.add(result);
- return result;
+ final List<String> tokens = this.tokens;
+ final VFS.Mount mount = vfs.getMount(tokens);
+ return mount.getFileSystem().openInputStream(tokens.subList(mount.getRealMountPoint().size(), tokens.size()));
}
/**
- * Check if streams set exist.
- */
- @SuppressWarnings("unchecked")
- protected void checkStreams()
- {
- if (streams == null)
- {
- synchronized (closed)
- {
- // double null check, so that possible
- // waiting threads don't override streams
- if (streams == null)
- streams = Collections.synchronizedSet(new WeakSet());
- }
- }
- }
-
- /**
- * Close the streams
- */
- public void closeStreams()
- {
- if (streams == null)
- return;
-
- // Close the streams
- VFSUtils.safeClose(streams);
- streams.clear();
- }
-
- /**
- * Do file cleanup.
- * e.g. delete temp files
- */
- public void cleanup()
- {
- try
- {
- getHandler().cleanup();
- }
- finally
- {
- VFS.cleanup(this);
- }
- }
-
- /**
- * Close the file resources (stream, etc.)
- */
- public void close()
- {
- if (closed.getAndSet(true) == false)
- {
- closeStreams();
- handler.close();
- }
- }
-
- /**
* Delete this virtual file
*
* @return true if file was deleted
@@ -298,47 +166,54 @@
*/
public boolean delete() throws IOException
{
- // gracePeriod of 2 seconds
- return getHandler().delete(2000);
+ final List<String> tokens = this.tokens;
+ final VFS.Mount mount = vfs.getMount(tokens);
+ return mount.getFileSystem().delete(tokens.subList(mount.getRealMountPoint().size(), tokens.size()));
}
/**
- * Delete this virtual file
+ * Get a physical file for this virtual file. Depending on the underlying file system type, this may simply return
+ * an already-existing file; it may create a copy of a file; or it may reuse a preexisting copy of the file. Furthermore,
+ * the retured file may or may not have any relationship to other files from the same or any other virtual
+ * directory.
*
- * @param gracePeriod max time to wait for any locks (in milliseconds)
- * @return true if file was deleted
- * @throws IOException if an error occurs
+ * @return the physical file
+ * @throws IOException if an I/O error occurs while producing the physical file
*/
- public boolean delete(int gracePeriod) throws IOException
+ public File getPhysicalFile() throws IOException
{
- return getHandler().delete(gracePeriod);
+ final List<String> tokens = this.tokens;
+ final VFS.Mount mount = vfs.getMount(tokens);
+ return mount.getFileSystem().getFile(tokens.subList(mount.getRealMountPoint().size(), tokens.size()));
}
/**
* Get the VFS instance for this virtual file
*
* @return the VFS
- * @throws IllegalStateException if the file is closed
*/
public VFS getVFS()
{
- VFSContext context = getHandler().getVFSContext();
- return context.getVFS();
+ return vfs;
}
/**
- * Get the parent
+ * Get a {@code VirtualFile} which represents the parent of this instance.
*
- * @return the parent or null if there is no parent
+ * @return the parent or {@code null} if there is no parent
* @throws IOException for any problem accessing the virtual file system
- * @throws IllegalStateException if the file is closed
*/
public VirtualFile getParent() throws IOException
{
- VirtualFileHandler parent = getHandler().getParent();
- if (parent != null)
- return parent.getVirtualFile();
- return null;
+ final List<String> tokens = this.tokens;
+ final String path = this.path;
+ final int size = tokens.size();
+ if (size == 0)
+ return null;
+ else if (size == 1)
+ return vfs.getRootVirtualFile();
+ else
+ return new VirtualFile(vfs, tokens.subList(0, size - 1), path.substring(0, path.lastIndexOf('/')));
}
/**
@@ -346,7 +221,6 @@
*
* @return the children
* @throws IOException for any problem accessing the virtual file system
- * @throws IllegalStateException if the file is closed
*/
public List<VirtualFile> getChildren() throws IOException
{
@@ -363,7 +237,7 @@
*/
public List<VirtualFile> getChildren(VirtualFileFilter filter) throws IOException
{
- if (isLeaf())
+ if (! isDirectory())
return Collections.emptyList();
if (filter == null)
@@ -399,7 +273,7 @@
*/
public List<VirtualFile> getChildrenRecursively(VirtualFileFilter filter) throws IOException
{
- if (isLeaf())
+ if (! isDirectory())
return Collections.emptyList();
if (filter == null)
@@ -419,75 +293,56 @@
*/
public void visit(VirtualFileVisitor visitor) throws IOException
{
- if (isLeaf() == false)
+ if (! isDirectory() == false)
getVFS().visit(this, visitor);
}
/**
- * Find a child
+ * Get a child virtual file.
*
* @param path the path
- * @return the child
- * @throws IOException for any problem accessing the VFS (including the child does not exist)
- * @throws IllegalArgumentException if the path is null
- * @throws IllegalStateException if the file is closed or it is a leaf node
- * @deprecated use getChild, and handle null if not found
- */
- @Deprecated
- public VirtualFile findChild(String path) throws IOException
- {
- if (path == null)
- throw new IllegalArgumentException("Null path");
-
- VirtualFileHandler handler = getHandler();
- VirtualFileHandler child = handler.getChild(VFSUtils.fixName(path));
- if (child == null)
- {
- List<VirtualFileHandler> children = handler.getChildren(true);
- throw new IOException("Child not found " + path + " for " + handler + ", available children: " + children);
- }
- return child.getVirtualFile();
- }
-
- /**
- * Get a child
- *
- * @param path the path
- * @return the child or <code>null</code> if not found
+ * @return the child or {@code null} if not found
* @throws IOException for any problem accessing the VFS
* @throws IllegalArgumentException if the path is null
- * @throws IllegalStateException if the file is closed or it is a leaf node
*/
public VirtualFile getChild(String path) throws IOException
{
if (path == null)
throw new IllegalArgumentException("Null path");
- VirtualFileHandler handler = getHandler();
- VirtualFileHandler child = handler.getChild(VFSUtils.fixName(path));
- return child != null ? child.getVirtualFile() : null;
+ final List<String> newPathTokens = new ArrayList<String>();
+ newPathTokens.addAll(tokens);
+ PathTokenizer.getTokens(newPathTokens, path);
+ final List<String> childPath = PathTokenizer.applySpecialPaths(newPathTokens);
+ return new VirtualFile(vfs, newPathTokens, PathTokenizer.getRemainingPath(childPath, 0));
}
@Override
public String toString()
{
- return handler.toString();
+ return "Virtual file \"" + path + "\" for " + vfs;
}
@Override
- public int hashCode()
+ public boolean equals(Object o)
{
- return handler.hashCode();
+ if (this == o)
+ return true;
+ if (! (o instanceof VirtualFile))
+ return false;
+ VirtualFile that = (VirtualFile) o;
+ if (! path.equals(that.path))
+ return false;
+ if (vfs != that.vfs)
+ return false;
+ return true;
}
@Override
- public boolean equals(Object obj)
+ public int hashCode()
{
- if (obj == this)
- return true;
- if (obj == null || obj instanceof VirtualFile == false)
- return false;
- VirtualFile other = (VirtualFile) obj;
- return handler.equals(other.handler);
+ int result = path.hashCode();
+ result = 31 * result + vfs.hashCode();
+ return result;
}
}
Modified: projects/vfs/branches/dml-zip-rework/src/main/java/org/jboss/virtual/plugins/vfs/helpers/PathTokenizer.java
===================================================================
--- projects/vfs/branches/dml-zip-rework/src/main/java/org/jboss/virtual/plugins/vfs/helpers/PathTokenizer.java 2009-07-01 22:28:40 UTC (rev 90752)
+++ projects/vfs/branches/dml-zip-rework/src/main/java/org/jboss/virtual/plugins/vfs/helpers/PathTokenizer.java 2009-07-02 01:28:49 UTC (rev 90753)
@@ -22,7 +22,6 @@
package org.jboss.virtual.plugins.vfs.helpers;
import java.io.IOException;
-import java.security.Permission;
import java.util.ArrayList;
import java.util.List;
@@ -43,12 +42,6 @@
/** The reverse path const */
private static final String REVERSE_PATH = "..";
- /** Catch some suspicious tokens */
- private static boolean errorOnSuspiciousTokens;
-
- /** Flag permission */
- private static Permission flagPermission = new RuntimePermission(PathTokenizer.class.getName() + ".setErrorOnSuspiciousTokens");
-
/** Token states */
private static final int STATE_INITIAL = 0;
private static final int STATE_NORMAL = 1;
@@ -96,19 +89,29 @@
*
* @param path the path
* @return the tokens or null if the path is empty
- * @throws IllegalArgumentException if the path is null, or if this class is configured to reject
- * so-called "suspicious" tokens (files that start with "." which are not one of the two special
- * directories "." or "..")
+ * @throws IllegalArgumentException if the path is null
*/
public static List<String> getTokens(String path)
{
if (path == null)
throw new IllegalArgumentException("Null path");
+ List<String> list = new ArrayList<String>();
+ getTokens(list, path);
+ return list;
+ }
+
+ /**
+ * Get the tokens that comprise this path and append them to the list.
+ *
+ * @param path the path
+ * @return the tokens or null if the path is empty
+ * @throws IllegalArgumentException if the path is null
+ */
+ public static void getTokens(List<String> list, String path)
+ {
int start = -1, length = path.length(), state = STATE_INITIAL;
char ch;
- List<String> list = new ArrayList<String>();
-
for (int index = 0; index < length; index ++) {
ch = path.charAt(index);
switch (ch) {
@@ -154,9 +157,6 @@
}
case STATE_MAYBE_REVERSE_PATH: {
// the third . in a row, guess it's just a weird path name
- if (errorOnSuspiciousTokens) {
- throw new IllegalArgumentException("Illegal suspicious token in path: " + path);
- }
state = STATE_NORMAL;
continue;
}
@@ -172,9 +172,6 @@
}
case STATE_MAYBE_CURRENT_PATH:
case STATE_MAYBE_REVERSE_PATH: {
- if (errorOnSuspiciousTokens) {
- throw new IllegalArgumentException("Illegal suspicious token in path: " + path);
- }
state = STATE_NORMAL;
}
}
@@ -200,10 +197,9 @@
break;
}
}
+ return;
+ }
- return list;
- }
-
/**
* Get the remaining path from some tokens
*
@@ -252,6 +248,28 @@
}
/**
+ * Apply any . or .. paths in the pathTokens parameter, returning the minimal token list.
+ *
+ * @param pathTokens the path tokens
+ * @return the simple path tokens
+ * @throws IOException if reverse path goes over the top path
+ */
+ public static List<String> applySpecialPaths(List<String> pathTokens) throws IOException
+ {
+ final ArrayList<String> newTokens = new ArrayList<String>();
+ for (String pathToken : pathTokens)
+ {
+ if (isCurrentToken(pathToken))
+ continue;
+ else if (isReverseToken(pathToken))
+ newTokens.remove(newTokens.size() - 1);
+ else
+ newTokens.add(pathToken);
+ }
+ return newTokens;
+ }
+
+ /**
* Is current token.
*
* @param token the token to check
@@ -272,18 +290,4 @@
{
return REVERSE_PATH == token;
}
-
- /**
- * Set errorOnSuspiciousTokens flag.
- *
- * @param errorOnSuspiciousTokens the errorOnSuspiciousTokens flag
- */
- public static void setErrorOnSuspiciousTokens(boolean errorOnSuspiciousTokens)
- {
- SecurityManager sm = System.getSecurityManager();
- if (sm != null)
- sm.checkPermission(flagPermission);
-
- PathTokenizer.errorOnSuspiciousTokens = errorOnSuspiciousTokens;
- }
}
Modified: projects/vfs/branches/dml-zip-rework/src/main/java/org/jboss/virtual/protocol/vfs/Handler.java
===================================================================
--- projects/vfs/branches/dml-zip-rework/src/main/java/org/jboss/virtual/protocol/vfs/Handler.java 2009-07-01 22:28:40 UTC (rev 90752)
+++ projects/vfs/branches/dml-zip-rework/src/main/java/org/jboss/virtual/protocol/vfs/Handler.java 2009-07-02 01:28:49 UTC (rev 90753)
@@ -27,7 +27,6 @@
import java.net.URLStreamHandler;
import org.jboss.virtual.VirtualFile;
-import org.jboss.virtual.AssembledDirectory;
import org.jboss.virtual.plugins.vfs.VirtualFileURLConnection;
/**
Modified: projects/vfs/branches/dml-zip-rework/src/main/java/org/jboss/virtual/protocol/vfsmemory/Handler.java
===================================================================
--- projects/vfs/branches/dml-zip-rework/src/main/java/org/jboss/virtual/protocol/vfsmemory/Handler.java 2009-07-01 22:28:40 UTC (rev 90752)
+++ projects/vfs/branches/dml-zip-rework/src/main/java/org/jboss/virtual/protocol/vfsmemory/Handler.java 2009-07-02 01:28:49 UTC (rev 90753)
@@ -26,7 +26,6 @@
import java.net.URLConnection;
import java.net.URLStreamHandler;
-import org.jboss.virtual.MemoryFileFactory;
import org.jboss.virtual.VFS;
import org.jboss.virtual.VirtualFile;
import org.jboss.virtual.plugins.vfs.VirtualFileURLConnection;
Added: projects/vfs/branches/dml-zip-rework/src/main/java/org/jboss/virtual/spi/FileSystem.java
===================================================================
--- projects/vfs/branches/dml-zip-rework/src/main/java/org/jboss/virtual/spi/FileSystem.java (rev 0)
+++ projects/vfs/branches/dml-zip-rework/src/main/java/org/jboss/virtual/spi/FileSystem.java 2009-07-02 01:28:49 UTC (rev 90753)
@@ -0,0 +1,97 @@
+/*
+ * 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.virtual.spi;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.Closeable;
+import java.io.InputStream;
+import java.util.List;
+import java.util.Iterator;
+
+/**
+ * A file system which is mounted in to the VFS. This is the driver class for a given virtual file system type. An
+ * instance of {@code FileSystem} will be mounted at some point on a VFS. The specific instance is only called when
+ * a file from this filesystem is called upon. The path components passed in to the operations are canonical, with
+ * no "." or ".." components.
+ */
+public interface FileSystem extends Closeable
+{
+ /**
+ * Get a real {@code File} for the given path within this filesystem. Some filesystem types will need to make a copy
+ * in order to return this file; such copies should be cached and retained until the filesystem is closed. Depending
+ * on the file type, the real path of the returned {@code File} may or may not bear a relationship to the virtual path
+ * provided; if such a relationship is required, it must be negotiated at the time the filesystem is mounted.
+ *
+ * @param pathComponents the relative path components
+ * @return the file instance
+ * @throws IOException if an I/O error occurs
+ */
+ File getFile(List<String> pathComponents) throws IOException;
+
+ /**
+ * Open an input stream for the file at the given relative path.
+ *
+ * @param pathComponents the relative path components
+ * @return the input stream
+ * @throws IOException if an I/O error occurs
+ */
+ InputStream openInputStream(List<String> pathComponents) throws IOException;
+
+ /**
+ * Determine whether this filesystem is read-only. A read-only filesystem prohibits file modification or
+ * deletion. It is not an error to mount a read-write filesystem within a read-only filesystem however (this
+ * operation does not take place within the {@code FileSystem} implementation).
+ *
+ * @return {@code true} if the filesystem is read-only
+ */
+ boolean isReadOnly();
+
+ boolean delete(List<String> pathComponents) throws IOException;
+
+ long getSize(List<String> pathComponents) throws IOException;
+
+ long getLastModified(List<String> pathComponents) throws IOException;
+
+ boolean exists(List<String> pathComponents) throws IOException;
+
+ boolean isDirectory(List<String> pathComponents) throws IOException;
+
+ /**
+ * Read a directory. Returns all the simple path names (excluding "." and "..").
+ *
+ * @param directoryPathComponents the relative path components for the directory
+ * @return the directory entries, or {@code null} if the specified path does not refer to a directory
+ * @throws IOException if an I/O error occurs
+ */
+ Iterator<String> getDirectoryEntries(List<String> directoryPathComponents) throws IOException;
+
+ /**
+ * Destroy this filesystem instance. After this method is called, the filesystem may not be used in any way. This
+ * method should be called only after all mounts of this filesystem have been cleared; otherwise, VFS accesses may
+ * result in {@code IOException}s.
+ *
+ * @throws IOException if an I/O error occurs during close
+ */
+ void close() throws IOException;
+}
Added: projects/vfs/branches/dml-zip-rework/src/main/java/org/jboss/virtual/spi/RealFileSystem.java
===================================================================
--- projects/vfs/branches/dml-zip-rework/src/main/java/org/jboss/virtual/spi/RealFileSystem.java (rev 0)
+++ projects/vfs/branches/dml-zip-rework/src/main/java/org/jboss/virtual/spi/RealFileSystem.java 2009-07-02 01:28:49 UTC (rev 90753)
@@ -0,0 +1,114 @@
+/*
+ * 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.virtual.spi;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.FileInputStream;
+import java.util.List;
+import java.util.Iterator;
+import java.util.Arrays;
+import java.util.Collections;
+
+public final class RealFileSystem implements FileSystem
+{
+ public static final RealFileSystem ROOT_INSTANCE = new RealFileSystem(Collections.<String>emptyList());
+
+ private final String base;
+
+ private RealFileSystem(List<String> baseComponents)
+ {
+ base = implode("", baseComponents) + File.separator;
+ }
+
+ public File getFile(List<String> pathComponents) throws IOException
+ {
+ return new File(implode(base, pathComponents));
+ }
+
+ private static String implode(String base, List<String> pathComponents)
+ {
+ int l = 0;
+ for (String s : pathComponents)
+ {
+ l += s.length() + 1;
+ }
+ if (l == 0) {
+ return base;
+ }
+ final StringBuilder builder = new StringBuilder(l + base.length());
+ builder.append(base);
+ for (String s : pathComponents)
+ {
+ builder.append(File.separatorChar);
+ builder.append(s);
+ }
+ return builder.toString();
+ }
+
+ public InputStream openInputStream(List<String> pathComponents) throws IOException
+ {
+ return new FileInputStream(getFile(pathComponents));
+ }
+
+ public boolean isReadOnly()
+ {
+ return false;
+ }
+
+ public boolean delete(List<String> pathComponents) throws IOException
+ {
+ return getFile(pathComponents).delete();
+ }
+
+ public long getSize(List<String> pathComponents) throws IOException
+ {
+ return getFile(pathComponents).length();
+ }
+
+ public long getLastModified(List<String> pathComponents) throws IOException
+ {
+ return getFile(pathComponents).lastModified();
+ }
+
+ public boolean exists(List<String> pathComponents) throws IOException
+ {
+ return getFile(pathComponents).exists();
+ }
+
+ public boolean isDirectory(List<String> pathComponents) throws IOException
+ {
+ return getFile(pathComponents).isDirectory();
+ }
+
+ public Iterator<String> getDirectoryEntries(List<String> directoryPathComponents) throws IOException
+ {
+ return Arrays.asList(getFile(directoryPathComponents).list()).iterator();
+ }
+
+ public void close() throws IOException
+ {
+ // no operation - the real FS can't be closed
+ }
+}
Added: projects/vfs/branches/dml-zip-rework/src/main/java/org/jboss/virtual/spi/ZipFileSystem.java
===================================================================
--- projects/vfs/branches/dml-zip-rework/src/main/java/org/jboss/virtual/spi/ZipFileSystem.java (rev 0)
+++ projects/vfs/branches/dml-zip-rework/src/main/java/org/jboss/virtual/spi/ZipFileSystem.java 2009-07-02 01:28:49 UTC (rev 90753)
@@ -0,0 +1,230 @@
+/*
+ * 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.virtual.spi;
+
+import org.jboss.jzipfile.ZipEntry;
+import org.jboss.jzipfile.Zip;
+import org.jboss.jzipfile.ZipCatalog;
+import org.jboss.jzipfile.ZipEntryType;
+import org.jboss.virtual.plugins.vfs.helpers.PathTokenizer;
+import org.jboss.virtual.VFSUtils;
+import org.jboss.virtual.TempFileProvider;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.FileInputStream;
+import java.util.List;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Collection;
+import java.util.HashMap;
+
+/**
+ * {@inheritDoc}
+ * <p/>
+ * This implementation is backed by a zip file. The provided file must be owned by this instance; otherwise, if the file
+ * disappears unexpectedly, the filesystem will malfunction.
+ */
+public final class ZipFileSystem implements FileSystem
+{
+ private final File zipFile;
+ private final ZipNode rootNode;
+ private final TempFileProvider tempFileProvider;
+
+ /**
+ * Create a new instance.
+ *
+ * @param name the name of the source archive
+ * @param inputStream an input stream from the source archive
+ * @param tempFileProvider the temp file provider to use
+ * @throws IOException if an I/O error occurs
+ */
+ public ZipFileSystem(String name, InputStream inputStream, TempFileProvider tempFileProvider) throws IOException {
+ this(tempFileProvider.createTempFile(name, name.hashCode(), inputStream), tempFileProvider);
+ }
+
+ public ZipFileSystem(File zipFile, TempFileProvider tempFileProvider) throws IOException
+ {
+ this.zipFile = zipFile;
+ this.tempFileProvider = tempFileProvider;
+ final ZipCatalog catalog = Zip.readCatalog(zipFile);
+ final Collection<ZipEntry> entries = catalog.allEntries();
+ final ZipNode rootNode = new ZipNode(new HashMap<String, ZipNode>(), null);
+ for (ZipEntry zipEntry : entries)
+ {
+ final List<String> tokens = PathTokenizer.getTokens(zipEntry.getName());
+ ZipNode node = rootNode;
+ final Iterator<String> it = tokens.iterator();
+ while (it.hasNext())
+ {
+ String token = it.next();
+ final Map<String, ZipNode> children = node.children;
+ ZipNode child = children.get(token);
+ if (child == null)
+ {
+ child = it.hasNext() || zipEntry.getEntryType() == ZipEntryType.DIRECTORY ? new ZipNode(new HashMap<String, ZipNode>(), null) : new ZipNode(null, zipEntry);
+ }
+ }
+ }
+ this.rootNode = rootNode;
+ }
+
+ public File getFile(List<String> pathComponents) throws IOException
+ {
+ final ZipNode zipNode = getExistingZipNode(pathComponents);
+
+ // check if we have cached one already
+ File cachedFile = zipNode.cachedFile;
+ if (cachedFile != null) {
+ return cachedFile;
+ }
+ synchronized (zipNode) {
+ // double-check
+ cachedFile = zipNode.cachedFile;
+ if (cachedFile != null) {
+ return cachedFile;
+ }
+
+ // nope, create a cached temp
+ final ZipEntry zipEntry = getNodeEntry(zipNode);
+ final String name = zipEntry.getName();
+ cachedFile = tempFileProvider.createTempFile(name, zipEntry.hashCode());
+ VFSUtils.copyStreamAndClose(Zip.openEntry(zipFile, zipEntry), new FileOutputStream(cachedFile));
+ zipNode.cachedFile = cachedFile;
+ return cachedFile;
+ }
+ }
+
+ public InputStream openInputStream(List<String> pathComponents) throws IOException
+ {
+ final ZipNode zipNode = getExistingZipNode(pathComponents);
+ final File cachedFile = zipNode.cachedFile;
+ if (cachedFile != null) {
+ return new FileInputStream(cachedFile);
+ }
+ final ZipEntry entry = getNodeEntry(zipNode);
+ return Zip.openEntry(zipFile, entry);
+ }
+
+ private ZipEntry getFileEntry(List<String> pathComponents)
+ throws IOException
+ {
+ final ZipNode zipNode = getExistingZipNode(pathComponents);
+ return getNodeEntry(zipNode);
+ }
+
+ private ZipEntry getNodeEntry(ZipNode zipNode)
+ throws IOException
+ {
+ final ZipEntry entry = zipNode.entry;
+ if (entry == null) {
+ throw new IOException("Cannot call this operation on a directory");
+ }
+ return entry;
+ }
+
+ private ZipNode getExistingZipNode(List<String> pathComponents)
+ throws FileNotFoundException
+ {
+ final ZipNode zipNode = rootNode.find(pathComponents.iterator());
+ if (zipNode == null) {
+ throw new FileNotFoundException();
+ }
+ return zipNode;
+ }
+
+ public boolean isReadOnly()
+ {
+ return true;
+ }
+
+ public boolean delete(List<String> pathComponents) throws IOException
+ {
+ return false;
+ }
+
+ public long getSize(List<String> pathComponents) throws IOException
+ {
+ final ZipEntry entry = getFileEntry(pathComponents);
+ return entry.getSize();
+ }
+
+ public long getLastModified(List<String> pathComponents) throws IOException
+ {
+ final ZipNode zipNode = getExistingZipNode(pathComponents);
+ final ZipEntry entry = zipNode.entry;
+ if (entry != null) {
+ return entry.getModificationTime();
+ } else {
+ return 0L;
+ }
+ }
+
+ public boolean exists(List<String> pathComponents) throws IOException
+ {
+ return rootNode.find(pathComponents.iterator()) != null;
+ }
+
+ public boolean isDirectory(List<String> pathComponents) throws IOException
+ {
+ final ZipNode zipNode = rootNode.find(pathComponents.iterator());
+ return zipNode != null && zipNode.children != null;
+ }
+
+ public Iterator<String> getDirectoryEntries(List<String> directoryPathComponents) throws IOException
+ {
+ return null;
+ }
+
+ public void close() throws IOException
+ {
+
+ }
+
+ private static final class ZipNode {
+ private final Map<String, ZipNode> children;
+ private final ZipEntry entry;
+ private volatile File cachedFile;
+
+ private ZipNode(Map<String, ZipNode> children, ZipEntry entry)
+ {
+ this.children = children;
+ this.entry = entry;
+ }
+
+ private ZipNode find(Iterator<String> node) {
+ if (node.hasNext())
+ {
+ final ZipNode next = children.get(node.next());
+ return next == null ? null : next.find(node);
+ }
+ else
+ {
+ return this;
+ }
+ }
+ }
+}
Modified: projects/vfs/branches/dml-zip-rework/src/test/java/org/jboss/test/virtual/test/AssembledContextTestCase.java
===================================================================
--- projects/vfs/branches/dml-zip-rework/src/test/java/org/jboss/test/virtual/test/AssembledContextTestCase.java 2009-07-01 22:28:40 UTC (rev 90752)
+++ projects/vfs/branches/dml-zip-rework/src/test/java/org/jboss/test/virtual/test/AssembledContextTestCase.java 2009-07-02 01:28:49 UTC (rev 90753)
@@ -27,7 +27,6 @@
import junit.framework.Test;
import org.jboss.virtual.VirtualFile;
-import org.jboss.virtual.AssembledDirectory;
/**
* comment
Modified: projects/vfs/branches/dml-zip-rework/src/test/java/org/jboss/test/virtual/test/FileVFSUnitTestCase.java
===================================================================
--- projects/vfs/branches/dml-zip-rework/src/test/java/org/jboss/test/virtual/test/FileVFSUnitTestCase.java 2009-07-01 22:28:40 UTC (rev 90752)
+++ projects/vfs/branches/dml-zip-rework/src/test/java/org/jboss/test/virtual/test/FileVFSUnitTestCase.java 2009-07-02 01:28:49 UTC (rev 90753)
@@ -50,7 +50,6 @@
import org.jboss.test.virtual.support.ClassPathIterator;
import org.jboss.test.virtual.support.MetaDataMatchFilter;
import org.jboss.test.virtual.support.ClassPathIterator.ClassPathEntry;
-import org.jboss.virtual.MemoryFileFactory;
import org.jboss.virtual.VFS;
import org.jboss.virtual.VFSUtils;
import org.jboss.virtual.VirtualFile;
Modified: projects/vfs/branches/dml-zip-rework/src/test/java/org/jboss/test/virtual/test/MemoryTestCase.java
===================================================================
--- projects/vfs/branches/dml-zip-rework/src/test/java/org/jboss/test/virtual/test/MemoryTestCase.java 2009-07-01 22:28:40 UTC (rev 90752)
+++ projects/vfs/branches/dml-zip-rework/src/test/java/org/jboss/test/virtual/test/MemoryTestCase.java 2009-07-02 01:28:49 UTC (rev 90753)
@@ -33,7 +33,6 @@
import junit.framework.Test;
import org.jboss.util.collection.Iterators;
import org.jboss.util.id.GUID;
-import org.jboss.virtual.MemoryFileFactory;
import org.jboss.virtual.VFS;
import org.jboss.virtual.VirtualFile;
More information about the jboss-cvs-commits
mailing list