[jboss-cvs] JBossAS SVN: r74620 - in projects/vfs/tags: 2.0.0.Beta17 and 4 other directories.

jboss-cvs-commits at lists.jboss.org jboss-cvs-commits at lists.jboss.org
Mon Jun 16 10:28:54 EDT 2008


Author: alesj
Date: 2008-06-16 10:28:54 -0400 (Mon, 16 Jun 2008)
New Revision: 74620

Added:
   projects/vfs/tags/2.0.0.Beta17/
   projects/vfs/tags/2.0.0.Beta17/pom.xml
   projects/vfs/tags/2.0.0.Beta17/release-pom.xml
   projects/vfs/tags/2.0.0.Beta17/src/main/java/org/jboss/virtual/VFSUtils.java
   projects/vfs/tags/2.0.0.Beta17/src/main/java/org/jboss/virtual/plugins/context/zip/ZipEntryContext.java
   projects/vfs/tags/2.0.0.Beta17/src/test/java/org/jboss/test/virtual/test/VFSAllTestSuite.java
   projects/vfs/tags/2.0.0.Beta17/src/test/java/org/jboss/test/virtual/test/VFSUtilTestCase.java
   projects/vfs/tags/2.0.0.Beta17/src/test/resources/vfs/test/badmf.jar
Removed:
   projects/vfs/tags/2.0.0.Beta17/pom.xml
   projects/vfs/tags/2.0.0.Beta17/src/main/java/org/jboss/virtual/VFSUtils.java
   projects/vfs/tags/2.0.0.Beta17/src/main/java/org/jboss/virtual/plugins/context/zip/ZipEntryContext.java
   projects/vfs/tags/2.0.0.Beta17/src/test/java/org/jboss/test/virtual/test/VFSAllTestSuite.java
Log:
[maven-release-plugin]  copy for tag 2.0.0.Beta17

Copied: projects/vfs/tags/2.0.0.Beta17 (from rev 74595, projects/vfs/trunk)

Deleted: projects/vfs/tags/2.0.0.Beta17/pom.xml
===================================================================
--- projects/vfs/trunk/pom.xml	2008-06-16 06:57:54 UTC (rev 74595)
+++ projects/vfs/tags/2.0.0.Beta17/pom.xml	2008-06-16 14:28:54 UTC (rev 74620)
@@ -1,121 +0,0 @@
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
-  <parent>
-    <groupId>org.jboss</groupId>
-    <artifactId>jboss-parent</artifactId>
-    <version>4-beta-2</version>
-  </parent>
-  <modelVersion>4.0.0</modelVersion>
-  <groupId>org.jboss</groupId>
-  <artifactId>jboss-vfs</artifactId>
-  <packaging>jar</packaging>
-  <version>2.0.0-SNAPSHOT</version>
-  <name>JBoss VFS</name>
-  <url>http://www.jboss.org</url>
-  <description>A VFS library</description>
- <scm>
-    <connection>scm:svn:http://anonsvn.jboss.org/repos/jbossas/projects/vfs/trunk</connection>    
-    <developerConnection>scm:svn:https://svn.jboss.org/repos/jbossas/projects/vfs/trunk</developerConnection>
-    <url>https://svn.jboss.org/repos/jbossas/projects/vfs/trunk</url>
-  </scm>
-  <licenses>
-    <license>
-      <name>lgpl</name>
-      <url>http://repository.jboss.org/licenses/lgpl.txt</url>
-    </license>
-  </licenses>
-  <organization>
-    <name>JBoss, A division of Red Hat, Inc</name>
-    <url>http://www.jboss.org</url>
-  </organization>
-
-  <properties>
-    <version.jboss.common.core>2.2.5.GA</version.jboss.common.core>
-    <version.jboss.logging>2.0.5.GA</version.jboss.logging>
-    <version.jboss.test>1.1.0.GA</version.jboss.test>
-    <version.junit>4.4</version.junit>
-  </properties>
-
-  <build>
-    <sourceDirectory>src/main/java</sourceDirectory>
-    <testSourceDirectory>src/test/java</testSourceDirectory>
-    <finalName>${artifactId}</finalName>
-    <testResources>
-      <testResource>
-        <directory>src/test/resources</directory>
-      </testResource>
-    </testResources>
-    <plugins>
-      
-      <!-- define how we want compilation to take place
-        here, we accept most of the defaults but say that we want the
-        optimization flag set, and define the source and target to be 1.5,
-        these setting will be inherited by child projects -->
-      <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-compiler-plugin</artifactId>
-        <version>2.0</version>
-        <configuration>
-          <debug>true</debug>
-          <source>1.5</source>
-          <target>1.5</target>
-        </configuration>
-      </plugin>
-      <!-- define that we wish to create src jars -->
-      <plugin>
-        <artifactId>maven-source-plugin</artifactId>
-        <inherited>true</inherited>
-        <executions>
-          <execution>
-            <goals>
-              <goal>jar</goal>
-            </goals>
-          </execution>
-        </executions>
-      </plugin>
-      <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-surefire-plugin</artifactId>
-        <version>2.3.1</version>
-        <configuration>
-          <forkMode>always</forkMode> <!-- required to correctly run the PojoServer tests -->
-          <useSystemClassLoader>true</useSystemClassLoader>
-          <redirectTestOutputToFile>true</redirectTestOutputToFile>
-        </configuration>
-      </plugin>
-      <plugin>
-         <groupId>org.apache.maven.plugins</groupId>
-         <artifactId>maven-release-plugin</artifactId>
-         <version>2.0-beta-7</version>
-         <configuration>
-           <tagBase>https://svn.jboss.org/repos/jbossas/projects/vfs/tags</tagBase>
-         </configuration>
-       </plugin>
-    </plugins>
-  </build>
-
-  <dependencies>
-    <dependency>
-      <groupId>org.jboss</groupId>
-      <artifactId>jboss-common-core</artifactId>
-      <version>${version.jboss.common.core}</version>
-    </dependency>
-    <dependency>
-      <groupId>org.jboss.logging</groupId>
-      <artifactId>jboss-logging-spi</artifactId>
-      <version>${version.jboss.logging}</version>
-    </dependency>
-    <dependency>
-      <groupId>org.jboss.test</groupId>
-      <artifactId>jboss-test</artifactId>
-      <version>${version.jboss.test}</version>
-      <scope>test</scope>
-    </dependency>
-    <dependency>
-      <groupId>junit</groupId>
-      <artifactId>junit</artifactId>
-      <version>${version.junit}</version>
-      <scope>test</scope>
-    </dependency>
-  </dependencies>
-
-</project>

Copied: projects/vfs/tags/2.0.0.Beta17/pom.xml (from rev 74619, projects/vfs/trunk/pom.xml)
===================================================================
--- projects/vfs/tags/2.0.0.Beta17/pom.xml	                        (rev 0)
+++ projects/vfs/tags/2.0.0.Beta17/pom.xml	2008-06-16 14:28:54 UTC (rev 74620)
@@ -0,0 +1,121 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <parent>
+    <groupId>org.jboss</groupId>
+    <artifactId>jboss-parent</artifactId>
+    <version>4-beta-2</version>
+  </parent>
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>org.jboss</groupId>
+  <artifactId>jboss-vfs</artifactId>
+  <packaging>jar</packaging>
+  <version>2.0.0.Beta17</version>
+  <name>JBoss VFS</name>
+  <url>http://www.jboss.org</url>
+  <description>A VFS library</description>
+ <scm>
+    <connection>scm:svn:http://anonsvn.jboss.org/repos/jbossas/projects/vfs/tags/2.0.0.Beta17</connection>    
+    <developerConnection>scm:svn:https://svn.jboss.org/repos/jbossas/projects/vfs/tags/2.0.0.Beta17</developerConnection>
+    <url>https://svn.jboss.org/repos/jbossas/projects/vfs/tags/2.0.0.Beta17</url>
+  </scm>
+  <licenses>
+    <license>
+      <name>lgpl</name>
+      <url>http://repository.jboss.org/licenses/lgpl.txt</url>
+    </license>
+  </licenses>
+  <organization>
+    <name>JBoss, A division of Red Hat, Inc</name>
+    <url>http://www.jboss.org</url>
+  </organization>
+
+  <properties>
+    <version.jboss.common.core>2.2.5.GA</version.jboss.common.core>
+    <version.jboss.logging>2.0.5.GA</version.jboss.logging>
+    <version.jboss.test>1.1.0.GA</version.jboss.test>
+    <version.junit>4.4</version.junit>
+  </properties>
+
+  <build>
+    <sourceDirectory>src/main/java</sourceDirectory>
+    <testSourceDirectory>src/test/java</testSourceDirectory>
+    <finalName>${artifactId}</finalName>
+    <testResources>
+      <testResource>
+        <directory>src/test/resources</directory>
+      </testResource>
+    </testResources>
+    <plugins>
+      
+      <!-- define how we want compilation to take place
+        here, we accept most of the defaults but say that we want the
+        optimization flag set, and define the source and target to be 1.5,
+        these setting will be inherited by child projects -->
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-compiler-plugin</artifactId>
+        <version>2.0</version>
+        <configuration>
+          <debug>true</debug>
+          <source>1.5</source>
+          <target>1.5</target>
+        </configuration>
+      </plugin>
+      <!-- define that we wish to create src jars -->
+      <plugin>
+        <artifactId>maven-source-plugin</artifactId>
+        <inherited>true</inherited>
+        <executions>
+          <execution>
+            <goals>
+              <goal>jar</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-surefire-plugin</artifactId>
+        <version>2.3.1</version>
+        <configuration>
+          <forkMode>always</forkMode> <!-- required to correctly run the PojoServer tests -->
+          <useSystemClassLoader>true</useSystemClassLoader>
+          <redirectTestOutputToFile>true</redirectTestOutputToFile>
+        </configuration>
+      </plugin>
+      <plugin>
+         <groupId>org.apache.maven.plugins</groupId>
+         <artifactId>maven-release-plugin</artifactId>
+         <version>2.0-beta-7</version>
+         <configuration>
+           <tagBase>https://svn.jboss.org/repos/jbossas/projects/vfs/tags</tagBase>
+         </configuration>
+       </plugin>
+    </plugins>
+  </build>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.jboss</groupId>
+      <artifactId>jboss-common-core</artifactId>
+      <version>${version.jboss.common.core}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.jboss.logging</groupId>
+      <artifactId>jboss-logging-spi</artifactId>
+      <version>${version.jboss.logging}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.jboss.test</groupId>
+      <artifactId>jboss-test</artifactId>
+      <version>${version.jboss.test}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <version>${version.junit}</version>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+
+</project>

Copied: projects/vfs/tags/2.0.0.Beta17/release-pom.xml (from rev 74619, projects/vfs/trunk/release-pom.xml)
===================================================================
--- projects/vfs/tags/2.0.0.Beta17/release-pom.xml	                        (rev 0)
+++ projects/vfs/tags/2.0.0.Beta17/release-pom.xml	2008-06-16 14:28:54 UTC (rev 74620)
@@ -0,0 +1,266 @@
+<?xml version="1.0" encoding="UTF-8"?><project>
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>org.jboss</groupId>
+  <artifactId>jboss-vfs</artifactId>
+  <name>JBoss VFS</name>
+  <version>2.0.0.Beta17</version>
+  <description>A VFS library</description>
+  <url>http://www.jboss.org</url>
+  <issueManagement>
+    <system>jira</system>
+    <url>http://jira.jboss.com/</url>
+  </issueManagement>
+  <licenses>
+    <license>
+      <name>lgpl</name>
+      <url>http://repository.jboss.org/licenses/lgpl.txt</url>
+    </license>
+  </licenses>
+  <scm>
+    <connection>https://svn.jboss.org/repos/jbossas/projects/vfs/tags/2.0.0.Beta17</connection>
+    <developerConnection>https://svn.jboss.org/repos/jbossas/projects/vfs/tags/2.0.0.Beta17</developerConnection>
+    <url>https://svn.jboss.org/repos/jbossas/projects/vfs/tags/2.0.0.Beta17</url>
+  </scm>
+  <organization>
+    <name>JBoss, A division of Red Hat, Inc</name>
+    <url>http://www.jboss.org</url>
+  </organization>
+  <build>
+    <sourceDirectory>src/main/java</sourceDirectory>
+    <scriptSourceDirectory>src/main/scripts</scriptSourceDirectory>
+    <testSourceDirectory>src/test/java</testSourceDirectory>
+    <outputDirectory>target/classes</outputDirectory>
+    <testOutputDirectory>target/test-classes</testOutputDirectory>
+    <resources>
+      <resource>
+        <directory>src/main/resources</directory>
+      </resource>
+    </resources>
+    <testResources>
+      <testResource>
+        <directory>src/test/resources</directory>
+      </testResource>
+    </testResources>
+    <directory>target</directory>
+    <finalName>jboss-vfs</finalName>
+    <plugins>
+      <plugin>
+        <artifactId>maven-compiler-plugin</artifactId>
+        <version>2.0</version>
+        <configuration>
+          <debug>true</debug>
+          <source>1.5</source>
+          <target>1.5</target>
+          <showDeprecation>true</showDeprecation>
+          <showWarnings>true</showWarnings>
+          <optimize>true</optimize>
+        </configuration>
+      </plugin>
+      <plugin>
+        <artifactId>maven-source-plugin</artifactId>
+        <version>2.0.3</version>
+        <executions>
+          <execution>
+            <id>attach-sources</id>
+            <goals>
+              <goal>jar</goal>
+            </goals>
+          </execution>
+          <execution>
+            <goals>
+              <goal>jar</goal>
+            </goals>
+          </execution>
+        </executions>
+        <inherited>true</inherited>
+      </plugin>
+      <plugin>
+        <artifactId>maven-surefire-plugin</artifactId>
+        <version>2.3.1</version>
+        <configuration>
+          <forkMode>always</forkMode>
+          <useSystemClassLoader>true</useSystemClassLoader>
+          <redirectTestOutputToFile>true</redirectTestOutputToFile>
+        </configuration>
+      </plugin>
+      <plugin>
+        <artifactId>maven-release-plugin</artifactId>
+        <version>2.0-beta-7</version>
+        <configuration>
+          <tagBase>https://svn.jboss.org/repos/jbossas/projects/vfs/tags</tagBase>
+          <generateReleasePoms>true</generateReleasePoms>
+          <useReleaseProfile>false</useReleaseProfile>
+          <arguments>-Prelease</arguments>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+  <repositories>
+    <repository>
+      <snapshots />
+      <id>snapshots.jboss.org</id>
+      <url>http://snapshots.jboss.org/maven2</url>
+    </repository>
+    <repository>
+      <snapshots>
+        <enabled>false</enabled>
+      </snapshots>
+      <id>repository.jboss.org</id>
+      <url>http://repository.jboss.org/maven2</url>
+    </repository>
+    <repository>
+      <snapshots>
+        <enabled>false</enabled>
+      </snapshots>
+      <id>central</id>
+      <name>Maven Repository Switchboard</name>
+      <url>http://repo1.maven.org/maven2</url>
+    </repository>
+  </repositories>
+  <pluginRepositories>
+    <pluginRepository>
+      <snapshots>
+        <enabled>false</enabled>
+      </snapshots>
+      <id>repository.jboss.org</id>
+      <url>http://repository.jboss.org/maven2</url>
+    </pluginRepository>
+    <pluginRepository>
+      <snapshots />
+      <id>snapshots.jboss.org</id>
+      <url>http://snapshots.jboss.org/maven2</url>
+    </pluginRepository>
+    <pluginRepository>
+      <releases>
+        <updatePolicy>never</updatePolicy>
+      </releases>
+      <snapshots>
+        <enabled>false</enabled>
+      </snapshots>
+      <id>central</id>
+      <name>Maven Plugin Repository</name>
+      <url>http://repo1.maven.org/maven2</url>
+    </pluginRepository>
+  </pluginRepositories>
+  <dependencies>
+    <dependency>
+      <groupId>apache-log4j</groupId>
+      <artifactId>log4j</artifactId>
+      <version>1.2.14</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>jboss.profiler.jvmti</groupId>
+      <artifactId>jboss-profiler-jvmti</artifactId>
+      <version>1.0.0.CR5</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <version>4.4</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.ant</groupId>
+      <artifactId>ant</artifactId>
+      <version>1.7.0</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.ant</groupId>
+      <artifactId>ant-junit</artifactId>
+      <version>1.7.0</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.ant</groupId>
+      <artifactId>ant-launcher</artifactId>
+      <version>1.7.0</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.jboss</groupId>
+      <artifactId>jboss-common-core</artifactId>
+      <version>2.2.5.GA</version>
+      <scope>compile</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.jboss.jbossas</groupId>
+      <artifactId>jboss-server-manager</artifactId>
+      <version>0.1.0.GA</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.jboss.logging</groupId>
+      <artifactId>jboss-logging-log4j</artifactId>
+      <version>2.0.5.GA</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.jboss.logging</groupId>
+      <artifactId>jboss-logging-spi</artifactId>
+      <version>2.0.5.GA</version>
+      <scope>compile</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.jboss.test</groupId>
+      <artifactId>jboss-test</artifactId>
+      <version>1.1.0.GA</version>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+  <reporting>
+    <outputDirectory>target/site</outputDirectory>
+    <plugins>
+      <plugin>
+        <artifactId>maven-javadoc-plugin</artifactId>
+        <version>2.2</version>
+        <configuration>
+          <links>
+            <link>http://java.sun.com/j2se/1.5.0/docs/api</link>
+          </links>
+        </configuration>
+      </plugin>
+      <plugin>
+        <artifactId>maven-project-info-reports-plugin</artifactId>
+        <version>2.0.1</version>
+      </plugin>
+      <plugin>
+        <artifactId>maven-surefire-report-plugin</artifactId>
+        <version>2.3</version>
+        <reportSets>
+          <reportSet>
+            <reports>
+              <report>report-only</report>
+            </reports>
+          </reportSet>
+        </reportSets>
+      </plugin>
+      <plugin>
+        <groupId>org.codehaus.mojo</groupId>
+        <artifactId>taglist-maven-plugin</artifactId>
+        <version>2.0</version>
+      </plugin>
+    </plugins>
+  </reporting>
+  <distributionManagement>
+    <repository>
+      <id>repository.jboss.org</id>
+      <url>file:///projects/repository/maven2</url>
+    </repository>
+    <snapshotRepository>
+      <id>snapshots.jboss.org</id>
+      <name>JBoss Snapshot Repository</name>
+      <url>dav:https://snapshots.jboss.org/maven2</url>
+    </snapshotRepository>
+  </distributionManagement>
+  <properties>
+    <maven.repository.root>/projects/repository/maven2</maven.repository.root>
+    <version.junit>4.4</version.junit>
+    <jboss.repository.root>/projects/repository/jboss</jboss.repository.root>
+    <version.jboss.logging>2.0.5.GA</version.jboss.logging>
+    <version.jboss.test>1.1.0.GA</version.jboss.test>
+    <version.jboss.common.core>2.2.5.GA</version.jboss.common.core>
+  </properties>
+</project>
\ No newline at end of file

Deleted: projects/vfs/tags/2.0.0.Beta17/src/main/java/org/jboss/virtual/VFSUtils.java
===================================================================
--- projects/vfs/trunk/src/main/java/org/jboss/virtual/VFSUtils.java	2008-06-16 06:57:54 UTC (rev 74595)
+++ projects/vfs/tags/2.0.0.Beta17/src/main/java/org/jboss/virtual/VFSUtils.java	2008-06-16 14:28:54 UTC (rev 74620)
@@ -1,610 +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.io.InputStream;
-import java.io.UnsupportedEncodingException;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.net.URL;
-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;
-import org.jboss.virtual.plugins.copy.CopyMechanism;
-import org.jboss.virtual.plugins.copy.ExplodedCopyMechanism;
-import org.jboss.virtual.plugins.copy.TempCopyMechanism;
-import org.jboss.virtual.plugins.copy.UnpackCopyMechanism;
-import org.jboss.virtual.spi.LinkInfo;
-import org.jboss.virtual.spi.VFSContext;
-import org.jboss.virtual.spi.VirtualFileHandler;
-
-/**
- * VFS Utilities
- *
- * @author <a href="adrian at jboss.com">Adrian Brock</a>
- * @author <a href="ales.justin at jboss.com">Ales Justin</a>
- * @version $Revision: 1.1 $
- */
-public class VFSUtils
-{
-   /** The log */
-   private static final Logger log = Logger.getLogger(VFSUtils.class);
-   /** The link */
-   public static final String VFS_LINK_PREFIX = ".vfslink";
-   /** 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";
-
-   /**
-    * Get the paths string for a collection of virtual files
-    *
-    * @param paths the paths
-    * @return the string
-    * @throws IllegalArgumentException for null paths
-    */
-   public static String getPathsString(Collection<VirtualFile> paths)
-   {
-      if (paths == null)
-         throw new IllegalArgumentException("Null paths");
-
-      StringBuilder buffer = new StringBuilder();
-      boolean first = true;
-      for (VirtualFile path : paths)
-      {
-         if (path == null)
-            throw new IllegalArgumentException("Null path in " + paths);
-         if (first == false)
-            buffer.append(':');
-         else
-            first = false;
-         buffer.append(path.getPathName());
-      }
-
-      if (first == true)
-         buffer.append("<empty>");
-
-      return buffer.toString();
-   }
-
-   /**
-    * Add manifest paths
-    *
-    * @param file the file
-    * @param paths the paths to add to
-    * @throws IOException if there is an error reading the manifest or the
-    *         virtual file is closed
-    * @throws IllegalStateException if the file has no parent
-    * @throws IllegalArgumentException for a null file or paths
-    */
-   public static void addManifestLocations(VirtualFile file, List<VirtualFile> paths) throws IOException
-   {
-      if (file == null)
-         throw new IllegalArgumentException("Null file");
-      if (paths == null)
-         throw new IllegalArgumentException("Null paths");
-
-      Manifest manifest = getManifest(file);
-      if (manifest == null)
-         return;
-
-      Attributes mainAttributes = manifest.getMainAttributes();
-      String classPath = mainAttributes.getValue(Attributes.Name.CLASS_PATH);
-
-      if (classPath == null)
-      {
-         if (log.isTraceEnabled())
-            log.trace("Manifest has no Class-Path for " + file.getPathName());
-         return;
-      }
-
-      VirtualFile parent = file.getParent();
-      if (parent == null)
-         throw new IllegalStateException(file + " has no parent.");
-
-      URL parentURL;
-      URL vfsRootURL;
-      int rootPathLength;
-      try
-      {
-         parentURL = parent.toURL();
-         vfsRootURL = file.getVFS().getRoot().toURL();
-         rootPathLength = vfsRootURL.getPath().length();
-      }
-      catch(URISyntaxException e)
-      {
-         IOException ioe = new IOException("Failed to get parent URL for " + file);
-         ioe.initCause(e);
-         throw ioe;
-      }
-
-      StringTokenizer tokenizer = new StringTokenizer(classPath);
-      while (tokenizer.hasMoreTokens())
-      {
-         String path = tokenizer.nextToken();
-         try
-         {
-            String parentPath = parentURL.toString();
-            if(parentPath.endsWith("/") == false)
-               parentPath += "/";
-            URL libURL = new URL(parentPath + path);
-            String libPath = libURL.getPath();
-            // TODO, this occurs for inner jars. Doubtful that such a mf cp is valid
-            if( rootPathLength > libPath.length() )
-               throw new IOException("Invalid rootPath: "+vfsRootURL+", libPath: "+libPath);
-
-            String vfsLibPath = libPath.substring(rootPathLength);
-            VirtualFile vf = file.getVFS().getChild(vfsLibPath);
-            if(vf != null)
-            {
-               if(paths.contains(vf) == false)
-               {
-                  paths.add(vf);
-                  // Recursively process the jar
-                  addManifestLocations(vf, paths);
-               }
-            }
-         }
-         catch (IOException e)
-         {
-            log.debug("Manifest Class-Path entry " + path + " ignored for " + file.getPathName() + " reason=" + e);
-         }
-      }
-   }
-
-   /**
-    * Get a manifest from a virtual file,
-    * assuming the virtual file is the root of an archive
-    *
-    * @param archive the root the archive
-    * @return the manifest or null if not found
-    * @throws IOException if there is an error reading the manifest or the
-    *         virtual file is closed
-    * @throws IllegalArgumentException for a null archive
-    */
-   public static Manifest getManifest(VirtualFile archive) throws IOException
-   {
-      if (archive == null)
-         throw new IllegalArgumentException("Null archive");
-
-      VirtualFile manifest = archive.getChild(JarFile.MANIFEST_NAME);
-      if (manifest == null)
-      {
-         if (log.isTraceEnabled())
-            log.trace("Can't find manifest for " + archive.getPathName());
-         return null;
-      }
-      return readManifest(manifest);
-   }
-
-   /**
-    * Read the manifest from given manifest VirtualFile.
-    *
-    * @param manifest the VF to read from
-    * @return JAR's manifest
-    * @throws IOException if problems while opening VF stream occur
-    */
-   public static Manifest readManifest(VirtualFile manifest) throws IOException
-   {
-      if (manifest == null)
-         throw new IllegalArgumentException("Null manifest file");
-
-      InputStream stream = manifest.openStream();
-      try
-      {
-         return new Manifest(stream);
-      }
-      finally
-      {
-         try
-         {
-            stream.close();
-         }
-         catch (IOException ignored)
-         {
-         }
-      }
-   }
-
-   /**
-     * 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
-    * @return the fixed name
-    * @throws IllegalArgumentException for a null name
-    */
-   public static String fixName(String name)
-   {
-      if (name == null)
-         throw new IllegalArgumentException("Null name");
-
-      int length = name.length();
-      if (length <= 1)
-         return name;
-      if (name.charAt(length-1) == '/')
-         return name.substring(0, length-1);
-      return name;
-   }
-
-   /**
-    * Get the name.
-    *
-    * @param uri the uri
-    * @return name from uri's path
-    */
-   public static String getName(URI uri)
-   {
-      if (uri == null)
-         throw new IllegalArgumentException("Null uri");
-
-      String name = uri.getPath();
-      if( name != null )
-      {
-         // TODO: Not correct for certain uris like jar:...!/
-         int lastSlash = name.lastIndexOf('/');
-         if( lastSlash > 0 )
-            name = name.substring(lastSlash+1);
-      }
-      return name;
-   }
-
-   /**
-    * Take a URL.getQuery string and parse it into name=value pairs
-    *
-    * @param query Possibly empty/null url query string
-    * @return String[] for the name/value pairs in the query. May be empty but never null.
-    */
-   public static Map<String, String> parseURLQuery(String query)
-   {
-	   Map<String, String> pairsMap = CollectionsFactory.createLazyMap();
-      if(query != null)
-      {
-   	   StringTokenizer tokenizer = new StringTokenizer(query, "=&");
-   	   while(tokenizer.hasMoreTokens())
-   	   {
-   		   String name = tokenizer.nextToken();
-   		   String value = tokenizer.nextToken();
-   		   pairsMap.put(name, value);
-   	   }
-      }
-	   return pairsMap;
-   }
-
-   /**
-    * 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_PREFIX) >= 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(".properties"))
-      {
-         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
-    * @return uri the uri
-    * @throws URISyntaxException for any error
-    */
-   public static URI toURI(URL url) throws URISyntaxException
-   {
-      if (url == null)
-         throw new IllegalArgumentException("Null url");
-
-      String urispec = url.toExternalForm();
-      // Escape any spaces
-      urispec = urispec.replaceAll(" ", "%20");
-      return new URI(urispec);
-   }
-
-   /**
-    * Get the options for this file.
-    *
-    * @param file the file
-    * @return options map
-    */
-   private static Map<String, String> getOptions(VirtualFile file)
-   {
-      if (file == null)
-         throw new IllegalArgumentException("Null file");
-
-      VirtualFileHandler handler = file.getHandler();
-      VFSContext context = handler.getVFSContext();
-      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)
-   {
-      Map<String, String> options = getOptions(file);
-      return options != null ? options.get(key) : null;
-   }
-
-   /**
-    * Enable copy for file param.
-    *
-    * @param file the file
-    */
-   public static void enableCopy(VirtualFile file)
-   {
-      Map<String, String> options = getOptions(file);
-      if (options == null)
-         throw new IllegalArgumentException("Cannot enable copy on null options: " + file);
-
-      options.put(USE_COPY_QUERY, Boolean.TRUE.toString());
-   }
-
-   /**
-    * Disable copy for file param.
-    *
-    * @param file the file
-    */
-   public static void disableCopy(VirtualFile file)
-   {
-      Map<String, String> options = getOptions(file);
-      if (options == null)
-         throw new IllegalArgumentException("Cannot disable copy on null options: " + file);
-
-      options.remove(USE_COPY_QUERY);
-   }
-
-   /**
-    * 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
-   {
-      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);
-   }
-
-   /**
-    * 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();
-   }
-
-   /**
-    * Get spec compatilbe url from virtual file.
-    *
-    * @param file the virtual file
-    * @return spec compatible url
-    * @throws IOException for any error
-    * @throws URISyntaxException for any uri syntax error
-    */
-   public static URL getCompatibleURL(VirtualFile file) throws IOException, URISyntaxException
-   {
-      if (file == null)
-         throw new IllegalArgumentException("Null file");
-
-      URL url = file.toURL();
-      if (url == null)
-         throw new IllegalArgumentException("Null url: " + file);
-
-      // is not nested, so direct VFS URL is not an option
-      if (isNestedFile(file) == false)
-      {
-         String urlString = url.toExternalForm();
-         if (urlString.startsWith("vfs"))
-         {
-            // treat vfszip as file
-            if (urlString.startsWith("vfszip"))
-               url = new URL("file" + urlString.substring(6));
-            else
-               url = new URL(urlString.substring(3)); // (vfs)file and (vfs)jar are ok
-         }
-      }
-      return url;
-   }
-}

Copied: projects/vfs/tags/2.0.0.Beta17/src/main/java/org/jboss/virtual/VFSUtils.java (from rev 74599, projects/vfs/trunk/src/main/java/org/jboss/virtual/VFSUtils.java)
===================================================================
--- projects/vfs/tags/2.0.0.Beta17/src/main/java/org/jboss/virtual/VFSUtils.java	                        (rev 0)
+++ projects/vfs/tags/2.0.0.Beta17/src/main/java/org/jboss/virtual/VFSUtils.java	2008-06-16 14:28:54 UTC (rev 74620)
@@ -0,0 +1,615 @@
+/*
+* 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.io.InputStream;
+import java.io.UnsupportedEncodingException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+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;
+import org.jboss.virtual.plugins.copy.CopyMechanism;
+import org.jboss.virtual.plugins.copy.ExplodedCopyMechanism;
+import org.jboss.virtual.plugins.copy.TempCopyMechanism;
+import org.jboss.virtual.plugins.copy.UnpackCopyMechanism;
+import org.jboss.virtual.spi.LinkInfo;
+import org.jboss.virtual.spi.VFSContext;
+import org.jboss.virtual.spi.VirtualFileHandler;
+
+/**
+ * VFS Utilities
+ *
+ * @author <a href="adrian at jboss.com">Adrian Brock</a>
+ * @author <a href="ales.justin at jboss.com">Ales Justin</a>
+ * @version $Revision: 1.1 $
+ */
+public class VFSUtils
+{
+   /** The log */
+   private static final Logger log = Logger.getLogger(VFSUtils.class);
+   /** The link */
+   public static final String VFS_LINK_PREFIX = ".vfslink";
+   /** 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";
+
+   /**
+    * Get the paths string for a collection of virtual files
+    *
+    * @param paths the paths
+    * @return the string
+    * @throws IllegalArgumentException for null paths
+    */
+   public static String getPathsString(Collection<VirtualFile> paths)
+   {
+      if (paths == null)
+         throw new IllegalArgumentException("Null paths");
+
+      StringBuilder buffer = new StringBuilder();
+      boolean first = true;
+      for (VirtualFile path : paths)
+      {
+         if (path == null)
+            throw new IllegalArgumentException("Null path in " + paths);
+         if (first == false)
+            buffer.append(':');
+         else
+            first = false;
+         buffer.append(path.getPathName());
+      }
+
+      if (first == true)
+         buffer.append("<empty>");
+
+      return buffer.toString();
+   }
+
+   /**
+    * Add manifest paths
+    *
+    * @param file the file
+    * @param paths the paths to add to
+    * @throws IOException if there is an error reading the manifest or the
+    *         virtual file is closed
+    * @throws IllegalStateException if the file has no parent
+    * @throws IllegalArgumentException for a null file or paths
+    */
+   public static void addManifestLocations(VirtualFile file, List<VirtualFile> paths) throws IOException
+   {
+      if (file == null)
+         throw new IllegalArgumentException("Null file");
+      if (paths == null)
+         throw new IllegalArgumentException("Null paths");
+
+      Manifest manifest = getManifest(file);
+      if (manifest == null)
+         return;
+
+      Attributes mainAttributes = manifest.getMainAttributes();
+      String classPath = mainAttributes.getValue(Attributes.Name.CLASS_PATH);
+
+      if (classPath == null)
+      {
+         if (log.isTraceEnabled())
+            log.trace("Manifest has no Class-Path for " + file.getPathName());
+         return;
+      }
+
+      VirtualFile parent = file.getParent();
+      if (parent == null)
+      {
+         log.debug(file + " has no parent.");
+         return;
+      }
+
+      URL parentURL;
+      URL vfsRootURL;
+      int rootPathLength;
+      try
+      {
+         parentURL = parent.toURL();
+         vfsRootURL = file.getVFS().getRoot().toURL();
+         rootPathLength = vfsRootURL.getPath().length();
+      }
+      catch(URISyntaxException e)
+      {
+         log.debug("Failed to get parent URL for " + file + ", reason=" + e);
+         return;
+      }
+
+      String parentPath = parentURL.toString();
+      if(parentPath.endsWith("/") == false)
+         parentPath += "/";
+
+      StringTokenizer tokenizer = new StringTokenizer(classPath);
+      while (tokenizer.hasMoreTokens())
+      {
+         String path = tokenizer.nextToken();
+         try
+         {
+            URL libURL = new URL(parentPath + path);
+            String libPath = libURL.getPath();
+            if(rootPathLength > libPath.length())
+            {
+               log.debug("Invalid rootPath: " + vfsRootURL + ", libPath: " + libPath);
+               continue;
+            }
+
+            String vfsLibPath = libPath.substring(rootPathLength);
+            VirtualFile vf = file.getVFS().getChild(vfsLibPath);
+            if(vf != null)
+            {
+               if(paths.contains(vf) == false)
+               {
+                  paths.add(vf);
+                  // Recursively process the jar
+                  addManifestLocations(vf, paths);
+               }
+            }
+         }
+         catch (IOException e)
+         {
+            log.debug("Manifest Class-Path entry " + path + " ignored for " + file.getPathName() + " reason=" + e);
+         }
+      }
+   }
+
+   /**
+    * Get a manifest from a virtual file,
+    * assuming the virtual file is the root of an archive
+    *
+    * @param archive the root the archive
+    * @return the manifest or null if not found
+    * @throws IOException if there is an error reading the manifest or the
+    *         virtual file is closed
+    * @throws IllegalArgumentException for a null archive
+    */
+   public static Manifest getManifest(VirtualFile archive) throws IOException
+   {
+      if (archive == null)
+         throw new IllegalArgumentException("Null archive");
+
+      VirtualFile manifest = archive.getChild(JarFile.MANIFEST_NAME);
+      if (manifest == null)
+      {
+         if (log.isTraceEnabled())
+            log.trace("Can't find manifest for " + archive.getPathName());
+         return null;
+      }
+      return readManifest(manifest);
+   }
+
+   /**
+    * Read the manifest from given manifest VirtualFile.
+    *
+    * @param manifest the VF to read from
+    * @return JAR's manifest
+    * @throws IOException if problems while opening VF stream occur
+    */
+   public static Manifest readManifest(VirtualFile manifest) throws IOException
+   {
+      if (manifest == null)
+         throw new IllegalArgumentException("Null manifest file");
+
+      InputStream stream = manifest.openStream();
+      try
+      {
+         return new Manifest(stream);
+      }
+      finally
+      {
+         try
+         {
+            stream.close();
+         }
+         catch (IOException ignored)
+         {
+         }
+      }
+   }
+
+   /**
+     * 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
+    * @return the fixed name
+    * @throws IllegalArgumentException for a null name
+    */
+   public static String fixName(String name)
+   {
+      if (name == null)
+         throw new IllegalArgumentException("Null name");
+
+      int length = name.length();
+      if (length <= 1)
+         return name;
+      if (name.charAt(length-1) == '/')
+         return name.substring(0, length-1);
+      return name;
+   }
+
+   /**
+    * Get the name.
+    *
+    * @param uri the uri
+    * @return name from uri's path
+    */
+   public static String getName(URI uri)
+   {
+      if (uri == null)
+         throw new IllegalArgumentException("Null uri");
+
+      String name = uri.getPath();
+      if( name != null )
+      {
+         // TODO: Not correct for certain uris like jar:...!/
+         int lastSlash = name.lastIndexOf('/');
+         if( lastSlash > 0 )
+            name = name.substring(lastSlash+1);
+      }
+      return name;
+   }
+
+   /**
+    * Take a URL.getQuery string and parse it into name=value pairs
+    *
+    * @param query Possibly empty/null url query string
+    * @return String[] for the name/value pairs in the query. May be empty but never null.
+    */
+   public static Map<String, String> parseURLQuery(String query)
+   {
+	   Map<String, String> pairsMap = CollectionsFactory.createLazyMap();
+      if(query != null)
+      {
+   	   StringTokenizer tokenizer = new StringTokenizer(query, "=&");
+   	   while(tokenizer.hasMoreTokens())
+   	   {
+   		   String name = tokenizer.nextToken();
+   		   String value = tokenizer.nextToken();
+   		   pairsMap.put(name, value);
+   	   }
+      }
+	   return pairsMap;
+   }
+
+   /**
+    * 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_PREFIX) >= 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(".properties"))
+      {
+         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
+    * @return uri the uri
+    * @throws URISyntaxException for any error
+    */
+   public static URI toURI(URL url) throws URISyntaxException
+   {
+      if (url == null)
+         throw new IllegalArgumentException("Null url");
+
+      String urispec = url.toExternalForm();
+      // Escape any spaces
+      urispec = urispec.replaceAll(" ", "%20");
+      return new URI(urispec);
+   }
+
+   /**
+    * Get the options for this file.
+    *
+    * @param file the file
+    * @return options map
+    */
+   private static Map<String, String> getOptions(VirtualFile file)
+   {
+      if (file == null)
+         throw new IllegalArgumentException("Null file");
+
+      VirtualFileHandler handler = file.getHandler();
+      VFSContext context = handler.getVFSContext();
+      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)
+   {
+      Map<String, String> options = getOptions(file);
+      return options != null ? options.get(key) : null;
+   }
+
+   /**
+    * Enable copy for file param.
+    *
+    * @param file the file
+    */
+   public static void enableCopy(VirtualFile file)
+   {
+      Map<String, String> options = getOptions(file);
+      if (options == null)
+         throw new IllegalArgumentException("Cannot enable copy on null options: " + file);
+
+      options.put(USE_COPY_QUERY, Boolean.TRUE.toString());
+   }
+
+   /**
+    * Disable copy for file param.
+    *
+    * @param file the file
+    */
+   public static void disableCopy(VirtualFile file)
+   {
+      Map<String, String> options = getOptions(file);
+      if (options == null)
+         throw new IllegalArgumentException("Cannot disable copy on null options: " + file);
+
+      options.remove(USE_COPY_QUERY);
+   }
+
+   /**
+    * 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
+   {
+      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);
+   }
+
+   /**
+    * 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();
+   }
+
+   /**
+    * Get spec compatilbe url from virtual file.
+    *
+    * @param file the virtual file
+    * @return spec compatible url
+    * @throws IOException for any error
+    * @throws URISyntaxException for any uri syntax error
+    */
+   public static URL getCompatibleURL(VirtualFile file) throws IOException, URISyntaxException
+   {
+      if (file == null)
+         throw new IllegalArgumentException("Null file");
+
+      URL url = file.toURL();
+      if (url == null)
+         throw new IllegalArgumentException("Null url: " + file);
+
+      // is not nested, so direct VFS URL is not an option
+      if (isNestedFile(file) == false)
+      {
+         String urlString = url.toExternalForm();
+         if (urlString.startsWith("vfs"))
+         {
+            // treat vfszip as file
+            if (urlString.startsWith("vfszip"))
+               url = new URL("file" + urlString.substring(6));
+            else
+               url = new URL(urlString.substring(3)); // (vfs)file and (vfs)jar are ok
+         }
+      }
+      return url;
+   }
+}

Deleted: projects/vfs/tags/2.0.0.Beta17/src/main/java/org/jboss/virtual/plugins/context/zip/ZipEntryContext.java
===================================================================
--- projects/vfs/trunk/src/main/java/org/jboss/virtual/plugins/context/zip/ZipEntryContext.java	2008-06-16 06:57:54 UTC (rev 74595)
+++ projects/vfs/tags/2.0.0.Beta17/src/main/java/org/jboss/virtual/plugins/context/zip/ZipEntryContext.java	2008-06-16 14:28:54 UTC (rev 74620)
@@ -1,1191 +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.plugins.context.zip;
-
-import java.io.BufferedOutputStream;
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.net.MalformedURLException;
-import java.net.URISyntaxException;
-import java.net.URL;
-import java.security.AccessController;
-import java.security.PrivilegedAction;
-import java.util.Collections;
-import java.util.Enumeration;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.TreeMap;
-import java.util.UUID;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.zip.ZipEntry;
-import java.util.zip.ZipInputStream;
-
-import org.jboss.logging.Logger;
-import org.jboss.virtual.VFSUtils;
-import org.jboss.virtual.plugins.context.AbstractVFSContext;
-import org.jboss.virtual.plugins.context.AbstractVirtualFileHandler;
-import org.jboss.virtual.plugins.context.DelegatingHandler;
-import org.jboss.virtual.plugins.context.jar.JarUtils;
-import org.jboss.virtual.plugins.copy.AbstractCopyMechanism;
-import org.jboss.virtual.spi.VirtualFileHandler;
-
-/**
- * <tt>ZipEntryContext</tt> implements a {@link org.jboss.virtual.spi.VFSContext}
- * that exposes a zip archive as a virtual file system.
- *
- * Zip archive can be in a form of a file or a stream.
- *
- * Nested archives are processed through this same class.
- * By default nested archives are cached in memory and mounted as new
- * instances of <tt>ZipEntryContext</tt> with <tt>ZipStreamWrapper</tt> as a source.
- * If system property <em>jboss.vfs.forceCopy=true</em> is specified,
- * or URL query parameter <em>forceCopy=true</em> is present,
- * nested archives are extracted into a temp directory before being
- * mounted as new instances of <tt>ZipEntryContext</tt>.
- *
- * In-memory nested archives may consume a lot of memory. To reduce memory footprint
- * at the expense of performance, system property <em>jboss.vfs.optimizeForMemory=true<em>
- * can be set.
- *
- * This context implementation has two modes of releasing file locks.
- * <em>Asynchronous</em> mode is the default one since it is better performant.
- * To switch this to <em>synchronous</em> mode a system property
- * <em>jboss.vfs.forceNoReaper=true</em> can be specified or URL query parameter
- * <em>noReaper=true</em> can be included in context URL.
- *
- * This context implementation is a replacement for
- * {@link org.jboss.virtual.plugins.context.jar.JarContext}.
- *
- * @author <a href="strukelj at parsek.net">Marko Strukelj</a>
- * @version $Revision: 1.0 $
- */
-public class ZipEntryContext extends AbstractVFSContext
-{
-   /** Logger */
-   private static final Logger log = Logger.getLogger(ZipEntryContext.class);
-
-   /** Global setting for nested archive processing mode: copy or no-copy (default) */
-   private static boolean forceCopy;
-
-   static
-   {
-      deleteTmpDirContents();
-
-      forceCopy = AccessController.doPrivileged(new CheckForceCopy());
-
-      if (forceCopy)
-         log.info("VFS force nested jars copy-mode is enabled.");
-   }
-
-   /** Abstracted access to zip archive - either ZipFileWrapper or ZipStreamWrapper */
-   private ZipWrapper zipSource;
-
-   /** Entry path representing a context root - archive root is not necessarily a context root */
-   private String rootEntryPath = "";
-
-   /** AutoClean signals if zip archive should be deleted after closing the context - true for nested archives */
-   private boolean autoClean = false;
-
-   /** Registry of everything that zipSource contains */
-   private Map<String, EntryInfo> entries = new ConcurrentHashMap<String, EntryInfo>();
-
-   /**
-    * Create a new ZipEntryContext
-    *
-    * @param rootURL - file or jar:file url
-    * @throws URISyntaxException for any URI error
-    * @throws java.io.IOException for any error
-    */
-   public ZipEntryContext(URL rootURL) throws URISyntaxException, IOException
-   {
-      this(rootURL, false);
-   }
-
-   /**
-    * Create a new ZipEntryContext
-    *
-    * @param rootURL - file or jar:file url
-    * @param autoClean - true if file represented by rootURL should be deleted after this context is closed
-    * @throws URISyntaxException for any URI error
-    * @throws java.io.IOException for any error
-    */
-   public ZipEntryContext(URL rootURL, boolean autoClean) throws URISyntaxException, IOException
-   {
-      super(VFSUtils.toURI(fixUrl(rootURL)));
-      this.autoClean = autoClean;
-      init(rootURL, null, null);
-   }
-
-   /**
-    * Create a new ZipEntryContext to be mounted into another context
-    *
-    * @param rootURL - url representing this context within another context
-    * @param peer - file handler in another context through which this context is being mounted
-    * @param localRootUrl - file or jar:file url
-    * @throws URISyntaxException for any URI error
-    * @throws java.io.IOException for any error
-    */
-   public ZipEntryContext(URL rootURL, VirtualFileHandler peer, URL localRootUrl) throws URISyntaxException, IOException
-   {
-      this(rootURL, peer, localRootUrl, false);
-   }
-
-   /**
-    * Create a new ZipEntryContext to be mounted into another context
-    *
-    * @param rootURL - url representing this context within another context
-    * @param peer - file handler in another context through which this context is being mounted
-    * @param localRootUrl - file or jar:file url
-    * @param autoClean - true if file represented by localRootURL should be deleted after this context is closed
-    * @throws URISyntaxException for any URI error
-    * @throws java.io.IOException for any error
-    */
-   public ZipEntryContext(URL rootURL, VirtualFileHandler peer, URL localRootUrl, boolean autoClean) throws URISyntaxException, IOException
-   {
-      super(VFSUtils.toURI(fixUrl(rootURL)));
-      this.autoClean = autoClean;
-      init(localRootUrl, peer, null);
-   }
-
-   /**
-    * Create a new ZipEntryContext to be mounted into another context
-    *
-    * @param rootURL - url representing this context within another context
-    * @param peer - file handler in another context through which this context is being mounted
-    * @param zipWrapper - abstracted zip archive source
-    * @param autoClean - true if file represented by localRootURL should be deleted after this context is closed
-    * @throws URISyntaxException for any URI error
-    * @throws java.io.IOException for any error
-    */
-   public ZipEntryContext(URL rootURL, VirtualFileHandler peer, ZipWrapper zipWrapper, boolean autoClean) throws URISyntaxException, IOException
-   {
-      super(VFSUtils.toURI(fixUrl(rootURL)));
-      this.autoClean = autoClean;
-      init(null, peer, zipWrapper);
-   }
-
-   /**
-    * Extra initialization in addition to what's inside constructors
-    *
-    * @param localRootURL the local url
-    * @param peer the peer
-    * @param zipWrapper zip wrapper
-    * @throws URISyntaxException for any URI error
-    * @throws java.io.IOException for any error
-    */
-   private void init(URL localRootURL, VirtualFileHandler peer, ZipWrapper zipWrapper) throws IOException, URISyntaxException
-   {
-      if (zipWrapper == null)
-      {
-         if (localRootURL == null)
-            throw new IllegalArgumentException("No ZipWrapper specified and localRootURL is null");
-
-         // initialize rootEntryPath and get archive file path
-         String rootPath = initRootAndPath(localRootURL);
-         zipSource = createZipSource(rootPath);
-      }
-      else
-      {
-         zipSource = zipWrapper;
-      }
-      
-      setRootPeer(peer);
-
-      String name = getRootURI().toString();
-      int toPos = name.length();
-
-      // cut off any ending slash
-      if(name.length() != 0 && name.charAt(name.length()-1) == '/')
-         toPos --;
-
-      // name is last path component
-      int namePos = name.lastIndexOf("/", toPos-1);
-      name = name.substring(namePos+1, toPos);
-      
-      // cut off any ending exclamation
-      if(name.length() != 0 && name.charAt(name.length()-1) == '!')
-         name = name.substring(0, name.length()-1);
-
-      // init initial root EntryInfo that will be overwritten
-      // if zip entry exists for rootEntryPath
-      entries.put("", new EntryInfo(new ZipEntryHandler(this, null, name, true), null));
-
-      initEntries();
-   }
-
-   /**
-    * Create zip source.
-    *
-    * @param rootPath the root path
-    * @return zip entry wrapper
-    * @throws IOException for any error
-    */
-   protected ZipWrapper createZipSource(String rootPath) throws IOException
-   {
-      File file = null;
-      String relative = null;
-      File fp = new File(rootPath);
-      if (fp.exists())
-      {
-         file = fp;
-      }
-      else
-      {
-         File curr = fp;
-         relative = fp.getName();
-         while ((curr = curr.getParentFile()) != null)
-         {
-            if (curr.exists())
-            {
-               file = curr;
-               break;
-            }
-            else
-            {
-               relative = curr.getName() + "/" + relative;
-            }
-         }
-      }
-
-      if (file == null)
-         throw new IOException("VFS file does not exist: " + rootPath);
-
-      if (relative != null)
-      {
-         return findEntry(new FileInputStream(file), relative);
-      }
-      else
-      {
-         boolean noReaper = Boolean.valueOf(getOptions().get(VFSUtils.NO_REAPER_QUERY));
-         return new ZipFileWrapper(file, autoClean, noReaper);
-      }
-   }
-
-   /**
-    * Find exact entry.
-    * Use recursion on relative path.
-    *
-    * @param is the input stream
-    * @param relative relative path
-    * @return zip wrapper instance
-    * @throws IOException for any error
-    */
-   protected static ZipWrapper findEntry(InputStream is, String relative) throws IOException
-   {
-      ByteArrayOutputStream baos = new ByteArrayOutputStream();
-      ZipEntryContext.copyStreamAndClose(is, baos);
-      ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
-
-      // first we need to find best/longest name
-      ZipInputStream zis = new ZipInputStream(bais);
-      ZipEntry entry;
-      String longestNameMatch = null;
-      while((entry = zis.getNextEntry()) != null)
-      {
-         String entryName = entry.getName();
-         if (relative.startsWith(entryName))
-         {
-            if (entryName.equals(relative))
-            {
-               InputStream stream = new SizeLimitedInputStream(zis, entry.getSize());
-               // directories and non archives
-               if (entry.isDirectory() || JarUtils.isArchive(entryName) == false)
-               {
-                  return new ZipEntryWrapper(stream, entryName, System.currentTimeMillis());
-               }
-               else
-                  return new ZipStreamWrapper(stream, entryName, System.currentTimeMillis());
-            }
-
-            if (longestNameMatch == null || longestNameMatch.length() < entryName.length())
-            {
-               longestNameMatch = entryName;
-            }
-         }
-      }
-      if (longestNameMatch == null)
-         throw new IllegalArgumentException("Cannot find entry: " + is + ", " + relative);
-
-      // do recursion on relative
-      bais.reset();
-      zis = new ZipInputStream(bais);
-      while((entry = zis.getNextEntry()) != null)
-      {
-         String entryName = entry.getName();
-         if (entryName.equals(longestNameMatch))
-         {
-            relative = relative.substring(longestNameMatch.length() + 1);
-            return findEntry(new SizeLimitedInputStream(zis, entry.getSize()), relative);
-         }
-      }
-      throw new IllegalArgumentException("No such entry: " + is + ", " + relative);
-   }
-
-   /**
-    * Returns archive file name - if this is a top-level ZipEntryContext.
-    * Otherwise it returns the last component of URL.
-    *
-    * @return name
-    */
-   public String getName()
-   {
-      VirtualFileHandler peer = getRootPeer();
-      if (peer != null)
-         return peer.getName();
-      else
-         return zipSource.getName();
-   }
-
-   /**
-    * Iterate through zip archive entries, compose a tree structure of archive's content
-    *
-    * @throws URISyntaxException for any URI error
-    * @throws java.io.IOException for any error
-    */
-   private synchronized void initEntries() throws IOException, URISyntaxException
-   {
-      // we're using a two phase approach - we first select the relevant ones
-      // then we order these by name and only then we process them
-      // this way we ensure that parent entries are processed before child entries
-
-      Map<String, ZipEntry> relevant = new HashMap<String, ZipEntry>();
-      zipSource.acquire();
-      try
-      {
-         Enumeration<? extends ZipEntry> zipEntries = zipSource.entries();
-         // zoom-in on entries under rootEntryPath - ignoring the rest
-         while(zipEntries.hasMoreElements())
-         {
-            ZipEntry ent = zipEntries.nextElement();
-            if(ent.getName().startsWith(rootEntryPath))
-            {
-               relevant.put(ent.getName(), ent);
-            }
-         }
-
-         Map<String, ZipEntry> orderedRelevant = new TreeMap<String, ZipEntry>(relevant);
-         for(Map.Entry<String, ZipEntry> entry : orderedRelevant.entrySet())
-         {
-            ZipEntry ent = entry.getValue();
-            String fullName = ent.getName().substring(rootEntryPath.length());
-
-            String [] split = splitParentChild(fullName);
-            String parentPath = split[0];
-            String name = split[1];
-
-            EntryInfo ei = entries.get(parentPath);
-            if(ei == null)
-               ei = makeDummyParent(parentPath);
-
-            AbstractVirtualFileHandler parent = ei != null ? ei.handler : null;
-
-            if(ent.isDirectory() == false && JarUtils.isArchive(ent.getName()))
-            {
-               boolean useCopyMode = forceCopy;
-               if (useCopyMode == false)
-               {
-                  String flag = getOptions().get(VFSUtils.USE_COPY_QUERY);
-                  useCopyMode = Boolean.valueOf(flag);
-               }
-
-               DelegatingHandler delegator;
-
-               if (useCopyMode)
-               {
-                  // extract it to temp dir
-                  File dest = new File(getTempDir() + "/" + getTempFileName(ent.getName()));
-                  dest.deleteOnExit();
-
-                  // ensure parent exists
-                  dest.getParentFile().mkdirs();
-
-                  InputStream is = zipSource.openStream(ent);
-                  OutputStream os = new BufferedOutputStream(new FileOutputStream(dest));
-                  copyStreamAndClose(is, os);
-
-                  // mount another instance of ZipEntryContext
-                  delegator = mountZipFile(parent, name, dest);
-               }
-               else
-               {
-                  // mount another instance of ZipEntryContext
-                  delegator = mountZipStream(parent, name, zipSource.openStream(ent));
-               }
-
-               entries.put(delegator.getLocalPathName(), new EntryInfo(delegator, ent));
-               addChild(parent, delegator);
-            }
-            else
-            {
-               ZipEntryHandler wrapper = new ZipEntryHandler(this, parent, name, ent.isDirectory() == false);
-               entries.put(wrapper.getLocalPathName(), new EntryInfo(wrapper, ent));
-            }
-         }
-      }
-      finally
-      {
-         zipSource.release();
-      }
-   }
-
-   /**
-    * Mount ZipEntryContext created around extracted nested archive
-    *
-    * @param parent the parent
-    * @param name the name
-    * @param file the file
-    * @return mounted delegate
-    * @throws IOException for any error
-    * @throws URISyntaxException for any URI syntax error
-    */
-   protected DelegatingHandler mountZipFile(VirtualFileHandler parent, String name, File file) throws IOException, URISyntaxException
-   {
-      DelegatingHandler delegator = new DelegatingHandler(this, parent, name);
-      URL fileUrl = file.toURL();
-      URL delegatorUrl = fileUrl;
-
-      if (parent != null)
-         delegatorUrl = getChildURL(parent, name);
-
-      ZipEntryContext ctx = new ZipEntryContext(delegatorUrl, delegator, fileUrl, true);
-      VirtualFileHandler handler = ctx.getRoot();
-      delegator.setDelegate(handler);
-
-      return delegator;
-   }
-
-   /**
-    * Mount ZipEntryContext created around ZipStreamWrapper
-    *
-    * @param parent the parent
-    * @param name the name
-    * @param zipStream the zip stream
-    * @return mounted delegate
-    * @throws IOException for any error
-    * @throws URISyntaxException for any URI syntax error
-    */
-   protected DelegatingHandler mountZipStream(VirtualFileHandler parent, String name, InputStream zipStream) throws IOException, URISyntaxException
-   {
-      DelegatingHandler delegator = new DelegatingHandler(this, parent, name);
-      ZipStreamWrapper wrapper = new ZipStreamWrapper(zipStream, name, parent.getLastModified());
-
-      URL delegatorUrl = null;
-
-      if (parent != null)
-         delegatorUrl = getChildURL(parent, name);
-
-      ZipEntryContext ctx = new ZipEntryContext(delegatorUrl, delegator, wrapper, false);
-      VirtualFileHandler handler = ctx.getRoot();
-      delegator.setDelegate(handler);
-
-      return delegator;
-   }
-
-   /**
-    * Zip archives sometimes don't contain directory entries - only leaf entries
-    *
-    * @param parentPath the parent path
-    * @return entry info
-    * @throws IOException for any error
-    */
-   private EntryInfo makeDummyParent(String parentPath) throws IOException
-   {
-      // get grand parent first
-      String [] split = splitParentChild(parentPath);
-      String grandPa = split[0];
-
-      EntryInfo eiParent = entries.get(grandPa);
-      if(eiParent == null)
-         eiParent = makeDummyParent(grandPa);
-
-      ZipEntryHandler handler = new ZipEntryHandler(this, eiParent.handler, split[1], false);
-      EntryInfo ei = new EntryInfo(handler, null);
-      entries.put(parentPath, ei);
-      return ei;
-   }
-
-   /**
-    * Initialize rootEntryPath and return archive file path
-    *
-    * @param localRootUrl local root url
-    * @return file path
-    */
-   private String initRootAndPath(URL localRootUrl)
-   {
-      String filePath = localRootUrl.toString();
-      String zipPath = filePath;
-
-      int pos = filePath.indexOf("!");
-      if(pos > 0)
-      {
-         zipPath = filePath.substring(0, pos);
-         rootEntryPath = filePath.substring(pos+2);
-         if(rootEntryPath.length() != 0)
-            rootEntryPath += "/";
-      }
-
-      // find where url protocol ends - i.e. jar:file:/ ...
-      pos= zipPath.indexOf(":/");
-      filePath = zipPath.substring(pos + 2);
-
-      // cut out url query part if present
-      int queryStart = filePath.indexOf("?");
-      if (queryStart != -1)
-         filePath = filePath.substring(0, queryStart);
-
-      return filePath;
-   }
-
-   /**
-    * If archive has been modified, clear <em>entries</em> and re-initialize
-    */
-   private synchronized void checkIfModified()
-   {
-      // TODO: if zipSource represents a nested archive we should maybe delegate lastModified to its parent
-      if (zipSource.hasBeenModified())
-      {
-         EntryInfo rootInfo = entries.get("");
-         entries = new ConcurrentHashMap<String, EntryInfo>();
-         entries.put("", rootInfo);
-
-         if (zipSource.exists())
-         {
-            try
-            {
-               initEntries();
-            }
-            catch(Exception ignored)
-            {
-               log.warn("IGNORING: Failed to reinitialize context: " + getRootURI(), ignored);
-            }
-         }
-      }
-   }
-
-   /**
-    * Returns this context's root
-    *
-    * @return root handler
-    * @throws IOException for any error
-    */
-   public VirtualFileHandler getRoot() throws IOException
-   {
-      return entries.get("").handler;
-   }
-
-   /**
-    * Find a child with a given name and a given parent
-    *
-    * @param parent parent handler
-    * @param name  name of the child
-    * @return child handler or null if not found
-    */
-   public VirtualFileHandler getChild(ZipEntryHandler parent, String name)
-   {
-      if (parent == null)
-         throw new IllegalArgumentException("Null parent");
-
-      checkIfModified();
-      String pathName = parent.getLocalPathName();
-      if("".equals(pathName))
-         pathName = name;
-      else
-         pathName = pathName + "/" + name;
-
-      EntryInfo ei = entries.get(pathName);
-      
-      if(ei != null)
-         return ei.handler;
-
-      return null;
-   }
-
-   /**
-    * Returns a list of children for a given parent
-    *
-    * @param parent parent handler
-    * @param ignoreErrors true if errors should be silently ignored
-    * @return list of handlers representing children of the given parent
-    * @throws IOException for any error
-    */
-   public List<VirtualFileHandler> getChildren(VirtualFileHandler parent, boolean ignoreErrors) throws IOException
-   {
-      if (parent == null)
-         throw new IllegalArgumentException("Null parent");
-
-      checkIfModified();
-      if(parent instanceof AbstractVirtualFileHandler)
-      {
-         AbstractVirtualFileHandler parentHandler  = (AbstractVirtualFileHandler) parent;
-         EntryInfo parentEntry = entries.get(parentHandler.getLocalPathName());
-         if (parentEntry != null)
-         {
-            if (parentEntry.handler instanceof DelegatingHandler)
-               return parentEntry.handler.getChildren(ignoreErrors);
-            
-            return parentEntry.getChildren();
-         }
-      }
-      return Collections.emptyList();
-   }
-
-   /**
-    * Returns lastModified timestamp for a given handler
-    *
-    * @param handler a handler
-    * @return lastModified timestamp
-    */
-   public long getLastModified(ZipEntryHandler handler)
-   {
-      if (handler == null)
-         throw new IllegalArgumentException("Null handler");
-
-      checkIfModified();
-      EntryInfo ei = entries.get(handler.getLocalPathName());
-      if(ei == null)
-         return 0;
-
-      if(ei.entry == null) {
-         return zipSource.getLastModified();
-      }
-
-      return ei.entry.getTime();
-   }
-
-   /**
-    * Returns the size for a given handler
-    *
-    * @param handler a handler
-    * @return size in bytes
-    */
-   public long getSize(ZipEntryHandler handler)
-   {
-      if (handler == null)
-         throw new IllegalArgumentException("Null handler");
-
-      checkIfModified();
-      String pathName = handler.getLocalPathName();
-      EntryInfo ei = entries.get(pathName);
-      if(ei == null)
-         return 0;
-
-      if(ei.entry == null)
-      {
-         if(pathName.length() == 0)
-            return zipSource.getSize();
-         else
-            return 0;
-      }
-
-      return ei.entry.getSize();
-   }
-
-   /**
-    * Returns true if entry exists for a given handler
-    *
-    * @param handler a handler
-    * @return true if entry exists
-    */
-   public boolean exists(ZipEntryHandler handler)
-   {
-      if (handler == null)
-         throw new IllegalArgumentException("Null handler");
-
-      checkIfModified();
-      String pathName = handler.getLocalPathName();
-      EntryInfo ei = entries.get(pathName);
-      if(ei == null)
-         return false;
-
-      if (ei.entry == null && pathName.length() == 0)
-         return zipSource.exists();
-
-      return true;
-   }
-
-   /**
-    * Returns true if handler represents a non-directory entry
-    *
-    * @param handler a handler
-    * @return true if not a directory
-    */
-   public boolean isLeaf(ZipEntryHandler handler)
-   {
-      if (handler == null)
-         throw new IllegalArgumentException("Null handler");
-
-      checkIfModified();
-      EntryInfo ei = entries.get(handler.getLocalPathName());
-      if(ei == null || ei.entry == null)
-         return false;
-
-      return !ei.entry.isDirectory();
-   }
-
-   /**
-    * Is archive.
-    *
-    * @param handler the handler
-    * @return true if archive
-    */
-   static boolean isArchive(VirtualFileHandler handler)
-   {
-      if (handler instanceof ZipEntryHandler && "".equals(handler.getLocalPathName()))
-      {
-         return true;
-      }
-
-      if (handler instanceof DelegatingHandler && ((DelegatingHandler) handler).getDelegate() instanceof ZipEntryHandler)
-      {
-         return true;
-      }
-
-      return false;
-   }
-
-   /**
-    * Get parent.
-    *
-    * @param handler the handler to check
-    * @return parent handler
-    * @throws IOException for any error
-    */
-   static VirtualFileHandler getParent(VirtualFileHandler handler) throws IOException
-   {
-      VirtualFileHandler parent = handler.getParent();
-      if (parent == null)
-      {
-         VirtualFileHandler peer = handler.getVFSContext().getRootPeer();
-         if (peer != null)
-            parent = peer.getParent();
-      }
-      return parent;
-   }
-
-   /**
-    * Is nested.
-    *
-    * @param handler the handler
-    * @return true if nested
-    * @throws IOException for any error
-    */
-   static boolean isNested(VirtualFileHandler handler) throws IOException
-   {
-      VirtualFileHandler parent = getParent(handler);
-      while (parent != null)
-      {
-         if(isArchive(parent))
-            return true;
-
-         parent = getParent(parent);
-      }
-      return false;
-   }
-
-   /**
-    * Contents of the file represented by a given handler
-    *
-    * @param handler a handler
-    * @return InputStream with entry's content
-    * @throws IOException for any error
-    */
-   public InputStream openStream(ZipEntryHandler handler) throws IOException
-   {
-      if (handler == null)
-         throw new IllegalArgumentException("Null handler");
-
-      checkIfModified();
-
-      String localPathName = handler.getLocalPathName();
-      EntryInfo ei = entries.get(localPathName);
-
-      if (ei == null)
-      {
-         String uriStr;
-         try
-         {
-            uriStr = handler.toURI().toString();
-         }
-         catch(Exception ex)
-         {
-            throw new RuntimeException("ASSERTION ERROR - uri generation failed for ZipEntryHandler: " + handler, ex);
-         }
-         throw new FileNotFoundException(uriStr);
-      }
-
-      if(ei.entry == null)
-      {
-         if ("".equals(localPathName))  // root
-            return zipSource.getRootAsStream();
-         else                           // directory
-            return new ByteArrayInputStream(new byte[0]);
-      }
-      
-      return zipSource.openStream(ei.entry);
-   }
-
-   /**
-    * Add a child to a given parent
-    *
-    * @param parent a parent
-    * @param child a child
-    */
-   public void addChild(AbstractVirtualFileHandler parent, AbstractVirtualFileHandler child)
-   {
-      if (parent == null)
-         throw new IllegalArgumentException("Null parent");
-
-      if (child == null)
-         throw new IllegalArgumentException("Null child");
-
-      EntryInfo parentEntry = entries.get(parent.getLocalPathName());
-      if (parentEntry != null)
-         parentEntry.add(child);
-      else
-         throw new RuntimeException("Parent does not exist: " + parent);
-   }
-
-   /**
-    * Properly release held resources
-    */
-   protected void finalize()
-   {
-      try
-      {
-         super.finalize();
-         if (zipSource != null)
-            zipSource.close();
-      }
-      catch (Throwable ignored)
-      {
-         log.debug("IGNORING: Failed to close zip source: " + zipSource, ignored);
-      }
-   }
-
-   /**
-    * Replace a current child of the given parent with another one
-    *
-    * @param parent a parent
-    * @param original current child
-    * @param replacement new child
-    */
-   public void replaceChild(ZipEntryHandler parent, AbstractVirtualFileHandler original, VirtualFileHandler replacement)
-   {
-      EntryInfo parentEntry = entries.get(parent.getLocalPathName());
-      if (parentEntry != null)
-      {
-         DelegatingHandler newOne;
-
-         if (replacement instanceof DelegatingHandler)
-         {
-            newOne = (DelegatingHandler) replacement;
-         }
-         else
-         {
-            newOne = new DelegatingHandler(this, parent, original.getName(), replacement);
-         }
-
-         synchronized(this)
-         {
-            parentEntry.replaceChild(original, newOne);
-
-            EntryInfo ei = entries.get(original.getLocalPathName());
-            ei.handler = newOne;
-            ei.entry = null;
-            ei.clearChildren();
-         }
-      }
-      else
-      {
-         throw new RuntimeException("Parent does not exist: " + parent);
-      }
-   }
-
-   /**
-    *  Internal data structure holding meta information of a virtual file in this context
-    */
-   static class EntryInfo
-   {
-      /** a handler */
-      private AbstractVirtualFileHandler handler;
-
-      /** a <tt>ZipEntry</tt> */
-      private ZipEntry entry;
-
-      /** a list of children */
-      private List<AbstractVirtualFileHandler> children;
-
-      /**
-       * EntryInfo constructor
-       *
-       * @param handler a handler
-       * @param entry an entry
-       */
-      EntryInfo(AbstractVirtualFileHandler handler, ZipEntry entry)
-      {
-         this.handler = handler;
-         this.entry = entry;
-      }
-
-      /**
-       * Get children.
-       *
-       * @return returns a list of children for this handler (by copy)
-       */
-      public synchronized List<VirtualFileHandler> getChildren()
-      {
-         if (children == null)
-            return Collections.emptyList();
-
-         return new LinkedList<VirtualFileHandler>(children);
-      }
-
-      /**
-       * Replace a child.
-       *
-       * @param original existing child
-       * @param replacement new child
-       */
-      public synchronized void replaceChild(AbstractVirtualFileHandler original, AbstractVirtualFileHandler replacement)
-      {
-         if (children != null)
-         {
-            int i = 0;
-            Iterator<AbstractVirtualFileHandler> it = children.iterator();
-            while(it.hasNext())
-            {
-               AbstractVirtualFileHandler child = it.next();
-               if (child.getName().equals(original.getName()))
-               {
-                  children.set(i, replacement);
-                  break;
-               }
-               i++;
-            }
-         }
-      }
-
-      /**
-       * Clear the list of children
-       */
-      public synchronized void clearChildren()
-      {
-         if (children != null)
-            children.clear();
-      }
-
-      /**
-       * Add a child. If a child with the same name exists already, first remove it.
-       *
-       * @param child a child
-       */
-      public synchronized void add(AbstractVirtualFileHandler child)
-      {
-         if (children == null)
-         {
-            children = new LinkedList<AbstractVirtualFileHandler>();
-         }
-         else
-         {
-            // if a child exists with this name already, remove it
-            Iterator<AbstractVirtualFileHandler> it = children.iterator();
-            while (it.hasNext())
-            {
-               AbstractVirtualFileHandler handler = it.next();
-               if (handler.getName().equals(child.getName()))
-               {
-                  it.remove();
-                  break;
-               }
-            }
-         }
-
-         children.add(child);
-      }
-   }
-
-   //
-   //   Helper methods
-   //
-
-   /**
-    * Copy input stream to output stream and close them both
-    *
-    * @param is input stream
-    * @param os output stream
-    * @throws IOException for any error
-    */
-   static void copyStreamAndClose(InputStream is, OutputStream os) throws IOException
-   {
-      try
-      {
-         byte [] buff = new byte[65536];
-         int count = is.read(buff);
-         while(count != -1)
-         {
-            os.write(buff, 0, count);
-            count = is.read(buff);
-         }
-      }
-      finally
-      {
-         if(is != null)
-         {
-            try {
-               is.close();
-            }
-            catch(Exception ignored)
-            {
-            }
-         }
-         os.close();
-      }
-   }
-
-   /**
-    * Make sure url protocol is <em>vfszip</em>
-    *
-    * @param rootURL the root url
-    * @return fixed url
-    * @throws MalformedURLException for any error
-    */
-   private static URL fixUrl(URL rootURL) throws MalformedURLException
-   {
-      if ("vfszip".equals(rootURL.getProtocol()) == false)
-      {
-         String url = rootURL.toString();
-         int pos = url.indexOf(":/");
-         if (pos != -1)
-            url = url.substring(pos);
-
-         return new URL("vfszip" + url);
-      }
-      return rootURL;
-   }
-
-   /**
-    * Break to path + name
-    *
-    * @param pathName the path name
-    * @return path tokens
-    */
-   public static String [] splitParentChild(String pathName)
-   {
-      if(pathName.length() == 0)
-         return new String [] {null, pathName};
-
-      int toPos = pathName.length();
-      if(pathName.charAt(pathName.length()-1) == '/')
-         toPos --;
-
-      int delimPos = pathName.lastIndexOf('/', toPos-1);
-
-      String [] ret;
-      if(delimPos == -1)
-      {
-         ret = new String []
-         {
-            "",
-            pathName.substring(delimPos+1, toPos)
-         };
-      }
-      else
-      {
-         ret = new String []
-         {
-            pathName.substring(0, delimPos),
-            pathName.substring(delimPos+1, toPos)
-         };
-      }
-      return ret;
-   }
-
-   /**
-    * Temporary files naming scheme
-    *
-    * @param name the name
-    * @return random name
-    */
-   private static String getTempFileName(String name)
-   {
-      int delim = name.lastIndexOf("/");
-      if (delim != -1)
-         name = name.substring(delim+1);
-      return UUID.randomUUID().toString().substring(0, 8) + "_" + name;
-   }
-
-   /**
-    * Use VFS's temp directory and make 'vfs-nested.tmp' sub-directory inside it for our purposes
-    *
-    * @return temp dir
-    */
-   private static String getTempDir()
-   {
-      File dir = new File(AbstractCopyMechanism.getTempDirectory(), "vfs-nested.tmp");
-      return dir.toString();
-   }
-
-   /**
-    * Delete the contents of a temporary directory. Delete first-level files only, don't drill down.
-    */
-   private static void deleteTmpDirContents()
-   {
-      try
-      {
-         File tmpDir = new File(getTempDir());
-         File [] files = tmpDir.listFiles();
-         if (files != null && files.length > 0)
-         {            
-            for (File file : files)
-            {
-               if (file.isDirectory() == false && file.isHidden() == false)
-                  file.delete();
-            }
-         }
-      }
-      catch(Exception ignored)
-      {
-      }
-   }
-
-   /**
-    * <tt>PriviligedAction</tt> class for checking a system property
-    */
-   private static class CheckForceCopy implements PrivilegedAction<Boolean>
-   {
-      public Boolean run()
-      {
-         String forceString = System.getProperty(VFSUtils.FORCE_COPY_KEY, "false");
-         return Boolean.valueOf(forceString);
-      }
-   }
-}

Copied: projects/vfs/tags/2.0.0.Beta17/src/main/java/org/jboss/virtual/plugins/context/zip/ZipEntryContext.java (from rev 74618, projects/vfs/trunk/src/main/java/org/jboss/virtual/plugins/context/zip/ZipEntryContext.java)
===================================================================
--- projects/vfs/tags/2.0.0.Beta17/src/main/java/org/jboss/virtual/plugins/context/zip/ZipEntryContext.java	                        (rev 0)
+++ projects/vfs/tags/2.0.0.Beta17/src/main/java/org/jboss/virtual/plugins/context/zip/ZipEntryContext.java	2008-06-16 14:28:54 UTC (rev 74620)
@@ -0,0 +1,1191 @@
+/*
+* 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.plugins.context.zip;
+
+import java.io.BufferedOutputStream;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.MalformedURLException;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+import java.util.UUID;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
+
+import org.jboss.logging.Logger;
+import org.jboss.virtual.VFSUtils;
+import org.jboss.virtual.plugins.context.AbstractVFSContext;
+import org.jboss.virtual.plugins.context.AbstractVirtualFileHandler;
+import org.jboss.virtual.plugins.context.DelegatingHandler;
+import org.jboss.virtual.plugins.context.jar.JarUtils;
+import org.jboss.virtual.plugins.copy.AbstractCopyMechanism;
+import org.jboss.virtual.spi.VirtualFileHandler;
+
+/**
+ * <tt>ZipEntryContext</tt> implements a {@link org.jboss.virtual.spi.VFSContext}
+ * that exposes a zip archive as a virtual file system.
+ *
+ * Zip archive can be in a form of a file or a stream.
+ *
+ * Nested archives are processed through this same class.
+ * By default nested archives are cached in memory and mounted as new
+ * instances of <tt>ZipEntryContext</tt> with <tt>ZipStreamWrapper</tt> as a source.
+ * If system property <em>jboss.vfs.forceCopy=true</em> is specified,
+ * or URL query parameter <em>forceCopy=true</em> is present,
+ * nested archives are extracted into a temp directory before being
+ * mounted as new instances of <tt>ZipEntryContext</tt>.
+ *
+ * In-memory nested archives may consume a lot of memory. To reduce memory footprint
+ * at the expense of performance, system property <em>jboss.vfs.optimizeForMemory=true<em>
+ * can be set.
+ *
+ * This context implementation has two modes of releasing file locks.
+ * <em>Asynchronous</em> mode is the default one since it is better performant.
+ * To switch this to <em>synchronous</em> mode a system property
+ * <em>jboss.vfs.forceNoReaper=true</em> can be specified or URL query parameter
+ * <em>noReaper=true</em> can be included in context URL.
+ *
+ * This context implementation is a replacement for
+ * {@link org.jboss.virtual.plugins.context.jar.JarContext}.
+ *
+ * @author <a href="strukelj at parsek.net">Marko Strukelj</a>
+ * @version $Revision: 1.0 $
+ */
+public class ZipEntryContext extends AbstractVFSContext
+{
+   /** Logger */
+   private static final Logger log = Logger.getLogger(ZipEntryContext.class);
+
+   /** Global setting for nested archive processing mode: copy or no-copy (default) */
+   private static boolean forceCopy;
+
+   static
+   {
+      deleteTmpDirContents();
+
+      forceCopy = AccessController.doPrivileged(new CheckForceCopy());
+
+      if (forceCopy)
+         log.info("VFS force nested jars copy-mode is enabled.");
+   }
+
+   /** Abstracted access to zip archive - either ZipFileWrapper or ZipStreamWrapper */
+   private ZipWrapper zipSource;
+
+   /** Entry path representing a context root - archive root is not necessarily a context root */
+   private String rootEntryPath = "";
+
+   /** AutoClean signals if zip archive should be deleted after closing the context - true for nested archives */
+   private boolean autoClean = false;
+
+   /** Registry of everything that zipSource contains */
+   private Map<String, EntryInfo> entries = new ConcurrentHashMap<String, EntryInfo>();
+
+   /**
+    * Create a new ZipEntryContext
+    *
+    * @param rootURL - file or jar:file url
+    * @throws URISyntaxException for any URI error
+    * @throws java.io.IOException for any error
+    */
+   public ZipEntryContext(URL rootURL) throws URISyntaxException, IOException
+   {
+      this(rootURL, false);
+   }
+
+   /**
+    * Create a new ZipEntryContext
+    *
+    * @param rootURL - file or jar:file url
+    * @param autoClean - true if file represented by rootURL should be deleted after this context is closed
+    * @throws URISyntaxException for any URI error
+    * @throws java.io.IOException for any error
+    */
+   public ZipEntryContext(URL rootURL, boolean autoClean) throws URISyntaxException, IOException
+   {
+      super(VFSUtils.toURI(fixUrl(rootURL)));
+      this.autoClean = autoClean;
+      init(rootURL, null, null);
+   }
+
+   /**
+    * Create a new ZipEntryContext to be mounted into another context
+    *
+    * @param rootURL - url representing this context within another context
+    * @param peer - file handler in another context through which this context is being mounted
+    * @param localRootUrl - file or jar:file url
+    * @throws URISyntaxException for any URI error
+    * @throws java.io.IOException for any error
+    */
+   public ZipEntryContext(URL rootURL, VirtualFileHandler peer, URL localRootUrl) throws URISyntaxException, IOException
+   {
+      this(rootURL, peer, localRootUrl, false);
+   }
+
+   /**
+    * Create a new ZipEntryContext to be mounted into another context
+    *
+    * @param rootURL - url representing this context within another context
+    * @param peer - file handler in another context through which this context is being mounted
+    * @param localRootUrl - file or jar:file url
+    * @param autoClean - true if file represented by localRootURL should be deleted after this context is closed
+    * @throws URISyntaxException for any URI error
+    * @throws java.io.IOException for any error
+    */
+   public ZipEntryContext(URL rootURL, VirtualFileHandler peer, URL localRootUrl, boolean autoClean) throws URISyntaxException, IOException
+   {
+      super(VFSUtils.toURI(fixUrl(rootURL)));
+      this.autoClean = autoClean;
+      init(localRootUrl, peer, null);
+   }
+
+   /**
+    * Create a new ZipEntryContext to be mounted into another context
+    *
+    * @param rootURL - url representing this context within another context
+    * @param peer - file handler in another context through which this context is being mounted
+    * @param zipWrapper - abstracted zip archive source
+    * @param autoClean - true if file represented by localRootURL should be deleted after this context is closed
+    * @throws URISyntaxException for any URI error
+    * @throws java.io.IOException for any error
+    */
+   public ZipEntryContext(URL rootURL, VirtualFileHandler peer, ZipWrapper zipWrapper, boolean autoClean) throws URISyntaxException, IOException
+   {
+      super(VFSUtils.toURI(fixUrl(rootURL)));
+      this.autoClean = autoClean;
+      init(null, peer, zipWrapper);
+   }
+
+   /**
+    * Extra initialization in addition to what's inside constructors
+    *
+    * @param localRootURL the local url
+    * @param peer the peer
+    * @param zipWrapper zip wrapper
+    * @throws URISyntaxException for any URI error
+    * @throws java.io.IOException for any error
+    */
+   private void init(URL localRootURL, VirtualFileHandler peer, ZipWrapper zipWrapper) throws IOException, URISyntaxException
+   {
+      if (zipWrapper == null)
+      {
+         if (localRootURL == null)
+            throw new IllegalArgumentException("No ZipWrapper specified and localRootURL is null");
+
+         // initialize rootEntryPath and get archive file path
+         String rootPath = initRootAndPath(localRootURL);
+         zipSource = createZipSource(rootPath);
+      }
+      else
+      {
+         zipSource = zipWrapper;
+      }
+      
+      setRootPeer(peer);
+
+      String name = getRootURI().toString();
+      int toPos = name.length();
+
+      // cut off any ending slash
+      if(name.length() != 0 && name.charAt(name.length()-1) == '/')
+         toPos --;
+
+      // name is last path component
+      int namePos = name.lastIndexOf("/", toPos-1);
+      name = name.substring(namePos+1, toPos);
+      
+      // cut off any ending exclamation
+      if(name.length() != 0 && name.charAt(name.length()-1) == '!')
+         name = name.substring(0, name.length()-1);
+
+      // init initial root EntryInfo that will be overwritten
+      // if zip entry exists for rootEntryPath
+      entries.put("", new EntryInfo(new ZipEntryHandler(this, null, name, true), null));
+
+      initEntries();
+   }
+
+   /**
+    * Create zip source.
+    *
+    * @param rootPath the root path
+    * @return zip entry wrapper
+    * @throws IOException for any error
+    */
+   protected ZipWrapper createZipSource(String rootPath) throws IOException
+   {
+      File file = null;
+      String relative = null;
+      File fp = new File(rootPath);
+      if (fp.exists())
+      {
+         file = fp;
+      }
+      else
+      {
+         File curr = fp;
+         relative = fp.getName();
+         while ((curr = curr.getParentFile()) != null)
+         {
+            if (curr.exists())
+            {
+               file = curr;
+               break;
+            }
+            else
+            {
+               relative = curr.getName() + "/" + relative;
+            }
+         }
+      }
+
+      if (file == null)
+         throw new IOException("VFS file does not exist: " + rootPath);
+
+      if (relative != null)
+      {
+         return findEntry(new FileInputStream(file), relative);
+      }
+      else
+      {
+         boolean noReaper = Boolean.valueOf(getOptions().get(VFSUtils.NO_REAPER_QUERY));
+         return new ZipFileWrapper(file, autoClean, noReaper);
+      }
+   }
+
+   /**
+    * Find exact entry.
+    * Use recursion on relative path.
+    *
+    * @param is the input stream
+    * @param relative relative path
+    * @return zip wrapper instance
+    * @throws IOException for any error
+    */
+   protected static ZipWrapper findEntry(InputStream is, String relative) throws IOException
+   {
+      ByteArrayOutputStream baos = new ByteArrayOutputStream();
+      ZipEntryContext.copyStreamAndClose(is, baos);
+      ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
+
+      // first we need to find best/longest name
+      ZipInputStream zis = new ZipInputStream(bais);
+      ZipEntry entry;
+      String longestNameMatch = null;
+      while((entry = zis.getNextEntry()) != null)
+      {
+         String entryName = entry.getName();
+         if (relative.startsWith(entryName))
+         {
+            if (entryName.equals(relative))
+            {
+               InputStream stream = new SizeLimitedInputStream(zis, entry.getSize());
+               // directories and non archives
+               if (entry.isDirectory() || JarUtils.isArchive(entryName) == false)
+               {
+                  return new ZipEntryWrapper(stream, entryName, System.currentTimeMillis());
+               }
+               else
+                  return new ZipStreamWrapper(stream, entryName, System.currentTimeMillis());
+            }
+
+            if (longestNameMatch == null || longestNameMatch.length() < entryName.length())
+            {
+               longestNameMatch = entryName;
+            }
+         }
+      }
+      if (longestNameMatch == null)
+         throw new IllegalArgumentException("Cannot find entry: " + is + ", " + relative);
+
+      // do recursion on relative
+      bais.reset();
+      zis = new ZipInputStream(bais);
+      while((entry = zis.getNextEntry()) != null)
+      {
+         String entryName = entry.getName();
+         if (entryName.equals(longestNameMatch))
+         {
+            relative = relative.substring(longestNameMatch.length() + 1);
+            return findEntry(new SizeLimitedInputStream(zis, entry.getSize()), relative);
+         }
+      }
+      throw new IllegalArgumentException("No such entry: " + is + ", " + relative);
+   }
+
+   /**
+    * Returns archive file name - if this is a top-level ZipEntryContext.
+    * Otherwise it returns the last component of URL.
+    *
+    * @return name
+    */
+   public String getName()
+   {
+      VirtualFileHandler peer = getRootPeer();
+      if (peer != null)
+         return peer.getName();
+      else
+         return zipSource.getName();
+   }
+
+   /**
+    * Iterate through zip archive entries, compose a tree structure of archive's content
+    *
+    * @throws URISyntaxException for any URI error
+    * @throws java.io.IOException for any error
+    */
+   private synchronized void initEntries() throws IOException, URISyntaxException
+   {
+      // we're using a two phase approach - we first select the relevant ones
+      // then we order these by name and only then we process them
+      // this way we ensure that parent entries are processed before child entries
+
+      Map<String, ZipEntry> relevant = new HashMap<String, ZipEntry>();
+      zipSource.acquire();
+      try
+      {
+         Enumeration<? extends ZipEntry> zipEntries = zipSource.entries();
+         // zoom-in on entries under rootEntryPath - ignoring the rest
+         while(zipEntries.hasMoreElements())
+         {
+            ZipEntry ent = zipEntries.nextElement();
+            if(ent.getName().startsWith(rootEntryPath))
+            {
+               relevant.put(ent.getName(), ent);
+            }
+         }
+
+         Map<String, ZipEntry> orderedRelevant = new TreeMap<String, ZipEntry>(relevant);
+         for(Map.Entry<String, ZipEntry> entry : orderedRelevant.entrySet())
+         {
+            ZipEntry ent = entry.getValue();
+            String fullName = ent.getName().substring(rootEntryPath.length());
+
+            String [] split = splitParentChild(fullName);
+            String parentPath = split[0];
+            String name = split[1];
+
+            EntryInfo ei = entries.get(parentPath);
+            if(ei == null)
+               ei = makeDummyParent(parentPath);
+
+            AbstractVirtualFileHandler parent = ei != null ? ei.handler : null;
+
+            if(ent.isDirectory() == false && JarUtils.isArchive(ent.getName()))
+            {
+               boolean useCopyMode = forceCopy;
+               if (useCopyMode == false)
+               {
+                  String flag = getOptions().get(VFSUtils.USE_COPY_QUERY);
+                  useCopyMode = Boolean.valueOf(flag);
+               }
+
+               DelegatingHandler delegator;
+
+               if (useCopyMode)
+               {
+                  // extract it to temp dir
+                  File dest = new File(getTempDir() + "/" + getTempFileName(ent.getName()));
+                  dest.deleteOnExit();
+
+                  // ensure parent exists
+                  dest.getParentFile().mkdirs();
+
+                  InputStream is = zipSource.openStream(ent);
+                  OutputStream os = new BufferedOutputStream(new FileOutputStream(dest));
+                  copyStreamAndClose(is, os);
+
+                  // mount another instance of ZipEntryContext
+                  delegator = mountZipFile(parent, name, dest);
+               }
+               else
+               {
+                  // mount another instance of ZipEntryContext
+                  delegator = mountZipStream(parent, name, zipSource.openStream(ent));
+               }
+
+               entries.put(delegator.getLocalPathName(), new EntryInfo(delegator, ent));
+               addChild(parent, delegator);
+            }
+            else
+            {
+               ZipEntryHandler wrapper = new ZipEntryHandler(this, parent, name, ent.isDirectory() == false);
+               entries.put(wrapper.getLocalPathName(), new EntryInfo(wrapper, ent));
+            }
+         }
+      }
+      finally
+      {
+         zipSource.release();
+      }
+   }
+
+   /**
+    * Mount ZipEntryContext created around extracted nested archive
+    *
+    * @param parent the parent
+    * @param name the name
+    * @param file the file
+    * @return mounted delegate
+    * @throws IOException for any error
+    * @throws URISyntaxException for any URI syntax error
+    */
+   protected DelegatingHandler mountZipFile(VirtualFileHandler parent, String name, File file) throws IOException, URISyntaxException
+   {
+      DelegatingHandler delegator = new DelegatingHandler(this, parent, name);
+      URL fileUrl = file.toURL();
+      URL delegatorUrl = fileUrl;
+
+      if (parent != null)
+         delegatorUrl = getChildURL(parent, name);
+
+      ZipEntryContext ctx = new ZipEntryContext(delegatorUrl, delegator, fileUrl, true);
+      VirtualFileHandler handler = ctx.getRoot();
+      delegator.setDelegate(handler);
+
+      return delegator;
+   }
+
+   /**
+    * Mount ZipEntryContext created around ZipStreamWrapper
+    *
+    * @param parent the parent
+    * @param name the name
+    * @param zipStream the zip stream
+    * @return mounted delegate
+    * @throws IOException for any error
+    * @throws URISyntaxException for any URI syntax error
+    */
+   protected DelegatingHandler mountZipStream(VirtualFileHandler parent, String name, InputStream zipStream) throws IOException, URISyntaxException
+   {
+      DelegatingHandler delegator = new DelegatingHandler(this, parent, name);
+      ZipStreamWrapper wrapper = new ZipStreamWrapper(zipStream, name, parent.getLastModified());
+
+      URL delegatorUrl = null;
+
+      if (parent != null)
+         delegatorUrl = getChildURL(parent, name);
+
+      ZipEntryContext ctx = new ZipEntryContext(delegatorUrl, delegator, wrapper, false);
+      VirtualFileHandler handler = ctx.getRoot();
+      delegator.setDelegate(handler);
+
+      return delegator;
+   }
+
+   /**
+    * Zip archives sometimes don't contain directory entries - only leaf entries
+    *
+    * @param parentPath the parent path
+    * @return entry info
+    * @throws IOException for any error
+    */
+   private EntryInfo makeDummyParent(String parentPath) throws IOException
+   {
+      // get grand parent first
+      String [] split = splitParentChild(parentPath);
+      String grandPa = split[0];
+
+      EntryInfo eiParent = entries.get(grandPa);
+      if(eiParent == null)
+         eiParent = makeDummyParent(grandPa);
+
+      ZipEntryHandler handler = new ZipEntryHandler(this, eiParent.handler, split[1], false);
+      EntryInfo ei = new EntryInfo(handler, null);
+      entries.put(parentPath, ei);
+      return ei;
+   }
+
+   /**
+    * Initialize rootEntryPath and return archive file path
+    *
+    * @param localRootUrl local root url
+    * @return file path
+    */
+   private String initRootAndPath(URL localRootUrl)
+   {
+      String filePath = localRootUrl.toString();
+      String zipPath = filePath;
+
+      int pos = filePath.indexOf("!");
+      if(pos > 0)
+      {
+         zipPath = filePath.substring(0, pos);
+         rootEntryPath = filePath.substring(pos+2);
+         if(rootEntryPath.length() != 0)
+            rootEntryPath += "/";
+      }
+
+      // find where url protocol ends - i.e. jar:file:/ ...
+      pos= zipPath.indexOf(":/");
+      filePath = zipPath.substring(pos + 1);
+
+      // cut out url query part if present
+      int queryStart = filePath.indexOf("?");
+      if (queryStart != -1)
+         filePath = filePath.substring(0, queryStart);
+
+      return filePath;
+   }
+
+   /**
+    * If archive has been modified, clear <em>entries</em> and re-initialize
+    */
+   private synchronized void checkIfModified()
+   {
+      // TODO: if zipSource represents a nested archive we should maybe delegate lastModified to its parent
+      if (zipSource.hasBeenModified())
+      {
+         EntryInfo rootInfo = entries.get("");
+         entries = new ConcurrentHashMap<String, EntryInfo>();
+         entries.put("", rootInfo);
+
+         if (zipSource.exists())
+         {
+            try
+            {
+               initEntries();
+            }
+            catch(Exception ignored)
+            {
+               log.warn("IGNORING: Failed to reinitialize context: " + getRootURI(), ignored);
+            }
+         }
+      }
+   }
+
+   /**
+    * Returns this context's root
+    *
+    * @return root handler
+    * @throws IOException for any error
+    */
+   public VirtualFileHandler getRoot() throws IOException
+   {
+      return entries.get("").handler;
+   }
+
+   /**
+    * Find a child with a given name and a given parent
+    *
+    * @param parent parent handler
+    * @param name  name of the child
+    * @return child handler or null if not found
+    */
+   public VirtualFileHandler getChild(ZipEntryHandler parent, String name)
+   {
+      if (parent == null)
+         throw new IllegalArgumentException("Null parent");
+
+      checkIfModified();
+      String pathName = parent.getLocalPathName();
+      if("".equals(pathName))
+         pathName = name;
+      else
+         pathName = pathName + "/" + name;
+
+      EntryInfo ei = entries.get(pathName);
+      
+      if(ei != null)
+         return ei.handler;
+
+      return null;
+   }
+
+   /**
+    * Returns a list of children for a given parent
+    *
+    * @param parent parent handler
+    * @param ignoreErrors true if errors should be silently ignored
+    * @return list of handlers representing children of the given parent
+    * @throws IOException for any error
+    */
+   public List<VirtualFileHandler> getChildren(VirtualFileHandler parent, boolean ignoreErrors) throws IOException
+   {
+      if (parent == null)
+         throw new IllegalArgumentException("Null parent");
+
+      checkIfModified();
+      if(parent instanceof AbstractVirtualFileHandler)
+      {
+         AbstractVirtualFileHandler parentHandler  = (AbstractVirtualFileHandler) parent;
+         EntryInfo parentEntry = entries.get(parentHandler.getLocalPathName());
+         if (parentEntry != null)
+         {
+            if (parentEntry.handler instanceof DelegatingHandler)
+               return parentEntry.handler.getChildren(ignoreErrors);
+            
+            return parentEntry.getChildren();
+         }
+      }
+      return Collections.emptyList();
+   }
+
+   /**
+    * Returns lastModified timestamp for a given handler
+    *
+    * @param handler a handler
+    * @return lastModified timestamp
+    */
+   public long getLastModified(ZipEntryHandler handler)
+   {
+      if (handler == null)
+         throw new IllegalArgumentException("Null handler");
+
+      checkIfModified();
+      EntryInfo ei = entries.get(handler.getLocalPathName());
+      if(ei == null)
+         return 0;
+
+      if(ei.entry == null) {
+         return zipSource.getLastModified();
+      }
+
+      return ei.entry.getTime();
+   }
+
+   /**
+    * Returns the size for a given handler
+    *
+    * @param handler a handler
+    * @return size in bytes
+    */
+   public long getSize(ZipEntryHandler handler)
+   {
+      if (handler == null)
+         throw new IllegalArgumentException("Null handler");
+
+      checkIfModified();
+      String pathName = handler.getLocalPathName();
+      EntryInfo ei = entries.get(pathName);
+      if(ei == null)
+         return 0;
+
+      if(ei.entry == null)
+      {
+         if(pathName.length() == 0)
+            return zipSource.getSize();
+         else
+            return 0;
+      }
+
+      return ei.entry.getSize();
+   }
+
+   /**
+    * Returns true if entry exists for a given handler
+    *
+    * @param handler a handler
+    * @return true if entry exists
+    */
+   public boolean exists(ZipEntryHandler handler)
+   {
+      if (handler == null)
+         throw new IllegalArgumentException("Null handler");
+
+      checkIfModified();
+      String pathName = handler.getLocalPathName();
+      EntryInfo ei = entries.get(pathName);
+      if(ei == null)
+         return false;
+
+      if (ei.entry == null && pathName.length() == 0)
+         return zipSource.exists();
+
+      return true;
+   }
+
+   /**
+    * Returns true if handler represents a non-directory entry
+    *
+    * @param handler a handler
+    * @return true if not a directory
+    */
+   public boolean isLeaf(ZipEntryHandler handler)
+   {
+      if (handler == null)
+         throw new IllegalArgumentException("Null handler");
+
+      checkIfModified();
+      EntryInfo ei = entries.get(handler.getLocalPathName());
+      if(ei == null || ei.entry == null)
+         return false;
+
+      return !ei.entry.isDirectory();
+   }
+
+   /**
+    * Is archive.
+    *
+    * @param handler the handler
+    * @return true if archive
+    */
+   static boolean isArchive(VirtualFileHandler handler)
+   {
+      if (handler instanceof ZipEntryHandler && "".equals(handler.getLocalPathName()))
+      {
+         return true;
+      }
+
+      if (handler instanceof DelegatingHandler && ((DelegatingHandler) handler).getDelegate() instanceof ZipEntryHandler)
+      {
+         return true;
+      }
+
+      return false;
+   }
+
+   /**
+    * Get parent.
+    *
+    * @param handler the handler to check
+    * @return parent handler
+    * @throws IOException for any error
+    */
+   static VirtualFileHandler getParent(VirtualFileHandler handler) throws IOException
+   {
+      VirtualFileHandler parent = handler.getParent();
+      if (parent == null)
+      {
+         VirtualFileHandler peer = handler.getVFSContext().getRootPeer();
+         if (peer != null)
+            parent = peer.getParent();
+      }
+      return parent;
+   }
+
+   /**
+    * Is nested.
+    *
+    * @param handler the handler
+    * @return true if nested
+    * @throws IOException for any error
+    */
+   static boolean isNested(VirtualFileHandler handler) throws IOException
+   {
+      VirtualFileHandler parent = getParent(handler);
+      while (parent != null)
+      {
+         if(isArchive(parent))
+            return true;
+
+         parent = getParent(parent);
+      }
+      return false;
+   }
+
+   /**
+    * Contents of the file represented by a given handler
+    *
+    * @param handler a handler
+    * @return InputStream with entry's content
+    * @throws IOException for any error
+    */
+   public InputStream openStream(ZipEntryHandler handler) throws IOException
+   {
+      if (handler == null)
+         throw new IllegalArgumentException("Null handler");
+
+      checkIfModified();
+
+      String localPathName = handler.getLocalPathName();
+      EntryInfo ei = entries.get(localPathName);
+
+      if (ei == null)
+      {
+         String uriStr;
+         try
+         {
+            uriStr = handler.toURI().toString();
+         }
+         catch(Exception ex)
+         {
+            throw new RuntimeException("ASSERTION ERROR - uri generation failed for ZipEntryHandler: " + handler, ex);
+         }
+         throw new FileNotFoundException(uriStr);
+      }
+
+      if(ei.entry == null)
+      {
+         if ("".equals(localPathName))  // root
+            return zipSource.getRootAsStream();
+         else                           // directory
+            return new ByteArrayInputStream(new byte[0]);
+      }
+      
+      return zipSource.openStream(ei.entry);
+   }
+
+   /**
+    * Add a child to a given parent
+    *
+    * @param parent a parent
+    * @param child a child
+    */
+   public void addChild(AbstractVirtualFileHandler parent, AbstractVirtualFileHandler child)
+   {
+      if (parent == null)
+         throw new IllegalArgumentException("Null parent");
+
+      if (child == null)
+         throw new IllegalArgumentException("Null child");
+
+      EntryInfo parentEntry = entries.get(parent.getLocalPathName());
+      if (parentEntry != null)
+         parentEntry.add(child);
+      else
+         throw new RuntimeException("Parent does not exist: " + parent);
+   }
+
+   /**
+    * Properly release held resources
+    */
+   protected void finalize()
+   {
+      try
+      {
+         super.finalize();
+         if (zipSource != null)
+            zipSource.close();
+      }
+      catch (Throwable ignored)
+      {
+         log.debug("IGNORING: Failed to close zip source: " + zipSource, ignored);
+      }
+   }
+
+   /**
+    * Replace a current child of the given parent with another one
+    *
+    * @param parent a parent
+    * @param original current child
+    * @param replacement new child
+    */
+   public void replaceChild(ZipEntryHandler parent, AbstractVirtualFileHandler original, VirtualFileHandler replacement)
+   {
+      EntryInfo parentEntry = entries.get(parent.getLocalPathName());
+      if (parentEntry != null)
+      {
+         DelegatingHandler newOne;
+
+         if (replacement instanceof DelegatingHandler)
+         {
+            newOne = (DelegatingHandler) replacement;
+         }
+         else
+         {
+            newOne = new DelegatingHandler(this, parent, original.getName(), replacement);
+         }
+
+         synchronized(this)
+         {
+            parentEntry.replaceChild(original, newOne);
+
+            EntryInfo ei = entries.get(original.getLocalPathName());
+            ei.handler = newOne;
+            ei.entry = null;
+            ei.clearChildren();
+         }
+      }
+      else
+      {
+         throw new RuntimeException("Parent does not exist: " + parent);
+      }
+   }
+
+   /**
+    *  Internal data structure holding meta information of a virtual file in this context
+    */
+   static class EntryInfo
+   {
+      /** a handler */
+      private AbstractVirtualFileHandler handler;
+
+      /** a <tt>ZipEntry</tt> */
+      private ZipEntry entry;
+
+      /** a list of children */
+      private List<AbstractVirtualFileHandler> children;
+
+      /**
+       * EntryInfo constructor
+       *
+       * @param handler a handler
+       * @param entry an entry
+       */
+      EntryInfo(AbstractVirtualFileHandler handler, ZipEntry entry)
+      {
+         this.handler = handler;
+         this.entry = entry;
+      }
+
+      /**
+       * Get children.
+       *
+       * @return returns a list of children for this handler (by copy)
+       */
+      public synchronized List<VirtualFileHandler> getChildren()
+      {
+         if (children == null)
+            return Collections.emptyList();
+
+         return new LinkedList<VirtualFileHandler>(children);
+      }
+
+      /**
+       * Replace a child.
+       *
+       * @param original existing child
+       * @param replacement new child
+       */
+      public synchronized void replaceChild(AbstractVirtualFileHandler original, AbstractVirtualFileHandler replacement)
+      {
+         if (children != null)
+         {
+            int i = 0;
+            Iterator<AbstractVirtualFileHandler> it = children.iterator();
+            while(it.hasNext())
+            {
+               AbstractVirtualFileHandler child = it.next();
+               if (child.getName().equals(original.getName()))
+               {
+                  children.set(i, replacement);
+                  break;
+               }
+               i++;
+            }
+         }
+      }
+
+      /**
+       * Clear the list of children
+       */
+      public synchronized void clearChildren()
+      {
+         if (children != null)
+            children.clear();
+      }
+
+      /**
+       * Add a child. If a child with the same name exists already, first remove it.
+       *
+       * @param child a child
+       */
+      public synchronized void add(AbstractVirtualFileHandler child)
+      {
+         if (children == null)
+         {
+            children = new LinkedList<AbstractVirtualFileHandler>();
+         }
+         else
+         {
+            // if a child exists with this name already, remove it
+            Iterator<AbstractVirtualFileHandler> it = children.iterator();
+            while (it.hasNext())
+            {
+               AbstractVirtualFileHandler handler = it.next();
+               if (handler.getName().equals(child.getName()))
+               {
+                  it.remove();
+                  break;
+               }
+            }
+         }
+
+         children.add(child);
+      }
+   }
+
+   //
+   //   Helper methods
+   //
+
+   /**
+    * Copy input stream to output stream and close them both
+    *
+    * @param is input stream
+    * @param os output stream
+    * @throws IOException for any error
+    */
+   static void copyStreamAndClose(InputStream is, OutputStream os) throws IOException
+   {
+      try
+      {
+         byte [] buff = new byte[65536];
+         int count = is.read(buff);
+         while(count != -1)
+         {
+            os.write(buff, 0, count);
+            count = is.read(buff);
+         }
+      }
+      finally
+      {
+         if(is != null)
+         {
+            try {
+               is.close();
+            }
+            catch(Exception ignored)
+            {
+            }
+         }
+         os.close();
+      }
+   }
+
+   /**
+    * Make sure url protocol is <em>vfszip</em>
+    *
+    * @param rootURL the root url
+    * @return fixed url
+    * @throws MalformedURLException for any error
+    */
+   private static URL fixUrl(URL rootURL) throws MalformedURLException
+   {
+      if ("vfszip".equals(rootURL.getProtocol()) == false)
+      {
+         String url = rootURL.toString();
+         int pos = url.indexOf(":/");
+         if (pos != -1)
+            url = url.substring(pos);
+
+         return new URL("vfszip" + url);
+      }
+      return rootURL;
+   }
+
+   /**
+    * Break to path + name
+    *
+    * @param pathName the path name
+    * @return path tokens
+    */
+   public static String [] splitParentChild(String pathName)
+   {
+      if(pathName.length() == 0)
+         return new String [] {null, pathName};
+
+      int toPos = pathName.length();
+      if(pathName.charAt(pathName.length()-1) == '/')
+         toPos --;
+
+      int delimPos = pathName.lastIndexOf('/', toPos-1);
+
+      String [] ret;
+      if(delimPos == -1)
+      {
+         ret = new String []
+         {
+            "",
+            pathName.substring(delimPos+1, toPos)
+         };
+      }
+      else
+      {
+         ret = new String []
+         {
+            pathName.substring(0, delimPos),
+            pathName.substring(delimPos+1, toPos)
+         };
+      }
+      return ret;
+   }
+
+   /**
+    * Temporary files naming scheme
+    *
+    * @param name the name
+    * @return random name
+    */
+   private static String getTempFileName(String name)
+   {
+      int delim = name.lastIndexOf("/");
+      if (delim != -1)
+         name = name.substring(delim+1);
+      return UUID.randomUUID().toString().substring(0, 8) + "_" + name;
+   }
+
+   /**
+    * Use VFS's temp directory and make 'vfs-nested.tmp' sub-directory inside it for our purposes
+    *
+    * @return temp dir
+    */
+   private static String getTempDir()
+   {
+      File dir = new File(AbstractCopyMechanism.getTempDirectory(), "vfs-nested.tmp");
+      return dir.toString();
+   }
+
+   /**
+    * Delete the contents of a temporary directory. Delete first-level files only, don't drill down.
+    */
+   private static void deleteTmpDirContents()
+   {
+      try
+      {
+         File tmpDir = new File(getTempDir());
+         File [] files = tmpDir.listFiles();
+         if (files != null && files.length > 0)
+         {            
+            for (File file : files)
+            {
+               if (file.isDirectory() == false && file.isHidden() == false)
+                  file.delete();
+            }
+         }
+      }
+      catch(Exception ignored)
+      {
+      }
+   }
+
+   /**
+    * <tt>PriviligedAction</tt> class for checking a system property
+    */
+   private static class CheckForceCopy implements PrivilegedAction<Boolean>
+   {
+      public Boolean run()
+      {
+         String forceString = System.getProperty(VFSUtils.FORCE_COPY_KEY, "false");
+         return Boolean.valueOf(forceString);
+      }
+   }
+}

Deleted: projects/vfs/tags/2.0.0.Beta17/src/test/java/org/jboss/test/virtual/test/VFSAllTestSuite.java
===================================================================
--- projects/vfs/trunk/src/test/java/org/jboss/test/virtual/test/VFSAllTestSuite.java	2008-06-16 06:57:54 UTC (rev 74595)
+++ projects/vfs/tags/2.0.0.Beta17/src/test/java/org/jboss/test/virtual/test/VFSAllTestSuite.java	2008-06-16 14:28:54 UTC (rev 74620)
@@ -1,87 +0,0 @@
-/*
-* JBoss, Home of Professional Open Source
-* Copyright 2005, JBoss Inc., and individual contributors as indicated
-* by the @authors tag. See the copyright.txt in the distribution for a
-* full listing of individual contributors.
-*
-* This is free software; you can redistribute it and/or modify it
-* under the terms of the GNU Lesser General Public License as
-* published by the Free Software Foundation; either version 2.1 of
-* the License, or (at your option) any later version.
-*
-* This software is distributed in the hope that it will be useful,
-* but WITHOUT ANY WARRANTY; without even the implied warranty of
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-* Lesser General Public License for more details.
-*
-* You should have received a copy of the GNU Lesser General Public
-* License along with this software; if not, write to the Free
-* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
-* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
-*/
-package org.jboss.test.virtual.test;
-
-import junit.framework.Test;
-import junit.framework.TestSuite;
-import junit.textui.TestRunner;
-import org.jboss.virtual.VFS;
-
-/**
- * VFS All Test Suite.
- * 
- * @author <a href="adrian at jboss.com">Adrian Brock</a>
- * @author <a href="ales.justin at jboss.com">Ales Justin</a>
- * @version $Revision: 46146 $
- */
-public class VFSAllTestSuite extends TestSuite
-{
-   public static void main(String[] args)
-   {
-      TestRunner.run(suite());
-   }
-
-   public static Test suite()
-   {
-      VFS.init();
-      TestSuite suite = new TestSuite("VFS Tests default");
-
-      // vfs / spi
-      suite.addTest(VFSUnitTestCase.suite());
-      suite.addTest(VirtualFileUnitTestCase.suite());
-      // url
-      suite.addTest(URLResolutionUnitTestCase.suite());
-      suite.addTest(URLExistsUnitTestCase.suite());
-      suite.addTest(URLConnectionUnitTestCase.suite());
-      // files
-      suite.addTest(FileVFSUnitTestCase.suite());
-      suite.addTest(CopyFileVFSUnitTestCase.suite());
-      suite.addTest(FileVFSContextUnitTestCase.suite());
-      suite.addTest(FileVirtualFileHandlerUnitTestCase.suite());
-      // jars
-      suite.addTest(JARCacheUnitTestCase.suite());
-      suite.addTest(CopyJARCacheUnitTestCase.suite());
-      suite.addTest(JARVFSContextUnitTestCase.suite());
-      suite.addTest(JARVirtualFileHandlerUnitTestCase.suite());
-      suite.addTest(JARSerializationUnitTestCase.suite());
-      suite.addTest(CopyJARSerializationUnitTestCase.suite());
-      suite.addTest(JAREntryTestCase.suite());
-      suite.addTest(CopyJAREntryTestCase.suite());
-      suite.addTest(ZipEntryHandlerUnitTestCase.suite());
-      suite.addTest(ZipEntryVFSContextUnitTestCase.suite());
-      // contexts
-      suite.addTest(AssembledContextTestCase.suite());
-      suite.addTest(MemoryTestCase.suite());
-      suite.addTest(SundryVFSUnitTestCase.suite());
-      // options / policy / path
-      suite.addTest(PathQueryTestCase.suite());
-      suite.addTest(PathTokensTestCase.suite());
-      // unpack
-      suite.addTest(UnpackTestCase.suite());
-      suite.addTest(ExplodeTestCase.suite());
-      suite.addTest(TempTestCase.suite());
-      // visitor
-      suite.addTest(VisitorUnitTestCase.suite());
-
-      return suite;
-   }
-}

Copied: projects/vfs/tags/2.0.0.Beta17/src/test/java/org/jboss/test/virtual/test/VFSAllTestSuite.java (from rev 74599, projects/vfs/trunk/src/test/java/org/jboss/test/virtual/test/VFSAllTestSuite.java)
===================================================================
--- projects/vfs/tags/2.0.0.Beta17/src/test/java/org/jboss/test/virtual/test/VFSAllTestSuite.java	                        (rev 0)
+++ projects/vfs/tags/2.0.0.Beta17/src/test/java/org/jboss/test/virtual/test/VFSAllTestSuite.java	2008-06-16 14:28:54 UTC (rev 74620)
@@ -0,0 +1,89 @@
+/*
+* JBoss, Home of Professional Open Source
+* Copyright 2005, JBoss Inc., and individual contributors as indicated
+* by the @authors tag. See the copyright.txt in the distribution for a
+* full listing of individual contributors.
+*
+* This is free software; you can redistribute it and/or modify it
+* under the terms of the GNU Lesser General Public License as
+* published by the Free Software Foundation; either version 2.1 of
+* the License, or (at your option) any later version.
+*
+* This software is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public
+* License along with this software; if not, write to the Free
+* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+*/
+package org.jboss.test.virtual.test;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+import junit.textui.TestRunner;
+import org.jboss.virtual.VFS;
+
+/**
+ * VFS All Test Suite.
+ * 
+ * @author <a href="adrian at jboss.com">Adrian Brock</a>
+ * @author <a href="ales.justin at jboss.com">Ales Justin</a>
+ * @version $Revision: 46146 $
+ */
+public class VFSAllTestSuite extends TestSuite
+{
+   public static void main(String[] args)
+   {
+      TestRunner.run(suite());
+   }
+
+   public static Test suite()
+   {
+      VFS.init();
+      TestSuite suite = new TestSuite("VFS Tests default");
+
+      // vfs / spi
+      suite.addTest(VFSUnitTestCase.suite());
+      suite.addTest(VirtualFileUnitTestCase.suite());
+      // url
+      suite.addTest(URLResolutionUnitTestCase.suite());
+      suite.addTest(URLExistsUnitTestCase.suite());
+      suite.addTest(URLConnectionUnitTestCase.suite());
+      // files
+      suite.addTest(FileVFSUnitTestCase.suite());
+      suite.addTest(CopyFileVFSUnitTestCase.suite());
+      suite.addTest(FileVFSContextUnitTestCase.suite());
+      suite.addTest(FileVirtualFileHandlerUnitTestCase.suite());
+      // jars
+      suite.addTest(JARCacheUnitTestCase.suite());
+      suite.addTest(CopyJARCacheUnitTestCase.suite());
+      suite.addTest(JARVFSContextUnitTestCase.suite());
+      suite.addTest(JARVirtualFileHandlerUnitTestCase.suite());
+      suite.addTest(JARSerializationUnitTestCase.suite());
+      suite.addTest(CopyJARSerializationUnitTestCase.suite());
+      suite.addTest(JAREntryTestCase.suite());
+      suite.addTest(CopyJAREntryTestCase.suite());
+      suite.addTest(ZipEntryHandlerUnitTestCase.suite());
+      suite.addTest(ZipEntryVFSContextUnitTestCase.suite());
+      // contexts
+      suite.addTest(AssembledContextTestCase.suite());
+      suite.addTest(MemoryTestCase.suite());
+      suite.addTest(SundryVFSUnitTestCase.suite());
+      // options / policy / path
+      suite.addTest(PathQueryTestCase.suite());
+      suite.addTest(PathTokensTestCase.suite());
+      // unpack
+      suite.addTest(UnpackTestCase.suite());
+      suite.addTest(ExplodeTestCase.suite());
+      suite.addTest(TempTestCase.suite());
+      // visitor
+      suite.addTest(VisitorUnitTestCase.suite());
+      // utils
+      suite.addTest(VFSUtilTestCase.suite());
+
+      return suite;
+   }
+}

Copied: projects/vfs/tags/2.0.0.Beta17/src/test/java/org/jboss/test/virtual/test/VFSUtilTestCase.java (from rev 74599, projects/vfs/trunk/src/test/java/org/jboss/test/virtual/test/VFSUtilTestCase.java)
===================================================================
--- projects/vfs/tags/2.0.0.Beta17/src/test/java/org/jboss/test/virtual/test/VFSUtilTestCase.java	                        (rev 0)
+++ projects/vfs/tags/2.0.0.Beta17/src/test/java/org/jboss/test/virtual/test/VFSUtilTestCase.java	2008-06-16 14:28:54 UTC (rev 74620)
@@ -0,0 +1,61 @@
+/*
+* 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.test.virtual.test;
+
+import java.net.URL;
+import java.util.List;
+import java.util.ArrayList;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+import org.jboss.virtual.VFS;
+import org.jboss.virtual.VirtualFile;
+import org.jboss.virtual.VFSUtils;
+
+/**
+ * VFSUtilTestCase.
+ *
+ * @author <a href="ales.justin at jboss.com">Ales Justin</a>
+ */
+public class VFSUtilTestCase extends AbstractMockVFSTest
+{
+   public VFSUtilTestCase(String name)
+   {
+      super(name);
+   }
+
+   public static Test suite()
+   {
+      return new TestSuite(VFSUtilTestCase.class);
+   }
+
+   public void testAddManifestLocations() throws Throwable
+   {
+      URL url = getResource("/vfs/test");
+      VirtualFile root = VFS.getRoot(url);
+      VirtualFile file = root.getChild("badmf.jar");
+      assertNotNull(file);
+      List<VirtualFile> paths = new ArrayList<VirtualFile>();
+      VFSUtils.addManifestLocations(file, paths);
+      assertEquals(3, paths.size());
+   }
+}
\ No newline at end of file

Copied: projects/vfs/tags/2.0.0.Beta17/src/test/resources/vfs/test/badmf.jar (from rev 74599, projects/vfs/trunk/src/test/resources/vfs/test/badmf.jar)
===================================================================
(Binary files differ)




More information about the jboss-cvs-commits mailing list