[jboss-svn-commits] JBoss Common SVN: r3836 - in shrinkwrap/trunk: api/src/main/java/org/jboss/shrinkwrap/api/spec and 15 other directories.

jboss-svn-commits at lists.jboss.org jboss-svn-commits at lists.jboss.org
Sun Dec 6 23:07:12 EST 2009


Author: ALRubinger
Date: 2009-12-06 23:07:12 -0500 (Sun, 06 Dec 2009)
New Revision: 3836

Added:
   shrinkwrap/trunk/api/src/main/java/org/jboss/shrinkwrap/api/container/DirectoryContainer.java
   shrinkwrap/trunk/impl-base/src/main/java/org/jboss/shrinkwrap/impl/base/asset/DirectoryAsset.java
   shrinkwrap/trunk/impl-base/src/test/java/org/jboss/shrinkwrap/impl/base/asset/DirectoryAssetTestCase.java
   shrinkwrap/trunk/impl-base/src/test/resources/exploded_import_test/empty_dir/
   shrinkwrap/trunk/impl-base/src/test/resources/exploded_import_test/parent/
   shrinkwrap/trunk/impl-base/src/test/resources/exploded_import_test/parent/empty_dir/
Modified:
   shrinkwrap/trunk/api/src/main/java/org/jboss/shrinkwrap/api/spec/EnterpriseArchive.java
   shrinkwrap/trunk/api/src/main/java/org/jboss/shrinkwrap/api/spec/JavaArchive.java
   shrinkwrap/trunk/api/src/main/java/org/jboss/shrinkwrap/api/spec/ResourceAdapterArchive.java
   shrinkwrap/trunk/api/src/main/java/org/jboss/shrinkwrap/api/spec/WebArchive.java
   shrinkwrap/trunk/impl-base/pom.xml
   shrinkwrap/trunk/impl-base/src/main/java/org/jboss/shrinkwrap/impl/base/container/ContainerBase.java
   shrinkwrap/trunk/impl-base/src/main/java/org/jboss/shrinkwrap/impl/base/exporter/AbstractExporterDelegate.java
   shrinkwrap/trunk/impl-base/src/main/java/org/jboss/shrinkwrap/impl/base/exporter/ExplodedExporterDelegate.java
   shrinkwrap/trunk/impl-base/src/main/java/org/jboss/shrinkwrap/impl/base/exporter/ZipExportDelegate.java
   shrinkwrap/trunk/impl-base/src/main/java/org/jboss/shrinkwrap/impl/base/importer/ExplodedImporterImpl.java
   shrinkwrap/trunk/impl-base/src/main/java/org/jboss/shrinkwrap/impl/base/importer/ZipImporterImpl.java
   shrinkwrap/trunk/impl-base/src/main/java/org/jboss/shrinkwrap/impl/base/path/BasicPath.java
   shrinkwrap/trunk/impl-base/src/main/java/org/jboss/shrinkwrap/impl/base/path/PathUtil.java
   shrinkwrap/trunk/impl-base/src/test/java/org/jboss/shrinkwrap/impl/base/exporter/ExportTestBase.java
   shrinkwrap/trunk/impl-base/src/test/java/org/jboss/shrinkwrap/impl/base/exporter/ZipExporterTestCase.java
   shrinkwrap/trunk/impl-base/src/test/java/org/jboss/shrinkwrap/impl/base/importer/ExplodedImporterTestCase.java
   shrinkwrap/trunk/impl-base/src/test/java/org/jboss/shrinkwrap/impl/base/importer/ZipImporterImplTestCase.java
   shrinkwrap/trunk/impl-base/src/test/java/org/jboss/shrinkwrap/impl/base/path/PathUtilTestCase.java
   shrinkwrap/trunk/impl-base/src/test/java/org/jboss/shrinkwrap/impl/base/path/PathsTestBase.java
   shrinkwrap/trunk/impl-base/src/test/java/org/jboss/shrinkwrap/impl/base/spec/EnterpriseArchiveImplTestCase.java
   shrinkwrap/trunk/impl-base/src/test/java/org/jboss/shrinkwrap/impl/base/spec/JavaArchiveImplTestCase.java
   shrinkwrap/trunk/impl-base/src/test/java/org/jboss/shrinkwrap/impl/base/spec/ResourceAdapterArchiveImplTestCase.java
   shrinkwrap/trunk/impl-base/src/test/java/org/jboss/shrinkwrap/impl/base/spec/WebArchiveImplTestCase.java
   shrinkwrap/trunk/impl-base/src/test/java/org/jboss/shrinkwrap/impl/base/test/DynamicContainerTestBase.java
   shrinkwrap/trunk/impl-base/src/test/resources/org/jboss/shrinkwrap/impl/base/importer/test.zip
Log:
[SHRINKWRAP-104] Support empty directories

Added: shrinkwrap/trunk/api/src/main/java/org/jboss/shrinkwrap/api/container/DirectoryContainer.java
===================================================================
--- shrinkwrap/trunk/api/src/main/java/org/jboss/shrinkwrap/api/container/DirectoryContainer.java	                        (rev 0)
+++ shrinkwrap/trunk/api/src/main/java/org/jboss/shrinkwrap/api/container/DirectoryContainer.java	2009-12-07 04:07:12 UTC (rev 3836)
@@ -0,0 +1,71 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2009, Red Hat Middleware LLC, and individual contributors
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jboss.shrinkwrap.api.container;
+
+import org.jboss.shrinkwrap.api.Archive;
+import org.jboss.shrinkwrap.api.Path;
+
+/**
+ * Defines the contract for a component capable of storing 
+ * empty directories.
+ *
+ * @author <a href="mailto:aslak at conduct.no">Aslak Knutsen</a>
+ * @version $Revision: $
+ */
+public interface DirectoryContainer<T extends Archive<T>>
+{
+   //-------------------------------------------------------------------------------------||
+   // Contracts --------------------------------------------------------------------------||
+   //-------------------------------------------------------------------------------------||
+
+   /**
+    * Adds the specified directory to the {@link Archive}.
+    * 
+    * @param path The path to add
+    * @return This archive
+    * @throws IllegalArgumentException If no path was specified
+    */
+   T addDirectory(String path) throws IllegalArgumentException;
+
+   /**
+    * Adds the specified directory to the {@link Archive}.
+    * 
+    * @param paths The paths to add
+    * @return This archive
+    * @throws IllegalArgumentException If no paths were specified
+    */
+   T addDirectories(String... paths) throws IllegalArgumentException;
+
+   /**
+    * Adds the specified directory to the {@link Archive}.
+    * 
+    * @param path The path to add
+    * @return This archive
+    * @throws IllegalArgumentException If no path was specified
+    */
+   T addDirectory(Path path) throws IllegalArgumentException;
+
+   /**
+    * Adds the specified directory to the {@link Archive}.
+    * 
+    * @param paths The paths to add
+    * @return This archive
+    * @throws IllegalArgumentException If no paths were specified
+    */
+   T addDirectories(Path... paths) throws IllegalArgumentException;
+
+}

Modified: shrinkwrap/trunk/api/src/main/java/org/jboss/shrinkwrap/api/spec/EnterpriseArchive.java
===================================================================
--- shrinkwrap/trunk/api/src/main/java/org/jboss/shrinkwrap/api/spec/EnterpriseArchive.java	2009-12-06 16:40:25 UTC (rev 3835)
+++ shrinkwrap/trunk/api/src/main/java/org/jboss/shrinkwrap/api/spec/EnterpriseArchive.java	2009-12-07 04:07:12 UTC (rev 3836)
@@ -17,6 +17,7 @@
 package org.jboss.shrinkwrap.api.spec;
 
 import org.jboss.shrinkwrap.api.Archive;
+import org.jboss.shrinkwrap.api.container.DirectoryContainer;
 import org.jboss.shrinkwrap.api.container.EnterpriseContainer;
 import org.jboss.shrinkwrap.api.container.LibraryContainer;
 import org.jboss.shrinkwrap.api.container.ManifestContainer;
@@ -32,12 +33,14 @@
  * @author <a href="mailto:aslak at conduct.no">Aslak Knutsen</a>
  * @version $Revision: $
  */
-public interface EnterpriseArchive extends 
-      Archive<EnterpriseArchive>, 
-      ResourceContainer<EnterpriseArchive>, 
-      ManifestContainer<EnterpriseArchive>, 
-      LibraryContainer<EnterpriseArchive>,
-      EnterpriseContainer<EnterpriseArchive>
+public interface EnterpriseArchive
+      extends
+         Archive<EnterpriseArchive>,
+         ResourceContainer<EnterpriseArchive>,
+         ManifestContainer<EnterpriseArchive>,
+         LibraryContainer<EnterpriseArchive>,
+         EnterpriseContainer<EnterpriseArchive>,
+         DirectoryContainer<EnterpriseArchive>
 {
 
 }

Modified: shrinkwrap/trunk/api/src/main/java/org/jboss/shrinkwrap/api/spec/JavaArchive.java
===================================================================
--- shrinkwrap/trunk/api/src/main/java/org/jboss/shrinkwrap/api/spec/JavaArchive.java	2009-12-06 16:40:25 UTC (rev 3835)
+++ shrinkwrap/trunk/api/src/main/java/org/jboss/shrinkwrap/api/spec/JavaArchive.java	2009-12-07 04:07:12 UTC (rev 3836)
@@ -18,6 +18,7 @@
 
 import org.jboss.shrinkwrap.api.Archive;
 import org.jboss.shrinkwrap.api.container.ClassContainer;
+import org.jboss.shrinkwrap.api.container.DirectoryContainer;
 import org.jboss.shrinkwrap.api.container.ManifestContainer;
 import org.jboss.shrinkwrap.api.container.ResourceContainer;
 
@@ -32,10 +33,12 @@
  * @author <a href="mailto:aslak at conduct.no">Aslak Knutsen</a>
  * @version $Revision: $
  */
-public interface JavaArchive extends 
-      Archive<JavaArchive>, 
-      ResourceContainer<JavaArchive>, 
-      ManifestContainer<JavaArchive>, 
-      ClassContainer<JavaArchive>
+public interface JavaArchive
+      extends
+         Archive<JavaArchive>,
+         ResourceContainer<JavaArchive>,
+         ManifestContainer<JavaArchive>,
+         ClassContainer<JavaArchive>,
+         DirectoryContainer<JavaArchive>
 {
 }

Modified: shrinkwrap/trunk/api/src/main/java/org/jboss/shrinkwrap/api/spec/ResourceAdapterArchive.java
===================================================================
--- shrinkwrap/trunk/api/src/main/java/org/jboss/shrinkwrap/api/spec/ResourceAdapterArchive.java	2009-12-06 16:40:25 UTC (rev 3835)
+++ shrinkwrap/trunk/api/src/main/java/org/jboss/shrinkwrap/api/spec/ResourceAdapterArchive.java	2009-12-07 04:07:12 UTC (rev 3836)
@@ -17,6 +17,7 @@
 package org.jboss.shrinkwrap.api.spec;
 
 import org.jboss.shrinkwrap.api.Archive;
+import org.jboss.shrinkwrap.api.container.DirectoryContainer;
 import org.jboss.shrinkwrap.api.container.LibraryContainer;
 import org.jboss.shrinkwrap.api.container.ManifestContainer;
 import org.jboss.shrinkwrap.api.container.ResourceAdapterContainer;
@@ -37,6 +38,7 @@
          ManifestContainer<ResourceAdapterArchive>,
          LibraryContainer<ResourceAdapterArchive>,
          ResourceContainer<ResourceAdapterArchive>,
-         ResourceAdapterContainer<ResourceAdapterArchive>
+         ResourceAdapterContainer<ResourceAdapterArchive>,
+         DirectoryContainer<ResourceAdapterArchive>
 {
 }

Modified: shrinkwrap/trunk/api/src/main/java/org/jboss/shrinkwrap/api/spec/WebArchive.java
===================================================================
--- shrinkwrap/trunk/api/src/main/java/org/jboss/shrinkwrap/api/spec/WebArchive.java	2009-12-06 16:40:25 UTC (rev 3835)
+++ shrinkwrap/trunk/api/src/main/java/org/jboss/shrinkwrap/api/spec/WebArchive.java	2009-12-07 04:07:12 UTC (rev 3836)
@@ -16,9 +16,9 @@
  */
 package org.jboss.shrinkwrap.api.spec;
 
-
 import org.jboss.shrinkwrap.api.Archive;
 import org.jboss.shrinkwrap.api.container.ClassContainer;
+import org.jboss.shrinkwrap.api.container.DirectoryContainer;
 import org.jboss.shrinkwrap.api.container.LibraryContainer;
 import org.jboss.shrinkwrap.api.container.ManifestContainer;
 import org.jboss.shrinkwrap.api.container.ResourceContainer;
@@ -34,12 +34,14 @@
  * @author <a href="mailto:aslak at conduct.no">Aslak Knutsen</a>
  * @version $Revision: $
  */
-public interface WebArchive extends 
-      Archive<WebArchive>, 
-      ManifestContainer<WebArchive>,
-      ClassContainer<WebArchive>,
-      LibraryContainer<WebArchive>,
-      ResourceContainer<WebArchive>,
-      WebContainer<WebArchive>
+public interface WebArchive
+      extends
+         Archive<WebArchive>,
+         ManifestContainer<WebArchive>,
+         ClassContainer<WebArchive>,
+         LibraryContainer<WebArchive>,
+         ResourceContainer<WebArchive>,
+         WebContainer<WebArchive>,
+         DirectoryContainer<WebArchive>
 {
 }

Modified: shrinkwrap/trunk/impl-base/pom.xml
===================================================================
--- shrinkwrap/trunk/impl-base/pom.xml	2009-12-06 16:40:25 UTC (rev 3835)
+++ shrinkwrap/trunk/impl-base/pom.xml	2009-12-07 04:07:12 UTC (rev 3836)
@@ -54,6 +54,7 @@
 
   </dependencies>
 
+  <!-- Build Configuration -->
   <build>
     <plugins>
       <plugin>
@@ -67,6 +68,17 @@
           </execution>
         </executions>
       </plugin>
+    
+      <!-- Resources Plugin -->
+      <plugin>
+        <artifactId>maven-resources-plugin</artifactId>
+        <version>2.3</version> <!-- Required for empty dirs config to be used -->
+        <configuration>
+          <!-- For the importer tests, we must copy empty directories -->
+          <includeEmptyDirs>true</includeEmptyDirs>
+        </configuration>
+      </plugin>
+      
     </plugins>
   </build>
 </project>

Added: shrinkwrap/trunk/impl-base/src/main/java/org/jboss/shrinkwrap/impl/base/asset/DirectoryAsset.java
===================================================================
--- shrinkwrap/trunk/impl-base/src/main/java/org/jboss/shrinkwrap/impl/base/asset/DirectoryAsset.java	                        (rev 0)
+++ shrinkwrap/trunk/impl-base/src/main/java/org/jboss/shrinkwrap/impl/base/asset/DirectoryAsset.java	2009-12-07 04:07:12 UTC (rev 3836)
@@ -0,0 +1,61 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2009, Red Hat Middleware LLC, and individual contributors
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jboss.shrinkwrap.impl.base.asset;
+
+import java.io.InputStream;
+
+import org.jboss.shrinkwrap.api.Archive;
+import org.jboss.shrinkwrap.api.Asset;
+import org.jboss.shrinkwrap.api.Path;
+
+/**
+ * {@link Asset} implementation used to denote no backing
+ * resource, but simply a directory structure.  When placed 
+ * into an {@link Archive} under some {@link Path}, only the 
+ * path context will be respected.  Modeled as a singleton
+ * as this implementation has no real state or identity (all
+ * directory assets are equal).  Calls to {@link DirectoryAsset#openStream()}
+ * will always return null.
+ * 
+ * @author <a href="mailto:andrew.rubinger at jboss.org">ALR</a>
+ * @version $Revision: $
+ */
+public enum DirectoryAsset implements Asset {
+
+   /**
+    * Singleton Instance
+    */
+   INSTANCE;
+
+   /**
+    * {@inheritDoc}
+    * @see org.jboss.shrinkwrap.api.Asset#openStream()
+    */
+   @Override
+   public InputStream openStream()
+   {
+      // To signify that we've got nothing to back us (we're just a directory),
+      // we use null.  A stream backed by an empty byte array would be an 
+      // empty file, which is different.
+      return null;
+   }
+
+   //-------------------------------------------------------------------------------------||
+   // Required Implementations -----------------------------------------------------------||
+   //-------------------------------------------------------------------------------------||
+
+}

Modified: shrinkwrap/trunk/impl-base/src/main/java/org/jboss/shrinkwrap/impl/base/container/ContainerBase.java
===================================================================
--- shrinkwrap/trunk/impl-base/src/main/java/org/jboss/shrinkwrap/impl/base/container/ContainerBase.java	2009-12-06 16:40:25 UTC (rev 3835)
+++ shrinkwrap/trunk/impl-base/src/main/java/org/jboss/shrinkwrap/impl/base/container/ContainerBase.java	2009-12-07 04:07:12 UTC (rev 3836)
@@ -20,6 +20,8 @@
 import java.net.URL;
 import java.security.AccessController;
 import java.security.PrivilegedAction;
+import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Map;
 import java.util.Set;
 
@@ -28,7 +30,9 @@
 import org.jboss.shrinkwrap.api.Filter;
 import org.jboss.shrinkwrap.api.Filters;
 import org.jboss.shrinkwrap.api.Path;
+import org.jboss.shrinkwrap.api.Paths;
 import org.jboss.shrinkwrap.api.container.ClassContainer;
+import org.jboss.shrinkwrap.api.container.DirectoryContainer;
 import org.jboss.shrinkwrap.api.container.LibraryContainer;
 import org.jboss.shrinkwrap.api.container.ManifestContainer;
 import org.jboss.shrinkwrap.api.container.ResourceContainer;
@@ -38,6 +42,7 @@
 import org.jboss.shrinkwrap.impl.base.asset.AssetUtil;
 import org.jboss.shrinkwrap.impl.base.asset.ClassAsset;
 import org.jboss.shrinkwrap.impl.base.asset.ClassLoaderAsset;
+import org.jboss.shrinkwrap.impl.base.asset.DirectoryAsset;
 import org.jboss.shrinkwrap.impl.base.asset.FileAsset;
 import org.jboss.shrinkwrap.impl.base.asset.UrlAsset;
 import org.jboss.shrinkwrap.impl.base.path.BasicPath;
@@ -53,7 +58,7 @@
  * @param <T>
  */
 public abstract class ContainerBase<T extends Archive<T>> extends AssignableBase implements 
-   Archive<T>, ManifestContainer<T>, ResourceContainer<T>, ClassContainer<T>, LibraryContainer<T> 
+   Archive<T>, ManifestContainer<T>, ResourceContainer<T>, ClassContainer<T>, LibraryContainer<T>, DirectoryContainer<T>
 {
    //-------------------------------------------------------------------------------------||
    // Class Members ----------------------------------------------------------------------||
@@ -890,6 +895,79 @@
    }
    
    //-------------------------------------------------------------------------------------||
+   // Required Implementations - DirectoryContainer --------------------------------------||
+   //-------------------------------------------------------------------------------------||
+
+   /**
+    * {@inheritDoc}
+    * @see org.jboss.shrinkwrap.api.container.DirectoryContainer#addDirectory(org.jboss.shrinkwrap.api.Path)
+    */
+   @Override
+   public T addDirectory(final Path path) throws IllegalArgumentException
+   {
+      // Precondition check
+      Validate.notNull(path, "path must be specified");
+      
+      // Delegate and return
+      return this.addDirectories(path);
+   }
+
+   /**
+    * {@inheritDoc}
+    * @see org.jboss.shrinkwrap.api.container.DirectoryContainer#addDirectory(java.lang.String)
+    */
+   @Override
+   public T addDirectory(final String path) throws IllegalArgumentException
+   {
+      // Precondition check
+      Validate.notNullOrEmpty(path, "path must be specified");
+      
+      // Delegate and return
+      return this.addDirectory(Paths.create(path));
+   }
+   
+   /**
+    * {@inheritDoc}
+    * @see org.jboss.shrinkwrap.api.container.DirectoryContainer#addDirectories(org.jboss.shrinkwrap.api.Path[])
+    */
+   @Override
+   public T addDirectories(final Path... paths) throws IllegalArgumentException
+   {
+      // Precondition check
+      Validate.notNull(paths, "paths must be specified");
+      
+      // Add
+      for (final Path path : paths)
+      {
+         this.add(DirectoryAsset.INSTANCE, path);
+      }
+      
+      // Return
+      return covarientReturn();
+   }
+
+   /**
+    * {@inheritDoc}
+    * @see org.jboss.shrinkwrap.api.container.DirectoryContainer#addDirectories(java.lang.String[])
+    */
+   @Override
+   public T addDirectories(final String... paths) throws IllegalArgumentException
+   {
+      // Precondition check
+      Validate.notNull(paths, "paths must be specified");
+      
+      // Represent as array of Paths
+      final Collection<Path> pathsCollection = new ArrayList<Path>(paths.length);
+      for (final String path : paths)
+      {
+         pathsCollection.add(Paths.create(path));
+      }
+      
+      // Delegate and return
+      return this.addDirectories(pathsCollection.toArray(new Path[]{}));
+   }
+   
+   //-------------------------------------------------------------------------------------||
    // Internal Helper Methods ------------------------------------------------------------||
    //-------------------------------------------------------------------------------------||
 

Modified: shrinkwrap/trunk/impl-base/src/main/java/org/jboss/shrinkwrap/impl/base/exporter/AbstractExporterDelegate.java
===================================================================
--- shrinkwrap/trunk/impl-base/src/main/java/org/jboss/shrinkwrap/impl/base/exporter/AbstractExporterDelegate.java	2009-12-06 16:40:25 UTC (rev 3835)
+++ shrinkwrap/trunk/impl-base/src/main/java/org/jboss/shrinkwrap/impl/base/exporter/AbstractExporterDelegate.java	2009-12-07 04:07:12 UTC (rev 3836)
@@ -16,8 +16,10 @@
  */
 package org.jboss.shrinkwrap.impl.base.exporter;
 
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
 import java.util.Map;
-import java.util.Map.Entry;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
@@ -81,15 +83,20 @@
 
       // Obtain all contents
       final Map<Path, Asset> content = archive.getContent();
-
+      
+      // Process in reverse order such that we can check for parent relationships, 
+      // and not write directories twice
+      final List<Path> paths = new ArrayList<Path>(content.keySet());
+      Collections.reverse(paths);
+      
       // For every Path in the Archive
-      for (final Entry<Path, Asset> contentEntry : content.entrySet())
+      for (final Path entry : paths)
       {
          // Get Asset information
-         final Path path = contentEntry.getKey();
-         final Asset asset = contentEntry.getValue();
+         final Path path = entry;
+         final Asset asset = content.get(entry);
 
-         // Process the asset 
+         // Process the asset
          processAsset(path, asset);
       }
    }

Modified: shrinkwrap/trunk/impl-base/src/main/java/org/jboss/shrinkwrap/impl/base/exporter/ExplodedExporterDelegate.java
===================================================================
--- shrinkwrap/trunk/impl-base/src/main/java/org/jboss/shrinkwrap/impl/base/exporter/ExplodedExporterDelegate.java	2009-12-06 16:40:25 UTC (rev 3835)
+++ shrinkwrap/trunk/impl-base/src/main/java/org/jboss/shrinkwrap/impl/base/exporter/ExplodedExporterDelegate.java	2009-12-07 04:07:12 UTC (rev 3836)
@@ -29,6 +29,7 @@
 import org.jboss.shrinkwrap.api.exporter.ArchiveExportException;
 import org.jboss.shrinkwrap.api.exporter.ExplodedExporter;
 import org.jboss.shrinkwrap.impl.base.asset.ArchiveAsset;
+import org.jboss.shrinkwrap.impl.base.asset.DirectoryAsset;
 import org.jboss.shrinkwrap.impl.base.io.IOUtil;
 
 /**
@@ -107,24 +108,43 @@
          processArchiveAsset(assetParent, nesteArchiveAsset);
          return;
       }
-
-      try
+      
+      // Handle directory assets separately
+      final boolean isDirectory = asset instanceof DirectoryAsset;
+      if (isDirectory)
       {
-         if (log.isLoggable(Level.FINE))
+         // If doesn't already exist
+         if (!assetFile.exists())
          {
-            log.fine("Writing asset " + path.get() + " to " + assetFile.getAbsolutePath());
+            // Attempt a create
+            if (!assetFile.mkdirs())
+            {
+               // Some error in writing
+               throw new ArchiveExportException("Failed to write directory: " + assetFile.getAbsolutePath());
+            }
          }
-         // Get the asset streams
-         final InputStream assetInputStream = asset.openStream();
-         final FileOutputStream assetFileOutputStream = new FileOutputStream(assetFile);
-         final BufferedOutputStream assetBufferedOutputStream = new BufferedOutputStream(assetFileOutputStream, 8192);
-
-         // Write contents
-         IOUtil.copyWithClose(assetInputStream, assetBufferedOutputStream);
       }
-      catch (Throwable t)
+      // Only handle non-directory assets, otherwise the path is handled above
+      else
       {
-         throw new ArchiveExportException("Failed to write asset " + path + " to " + assetFile);
+         try
+         {
+            if (log.isLoggable(Level.FINE))
+            {
+               log.fine("Writing asset " + path.get() + " to " + assetFile.getAbsolutePath());
+            }
+            // Get the asset streams
+            final InputStream assetInputStream = asset.openStream();
+            final FileOutputStream assetFileOutputStream = new FileOutputStream(assetFile);
+            final BufferedOutputStream assetBufferedOutputStream = new BufferedOutputStream(assetFileOutputStream, 8192);
+
+            // Write contents
+            IOUtil.copyWithClose(assetInputStream, assetBufferedOutputStream);
+         }
+         catch (Throwable t)
+         {
+            throw new ArchiveExportException("Failed to write asset " + path + " to " + assetFile);
+         }
       }
    }
 

Modified: shrinkwrap/trunk/impl-base/src/main/java/org/jboss/shrinkwrap/impl/base/exporter/ZipExportDelegate.java
===================================================================
--- shrinkwrap/trunk/impl-base/src/main/java/org/jboss/shrinkwrap/impl/base/exporter/ZipExportDelegate.java	2009-12-06 16:40:25 UTC (rev 3835)
+++ shrinkwrap/trunk/impl-base/src/main/java/org/jboss/shrinkwrap/impl/base/exporter/ZipExportDelegate.java	2009-12-07 04:07:12 UTC (rev 3836)
@@ -24,16 +24,17 @@
 import java.util.logging.Level;
 import java.util.logging.Logger;
 import java.util.zip.ZipEntry;
+import java.util.zip.ZipException;
 import java.util.zip.ZipOutputStream;
 
 import org.jboss.shrinkwrap.api.Archive;
 import org.jboss.shrinkwrap.api.Asset;
 import org.jboss.shrinkwrap.api.Path;
 import org.jboss.shrinkwrap.api.exporter.ArchiveExportException;
+import org.jboss.shrinkwrap.impl.base.asset.DirectoryAsset;
 import org.jboss.shrinkwrap.impl.base.io.IOUtil;
 import org.jboss.shrinkwrap.impl.base.io.StreamErrorHandler;
 import org.jboss.shrinkwrap.impl.base.io.StreamTask;
-import org.jboss.shrinkwrap.impl.base.path.BasicPath;
 import org.jboss.shrinkwrap.impl.base.path.PathUtil;
 
 public class ZipExportDelegate extends AbstractExporterDelegate<InputStream>
@@ -126,18 +127,23 @@
          throw new IllegalArgumentException("Path must be specified");
       }
 
+      if(isParentOfAnyPathsExported(path))
+      {
+         return;
+      }
+      
       /*
        * SHRINKWRAP-94
        * Add entries for all parents of this Path
        * by recursing first and adding parents that
        * haven't already been written.
        */
-      final Path parent = getParent(path);
+      final Path parent = PathUtil.getParent(path);
       if (parent != null && !this.pathsExported.contains(parent))
       {
          // If this is not the root
          // SHRINKWRAP-96
-         final Path grandParent = getParent(parent);
+         final Path grandParent = PathUtil.getParent(parent);
          final boolean isRoot = grandParent == null;
          if (!isRoot)
          {
@@ -146,56 +152,67 @@
          }
       }
       // Mark if we're writing a directory
-      final boolean isDirectory = asset == null;
+      final boolean isDirectory = ((asset == null) || (asset instanceof DirectoryAsset));
 
       // Get Asset InputStream if the asset is specified (else it's a directory so use null)
       final InputStream assetStream = !isDirectory ? asset.openStream() : null;
       final String pathName = PathUtil.optionallyRemovePrecedingSlash(path.get());
 
-      // Make a task for this stream and close when done
-      IOUtil.closeOnComplete(assetStream, new StreamTask<InputStream>()
+      // If we haven't already written this path
+      if (!this.pathsExported.contains(path))
       {
+         // Make a task for this stream and close when done
+         IOUtil.closeOnComplete(assetStream, new StreamTask<InputStream>()
+         {
 
-         @Override
-         public void execute(InputStream stream) throws Exception
-         {
-            // If we're writing a directory, ensure we trail a slash for the ZipEntry
-            String resolvedPath = pathName;
-            if (isDirectory)
+            @Override
+            public void execute(InputStream stream) throws Exception
             {
-               resolvedPath = PathUtil.optionallyAppendSlash(resolvedPath);
-            }
+               // If we're writing a directory, ensure we trail a slash for the ZipEntry
+               String resolvedPath = pathName;
+               if (isDirectory)
+               {
+                  resolvedPath = PathUtil.optionallyAppendSlash(resolvedPath);
+               }
 
-            // Make a ZipEntry
-            final ZipEntry entry = new ZipEntry(resolvedPath);
+               // Make a ZipEntry
+               final ZipEntry entry = new ZipEntry(resolvedPath);
 
-            // Write the Asset under the same Path name in the Zip
-            zipOutputStream.putNextEntry(entry);
+               // Write the Asset under the same Path name in the Zip
+               try{
+                  zipOutputStream.putNextEntry(entry);
+               }
+               catch(final ZipException ze)
+               {
+                  log.log(Level.SEVERE,pathsExported.toString());
+                  throw new RuntimeException(ze);
+               }
 
-            // Mark that we've written this Path 
-            pathsExported.add(path);
+               // Mark that we've written this Path 
+               pathsExported.add(path);
 
-            // Read the contents of the asset and write to the JAR, 
-            // if we're not just a directory
-            if (!isDirectory)
-            {
-               IOUtil.copy(stream, zipOutputStream);
+               // Read the contents of the asset and write to the JAR, 
+               // if we're not just a directory
+               if (!isDirectory)
+               {
+                  IOUtil.copy(stream, zipOutputStream);
+               }
+
+               // Close up the instream and the entry
+               zipOutputStream.closeEntry();
             }
 
-            // Close up the instream and the entry
-            zipOutputStream.closeEntry();
-         }
+         }, new StreamErrorHandler()
+         {
 
-      }, new StreamErrorHandler()
-      {
+            @Override
+            public void handle(Throwable t)
+            {
+               throw new ArchiveExportException("Failed to write asset to Zip: " + pathName, t);
+            }
 
-         @Override
-         public void handle(Throwable t)
-         {
-            throw new ArchiveExportException("Failed to write asset to Zip: " + pathName, t);
-         }
-
-      });
+         });
+      }
    }
 
    /* (non-Javadoc)
@@ -217,38 +234,46 @@
       // Return
       return inputStream;
    }
-
-   //-------------------------------------------------------------------------------------||
-   // Internal Helper Methods ------------------------------------------------------------||
-   //-------------------------------------------------------------------------------------||
-
+   
    /**
-    * Obtains the parent of this Path, if exists, else null.
-    * For instance if the Path is "/my/path", the parent 
-    * will be "/my".  Each call will result in a new object reference,
-    * though subsequent calls upon the same Path will be equal by value.
+    * Returns whether or not this Path is a parent of any Paths exported 
+    * @param path
     * @return
-    * 
-    * @param path The path whose parent context we should return
     */
-   static Path getParent(final Path path)
+   //TODO The performance here will degrade geometrically with size of the archive
+   private boolean isParentOfAnyPathsExported(final Path path)
    {
-      // Precondition checks
-      assert path != null : "Path must be specified";
-
-      // Get the last index of "/"
-      final String resolvedContext = PathUtil.optionallyRemoveFollowingSlash(path.get());
-      final int lastIndex = resolvedContext.lastIndexOf(PathUtil.SLASH);
-      // If it either doesn't occur or is the root
-      if (lastIndex == -1 || (lastIndex == 0 && resolvedContext.length() == 1))
+      // For all Paths already exported
+      for(final Path exportedPath :this.pathsExported)
       {
-         // No parent present, return null
-         return null;
+         if( this.isParentOfSpecifiedHierarchy(path, exportedPath)){
+            return true;
+         }
       }
-      // Get the parent context
-      final String sub = resolvedContext.substring(0, lastIndex);
-      // Return
-      return new BasicPath(sub);
+      
+      return false;
    }
-
+   
+   /**
+    * 
+    * @param path
+    * @param compare
+    * @return
+    */
+   private boolean isParentOfSpecifiedHierarchy(final Path path,final Path compare){
+      // If we've reached the root, we're not a parent of any paths already exported
+      final Path parent = PathUtil.getParent(compare);
+      if(parent==null)
+      {
+         return false;
+      }
+      // If equal to me, yes
+      if(path.equals(compare))
+      {
+         return true;
+      }
+      
+      // Check my parent
+      return this.isParentOfSpecifiedHierarchy(path, parent);
+   }
 }

Modified: shrinkwrap/trunk/impl-base/src/main/java/org/jboss/shrinkwrap/impl/base/importer/ExplodedImporterImpl.java
===================================================================
--- shrinkwrap/trunk/impl-base/src/main/java/org/jboss/shrinkwrap/impl/base/importer/ExplodedImporterImpl.java	2009-12-06 16:40:25 UTC (rev 3835)
+++ shrinkwrap/trunk/impl-base/src/main/java/org/jboss/shrinkwrap/impl/base/importer/ExplodedImporterImpl.java	2009-12-07 04:07:12 UTC (rev 3836)
@@ -17,12 +17,14 @@
 package org.jboss.shrinkwrap.impl.base.importer;
 
 import java.io.File;
+import java.util.logging.Logger;
 
 import org.jboss.shrinkwrap.api.Archive;
 import org.jboss.shrinkwrap.api.Path;
 import org.jboss.shrinkwrap.api.importer.ExplodedImporter;
 import org.jboss.shrinkwrap.impl.base.AssignableBase;
 import org.jboss.shrinkwrap.impl.base.Validate;
+import org.jboss.shrinkwrap.impl.base.asset.DirectoryAsset;
 import org.jboss.shrinkwrap.impl.base.asset.FileAsset;
 import org.jboss.shrinkwrap.impl.base.path.BasicPath;
 
@@ -38,6 +40,15 @@
       ExplodedImporter
 {
    // -------------------------------------------------------------------------------------||
+   // Class Members -----------------------------------------------------------------------||
+   // -------------------------------------------------------------------------------------||
+   
+   /**
+    * Logger
+    */
+   private static final Logger log = Logger.getLogger(ExplodedImporterImpl.class.getName());
+   
+   // -------------------------------------------------------------------------------------||
    // Instance Members --------------------------------------------------------------------||
    // -------------------------------------------------------------------------------------||
 
@@ -110,12 +121,15 @@
    {
       for (File file : files)
       {
+         log.info(file.getAbsolutePath());
+         final Path path  = calculatePath(root, file);
          if (file.isDirectory())
          {
+            archive.add(DirectoryAsset.INSTANCE,path);
             doImport(root, file.listFiles());
          } else
          {
-            archive.add(new FileAsset(file), calculatePath(root, file));
+            archive.add(new FileAsset(file), path);
          }
       }
    }

Modified: shrinkwrap/trunk/impl-base/src/main/java/org/jboss/shrinkwrap/impl/base/importer/ZipImporterImpl.java
===================================================================
--- shrinkwrap/trunk/impl-base/src/main/java/org/jboss/shrinkwrap/impl/base/importer/ZipImporterImpl.java	2009-12-06 16:40:25 UTC (rev 3835)
+++ shrinkwrap/trunk/impl-base/src/main/java/org/jboss/shrinkwrap/impl/base/importer/ZipImporterImpl.java	2009-12-07 04:07:12 UTC (rev 3836)
@@ -19,6 +19,8 @@
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.util.Enumeration;
+import java.util.logging.Level;
+import java.util.logging.Logger;
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipFile;
 import java.util.zip.ZipInputStream;
@@ -29,6 +31,7 @@
 import org.jboss.shrinkwrap.impl.base.AssignableBase;
 import org.jboss.shrinkwrap.impl.base.Validate;
 import org.jboss.shrinkwrap.impl.base.asset.ByteArrayAsset;
+import org.jboss.shrinkwrap.impl.base.asset.DirectoryAsset;
 import org.jboss.shrinkwrap.impl.base.asset.ZipFileEntryAsset;
 import org.jboss.shrinkwrap.impl.base.path.BasicPath;
 
@@ -41,6 +44,15 @@
 public class ZipImporterImpl extends AssignableBase implements ZipImporter  
 {
    //-------------------------------------------------------------------------------------||
+   // Class Members ----------------------------------------------------------------------||
+   //-------------------------------------------------------------------------------------||
+   
+   /**
+    * Logger
+    */
+   private static final Logger log = Logger.getLogger(ZipImporter.class.getName());
+   
+   //-------------------------------------------------------------------------------------||
    // Instance Members -------------------------------------------------------------------||
    //-------------------------------------------------------------------------------------||
    
@@ -72,7 +84,8 @@
       return archive;
    }
 
-   /* (non-Javadoc)
+   /**
+    * {@inheritDoc}
     * @see org.jboss.shrinkwrap.api.importer.ZipImporter#importZip(java.util.zip.ZipInputStream)
     */
    // TODO: create a ZipEntryAsset that can stream directly from the stream somehow?
@@ -85,15 +98,15 @@
          ZipEntry entry;
          while( (entry = stream.getNextEntry()) != null) 
          {
-            /*
-             *  TODO: we skip directories since the whole path is auto created and we have to directory concept. 
-             *  we lose the empty directories, ok?
-             */
+            // Get the name
+            final String entryName = entry.getName();
+            
+            // Handle directories separately
             if(entry.isDirectory()) 
             {
+               archive.add(DirectoryAsset.INSTANCE, entryName);
                continue; 
             }
-            String entryName = entry.getName();
 
             ByteArrayOutputStream output = new ByteArrayOutputStream(8192);
             byte[] content = new byte[4096];
@@ -116,8 +129,12 @@
          {
             stream.close();
          } 
-         catch (Exception ingore) 
+         catch (final Exception ignore) 
          {
+            if (log.isLoggable(Level.FINER))
+            {
+               log.finer("Caught and ignoring exception while closing instream during import" + ignore);
+            }
          }
       }
       return this;
@@ -135,14 +152,16 @@
       while(entries.hasMoreElements())
       {
          ZipEntry entry = entries.nextElement();
-         /*
-          *  TODO: we skip directories since the whole path is auto created and we have to directory concept. 
-          *  we lose the empty directories, ok?
-          */
-         if(entry.isDirectory()) {
-            continue;
+
+         // Get the entry (path) name
+         final String entryName = entry.getName();
+         
+         // Handle directories separately
+         if(entry.isDirectory())
+         {
+            archive.add(DirectoryAsset.INSTANCE, entryName);
+            continue; 
          }
-         String entryName = entry.getName();
          
          archive.add(new ZipFileEntryAsset(file, entry), new BasicPath(entryName));
       }

Modified: shrinkwrap/trunk/impl-base/src/main/java/org/jboss/shrinkwrap/impl/base/path/BasicPath.java
===================================================================
--- shrinkwrap/trunk/impl-base/src/main/java/org/jboss/shrinkwrap/impl/base/path/BasicPath.java	2009-12-06 16:40:25 UTC (rev 3835)
+++ shrinkwrap/trunk/impl-base/src/main/java/org/jboss/shrinkwrap/impl/base/path/BasicPath.java	2009-12-07 04:07:12 UTC (rev 3836)
@@ -144,11 +144,30 @@
       {
          return 1;
       }
+      /*
+       * Check for parent relationship
+       */
+      final Path parentOfSpecified = PathUtil.getParent(path);
+      final Path parentOfThis = PathUtil.getParent(this);
+      // If we're the parent of the specified, we're less
+      if (this.equals(parentOfSpecified))
+      {
+         return -1;
+      }
+      // If the specified if the parent of us, we're more
+      if (path.equals(parentOfThis))
+      {
+         return 1;
+      }
 
-      // Just delegate to underlying Strings
-      return path.get().compareTo(this.get());
+      // Just delegate to underlying contexts
+      final int comparedContexts = path.get().compareTo(this.get());
+
+      // Return the inverted value of the contents (in this ordering, less is more)
+      final int adjusted = 0 - comparedContexts;
+      return adjusted;
    }
-
+   
    //-------------------------------------------------------------------------------------||
    // Overridden Implementations ---------------------------------------------------------||
    //-------------------------------------------------------------------------------------||
@@ -180,13 +199,22 @@
       if (getClass() != obj.getClass())
          return false;
       final BasicPath other = (BasicPath) obj;
+      
       if (context == null)
       {
          if (other.context != null)
             return false;
       }
-      else if (!context.equals(other.context))
+      
+      // Ensure we treat following slashes equally
+      final String adjustedContext = PathUtil.optionallyRemoveFollowingSlash(context);
+      final String adjustedOther = PathUtil.optionallyRemoveFollowingSlash(other.context);
+      if (!adjustedContext.equals(adjustedOther))
+      {
          return false;
+      }
+       
+      // No match
       return true;
    }
 

Modified: shrinkwrap/trunk/impl-base/src/main/java/org/jboss/shrinkwrap/impl/base/path/PathUtil.java
===================================================================
--- shrinkwrap/trunk/impl-base/src/main/java/org/jboss/shrinkwrap/impl/base/path/PathUtil.java	2009-12-06 16:40:25 UTC (rev 3835)
+++ shrinkwrap/trunk/impl-base/src/main/java/org/jboss/shrinkwrap/impl/base/path/PathUtil.java	2009-12-07 04:07:12 UTC (rev 3836)
@@ -17,6 +17,8 @@
  */
 package org.jboss.shrinkwrap.impl.base.path;
 
+import org.jboss.shrinkwrap.api.Path;
+
 /**
  * PathUtil
  * 
@@ -233,7 +235,36 @@
       // Return as-is
       return resolved;
    }
+   
+   /**
+    * Obtains the parent of this Path, if exists, else null.
+    * For instance if the Path is "/my/path", the parent 
+    * will be "/my".  Each call will result in a new object reference,
+    * though subsequent calls upon the same Path will be equal by value.
+    * @return
+    * 
+    * @param path The path whose parent context we should return
+    */
+   public static Path getParent(final Path path)
+   {
+      // Precondition checks
+      assert path != null : "Path must be specified";
 
+      // Get the last index of "/"
+      final String resolvedContext = PathUtil.optionallyRemoveFollowingSlash(path.get());
+      final int lastIndex = resolvedContext.lastIndexOf(PathUtil.SLASH);
+      // If it either doesn't occur or is the root
+      if (lastIndex == -1 || (lastIndex == 0 && resolvedContext.length() == 1))
+      {
+         // No parent present, return null
+         return null;
+      }
+      // Get the parent context
+      final String sub = resolvedContext.substring(0, lastIndex);
+      // Return
+      return new BasicPath(PathUtil.optionallyAppendSlash(sub));
+   }
+
    //-------------------------------------------------------------------------------------||
    // Internal Helper Methods ------------------------------------------------------------||
    //-------------------------------------------------------------------------------------||

Added: shrinkwrap/trunk/impl-base/src/test/java/org/jboss/shrinkwrap/impl/base/asset/DirectoryAssetTestCase.java
===================================================================
--- shrinkwrap/trunk/impl-base/src/test/java/org/jboss/shrinkwrap/impl/base/asset/DirectoryAssetTestCase.java	                        (rev 0)
+++ shrinkwrap/trunk/impl-base/src/test/java/org/jboss/shrinkwrap/impl/base/asset/DirectoryAssetTestCase.java	2009-12-07 04:07:12 UTC (rev 3836)
@@ -0,0 +1,56 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2009, Red Hat Middleware LLC, and individual contributors
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jboss.shrinkwrap.impl.base.asset;
+
+import java.io.InputStream;
+
+import junit.framework.TestCase;
+
+import org.jboss.shrinkwrap.api.Asset;
+import org.junit.Test;
+
+/**
+ * Enforces the contract of {@link DirectoryAsset}
+ * 
+ * @author <a href="mailto:andrew.rubinger at jboss.org">ALR</a>
+ * @version $Revision: $
+ */
+public class DirectoryAssetTestCase
+{
+
+   //-------------------------------------------------------------------------------------||
+   // Tests ------------------------------------------------------------------------------||
+   //-------------------------------------------------------------------------------------||
+
+   /**
+    * Ensures the {@link DirectoryAsset} always has a null stream
+    */
+   @Test
+   public void directoryAssetHasNullStream()
+   {
+
+      // Get the asset
+      final Asset asset = DirectoryAsset.INSTANCE;
+
+      // Get the stream
+      final InputStream stream = asset.openStream();
+
+      // Ensure null
+      TestCase.assertNull("Directory assets should always have null streams (contents)", stream);
+   }
+
+}

Modified: shrinkwrap/trunk/impl-base/src/test/java/org/jboss/shrinkwrap/impl/base/exporter/ExportTestBase.java
===================================================================
--- shrinkwrap/trunk/impl-base/src/test/java/org/jboss/shrinkwrap/impl/base/exporter/ExportTestBase.java	2009-12-06 16:40:25 UTC (rev 3835)
+++ shrinkwrap/trunk/impl-base/src/test/java/org/jboss/shrinkwrap/impl/base/exporter/ExportTestBase.java	2009-12-07 04:07:12 UTC (rev 3836)
@@ -24,9 +24,11 @@
 import org.jboss.shrinkwrap.api.Archives;
 import org.jboss.shrinkwrap.api.Asset;
 import org.jboss.shrinkwrap.api.Path;
+import org.jboss.shrinkwrap.api.Paths;
 import org.jboss.shrinkwrap.api.spec.JavaArchive;
 import org.jboss.shrinkwrap.impl.base.TestIOUtil;
 import org.jboss.shrinkwrap.impl.base.asset.ClassLoaderAsset;
+import org.jboss.shrinkwrap.impl.base.asset.DirectoryAsset;
 import org.jboss.shrinkwrap.impl.base.path.BasicPath;
 import org.junit.Assert;
 
@@ -100,6 +102,16 @@
    * Another path used for testing
    */
    protected static final Path PATH_TWO = new BasicPath(NESTED_PATH, "Test2.properties");
+   
+   /**
+    * Path to a nested empty directory
+    */
+   protected static final Path PATH_EMPTY_NESTED_DIR = Paths.create("/empty");
+   
+   /**
+    * Path to an empty directory, a child of the nested
+    */
+   protected static final Path PATH_EMPTY_TOPLEVEL_DIR = Paths.create("/empty/directory");
 
    //-------------------------------------------------------------------------------------||
    // Functional Methods -----------------------------------------------------------------||
@@ -179,6 +191,10 @@
 
       // Add the archive under a nested path
       archive.add(nestedArchiveTwo, NESTED_PATH);
+      
+      // Add empty directories
+      archive.add(DirectoryAsset.INSTANCE, PATH_EMPTY_NESTED_DIR);
+      archive.add(DirectoryAsset.INSTANCE, PATH_EMPTY_TOPLEVEL_DIR);
 
       // Return archive
       return archive;

Modified: shrinkwrap/trunk/impl-base/src/test/java/org/jboss/shrinkwrap/impl/base/exporter/ZipExporterTestCase.java
===================================================================
--- shrinkwrap/trunk/impl-base/src/test/java/org/jboss/shrinkwrap/impl/base/exporter/ZipExporterTestCase.java	2009-12-06 16:40:25 UTC (rev 3835)
+++ shrinkwrap/trunk/impl-base/src/test/java/org/jboss/shrinkwrap/impl/base/exporter/ZipExporterTestCase.java	2009-12-07 04:07:12 UTC (rev 3836)
@@ -25,8 +25,6 @@
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipFile;
 
-import junit.framework.TestCase;
-
 import org.jboss.shrinkwrap.api.Archive;
 import org.jboss.shrinkwrap.api.Asset;
 import org.jboss.shrinkwrap.api.Path;
@@ -246,35 +244,4 @@
       IOUtil.copyWithClose(inputStream, fileOutputStream);
    }
 
-   /**
-    * Ensures the contract of {@link PathProvider#parent()}
-    * is intact
-    */
-   @Test
-   public void testParent()
-   {
-      // Log
-      log.info("testParent");
-
-      // Create new paths
-      final String rootString = "/";
-      final String subpathString = "subpath";
-      final String contextString = "context";
-      final String context2String = "context/";
-      final BasicPath root = new BasicPath(rootString);
-      final BasicPath subpath = new BasicPath(subpathString);
-      final BasicPath context = new BasicPath(subpath, contextString);
-      final BasicPath contextWithFollowingSlash = new BasicPath(subpath, context2String);
-
-      // Test
-      TestCase.assertEquals("The parent of the context path should be equal to the initial subpath", subpath,
-            ZipExportDelegate.getParent(context));
-      TestCase.assertEquals(
-            "The parent of the context path with a following slash should be equal to the initial subpath", subpath,
-            ZipExportDelegate.getParent(contextWithFollowingSlash));
-      TestCase.assertEquals("The parent of the subpath should be the root", root, ZipExportDelegate.getParent(subpath));
-      TestCase.assertNull("The parent of the root should be null", ZipExportDelegate.getParent(root));
-
-   }
-
 }

Modified: shrinkwrap/trunk/impl-base/src/test/java/org/jboss/shrinkwrap/impl/base/importer/ExplodedImporterTestCase.java
===================================================================
--- shrinkwrap/trunk/impl-base/src/test/java/org/jboss/shrinkwrap/impl/base/importer/ExplodedImporterTestCase.java	2009-12-06 16:40:25 UTC (rev 3835)
+++ shrinkwrap/trunk/impl-base/src/test/java/org/jboss/shrinkwrap/impl/base/importer/ExplodedImporterTestCase.java	2009-12-07 04:07:12 UTC (rev 3836)
@@ -16,6 +16,8 @@
  */
 package org.jboss.shrinkwrap.impl.base.importer;
 
+import java.util.logging.Logger;
+
 import org.jboss.shrinkwrap.api.Archive;
 import org.jboss.shrinkwrap.api.Archives;
 import org.jboss.shrinkwrap.api.importer.ExplodedImporter;
@@ -46,7 +48,7 @@
                                        .getResource(EXISTING_DIRECTORY_RESOURCE).toURI().getPath()
                               )
                               .as(JavaArchive.class);
-      
+      Logger.getLogger(ExplodedImporterTestCase.class.getName()).info(archive.toString(true));
       Assert.assertTrue(
             "Root files should be imported",
             archive.contains(new BasicPath("/Test.properties")));      
@@ -57,7 +59,15 @@
 
       Assert.assertTrue(
             "Nested files should be imported",
-            archive.contains(new BasicPath("/org/jboss/Test.properties")));  
+            archive.contains(new BasicPath("/org/jboss/Test.properties")));
+      
+      Assert.assertTrue(
+            "Empty directories should be imported",
+            archive.contains(new BasicPath("/empty_dir")));
+      
+      Assert.assertTrue(
+            "Nested empty directories should be imported",
+            archive.contains(new BasicPath("/parent/empty_dir"))); 
    }
    
    @Test(expected = IllegalArgumentException.class)

Modified: shrinkwrap/trunk/impl-base/src/test/java/org/jboss/shrinkwrap/impl/base/importer/ZipImporterImplTestCase.java
===================================================================
--- shrinkwrap/trunk/impl-base/src/test/java/org/jboss/shrinkwrap/impl/base/importer/ZipImporterImplTestCase.java	2009-12-06 16:40:25 UTC (rev 3835)
+++ shrinkwrap/trunk/impl-base/src/test/java/org/jboss/shrinkwrap/impl/base/importer/ZipImporterImplTestCase.java	2009-12-07 04:07:12 UTC (rev 3836)
@@ -65,6 +65,16 @@
    
    private static final String EXISTING_RESOURCE = "org/jboss/shrinkwrap/impl/base/asset/Test.properties";
    
+   /**
+    * Name of the expected empty directory
+    */
+   private static final String EXPECTED_EMPTY_DIR ="empty_dir/";
+   
+   /**
+    * Name of the expected nested directory
+    */
+   private static final String EXPECTED_NESTED_EMPTY_DIR ="parent/empty_dir/";
+   
    //-------------------------------------------------------------------------------------||
    // Tests ------------------------------------------------------------------------------||
    //-------------------------------------------------------------------------------------||
@@ -79,6 +89,9 @@
       Archive<?> archive = Archives.create("test.jar", ZipImporter.class)
                                  .importZip(testZip)
                               .as(JavaArchive.class);
+      
+      final InputStream stream = archive.as(ZipExporter.class).exportZip();
+      IOUtil.copy(stream, new FileOutputStream(new File("/home/alr/Desktop/test.zip")));
 
       Assert.assertNotNull("Should not return a null archive", archive);
       
@@ -148,14 +161,28 @@
             "Test zip should contain data", 
             entries.isEmpty());
       Assert.assertEquals(
-            "Should have imported all files",
-            findNumberOfFiles(entries), 
+            "Should have imported all files and directories",
+            entries.size(),
             importedArchive.getContent().size());
       
+      
+      boolean containsEmptyDir = false;
+      boolean containsEmptyNestedDir = false;
+      
       for(ZipEntry originalEntry : entries) 
       {
+         
          if(originalEntry.isDirectory()) 
          {
+            // Check for expected empty dirs
+            if (originalEntry.getName().equals(EXPECTED_EMPTY_DIR))
+            {
+               containsEmptyDir = true;
+            }
+            if (originalEntry.getName().equals(EXPECTED_NESTED_EMPTY_DIR))
+            {
+               containsEmptyNestedDir = true;
+            }
             continue;
          }
 
@@ -177,24 +204,9 @@
                "The content of " + originalEntry.getName() + " should be equal to the imported content",
                Arrays.equals(importedContent, originalContent));
       }
+      
+      // Ensure empty directories have come in cleanly
+      Assert.assertTrue("Empty directory not imported", containsEmptyDir);
+      Assert.assertTrue("Empty nested directory not imported", containsEmptyNestedDir);
    }
-
-   /**
-    * Find the number of files in original zip, exclude directories.
-    * 
-    * @param enties
-    * @return
-    */
-   private int findNumberOfFiles(List<? extends ZipEntry> enties) 
-   {
-      int count = 0;
-      for(ZipEntry entry : enties) 
-      {
-         if(!entry.isDirectory()) 
-         {
-            count++;
-         }
-      }
-      return count;
-   }
 }

Modified: shrinkwrap/trunk/impl-base/src/test/java/org/jboss/shrinkwrap/impl/base/path/PathUtilTestCase.java
===================================================================
--- shrinkwrap/trunk/impl-base/src/test/java/org/jboss/shrinkwrap/impl/base/path/PathUtilTestCase.java	2009-12-06 16:40:25 UTC (rev 3835)
+++ shrinkwrap/trunk/impl-base/src/test/java/org/jboss/shrinkwrap/impl/base/path/PathUtilTestCase.java	2009-12-07 04:07:12 UTC (rev 3836)
@@ -2,6 +2,10 @@
 
 import java.util.logging.Logger;
 
+import junit.framework.TestCase;
+
+import org.jboss.shrinkwrap.api.Path;
+import org.jboss.shrinkwrap.api.Paths;
 import org.junit.Assert;
 import org.junit.Test;
 
@@ -172,5 +176,35 @@
       final String result = PathUtil.composeAbsoluteContext(base, context);
       Assert.assertEquals("Composing an absolute context from base and context did not succeed", expected, result);
    }
+   
+   /**
+    * Ensures the contract of {@link PathProvider#parent()}
+    * is intact
+    */
+   @Test
+   public void testParent()
+   {
+      // Log
+      log.info("testParent");
 
+      // Create new paths
+      final String rootString = "/";
+      final String subpathString = "subpath/";
+      final String contextString = "context";
+      final String contextWithFollowingSlashString = "context/";
+      final Path root = Paths.create(rootString);
+      final Path subpath = Paths.create(subpathString);
+      final Path context = Paths.create(subpath, contextString);
+      final Path contextWithFollowingSlash = new BasicPath(subpath, contextWithFollowingSlashString);
+
+      // Test
+      TestCase.assertEquals("The parent of the context path should be equal to the initial subpath", subpath,
+            PathUtil.getParent(context));
+      TestCase.assertEquals(
+            "The parent of the context path with a following slash should be equal to the initial subpath", subpath,
+            PathUtil.getParent(contextWithFollowingSlash));
+      TestCase.assertEquals("The parent of the subpath should be the root", root, PathUtil.getParent(subpath));
+      TestCase.assertNull("The parent of the root should be null", PathUtil.getParent(root));
+   }
+
 }

Modified: shrinkwrap/trunk/impl-base/src/test/java/org/jboss/shrinkwrap/impl/base/path/PathsTestBase.java
===================================================================
--- shrinkwrap/trunk/impl-base/src/test/java/org/jboss/shrinkwrap/impl/base/path/PathsTestBase.java	2009-12-06 16:40:25 UTC (rev 3835)
+++ shrinkwrap/trunk/impl-base/src/test/java/org/jboss/shrinkwrap/impl/base/path/PathsTestBase.java	2009-12-07 04:07:12 UTC (rev 3836)
@@ -260,11 +260,15 @@
 
       // Create new paths
       final String context = "context";
+      final String contextWithFollowingSlash = context + PathUtil.SLASH;
       final Path path1 = this.createPath(context);
       final Path path2 = this.createPath(context);
+      final Path pathWithFollowingSlash = this.createPath(contextWithFollowingSlash);
 
       // Ensure expected
       Assert.assertEquals("Paths with same context should be equal by value", path1, path2);
+      Assert.assertEquals("Paths with same context (regardless of following slash) should be equal by value", path1,
+            pathWithFollowingSlash);
       log.info(path1 + " equal by value to " + path2);
    }
 

Modified: shrinkwrap/trunk/impl-base/src/test/java/org/jboss/shrinkwrap/impl/base/spec/EnterpriseArchiveImplTestCase.java
===================================================================
--- shrinkwrap/trunk/impl-base/src/test/java/org/jboss/shrinkwrap/impl/base/spec/EnterpriseArchiveImplTestCase.java	2009-12-06 16:40:25 UTC (rev 3835)
+++ shrinkwrap/trunk/impl-base/src/test/java/org/jboss/shrinkwrap/impl/base/spec/EnterpriseArchiveImplTestCase.java	2009-12-07 04:07:12 UTC (rev 3836)
@@ -21,6 +21,7 @@
 import org.jboss.shrinkwrap.api.Archives;
 import org.jboss.shrinkwrap.api.Path;
 import org.jboss.shrinkwrap.api.container.ClassContainer;
+import org.jboss.shrinkwrap.api.container.DirectoryContainer;
 import org.jboss.shrinkwrap.api.container.EnterpriseContainer;
 import org.jboss.shrinkwrap.api.container.LibraryContainer;
 import org.jboss.shrinkwrap.api.container.ManifestContainer;
@@ -120,7 +121,17 @@
       return archive;
    }
 
+   /**
+    * {@inheritDoc}
+    * @see org.jboss.shrinkwrap.impl.base.test.DynamicContainerTestBase#getDirectoryContainer()
+    */
    @Override
+   protected DirectoryContainer<EnterpriseArchive> getDirectoryContainer()
+   {
+      return archive;
+   }
+
+   @Override
    protected Path getManifestPath()
    {
       return PATH_APPLICATION;

Modified: shrinkwrap/trunk/impl-base/src/test/java/org/jboss/shrinkwrap/impl/base/spec/JavaArchiveImplTestCase.java
===================================================================
--- shrinkwrap/trunk/impl-base/src/test/java/org/jboss/shrinkwrap/impl/base/spec/JavaArchiveImplTestCase.java	2009-12-06 16:40:25 UTC (rev 3835)
+++ shrinkwrap/trunk/impl-base/src/test/java/org/jboss/shrinkwrap/impl/base/spec/JavaArchiveImplTestCase.java	2009-12-07 04:07:12 UTC (rev 3836)
@@ -21,6 +21,7 @@
 import org.jboss.shrinkwrap.api.Archives;
 import org.jboss.shrinkwrap.api.Path;
 import org.jboss.shrinkwrap.api.container.ClassContainer;
+import org.jboss.shrinkwrap.api.container.DirectoryContainer;
 import org.jboss.shrinkwrap.api.container.LibraryContainer;
 import org.jboss.shrinkwrap.api.container.ManifestContainer;
 import org.jboss.shrinkwrap.api.container.ResourceContainer;
@@ -98,7 +99,6 @@
    // Required Impls - ContainerTestBase ---------------------------------------------------||
    //-------------------------------------------------------------------------------------||
 
-   
    @Override
    protected ResourceContainer<JavaArchive> getResourceContainer()
    {
@@ -116,14 +116,24 @@
    {
       return getArchive();
    }
-   
+
    @Override
    protected LibraryContainer<JavaArchive> getLibraryContainer()
    {
       throw new UnsupportedOperationException("JavaArchive does not support libraries");
    }
 
+   /**
+    * {@inheritDoc}
+    * @see org.jboss.shrinkwrap.impl.base.test.DynamicContainerTestBase#getDirectoryContainer()
+    */
    @Override
+   protected DirectoryContainer<JavaArchive> getDirectoryContainer()
+   {
+      return archive;
+   }
+
+   @Override
    protected Path getManifestPath()
    {
       return PATH_MANIFEST;

Modified: shrinkwrap/trunk/impl-base/src/test/java/org/jboss/shrinkwrap/impl/base/spec/ResourceAdapterArchiveImplTestCase.java
===================================================================
--- shrinkwrap/trunk/impl-base/src/test/java/org/jboss/shrinkwrap/impl/base/spec/ResourceAdapterArchiveImplTestCase.java	2009-12-06 16:40:25 UTC (rev 3835)
+++ shrinkwrap/trunk/impl-base/src/test/java/org/jboss/shrinkwrap/impl/base/spec/ResourceAdapterArchiveImplTestCase.java	2009-12-07 04:07:12 UTC (rev 3836)
@@ -21,6 +21,7 @@
 import org.jboss.shrinkwrap.api.Archives;
 import org.jboss.shrinkwrap.api.Path;
 import org.jboss.shrinkwrap.api.container.ClassContainer;
+import org.jboss.shrinkwrap.api.container.DirectoryContainer;
 import org.jboss.shrinkwrap.api.container.LibraryContainer;
 import org.jboss.shrinkwrap.api.container.ManifestContainer;
 import org.jboss.shrinkwrap.api.container.ResourceAdapterContainer;
@@ -120,6 +121,16 @@
    {
       return archive;
    }
+   
+   /**
+    * {@inheritDoc}
+    * @see org.jboss.shrinkwrap.impl.base.test.DynamicContainerTestBase#getDirectoryContainer()
+    */
+   @Override
+   protected DirectoryContainer<ResourceAdapterArchive> getDirectoryContainer()
+   {
+      return archive;
+   }
 
    @Override
    protected Path getManifestPath()

Modified: shrinkwrap/trunk/impl-base/src/test/java/org/jboss/shrinkwrap/impl/base/spec/WebArchiveImplTestCase.java
===================================================================
--- shrinkwrap/trunk/impl-base/src/test/java/org/jboss/shrinkwrap/impl/base/spec/WebArchiveImplTestCase.java	2009-12-06 16:40:25 UTC (rev 3835)
+++ shrinkwrap/trunk/impl-base/src/test/java/org/jboss/shrinkwrap/impl/base/spec/WebArchiveImplTestCase.java	2009-12-07 04:07:12 UTC (rev 3836)
@@ -21,6 +21,7 @@
 import org.jboss.shrinkwrap.api.Archives;
 import org.jboss.shrinkwrap.api.Path;
 import org.jboss.shrinkwrap.api.container.ClassContainer;
+import org.jboss.shrinkwrap.api.container.DirectoryContainer;
 import org.jboss.shrinkwrap.api.container.LibraryContainer;
 import org.jboss.shrinkwrap.api.container.ManifestContainer;
 import org.jboss.shrinkwrap.api.container.ResourceContainer;
@@ -127,6 +128,16 @@
    {
       return archive;
    }
+   
+   /**
+    * {@inheritDoc}
+    * @see org.jboss.shrinkwrap.impl.base.test.DynamicContainerTestBase#getDirectoryContainer()
+    */
+   @Override
+   protected DirectoryContainer<WebArchive> getDirectoryContainer()
+   {
+      return archive;
+   }
 
    @Override
    protected Path getManifestPath()

Modified: shrinkwrap/trunk/impl-base/src/test/java/org/jboss/shrinkwrap/impl/base/test/DynamicContainerTestBase.java
===================================================================
--- shrinkwrap/trunk/impl-base/src/test/java/org/jboss/shrinkwrap/impl/base/test/DynamicContainerTestBase.java	2009-12-06 16:40:25 UTC (rev 3835)
+++ shrinkwrap/trunk/impl-base/src/test/java/org/jboss/shrinkwrap/impl/base/test/DynamicContainerTestBase.java	2009-12-07 04:07:12 UTC (rev 3836)
@@ -18,14 +18,18 @@
 
 import java.io.File;
 import java.net.URL;
+import java.util.logging.Logger;
 
 import junit.framework.Assert;
+import junit.framework.TestCase;
 
 import org.jboss.shrinkwrap.api.Archive;
 import org.jboss.shrinkwrap.api.Asset;
 import org.jboss.shrinkwrap.api.Filter;
 import org.jboss.shrinkwrap.api.Path;
+import org.jboss.shrinkwrap.api.Paths;
 import org.jboss.shrinkwrap.api.container.ClassContainer;
+import org.jboss.shrinkwrap.api.container.DirectoryContainer;
 import org.jboss.shrinkwrap.api.container.LibraryContainer;
 import org.jboss.shrinkwrap.api.container.ManifestContainer;
 import org.jboss.shrinkwrap.api.container.ResourceContainer;
@@ -47,6 +51,19 @@
 public abstract class DynamicContainerTestBase<T extends Archive<T>> extends ArchiveTestBase<T>
 {
    
+   //-------------------------------------------------------------------------------------||
+   // Class Members ----------------------------------------------------------------------||
+   //-------------------------------------------------------------------------------------||
+
+   /**
+    * Logger
+    */
+   private static final Logger log = Logger.getLogger(DynamicContainerTestBase.class.getName());
+
+   //-------------------------------------------------------------------------------------||
+   // Contracts ----------------------------------------------------------------------||
+   //-------------------------------------------------------------------------------------||
+   
    protected abstract Path getResourcePath();
    protected abstract ResourceContainer<T> getResourceContainer();
    protected abstract Path getClassPath();
@@ -55,6 +72,7 @@
    protected abstract ManifestContainer<T> getManifestContainer();
    protected abstract Path getLibraryPath();
    protected abstract LibraryContainer<T> getLibraryContainer();
+   protected abstract DirectoryContainer<T> getDirectoryContainer();
    
    protected URL getURLForClassResource(String name) {
       return SecurityActions.getThreadContextClassLoader().getResource(name);
@@ -689,5 +707,37 @@
             getArchive().contains(testPath2));
    }
 
+   /**
+    * Tests that empty directories may be added to the archive
+    * @throws Exception
+    */
+   @Test
+   @ArchiveType(DirectoryContainer.class)
+   public void testAddEmptyDirectories() throws Exception
+   {
 
+      // Get the container
+      final DirectoryContainer<T> container = getDirectoryContainer();
+
+      // Get Paths to add
+      final Path path1 = Paths.create("path/to/dir");
+      final Path path2 = Paths.create("path/to/dir2");
+      final Path path3 = Paths.create("path/to");
+
+      // Add
+      container.addDirectories(path1, path2, path3);
+
+      // Obtain as archive view
+      final Archive<T> archive = this.getArchive();
+
+      // Test
+      final String message = "Should be able to add directory: ";
+      TestCase.assertTrue(message + path1, archive.contains(path1));
+      TestCase.assertTrue(message + path2, archive.contains(path2));
+      TestCase.assertTrue(message + path3, archive.contains(path3));
+
+      // Log out
+      log.info("testAddEmptyDirectories:\n" + archive.toString(true));
+   }
+
 }

Modified: shrinkwrap/trunk/impl-base/src/test/resources/org/jboss/shrinkwrap/impl/base/importer/test.zip
===================================================================
(Binary files differ)



More information about the jboss-svn-commits mailing list