Author: schor
Date: Tue Jun 7 13:29:34 2016
New Revision: 1747229
URL: http://svn.apache.org/viewvc?rev=1747229&view=rev
Log:
[UIMA-4518] rework reports to use Paths.
switch to built-in directory walkers.
make walkers into Jars work with nested Jars by extracting the nested Jar into
a temporary dir (deleted on exit).
Call the close method on the walkers to insure file handles are released (got
too-many-open-files error otherwise). improve translation in several cases.
correct usage string. add workaround for empty implements bug.
Modified:
uima/uimaj/uimaj-v3migration-jcas/src/main/java/org/apache/uima/migratev3/jcas/MigrateJCas.java
Modified:
uima/uimaj/uimaj-v3migration-jcas/src/main/java/org/apache/uima/migratev3/jcas/MigrateJCas.java
URL:
http://svn.apache.org/viewvc/uima/uimaj/uimaj-v3migration-jcas/src/main/java/org/apache/uima/migratev3/jcas/MigrateJCas.java?rev=1747229&r1=1747228&r2=1747229&view=diff
==============================================================================
---
uima/uimaj/uimaj-v3migration-jcas/src/main/java/org/apache/uima/migratev3/jcas/MigrateJCas.java
(original)
+++
uima/uimaj/uimaj-v3migration-jcas/src/main/java/org/apache/uima/migratev3/jcas/MigrateJCas.java
Tue Jun 7 13:29:34 2016
@@ -24,13 +24,14 @@ import java.io.File;
import java.io.IOException;
import java.io.StringReader;
import java.lang.reflect.Modifier;
-import java.net.URI;
import java.nio.file.FileAlreadyExistsException;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
+import java.nio.file.FileVisitOption;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
+import java.nio.file.StandardCopyOption;
import java.nio.file.StandardOpenOption;
import java.util.ArrayList;
import java.util.Collections;
@@ -40,14 +41,16 @@ import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.stream.Stream;
import org.apache.uima.cas.impl.TypeImpl;
import org.apache.uima.cas.impl.TypeSystemImpl;
import org.apache.uima.cas.impl.UimaDecompiler;
import org.apache.uima.internal.util.CommandLineParser;
-import org.apache.uima.internal.util.Pair;
+import org.apache.uima.internal.util.Misc;
import org.apache.uima.util.FileUtils;
-import org.apache.uima.util.Misc;
import com.github.javaparser.ASTHelper;
import com.github.javaparser.JavaParser;
@@ -128,7 +131,9 @@ public class MigrateJCas extends VoidVis
private static final String OUTPUT_DIRECTORY = "-outputDirectory";
- private static final String SKIP_TYPE_CHECK = "-skip_Type_check";
+ private static final String SKIP_TYPE_CHECK = "-skipTypeCheck";
+
+ private Path tempDir = null;
private boolean isSource = false;
@@ -155,20 +160,114 @@ private String outDirLog;
private CompilationUnit cu;
+ private static abstract class Report2 {
+ public abstract Comparable getFirst(); // Eclipse on linux complained if
not public, was OK on windows
+ public abstract Comparable getSecond();
+ abstract int getFirstLength();
+ }
+
+ private static class PathAndReason extends Report2 {
+ Path path;
+ String reason;
+ PathAndReason(Path path, String reason) {
+ this.path = path;
+ this.reason = reason;
+ }
+ @Override
+ public Comparable<Path> getFirst() { return path; }
+ @Override
+ public Comparable<String> getSecond() { return reason; }
+ @Override
+ int getFirstLength() { return path.toString().length(); }
+ }
+
+ private static class ClassnameAndPath extends Report2 {
+ String classname;
+ Path path;
+ ClassnameAndPath(String classname, Path path) {
+ this.classname = classname;
+ this.path = path;
+ }
+ @Override
+ public Comparable<String> getFirst() { return classname; }
+ @Override
+ public Comparable<Path> getSecond() { return path; }
+ @Override
+ int getFirstLength() { return classname.length(); }
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((classname == null) ? 0 :
classname.hashCode());
+ result = prime * result + ((path == null) ? 0 : path.hashCode());
+ return result;
+ }
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (!(obj instanceof ClassnameAndPath))
+ return false;
+ ClassnameAndPath other = (ClassnameAndPath) obj;
+ if (classname == null) {
+ if (other.classname != null)
+ return false;
+ } else if (!classname.equals(other.classname))
+ return false;
+ if (path == null) {
+ if (other.path != null)
+ return false;
+ } else if (!path.equals(other.path))
+ return false;
+ return true;
+ }
+ }
+
+ private static class String1AndString2 extends Report2 {
+ String s1;
+ String s2;
+ @Override
+ public Comparable<String> getFirst() { return s1; }
+ @Override
+ public Comparable<String> getSecond() { return s2; }
+ @Override
+ int getFirstLength() { return s1.toString().length(); }
+ }
+
+ private static class PathAndPath extends Report2 {
+ Path p1;
+ Path p2;
+ PathAndPath(Path p1, Path p2) {
+ this.p1 = p1;
+ this.p2 = p2;
+ }
+ @Override
+ public Comparable<Path> getFirst() { return p1; }
+ @Override
+ public Comparable<Path> getSecond() { return p2; }
+ @Override
+ int getFirstLength() { return p1.toString().length(); }
+ }
+
/************************************
* Reporting
************************************/
private final List<Path> v2JCasFiles = new ArrayList<>();
private final List<Path> v3JCasFiles = new ArrayList<>();
- private final List<Pair<String, String>> nonJCasFiles = new ArrayList<>();
// path, reason
- private final List<Pair<String, String>> failedMigration = new
ArrayList<>(); // path, reason
- private final List<Pair<String, String>> c2ps = new ArrayList<>();
// class, path
- private final List<Pair<String, String>> extendableBuiltins = new
ArrayList<>(); // class, path
- private final List<Pair<String, String>> nonExtendableBuiltins = new
ArrayList<>(); // class, path
- private final List<Pair<String, String>> nonIdenticalDuplicates = new
ArrayList<>(); // class, path
- private final List<Pair<String, String>> identicalDuplicates = new
ArrayList<>(); // class, path
- private final List<Pair<String, String>> deletedCheckModified = new
ArrayList<>(); // class, deleted check string
- private final List<Pair<String, String>> pathWorkaround = new ArrayList<>();
// original, workaround
+
+ private final List<PathAndReason> nonJCasFiles = new ArrayList<>(); //
path, reason
+ private final List<PathAndReason> failedMigration = new ArrayList<>(); //
path, reason
+ private final List<ClassnameAndPath> c2ps = new ArrayList<>(); //
class, path
+ private final List<ClassnameAndPath> extendableBuiltins = new ArrayList<>();
// class, path
+ private final List<ClassnameAndPath> nonExtendableBuiltins = new
ArrayList<>(); // class, path
+ private final List<ClassnameAndPath> nonIdenticalDuplicates = new
ArrayList<>(); // class, path
+ private final List<ClassnameAndPath> identicalDuplicates = new
ArrayList<>(); // class, path
+ private final List<PathAndReason> deletedCheckModified = new ArrayList<>();
// path, deleted check string
+ private final List<String1AndString2> pathWorkaround = new ArrayList<>(); //
original, workaround
+ private final List<PathAndReason> manualInspection = new ArrayList<>(); //
path, reason
+// private final List<PathAndPath> embeddedJars = new ArrayList<>(); //
source, temp
private boolean v2; // false at start of migrate, set to true if a v2 class
candidate is discovered
private boolean v3; // true at start of migrate, set to false if no
conversion done
@@ -204,6 +303,8 @@ private String outDirLog;
private boolean hasV2Constructors;
private boolean hasV3Constructors;
+ private boolean isSkipTypeCheck = false;
+
public MigrateJCas() {
}
@@ -241,11 +342,12 @@ private String outDirLog;
for (String root : roots) {
System.out.println("Migrating from root: " + root);
int i = 1;
+ System.out.print(" ");
for (Path c : getCandidates(clp, root)) {
System.out.print(".");
- if ((i % 50) == 0) System.out.print("\n " + i);
+ if ((i % 50) == 0) System.out.format("%n%4d",i);
candidate = c;
- String source = getSource();
+ String source = getSource(candidate);
migrate(source);
i++;
}
@@ -257,15 +359,15 @@ private String outDirLog;
return clp.getParamArgument(kind).split("\\" + File.pathSeparator);
}
- private String getSource() {
+ private String getSource(Path path) {
try {
String s;
if (isSource) {
- s = FileUtils.reader2String(Files.newBufferedReader(candidate));
+ s = FileUtils.reader2String(Files.newBufferedReader(path));
// System.out.println("debug read " + s.length());
} else {
// read in bytes and decompile the class to a string
- byte[] b = Files.readAllBytes(candidate);
+ byte[] b = Files.readAllBytes(path);
s = decompile(b);
}
return s;
@@ -314,15 +416,18 @@ private String outDirLog;
StringReader sr = new StringReader(source);
try {
cu = JavaParser.parse(sr, true);
-
+
addImport("org.apache.uima.cas.impl.CASImpl");
addImport("org.apache.uima.cas.impl.TypeImpl");
addImport("org.apache.uima.cas.impl.TypeSystemImpl");
this.visit(cu, null);
new removeEmptyStmts().visit(cu, null);
-
- if (fi_fields.size() > 0) {
+ if (v3) {
+ removeImport("org.apache.uima.jcas.cas.TOP_Type");
+ }
+
+ if (v3 && fi_fields.size() > 0) {
List<BodyDeclaration> classMembers = cu.getTypes().get(0).getMembers();
int positionOfFirstConstructor = findConstructor(classMembers);
if (positionOfFirstConstructor < 0) {
@@ -354,21 +459,18 @@ private String outDirLog;
@Override
public void visit(AnnotationDeclaration n, Object ignore) {
updateClassName(n);
- v3 = false;
super.visit(n, ignore);
}
@Override
public void visit(EmptyTypeDeclaration n, Object ignore) {
updateClassName(n);
- v3 = false;
super.visit(n, ignore);
}
@Override
public void visit(EnumDeclaration n, Object ignore) {
updateClassName(n);
- v3 = false;
super.visit(n, ignore);
}
@@ -441,7 +543,6 @@ private String outDirLog;
return;
}
List<Parameter> ps = n.getParameters();
- Parameter ps0, ps1;
if (ps.size() == 2 &&
getParmTypeName(ps, 0).equals("int") &&
@@ -468,6 +569,9 @@ private String outDirLog;
}
}
+ private final static Pattern refGetter =
Pattern.compile("(ll_getRef(Array)?Value)|"
+ + "(ll_getFSForRef)");
+ private final static Pattern word1 = Pattern.compile("\\A(\\w*)"); // word
chars starting at beginning \\A means beginning
/*****************************
* Method Declaration Visitor
* Heuristic to determine if a feature getter or setter:
@@ -478,6 +582,8 @@ private String outDirLog;
* - for getter: has 0 or 1 arg (1 arg case for indexed getter, arg must
be int type)
* - for setter: has 1 or 2 args
*
+ * Workaround for decompiler - getters which return FSs might be missing
the cast to the return value type
+ *
*****************************/
@Override
public void visit(MethodDeclaration n, Object ignore) {
@@ -501,25 +607,46 @@ private String outDirLog;
}
// get the range-part-name and convert to v3 range ("Ref" changes to
"Feature")
- String s = n.getBody().toStringWithoutComments();
- int i = s.indexOf("jcasType.ll_cas.ll_");
+ String bodyString = n.getBody().toStringWithoutComments();
+ int i = bodyString.indexOf("jcasType.ll_cas.ll_");
if (i < 0) break;
- s = s.substring(i + "jcasType.ll_cas.ll_get".length());
+ String s = bodyString.substring(i +
"jcasType.ll_cas.ll_get".length()); // also for ...ll_set - same length!
if (s.startsWith("FSForRef(")) { // then it's the wrapper and the
wrong instance.
i = s.indexOf("jcasType.ll_cas.ll_");
- if (i < 0) throw new RuntimeException();
+ if (i < 0) {
+ reportUnrecognizedV2Code("Found \"jcasType.ll_cas.ll_[set or
get]...FSForRef(\" but didn't find following \"jcasType.ll_cas_ll_\"\n" +
n.toString());
+ break;
+ }
s = s.substring(i + "jcasType.ll_cas.ll_get".length());
}
i = s.indexOf("Value");
if (i < 0) {
- reportUnrecognizedV2Code(s);
+ reportUnrecognizedV2Code("Found \"jcasType.ll_cas.ll_[set or get]\"
but didn't find following \"Value\"\n" + n.toString());
break; // give up
}
s = Character.toUpperCase(s.charAt(0)) + s.substring(1, i);
rangeNameV2Part = s;
rangeNamePart = s.equals("Ref") ? "Feature" : s;
- featName = Character.toLowerCase(name.charAt(3)) + name.substring(4);
+ // get feat name following ")jcasType).casFeatCode_xxxxx,
+ i = bodyString.indexOf("jcasType).casFeatCode_");
+ if (i == -1) {
+ reportUnrecognizedV2Code("Didn't find
\"...jcasType).casFeatCode_\"\n" + n.toString());
+ break;
+ }
+ Matcher m = word1.matcher(bodyString.substring(i +
"jcasType).casFeatCode_".length() ));
+ if (!m.find()) {
+ reportUnrecognizedV2Code("Found \"...jcasType).casFeatCode_\" but
didn't find subsequent word\n" + n.toString());
+ break;
+ }
+ featName = m.group(1);
+ String fromMethod = Character.toLowerCase(name.charAt(3)) +
name.substring(4);
+ if (!featName.equals(fromMethod)) {
+ // don't report if the only difference is the first letter
captialization
+ if (!(Character.toLowerCase(featName.charAt(0)) +
featName.substring(1)).equals(fromMethod)) {
+ reportMismatchedFeatureName(String.format("%-25s %s", featName,
name));
+ }
+ }
List<Expression> args = Collections.singletonList(new
StringLiteralExpr(featName));
VariableDeclarator vd = new VariableDeclarator(
@@ -531,6 +658,29 @@ private String outDirLog;
ASTHelper.INT_TYPE,
vd));
}
+
+ /**
+ * add missing cast stmt for
+ * return stmts where the value being returned:
+ * - doesn't have a cast already
+ * - has the expression be a methodCallExpr with a name which looks
like:
+ * ll_getRefValue or
+ * ll_getRefArrayValue
+ */
+ if (isGetter && "Feature".equals(rangeNamePart)) {
+ for (Statement stmt : n.getBody().getStmts()) {
+ if (stmt instanceof ReturnStmt) {
+ Expression e = getUnenclosedExpr(((ReturnStmt)stmt).getExpr());
+ if ((e instanceof MethodCallExpr)) {
+ String methodName = ((MethodCallExpr)e).getName();
+ if (refGetter.matcher(methodName).matches()) { //
ll_getRefValue or ll_getRefArrayValue
+ addCastExpr(stmt, n.getType());
+ }
+ }
+ }
+ }
+ }
+
get_set_method = n; // used as a flag during inner "visits" to signal
// we're inside a likely feature setter/getter
@@ -540,20 +690,19 @@ private String outDirLog;
super.visit(n, ignore);
get_set_method = null; // after visiting, reset the get_set_method to null
}
-
+
/**
* Visitor for if stmts
- * - remove feature missing test
+ * - removes feature missing test
*/
@Override
public void visit(IfStmt n, Object ignore) {
do {
- if (get_set_method == null) break;
+ // if (get_set_method == null) break; // sometimes, these occur outside
of recogn. getters/setters
Expression c = n.getCondition(), e;
- BinaryExpr be, be2;
+ BinaryExpr be, be2;
List<Statement> stmts;
-
if ((c instanceof BinaryExpr) &&
((be = (BinaryExpr)c).getLeft() instanceof FieldAccessExpr) &&
((FieldAccessExpr)be.getLeft()).getField().equals("featOkTst")) {
@@ -563,12 +712,10 @@ private String outDirLog;
if (! (be.getRight() instanceof BinaryExpr)
|| ! ((be2 = (BinaryExpr)be.getRight()).getRight() instanceof
NullLiteralExpr)
|| ! (be2.getLeft() instanceof FieldAccessExpr)
- || ! (n.getThenStmt() instanceof BlockStmt)
- || ! ((stmts = ((BlockStmt)n.getThenStmt()).getStmts()).size() == 1)
- || ! (stmts.get(0) instanceof ExpressionStmt)
- || ! ((e = ((ExpressionStmt)stmts.get(0)).getExpression()) instanceof
MethodCallExpr)
+
+ || ! ((e = getExpressionFromStmt(n.getThenStmt())) instanceof
MethodCallExpr)
|| ! (((MethodCallExpr)e).getName()).equals("throwFeatMissing")) {
- reportDeletedCheckModified("The featOkTst was modified:\n" +
n.toString());
+ reportDeletedCheckModified("The featOkTst was modified:\n" +
n.toString() + '\n');
}
BlockStmt parent = (BlockStmt) n.getParentNode();
@@ -624,6 +771,7 @@ private String outDirLog;
String s = n.getName().substring(z.length());
s = s.substring(0, s.length() - "Value".length()); // s =
"ShortArray", etc.
if (s.equals("RefArray")) s = "FSArray";
+ if (s.equals("IntArray")) s = "IntegerArray";
EnclosedExpr ee = new EnclosedExpr(
new CastExpr(new ClassOrInterfaceType(s), n.getArgs().get(0)));
@@ -660,14 +808,15 @@ private String outDirLog;
public void visit(FieldAccessExpr n, Object ignore) {
Expression e;
- if (get_set_method != null) {
+ if (get_set_method != null) {
if (n.getField().startsWith("casFeatCode_") &&
((e = getUnenclosedExpr(n.getScope())) instanceof CastExpr) &&
("jcasType".equals(getName(((CastExpr)e).getExpr())))) {
- replaceInParent(n, new NameExpr("_FI_" + featName)); // repl last in
List<Expression> (args)
+ String featureName = n.getField().substring("casFeatCode_".length());
+ replaceInParent(n, new NameExpr("_FI_" + featureName)); // repl last
in List<Expression> (args)
return;
} else if (n.getField().startsWith("casFeatCode_")) {
- System.out.println("debug");
+ reportMigrateFailed("Found field casFeatCode_ ... without a previous
cast expr using jcasType");
}
}
super.visit(n, ignore);
@@ -707,7 +856,7 @@ private String outDirLog;
*
*/
private void report() {
- System.out.format("Migration Summary. Using input from %s files%n",
isSource ? ".java" : ".class");
+ System.out.format("%n%nMigration Summary. Using input from %s files%n",
isSource ? ".java" : ".class");
System.out.format("Output top directory: %s%n", outputDirectory);
System.out.format("Date/time: %tc%n", new Date());
System.out.println(" Roots:");
@@ -719,6 +868,7 @@ private String outDirLog;
try {
reportPaths("Workaround Directories", "workaroundDir", pathWorkaround);
reportPaths("Report of converted files where a deleted check was
customized", "deletedCheckModified", deletedCheckModified);
+ reportPaths("Report of converted files needing manual inspection",
"manualInspection", manualInspection);
reportPaths("Report of files which failed migration", "failed.txt",
failedMigration);
reportPaths("Report of non-JCas files", "NonJCasFiles.txt",
nonJCasFiles);
reportPaths("Builtin Extendable JCas classes - skipped - need manual
checking to see if they are modified",
@@ -736,15 +886,15 @@ private String outDirLog;
}
private void computeDuplicates() {
- List<Pair<String, String>> toCheck = new ArrayList<>(c2ps);
+ List<ClassnameAndPath> toCheck = new ArrayList<>(c2ps);
toCheck.addAll(extendableBuiltins);
- sortPairs(toCheck);
- Pair<String, String> prevP = new Pair<>("","");
- List<Pair<String, String>> sameList = new ArrayList<>();
+ sortReport2(toCheck);
+ ClassnameAndPath prevP = new ClassnameAndPath(null, null);
+ List<ClassnameAndPath> sameList = new ArrayList<>();
boolean areAllEqual = true;
- for (Pair<String, String> p : toCheck) {
- if (!p.t.equals(prevP.t)) {
+ for (ClassnameAndPath p : toCheck) {
+ if (!p.getFirst().equals(prevP.getFirst())) {
addToIdenticals(sameList, areAllEqual);
sameList.clear();
@@ -760,7 +910,7 @@ private String outDirLog;
}
sameList.add(p);
if (areAllEqual) {
- if (filesMiscompare(p.u, prevP.u)) {
+ if (isFilesMiscompare(p.path, prevP.path)) {
areAllEqual = false;
}
}
@@ -769,19 +919,19 @@ private String outDirLog;
addToIdenticals(sameList, areAllEqual);
}
- private boolean filesMiscompare(String sp1, String sp2) {
- Path p1 = Paths.get(sp1);
- Path p2 = Paths.get(sp2);
- try {
- String s1 = FileUtils.reader2String(Files.newBufferedReader(p1));
- String s2 = FileUtils.reader2String(Files.newBufferedReader(p2));
+ /**
+ * Compare two java source or class files
+ * @param p1
+ * @param p2
+ * @return
+ */
+ private boolean isFilesMiscompare(Path p1, Path p2) {
+ String s1 = getSource(p1);
+ String s2 = getSource(p2);
return !s1.equals(s2);
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
}
- private void addToIdenticals(List<Pair<String, String>> sameList, boolean
areAllEqual) {
+ private void addToIdenticals(List<ClassnameAndPath> sameList, boolean
areAllEqual) {
if (sameList.size() > 0) {
if (areAllEqual) {
identicalDuplicates.addAll(sameList);
@@ -809,7 +959,7 @@ private String outDirLog;
return p;
}
- private void reportPaths(String title, String fileName, List<Pair<String,
String>> items) throws IOException {
+ private void reportPaths(String title, String fileName, List<? extends
Report2> items) throws IOException {
if (items.size() == 0) {
System.out.println("No " + title);
return;
@@ -819,17 +969,25 @@ private String outDirLog;
System.out.println("");
try (BufferedWriter bw = Files.newBufferedWriter(makePath(outDirLog +
fileName), StandardOpenOption.CREATE)) {
- List<Pair<String, String>> sorted = new ArrayList<>(items);
+ List<Report2> sorted = new ArrayList<>(items);
- sortPairs(sorted);
+ sortReport2(sorted);
int max = 0;
- for (Pair<String, String> p : sorted) {
- max = Math.max(max, p.t.length());
+ for (Report2 p : sorted) {
+ max = Math.max(max, p.getFirstLength());
}
int i = 1;
- for (Pair<String, String> p : sorted) {
- String s = String.format("%5d %-" +max+ "s %s%n", i, p.t, p.u);
+ for (Report2 p : sorted) {
+ Object v = p.getSecond();
+ if (v instanceof Path) {
+ Path path = (Path) v;
+ FileSystem fileSystem = path.getFileSystem();
+ if (fileSystem instanceof com.sun.nio.zipfs.ZipFileSystem) {
+ v = v.toString() + "\t\t " + fileSystem.toString();
+ }
+ }
+ String s = String.format("%5d %-" +max+ "s %s%n", i, p.getFirst(), v);
bw.write(s);
System.out.print(s);
i++;
@@ -837,39 +995,46 @@ private String outDirLog;
System.out.println("");
} // end of try-with-resources
}
-
- private void sortPairs(List<Pair<String, String>> items) {
- Collections.sort(items, new Comparator<Pair<String, String>>() {
- @Override
- public int compare(Pair<String, String> o1, Pair<String, String> o2) {
- int r = o1.t.compareTo(o2.t);
- if (r == 0) {
- r = o1.u.compareTo(o2.u);
- }
- return r;
- }
- });
+
+ private void sortReport2(List<? extends Report2> items) {
+ Collections.sort(items,
+ (o1, o2) -> {
+ int r = o1.getFirst().compareTo(o2.getFirst());
+ if (r == 0) {
+ r = o1.getSecond().compareTo(o2.getSecond());
+ }
+ return r;
+ });
}
-
+
/**
* Walk the directory tree rooted at root
* - descend subdirectories
* - descend Jar file
+ * -- descend nested Jar files (!)
+ * by extracting these to a temp dir, and keeping a back reference to
where they were extracted from.
+ *
* output the paths representing the classes
* -- for non-jars:
* file:/c:/data/test.class
* -- for Jars:
* jar:file:/c:/data/test.jar!/path/to/file
* @param root
- * @return
+ * @return list of Paths
* @throws IOException
*/
private List<Path> getCandidates(CommandLineParser clp, String root) {
- boolean skip_Type_check = clp.isInArgsList(SKIP_TYPE_CHECK);
+ isSkipTypeCheck = clp.isInArgsList(SKIP_TYPE_CHECK);
Path startPath = Paths.get(root);
candidates = new ArrayList<>();
- getCandidates_processCandidate(startPath);
+ try (Stream<Path> stream = Files.walk(startPath,
FileVisitOption.FOLLOW_LINKS)) { // needed to release file handles
+ stream.forEachOrdered(
+ p -> getCandidates_processFile(p));
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+
Collections.sort(candidates, pathComparator);
List<Path> c = new ArrayList<>(); // candidates
@@ -878,7 +1043,7 @@ private String outDirLog;
return c;
}
for (int i = 0; i < nbrOfPaths;) {
- if (skip_Type_check) {
+ if (isSkipTypeCheck) {
candidate = candidates.get(i);
if (candidate.getFileName().endsWith(isSource ? "_Type.java" :
"_Type.class")) {
continue; // skip the _Type files
@@ -886,9 +1051,10 @@ private String outDirLog;
c.add(candidate);
i++;
} else {
- int next_Type = indexOf_Type(i);
+ // doing _Type check: only include java files if there's an associated
_Type file
+ int next_Type = indexOf_Type(i); // look for the next _Type file
starting at position i
if (next_Type == -1) {
- System.out.println("debug getCandidates retuning:");
+// System.out.println("debug getCandidates returning because doing
_Type checking and no further _Types");
for (Path x : c) {
System.out.println("debug " + x);
}
@@ -930,16 +1096,38 @@ private String outDirLog;
}
}
+
+ /**
+ * adds all the .java or .class files to the candidates, including _Type if
not skipping the _Type check
+ * Handling embedded jar files
+ * - single level Jar (at the top level of the default file system)
+ * -- handle using an overlayed file system
+ * - embedded Jars within Jars:
+ * - not supported by Zip File System Provider (it only supports one
level)
+ * - handle by extracting to a temp dir, and then using the Zip File
System Provider
+ * @param path
+ */
private void getCandidates_processFile(Path path) {
// System.out.println("debug processing " + path);
try {
- URI pathUri = path.toUri();
- String pathString = pathUri.toString();
- if (pathString.endsWith(".jar")) {
+// URI pathUri = path.toUri();
+ String pathString = path.toString();
+ if (pathString.endsWith(".jar")) { // path.endsWith does mean this !!
+ if (!path.getFileSystem().equals(FileSystems.getDefault())) {
+ // embedded Jar: extract to temp
+ Path out = getTempOutputPath(path);
+ Files.copy(path, out, StandardCopyOption.REPLACE_EXISTING);
+// embeddedJars.add(new PathAndPath(path, out));
+ path = out;
+ }
FileSystem jfs = FileSystems.newFileSystem(path, null);
Path start = jfs.getPath("/");
- getCandidates_DescendDirectory(start);
+ try (Stream<Path> stream = Files.walk(start)) { // needed to release
file handles
+ stream.forEachOrdered(
+ p -> getCandidates_processFile(p));
+ }
} else {
+ // is not a .jar file. see if it's a jcas file
// System.out.println("debug path ends with java or class " +
pathString.endsWith(isSource ? ".java" : ".class") + " " + pathString);
if (pathString.endsWith(isSource ? ".java" : ".class")) {
candidates.add(path);
@@ -950,22 +1138,20 @@ private String outDirLog;
}
}
- private void getCandidates_DescendDirectory(Path path) {
- try {
- Files.list(path).forEach(p -> getCandidates_processCandidate(p));
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
+ private Path getTempOutputPath(Path path) throws IOException {
+ Path localTempDir = getTempDir();
+ Path tempFile = Files.createTempFile(localTempDir,
path.getFileName().toString(), ".jar");
+ tempFile.toFile().deleteOnExit();
+ return tempFile;
}
- private void getCandidates_processCandidate(Path p) {
- if (Files.isDirectory(p)) {
- getCandidates_DescendDirectory(p);
- } else {
- getCandidates_processFile(p);
+ private Path getTempDir() throws IOException {
+ if (tempDir == null) {
+ tempDir = Files.createTempDirectory("migrateJCas");
+ tempDir.toFile().deleteOnExit();
}
- }
-
+ return tempDir;
+ }
private int indexOf_Type(int start) {
int i = start;
@@ -1032,6 +1218,17 @@ private String outDirLog;
private void addImport(String s) {
cu.getImports().add(new ImportDeclaration(new NameExpr(s), false, false));
}
+
+ private void removeImport(String s) {
+ Iterator<ImportDeclaration> it = cu.getImports().iterator();
+ while (it.hasNext()) {
+ ImportDeclaration impDcl = it.next();
+ if (impDcl.getName().toString().equals(s)) {
+ it.remove();
+ break;
+ }
+ }
+ }
/******************
* AST Utilities
@@ -1173,13 +1370,6 @@ private String outDirLog;
Misc.internalError(); return null;
}
- private Expression getUnenclosedExpr(Expression e) {
- while (e instanceof EnclosedExpr) {
- e = ((EnclosedExpr)e).getInner();
- }
- return e;
- }
-
/**
* Get the name of a field
* @param e -
@@ -1208,18 +1398,57 @@ private String outDirLog;
TypeImpl ti =
TypeSystemImpl.staticTsi.getType(Misc.javaClassName2UimaTypeName(packageAndClassName));
if (null != ti) {
// is a built-in type
- Pair<String, String> p = new Pair<String,
String>(packageAndClassNameSlash, candidate.toString());
+ ClassnameAndPath p = new ClassnameAndPath(packageAndClassNameSlash,
candidate);
if (!ti.isFeatureFinal()) {
extendableBuiltins.add(p);
} else {
nonExtendableBuiltins.add(p);
}
- v3 = false;
- return; // skip further processing of this class
+ v3 = false; // skip further processing of this class
+ return;
}
- c2ps.add(new Pair<String, String>(packageAndClassNameSlash,
candidate.toString()));
+ c2ps.add(new ClassnameAndPath(packageAndClassNameSlash, candidate));
+ return;
+ }
+ return;
+ }
+
+ private Expression getExpressionFromStmt(Statement stmt) {
+ stmt = getStmtFromStmt(stmt);
+ if (stmt instanceof ExpressionStmt) {
+ return getUnenclosedExpr(((ExpressionStmt)stmt).getExpression());
+ }
+ return null;
+ }
+
+ private Expression getUnenclosedExpr(Expression e) {
+ while (e instanceof EnclosedExpr) {
+ e = ((EnclosedExpr)e).getInner();
}
+ return e;
+ }
+
+ /**
+ * Unwrap (possibly nested) 1 statement blocks
+ * @param stmt -
+ * @return unwrapped (non- block) statement
+ */
+ private Statement getStmtFromStmt(Statement stmt) {
+ while (stmt instanceof BlockStmt) {
+ List<Statement> stmts = ((BlockStmt) stmt).getStmts();
+ if (stmts.size() == 1) {
+ stmt = stmts.get(0);
+ continue;
+ }
+ return null;
+ }
+ return stmt;
+ }
+
+ private void addCastExpr(Statement stmt, Type castType) {
+ ReturnStmt rstmt = (ReturnStmt) stmt;
+ rstmt.setExpr(new CastExpr(castType, rstmt.getExpr()));
}
/********************
@@ -1235,7 +1464,7 @@ private String outDirLog;
}
private void migrationFailed(String reason) {
- failedMigration.add(new Pair<String, String>(candidate.toString(),
reason));
+ failedMigration.add(new PathAndReason(candidate, reason));
v3 = false;
}
@@ -1255,7 +1484,7 @@ private String outDirLog;
}
private void reportNotJCasClass(String reason) {
- nonJCasFiles.add(new Pair<String, String>(candidate.toString(), reason));
+ nonJCasFiles.add(new PathAndReason(candidate, reason));
v3 = false;
}
@@ -1264,11 +1493,15 @@ private String outDirLog;
}
private void reportDeletedCheckModified(String m) {
- deletedCheckModified.add(new Pair<>(candidate.toString(), m));
+ deletedCheckModified.add(new PathAndReason(candidate, m));
+ }
+
+ private void reportMismatchedFeatureName(String m) {
+ manualInspection.add(new PathAndReason(candidate, "This getter/setter name
doesn't match internal feature name: " + m));
}
private void reportUnrecognizedV2Code(String m) {
- migrationFailed("V2 code not recognized: " + m);
+ migrationFailed("V2 code not recognized:\n" + m);
}
private void reportPathWorkaround(String orig, String modified) {
@@ -1297,17 +1530,24 @@ private String outDirLog;
private void writeV3(String data) throws IOException {
String base = getBaseOutputPath(true, false); // adds numeric suffix if
dupls
+ data = fixImplementsBug(data);
FileUtils.writeToFile(makePath(base), data);
}
private void printUsage() {
System.out.println(
"Usage: java org.apache.uima.migratev3.jcas.MigrateJCas \n"
- + " [-sourcesRoots
<One-or-more-directories-separated-by-Path-separator>] [-desc
<XmlDescriptor>]\n"
- + " [-classesRoots
<One-or-more-directories-separated-by-Path-separator>]\n"
+ + " [-sourcesRoots
<One-or-more-directories-or-jars-separated-by-Path-separator>]\n"
+ + " [-classesRoots
<One-or-more-directories-or-jars-separated-by-Path-separator>]\n"
+ " [-outputDirectory a-writable-directory-path\n"
+ + " [-skipTypeCheck if specified, skips validing a found item by
looking for the corresponding _Type file"
+ " NOTE: either -sourcesRoots or -classesRoots is required, but only
one may be specified.\n"
+ + " NOTE: classesRoots are scanned for JCas classes, which are then
decompiled, and the results processed like sourcesRoots\n"
+ " NOTE: -outputDirectory is required\n");
}
+ private static final Pattern implementsEmpty = Pattern.compile("implements
\\{");
+ private String fixImplementsBug(String data) {
+ return implementsEmpty.matcher(data).replaceAll("{");
+ }
}