[Git][java-team/tomcat-jakartaee-migration][master] 3 commits: New upstream version 0.2.0
Emmanuel Bourg
gitlab at salsa.debian.org
Sun Feb 28 20:21:31 GMT 2021
Emmanuel Bourg pushed to branch master at Debian Java Maintainers / tomcat-jakartaee-migration
Commits:
b184ff42 by Emmanuel Bourg at 2021-02-28T21:11:46+01:00
New upstream version 0.2.0
- - - - -
6b8616d5 by Emmanuel Bourg at 2021-02-28T21:11:47+01:00
Update upstream source from tag 'upstream/0.2.0'
Update to upstream version '0.2.0'
with Debian dir 5f91872754880be229eca958b0785e9153e93440
- - - - -
865db0d4 by Emmanuel Bourg at 2021-02-28T21:17:57+01:00
New upstream release (0.2.0)
- - - - -
22 changed files:
- + CHANGES.md
- NOTICE.txt
- README.md
- debian/changelog
- pom.xml
- src/assembly/src.xml
- src/main/java/org/apache/tomcat/jakartaee/ClassConverter.java
- src/main/java/org/apache/tomcat/jakartaee/Converter.java
- src/main/java/org/apache/tomcat/jakartaee/EESpecProfile.java
- + src/main/java/org/apache/tomcat/jakartaee/GlobMatcher.java
- + src/main/java/org/apache/tomcat/jakartaee/ManifestConverter.java
- src/main/java/org/apache/tomcat/jakartaee/Migration.java
- src/main/java/org/apache/tomcat/jakartaee/MigrationCLI.java
- src/main/java/org/apache/tomcat/jakartaee/MigrationTask.java
- src/main/java/org/apache/tomcat/jakartaee/PassThroughConverter.java
- src/main/java/org/apache/tomcat/jakartaee/TextConverter.java
- src/main/resources/org/apache/tomcat/jakartaee/LocalStrings.properties
- src/main/scripts/migrate.sh
- src/test/java/org/apache/tomcat/jakartaee/EESpecProfileTest.java
- src/test/java/org/apache/tomcat/jakartaee/MigrationTest.java
- src/test/java/org/apache/tomcat/jakartaee/PassThroughConverterTest.java
- src/test/java/org/apache/tomcat/jakartaee/TextConverterTest.java
Changes:
=====================================
CHANGES.md
=====================================
@@ -0,0 +1,33 @@
+# Tomcat Migration Tool for Jakarta EE - Changelog
+
+## 0.2.0 (in progress)
+
+- Add this changelog (markt)
+- Update dependencies (Apache Commons IO 2.8.0, Apache Ant 1.10.9) (markt)
+- Fix [#9](https://github.com/apache/tomcat-jakartaee-migration/issues/9). Exclude the `javax.xml.namespace` package in the EE profile (ebourg)
+- Include the `javax.management.j2ee` package in the EE profile (ebourg)
+- Add a test to confirm `javax.xml.xpath.XPathConstants` is not converted (ebourg)
+- Update README to mention the tool is now available on Debian/Ubuntu (ebourg)
+- Include the `javax.security.enterprise` package in the EE profile (ebourg)
+- Include the `javax.xml.registry` package in the EE profile (ebourg)
+- Include the `javax.security.jacc` package in the EE profile (ebourg)
+- Include the `javax.faces` package in the EE profile (ebourg)
+- Include the `javax.batch` package in the EE profile (ebourg)
+- Include the `javax.jws` package in the EE profile (ebourg)
+- 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. (markt)
+- Include the Maven Wrapper source files in the source distribution. (markt)
+- Ensure that all the Manifest attributes are processed during the migration process. (markt)
+- Include `.properties` and `.json` files in the conversion process. (markt)
+- Replace `-verbose` with `-logLevel=` to provide more control over logging level. (markt)
+- Fix [#13](https://github.com/apache/tomcat-jakartaee-migration/issues/13). Refactor mapping of log messages to log levels. (markt)
+- Fix [#3](https://github.com/apache/tomcat-jakartaee-migration/issues/3). Add support for excluding files from conversion. (markt)
+- Fix handling of classes with more than 32768 entries in the constant pool. (markt)
+- Exclude `javax.xml.stream` and `javax.xml.XMLConstants` from the EE profile. (markt)
+- Relocate dependencies under the `org.apache.tomcat.jakartaee` package to avoid clashes when integrating the shaded jar. (markt)
+
+## 0.1.0
+
+- Initial release (markt)
=====================================
NOTICE.txt
=====================================
@@ -1,5 +1,5 @@
Apache Tomcat migration tool for Jakarta EE
-Copyright 2020 The Apache Software Foundation
+Copyright 2021 The Apache Software Foundation
This product includes software developed at
The Apache Software Foundation (https://www.apache.org/).
\ No newline at end of file
=====================================
README.md
=====================================
@@ -39,6 +39,10 @@ the same type as the source.
>
> A warning will be logged for each JAR file where the signature has been removed.
+This tool is also available on Debian and Ubuntu systems by installing the
+[tomcat-jakartaee-migration](https://tracker.debian.org/tomcat-jakartaee-migration)
+package and invoking the `javax2jakarta` command.
+
## Ant task
The migration tool is available as an Ant task, here is an example:
@@ -49,13 +53,17 @@ The migration tool is available as an Ant task, here is an example:
## Differences between Java EE 8 and Jakarta EE 9
-Jakarta EE 9 is still under development and there are some details that remain
-to be worked out.
-
-The differences currently supported by this tool are:
+The difference between Java EE 8 and Jakarta EE 9 is that all the
+[Java EE 8 packages](https://github.com/apache/tomcat-jakartaee-migration/blob/master/src/main/java/org/apache/tomcat/jakartaee/EESpecProfile.java#L37)
+in the `javax.*` namespace have moved to the `jakarta.*` namespace.
+Some sub-packages have also been renamed.
+This migration tool performs all the necessary changes to migrate an application
+from Java EE 8 to Jakarta EE 9 by renaming each Java EE 8 package to its Jakarta
+EE 9 replacement.
-* Renaming packages for Jakarta EE 9 APIs from `javax.*` to `jakarta.*`
+Note: Not all `javax.*` packages are part of Java EE. Only those defined by Java
+EE have moved to the `jakarta.*` namespace.
-Note: It will not be necessary to migrate any references to XML schemas. The
-schemas don't directly reference javax packages and Jakarta EE 9 will continue
-to support the use of schemas from Java EE 8 and earlier.
+Note: It is not necessary to migrate any references to XML schemas. The schemas
+don't directly reference javax packages and Jakarta EE 9 will continue to
+support the use of schemas from Java EE 8 and earlier.
=====================================
debian/changelog
=====================================
@@ -1,3 +1,9 @@
+tomcat-jakartaee-migration (0.2.0-1) unstable; urgency=medium
+
+ * New upstream release
+
+ -- Emmanuel Bourg <ebourg at apache.org> Sun, 28 Feb 2021 21:17:45 +0100
+
tomcat-jakartaee-migration (0.1.0-1) unstable; urgency=medium
* New upstream release
=====================================
pom.xml
=====================================
@@ -26,7 +26,8 @@
<groupId>org.apache.tomcat</groupId>
<artifactId>jakartaee-migration</artifactId>
- <version>0.1.0</version>
+ <name>Apache Tomcat Migration Tool for Jakarta EE</name>
+ <version>0.2.0</version>
<description>
This tool is a work in progress.
@@ -72,15 +73,20 @@
<artifactId>bcel</artifactId>
<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.6</version>
+ <version>2.8.0</version>
</dependency>
<dependency>
<groupId>org.apache.ant</groupId>
<artifactId>ant</artifactId>
- <version>1.10.8</version>
+ <version>1.10.9</version>
<scope>provided</scope>
</dependency>
@@ -97,7 +103,7 @@
<connection>scm:git:https://gitbox.apache.org/repos/asf/tomcat-jakartaee-migration.git</connection>
<developerConnection>scm:git:https://gitbox.apache.org/repos/asf/tomcat-jakartaee-migration.git</developerConnection>
<url>https://gitbox.apache.org/repos/asf?p=tomcat-jakartaee-migration.git</url>
- <tag>0.1.0</tag>
+ <tag>0.2.0</tag>
</scm>
<build>
@@ -254,6 +260,12 @@
<exclude>META-INF/**</exclude>
</excludes>
</filter>
+ <filter>
+ <artifact>org.apache.commons:*</artifact>
+ <excludes>
+ <exclude>META-INF/**</exclude>
+ </excludes>
+ </filter>
<filter>
<artifact>commons-io:*</artifact>
<excludes>
@@ -261,6 +273,16 @@
</excludes>
</filter>
</filters>
+ <relocations>
+ <relocation>
+ <pattern>org.apache.commons</pattern>
+ <shadedPattern>org.apache.tomcat.jakartaee.commons</shadedPattern>
+ </relocation>
+ <relocation>
+ <pattern>org.apache.bcel</pattern>
+ <shadedPattern>org.apache.tomcat.jakartaee.bcel</shadedPattern>
+ </relocation>
+ </relocations>
</configuration>
</execution>
</executions>
=====================================
src/assembly/src.xml
=====================================
@@ -35,5 +35,11 @@
<fileSet>
<directory>src</directory>
</fileSet>
+ <fileSet>
+ <directory>.mvn</directory>
+ <excludes>
+ <exclude>**/*.jar</exclude>
+ </excludes>
+ </fileSet>
</fileSets>
</assembly>
=====================================
src/main/java/org/apache/tomcat/jakartaee/ClassConverter.java
=====================================
@@ -16,16 +16,26 @@
*/
package org.apache.tomcat.jakartaee;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import java.lang.instrument.ClassFileTransformer;
+import java.lang.instrument.IllegalClassFormatException;
+import java.security.ProtectionDomain;
+import java.util.logging.Level;
+import java.util.logging.Logger;
import org.apache.bcel.classfile.ClassParser;
import org.apache.bcel.classfile.Constant;
import org.apache.bcel.classfile.ConstantUtf8;
import org.apache.bcel.classfile.JavaClass;
-public class ClassConverter implements Converter {
+public class ClassConverter implements Converter, ClassFileTransformer {
+
+ private static final Logger logger = Logger.getLogger(ClassConverter.class.getCanonicalName());
+ private static final StringManager sm = StringManager.getManager(ClassConverter.class);
@Override
public boolean accepts(String filename) {
@@ -35,22 +45,54 @@ public class ClassConverter implements Converter {
@Override
- public void convert(InputStream src, OutputStream dest, EESpecProfile profile) throws IOException {
+ public void convert(String path, InputStream src, OutputStream dest, EESpecProfile profile) throws IOException {
ClassParser parser = new ClassParser(src, "unknown");
JavaClass javaClass = parser.parse();
+ boolean converted = false;
+
// Loop through constant pool
Constant[] constantPool = javaClass.getConstantPool().getConstantPool();
- for (short i = 0; i < constantPool.length; i++) {
+ // Need an int as the maximum pool size is 2^16
+ for (int i = 0; i < constantPool.length; i++) {
if (constantPool[i] instanceof ConstantUtf8) {
ConstantUtf8 c = (ConstantUtf8) constantPool[i];
String str = c.getBytes();
- c = new ConstantUtf8(profile.convert(str));
- constantPool[i] = c;
+ String newString = profile.convert(str);
+ // Object comparison is deliberate
+ if (newString != str) {
+ c = new ConstantUtf8(profile.convert(str));
+ constantPool[i] = c;
+ converted = true;
+ }
+ }
+ }
+
+ if (logger.isLoggable(Level.FINE)) {
+ if (converted) {
+ logger.log(Level.FINE, sm.getString("classConverter.converted", path));
+ } else if (logger.isLoggable(Level.FINEST)) {
+ logger.log(Level.FINEST, sm.getString("classConverter.noConversion", path));
}
}
javaClass.dump(dest);
}
+
+
+ @Override
+ public byte[] transform(ClassLoader loader, String className,
+ Class<?> classBeingRedefined, ProtectionDomain protectionDomain,
+ byte[] classfileBuffer) throws IllegalClassFormatException {
+ ByteArrayInputStream inputStream = new ByteArrayInputStream(classfileBuffer);
+ ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+ try {
+ convert(className, inputStream, outputStream, EESpecProfile.TOMCAT);
+ } catch (IOException e) {
+ throw new IllegalClassFormatException(e.getLocalizedMessage());
+ }
+ return outputStream.toByteArray();
+ }
+
}
=====================================
src/main/java/org/apache/tomcat/jakartaee/Converter.java
=====================================
@@ -24,5 +24,16 @@ public interface Converter {
boolean accepts(String filename);
- void convert(InputStream src, OutputStream dest, EESpecProfile profile) throws IOException;
+ /**
+ * Copies the source to the destination, converting it if necessary,
+ * according to the requirements of the given profile.
+ *
+ * @param path The path to the data being converted
+ * @param src The source data to convert
+ * @param dest The destination to write the converted data
+ * @param profile The profile that defines the conversion required
+ *
+ * @throws IOException If the conversion fails
+ */
+ void convert(String path, InputStream src, OutputStream dest, EESpecProfile profile) throws IOException;
}
=====================================
src/main/java/org/apache/tomcat/jakartaee/EESpecProfile.java
=====================================
@@ -24,11 +24,40 @@ import java.util.regex.Pattern;
*/
public enum EESpecProfile {
- TOMCAT("javax([/\\.](annotation(?![/\\.]processing)|ejb|el|mail|persistence|security[/\\.]auth[/\\.]message|servlet|transaction(?![/\\.]xa)|websocket))"),
+ TOMCAT("javax([/\\.](annotation(?![/\\.]processing)" +
+ "|ejb" +
+ "|el" +
+ "|mail" +
+ "|persistence" +
+ "|security[/\\.]auth[/\\.]message" +
+ "|servlet" +
+ "|transaction(?![/\\.]xa)" +
+ "|websocket))"),
- EE("javax([/\\.](activation|annotation(?![/\\.]processing)|decorator|ejb|el|enterprise|json|interceptor|inject|mail|persistence|"
- + "security[/\\.]auth[/\\.]message|servlet|transaction(?![/\\.]xa)|validation|websocket|ws[/\\.]rs|"
- + "xml[/\\.](bind|namespace|rpc|soap|stream|ws|XMLConstants)))");
+ EE("javax([/\\.](activation" +
+ "|annotation(?![/\\.]processing)" +
+ "|batch" +
+ "|decorator" +
+ "|ejb" +
+ "|el" +
+ "|enterprise" +
+ "|faces" +
+ "|jms" +
+ "|json" +
+ "|jws" +
+ "|interceptor" +
+ "|inject" +
+ "|mail" +
+ "|management[/\\.]j2ee" +
+ "|persistence" +
+ "|resource" +
+ "|security[/\\.](auth[/\\.]message|enterprise|jacc)" +
+ "|servlet" +
+ "|transaction(?![/\\.]xa)" +
+ "|validation" +
+ "|websocket" +
+ "|ws[/\\.]rs" +
+ "|xml[/\\.](bind|registry|rpc|soap|ws)))");
private Pattern pattern;
=====================================
src/main/java/org/apache/tomcat/jakartaee/GlobMatcher.java
=====================================
@@ -0,0 +1,243 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.tomcat.jakartaee;
+
+import java.util.Set;
+
+/**
+ * <p>This is a utility class to match file globs.
+ * The class has been derived from
+ * org.apache.tools.ant.types.selectors.SelectorUtils.
+ * </p>
+ * <p>All methods are static.</p>
+ */
+public final class GlobMatcher {
+
+ /**
+ * Tests whether or not a given file name matches any file name pattern in
+ * the given set. The match is performed case-sensitively.
+ *
+ * @see #match(String, String, boolean)
+ *
+ * @param patternSet The pattern set to match against. Must not be
+ * <code>null</code>.
+ * @param fileName The file name to match, as a String. Must not be
+ * <code>null</code>. It must be just a file name, without
+ * a path.
+ * @param caseSensitive Whether or not matching should be performed
+ * case sensitively.
+ *
+ * @return <code>true</code> if any pattern in the set matches against the
+ * file name, or <code>false</code> otherwise.
+ */
+ public static boolean matchName(Set<String> patternSet, String fileName, boolean caseSensitive) {
+ char[] fileNameArray = fileName.toCharArray();
+ for (String pattern: patternSet) {
+ if (match(pattern, fileNameArray, caseSensitive)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+
+ /**
+ * Tests whether or not a string matches against a pattern.
+ * The pattern may contain two special characters:<br>
+ * '*' means zero or more characters<br>
+ * '?' means one and only one character
+ *
+ * @param pattern The pattern to match against.
+ * Must not be <code>null</code>.
+ * @param str The string which must be matched against the
+ * pattern. Must not be <code>null</code>.
+ * @param caseSensitive Whether or not matching should be performed
+ * case sensitively.
+ *
+ *
+ * @return <code>true</code> if the string matches against the pattern,
+ * or <code>false</code> otherwise.
+ */
+ public static boolean match(String pattern, String str,
+ boolean caseSensitive) {
+
+ return match(pattern, str.toCharArray(), caseSensitive);
+ }
+
+
+ /**
+ * Tests whether or not a string matches against a pattern.
+ * The pattern may contain two special characters:<br>
+ * '*' means zero or more characters<br>
+ * '?' means one and only one character
+ *
+ * @param pattern The pattern to match against.
+ * Must not be <code>null</code>.
+ * @param strArr The character array which must be matched against the
+ * pattern. Must not be <code>null</code>.
+ * @param caseSensitive Whether or not matching should be performed
+ * case sensitively.
+ *
+ *
+ * @return <code>true</code> if the string matches against the pattern,
+ * or <code>false</code> otherwise.
+ */
+ private static boolean match(String pattern, char[] strArr,
+ boolean caseSensitive) {
+ char[] patArr = pattern.toCharArray();
+ int patIdxStart = 0;
+ int patIdxEnd = patArr.length - 1;
+ int strIdxStart = 0;
+ int strIdxEnd = strArr.length - 1;
+ char ch;
+
+ boolean containsStar = false;
+ for (char c : patArr) {
+ if (c == '*') {
+ containsStar = true;
+ break;
+ }
+ }
+
+ if (!containsStar) {
+ // No '*'s, so we make a shortcut
+ if (patIdxEnd != strIdxEnd) {
+ return false; // Pattern and string do not have the same size
+ }
+ for (int i = 0; i <= patIdxEnd; i++) {
+ ch = patArr[i];
+ if (ch != '?') {
+ if (different(caseSensitive, ch, strArr[i])) {
+ return false; // Character mismatch
+ }
+ }
+ }
+ return true; // String matches against pattern
+ }
+
+ if (patIdxEnd == 0) {
+ return true; // Pattern contains only '*', which matches anything
+ }
+
+ // Process characters before first star
+ while (true) {
+ ch = patArr[patIdxStart];
+ if (ch == '*' || strIdxStart > strIdxEnd) {
+ break;
+ }
+ if (ch != '?') {
+ if (different(caseSensitive, ch, strArr[strIdxStart])) {
+ return false; // Character mismatch
+ }
+ }
+ patIdxStart++;
+ strIdxStart++;
+ }
+ if (strIdxStart > strIdxEnd) {
+ // All characters in the string are used. Check if only '*'s are
+ // left in the pattern. If so, we succeeded. Otherwise failure.
+ return allStars(patArr, patIdxStart, patIdxEnd);
+ }
+
+ // Process characters after last star
+ while (true) {
+ ch = patArr[patIdxEnd];
+ if (ch == '*' || strIdxStart > strIdxEnd) {
+ break;
+ }
+ if (ch != '?') {
+ if (different(caseSensitive, ch, strArr[strIdxEnd])) {
+ return false; // Character mismatch
+ }
+ }
+ patIdxEnd--;
+ strIdxEnd--;
+ }
+ if (strIdxStart > strIdxEnd) {
+ // All characters in the string are used. Check if only '*'s are
+ // left in the pattern. If so, we succeeded. Otherwise failure.
+ return allStars(patArr, patIdxStart, patIdxEnd);
+ }
+
+ // process pattern between stars. padIdxStart and patIdxEnd point
+ // always to a '*'.
+ while (patIdxStart != patIdxEnd && strIdxStart <= strIdxEnd) {
+ int patIdxTmp = -1;
+ for (int i = patIdxStart + 1; i <= patIdxEnd; i++) {
+ if (patArr[i] == '*') {
+ patIdxTmp = i;
+ break;
+ }
+ }
+ if (patIdxTmp == patIdxStart + 1) {
+ // Two stars next to each other, skip the first one.
+ patIdxStart++;
+ continue;
+ }
+ // Find the pattern between padIdxStart & padIdxTmp in str between
+ // strIdxStart & strIdxEnd
+ int patLength = (patIdxTmp - patIdxStart - 1);
+ int strLength = (strIdxEnd - strIdxStart + 1);
+ int foundIdx = -1;
+ strLoop:
+ for (int i = 0; i <= strLength - patLength; i++) {
+ for (int j = 0; j < patLength; j++) {
+ ch = patArr[patIdxStart + j + 1];
+ if (ch != '?') {
+ if (different(caseSensitive, ch,
+ strArr[strIdxStart + i + j])) {
+ continue strLoop;
+ }
+ }
+ }
+
+ foundIdx = strIdxStart + i;
+ break;
+ }
+
+ if (foundIdx == -1) {
+ return false;
+ }
+
+ patIdxStart = patIdxTmp;
+ strIdxStart = foundIdx + patLength;
+ }
+
+ // All characters in the string are used. Check if only '*'s are left
+ // in the pattern. If so, we succeeded. Otherwise failure.
+ return allStars(patArr, patIdxStart, patIdxEnd);
+ }
+
+ private static boolean allStars(char[] chars, int start, int end) {
+ for (int i = start; i <= end; ++i) {
+ if (chars[i] != '*') {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private static boolean different(
+ boolean caseSensitive, char ch, char other) {
+ return caseSensitive
+ ? ch != other
+ : Character.toUpperCase(ch) != Character.toUpperCase(other);
+ }
+
+}
=====================================
src/main/java/org/apache/tomcat/jakartaee/ManifestConverter.java
=====================================
@@ -0,0 +1,128 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.tomcat.jakartaee;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.jar.Attributes;
+import java.util.jar.JarFile;
+import java.util.jar.Manifest;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * Updates Manifests.
+ */
+public class ManifestConverter implements Converter {
+
+ private static final Logger logger = Logger.getLogger(ManifestConverter.class.getCanonicalName());
+ private static final StringManager sm = StringManager.getManager(ManifestConverter.class);
+
+ @Override
+ public boolean accepts(String filename) {
+ if (JarFile.MANIFEST_NAME.equals(filename)) {
+ return true;
+ }
+
+ // Reject everything else
+ return false;
+ }
+
+ @Override
+ public void convert(String path, InputStream src, OutputStream dest, EESpecProfile profile) throws IOException {
+ Manifest srcManifest = new Manifest(src);
+ Manifest destManifest = new Manifest(srcManifest);
+
+ boolean result = false;
+
+ result = result | removeSignatures(destManifest);
+ result = result | updateValues(destManifest, profile);
+
+ if (result) {
+ destManifest.write(dest);
+ } else {
+ srcManifest.write(dest);
+ }
+ }
+
+
+ private boolean removeSignatures(Manifest manifest) {
+ boolean removedSignatures = manifest.getMainAttributes().remove(Attributes.Name.SIGNATURE_VERSION) != null;
+ List<String> signatureEntries = new ArrayList<>();
+ Map<String, Attributes> manifestAttributeEntries = manifest.getEntries();
+ for (Entry<String, Attributes> entry : manifestAttributeEntries.entrySet()) {
+ if (isCryptoSignatureEntry(entry.getValue())) {
+ String entryName = entry.getKey();
+ signatureEntries.add(entryName);
+ logger.log(Level.FINE, sm.getString("migration.removeSignature", entryName));
+ removedSignatures = true;
+ }
+ }
+
+ for (String entry : signatureEntries) {
+ manifestAttributeEntries.remove(entry);
+ }
+
+ return removedSignatures;
+ }
+
+
+ private boolean isCryptoSignatureEntry(Attributes attributes) {
+ for (Object attributeKey : attributes.keySet()) {
+ if (attributeKey.toString().endsWith("-Digest")) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+
+ private boolean updateValues(Manifest manifest, EESpecProfile profile) {
+ boolean result = false;
+ result = result | updateValues(manifest.getMainAttributes(), profile);
+ for (Attributes attributes : manifest.getEntries().values()) {
+ result = result | updateValues(attributes, profile);
+ }
+ return result;
+ }
+
+
+ private boolean updateValues(Attributes attributes, EESpecProfile profile) {
+ boolean result = false;
+ // Update version info
+ if (attributes.containsKey(Attributes.Name.IMPLEMENTATION_VERSION)) {
+ String newValue = attributes.get(Attributes.Name.IMPLEMENTATION_VERSION) + "-" + Info.getVersion();
+ attributes.put(Attributes.Name.IMPLEMENTATION_VERSION, newValue);
+ result = true;
+ }
+ // Update package names in values
+ for (Entry<Object,Object> entry : attributes.entrySet()) {
+ String newValue = profile.convert((String) entry.getValue());
+ // Object comparison is deliberate
+ if (newValue != entry.getValue()) {
+ entry.setValue(newValue);
+ result = true;
+ }
+ }
+ return result;
+ }
+}
=====================================
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,19 +25,24 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.HashSet;
import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
+import java.util.Set;
import java.util.concurrent.TimeUnit;
-import java.util.jar.Attributes;
import java.util.jar.JarEntry;
-import java.util.jar.JarFile;
-import java.util.jar.JarInputStream;
-import java.util.jar.JarOutputStream;
-import java.util.jar.Manifest;
import java.util.logging.Level;
import java.util.logging.Logger;
-
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipException;
+import java.util.zip.ZipInputStream;
+import java.util.zip.ZipOutputStream;
+
+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;
@@ -45,10 +51,50 @@ public class Migration {
private static final Logger logger = Logger.getLogger(Migration.class.getCanonicalName());
private static final StringManager sm = StringManager.getManager(Migration.class);
+ private static final Set<String> DEFAULT_EXCLUDES = new HashSet<>();
+
+ static {
+ // Apache Commons
+ DEFAULT_EXCLUDES.add("commons-codec-*.jar");
+ DEFAULT_EXCLUDES.add("commons-lang-*.jar");
+ // Apache HTTP Components
+ DEFAULT_EXCLUDES.add("httpclient-*.jar");
+ DEFAULT_EXCLUDES.add("httpcore-*.jar");
+ // ASM
+ DEFAULT_EXCLUDES.add("asm-*.jar");
+ // AspectJ
+ DEFAULT_EXCLUDES.add("aspectjweaver-*.jar");
+ // Bouncy Castle JCE provider
+ DEFAULT_EXCLUDES.add("bcprov*.jar");
+ DEFAULT_EXCLUDES.add("bcpkix*.jar");
+ // Closure compiler
+ DEFAULT_EXCLUDES.add("closure-compiler-*.jar");
+ // Eclipse compiler for Java
+ DEFAULT_EXCLUDES.add("ecj-*.jar");
+ // Hystrix
+ DEFAULT_EXCLUDES.add("hystrix-core-*.jar");
+ DEFAULT_EXCLUDES.add("hystrix-serialization-*.jar");
+ // Jackson
+ DEFAULT_EXCLUDES.add("jackson-annotations-*.jar");
+ DEFAULT_EXCLUDES.add("jackson-core-*.jar");
+ DEFAULT_EXCLUDES.add("jackson-module-afterburner-*.jar");
+ // Logging
+ DEFAULT_EXCLUDES.add("jul-to-slf4j-*.jar");
+ DEFAULT_EXCLUDES.add("log4j-to-slf4j-*.jar");
+ DEFAULT_EXCLUDES.add("slf4j-api-*.jar");
+ // Spring
+ DEFAULT_EXCLUDES.add("spring-aop-*.jar");
+ DEFAULT_EXCLUDES.add("spring-expression-*.jar");
+ DEFAULT_EXCLUDES.add("spring-security-crypto-*.jar");
+ DEFAULT_EXCLUDES.add("spring-security-rsa-*.jar");
+ }
+
private EESpecProfile profile = EESpecProfile.TOMCAT;
+ private boolean zipInMemory;
private File source;
private File destination;
private final List<Converter> converters;
+ private final Set<String> excludes = new HashSet<>();
public Migration() {
// Initialise the converters
@@ -56,6 +102,7 @@ public class Migration {
converters.add(new TextConverter());
converters.add(new ClassConverter());
+ converters.add(new ManifestConverter());
// Final converter is the pass-through converter
converters.add(new PassThroughConverter());
@@ -79,6 +126,14 @@ public class Migration {
return profile;
}
+ public void setZipInMemory(boolean zipInMemory) {
+ this.zipInMemory = zipInMemory;
+ }
+
+ public void addExclude(String exclude) {
+ this.excludes.add(exclude);
+ }
+
public void setSource(File source) {
if (!source.canRead()) {
throw new IllegalArgumentException(sm.getString("migration.cannotReadSource",
@@ -93,113 +148,124 @@ public class Migration {
}
- public boolean execute() throws IOException {
+ public void execute() throws IOException {
logger.log(Level.INFO, sm.getString("migration.execute", source.getAbsolutePath(),
destination.getAbsolutePath(), profile.toString()));
- boolean result = true;
+
long t1 = System.nanoTime();
if (source.isDirectory()) {
if ((destination.exists() && destination.isDirectory()) || destination.mkdirs()) {
- result = result && migrateDirectory(source, destination);
+ migrateDirectory(source, destination);
} else {
- logger.log(Level.WARNING, sm.getString("migration.mkdirError", destination.getAbsolutePath()));
- result = false;
+ throw new IOException(sm.getString("migration.mkdirError", destination.getAbsolutePath()));
}
} else {
// Single file
File parentDestination = destination.getAbsoluteFile().getParentFile();
if (parentDestination.exists() || parentDestination.mkdirs()) {
- result = result && migrateFile(source, destination);
+ migrateFile(source, destination);
} else {
- logger.log(Level.WARNING, sm.getString("migration.mkdirError", parentDestination.getAbsolutePath()));
- result = false;
+ throw new IOException(sm.getString("migration.mkdirError", parentDestination.getAbsolutePath()));
}
}
logger.log(Level.INFO, sm.getString("migration.done",
- Long.valueOf(TimeUnit.MILLISECONDS.convert(System.nanoTime() - t1, TimeUnit.NANOSECONDS)),
- Boolean.valueOf(result)));
- return result;
+ Long.valueOf(TimeUnit.MILLISECONDS.convert(System.nanoTime() - t1, TimeUnit.NANOSECONDS))));
}
- private boolean migrateDirectory(File src, File dest) throws IOException {
- boolean result = true;
+ private void migrateDirectory(File src, File dest) throws IOException {
+ // 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);
File destFile = new File(dest, file);
if (srcFile.isDirectory()) {
if ((destFile.exists() && destFile.isDirectory()) || destFile.mkdir()) {
- result = result && migrateDirectory(srcFile, destFile);
+ migrateDirectory(srcFile, destFile);
} else {
- logger.log(Level.WARNING, sm.getString("migration.mkdirError", destFile.getAbsolutePath()));
- result = false;
+ throw new IOException(sm.getString("migration.mkdirError", destFile.getAbsolutePath()));
}
} else {
- result = result && migrateFile(srcFile, destFile);
+ migrateFile(srcFile, destFile);
}
}
- return result;
}
- private boolean migrateFile(File src, File dest) throws IOException {
- boolean result = false;
-
+ private void migrateFile(File src, File dest) throws IOException {
boolean inplace = src.equals(dest);
if (!inplace) {
try (InputStream is = new FileInputStream(src);
OutputStream os = new FileOutputStream(dest)) {
- result = migrateStream(src.getName(), is, os);
+ migrateStream(src.getName(), is, os);
}
} else {
ByteArrayOutputStream buffer = new ByteArrayOutputStream((int) (src.length() * 1.05));
try (InputStream is = new FileInputStream(src)) {
- result = migrateStream(src.getName(), is, buffer);
+ migrateStream(src.getName(), is, buffer);
}
try (OutputStream os = new FileOutputStream(dest)) {
os.write(buffer.toByteArray());
}
}
-
- return result;
}
- private boolean migrateArchive(InputStream src, OutputStream dest) throws IOException {
- boolean result = true;
- try (JarInputStream jarIs = new JarInputStream(new CloseShieldInputStream(src));
- JarOutputStream jarOs = new JarOutputStream(new CloseShieldOutputStream(dest))) {
- Manifest manifest = jarIs.getManifest();
- if (manifest != null) {
- // Make a safe copy to leave original manifest untouched.
- // Otherwise messing with signatures will fail
- manifest = new Manifest(manifest);
- updateVersion(manifest);
- if (removeSignatures(manifest)) {
- logger.log(Level.WARNING, sm.getString("migration.warnSignatureRemoval"));
- }
- JarEntry manifestEntry = new JarEntry(JarFile.MANIFEST_NAME);
- jarOs.putNextEntry(manifestEntry);
- manifest.write(jarOs);
- }
- JarEntry jarEntry;
- while ((jarEntry = jarIs.getNextJarEntry()) != null) {
- String sourceName = jarEntry.getName();
- logger.log(Level.FINE, sm.getString("migration.entry", sourceName));
+ private void migrateArchiveStreaming(String name, InputStream src, OutputStream dest) throws IOException {
+ try (ZipInputStream zipIs = new ZipInputStream(new CloseShieldInputStream(src));
+ ZipOutputStream zipOs = new ZipOutputStream(new CloseShieldOutputStream(dest))) {
+ ZipEntry zipEntry;
+ while ((zipEntry = zipIs.getNextEntry()) != null) {
+ String sourceName = zipEntry.getName();
if (isSignatureFile(sourceName)) {
- logger.log(Level.FINE, sm.getString("migration.skipSignatureFile", sourceName));
+ logger.log(Level.WARNING, sm.getString("migration.skipSignatureFile", sourceName));
continue;
}
String destName = profile.convert(sourceName);
JarEntry destEntry = new JarEntry(destName);
- jarOs.putNextEntry(destEntry);
- result = result && migrateStream(destEntry.getName(), jarIs, jarOs);
+ zipOs.putNextEntry(destEntry);
+ migrateStream(sourceName, zipIs, zipOs);
+ }
+ } catch (ZipException ze) {
+ logger.log(Level.SEVERE, sm.getString("migration.archiveFailed", name), ze);
+ throw ze;
+ }
+ }
+
+
+ private void migrateArchiveInMemory(InputStream src, OutputStream dest) throws IOException {
+ // Read the source into memory
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ IOUtils.copy(src, baos);
+ baos.flush();
+ 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();
+ if (isSignatureFile(srcName)) {
+ logger.log(Level.WARNING, sm.getString("migration.skipSignatureFile", srcName));
+ continue;
+ }
+ String destName = profile.convert(srcName);
+ RenamableZipArchiveEntry destZipEntry = new RenamableZipArchiveEntry(srcZipEntry);
+ destZipEntry.setName(destName);
+ destZipStream.putArchiveEntry(destZipEntry);
+ migrateStream(srcName, srcZipFile.getInputStream(srcZipEntry), destZipStream);
+ destZipStream.closeArchiveEntry();
}
}
- return result;
+
+ // Write the destination back to the stream
+ ByteArrayInputStream bais = new ByteArrayInputStream(destByteChannel.array(), 0, (int) destByteChannel.size());
+ IOUtils.copy(bais, dest);
}
@@ -209,70 +275,60 @@ 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);
+ private void migrateStream(String name, InputStream src, OutputStream dest) throws IOException {
+ if (isExcluded(name)) {
+ Util.copy(src, dest);
+ logger.log(Level.INFO, sm.getString("migration.skip", name));
+ } else if (isArchive(name)) {
+ if (zipInMemory) {
+ logger.log(Level.INFO, sm.getString("migration.archive.memory", name));
+ migrateArchiveInMemory(src, dest);
+ logger.log(Level.INFO, sm.getString("migration.archive.complete", name));
+ } else {
+ logger.log(Level.INFO, sm.getString("migration.archive.stream", name));
+ migrateArchiveStreaming(name, src, dest);
+ logger.log(Level.INFO, sm.getString("migration.archive.complete", name));
+ }
} else {
- logger.log(Level.FINE, sm.getString("migration.stream", name));
for (Converter converter : converters) {
if (converter.accepts(name)) {
- converter.convert(src, dest, profile);
+ converter.convert(name, src, dest, profile);
break;
}
}
- return true;
}
}
- private boolean removeSignatures(Manifest manifest) {
- boolean removedSignatures = manifest.getMainAttributes().remove(Attributes.Name.SIGNATURE_VERSION) != null;
- List<String> signatureEntries = new ArrayList<>();
- Map<String, Attributes> manifestAttributeEntries = manifest.getEntries();
- for (Entry<String, Attributes> entry : manifestAttributeEntries.entrySet()) {
- if (isCryptoSignatureEntry(entry.getValue())) {
- String entryName = entry.getKey();
- signatureEntries.add(entryName);
- logger.log(Level.FINE, sm.getString("migration.removeSignature", entryName));
- removedSignatures = true;
- }
- }
+ private boolean isArchive(String fileName) {
+ return fileName.endsWith(".jar") || fileName.endsWith(".war") || fileName.endsWith(".zip");
+ }
- for (String entry : signatureEntries) {
- manifestAttributeEntries.remove(entry);
- }
- return removedSignatures;
- }
+ private boolean isExcluded(String name) {
+ File f = new File(name);
+ String filename = f.getName();
+ if (GlobMatcher.matchName(DEFAULT_EXCLUDES, filename, true)) {
+ return true;
+ }
- private boolean isCryptoSignatureEntry(Attributes attributes) {
- for (Object attributeKey : attributes.keySet()) {
- if (attributeKey.toString().endsWith("-Digest")) {
- return true;
- }
+ if (GlobMatcher.matchName(excludes, filename, true)) {
+ return true;
}
+
return false;
}
+ private static class RenamableZipArchiveEntry extends ZipArchiveEntry {
- private void updateVersion(Manifest manifest) {
- updateVersion(manifest.getMainAttributes());
- for (Attributes attributes : manifest.getEntries().values()) {
- updateVersion(attributes);
+ public RenamableZipArchiveEntry(ZipArchiveEntry entry) throws ZipException {
+ super(entry);
}
- }
-
- private void updateVersion(Attributes attributes) {
- if (attributes.containsKey(Attributes.Name.IMPLEMENTATION_VERSION)) {
- String newValue = attributes.get(Attributes.Name.IMPLEMENTATION_VERSION) + "-" + Info.getVersion();
- attributes.put(Attributes.Name.IMPLEMENTATION_VERSION, newValue);
+ @Override
+ public void setName(String name) {
+ super.setName(name);
}
}
-
- private static boolean isArchive(String fileName) {
- return fileName.endsWith(".jar") || fileName.endsWith(".war") || fileName.endsWith(".zip");
- }
}
=====================================
src/main/java/org/apache/tomcat/jakartaee/MigrationCLI.java
=====================================
@@ -20,73 +20,92 @@ import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Iterator;
import java.util.List;
+import java.util.Locale;
import java.util.logging.Level;
import java.util.logging.Logger;
public class MigrationCLI {
- private static final Logger logger = Logger.getLogger(MigrationCLI.class.getCanonicalName());
private static final StringManager sm = StringManager.getManager(MigrationCLI.class);
+ private static final String EXCLUDE_ARG = "-exclude=";
+ private static final String LOGLEVEL_ARG = "-logLevel=";
private static final String PROFILE_ARG = "-profile=";
+ // Will be removed for 1.0.0
+ @Deprecated
+ private static final String VERBOSE_ARG = "-verbose";
+ private static final String ZIPINMEMORY_ARG = "-zipInMemory";
- public static void main(String[] args) {
+ public static void main(String[] args) throws IOException {
+
+ // Defaults
System.setProperty("java.util.logging.SimpleFormatter.format", "%5$s%n");
+ Migration migration = new Migration();
+ // Process argumnets
List<String> arguments = new ArrayList<>(Arrays.asList(args));
- if (arguments.contains("-verbose")) {
- Logger.getGlobal().getParent().getHandlers()[0].setLevel(Level.FINE);
- Logger.getGlobal().getParent().setLevel(Level.FINE);
- arguments.remove("-verbose");
- }
- Migration migration = new Migration();
-
- boolean valid = false;
- String source = null;
- String dest = null;
- if (arguments.size() == 3) {
- if (arguments.get(0).startsWith(PROFILE_ARG)) {
- source = arguments.get(1);
- dest = arguments.get(2);
- valid = true;
+ // Process the custom log level if present
+ // Use an iterator so we can remove the log level argument if found
+ Iterator<String> iter = arguments.iterator();
+ while (iter.hasNext()) {
+ String argument = iter.next();
+ if (argument.startsWith(EXCLUDE_ARG)) {
+ iter.remove();
+ String exclude = argument.substring(EXCLUDE_ARG.length());
+ migration.addExclude(exclude);
+ } else if (argument.startsWith(LOGLEVEL_ARG)) {
+ iter.remove();
+ String logLevelName = argument.substring(LOGLEVEL_ARG.length());
+ Level level = null;
+ try {
+ level = Level.parse(logLevelName.toUpperCase(Locale.ENGLISH));
+ } catch (IllegalArgumentException iae) {
+ invalidArguments();
+ }
+ // Configure the explicit level
+ Logger.getGlobal().getParent().getHandlers()[0].setLevel(level);
+ Logger.getGlobal().getParent().setLevel(level);
+ } else if (argument.startsWith(PROFILE_ARG)) {
+ iter.remove();
+ String profileName = argument.substring(PROFILE_ARG.length());
try {
- migration.setEESpecProfile(EESpecProfile.valueOf(arguments.get(0).substring(PROFILE_ARG.length())));
+ EESpecProfile profile = EESpecProfile.valueOf(profileName.toUpperCase(Locale.ENGLISH));
+ migration.setEESpecProfile(profile);
} catch (IllegalArgumentException e) {
// Invalid profile value
- valid = false;
+ invalidArguments();
+ }
+ } else if (argument.equals(ZIPINMEMORY_ARG)) {
+ iter.remove();
+ migration.setZipInMemory(true);
+ } else if (argument.equals(VERBOSE_ARG)) {
+ iter.remove();
+ // Ignore if LOGLEVEL_ARG has set something different
+ if (Logger.getGlobal().getParent().getLevel().equals(Level.INFO)) {
+ Logger.getGlobal().getParent().getHandlers()[0].setLevel(Level.FINE);
+ Logger.getGlobal().getParent().setLevel(Level.FINE);
}
}
}
- if (arguments.size() == 2) {
- source = arguments.get(0);
- dest = arguments.get(1);
- valid = true;
- }
- if (!valid) {
- usage();
- System.exit(1);
+
+ if (arguments.size() != 2) {
+ invalidArguments();
}
+ String source = arguments.get(0);
+ String dest = arguments.get(1);
+
migration.setSource(new File(source));
migration.setDestination(new File(dest));
- boolean result = false;
- try {
- result = migration.execute();
- } catch (IOException e) {
- logger.log(Level.SEVERE, sm.getString("migration.error"), e);
- result = false;
- }
- // Signal caller that migration failed
- if (!result) {
- System.exit(1);
- }
+ migration.execute();
}
- private static void usage() {
+ private static void invalidArguments() {
System.out.println(sm.getString("migration.usage"));
+ System.exit(1);
}
-
}
=====================================
src/main/java/org/apache/tomcat/jakartaee/MigrationTask.java
=====================================
@@ -32,6 +32,8 @@ public class MigrationTask extends Task {
private File src;
private File dest;
private String profile = EESpecProfile.TOMCAT.toString();
+ private boolean zipInMemory = false;
+ private String excludes;
public void setSrc(File src) {
this.src = src;
@@ -45,6 +47,20 @@ public class MigrationTask extends Task {
this.profile = profile;
}
+ public void setZipInMemory(boolean zipInMemory) {
+ this.zipInMemory = zipInMemory;
+ }
+
+ /**
+ * Set exclusion patterns.
+ *
+ * @param excludes Comma separated, case sensitive list of glob patterns
+ * for files to exclude
+ */
+ public void setExcludes(String excludes) {
+ this.excludes = excludes;
+ }
+
@Override
public void execute() throws BuildException {
// redirect the log messages to Ant
@@ -67,16 +83,18 @@ public class MigrationTask extends Task {
migration.setSource(src);
migration.setDestination(dest);
migration.setEESpecProfile(profile);
+ migration.setZipInMemory(zipInMemory);
+ if (this.excludes != null) {
+ String[] excludes= this.excludes.split(",");
+ for (String exclude : excludes) {
+ migration.addExclude(exclude);
+ }
+ }
- boolean success = false;
try {
- success = migration.execute();
+ migration.execute();
} catch (IOException e) {
throw new BuildException(e, getLocation());
}
-
- if (!success) {
- throw new BuildException("Migration failed", getLocation());
- }
}
}
=====================================
src/main/java/org/apache/tomcat/jakartaee/PassThroughConverter.java
=====================================
@@ -19,9 +19,14 @@ package org.apache.tomcat.jakartaee;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import java.util.logging.Level;
+import java.util.logging.Logger;
public class PassThroughConverter implements Converter {
+ private static final Logger logger = Logger.getLogger(PassThroughConverter.class.getCanonicalName());
+ private static final StringManager sm = StringManager.getManager(PassThroughConverter.class);
+
@Override
public boolean accepts(String filename) {
// Accepts everything
@@ -29,8 +34,11 @@ public class PassThroughConverter implements Converter {
}
@Override
- public void convert(InputStream src, OutputStream dest, EESpecProfile profile) throws IOException {
+ public void convert(String path, InputStream src, OutputStream dest, EESpecProfile profile) throws IOException {
// This simply copies the source to the destination
Util.copy(src, dest);
+ if (logger.isLoggable(Level.FINEST)) {
+ logger.log(Level.FINEST, sm.getString("passThroughConverter.noConversion", path));
+ }
}
}
=====================================
src/main/java/org/apache/tomcat/jakartaee/TextConverter.java
=====================================
@@ -23,9 +23,14 @@ import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
public class TextConverter implements Converter {
+ private static final Logger logger = Logger.getLogger(TextConverter.class.getCanonicalName());
+ private static final StringManager sm = StringManager.getManager(TextConverter.class);
+
private static final List<String> supportedExtensions;
static {
@@ -38,6 +43,8 @@ public class TextConverter implements Converter {
supportedExtensions.add("tld");
supportedExtensions.add("txt");
supportedExtensions.add("xml");
+ supportedExtensions.add("json");
+ supportedExtensions.add("properties");
}
@@ -58,10 +65,21 @@ public class TextConverter implements Converter {
* execution.
*/
@Override
- public void convert(InputStream src, OutputStream dest, EESpecProfile profile) throws IOException {
+ public void convert(String path, InputStream src, OutputStream dest, EESpecProfile profile) throws IOException {
String srcString = Util.toString(src, StandardCharsets.ISO_8859_1);
String destString = profile.convert(srcString);
+ // Object comparison is deliberate here
+ if (srcString == destString) {
+ if (logger.isLoggable(Level.FINEST)) {
+ logger.log(Level.FINEST, sm.getString("classConverter.noConversion", path));
+ }
+ } else {
+ if (logger.isLoggable(Level.FINE)) {
+ logger.log(Level.FINE, sm.getString("textConverter.converted", path));
+ }
+ }
+
ByteArrayInputStream bais = new ByteArrayInputStream(destString.getBytes(StandardCharsets.ISO_8859_1));
Util.copy(bais, dest);
}
=====================================
src/main/resources/org/apache/tomcat/jakartaee/LocalStrings.properties
=====================================
@@ -13,15 +13,41 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-migration.archive=Migrating archive [{0}]
+classConverter.converted=Migrated class [{0}]
+classConverter.noConversion=No conversion necessary for [{0}]
+
+migration.archive.complete=Migration finished for archive [{0}]
+migration.archive.memory=Migration starting for archive [{0}] using in memory copy
+migration.skip=Migration skipped for archive [{0}] because it is excluded (the archive was copied unchanged)
+migration.archive.stream=Migration starting for archive [{0}] using streaming
+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}]
+migration.done=Migration completed successfully in [{0}] milliseconds
migration.error=Error performing migration
migration.execute=Performing migration from source [{0}] to destination [{1}] with Jakarta EE specification profile [{2}]
migration.mkdirError=Error creating destination directory [{0}]
migration.removeSignature=Remove cryptographic signature for [{0}]
+migration.skip=Migration skipped for archive [{0}] because it is excluded (the archive was copied unchanged)
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 [options] <source> <destination>\n\
+where options includes:\n\
+\ -exclude=<glob pattern to exclude>\n\
+\ This option may be used multiple times. Wild cards '*'\n\
+\ and '?' are supported. Matching is case sensitive.\n\
+\ -logLevel=<name of java.util.logging.level enum value>\n\
+\ Useful values are INFO (default), FINE or FINEST\n\
+\ -profile=<profile name>\n\
+\ TOMCAT (default) to convert Java EE APIs provided by Tomcat\n\
+\ EE to convert all Java EE APIs\n\
+\ -zipInMemory\n\
+\ By default zip format archives (.zip, jar, .war, .ear, etc.)\n\
+\ are processed in memory. This is more efficient but is not\n\
+\ compatible with some zip archive structures. If you see an\n\
+\ exception while processing a zip file, enabling this option\n\
+\ may workaround the issue.
migration.warnSignatureRemoval=Removed cryptographic signature from JAR file
+
+passThroughConverter.noConversion=No conversion necessary for [{0}]
+
+textConverter.converted=Migrated text file [{0}]
+textConverter.noConversion=No conversion necessary for [{0}]
=====================================
src/main/scripts/migrate.sh
=====================================
@@ -1,4 +1,6 @@
#!/bin/sh
+BIN_FOLDER=`dirname "$0"`
+
# Assumes java is on the path
-java -cp "../lib/*" org.apache.tomcat.jakartaee.MigrationCLI "$@"
+java -cp "$BIN_FOLDER/../lib/*" org.apache.tomcat.jakartaee.MigrationCLI "$@"
=====================================
src/test/java/org/apache/tomcat/jakartaee/EESpecProfileTest.java
=====================================
@@ -39,27 +39,38 @@ public class EESpecProfileTest {
// not converted EE packages
assertEquals("javax.activation", profile.convert("javax.activation"));
+ assertEquals("javax.batch", profile.convert("javax.batch"));
assertEquals("javax.decorator", profile.convert("javax.decorator"));
assertEquals("javax.enterprise", profile.convert("javax.enterprise"));
+ assertEquals("javax.faces", profile.convert("javax.faces"));
+ assertEquals("javax.jms", profile.convert("javax.jms"));
assertEquals("javax.json", profile.convert("javax.json"));
+ assertEquals("javax.jws", profile.convert("javax.jws"));
assertEquals("javax.interceptor", profile.convert("javax.interceptor"));
assertEquals("javax.inject", profile.convert("javax.inject"));
+ assertEquals("javax.management.j2ee", profile.convert("javax.management.j2ee"));
+ assertEquals("javax.resource", profile.convert("javax.resource"));
+ assertEquals("javax.security.enterprise", profile.convert("javax.security.enterprise"));
+ assertEquals("javax.security.jacc", profile.convert("javax.security.jacc"));
assertEquals("javax.validation", profile.convert("javax.validation"));
assertEquals("javax.ws.rs", profile.convert("javax.ws.rs"));
assertEquals("javax.xml.bind", profile.convert("javax.xml.bind"));
- assertEquals("javax.xml.namespace", profile.convert("javax.xml.namespace"));
assertEquals("javax.xml.rpc", profile.convert("javax.xml.rpc"));
+ assertEquals("javax.xml.registry", profile.convert("javax.xml.registry"));
assertEquals("javax.xml.soap", profile.convert("javax.xml.soap"));
- assertEquals("javax.xml.stream", profile.convert("javax.xml.stream"));
assertEquals("javax.xml.ws", profile.convert("javax.xml.ws"));
- assertEquals("javax.xml.XMLConstants", profile.convert("javax.xml.XMLConstants"));
// non EE javax packages
assertEquals("javax.annotation.processing", profile.convert("javax.annotation.processing"));
+ assertEquals("javax.management", profile.convert("javax.management"));
assertEquals("javax.security", profile.convert("javax.security"));
assertEquals("javax.security.auth", profile.convert("javax.security.auth"));
assertEquals("javax.swing", profile.convert("javax.swing"));
assertEquals("javax.transaction.xa", profile.convert("javax.transaction.xa"));
+ assertEquals("javax.xml.stream", profile.convert("javax.xml.stream"));
+ assertEquals("javax.xml.namespace", profile.convert("javax.xml.namespace"));
+ assertEquals("javax.xml.xpath.XPathConstants", profile.convert("javax.xml.xpath.XPathConstants"));
+ assertEquals("javax.xml.XMLConstants", profile.convert("javax.xml.XMLConstants"));
}
@Test
@@ -68,34 +79,45 @@ public class EESpecProfileTest {
assertEquals("jakarta.activation", profile.convert("javax.activation"));
assertEquals("jakarta.annotation", profile.convert("javax.annotation"));
+ assertEquals("jakarta.batch", profile.convert("javax.batch"));
assertEquals("jakarta.decorator", profile.convert("javax.decorator"));
assertEquals("jakarta.ejb", profile.convert("javax.ejb"));
assertEquals("jakarta.el", profile.convert("javax.el"));
assertEquals("jakarta.enterprise", profile.convert("javax.enterprise"));
+ assertEquals("jakarta.faces", profile.convert("javax.faces"));
+ assertEquals("jakarta.jms", profile.convert("javax.jms"));
assertEquals("jakarta.json", profile.convert("javax.json"));
+ assertEquals("jakarta.jws", profile.convert("javax.jws"));
assertEquals("jakarta.interceptor", profile.convert("javax.interceptor"));
assertEquals("jakarta.inject", profile.convert("javax.inject"));
assertEquals("jakarta.mail", profile.convert("javax.mail"));
+ assertEquals("jakarta.management.j2ee", profile.convert("javax.management.j2ee"));
assertEquals("jakarta.persistence", profile.convert("javax.persistence"));
+ assertEquals("jakarta.resource", profile.convert("javax.resource"));
assertEquals("jakarta.security.auth.message", profile.convert("javax.security.auth.message"));
+ assertEquals("jakarta.security.enterprise", profile.convert("javax.security.enterprise"));
+ assertEquals("jakarta.security.jacc", profile.convert("javax.security.jacc"));
assertEquals("jakarta.servlet", profile.convert("javax.servlet"));
assertEquals("jakarta.transaction", profile.convert("javax.transaction"));
assertEquals("jakarta.validation", profile.convert("javax.validation"));
assertEquals("jakarta.websocket", profile.convert("javax.websocket"));
assertEquals("jakarta.ws.rs", profile.convert("javax.ws.rs"));
assertEquals("jakarta.xml.bind", profile.convert("javax.xml.bind"));
- assertEquals("jakarta.xml.namespace", profile.convert("javax.xml.namespace"));
+ assertEquals("jakarta.xml.registry", profile.convert("javax.xml.registry"));
assertEquals("jakarta.xml.rpc", profile.convert("javax.xml.rpc"));
assertEquals("jakarta.xml.soap", profile.convert("javax.xml.soap"));
- assertEquals("jakarta.xml.stream", profile.convert("javax.xml.stream"));
assertEquals("jakarta.xml.ws", profile.convert("javax.xml.ws"));
- assertEquals("jakarta.xml.XMLConstants", profile.convert("javax.xml.XMLConstants"));
// non EE javax packages
assertEquals("javax.annotation.processing", profile.convert("javax.annotation.processing"));
+ assertEquals("javax.management", profile.convert("javax.management"));
assertEquals("javax.security", profile.convert("javax.security"));
assertEquals("javax.security.auth", profile.convert("javax.security.auth"));
assertEquals("javax.swing", profile.convert("javax.swing"));
assertEquals("javax.transaction.xa", profile.convert("javax.transaction.xa"));
+ assertEquals("javax.xml.stream", profile.convert("javax.xml.stream"));
+ assertEquals("javax.xml.namespace", profile.convert("javax.xml.namespace"));
+ assertEquals("javax.xml.xpath.XPathConstants", profile.convert("javax.xml.xpath.XPathConstants"));
+ assertEquals("javax.xml.XMLConstants", profile.convert("javax.xml.XMLConstants"));
}
}
=====================================
src/test/java/org/apache/tomcat/jakartaee/MigrationTest.java
=====================================
@@ -115,9 +115,8 @@ public class MigrationTest {
Migration migration = new Migration();
migration.setSource(sourceDirectory);
migration.setDestination(destinationDirectory);
- boolean success = migration.execute();
+ migration.execute();
- assertTrue("Migration failed", success);
assertTrue("Destination directory not found", destinationDirectory.exists());
File migratedFile = new File("target/test-classes/migration/HelloServlet.java");
=====================================
src/test/java/org/apache/tomcat/jakartaee/PassThroughConverterTest.java
=====================================
@@ -26,6 +26,8 @@ import static org.junit.Assert.*;
public class PassThroughConverterTest {
+ private static final String TEST_FILENAME = "project.properties";
+
@Test
public void testConverter() throws Exception {
String content = "javax.servlet";
@@ -35,9 +37,9 @@ public class PassThroughConverterTest {
Converter converter = new PassThroughConverter();
- assertTrue(converter.accepts("project.properties"));
+ assertTrue(converter.accepts(TEST_FILENAME));
- converter.convert(in, out, null);
+ converter.convert(TEST_FILENAME, in, out, null);
assertArrayEquals(content.getBytes(), out.toByteArray());
}
=====================================
src/test/java/org/apache/tomcat/jakartaee/TextConverterTest.java
=====================================
@@ -10,6 +10,8 @@ import org.junit.Test;
public class TextConverterTest {
+ private static final String TEST_FILENAME = "text.txt";
+
private static final String INPUT = "javax.servlet.http.HttpServletRequest";
private static final String OUTPUT = "jakarta.servlet.http.HttpServletRequest";
@@ -23,7 +25,7 @@ public class TextConverterTest {
EESpecProfile profile = EESpecProfile.EE;
// test
- converter.convert(in, out, profile);
+ converter.convert(TEST_FILENAME, in, out, profile);
// assert
String result = new String(out.toByteArray(), StandardCharsets.ISO_8859_1);
View it on GitLab: https://salsa.debian.org/java-team/tomcat-jakartaee-migration/-/compare/c4ac1c4a876732702399f45a794b27603b089baf...865db0d4bf871c89b31bc338b2d7316698b855de
--
View it on GitLab: https://salsa.debian.org/java-team/tomcat-jakartaee-migration/-/compare/c4ac1c4a876732702399f45a794b27603b089baf...865db0d4bf871c89b31bc338b2d7316698b855de
You're receiving this email because of your account on salsa.debian.org.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/pkg-java-commits/attachments/20210228/167879cf/attachment.htm>
More information about the pkg-java-commits
mailing list