Merge pull request #5 from cesarhernandezgt/exclude-jar

TOMEE-3826 Exclusion list implemented in Transformation to preserve jar signature
diff --git a/README.adoc b/README.adoc
index 679c8c0..e7154af 100644
--- a/README.adoc
+++ b/README.adoc
@@ -98,7 +98,7 @@
 
 Note that transitive dependecies are not supported, so each jar directly needed to compile must be specified individually.
 
-## Repacing Jar files in the Archive
+## Replacing Jar files in the Archive
 
 The `<replace><jars>` list allows us to tell the plugin, "when you see a `jakarta.faces-3.0.0.jar` in the war file, replace it with the `org.glassfish:jakarta.faces:jar:3.0.0` artifact from our local maven repo."
 
@@ -122,3 +122,16 @@
 
 The `<replace><jars>` list allows us to tell the plugin, "when you see an `openejb-version.properties` file anywhere in the war file or its libraries, replace it with the specially modified version from `target/classes/`."  In the module we're generating a new `openejb-version.properties` so we can change the version TomEE reports from "8.0.7-SNAPSHOT" to "9.0.0-M7-SNAPSHOT"
 
+## Skipping Jar files from the Archives
+This is useful when you have jars found in the archive need to preserve jar signature metadata.
+The `<skips><jars>` list allows you to tell the plugin which Jars should be skipped during archive transformation.
+Example configuration:
+
+        <configuration>
+           <skips>
+               <jars>
+                 <eclipselink-3.0.0.jar>org.eclipse.persistence:eclipselink:jar:3.0.0</eclipselink-3.0.0.jar>
+                 <bcprov-jdk15on-1.69.jar>org.bouncycastle:bcprov-jdk15on:jar:1.69</bcprov-jdk15on-1.69.jar>
+               </jars>
+             </skips>
+        </configuration>
\ No newline at end of file
diff --git a/tomee-patch-core/src/main/java/org/apache/tomee/patch/core/Skips.java b/tomee-patch-core/src/main/java/org/apache/tomee/patch/core/Skips.java
new file mode 100644
index 0000000..a548047
--- /dev/null
+++ b/tomee-patch-core/src/main/java/org/apache/tomee/patch/core/Skips.java
@@ -0,0 +1,11 @@
+package org.apache.tomee.patch.core;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class Skips {
+    private Map<String, String> jars = new  HashMap<>();
+    public Map<String, String> getJars() {
+        return jars;
+    }
+}
diff --git a/tomee-patch-core/src/main/java/org/apache/tomee/patch/core/Transformation.java b/tomee-patch-core/src/main/java/org/apache/tomee/patch/core/Transformation.java
index 3a3997c..3cc2a39 100644
--- a/tomee-patch-core/src/main/java/org/apache/tomee/patch/core/Transformation.java
+++ b/tomee-patch-core/src/main/java/org/apache/tomee/patch/core/Transformation.java
@@ -28,11 +28,7 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
+import java.util.*;
 import java.util.regex.Pattern;
 import java.util.stream.Collectors;
 import java.util.zip.ZipEntry;
@@ -46,6 +42,7 @@
     private final List<Clazz> classes = new ArrayList<Clazz>();
     private final Log log;
     private final Replacements replacements;
+    private final Skips skips;
     private final Additions additions;
     private final Boolean skipTransform;
     private final File patchResources;
@@ -53,16 +50,18 @@
     public Transformation() {
         this.log = new NullLog();
         this.replacements = new Replacements();
+        this.skips = new Skips();
         this.additions = new Additions();
         this.skipTransform = false;
         this.patchResources = new File("does not exist");
     }
 
 
-    public Transformation(final List<Clazz> classes, final File patchResources, final Replacements replacements, final Additions additions, final Log log, final Boolean skipTransform) {
+    public Transformation(final List<Clazz> classes, final File patchResources, final Replacements replacements, final Skips skips, final Additions additions, final Log log, final Boolean skipTransform) {
         this.classes.addAll(classes);
         this.log = log;
         this.replacements = replacements == null ? new Replacements() : replacements;
+        this.skips = skips == null ? new Skips() : skips;
         this.additions = additions == null ? new Additions() : additions;
         this.patchResources = patchResources;
         this.skipTransform = skipTransform;
@@ -139,7 +138,11 @@
                     if (path.endsWith(".class")) {
                         scanClass(zipInputStream, zipOutputStream);
                     } else if (isZip(path)) {
-                        scanJar(path, zipInputStream, zipOutputStream);
+                        if(isExcludedJar(path)){
+                            IO.copy(zipInputStream, zipOutputStream);
+                        }else{
+                            scanJar(path, zipInputStream, zipOutputStream);
+                        }
                     } else if (copyUnmodified(path)) {
                         IO.copy(zipInputStream, zipOutputStream);
                     } else {
@@ -263,6 +266,20 @@
         return false;
     }
 
+    private boolean isExcludedJar(final String path) {
+        if (skips != null) {
+            Map<String, String> skipsJars = skips.getJars();
+            if (!skipsJars.isEmpty()) {
+                for (Map.Entry<String, String> set : skipsJars.entrySet()) {
+                    if (path.contains(set.getKey())) {
+                        return true;
+                    }
+                }
+            }
+        }
+        return false;
+    }
+
     private void scanResource(final String path, InputStream inputStream, final OutputStream outputStream) throws IOException {
 
         {
diff --git a/tomee-patch-core/src/test/java/org/apache/tomee/patch/core/ExcludeJarsTest.java b/tomee-patch-core/src/test/java/org/apache/tomee/patch/core/ExcludeJarsTest.java
new file mode 100644
index 0000000..719ba97
--- /dev/null
+++ b/tomee-patch-core/src/test/java/org/apache/tomee/patch/core/ExcludeJarsTest.java
@@ -0,0 +1,109 @@
+package org.apache.tomee.patch.core;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.tomitribe.util.Archive;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.*;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+public class ExcludeJarsTest {
+    public static final int DEFAULT_BUFFER_SIZE = 8192;
+    public Skips customSkips = new Skips();
+
+    @Before
+    public void prepareLists(){
+        customSkips.getJars().put("eclipselink-3.0.0.jar","org.eclipse.persistence:eclipselink:jar:3.0.0");
+        customSkips.getJars().put("bcprov-jdk15on-1.69.jar","org.bouncycastle:bcprov-jdk15on:jar:1.69");
+    }
+
+    @Test
+    public void transformWithJarExclusions() throws Exception {
+        final String jarSignatureFileName = "META-INF/sigTest.DSA";
+        final String jarName = "bcprov-jdk15on-1.69.jar";
+        final File testJar = Archive.archive()
+                .add(jarSignatureFileName, "DC143C")
+                .add("index.txt", "red,green,blue")
+                .toJar();
+
+        final File zipFile = Archive.archive()
+                .add("README.txt", "hi")
+                .add(jarName, testJar).toJar();
+
+        Transformation transformation = new Transformation(new ArrayList<Clazz>(), new File("does not exist"),null, customSkips, null, new NullLog(), false);
+        File transformedJar = transformation.transformArchive(zipFile);
+        assertTrue(obtainJarContent(transformedJar).contains(jarSignatureFileName));
+    }
+
+    @Test
+    public void transformWithoutJarExclusions() throws Exception {
+        final String jarSignatureFileName = "META-INF/sigTest.DSA";
+        final String jarName = "jdbc.jar";
+
+        final File testJar = Archive.archive()
+                .add(jarSignatureFileName, "DC143C")
+                .add("index.txt", "red,green,blue")
+                .toJar();
+
+        final File zipFile = Archive.archive()
+                .add("README.txt", "hi")
+                .add(jarName, testJar).toJar();
+
+        Transformation transformation = new Transformation(new ArrayList<Clazz>(), new File("does not exist"),null, customSkips, null, new NullLog(), false);
+        File transformedJar = transformation.transformArchive(zipFile);
+        assertFalse(obtainJarContent(transformedJar).contains(jarSignatureFileName));
+    }
+
+    private List obtainJarContent(File transformedJar) throws IOException {
+        List<String> jarFileList = new ArrayList<String>();
+
+        //Iterating over the zip files
+        ZipFile zip = new ZipFile(transformedJar);
+        Enumeration content = zip.entries();
+        for (Enumeration f = content; f.hasMoreElements(); ) {
+            ZipEntry entry = (ZipEntry) f.nextElement();
+            //System.out.println(entry.getName());
+
+            if (entry.getName().endsWith(".jar")) {
+
+                //Iterating over the jar foun in the zip file
+                File jar = new File(entry.getName());
+                copyInputStreamToFile(zip.getInputStream(entry),jar);
+                JarFile jarFile = new JarFile(jar);
+                Enumeration innerEntries = jarFile.entries();
+                for (Enumeration e = innerEntries; e.hasMoreElements(); ) {
+                    JarEntry file = (JarEntry) e.nextElement();
+               //System.out.println("  - " +file.getName());
+                    jarFileList.add(file.getName());
+                }
+                jarFile.close();
+                jar.deleteOnExit();
+            }
+        }
+        zip.close();
+        return jarFileList;
+    }
+
+
+    private static void copyInputStreamToFile(InputStream inputStream, File file) throws IOException {
+        try (FileOutputStream outputStream = new FileOutputStream(file, false)) {
+            int read;
+            byte[] bytes = new byte[DEFAULT_BUFFER_SIZE];
+            while ((read = inputStream.read(bytes)) != -1) {
+                outputStream.write(bytes, 0, read);
+            }
+        }
+
+    }
+}
+
diff --git a/tomee-patch-plugin/src/main/java/org/apache/tomee/patch/plugin/PatchMojo.java b/tomee-patch-plugin/src/main/java/org/apache/tomee/patch/plugin/PatchMojo.java
index 4975a39..192e54a 100644
--- a/tomee-patch-plugin/src/main/java/org/apache/tomee/patch/plugin/PatchMojo.java
+++ b/tomee-patch-plugin/src/main/java/org/apache/tomee/patch/plugin/PatchMojo.java
@@ -48,12 +48,7 @@
 import org.apache.maven.shared.transfer.dependencies.resolve.DependencyResolverException;
 import org.apache.maven.toolchain.Toolchain;
 import org.apache.maven.toolchain.ToolchainManager;
-import org.apache.tomee.patch.core.Additions;
-import org.apache.tomee.patch.core.Clazz;
-import org.apache.tomee.patch.core.Is;
-import org.apache.tomee.patch.core.Replacements;
-import org.apache.tomee.patch.core.Transformation;
-import org.apache.tomee.patch.core.ZipToTar;
+import org.apache.tomee.patch.core.*;
 import org.codehaus.plexus.compiler.Compiler;
 import org.codehaus.plexus.compiler.CompilerConfiguration;
 import org.codehaus.plexus.compiler.CompilerMessage;
@@ -180,6 +175,9 @@
     private Replacements replace;
 
     @Parameter
+    private Skips skips;
+
+    @Parameter
     private Additions add;
 
     @Parameter(defaultValue = "false")
@@ -285,7 +283,7 @@
 
             final List<Clazz> clazzes = classes();
 
-            final Transformation transformation = new Transformation(clazzes, patchResourceDirectory, replace, add, new MavenLog(getLog()), skipTransform);
+            final Transformation transformation = new Transformation(clazzes, patchResourceDirectory, replace, skips, add, new MavenLog(getLog()), skipTransform);
             for (final Artifact artifact : artifacts) {
                 final File file = artifact.getFile();
                 getLog().debug("Patching " + file.getAbsolutePath());