Author: jdcasey
Date: Mon Sep 22 12:16:33 2008
New Revision: 697952

URL: http://svn.apache.org/viewvc?rev=697952&view=rev
Log:
[MSHARED-32] Introduce custom classpath layout; see 
src/site/examples/classpath.apt for more information.

Modified:
    maven/shared/trunk/maven-archiver/pom.xml
    
maven/shared/trunk/maven-archiver/src/main/java/org/apache/maven/archiver/ManifestConfiguration.java
    
maven/shared/trunk/maven-archiver/src/main/java/org/apache/maven/archiver/MavenArchiver.java
    maven/shared/trunk/maven-archiver/src/site/apt/examples/classpath.apt
    
maven/shared/trunk/maven-archiver/src/test/java/org/apache/maven/archiver/MavenArchiverTest.java

Modified: maven/shared/trunk/maven-archiver/pom.xml
URL: 
http://svn.apache.org/viewvc/maven/shared/trunk/maven-archiver/pom.xml?rev=697952&r1=697951&r2=697952&view=diff
==============================================================================
--- maven/shared/trunk/maven-archiver/pom.xml (original)
+++ maven/shared/trunk/maven-archiver/pom.xml Mon Sep 22 12:16:33 2008
@@ -88,6 +88,11 @@
       <version>3.8.2</version>
       <scope>test</scope>
     </dependency>
+    <dependency>
+       <groupId>org.codehaus.plexus</groupId>
+       <artifactId>plexus-interpolation</artifactId>
+       <version>1.5</version>
+    </dependency>
   </dependencies>
   <reporting>
     <plugins>

Modified: 
maven/shared/trunk/maven-archiver/src/main/java/org/apache/maven/archiver/ManifestConfiguration.java
URL: 
http://svn.apache.org/viewvc/maven/shared/trunk/maven-archiver/src/main/java/org/apache/maven/archiver/ManifestConfiguration.java?rev=697952&r1=697951&r2=697952&view=diff
==============================================================================
--- 
maven/shared/trunk/maven-archiver/src/main/java/org/apache/maven/archiver/ManifestConfiguration.java
 (original)
+++ 
maven/shared/trunk/maven-archiver/src/main/java/org/apache/maven/archiver/ManifestConfiguration.java
 Mon Sep 22 12:16:33 2008
@@ -1,5 +1,8 @@
 package org.apache.maven.archiver;
 
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.artifact.handler.ArtifactHandler;
+
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -28,6 +31,12 @@
  */
 public class ManifestConfiguration
 {
+    public static final String CLASSPATH_LAYOUT_TYPE_SIMPLE = "simple";
+
+    public static final String CLASSPATH_LAYOUT_TYPE_REPOSITORY = "repository";
+
+    public static final String CLASSPATH_LAYOUT_TYPE_CUSTOM = "custom";
+
     private String mainClass;
 
     private String packageName;
@@ -60,8 +69,13 @@
      * Maven 2 repository layout:
      * $groupId[0]/../${groupId[n]/$artifactId/$version/{fileName}
      * @since 2.3
+     * @deprecated Use [EMAIL PROTECTED] 
ManifestConfiguration#classpathLayoutType} instead.
      */
     private boolean classpathMavenRepositoryLayout = false;
+    
+    private String classpathLayoutType = CLASSPATH_LAYOUT_TYPE_SIMPLE;
+    
+    private String customClasspathLayout;
 
     public String getMainClass()
     {
@@ -93,6 +107,10 @@
         return addExtensions;
     }
 
+    /**
+     * @deprecated Use [EMAIL PROTECTED] 
ManifestConfiguration#getClasspathLayoutType()}, and compare to
+     * CLASSPATH_LAYOUT_TYPE_SIMPLE or CLASSPATH_LAYOUT_TYPE_REPOSITORY, also 
declared in [EMAIL PROTECTED] ManifestConfiguration}.
+     */
     public boolean isClasspathMavenRepositoryLayout()
     {
         return classpathMavenRepositoryLayout;
@@ -118,6 +136,11 @@
         this.addExtensions = addExtensions;
     }
 
+    /**
+     * @deprecated Use [EMAIL PROTECTED] 
ManifestConfiguration#setClasspathLayoutType(String)}, and use
+     * CLASSPATH_LAYOUT_TYPE_SIMPLE, CLASSPATH_LAYOUT_TYPE_CUSTOM, or 
CLASSPATH_LAYOUT_TYPE_REPOSITORY, 
+     * also declared in [EMAIL PROTECTED] ManifestConfiguration}.
+     */
     public void setClasspathMavenRepositoryLayout( boolean 
classpathMavenRepositoryLayout )
     {
         this.classpathMavenRepositoryLayout = classpathMavenRepositoryLayout;
@@ -149,4 +172,64 @@
 
         return cpp;
     }
+
+    /**
+     * Return the type of layout to use when formatting classpath entries.
+     * Default is taken from the constant CLASSPATH_LAYOUT_TYPE_SIMPLE, 
declared 
+     * in this class, which has a value of 'simple'. Other values are: 
'repository'
+     * (CLASSPATH_LAYOUT_TYPE_REPOSITORY, or the same as a maven classpath 
layout),
+     * and 'custom' (CLASSPATH_LAYOUT_TYPE_CUSTOM).
+     * <br/>
+     * <b>NOTE:</b> If you specify a type of 'custom' you MUST set [EMAIL 
PROTECTED] ManifestConfiguration#setCustomClasspathLayout(String)}.
+     */
+    public String getClasspathLayoutType()
+    {
+        return CLASSPATH_LAYOUT_TYPE_SIMPLE.equals( classpathLayoutType ) && 
classpathMavenRepositoryLayout ? CLASSPATH_LAYOUT_TYPE_REPOSITORY
+                        : classpathLayoutType;
+    }
+
+    /**
+     * Set the type of layout to use when formatting classpath entries.
+     * Should be one of: 'simple' (CLASSPATH_LAYOUT_TYPE_SIMPLE), 'repository'
+     * (CLASSPATH_LAYOUT_TYPE_REPOSITORY, or the same as a maven classpath 
layout),
+     * and 'custom' (CLASSPATH_LAYOUT_TYPE_CUSTOM). The constant names noted 
here
+     * are defined in the [EMAIL PROTECTED] ManifestConfiguration} class.
+     * <br/>
+     * <b>NOTE:</b> If you specify a type of 'custom' you MUST set [EMAIL 
PROTECTED] ManifestConfiguration#setCustomClasspathLayout(String)}.
+     */
+    public void setClasspathLayoutType( String classpathLayoutType )
+    {
+        this.classpathLayoutType = classpathLayoutType;
+    }
+
+    /**
+     * Retrieve the layout expression for use when the layout type set in 
[EMAIL PROTECTED] ManifestConfiguration#setClasspathLayoutType(String)}
+     * has the value 'custom'. <b>The default value is null.</b>
+     * Expressions will be evaluated against the following ordered list of 
classpath-related objects:
+     * <ol>
+     *   <li>The current [EMAIL PROTECTED] Artifact} instance, if one 
exists.</li>
+     *   <li>The current [EMAIL PROTECTED] ArtifactHandler} instance from the 
artifact above.</li>
+     * </ol>
+     * <br/>
+     * <b>NOTE:</b> If you specify a layout type of 'custom' you MUST set this 
layout expression.
+     */
+    public String getCustomClasspathLayout()
+    {
+        return customClasspathLayout;
+    }
+
+    /**
+     * Set the layout expression for use when the layout type set in [EMAIL 
PROTECTED] ManifestConfiguration#setClasspathLayoutType(String)}
+     * has the value 'custom'. Expressions will be evaluated against the 
following ordered list of classpath-related objects:
+     * <ol>
+     *   <li>The current [EMAIL PROTECTED] Artifact} instance, if one 
exists.</li>
+     *   <li>The current [EMAIL PROTECTED] ArtifactHandler} instance from the 
artifact above.</li>
+     * </ol>
+     * <br/>
+     * <b>NOTE:</b> If you specify a layout type of 'custom' you MUST set this 
layout expression.
+     */
+    public void setCustomClasspathLayout( String customClasspathLayout )
+    {
+        this.customClasspathLayout = customClasspathLayout;
+    }
 }

Modified: 
maven/shared/trunk/maven-archiver/src/main/java/org/apache/maven/archiver/MavenArchiver.java
URL: 
http://svn.apache.org/viewvc/maven/shared/trunk/maven-archiver/src/main/java/org/apache/maven/archiver/MavenArchiver.java?rev=697952&r1=697951&r2=697952&view=diff
==============================================================================
--- 
maven/shared/trunk/maven-archiver/src/main/java/org/apache/maven/archiver/MavenArchiver.java
 (original)
+++ 
maven/shared/trunk/maven-archiver/src/main/java/org/apache/maven/archiver/MavenArchiver.java
 Mon Sep 22 12:16:33 2008
@@ -26,14 +26,25 @@
 import org.codehaus.plexus.archiver.jar.JarArchiver;
 import org.codehaus.plexus.archiver.jar.Manifest;
 import org.codehaus.plexus.archiver.jar.ManifestException;
+import org.codehaus.plexus.interpolation.InterpolationException;
+import org.codehaus.plexus.interpolation.Interpolator;
+import org.codehaus.plexus.interpolation.PrefixAwareRecursionInterceptor;
+import org.codehaus.plexus.interpolation.PrefixedObjectValueSource;
+import org.codehaus.plexus.interpolation.PrefixedPropertiesValueSource;
+import org.codehaus.plexus.interpolation.PrefixedValueSourceWrapper;
+import org.codehaus.plexus.interpolation.RecursionInterceptor;
+import org.codehaus.plexus.interpolation.StringSearchInterpolator;
+import org.codehaus.plexus.interpolation.ValueSource;
 import org.codehaus.plexus.util.StringUtils;
 
 import java.io.File;
 import java.io.IOException;
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.Properties;
 import java.util.Set;
 
 /**
@@ -42,6 +53,16 @@
  */
 public class MavenArchiver
 {
+    private static final List ARTIFACT_EXPRESSION_PREFIXES;
+    
+    static
+    {
+        List artifactExpressionPrefixes = new ArrayList();
+        artifactExpressionPrefixes.add( "artifact." );
+        
+        ARTIFACT_EXPRESSION_PREFIXES = artifactExpressionPrefixes;
+    }
+
     private JarArchiver archiver;
 
     private File archiveFile;
@@ -166,26 +187,34 @@
             
             List artifacts = project.getRuntimeClasspathElements();
             String classpathPrefix = config.getClasspathPrefix();
+            String layoutType = config.getClasspathLayoutType();
+            String layout = config.getCustomClasspathLayout();
+            
+            Interpolator interpolator = new StringSearchInterpolator();
 
             for ( Iterator iter = artifacts.iterator(); iter.hasNext(); )
             {
                 File f = new File( (String) iter.next() );
-                if ( f.isFile() )
+                if ( f.getAbsoluteFile().isFile() )
                 {
+                    Artifact artifact = findArtifactWithFile( 
project.getArtifacts(), f );
+                    
                     if ( classpath.length() > 0 )
                     {
                         classpath.append( " " );
                     }
                     classpath.append( classpathPrefix );
-                    if ( !config.isClasspathMavenRepositoryLayout() )
+                    
+                    // NOTE: If the artifact or layout type (from config) is 
null, give up and use the file name by itself.
+                    if ( artifact == null || layoutType == null
+                        || 
ManifestConfiguration.CLASSPATH_LAYOUT_TYPE_SIMPLE.equals( layoutType ) )
                     {
                         classpath.append( f.getName() );
                     }
-                    else
+                    else if ( 
ManifestConfiguration.CLASSPATH_LAYOUT_TYPE_REPOSITORY.equals( layoutType ) )
                     {
                         // we use layout 
/$groupId[0]/../${groupId[n]/$artifactId/$version/{fileName}
                         // here we must find the Artifact in the project 
Artifacts to generate the maven layout
-                        Artifact artifact = findArtifactWithFile( 
project.getArtifacts(), f );
                         StringBuffer classpathElement = new StringBuffer();
                         if ( !StringUtils.isEmpty( artifact.getGroupId() ) )
                         {
@@ -196,13 +225,77 @@
                         classpathElement.append( f.getName() );
                         classpath.append( classpathElement );
                     }
+                    else if ( 
ManifestConfiguration.CLASSPATH_LAYOUT_TYPE_CUSTOM.equals( layoutType ) )
+                    {
+                        if ( layout == null )
+                        {
+                            throw new ManifestException(
+                                                         
ManifestConfiguration.CLASSPATH_LAYOUT_TYPE_CUSTOM
+                                                             + " layout type 
was declared, but custom layout expression was not specified. Check your 
<archive><manifest><customLayout/> element." );
+                        }
+                        
+                        // FIXME: This query method SHOULD NOT affect the 
internal
+                        // state of the artifact version, but it does.
+                        artifact.isSnapshot();
+                        
+                        List valueSources = new ArrayList();
+                        valueSources.add( new PrefixedObjectValueSource( 
ARTIFACT_EXPRESSION_PREFIXES, artifact, true ) );
+                        valueSources.add( new PrefixedObjectValueSource( 
ARTIFACT_EXPRESSION_PREFIXES, artifact == null ? null : 
artifact.getArtifactHandler(), true ) );
+                        
+                        Properties extraExpressions = new Properties();
+                        if ( artifact != null )
+                        {
+                            extraExpressions.setProperty( "groupIdPath", 
artifact.getGroupId().replace( '.', '/' ) );
+                            if ( artifact.getClassifier() != null )
+                            {
+                                extraExpressions.setProperty( 
"dashClassifier", "-" + artifact.getClassifier() );
+                                extraExpressions.setProperty( 
"dashClassifier?", "-" + artifact.getClassifier() );
+                            }
+                            else
+                            {
+                                extraExpressions.setProperty( 
"dashClassifier", "" );
+                                extraExpressions.setProperty( 
"dashClassifier?", "" );
+                            }
+                        }
+                        valueSources.add( new PrefixedPropertiesValueSource( 
ARTIFACT_EXPRESSION_PREFIXES, extraExpressions, true ) );
+                        
+                        for ( Iterator it = valueSources.iterator(); 
it.hasNext(); )
+                        {
+                            ValueSource vs = (ValueSource) it.next();
+                            interpolator.addValueSource( vs );
+                        }
+                        
+                        RecursionInterceptor recursionInterceptor = new 
PrefixAwareRecursionInterceptor( ARTIFACT_EXPRESSION_PREFIXES );
+                        try
+                        {
+                            classpath.append( interpolator.interpolate( 
layout, recursionInterceptor ) );
+                        }
+                        catch ( InterpolationException e )
+                        {
+                            ManifestException error =
+                                new ManifestException( "Error interpolating 
artifact path for classpath entry: "
+                                    + e.getMessage() );
+                            
+                            error.initCause( e );
+                            throw error;
+                        }
+                        finally
+                        {
+                            for ( Iterator it = valueSources.iterator(); 
it.hasNext(); )
+                            {
+                                ValueSource vs = (ValueSource) it.next();
+                                interpolator.removeValuesSource( vs );
+                            }
+                        }
+                    }
+                    else
+                    {
+                        throw new ManifestException( "Unknown classpath layout 
type: '" + layoutType
+                            + "'. Check your <archive><manifest><layoutType/> 
element." );
+                    }
                 }
-
             }
 
-            
-            
-            
             if ( classpath.length() > 0 )
             {
                 // Class-Path is special and should be added to manifest even 
if

Modified: maven/shared/trunk/maven-archiver/src/site/apt/examples/classpath.apt
URL: 
http://svn.apache.org/viewvc/maven/shared/trunk/maven-archiver/src/site/apt/examples/classpath.apt?rev=697952&r1=697951&r2=697952&view=diff
==============================================================================
--- maven/shared/trunk/maven-archiver/src/site/apt/examples/classpath.apt 
(original)
+++ maven/shared/trunk/maven-archiver/src/site/apt/examples/classpath.apt Mon 
Sep 22 12:16:33 2008
@@ -139,7 +139,7 @@
 +-----+
 
 
-* Altering The Classpath
+* Altering The Classpath: Defining a Classpath Directory Prefix
 
  Sometimes it is useful to be able to alter the classpath, for example when
  
{{{http://maven.apache.org/plugins/maven-war-plugin/examples/skinny-wars.html}creating
 skinny war-files}}.
@@ -180,13 +180,166 @@
 </project>
 +-----+
 
- The manifest produced using the above configuration would look like this:
+ The manifest classpath produced using the above configuration would look like 
this:
 
 +-----+
-Manifest-Version: 1.0
-Archiver-Version: Plexus Archiver
-Created-By: Apache Maven
-Built-By: ${user.name}
-Build-Jdk: ${java.version}
 Class-Path: lib/plexus-utils-1.1.jar lib/commons-lang-2.1.jar
 +-----+
+
+* Altering The Classpath: Using a Maven Repository-Style Classpath
+
+  <(Since: 2.3, see below)>
+
+  Occasionally, you may want to include a Maven repository-style directory 
structure in your
+  archive. If you wish to reference the dependency archives within those 
directories in your
+  manifest classpath, try using the <<<\<classpathLayoutType\>>>> element with 
a value of 
+  <<<'repository'>>>, like this:
+
++-----+
+<project>
+  ...
+  <build>
+    <plugins>
+      <plugin>
+         <artifactId>maven-jar-plugin</artifactId>
+         <configuration>
+           <archive>
+             <manifest>
+               <addClasspath>true</addClasspath>
+               <classpathPrefix>lib/</classpathPrefix>
+               <classpathLayoutType>repository</classpathLayoutType>
+               
+               <!-- NOTE: Deprecated in version 2.4. Use 'classpathLayoutType' 
instead.
+               
<classpathMavenRepositoryLayout>true</classpathMavenRepositoryLayout>
+               -->
+             </manifest>
+           </archive>
+         </configuration>
+      </plugin>
+    </plugins>
+  </build>
+  ...
+  <dependencies>
+    <dependency>
+      <groupId>commons-lang</groupId>
+      <artifactId>commons-lang</artifactId>
+      <version>2.1</version>
+    </dependency>
+    <dependency>
+      <groupId>org.codehaus.plexus</groupId>
+      <artifactId>plexus-utils</artifactId>
+      <version>1.1</version>
+    </dependency>
+  </dependencies>
+  ...
+</project>
++-----+
+
+  <<NOTE:>> In version 2.3, this feature was available by setting the 
<<<\<classpathMavenRepositoryLayout\>>>>
+  element to the value <<<true>>>. This configuration option has been 
*deprecated* in version 2.4, 
+  in favor of the more general <<<\<classpathLayoutType\>>>> element, where a 
value of <<<'repository'>>>
+  will render the same behavior.
+
+ The manifest classpath produced using the above configuration would look like 
this:
+
++-----+
+Class-Path: lib/org/codehaus/plexus/plexus-utils/1.1/plexus-utils-1.1.jar 
lib/commons-lang/commons-lang/2.1/commons-lang-2.1.jar
++-----+
+
+* Altering The Classpath: Using a Custom Classpath Format
+
+  <(Since: 2.4)>
+
+  At times, you may have dependency archives in a custom format within your 
own archive, one that doesn't
+  conform to any of the above classpath layouts. If you wish to define a 
custom layout for dependency archives
+  within your archive's manifest classpath, try using the 
<<<\<classpathLayoutType\>>>> element with a value of 
+  <<<'custom'>>>, along with the <<<\<customClasspathLayout\>>>> element, like 
this:
+
++-----+
+<project>
+  ...
+  <build>
+    <plugins>
+      <plugin>
+         <artifactId>maven-war-plugin</artifactId>
+         <configuration>
+           <archive>
+             <manifest>
+               <addClasspath>true</addClasspath>
+               <classpathLayoutType>custom</classpathLayoutType>
+               
<customClasspathLayout>WEB-INF/lib/${artifact.groupIdPath}/${artifact.artifactId}-${artifact.version}${dashClassifier?}.${artifact.extension}</customClasspathLayout>
+             </manifest>
+           </archive>
+         </configuration>
+      </plugin>
+    </plugins>
+  </build>
+  ...
+  <dependencies>
+    <dependency>
+      <groupId>commons-lang</groupId>
+      <artifactId>commons-lang</artifactId>
+      <version>2.1</version>
+    </dependency>
+    <dependency>
+      <groupId>org.codehaus.plexus</groupId>
+      <artifactId>plexus-utils</artifactId>
+      <version>1.1</version>
+    </dependency>
+  </dependencies>
+  ...
+</project>
++-----+
+
+  This classpath layout is a little more involved than the previous examples. 
+  To understand how the value of the <<<\<customClasspathLayout\>>>> 
configuration
+  is interpreted, it's useful to understand the rules applied when resolving 
+  expressions within the value:
+  
+  [[1]] If present, trim off the prefix 'artifact.' from the expression.
+  
+  [[2]] Attempt to resolve the expression as a reference to the Artifact using 
+        reflection (eg. <<<'artifactId'>>> becomes a reference to the method 
+        <<<'getArtifactId()'>>>).
+  
+  [[3]] Attempt to resolve the expression as a reference to the 
ArtifactHandler of 
+        the current Artifact, again using reflection (eg. <<<'extension'>>> 
becomes a reference
+        to the method <<<'getExtension()'>>>).
+        
+  [[4]] Attempt to resolve the expression as a key in the special-case 
Properties instance, 
+        which contains the following mappings:
+        
+        * <<<'dashClassifier'>>>: If the Artifact has a classifier, this will 
be 
+                                  <<<'-${artifact.classifier}'>>>, otherwise 
this 
+                                  is an empty string.
+        
+        * <<<'dashClassifier?'>>>: This is a synonym of <<<'dashClassifier'>>>.
+        
+        * <<<'groupIdPath'>>>: This is the equivalent of 
<<<'${artifact.groupId}'>>>, 
+                               with all <<<'.'>>> characters replaced by 
<<<'/'>>>.
+                               
+        []
+        
+  []
+
+ The manifest classpath produced using the above configuration would look like 
this:
+
++-----+
+Class-Path: WEB-INF/lib/org/codehaus/plexus/plexus-utils-1.1.jar 
WEB-INF/lib/commons-lang/commons-lang-2.1.jar
++-----+
+
+** Forcing the use of -SNAPSHOT in classpath archive versions
+
+  Depending on how you construct your archive, you may have the ability to 
specify whether 
+  snapshot dependency archives are included with the version suffix 
<<<'-SNAPSHOT'>>>, or
+  whether the unique timestamp and build-number for that archive is used. For 
instance,
+  the {{{http://maven.apache.org/plugins/maven-assembly-plugin}Assembly 
Plugin}} allows
+  you to make this decision in the <<<\<outputFileNameMapping\>>>> element of 
its 
+  <<<\<dependencySet>>>> descriptor section.
+    
+  To force the use of <<<'-SNAPSHOT'>>> version naming, simply replace 
<<<'${artifact.version}'>>>
+  with <<<'${artifact.baseVersion}'>>> in the example above, so it looks like 
this:
+  
++-----+
+<customClasspathLayout>WEB-INF/lib/${artifact.groupIdPath}/${artifact.artifactId}-${artifact.baseVersion}${dashClassifier?}.${artifact.extension}</customClasspathLayout>
++-----+

Modified: 
maven/shared/trunk/maven-archiver/src/test/java/org/apache/maven/archiver/MavenArchiverTest.java
URL: 
http://svn.apache.org/viewvc/maven/shared/trunk/maven-archiver/src/test/java/org/apache/maven/archiver/MavenArchiverTest.java?rev=697952&r1=697951&r2=697952&view=diff
==============================================================================
--- 
maven/shared/trunk/maven-archiver/src/test/java/org/apache/maven/archiver/MavenArchiverTest.java
 (original)
+++ 
maven/shared/trunk/maven-archiver/src/test/java/org/apache/maven/archiver/MavenArchiverTest.java
 Mon Sep 22 12:16:33 2008
@@ -20,6 +20,8 @@
  */
 
 import java.io.File;
+import java.net.URI;
+import java.net.URL;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Comparator;
@@ -188,8 +190,8 @@
             Manifest manifest = archiver.getManifest( project, 
archiveConfiguration );
             String classPath = manifest.getMainSection().getAttribute( 
"Class-Path" ).getValue();
             assertTrue( "User specified Class-Path entry was not added to 
manifest", classPath.indexOf( "help/" ) != -1 );
-            assertTrue( "Class-Path generated by addClasspath was not added to 
manifest", classPath.indexOf( tempFile
-                .getName() ) != -1 );
+            assertTrue( "Class-Path generated by addClasspath was not added to 
manifest",
+                        classPath.indexOf( tempFile.getName() ) != -1 );
         }
         finally
         {
@@ -236,7 +238,7 @@
         archiver.createArchive( project, config );
         assertTrue( jarFile.lastModified() > time );
     }
-    
+
     public void testNotGenerateImplementationVersionForMANIFESTMF()
         throws Exception
     {
@@ -274,7 +276,7 @@
             }
         }
     }
-    
+
     public void testGenerateImplementationVersionForMANIFESTMF()
         throws Exception
     {
@@ -316,8 +318,8 @@
                 jar.close();
             }
         }
-    }    
-    
+    }
+
     public void testCarriageReturnInManifestEntry()
         throws Exception
     {
@@ -341,7 +343,8 @@
             config.setForced( true );
             config.getManifest().setAddDefaultImplementationEntries( true );
             config.addManifestEntry( "Description", project.getDescription() );
-            //config.addManifestEntry( "EntryWithTab", " foo tab " + ( 
'\u0009' ) + ( '\u0009' ) + " bar tab" + ( '\u0009' ) );
+            // config.addManifestEntry( "EntryWithTab", " foo tab " + ( 
'\u0009' ) + ( '\u0009' ) + " bar tab" + (
+            // '\u0009' ) );
             archiver.createArchive( project, config );
             assertTrue( jarFile.exists() );
 
@@ -362,8 +365,8 @@
                 jar.close();
             }
         }
-    }     
-    
+    }
+
     public void testManifestEntries()
         throws Exception
     {
@@ -385,13 +388,13 @@
             config.setForced( true );
             config.getManifest().setAddDefaultImplementationEntries( true );
             config.getManifest().setAddDefaultSpecificationEntries( true );
-            
+
             Map manifestEntries = new HashMap();
             manifestEntries.put( "foo", "bar" );
             manifestEntries.put( "first-name", "olivier" );
             manifestEntries.put( "keyWithEmptyValue", null );
             config.setManifestEntries( manifestEntries );
-            
+
             ManifestSection manifestSection = new ManifestSection();
             manifestSection.setName( "UserSection" );
             manifestSection.addManifestEntry( "key", "value" );
@@ -406,31 +409,35 @@
             Attributes manifest = jar.getManifest().getMainAttributes();
 
             assertEquals( "Apache Maven", manifest.get( new Attributes.Name( 
"Created-By" ) ) );
-            assertEquals( "archiver test", manifest.get( 
Attributes.Name.SPECIFICATION_TITLE ));// "Specification-Title" ) );
-            assertEquals( "0.1", manifest.get( 
Attributes.Name.SPECIFICATION_VERSION ));// "Specification-Version" ) );
-            assertEquals( "Apache", manifest.get( 
Attributes.Name.SPECIFICATION_VENDOR ));// "Specification-Vendor" ) );
-
-            assertEquals( "archiver test", manifest.get( 
Attributes.Name.IMPLEMENTATION_TITLE ));// "Implementation-Title" ) );
-            assertEquals( "0.1", manifest.get( 
Attributes.Name.IMPLEMENTATION_VERSION ));// "Implementation-Version" ) );
-            assertEquals( "org.apache.dummy", manifest.get( 
Attributes.Name.IMPLEMENTATION_VENDOR_ID ));// "Implementation-Vendor-Id" ) );
-            assertEquals( "Apache", manifest.get( 
Attributes.Name.IMPLEMENTATION_VENDOR ));// "Implementation-Vendor" ) );
-            assertEquals( "org.apache.maven.Foo", manifest.get( 
Attributes.Name.MAIN_CLASS ));// "Main-Class" ) );
+            assertEquals( "archiver test", manifest.get( 
Attributes.Name.SPECIFICATION_TITLE ) );// "Specification-Title"
+                                                                               
                  // ) );
+            assertEquals( "0.1", manifest.get( 
Attributes.Name.SPECIFICATION_VERSION ) );// "Specification-Version" ) );
+            assertEquals( "Apache", manifest.get( 
Attributes.Name.SPECIFICATION_VENDOR ) );// "Specification-Vendor" )
+                                                                               
            // );
+
+            assertEquals( "archiver test", manifest.get( 
Attributes.Name.IMPLEMENTATION_TITLE ) );// "Implementation-Title"
+                                                                               
                   // ) );
+            assertEquals( "0.1", manifest.get( 
Attributes.Name.IMPLEMENTATION_VERSION ) );// "Implementation-Version" )
+                                                                               
           // );
+            assertEquals( "org.apache.dummy", manifest.get( 
Attributes.Name.IMPLEMENTATION_VENDOR_ID ) );// "Implementation-Vendor-Id"
+                                                                               
                          // ) );
+            assertEquals( "Apache", manifest.get( 
Attributes.Name.IMPLEMENTATION_VENDOR ) );// "Implementation-Vendor" )
+                                                                               
             // );
+            assertEquals( "org.apache.maven.Foo", manifest.get( 
Attributes.Name.MAIN_CLASS ) );// "Main-Class" ) );
 
             assertEquals( "bar", manifest.get( new Attributes.Name( "foo" ) ) 
);
             assertEquals( "olivier", manifest.get( new Attributes.Name( 
"first-name" ) ) );
 
-            
-            assertEquals( System.getProperty( "java.version"), manifest.get( 
new Attributes.Name( "Build-Jdk" ) ) );
-            assertEquals( System.getProperty( "user.name"), manifest.get( new 
Attributes.Name( "Built-By" ) ) );            
-            
+            assertEquals( System.getProperty( "java.version" ), manifest.get( 
new Attributes.Name( "Build-Jdk" ) ) );
+            assertEquals( System.getProperty( "user.name" ), manifest.get( new 
Attributes.Name( "Built-By" ) ) );
+
             assertTrue( StringUtils.isEmpty( manifest.getValue( new 
Attributes.Name( "keyWithEmptyValue" ) ) ) );
             assertTrue( manifest.containsKey( new Attributes.Name( 
"keyWithEmptyValue" ) ) );
-            
-            
+
             manifest = jar.getManifest().getAttributes( "UserSection" );
-            
+
             assertEquals( "value", manifest.get( new Attributes.Name( "key" ) 
) );
-                 
+
         }
         finally
         {
@@ -463,7 +470,7 @@
         Manifest manifest = archiver.getManifest( project, config );
 
         Manifest.Section section = manifest.getSection( "SectionOne" );
-        assertNotNull( "The section is not present in the manifest as it 
should be.",  section );
+        assertNotNull( "The section is not present in the manifest as it 
should be.", section );
 
         Manifest.Attribute attribute = section.getAttribute( "key" );
         assertNotNull( "The attribute we are looking for is not present in the 
section.", attribute );
@@ -496,13 +503,13 @@
             archiver.createArchive( project, config );
             assertTrue( jarFile.exists() );
             jar = new JarFile( jarFile );
-            
+
             String classPath = jar.getManifest().getMainAttributes().getValue( 
Attributes.Name.CLASS_PATH );
             assertNotNull( classPath );
             String[] classPathEntries = StringUtils.split( classPath, " " );
-            assertEquals("dummy1-1.0.jar", classPathEntries[0]);
-            assertEquals("dummy2-1.5.jar", classPathEntries[1]);
-            assertEquals("dummy3-2.0.jar", classPathEntries[2]);
+            assertEquals( "dummy1-1.0.jar", classPathEntries[0] );
+            assertEquals( "dummy2-1.5.jar", classPathEntries[1] );
+            assertEquals( "dummy3-2.0.jar", classPathEntries[2] );
         }
         finally
         {
@@ -513,7 +520,7 @@
             }
         }
     }
-    
+
     public void testMavenRepoClassPathValue()
         throws Exception
     {
@@ -537,19 +544,20 @@
             config.getManifest().setAddDefaultSpecificationEntries( true );
             config.getManifest().setMainClass( "org.apache.maven.Foo" );
             config.getManifest().setAddClasspath( true );
-            config.getManifest().setClasspathMavenRepositoryLayout( true );
+            config.getManifest().setClasspathLayoutType( 
ManifestConfiguration.CLASSPATH_LAYOUT_TYPE_REPOSITORY );
             archiver.createArchive( project, config );
             assertTrue( jarFile.exists() );
             jar = new JarFile( jarFile );
 
             Manifest manifest = archiver.getManifest( project, config );
-            String[] classPathEntries = StringUtils.split( new String( 
manifest.getMainSection()
-                .getAttributeValue( "Class-Path" ).getBytes() ), " " );
+            String[] classPathEntries =
+                StringUtils.split(
+                                   new String( 
manifest.getMainSection().getAttributeValue( "Class-Path" ).getBytes() ),
+                                   " " );
             assertEquals( "org/apache/dummy/dummy1/1.0/dummy1-1.0.jar", 
classPathEntries[0] );
             assertEquals( "org/apache/dummy/foo/dummy2/1.5/dummy2-1.5.jar", 
classPathEntries[1] );
             assertEquals( "org/apache/dummy/bar/dummy3/2.0/dummy3-2.0.jar", 
classPathEntries[2] );
 
-            
             String classPath = jar.getManifest().getMainAttributes().getValue( 
Attributes.Name.CLASS_PATH );
             assertNotNull( classPath );
             classPathEntries = StringUtils.split( classPath, " " );
@@ -567,11 +575,67 @@
             }
         }
     }
-    
+
+    public void testCustomClassPathValue()
+        throws Exception
+    {
+        MavenProject project = getDummyProject();
+        JarFile jar = null;
+        try
+        {
+            File jarFile = new File( "target/test/dummy.jar" );
+            jarFile.delete();
+            assertFalse( jarFile.exists() );
+            JarArchiver jarArchiver = new JarArchiver();
+            jarArchiver.setDestFile( jarFile );
+
+            MavenArchiver archiver = new MavenArchiver();
+            archiver.setArchiver( jarArchiver );
+            archiver.setOutputFile( jarArchiver.getDestFile() );
+
+            MavenArchiveConfiguration config = new MavenArchiveConfiguration();
+            config.setForced( true );
+            config.getManifest().setAddDefaultImplementationEntries( true );
+            config.getManifest().setAddDefaultSpecificationEntries( true );
+            config.getManifest().setMainClass( "org.apache.maven.Foo" );
+            config.getManifest().setAddClasspath( true );
+            config.getManifest().setClasspathLayoutType( 
ManifestConfiguration.CLASSPATH_LAYOUT_TYPE_CUSTOM );
+            config.getManifest().setCustomClasspathLayout( 
"${artifact.groupIdPath}/${artifact.artifactId}/${artifact.version}/TEST-${artifact.artifactId}-${artifact.version}${dashClassifier?}.${artifact.extension}"
 );
+            archiver.createArchive( project, config );
+            assertTrue( jarFile.exists() );
+            jar = new JarFile( jarFile );
+
+            Manifest manifest = archiver.getManifest( project, config );
+            String[] classPathEntries =
+                StringUtils.split(
+                                   new String( 
manifest.getMainSection().getAttributeValue( "Class-Path" ).getBytes() ),
+                                   " " );
+            assertEquals( "org/apache/dummy/dummy1/1.0/TEST-dummy1-1.0.jar", 
classPathEntries[0] );
+            assertEquals( 
"org/apache/dummy/foo/dummy2/1.5/TEST-dummy2-1.5.jar", classPathEntries[1] );
+            assertEquals( 
"org/apache/dummy/bar/dummy3/2.0/TEST-dummy3-2.0.jar", classPathEntries[2] );
+
+            String classPath = jar.getManifest().getMainAttributes().getValue( 
Attributes.Name.CLASS_PATH );
+            assertNotNull( classPath );
+            classPathEntries = StringUtils.split( classPath, " " );
+            assertEquals( "org/apache/dummy/dummy1/1.0/TEST-dummy1-1.0.jar", 
classPathEntries[0] );
+            assertEquals( 
"org/apache/dummy/foo/dummy2/1.5/TEST-dummy2-1.5.jar", classPathEntries[1] );
+            assertEquals( 
"org/apache/dummy/bar/dummy3/2.0/TEST-dummy3-2.0.jar", classPathEntries[2] );
+
+        }
+        finally
+        {
+            // cleanup streams
+            if ( jar != null )
+            {
+                jar.close();
+            }
+        }
+    }
+
     // ----------------------------------------
-    //  common methods for testing
+    // common methods for testing
     // ----------------------------------------
-        
+
     private MavenProject getDummyProject()
     {
         Model model = new Model();
@@ -585,7 +649,7 @@
         project.setExtensionArtifacts( Collections.EMPTY_SET );
         project.setRemoteArtifactRepositories( Collections.EMPTY_LIST );
         project.setPluginArtifactRepositories( Collections.EMPTY_LIST );
-        
+
         File pomFile = new File( "src/test/resources/pom.xml" );
         pomFile.setLastModified( System.currentTimeMillis() - 60000L );
         project.setFile( pomFile );
@@ -603,8 +667,6 @@
         artifact.setVersion( "0.1" );
         artifact.setType( "jar" );
         project.setArtifact( artifact );
-        
-        
 
         ArtifactHandler artifactHandler = new ArtifactHandler()
         {
@@ -621,7 +683,7 @@
 
             public String getExtension()
             {
-                return null;
+                return "jar";
             }
 
             public String getLanguage()
@@ -643,24 +705,23 @@
             {
                 return false;
             }
-            
+
         };
-        
-        
+
         Set artifacts = new TreeSet( new ArtifactComparator() );
-        
+
         MockArtifact artifact1 = new MockArtifact();
         artifact1.setGroupId( "org.apache.dummy" );
         artifact1.setArtifactId( "dummy1" );
         artifact1.setVersion( "1.0" );
         artifact1.setType( "jar" );
-        artifact1.setScope( "runtime" );        
-        artifact1.setFile( new File( "target/test-classes", 
artifact1.getArtifactId() + "-" + artifact1.getVersion() + ".jar" ) );
-        
-        artifact1.setArtifactHandler( artifactHandler);
+        artifact1.setScope( "runtime" );
+        artifact1.setFile( getClasspathFile( artifact1.getArtifactId() + "-" + 
artifact1.getVersion()
+            + ".jar" ) );
 
-        artifacts.add( artifact1 );
+        artifact1.setArtifactHandler( artifactHandler );
 
+        artifacts.add( artifact1 );
 
         MockArtifact artifact2 = new MockArtifact();
         artifact2.setGroupId( "org.apache.dummy.foo" );
@@ -668,24 +729,39 @@
         artifact2.setVersion( "1.5" );
         artifact2.setType( "jar" );
         artifact2.setScope( "runtime" );
-        artifact2.setFile( new File( "target/test-classes", 
artifact2.getArtifactId() + "-" + artifact2.getVersion() + ".jar" ) );
-        
-        artifact2.setArtifactHandler( artifactHandler);
-        artifacts.add( artifact2 );
+        artifact2.setFile( getClasspathFile( artifact2.getArtifactId() + "-" + 
artifact2.getVersion()
+            + ".jar" ) );
 
+        artifact2.setArtifactHandler( artifactHandler );
+        artifacts.add( artifact2 );
 
         MockArtifact artifact3 = new MockArtifact();
         artifact3.setGroupId( "org.apache.dummy.bar" );
         artifact3.setArtifactId( "dummy3" );
         artifact3.setVersion( "2.0" );
         artifact3.setScope( "runtime" );
-        artifact3.setType( "jar" );        
-        artifact3.setFile( new File( "target/test-classes", 
artifact3.getArtifactId() + "-" + artifact3.getVersion() + ".jar" ) );
-        artifact3.setArtifactHandler( artifactHandler);
+        artifact3.setType( "jar" );
+        artifact3.setFile( getClasspathFile( artifact3.getArtifactId() + "-" + 
artifact3.getVersion()
+            + ".jar" ) );
+        artifact3.setArtifactHandler( artifactHandler );
         artifacts.add( artifact3 );
-        
+
         project.setArtifacts( artifacts );
-        
+
         return project;
     }
+
+    private File getClasspathFile( String file )
+    {
+        URL resource = 
Thread.currentThread().getContextClassLoader().getResource( file );
+        if ( resource == null )
+        {
+            fail( "Cannot retrieve java.net.URL for file: " + file + " on the 
current test classpath." );
+        }
+        
+        URI uri = new File( resource.getPath() ).toURI().normalize();
+        File result = new File( uri.getPath().replaceAll( "%20", " " ) );
+        
+        return result;
+    }
 }


Reply via email to