[SUREFIRE-1588] Surefire manifest jar classloading broken on latest Debian/Ubuntu Java8
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/AbstractSurefireMojo.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/AbstractSurefireMojo.java
index 1cce687..3a1a64a 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/AbstractSurefireMojo.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/AbstractSurefireMojo.java
@@ -2173,7 +2173,8 @@
                     getEffectiveForkCount(),
                     reuseForks,
                     platform,
-                    getConsoleLogger() );
+                    getConsoleLogger(),
+                    getReportsDirectory() );
         }
         else
         {
@@ -2188,7 +2189,8 @@
                     getEffectiveForkCount(),
                     reuseForks,
                     platform,
-                    getConsoleLogger() );
+                    getConsoleLogger(),
+                    getReportsDirectory() );
         }
     }
 
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/AbstractClasspathForkConfiguration.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/AbstractClasspathForkConfiguration.java
index 6c57ebc..2d6412e 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/AbstractClasspathForkConfiguration.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/AbstractClasspathForkConfiguration.java
@@ -19,6 +19,7 @@
  * under the License.
  */
 
+import org.apache.maven.plugin.surefire.booterclient.output.InPluginProcessDumpSingleton;
 import org.apache.maven.plugin.surefire.log.api.ConsoleLogger;
 import org.apache.maven.surefire.booter.Classpath;
 
@@ -35,6 +36,7 @@
 abstract class AbstractClasspathForkConfiguration
         extends DefaultForkConfiguration
 {
+    private final File reportsDir;
 
     @SuppressWarnings( "checkstyle:parameternumber" )
     AbstractClasspathForkConfiguration( @Nonnull Classpath bootClasspath,
@@ -48,10 +50,12 @@
                                         int forkCount,
                                         boolean reuseForks,
                                         @Nonnull Platform pluginPlatform,
-                                        @Nonnull ConsoleLogger log )
+                                        @Nonnull ConsoleLogger log,
+                                        @Nonnull File reportsDir )
     {
         super( bootClasspath, tempDirectory, debugLine, workingDirectory, modelProperties, argLine,
                 environmentVariables, debug, forkCount, reuseForks, pluginPlatform, log );
+        this.reportsDir = reportsDir;
     }
 
     @Override
@@ -60,4 +64,10 @@
     {
         return jvmArgLine;
     }
+
+    protected void logDump( Exception e, String msg )
+    {
+        InPluginProcessDumpSingleton.getSingleton()
+                .dumpException( e, msg, reportsDir );
+    }
 }
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/ClasspathForkConfiguration.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/ClasspathForkConfiguration.java
index f87b473..bf97774 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/ClasspathForkConfiguration.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/ClasspathForkConfiguration.java
@@ -46,10 +46,10 @@
                                        @Nonnull Properties modelProperties, @Nullable String argLine,
                                        @Nonnull Map<String, String> environmentVariables, boolean debug, int forkCount,
                                        boolean reuseForks, @Nonnull Platform pluginPlatform,
-                                       @Nonnull ConsoleLogger log )
+                                       @Nonnull ConsoleLogger log, @Nonnull File reportsDir )
     {
         super( bootClasspath, tempDirectory, debugLine, workingDirectory, modelProperties, argLine,
-                environmentVariables, debug, forkCount, reuseForks, pluginPlatform, log );
+                environmentVariables, debug, forkCount, reuseForks, pluginPlatform, log, reportsDir );
     }
 
     @Override
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/JarManifestForkConfiguration.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/JarManifestForkConfiguration.java
index 72ae7da..8014507 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/JarManifestForkConfiguration.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/JarManifestForkConfiguration.java
@@ -30,6 +30,9 @@
 import java.io.File;
 import java.io.FileOutputStream;
 import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.nio.file.Path;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
@@ -53,10 +56,10 @@
                                          @Nonnull Properties modelProperties, @Nullable String argLine,
                                          @Nonnull Map<String, String> environmentVariables, boolean debug,
                                          int forkCount, boolean reuseForks, @Nonnull Platform pluginPlatform,
-                                         @Nonnull ConsoleLogger log )
+                                         @Nonnull ConsoleLogger log, @Nonnull File reportsDir )
     {
         super( bootClasspath, tempDirectory, debugLine, workingDirectory, modelProperties, argLine,
-                environmentVariables, debug, forkCount, reuseForks, pluginPlatform, log );
+                environmentVariables, debug, forkCount, reuseForks, pluginPlatform, log, reportsDir );
     }
 
     @Override
@@ -95,6 +98,7 @@
         {
             file.deleteOnExit();
         }
+        Path parent = file.getParentFile().toPath();
         FileOutputStream fos = new FileOutputStream( file );
         try ( JarOutputStream jos = new JarOutputStream( fos ) )
         {
@@ -110,7 +114,7 @@
             for ( Iterator<String> it = classPath.iterator(); it.hasNext(); )
             {
                 File file1 = new File( it.next() );
-                String uri = file1.toURI().toASCIIString();
+                String uri = toClasspathElementUri( parent, file1 );
                 cp.append( uri );
                 if ( file1.isDirectory() && !uri.endsWith( "/" ) )
                 {
@@ -135,4 +139,27 @@
             return file;
         }
     }
+
+    private String toClasspathElementUri( Path parent, File classPathElement ) throws IOException
+    {
+        try
+        {
+            return new URI( null, parent.relativize( classPathElement.toPath() ).toString(), null )
+                    .toASCIIString();
+        }
+        catch ( IllegalArgumentException e )
+        {
+            logDump( e, "Boot Manifest-JAR contains absolute paths in classpath " + classPathElement.getPath() );
+            return classPathElement.toURI()
+                    .toASCIIString();
+        }
+        catch ( URISyntaxException e )
+        {
+            // This is really unexpected, so fail
+            throw new IOException( "Could not create a relative path "
+                    + classPathElement
+                    + " against "
+                    + parent, e );
+        }
+    }
 }
diff --git a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/ForkConfigurationTest.java b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/ForkConfigurationTest.java
index 0067a06..1858981 100644
--- a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/ForkConfigurationTest.java
+++ b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/ForkConfigurationTest.java
@@ -39,6 +39,7 @@
 import java.util.List;
 import java.util.Properties;
 
+import static java.io.File.createTempFile;
 import static java.util.Collections.singletonList;
 import static org.apache.maven.surefire.booter.Classpath.emptyClasspath;
 import static org.junit.Assert.assertEquals;
@@ -181,7 +182,7 @@
     private File getTempClasspathFile()
         throws IOException
     {
-        File cpElement = File.createTempFile( "ForkConfigurationTest.", ".file" );
+        File cpElement = createTempFile( "ForkConfigurationTest.", ".file" );
         cpElement.deleteOnExit();
         return cpElement;
     }
@@ -204,12 +205,12 @@
         throws IOException
     {
         Platform platform = new Platform().withJdkExecAttributesForTests( new JdkAttributes( jvm, false ) );
-        File tmpDir = File.createTempFile( "target", "surefire" );
+        File tmpDir = createTempFile( "target", "surefire" );
         assertTrue( tmpDir.delete() );
         assertTrue( tmpDir.mkdirs() );
         return new JarManifestForkConfiguration( emptyClasspath(), tmpDir, null,
                 cwd, new Properties(), argLine, Collections.<String, String>emptyMap(), false, 1, false,
-                platform, new NullConsoleLogger() );
+                platform, new NullConsoleLogger(), createTempFile( "target", "surefire-reports" ) );
     }
 
     // based on http://stackoverflow.com/questions/2591083/getting-version-of-java-in-runtime