[jboss-cvs] JBossAS SVN: r91185 - in projects/vfs/branches/dml-zip-rework/src/main/java/org/jboss/virtual: spi and 1 other directory.
jboss-cvs-commits at lists.jboss.org
jboss-cvs-commits at lists.jboss.org
Tue Jul 14 00:56:40 EDT 2009
Author: david.lloyd at jboss.com
Date: 2009-07-14 00:56:39 -0400 (Tue, 14 Jul 2009)
New Revision: 91185
Added:
projects/vfs/branches/dml-zip-rework/src/main/java/org/jboss/virtual/spi/EnumerationIterable.java
projects/vfs/branches/dml-zip-rework/src/main/java/org/jboss/virtual/spi/EnumerationIterator.java
projects/vfs/branches/dml-zip-rework/src/main/java/org/jboss/virtual/spi/JZipFileSystem.java
projects/vfs/branches/dml-zip-rework/src/main/java/org/jboss/virtual/spi/JavaZipFileSystem.java
Removed:
projects/vfs/branches/dml-zip-rework/src/main/java/org/jboss/virtual/spi/ZipFileSystem.java
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/VirtualFile.java
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
Log:
Fix really a lot of bugs; rewrite for performance
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-14 02:44:23 UTC (rev 91184)
+++ projects/vfs/branches/dml-zip-rework/src/main/java/org/jboss/virtual/VFS.java 2009-07-14 04:56:39 UTC (rev 91185)
@@ -26,14 +26,17 @@
import java.util.List;
import java.util.Collections;
import java.util.Map;
+import java.util.Set;
+import java.util.HashSet;
import java.util.Iterator;
+import java.util.Collection;
+import java.util.AbstractSet;
import java.util.HashMap;
-import java.util.ArrayList;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.ConcurrentHashMap;
-import org.jboss.logging.Logger;
import org.jboss.virtual.spi.RealFileSystem;
import org.jboss.virtual.spi.FileSystem;
-import org.jboss.virtual.plugins.vfs.helpers.PathTokenizer;
/**
* Virtual File System
@@ -45,13 +48,14 @@
*/
public class VFS
{
- /** The log */
- private static final Logger log = Logger.getLogger(VFS.class);
-
- private final MountNode rootMountNode = new MountNode();
+ private final ConcurrentMap<VirtualFile, Map<String, Mount>> mounts = new ConcurrentHashMap<VirtualFile, Map<String, Mount>>();
private final VirtualFile rootVirtualFile;
+ private final Mount rootMount;
private static VFS instance = new VFS();
+ // todo - LRU VirtualFiles?
+ // todo - LRU String intern?
+
static
{
init();
@@ -73,10 +77,9 @@
public VFS()
{
// By default, there's a root mount which points to the "real" FS
- final List<String> emptyList = Collections.<String>emptyList();
- rootMountNode.mount = new Mount(RealFileSystem.ROOT_INSTANCE, emptyList);
//noinspection ThisEscapedInObjectConstruction
- rootVirtualFile = new VirtualFile(this, emptyList, "");
+ rootVirtualFile = new VirtualFile(this, "", null);
+ rootMount = new Mount(RealFileSystem.ROOT_INSTANCE, rootVirtualFile);
}
/**
@@ -113,42 +116,32 @@
* @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
*/
- public Closeable mount(String mountPoint, FileSystem fileSystem) throws IOException {
- final List<String> realMountPoint = PathTokenizer.applySpecialPaths(PathTokenizer.getTokens(mountPoint));
- MountNode mountNode = rootMountNode;
- for (String seg : realMountPoint)
- {
- synchronized (mountNode) {
- Map<String, MountNode> childMap = mountNode.nodeMap;
- MountNode subNode;
- if (childMap == null) {
- childMap = new HashMap<String, MountNode>();
- subNode = new MountNode();
- childMap.put(seg, subNode);
- mountNode.nodeMap = childMap;
- mountNode = subNode;
- } else {
- subNode = childMap.get(seg);
- if (subNode != null) {
- mountNode = subNode;
- } else {
- childMap = new HashMap<String, MountNode>(childMap);
- subNode = new MountNode();
- childMap.put(seg, subNode);
- mountNode.nodeMap = childMap;
- mountNode = subNode;
- }
+ public Closeable mount(VirtualFile mountPoint, FileSystem fileSystem) throws IOException {
+ if (mountPoint.getVFS() != this) {
+ throw new IOException("VirtualFile does not match VFS instance");
+ }
+ final VirtualFile parent = mountPoint.getParent();
+ if (parent == null) {
+ throw new IOException("Root filsystem already mounted");
+ }
+ final String name = mountPoint.getName();
+ final Mount mount = new Mount(fileSystem, mountPoint);
+ for (;;) {
+ Map<String, Mount> childMountMap = mounts.get(parent);
+ Map<String, Mount> newMap;
+ if (childMountMap == null) {
+ childMountMap = mounts.putIfAbsent(parent, Collections.singletonMap(name, mount));
+ if (childMountMap == null) {
+ return mount;
}
}
- }
- synchronized (mountNode) {
- if (mountNode.mount != null) {
+ newMap = new HashMap<String, Mount>(childMountMap);
+ if (newMap.put(name, mount) != null) {
throw new IOException("Filsystem already mounted at mount point \"" + mountPoint + "\"");
}
- final Mount mount = new Mount(fileSystem, realMountPoint);
- mountNode.mount = mount;
- log.debugf("Created mount %s for %s on %s at mount point '%s'", mount, fileSystem, this, mountPoint);
- return mount;
+ if (mounts.replace(parent, childMountMap, newMap)) {
+ return mount;
+ }
}
}
@@ -164,9 +157,7 @@
{
if (path == null)
throw new IllegalArgumentException("Null path");
- final List<String> realPath = PathTokenizer.applySpecialPaths(PathTokenizer.getTokens(path));
- final String realPathString = PathTokenizer.getRemainingPath(realPath, 0);
- return new VirtualFile(this, realPath, realPathString);
+ return rootVirtualFile.getChild(path);
}
/**
@@ -260,63 +251,75 @@
visitor.visit(file);
}
- /**
- * Get the enclosing mounted FileSystem for the given path.
- *
- * @param pathTokens the path tokens
- * @return the filesystem
- */
- Mount getMount(List<String> pathTokens)
- {
- MountNode mountNode = rootMountNode;
- Mount mount = mountNode.mount;
- for (String pathToken : pathTokens)
- {
- final Map<String, MountNode> childMap = mountNode.nodeMap;
- if (childMap != null) {
- mountNode = childMap.get(pathToken);
- final Mount subMount = mountNode.mount;
- if (subMount != null) {
- mount = subMount;
- }
+ Mount getMount(VirtualFile virtualFile) {
+ final ConcurrentMap<VirtualFile, Map<String, Mount>> mounts = this.mounts;
+ for (;;) {
+ final VirtualFile parent = virtualFile.getParent();
+ if (parent == null) {
+ return rootMount;
+ }
+ final Map<String, Mount> parentMounts = mounts.get(parent);
+ if (parentMounts == null) {
+ virtualFile = parent;
} else {
- break;
+ final Mount mount = parentMounts.get(virtualFile.getName());
+ if (mount == null) {
+ virtualFile = parent;
+ } else {
+ return mount;
+ }
}
}
- return mount;
}
/**
* Get all immediate submounts for a path.
*
- * @param tokens the path tokens
+ * @param virtualFile the path
* @return the collection of present mount (simple) names
*/
- Iterator<String> getSubmounts(List<String> tokens)
+ Set<String> getSubmounts(VirtualFile virtualFile)
{
- MountNode mountNode = rootMountNode;
- for (String pathToken : tokens)
+ final ConcurrentMap<VirtualFile, Map<String, Mount>> mounts = this.mounts;
+ final Map<String, Mount> mountMap = mounts.get(virtualFile);
+ if (mountMap == null) {
+ return emptyRemovableSet();
+ }
+ return new HashSet<String>(mountMap.keySet());
+ }
+
+ @SuppressWarnings({ "unchecked" })
+ private static <E> Set<E> emptyRemovableSet() {
+ return EMPTY_REMOVABLE_SET;
+ }
+
+ private static final Set EMPTY_REMOVABLE_SET = new EmptyRemovableSet();
+
+ private static final class EmptyRemovableSet<E> extends AbstractSet<E> {
+
+ public boolean remove(Object o)
{
- final Map<String, MountNode> childMap = mountNode.nodeMap;
- if (childMap != null) {
- mountNode = childMap.get(pathToken);
- } else {
- return Collections.<String>emptyList().iterator();
- }
+ return false;
}
- final List<String> list = new ArrayList<String>();
- final Map<String, MountNode> childMap = mountNode.nodeMap;
- if (childMap == null) {
- return Collections.<String>emptySet().iterator();
+
+ public boolean retainAll(Collection<?> c)
+ {
+ return false;
}
- for (Map.Entry<String, MountNode> entry : childMap.entrySet())
+
+ public void clear()
{
- final MountNode subNode = entry.getValue();
- if (subNode.mount != null) {
- list.add(entry.getKey());
- }
}
- return list.iterator();
+
+ public Iterator<E> iterator()
+ {
+ return Collections.<E>emptySet().iterator();
+ }
+
+ public int size()
+ {
+ return 0;
+ }
}
/**
@@ -326,61 +329,50 @@
*/
final class Mount implements Closeable {
private final FileSystem fileSystem;
- private final List<String> realMountPoint;
+ private final VirtualFile mountPoint;
- private Mount(FileSystem fileSystem, List<String> realMountPoint)
+ Mount(FileSystem fileSystem, VirtualFile mountPoint)
{
this.fileSystem = fileSystem;
- this.realMountPoint = realMountPoint;
+ this.mountPoint = mountPoint;
}
public void close() throws IOException
{
- unmountFrom(rootMountNode, realMountPoint.iterator());
- }
-
- private boolean unmountFrom(MountNode node, Iterator<String> iter)
- {
- synchronized (node) {
- final Map<String, MountNode> nodeMap = node.nodeMap;
- if (iter.hasNext()) {
- if (nodeMap != null) {
- final String key = iter.next();
- final MountNode nextNode = nodeMap.get(key);
- if (nextNode == null) {
- return nodeMap.isEmpty();
- }
- final boolean emptySubNode = unmountFrom(nextNode, iter);
- if (emptySubNode) {
- final boolean otherChildren = nodeMap.size() > 1;
- // subnode is dead; remove it from our map
- if (otherChildren) {
- // there's other children; not dead yet
- final HashMap<String, MountNode> newMap = new HashMap<String, MountNode>(nodeMap);
- newMap.remove(key);
- node.nodeMap = newMap;
- return false;
- } else {
- // no other children; dead if there's no mount here
- node.nodeMap = null;
- return node.mount == null;
- }
- }
- // subnode isn't empty; not dead
- return false;
+ final String name = mountPoint.getName();
+ final VirtualFile parent = mountPoint.getParent();
+ final ConcurrentMap<VirtualFile, Map<String, Mount>> mounts = VFS.this.mounts;
+ for (;;) {
+ final Map<String, Mount> parentMounts = mounts.get(parent);
+ if (parentMounts == null) {
+ return;
+ }
+ final VFS.Mount mount = parentMounts.get(name);
+ if (mount != this) {
+ return;
+ }
+ final Map<String, Mount> newParentMounts;
+ if (parentMounts.size() == 2) {
+ final Iterator<Map.Entry<String, Mount>> ei = parentMounts.entrySet().iterator();
+ final Map.Entry<String, Mount> e1 = ei.next();
+ if (e1.getKey().equals(name)) {
+ final Map.Entry<String, Mount> e2 = ei.next();
+ newParentMounts = Collections.singletonMap(e2.getKey(), e2.getValue());
} else {
- // dead node if there's no mount here
- return node.mount == null;
+ newParentMounts = Collections.singletonMap(e1.getKey(), e1.getValue());
}
+ if (mounts.replace(parent, parentMounts, newParentMounts)) {
+ return;
+ }
+ } else if (parentMounts.size() == 1) {
+ if (mounts.remove(parent, parentMounts)) {
+ return;
+ }
} else {
- if (node.mount == this) {
- node.mount = null;
- log.debugf("Unmounted %s for %s on %s", this, fileSystem, this);
- // the node is dead if there are no children
- return nodeMap == null;
- } else {
- // Node must be already unmounted; do cleanup work anyway.
- return node.mount == null && nodeMap == null;
+ newParentMounts = new HashMap<String, Mount>(parentMounts);
+ newParentMounts.remove(name);
+ if (mounts.replace(parent, parentMounts, newParentMounts)) {
+ return;
}
}
}
@@ -391,29 +383,9 @@
return fileSystem;
}
- List<String> getRealMountPoint()
+ VirtualFile getMountPoint()
{
- return realMountPoint;
+ return mountPoint;
}
}
-
- /**
- * A mount point node. These nodes form a tree of possible mount points.
- */
- private static final class MountNode {
-
- /**
- * The immutable node map. Since the map is immutable, changes to this field must be accomplished by replacing
- * the field value with a new map (copy on write). Modifications to this field are protected by {@code this}.
- */
- private volatile Map<String, MountNode> nodeMap;
- /**
- * The current mount at this point. Modifications to this field are protected by {@code this}.
- */
- private volatile Mount mount;
-
- private MountNode()
- {
- }
- }
}
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-14 02:44:23 UTC (rev 91184)
+++ projects/vfs/branches/dml-zip-rework/src/main/java/org/jboss/virtual/VirtualFile.java 2009-07-14 04:56:39 UTC (rev 91185)
@@ -28,9 +28,7 @@
import java.util.Collections;
import java.util.List;
import java.util.ArrayList;
-import java.util.Iterator;
import java.util.Set;
-import java.util.HashSet;
import org.jboss.virtual.plugins.vfs.helpers.FilterVirtualFileVisitor;
import org.jboss.virtual.plugins.vfs.helpers.MatchAllVirtualFileFilter;
@@ -49,18 +47,21 @@
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 String lcname;
private final VFS vfs;
+ private final VirtualFile parent;
+ private final int hashCode;
- VirtualFile(VFS vfs, List<String> realPath, String realPathString)
+ VirtualFile(VFS vfs, String name, VirtualFile parent)
{
- path = realPathString;
- final int size = realPath.size();
- name = size == 0 ? "" : realPath.get(size - 1);
- tokens = realPath;
+ this.name = name;
+ lcname = name.toLowerCase();
this.vfs = vfs;
+ this.parent = parent;
+ int result = parent == null ? vfs.hashCode() : parent.hashCode();
+ result = 31 * result + name.hashCode();
+ hashCode = result;
}
/**
@@ -73,14 +74,30 @@
return name;
}
+ public String getLowerCaseName()
+ {
+ return lcname;
+ }
+
/**
- * Get the VFS relative path name (org/jboss/X.java)
+ * Get the absolute VFS full path name (/xxx/yyy/foo.ear/baz.jar/org/jboss/X.java)
*
* @return the VFS relative path name
*/
public String getPathName()
{
- return path;
+ final StringBuilder builder = new StringBuilder(160);
+ final VirtualFile parent = this.parent;
+ if (parent == null) {
+ return "/";
+ } else {
+ builder.append(parent.getPathName());
+ if (parent.parent != null) {
+ builder.append('/');
+ }
+ builder.append(name);
+ }
+ return builder.toString();
}
/**
@@ -91,9 +108,8 @@
*/
public long getLastModified() throws IOException
{
- final List<String> tokens = this.tokens;
- final VFS.Mount mount = vfs.getMount(tokens);
- return mount.getFileSystem().getLastModified(tokens.subList(mount.getRealMountPoint().size(), tokens.size()));
+ final VFS.Mount mount = vfs.getMount(this);
+ return mount.getFileSystem().getLastModified(mount.getMountPoint(), this);
}
/**
@@ -104,9 +120,8 @@
*/
public long getSize() throws IOException
{
- final List<String> tokens = this.tokens;
- final VFS.Mount mount = vfs.getMount(tokens);
- return mount.getFileSystem().getSize(tokens.subList(mount.getRealMountPoint().size(), tokens.size()));
+ final VFS.Mount mount = vfs.getMount(this);
+ return mount.getFileSystem().getSize(mount.getMountPoint(), this);
}
/**
@@ -116,9 +131,8 @@
*/
public boolean exists() throws IOException
{
- final List<String> tokens = this.tokens;
- final VFS.Mount mount = vfs.getMount(tokens);
- return mount.getFileSystem().exists(tokens.subList(mount.getRealMountPoint().size(), tokens.size()));
+ final VFS.Mount mount = vfs.getMount(this);
+ return mount.getFileSystem().exists(mount.getMountPoint(), this);
}
/**
@@ -143,9 +157,8 @@
*/
public boolean isDirectory() throws IOException
{
- final List<String> tokens = this.tokens;
- final VFS.Mount mount = vfs.getMount(tokens);
- return mount.getFileSystem().isDirectory(tokens.subList(mount.getRealMountPoint().size(), tokens.size()));
+ final VFS.Mount mount = vfs.getMount(this);
+ return mount.getFileSystem().isDirectory(mount.getMountPoint(), this);
}
/**
@@ -156,9 +169,8 @@
*/
public InputStream openStream() throws IOException
{
- final List<String> tokens = this.tokens;
- final VFS.Mount mount = vfs.getMount(tokens);
- return mount.getFileSystem().openInputStream(tokens.subList(mount.getRealMountPoint().size(), tokens.size()));
+ final VFS.Mount mount = vfs.getMount(this);
+ return mount.getFileSystem().openInputStream(mount.getMountPoint(), this);
}
/**
@@ -169,9 +181,8 @@
*/
public boolean delete() throws IOException
{
- final List<String> tokens = this.tokens;
- final VFS.Mount mount = vfs.getMount(tokens);
- return mount.getFileSystem().delete(tokens.subList(mount.getRealMountPoint().size(), tokens.size()));
+ final VFS.Mount mount = vfs.getMount(this);
+ return mount.getFileSystem().delete(mount.getMountPoint(), this);
}
/**
@@ -185,9 +196,8 @@
*/
public File getPhysicalFile() throws IOException
{
- final List<String> tokens = this.tokens;
- final VFS.Mount mount = vfs.getMount(tokens);
- return mount.getFileSystem().getFile(tokens.subList(mount.getRealMountPoint().size(), tokens.size()));
+ final VFS.Mount mount = vfs.getMount(this);
+ return mount.getFileSystem().getFile(mount.getMountPoint(), this);
}
/**
@@ -206,19 +216,26 @@
* @return the parent or {@code null} if there is no parent
* @throws IOException for any problem accessing the virtual file system
*/
- public VirtualFile getParent() throws IOException
+ public VirtualFile getParent()
{
- 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('/')));
+ return parent;
}
+ public VirtualFile[] getParentFiles() {
+ return getParentFiles(0);
+ }
+
+ private VirtualFile[] getParentFiles(int idx) {
+ final VirtualFile[] array;
+ if (parent == null) {
+ array = new VirtualFile[idx + 1];
+ } else {
+ array = parent.getParentFiles(idx + 1);
+ }
+ array[idx] = this;
+ return array;
+ }
+
/**
* Get the children. This is the combined list of real children within this directory, as well as virtual
* children created by submounts.
@@ -228,32 +245,19 @@
*/
public List<VirtualFile> getChildren() throws IOException
{
- final ArrayList<VirtualFile> list = new ArrayList<VirtualFile>();
- for (String name : getChildrenNames())
+ final VFS.Mount mount = vfs.getMount(this);
+ final Set<String> submounts = vfs.getSubmounts(this);
+ final List<String> names = mount.getFileSystem().getDirectoryEntries(mount.getMountPoint(), this);
+ final List<VirtualFile> virtualFiles = new ArrayList<VirtualFile>(names.size() + submounts.size());
+ for (String name : names)
{
- list.add(getChild(name));
+ final VirtualFile child = new VirtualFile(vfs, name, this);
+ virtualFiles.add(child);
+ submounts.remove(name);
}
- return list;
+ return virtualFiles;
}
- private Set<String> getChildrenNames() throws IOException
- {
- // Add the files physically present
- final List<String> tokens = this.tokens;
- final VFS.Mount mount = vfs.getMount(tokens);
- final Iterator<String> iter = mount.getFileSystem().getDirectoryEntries(tokens.subList(mount.getRealMountPoint().size(), tokens.size()));
- final Set<String> names = new HashSet<String>();
- while (iter.hasNext()) {
- names.add(iter.next());
- }
- // Add any mounts that are logically present
- final Iterator<String> submounts = vfs.getSubmounts(tokens);
- while (submounts.hasNext()) {
- names.add(submounts.next());
- }
- return names;
- }
-
/**
* Get the children
*
@@ -347,25 +351,31 @@
* @throws IOException for any problem accessing the VFS
* @throws IllegalArgumentException if the path is null
*/
- public VirtualFile getChild(String path) throws IOException
+ public VirtualFile getChild(String path)
{
if (path == null)
throw new IllegalArgumentException("Null path");
-
- 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));
+ final List<String> pathParts = PathTokenizer.getTokens(path);
+ VirtualFile current = this;
+ for (String part : pathParts)
+ {
+ if (PathTokenizer.isCurrentToken(part)) {
+ continue;
+ } else if (PathTokenizer.isReverseToken(part)) {
+ final VirtualFile parent = current.parent;
+ current = parent == null ? current : parent;
+ } else {
+ current = new VirtualFile(vfs, part, current);
+ }
+ }
+ return current;
}
- @Override
public String toString()
{
- return "Virtual file \"" + path + "\" for " + vfs;
+ return "Virtual file \"" + getPathName() + "\" for " + vfs;
}
- @Override
public boolean equals(Object o)
{
if (this == o)
@@ -373,18 +383,21 @@
if (! (o instanceof VirtualFile))
return false;
VirtualFile that = (VirtualFile) o;
- if (! path.equals(that.path))
+ if (hashCode != that.hashCode)
return false;
+ if (! name.equals(that.name))
+ return false;
if (vfs != that.vfs)
return false;
- return true;
+ final VirtualFile parent = this.parent;
+ if (parent == null)
+ return that.parent == null;
+ else
+ return parent.equals(that.parent);
}
- @Override
public int hashCode()
{
- int result = path.hashCode();
- result = 31 * result + vfs.hashCode();
- return result;
+ return hashCode;
}
}
Added: projects/vfs/branches/dml-zip-rework/src/main/java/org/jboss/virtual/spi/EnumerationIterable.java
===================================================================
--- projects/vfs/branches/dml-zip-rework/src/main/java/org/jboss/virtual/spi/EnumerationIterable.java (rev 0)
+++ projects/vfs/branches/dml-zip-rework/src/main/java/org/jboss/virtual/spi/EnumerationIterable.java 2009-07-14 04:56:39 UTC (rev 91185)
@@ -0,0 +1,41 @@
+/*
+ * 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.util.Enumeration;
+import java.util.Iterator;
+
+class EnumerationIterable<T> implements Iterable<T>
+{
+ private final Enumeration<T> entries;
+
+ public EnumerationIterable(Enumeration<T> entries)
+ {
+ this.entries = entries;
+ }
+
+ public Iterator<T> iterator()
+ {
+ return new EnumerationIterator<T>(entries);
+ }
+}
Added: projects/vfs/branches/dml-zip-rework/src/main/java/org/jboss/virtual/spi/EnumerationIterator.java
===================================================================
--- projects/vfs/branches/dml-zip-rework/src/main/java/org/jboss/virtual/spi/EnumerationIterator.java (rev 0)
+++ projects/vfs/branches/dml-zip-rework/src/main/java/org/jboss/virtual/spi/EnumerationIterator.java 2009-07-14 04:56:39 UTC (rev 91185)
@@ -0,0 +1,51 @@
+/*
+ * 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.util.Iterator;
+import java.util.Enumeration;
+
+class EnumerationIterator<T> implements Iterator<T>
+{
+ private final Enumeration<T> entries;
+
+ public EnumerationIterator(Enumeration<T> entries)
+ {
+ this.entries = entries;
+ }
+
+ public boolean hasNext()
+ {
+ return entries.hasMoreElements();
+ }
+
+ public T next()
+ {
+ return entries.nextElement();
+ }
+
+ public void remove()
+ {
+ throw new UnsupportedOperationException();
+ }
+}
Modified: 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 2009-07-14 02:44:23 UTC (rev 91184)
+++ projects/vfs/branches/dml-zip-rework/src/main/java/org/jboss/virtual/spi/FileSystem.java 2009-07-14 04:56:39 UTC (rev 91185)
@@ -22,6 +22,8 @@
package org.jboss.virtual.spi;
+import org.jboss.virtual.VirtualFile;
+
import java.io.File;
import java.io.IOException;
import java.io.Closeable;
@@ -43,20 +45,22 @@
* 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
+ * @param mountPoint the mount point of the filesystem instance (guaranteed to be a parent of {@code target})
+ * @param target the virtual file to act upon
* @return the file instance
* @throws IOException if an I/O error occurs
*/
- File getFile(List<String> pathComponents) throws IOException;
+ File getFile(VirtualFile mountPoint, VirtualFile target) throws IOException;
/**
* Open an input stream for the file at the given relative path.
*
- * @param pathComponents the relative path components
+ * @param mountPoint the mount point of the filesystem instance (guaranteed to be a parent of {@code target})
+ * @param target the virtual file to act upon
* @return the input stream
* @throws IOException if an I/O error occurs
*/
- InputStream openInputStream(List<String> pathComponents) throws IOException;
+ InputStream openInputStream(VirtualFile mountPoint, VirtualFile target) throws IOException;
/**
* Determine whether this filesystem is read-only. A read-only filesystem prohibits file modification or
@@ -67,24 +71,25 @@
*/
boolean isReadOnly();
- boolean delete(List<String> pathComponents) throws IOException;
+ boolean delete(VirtualFile mountPoint, VirtualFile target) throws IOException;
- long getSize(List<String> pathComponents) throws IOException;
+ long getSize(VirtualFile mountPoint, VirtualFile target) throws IOException;
- long getLastModified(List<String> pathComponents) throws IOException;
+ long getLastModified(VirtualFile mountPoint, VirtualFile target) throws IOException;
- boolean exists(List<String> pathComponents) throws IOException;
+ boolean exists(VirtualFile mountPoint, VirtualFile target) throws IOException;
- boolean isDirectory(List<String> pathComponents) throws IOException;
+ boolean isDirectory(VirtualFile mountPoint, VirtualFile target) 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
+ * @param mountPoint the mount point of the filesystem instance (guaranteed to be a parent of {@code target})
+ * @param target the virtual file to act upon
+ * @return the collection of children names
* @throws IOException if an I/O error occurs
*/
- Iterator<String> getDirectoryEntries(List<String> directoryPathComponents) throws IOException;
+ List<String> getDirectoryEntries(VirtualFile mountPoint, VirtualFile target) throws IOException;
/**
* Destroy this filesystem instance. After this method is called, the filesystem may not be used in any way. This
Copied: projects/vfs/branches/dml-zip-rework/src/main/java/org/jboss/virtual/spi/JZipFileSystem.java (from rev 91123, 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/JZipFileSystem.java (rev 0)
+++ projects/vfs/branches/dml-zip-rework/src/main/java/org/jboss/virtual/spi/JZipFileSystem.java 2009-07-14 04:56:39 UTC (rev 91185)
@@ -0,0 +1,264 @@
+/*
+ * 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 org.jboss.virtual.VirtualFile;
+
+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.io.BufferedOutputStream;
+import java.util.List;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.ArrayList;
+
+/**
+ * {@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 JZipFileSystem implements FileSystem
+{
+ private final File zipFile;
+ private final long zipTime;
+ 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 java.io.IOException if an I/O error occurs
+ */
+ public JZipFileSystem(String name, InputStream inputStream, TempFileProvider tempFileProvider) throws IOException {
+ this(tempFileProvider.createTempFile(name, name.hashCode(), inputStream), tempFileProvider);
+ }
+
+ public JZipFileSystem(File zipFile, TempFileProvider tempFileProvider) throws IOException
+ {
+ zipTime = zipFile.lastModified();
+ this.tempFileProvider = tempFileProvider;
+ this.zipFile = zipFile;
+ final ZipCatalog catalog = Zip.readCatalog(zipFile);
+ final ZipNode rootNode = new ZipNode(new HashMap<String, ZipNode>(), "", null);
+ FILES: for (ZipEntry entry : catalog.allEntries())
+ {
+ final String name = entry.getName();
+ final boolean isDirectory = entry.getEntryType() == ZipEntryType.DIRECTORY;
+ final List<String> tokens = PathTokenizer.getTokens(name);
+ ZipNode node = rootNode;
+ final Iterator<String> it = tokens.iterator();
+ while (it.hasNext())
+ {
+ String token = it.next();
+ if (PathTokenizer.isCurrentToken(token) || PathTokenizer.isReverseToken(token)) {
+ // invalid file name
+ continue FILES;
+ }
+ final Map<String, ZipNode> children = node.children;
+ if (children == null) {
+ // todo - log bad zip entry
+ continue FILES;
+ }
+ ZipNode child = children.get(token.toLowerCase());
+ if (child == null)
+ {
+ child = it.hasNext() || isDirectory ? new ZipNode(new HashMap<String, ZipNode>(), token, null) : new ZipNode(null, token, entry);
+ children.put(token.toLowerCase(), child);
+ }
+ node = child;
+ }
+ }
+ this.rootNode = rootNode;
+ }
+
+ public File getFile(VirtualFile mountPoint, VirtualFile target) throws IOException
+ {
+ final ZipNode zipNode = getExistingZipNode(mountPoint, target);
+
+ // 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 entry = getNodeEntry(zipNode);
+ final String name = entry.getName();
+ cachedFile = tempFileProvider.createTempFile(name, entry.hashCode());
+ VFSUtils.copyStreamAndClose(Zip.openEntry(zipFile, entry), new BufferedOutputStream(new FileOutputStream(cachedFile)));
+ zipNode.cachedFile = cachedFile;
+ return cachedFile;
+ }
+ }
+
+ public InputStream openInputStream(VirtualFile mountPoint, VirtualFile target) throws IOException
+ {
+ final ZipNode zipNode = getExistingZipNode(mountPoint, target);
+ final File cachedFile = zipNode.cachedFile;
+ if (cachedFile != null) {
+ return new FileInputStream(cachedFile);
+ }
+ final ZipEntry entry = zipNode.entry;
+ if (entry == null) {
+ throw new IOException("Not a file: \"" + target.getPathName() + "\"");
+ }
+ return Zip.openEntry(zipFile, entry);
+ }
+
+ public boolean delete(VirtualFile mountPoint, VirtualFile target) throws IOException
+ {
+ final ZipNode zipNode = getExistingZipNode(mountPoint, target);
+ final File cachedFile = zipNode.cachedFile;
+ return cachedFile != null && cachedFile.delete();
+ }
+
+ public long getSize(VirtualFile mountPoint, VirtualFile target) throws IOException
+ {
+ final ZipNode zipNode = getExistingZipNode(mountPoint, target);
+ final File cachedFile = zipNode.cachedFile;
+ final ZipEntry entry = zipNode.entry;
+ return cachedFile != null ? cachedFile.length() : entry == null ? 0L : entry.getSize();
+ }
+
+ public long getLastModified(VirtualFile mountPoint, VirtualFile target) throws IOException
+ {
+ final ZipNode zipNode = getExistingZipNode(mountPoint, target);
+ final File cachedFile = zipNode.cachedFile;
+ final ZipEntry entry = zipNode.entry;
+ return cachedFile != null ? cachedFile.lastModified() : entry == null ? zipTime : entry.getModificationTime();
+ }
+
+ public boolean exists(VirtualFile mountPoint, VirtualFile target) throws IOException
+ {
+ final ZipNode zipNode = rootNode.find(mountPoint, target);
+ if (zipNode == null) {
+ return false;
+ } else {
+ final File cachedFile = zipNode.cachedFile;
+ return cachedFile == null || cachedFile.exists();
+ }
+ }
+
+ public boolean isDirectory(VirtualFile mountPoint, VirtualFile target) throws IOException
+ {
+ final ZipNode zipNode = rootNode.find(mountPoint, target);
+ return zipNode != null && zipNode.entry == null;
+ }
+
+ public List<String> getDirectoryEntries(VirtualFile mountPoint, VirtualFile target) throws IOException
+ {
+ final ZipNode zipNode = getExistingZipNode(mountPoint, target);
+ final Map<String, ZipNode> children = zipNode.children;
+ final Collection<ZipNode> values = children.values();
+ final List<String> names = new ArrayList<String>(values.size());
+ for (ZipNode node : values)
+ {
+ names.add(node.name);
+ }
+ return names;
+ }
+
+ 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(VirtualFile mountPoint, VirtualFile target)
+ throws FileNotFoundException
+ {
+ final ZipNode zipNode = rootNode.find(mountPoint, target);
+ if (zipNode == null) {
+ throw new FileNotFoundException(target.getPathName());
+ }
+ return zipNode;
+ }
+
+ public boolean isReadOnly()
+ {
+ return true;
+ }
+
+ public void close() throws IOException
+ {
+ tempFileProvider.close();
+ }
+
+ private static final class ZipNode {
+ // immutable child map
+ private final Map<String, ZipNode> children;
+ private final String name;
+ private final ZipEntry entry;
+ private volatile File cachedFile;
+
+ private ZipNode(Map<String, ZipNode> children, String name, ZipEntry entry)
+ {
+ this.children = children;
+ this.name = name;
+ this.entry = entry;
+ }
+
+ private ZipNode find(VirtualFile mountPoint, VirtualFile target) {
+ if (mountPoint.equals(target)) {
+ return this;
+ } else {
+ final ZipNode parent = find(mountPoint, target.getParent());
+ if (parent == null) {
+ return null;
+ }
+ final Map<String, ZipNode> children = parent.children;
+ if (children == null) {
+ return null;
+ }
+ return children.get(target.getLowerCaseName());
+ }
+ }
+ }
+}
Added: projects/vfs/branches/dml-zip-rework/src/main/java/org/jboss/virtual/spi/JavaZipFileSystem.java
===================================================================
--- projects/vfs/branches/dml-zip-rework/src/main/java/org/jboss/virtual/spi/JavaZipFileSystem.java (rev 0)
+++ projects/vfs/branches/dml-zip-rework/src/main/java/org/jboss/virtual/spi/JavaZipFileSystem.java 2009-07-14 04:56:39 UTC (rev 91185)
@@ -0,0 +1,276 @@
+/*
+ * 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.virtual.plugins.vfs.helpers.PathTokenizer;
+import org.jboss.virtual.VFSUtils;
+import org.jboss.virtual.TempFileProvider;
+import org.jboss.virtual.VirtualFile;
+
+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.io.Closeable;
+import java.io.BufferedOutputStream;
+import java.util.List;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.HashMap;
+import java.util.Enumeration;
+import java.util.Collection;
+import java.util.ArrayList;
+import java.util.zip.ZipFile;
+import java.util.zip.ZipEntry;
+
+/**
+ * {@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 JavaZipFileSystem implements FileSystem
+{
+ private final ZipFile zipFile;
+ private final long zipTime;
+ 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 java.io.IOException if an I/O error occurs
+ */
+ public JavaZipFileSystem(String name, InputStream inputStream, TempFileProvider tempFileProvider) throws IOException {
+ this(tempFileProvider.createTempFile(name, name.hashCode(), inputStream), tempFileProvider);
+ }
+
+ public JavaZipFileSystem(File file, TempFileProvider tempFileProvider) throws IOException
+ {
+ zipTime = file.lastModified();
+ final ZipFile zipFile;
+ this.zipFile = zipFile = new ZipFile(file);
+ this.tempFileProvider = tempFileProvider;
+ final Enumeration<? extends ZipEntry> entries = zipFile.entries();
+ final ZipNode rootNode = new ZipNode(new HashMap<String, ZipNode>(), "", null);
+ FILES: for (ZipEntry entry : iter(entries))
+ {
+ final String name = entry.getName();
+ final boolean isDirectory = entry.isDirectory();
+ final List<String> tokens = PathTokenizer.getTokens(name);
+ ZipNode node = rootNode;
+ final Iterator<String> it = tokens.iterator();
+ while (it.hasNext())
+ {
+ String token = it.next();
+ if (PathTokenizer.isCurrentToken(token) || PathTokenizer.isReverseToken(token)) {
+ // invalid file name
+ continue FILES;
+ }
+ final Map<String, ZipNode> children = node.children;
+ if (children == null) {
+ // todo - log bad zip entry
+ continue FILES;
+ }
+ final String lcToken = token.toLowerCase();
+ ZipNode child = children.get(lcToken);
+ if (child == null)
+ {
+ child = it.hasNext() || isDirectory ? new ZipNode(new HashMap<String, ZipNode>(), token, null) : new ZipNode(null, token, entry);
+ children.put(lcToken, child);
+ }
+ node = child;
+ }
+ }
+ this.rootNode = rootNode;
+ }
+
+ private static <T> Iterable<T> iter(final Enumeration<T> entries)
+ {
+ return new EnumerationIterable<T>(entries);
+ }
+
+ public File getFile(VirtualFile mountPoint, VirtualFile target) throws IOException
+ {
+ final ZipNode zipNode = getExistingZipNode(mountPoint, target);
+
+ // 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(zipFile.getInputStream(zipEntry), new BufferedOutputStream(new FileOutputStream(cachedFile)));
+ zipNode.cachedFile = cachedFile;
+ return cachedFile;
+ }
+ }
+
+ public InputStream openInputStream(VirtualFile mountPoint, VirtualFile target) throws IOException
+ {
+ final ZipNode zipNode = getExistingZipNode(mountPoint, target);
+ final File cachedFile = zipNode.cachedFile;
+ if (cachedFile != null) {
+ return new FileInputStream(cachedFile);
+ }
+ final ZipEntry entry = zipNode.entry;
+ if (entry == null) {
+ throw new IOException("Not a file: \"" + target.getPathName() + "\"");
+ }
+ return zipFile.getInputStream(entry);
+ }
+
+ public boolean delete(VirtualFile mountPoint, VirtualFile target) throws IOException
+ {
+ final ZipNode zipNode = getExistingZipNode(mountPoint, target);
+ final File cachedFile = zipNode.cachedFile;
+ return cachedFile != null && cachedFile.delete();
+ }
+
+ public long getSize(VirtualFile mountPoint, VirtualFile target) throws IOException
+ {
+ final ZipNode zipNode = getExistingZipNode(mountPoint, target);
+ final File cachedFile = zipNode.cachedFile;
+ final ZipEntry entry = zipNode.entry;
+ return cachedFile != null ? cachedFile.length() : entry == null ? 0L : entry.getSize();
+ }
+
+ public long getLastModified(VirtualFile mountPoint, VirtualFile target) throws IOException
+ {
+ final ZipNode zipNode = getExistingZipNode(mountPoint, target);
+ final File cachedFile = zipNode.cachedFile;
+ final ZipEntry entry = zipNode.entry;
+ return cachedFile != null ? cachedFile.lastModified() : entry == null ? zipTime : entry.getTime();
+ }
+
+ public boolean exists(VirtualFile mountPoint, VirtualFile target) throws IOException
+ {
+ final ZipNode zipNode = rootNode.find(mountPoint, target);
+ if (zipNode == null) {
+ return false;
+ } else {
+ final File cachedFile = zipNode.cachedFile;
+ return cachedFile == null || cachedFile.exists();
+ }
+ }
+
+ public boolean isDirectory(VirtualFile mountPoint, VirtualFile target) throws IOException
+ {
+ final ZipNode zipNode = rootNode.find(mountPoint, target);
+ return zipNode != null && zipNode.entry == null;
+ }
+
+ public List<String> getDirectoryEntries(VirtualFile mountPoint, VirtualFile target) throws IOException
+ {
+ final ZipNode zipNode = getExistingZipNode(mountPoint, target);
+ final Map<String, ZipNode> children = zipNode.children;
+ final Collection<ZipNode> values = children.values();
+ final List<String> names = new ArrayList<String>(values.size());
+ for (ZipNode node : values)
+ {
+ names.add(node.name);
+ }
+ return names;
+ }
+
+ 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(VirtualFile mountPoint, VirtualFile target)
+ throws FileNotFoundException
+ {
+ final ZipNode zipNode = rootNode.find(mountPoint, target);
+ if (zipNode == null) {
+ throw new FileNotFoundException(target.getPathName());
+ }
+ return zipNode;
+ }
+
+ public boolean isReadOnly()
+ {
+ return true;
+ }
+
+ public void close() throws IOException
+ {
+ VFSUtils.safeClose(new Closeable() {
+ public void close() throws IOException {
+ zipFile.close();
+ }
+ });
+ tempFileProvider.close();
+ }
+
+ private static final class ZipNode {
+ // immutable child map
+ private final Map<String, ZipNode> children;
+ private final String name;
+ private final ZipEntry entry;
+ private volatile File cachedFile;
+
+ private ZipNode(Map<String, ZipNode> children, String name, ZipEntry entry)
+ {
+ this.children = children;
+ this.name = name;
+ this.entry = entry;
+ }
+
+ private ZipNode find(VirtualFile mountPoint, VirtualFile target) {
+ if (mountPoint.equals(target)) {
+ return this;
+ } else {
+ final ZipNode parent = find(mountPoint, target.getParent());
+ if (parent == null) {
+ return null;
+ }
+ final Map<String, ZipNode> children = parent.children;
+ if (children == null) {
+ return null;
+ }
+ return children.get(target.getLowerCaseName());
+ }
+ }
+ }
+}
\ No newline at end of file
Modified: 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 2009-07-14 02:44:23 UTC (rev 91184)
+++ projects/vfs/branches/dml-zip-rework/src/main/java/org/jboss/virtual/spi/RealFileSystem.java 2009-07-14 04:56:39 UTC (rev 91185)
@@ -22,91 +22,75 @@
package org.jboss.virtual.spi;
+import org.jboss.virtual.VirtualFile;
+
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());
+ public static final RealFileSystem ROOT_INSTANCE = new RealFileSystem(new File(""));
- private final String base;
+ private final File realRoot;
- private RealFileSystem(List<String> baseComponents)
+ private RealFileSystem(File realRoot)
{
- base = implode("", baseComponents) + File.separator;
+ this.realRoot = realRoot;
}
- public File getFile(List<String> pathComponents) throws IOException
+ public InputStream openInputStream(VirtualFile mountPoint, VirtualFile target) throws IOException
{
- return new File(implode(base, pathComponents));
+ return new FileInputStream(getFile(mountPoint, target));
}
- private static String implode(String base, List<String> pathComponents)
+ public boolean isReadOnly()
{
- 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();
+ return false;
}
- public InputStream openInputStream(List<String> pathComponents) throws IOException
+ public File getFile(VirtualFile mountPoint, VirtualFile target) throws IOException
{
- return new FileInputStream(getFile(pathComponents));
+ if (mountPoint == target) {
+ return realRoot;
+ } else {
+ return new File(getFile(mountPoint, target.getParent()), target.getName());
+ }
}
- public boolean isReadOnly()
+ public boolean delete(VirtualFile mountPoint, VirtualFile target) throws IOException
{
- return false;
+ return getFile(mountPoint, target).delete();
}
- public boolean delete(List<String> pathComponents) throws IOException
+ public long getSize(VirtualFile mountPoint, VirtualFile target) throws IOException
{
- return getFile(pathComponents).delete();
+ return getFile(mountPoint, target).length();
}
- public long getSize(List<String> pathComponents) throws IOException
+ public long getLastModified(VirtualFile mountPoint, VirtualFile target) throws IOException
{
- return getFile(pathComponents).length();
+ return getFile(mountPoint, target).lastModified();
}
- public long getLastModified(List<String> pathComponents) throws IOException
+ public boolean exists(VirtualFile mountPoint, VirtualFile target) throws IOException
{
- return getFile(pathComponents).lastModified();
+ return getFile(mountPoint, target).exists();
}
- public boolean exists(List<String> pathComponents) throws IOException
+ public boolean isDirectory(VirtualFile mountPoint, VirtualFile target) throws IOException
{
- return getFile(pathComponents).exists();
+ return getFile(mountPoint, target).isDirectory();
}
- public boolean isDirectory(List<String> pathComponents) throws IOException
+ public List<String> getDirectoryEntries(VirtualFile mountPoint, VirtualFile target) throws IOException
{
- return getFile(pathComponents).isDirectory();
+ return Arrays.asList(getFile(mountPoint, target).list());
}
- 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
Deleted: 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 2009-07-14 02:44:23 UTC (rev 91184)
+++ projects/vfs/branches/dml-zip-rework/src/main/java/org/jboss/virtual/spi/ZipFileSystem.java 2009-07-14 04:56:39 UTC (rev 91185)
@@ -1,278 +0,0 @@
-/*
- * 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, "");
- FILES: 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;
- if (children == null) {
- // todo - log bad zip entry
- continue FILES;
- }
- ZipNode child = children.get(token.toLowerCase());
- if (child == null)
- {
- child = it.hasNext() || zipEntry.getEntryType() == ZipEntryType.DIRECTORY ? new ZipNode(new HashMap<String, ZipNode>(), null, token) : new ZipNode(null, zipEntry, token);
- children.put(token.toLowerCase(), child);
- }
- node = child;
- }
- }
- 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(join(pathComponents));
- }
- return zipNode;
- }
-
- private static String join(List<String> pathComponents)
- {
- int l = 0;
- for (String pathComponent : pathComponents)
- {
- l += pathComponent.length();
- }
- final StringBuilder sb = new StringBuilder(l);
- for (String pathComponent : pathComponents)
- {
- sb.append('/');
- sb.append(pathComponent);
- }
- return sb.toString();
- }
-
- 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
- {
- final ZipNode zipNode = rootNode.find(directoryPathComponents.iterator());
- if (zipNode != null) {
- final Map<String, ZipNode> children = zipNode.children;
- if (children != null) {
- final Iterator<ZipNode> it = children.values().iterator();
- return new Iterator<String>()
- {
- public boolean hasNext()
- {
- return it.hasNext();
- }
-
- public String next()
- {
- return it.next().name;
- }
-
- public void remove()
- {
- throw new UnsupportedOperationException();
- }
- };
- }
- }
- throw new FileNotFoundException(join(directoryPathComponents));
- }
-
- public void close() throws IOException
- {
- tempFileProvider.close();
- }
-
- private static final class ZipNode {
- private final Map<String, ZipNode> children;
- private final ZipEntry entry;
- private final String name;
- private volatile File cachedFile;
-
- private ZipNode(Map<String, ZipNode> children, ZipEntry entry, String name)
- {
- this.children = children;
- this.entry = entry;
- this.name = name;
- }
-
- private ZipNode find(Iterator<String> node) {
- if (node.hasNext())
- {
- final ZipNode next = children.get(node.next().toLowerCase());
- return next == null ? null : next.find(node);
- }
- else
- {
- return this;
- }
- }
- }
-}
More information about the jboss-cvs-commits
mailing list