This is an automated email from the ASF dual-hosted git repository.

markt pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/tomcat-jakartaee-migration.git

commit fc2245dd5d7d605e77d31a33221fa4af5ce08f7d
Author: Mark Thomas <ma...@apache.org>
AuthorDate: Mon Feb 8 13:58:15 2021 +0000

    Fix#5  Add a new -zipInMemory option
---
 CHANGES.md                                         |  1 +
 pom.xml                                            |  5 ++
 .../org/apache/tomcat/jakartaee/Migration.java     | 87 +++++++++++++++++++++-
 .../org/apache/tomcat/jakartaee/MigrationCLI.java  |  9 +++
 .../org/apache/tomcat/jakartaee/MigrationTask.java |  6 ++
 .../tomcat/jakartaee/LocalStrings.properties       |  3 +-
 6 files changed, 108 insertions(+), 3 deletions(-)

diff --git a/CHANGES.md b/CHANGES.md
index 5e9ed97..6e2b583 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -17,6 +17,7 @@
 - Include the `javax.resource` package in the EE profile (ebourg)
 - Fix [#7](https://github.com/apache/tomcat-jakartaee-migration/issues/7). 
Include the `javax.jms` package in the EE profile (alitokmen/mgirgorov)
 - Make `migrate.sh` work from any path (mgrigorov)
+- Add a new option `-zipInMemory` that processes archives (ZIP, JAR, WAR, 
etc.) in memory rather via a streaming approach. While less efficient, it 
allows archives to be processed when their structure means that a streaming 
approach will fail.
 
 ## 0.1.0
 
diff --git a/pom.xml b/pom.xml
index d8290db..5b4b1ec 100644
--- a/pom.xml
+++ b/pom.xml
@@ -73,6 +73,11 @@
       <version>6.5.0</version>
     </dependency>
     <dependency>
+      <groupId>org.apache.commons</groupId>
+      <artifactId>commons-compress</artifactId>
+      <version>1.20</version>
+    </dependency>
+    <dependency>
       <groupId>commons-io</groupId>
       <artifactId>commons-io</artifactId>
       <version>2.8.0</version>
diff --git a/src/main/java/org/apache/tomcat/jakartaee/Migration.java 
b/src/main/java/org/apache/tomcat/jakartaee/Migration.java
index 69a23c0..2489844 100644
--- a/src/main/java/org/apache/tomcat/jakartaee/Migration.java
+++ b/src/main/java/org/apache/tomcat/jakartaee/Migration.java
@@ -16,6 +16,7 @@
  */
 package org.apache.tomcat.jakartaee;
 
+import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.File;
 import java.io.FileInputStream;
@@ -24,6 +25,7 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.util.ArrayList;
+import java.util.Enumeration;
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
@@ -36,7 +38,13 @@ import java.util.jar.JarOutputStream;
 import java.util.jar.Manifest;
 import java.util.logging.Level;
 import java.util.logging.Logger;
+import java.util.zip.ZipException;
 
+import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
+import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream;
+import org.apache.commons.compress.archivers.zip.ZipFile;
+import org.apache.commons.compress.utils.SeekableInMemoryByteChannel;
+import org.apache.commons.io.IOUtils;
 import org.apache.commons.io.input.CloseShieldInputStream;
 import org.apache.commons.io.output.CloseShieldOutputStream;
 
@@ -46,6 +54,7 @@ public class Migration {
     private static final StringManager sm = 
StringManager.getManager(Migration.class);
 
     private EESpecProfile profile = EESpecProfile.TOMCAT;
+    private boolean zipInMemory;
     private File source;
     private File destination;
     private final List<Converter> converters;
@@ -79,6 +88,10 @@ public class Migration {
         return profile;
     }
 
+    public void setZipInMemory(boolean zipInMemory) {
+        this.zipInMemory = zipInMemory;
+    }
+
     public void setSource(File source) {
         if (!source.canRead()) {
             throw new 
IllegalArgumentException(sm.getString("migration.cannotReadSource",
@@ -124,6 +137,7 @@ public class Migration {
 
     private boolean migrateDirectory(File src, File dest) throws IOException {
         boolean result = true;
+        // Won't return null because src is known to be a directory
         String[] files = src.list();
         for (String file : files) {
             File srcFile = new File(src, file);
@@ -168,7 +182,7 @@ public class Migration {
     }
 
 
-    private boolean migrateArchive(InputStream src, OutputStream dest) throws 
IOException {
+    private boolean migrateArchiveStreaming(String name, InputStream src, 
OutputStream dest) throws IOException {
         boolean result = true;
         try (JarInputStream jarIs = new JarInputStream(new 
CloseShieldInputStream(src));
                 JarOutputStream jarOs = new JarOutputStream(new 
CloseShieldOutputStream(dest))) {
@@ -198,7 +212,59 @@ public class Migration {
                 jarOs.putNextEntry(destEntry);
                 result = result && migrateStream(destEntry.getName(), jarIs, 
jarOs);
             }
+        } catch (ZipException ze) {
+            logger.log(Level.SEVERE, sm.getString("migration.archiveFailed", 
name), ze);
+            throw ze;
+        }
+        return result;
+    }
+
+
+    private boolean migrateArchiveInMemory(InputStream src, OutputStream dest) 
throws IOException {
+        boolean result = true;
+        // Read the source into memory
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        IOUtils.copy(src, baos);
+        SeekableInMemoryByteChannel srcByteChannel = new 
SeekableInMemoryByteChannel(baos.toByteArray());
+        // Create the destination in memory
+        SeekableInMemoryByteChannel destByteChannel = new 
SeekableInMemoryByteChannel();
+
+        try (ZipFile srcZipFile = new ZipFile(srcByteChannel);
+                ZipArchiveOutputStream destZipStream = new 
ZipArchiveOutputStream(destByteChannel)) {
+            Enumeration<ZipArchiveEntry> entries = srcZipFile.getEntries();
+            while (entries.hasMoreElements()) {
+                ZipArchiveEntry srcZipEntry = entries.nextElement();
+                String srcName = srcZipEntry.getName();
+                logger.log(Level.FINE, sm.getString("migration.entry", 
srcName));
+                if (srcZipEntry.getName().equals(JarFile.MANIFEST_NAME)) {
+                    // Special handling for manifest
+                    Manifest manifest = new 
Manifest(srcZipFile.getInputStream(srcZipEntry));
+                    updateVersion(manifest);
+                    if (removeSignatures(manifest)) {
+                        logger.log(Level.WARNING, 
sm.getString("migration.warnSignatureRemoval"));
+                    }
+                    destZipStream.putArchiveEntry(srcZipEntry);
+                    manifest.write(destZipStream);
+                    destZipStream.closeArchiveEntry();
+                } else {
+                    if (isSignatureFile(srcName)) {
+                        logger.log(Level.FINE, 
sm.getString("migration.skipSignatureFile", srcName));
+                        continue;
+                    }
+                    String destName = profile.convert(srcName);
+                    RenamableZipArchiveEntry destZipEntry = new 
RenamableZipArchiveEntry(srcZipEntry);
+                    destZipEntry.setName(destName);
+                    destZipStream.putArchiveEntry(destZipEntry);
+                    result = result && migrateStream(srcName, 
srcZipFile.getInputStream(srcZipEntry), destZipStream);
+                    destZipStream.closeArchiveEntry();
+                }
+            }
         }
+
+        // Write the destination back to the stream
+        ByteArrayInputStream bais = new 
ByteArrayInputStream(destByteChannel.array());
+        IOUtils.copy(bais, dest);
+
         return result;
     }
 
@@ -212,7 +278,11 @@ public class Migration {
     private boolean migrateStream(String name, InputStream src, OutputStream 
dest) throws IOException {
         if (isArchive(name)) {
             logger.log(Level.INFO, sm.getString("migration.archive", name));
-            return migrateArchive(src, dest);
+            if (zipInMemory) {
+                return migrateArchiveInMemory(src, dest);
+            } else {
+                return migrateArchiveStreaming(name, src, dest);
+            }
         } else {
             logger.log(Level.FINE, sm.getString("migration.stream", name));
             for (Converter converter : converters) {
@@ -275,4 +345,17 @@ public class Migration {
     private static boolean isArchive(String fileName) {
         return fileName.endsWith(".jar") || fileName.endsWith(".war") || 
fileName.endsWith(".zip");
     }
+
+
+    private static class RenamableZipArchiveEntry extends ZipArchiveEntry {
+
+        public RenamableZipArchiveEntry(ZipArchiveEntry entry) throws 
ZipException {
+            super(entry);
+        }
+
+        @Override
+        public void setName(String name) {
+            super.setName(name);
+        }
+    }
 }
diff --git a/src/main/java/org/apache/tomcat/jakartaee/MigrationCLI.java 
b/src/main/java/org/apache/tomcat/jakartaee/MigrationCLI.java
index 8c33d2d..5c3bf4f 100644
--- a/src/main/java/org/apache/tomcat/jakartaee/MigrationCLI.java
+++ b/src/main/java/org/apache/tomcat/jakartaee/MigrationCLI.java
@@ -31,6 +31,8 @@ public class MigrationCLI {
 
     private static final String PROFILE_ARG = "-profile=";
 
+    private static final String ZIPINMEMORY_ARG = "-zipInMemory";
+
     public static void main(String[] args) {
         System.setProperty("java.util.logging.SimpleFormatter.format", "%5$s%n 
%6$s%n");
 
@@ -41,7 +43,14 @@ public class MigrationCLI {
             arguments.remove("-verbose");
         }
 
+        boolean zipInMemory = false;
+        if (arguments.contains(ZIPINMEMORY_ARG)) {
+            zipInMemory = true;
+            arguments.remove(ZIPINMEMORY_ARG);
+        }
+
         Migration migration = new Migration();
+        migration.setZipInMemory(zipInMemory);
 
         boolean valid = false;
         String source = null;
diff --git a/src/main/java/org/apache/tomcat/jakartaee/MigrationTask.java 
b/src/main/java/org/apache/tomcat/jakartaee/MigrationTask.java
index 4d7d967..6bdda1d 100644
--- a/src/main/java/org/apache/tomcat/jakartaee/MigrationTask.java
+++ b/src/main/java/org/apache/tomcat/jakartaee/MigrationTask.java
@@ -32,6 +32,7 @@ public class MigrationTask extends Task {
     private File src;
     private File dest;
     private String profile = EESpecProfile.TOMCAT.toString();
+    private boolean zipInMemory = false;
 
     public void setSrc(File src) {
         this.src = src;
@@ -45,6 +46,10 @@ public class MigrationTask extends Task {
         this.profile = profile;
     }
 
+    public void setZipInMemory(boolean zipInMemory) {
+        this.zipInMemory = zipInMemory;
+    }
+
     @Override
     public void execute() throws BuildException {
         // redirect the log messages to Ant
@@ -67,6 +72,7 @@ public class MigrationTask extends Task {
         migration.setSource(src);
         migration.setDestination(dest);
         migration.setEESpecProfile(profile);
+        migration.setZipInMemory(zipInMemory);
 
         boolean success = false;
         try {
diff --git 
a/src/main/resources/org/apache/tomcat/jakartaee/LocalStrings.properties 
b/src/main/resources/org/apache/tomcat/jakartaee/LocalStrings.properties
index 93a7649..cf62ca3 100644
--- a/src/main/resources/org/apache/tomcat/jakartaee/LocalStrings.properties
+++ b/src/main/resources/org/apache/tomcat/jakartaee/LocalStrings.properties
@@ -14,6 +14,7 @@
 # limitations under the License.
 
 migration.archive=Migrating archive [{0}]
+migration.archiveFailed=Failed to migrate archive [{0}]. Using the 
"-zipInMemory" option may help. 
 migration.cannotReadSource=Cannot read source location [{0}]
 migration.done=Migration completed successfully [{1}] in [{0}] milliseconds
 migration.entry=Migrating Jar entry [{0}]
@@ -23,5 +24,5 @@ migration.mkdirError=Error creating destination directory 
[{0}]
 migration.removeSignature=Remove cryptographic signature for [{0}]
 migration.skipSignatureFile=Drop cryptographic signature file [{0}]
 migration.stream=Migrating stream [{0}]
-migration.usage=Usage: Migration [-profile=TOMCAT|-profile=EE] <source> 
<destination>
+migration.usage=Usage: Migration [-profile=TOMCAT|-profile=EE] [-zipInMemory] 
[-verbose] <source> <destination>
 migration.warnSignatureRemoval=Removed cryptographic signature from JAR file


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org
For additional commands, e-mail: dev-h...@tomcat.apache.org

Reply via email to