Author: schor
Date: Thu Jun 16 17:29:38 2016
New Revision: 1748765
URL: http://svn.apache.org/viewvc?rev=1748765&view=rev
Log:
[UIMA-4518] improve finding candidates, improve duplicate handling, avoid
recomputing identical inputs, support individual class migration, improve use
of and clarity around classpath
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=1748765&r1=1748764&r2=1748765&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
Thu Jun 16 17:29:38 2016
@@ -24,6 +24,7 @@ import java.io.File;
import java.io.IOException;
import java.io.StringReader;
import java.lang.reflect.Modifier;
+import java.net.URLClassLoader;
import java.nio.file.FileAlreadyExistsException;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
@@ -34,13 +35,18 @@ import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.nio.file.StandardOpenOption;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
+import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
import java.util.Set;
+import java.util.TreeMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Stream;
@@ -96,13 +102,14 @@ import com.github.javaparser.ast.type.Ty
import com.github.javaparser.ast.visitor.VoidVisitorAdapter;
/**
- * A driver that scans given roots for source and/or class Java files that
contain
- * JCas classes
+ * A driver that scans given roots for source and/or class Java files that
contain JCas classes
*
* - identifies which ones appear to be JCas classes (heuristic)
* -- identifies which ones appear to be v2
* --- converts these to v3
*
+ * - also can receive a list of individual class names
+ *
* Creates summary and detailed reports of its actions.
*
* Outputs converted files to an output file tree.
@@ -111,17 +118,41 @@ import com.github.javaparser.ast.visitor
*
* Directory structure, starting at -outputDirectory
* converted/
- * x/y/z/javapath/.../Classname.java
- * x/y/z/javapath/.../Classname.javav2Orig
- * x/y/z/javapath/.../Classname.java1 // for duplicates
- * x/y/z/javapath/.../Classname.java1v2Orig
+ * v2/
+ * x/y/z/javapath/.../Classname.java
+ * x/y/z/javapath/.../Classname.java
+ * ...
+ * v3/
+ * x/y/z/javapath/.../Classname.java
+ * x/y/z/javapath/.../Classname.java
+ * ...
+ * 1/ << for duplicates, each set is
for identical dups, different sets for non-identical
+ * x/y/z/javapath/.../Classname.java << for duplicates, each set is
for identical dups, different sets for non-identical
+ * x/y/z/javapath/.../Classname.java << for duplicates, each set is
for identical dups, different sets for non-identical
+ * ...
+ * 2/ << for duplicates, each set is
for identical dups, different sets for non-identical
+ * x/y/z/javapath/.../Classname.java << for duplicates, each set is
for identical dups, different sets for non-identical
+ * x/y/z/javapath/.../Classname.java << for duplicates, each set is
for identical dups, different sets for non-identical
+ * ...
+ *
* not-converted/
- * log/
- * converted/
- * not-converted/
- * duplicates/
- * classname-to-sourcepath.csv // includes Classname.java1 etc.
+ * logs/
+ * processed.txt
+ * builtinsNotExtended.txt
+ * ...
*
+ * Operates in one of two modes:
+ * Mode 1: Given classes-roots and/or individual class names, and a
classpath,
+ * scans the classes-routes looking for classes candidates, or iterate
through the individual class names
+ * - determines the class name,
+ * - looks up the right "version" in the provided classpath, and
decompiles that
+ * - migrates that decompiled source.
+ * -- duplicates are also processed. If different they are put into
v3/nnn/etc.
+ *
+ * Mode 2: Given sources-roots
+ * Duplicates are migrated, results are put into a v3/nnn/
rest-of-path-identical
+ *
+ * Note: Each run clears the output directory before starting the migration.
*/
public class MigrateJCas extends VoidVisitorAdapter<Object> {
@@ -133,6 +164,10 @@ public class MigrateJCas extends VoidVis
private static final String SKIP_TYPE_CHECK = "-skipTypeCheck";
+ private static final String MIGRATE_CLASSPATH = "-migrateClasspath";
+
+ private static final String CLASSES = "-classes"; // individual classes to
migrate, get from supplied classpath
+
private Path tempDir = null;
private boolean isSource = false;
@@ -144,7 +179,7 @@ public class MigrateJCas extends VoidVis
private String className; // (omitting package)
private String packageAndClassNameSlash;
private final Set<String> usedPackageAndClassNames = new HashSet<>();
- private String currentPackageAndClassNameSlash;
+ private int packageAndClassNameSlash_i;
/** includes trailing / */
private String outputDirectory;
@@ -153,104 +188,44 @@ public class MigrateJCas extends VoidVis
/** includes trailing / */
private String outDirSkipped;
/** includes trailing / */
-private String outDirLog;
+ private String outDirLog;
private String[] roots;
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 ClassLoader migrateClassLoader = null;
- 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 String migrateClasspath = null;
- 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;
+ private String individualClasses = null; // to decompile
+
+ private class ConvertedSource {
+ String rOrigSource; // remembered original source
+ byte[] rOrigBytes; // remembered original bytes
+ List<Path> paths;
+ ConvertedSource(String origSource, byte[] origBytes, Path path) {
+ this.rOrigSource = origSource;
+ this.rOrigBytes = origBytes;
+ paths = new ArrayList<>();
+ add(path);
}
- @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;
+
+ void add(Path path) {
+ paths.add(path);
}
}
- 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(); }
- }
+ /**
+ * A map from classnames (fully qualified, with slashes) to a list of
converted sources
+ * one per non-duplicated source
+ */
+ private Map<String, List<ConvertedSource>> classname2multiSources = new
TreeMap<>();
+ private Map<byte[], String> origBytesToClassName = new HashMap<>();
+ private Map<String, String> origSourceToClassName = new HashMap<>();
+
/************************************
* Reporting
************************************/
@@ -262,8 +237,8 @@ private String outDirLog;
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<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
@@ -305,6 +280,10 @@ private String outDirLog;
private boolean isSkipTypeCheck = false;
+
+ private byte[] origBytes; // set by getSource()
+ private String origSource; // set by getSource()
+ private String alreadyDone; // the slashifiedClassName
public MigrateJCas() {
}
@@ -334,7 +313,7 @@ private String outDirLog;
} else {
printUsage();
System.exit(2);
- }
+ }
// clear output dir
FileUtils.deleteRecursive(new File(outputDirectory));
@@ -344,14 +323,28 @@ private String outDirLog;
int i = 1;
System.out.print(" ");
for (Path c : getCandidates(clp, root)) {
- System.out.print(".");
- if ((i % 50) == 0) System.out.format("%n%4d",i);
- candidate = c;
- String source = getSource(candidate);
+ String source = prepare(c);
+ migrate(source);
+ if ((i % 50) == 0) System.out.format("%n%4d", Integer.valueOf(i));
+ i++;
+ }
+ System.out.println("");
+ }
+
+ if (individualClasses != null) {
+ String[] cn = individualClasses.split(File.pathSeparator);
+ System.out.println("Migrating individual classes: " );
+ int i = 1;
+ System.out.print(" ");
+ for (String classname : cn) {
+ String source = prepareIndividual(classname);
migrate(source);
+ if ((i % 50) == 0) System.out.format("%n%4d", Integer.valueOf(i));
i++;
}
+ System.out.println("");
}
+
report();
}
@@ -359,18 +352,35 @@ private String outDirLog;
return clp.getParamArgument(kind).split("\\" + File.pathSeparator);
}
+ /**
+ * If working with .class files:
+ * - read the byte array
+ * - see if it has already been decompiled; if so, return false
+ *
+ * Side effect, set origSource and origBytes and alreadyDone
+ * @param path
+ * @return the source to maybe migrate
+ */
private String getSource(Path path) {
try {
- String s;
+ origSource = null;
+ origBytes = null;
if (isSource) {
- s = FileUtils.reader2String(Files.newBufferedReader(path));
+ origSource = FileUtils.reader2String(Files.newBufferedReader(path));
+ alreadyDone = origSourceToClassName.get(origSource);
// System.out.println("debug read " + s.length());
} else {
- // read in bytes and decompile the class to a string
- byte[] b = Files.readAllBytes(path);
- s = decompile(b);
+ origBytes = Files.readAllBytes(path);
+ alreadyDone = origBytesToClassName.get(origBytes);
+ if (null == alreadyDone) {
+ origSource = decompile(origBytes);
+ }
}
- return s;
+ if (alreadyDone != null) {
+ return null;
+ }
+
+ return origSource;
} catch (IOException e) {
throw new RuntimeException(e);
}
@@ -404,49 +414,110 @@ private String outDirLog;
* @param source - the source, either directly from a .java file, or a
decompiled .class file
*/
private void migrate(String source) {
- v3 = true; // preinit
- v2 = false;
- featNames.clear();
- fi_fields.clear();
-
-// System.out.println("Migrating source before migration:\n");
-// System.out.println(source);
-// System.out.println("\n\n\n");
- StringReader sr = new StringReader(source);
- try {
- cu = JavaParser.parse(sr, true);
+ if (alreadyDone == null) {
+ v3 = true; // preinit
+ v2 = false;
+ featNames.clear();
+ fi_fields.clear();
- 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 (v3) {
- removeImport("org.apache.uima.jcas.cas.TOP_Type");
+ // System.out.println("Migrating source before migration:\n");
+ // System.out.println(source);
+ // System.out.println("\n\n\n");
+
+ 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 (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) {
+ throw new RuntimeException();
+ }
+ classMembers.addAll(positionOfFirstConstructor, fi_fields);
+ }
+
+ if (isSource) {
+ origSourceToClassName.put(origSource, packageAndClassNameSlash);
+ } else {
+ origBytesToClassName.put(origBytes, packageAndClassNameSlash);
+ }
+
+ boolean identicalFound = collectInfoForReports();
+
+ if (!identicalFound) { // don't write out identicals
+ getBaseOutputPath();
+ if (v2) {
+ writeV2Orig(source, v3);
+ }
+ if (v3) {
+ String s = cu.toString();
+ writeV3(s);
+ }
+ System.out.println(".");
+ } else {
+ System.out.println("d");
+ }
+ } catch (ParseException e) {
+ reportParseException();
+ } catch (IOException e) {
+ throw new RuntimeException(e);
}
-
- if (v3 && fi_fields.size() > 0) {
- List<BodyDeclaration> classMembers = cu.getTypes().get(0).getMembers();
- int positionOfFirstConstructor = findConstructor(classMembers);
- if (positionOfFirstConstructor < 0) {
- throw new RuntimeException();
- }
- classMembers.addAll(positionOfFirstConstructor, fi_fields);
- }
- // Reporting
- getBaseOutputPath();
- if (v2)
- writeV2Orig(source, v3);
- if (v3)
- writeV3(cu.toString());
- } catch (ParseException e) {
- reportParseException();
- } catch (IOException e) {
- throw new RuntimeException(e);
+ } else {
+ collectInfoForReports();
+ System.out.println("d");
}
}
+
+ /**
+ * Add this instance to the tracking information for multiple versions
(identical or not) of a class
+ * @return true if this is an identical duplicate of one already done
+ */
+
+ private boolean collectInfoForReports() {
+ String fqcn = (alreadyDone == null)
+ ? packageAndClassNameSlash
+ : alreadyDone;
+ // for a given fully qualified class name (slashified),
+ // find the list of ConvertedSources - one per each different version
+ // create it if null
+ List<ConvertedSource> convertedSources = classname2multiSources.get(fqcn);
+ if (convertedSources == null) {
+ convertedSources = new ArrayList<>();
+ classname2multiSources.put(fqcn, convertedSources);
+ }
+
+ // search to see if this instance already in the set
+ // if so, add the path to the set of identicals
+ boolean found = false;
+ for (ConvertedSource cs : convertedSources) {
+ if ((isSource && cs.rOrigSource.equals(origSource)) ||
+ (!isSource && Arrays.equals(cs.rOrigBytes, origBytes))) {
+ cs.add(candidate);
+ found = true;
+ break;
+ }
+ }
+
+
+ if (!found) {
+ ConvertedSource cs = new ConvertedSource(origSource, origBytes,
candidate);
+ convertedSources.add(cs);
+ }
+
+ return found;
+ }
/******************
* Visitors
@@ -874,9 +945,10 @@ private String outDirLog;
reportPaths("Builtin Extendable JCas classes - skipped - need manual
checking to see if they are modified",
"extendableBuiltins.txt", extendableBuiltins);
- computeDuplicates();
- reportPaths("Report of duplicates - not identical",
"nonIdenticalDuplicates.txt", nonIdenticalDuplicates);
- reportPaths("Report of duplicates - identical",
"identicalDuplicates.txt", identicalDuplicates);
+// computeDuplicates();
+// reportPaths("Report of duplicates - not identical",
"nonIdenticalDuplicates.txt", nonIdenticalDuplicates);
+// reportPaths("Report of duplicates - identical",
"identicalDuplicates.txt", identicalDuplicates);
+ reportDuplicates();
reportPaths("Report of processed files", "processed.txt", c2ps);
reportPaths("Builtin non-Extendable JCas classes - skipped",
"builtinsNotExtendable.txt", nonExtendableBuiltins);
@@ -885,61 +957,61 @@ private String outDirLog;
}
}
- private void computeDuplicates() {
- List<ClassnameAndPath> toCheck = new ArrayList<>(c2ps);
- toCheck.addAll(extendableBuiltins);
- sortReport2(toCheck);
- ClassnameAndPath prevP = new ClassnameAndPath(null, null);
- List<ClassnameAndPath> sameList = new ArrayList<>();
- boolean areAllEqual = true;
-
- for (ClassnameAndPath p : toCheck) {
- if (!p.getFirst().equals(prevP.getFirst())) {
-
- addToIdenticals(sameList, areAllEqual);
- sameList.clear();
- areAllEqual = true;
-
- prevP = p;
- continue;
- }
-
- // have 2nd or subsequent same class
- if (sameList.size() == 0) {
- sameList.add(prevP);
- }
- sameList.add(p);
- if (areAllEqual) {
- if (isFilesMiscompare(p.path, prevP.path)) {
- areAllEqual = false;
- }
- }
- }
-
- addToIdenticals(sameList, areAllEqual);
- }
-
- /**
- * 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);
- }
-
- private void addToIdenticals(List<ClassnameAndPath> sameList, boolean
areAllEqual) {
- if (sameList.size() > 0) {
- if (areAllEqual) {
- identicalDuplicates.addAll(sameList);
- } else {
- nonIdenticalDuplicates.addAll(sameList);
- }
- }
- }
+// private void computeDuplicates() {
+// List<ClassnameAndPath> toCheck = new ArrayList<>(c2ps);
+// toCheck.addAll(extendableBuiltins);
+// sortReport2(toCheck);
+// ClassnameAndPath prevP = new ClassnameAndPath(null, null);
+// List<ClassnameAndPath> sameList = new ArrayList<>();
+// boolean areAllEqual = true;
+//
+// for (ClassnameAndPath p : toCheck) {
+// if (!p.getFirst().equals(prevP.getFirst())) {
+//
+// addToIdenticals(sameList, areAllEqual);
+// sameList.clear();
+// areAllEqual = true;
+//
+// prevP = p;
+// continue;
+// }
+//
+// // have 2nd or subsequent same class
+// if (sameList.size() == 0) {
+// sameList.add(prevP);
+// }
+// sameList.add(p);
+// if (areAllEqual) {
+// if (isFilesMiscompare(p.path, prevP.path)) {
+// areAllEqual = false;
+// }
+// }
+// }
+//
+// addToIdenticals(sameList, areAllEqual);
+// }
+
+// /**
+// * 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);
+// }
+
+// private void addToIdenticals(List<ClassnameAndPath> sameList, boolean
areAllEqual) {
+// if (sameList.size() > 0) {
+// if (areAllEqual) {
+// identicalDuplicates.addAll(sameList);
+// } else {
+// nonIdenticalDuplicates.addAll(sameList);
+// }
+// }
+// }
private Path makePath(String name) throws IOException {
Path p = Paths.get(name);
@@ -959,6 +1031,51 @@ private String outDirLog;
return p;
}
+ private void reportDuplicates() {
+ List<Entry<String, List<ConvertedSource>>> nonIdenticals = new
ArrayList<>();
+ List<ConvertedSource> onlyIdenticals = new ArrayList<>();
+ for (Entry<String, List<ConvertedSource>> e :
classname2multiSources.entrySet()) {
+ List<ConvertedSource> convertedSourcesFor1class = e.getValue();
+ if (convertedSourcesFor1class.size() > 1) {
+ // have multiple non-identical sources for one class
+ nonIdenticals.add(e);
+ } else {
+ ConvertedSource cs = convertedSourcesFor1class.get(0);
+ if (cs.paths.size() > 1) {
+ // have multiple (only) identical sources for one class
+ onlyIdenticals.add(cs);
+ }
+ }
+ }
+
+ if (nonIdenticals.size() == 0) {
+ if (onlyIdenticals.size() == 0) {
+ System.out.println("No duplicates found.");
+ } else {
+ // report identical duplicates
+ System.out.println("Identical duplicates (only):");
+ for (ConvertedSource cs : onlyIdenticals) {
+ for (Path path : cs.paths) {
+ System.out.println(" " + vWithFileSys(path));
+ }
+ }
+ }
+ } else {
+ System.out.println("Report of non-identical duplicates");
+ for (Entry<String, List<ConvertedSource>> nonIdentical : nonIdenticals) {
+ System.out.println(" classname: " + nonIdentical.getKey());
+ int i = 1;
+ for (ConvertedSource cs : nonIdentical.getValue()) {
+ System.out.println(" version " + i);
+ for (Path path : cs.paths) {
+ System.out.println(" " + vWithFileSys(path));
+ }
+ i++;
+ }
+ }
+ }
+ }
+
private void reportPaths(String title, String fileName, List<? extends
Report2> items) throws IOException {
if (items.size() == 0) {
System.out.println("No " + title);
@@ -980,14 +1097,7 @@ private String outDirLog;
int i = 1;
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);
+ String s = String.format("%5d %-" +max+ "s %s%n", Integer.valueOf(i),
p.getFirst(), vWithFileSys(v));
bw.write(s);
System.out.print(s);
i++;
@@ -995,7 +1105,18 @@ private String outDirLog;
System.out.println("");
} // end of try-with-resources
}
-
+
+ private String vWithFileSys(Object v) {
+ 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();
+ }
+ }
+ return v.toString();
+ }
+
private void sortReport2(List<? extends Report2> items) {
Collections.sort(items,
(o1, o2) -> {
@@ -1015,12 +1136,9 @@ private String outDirLog;
* 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
+ * - the path includes the "file system".
* @param root
- * @return list of Paths
+ * @return list of Paths to walk
* @throws IOException
*/
private List<Path> getCandidates(CommandLineParser clp, String root) {
@@ -1036,32 +1154,39 @@ private String outDirLog;
}
Collections.sort(candidates, pathComparator);
+
+ // the collection potentially includes inner class files
List<Path> c = new ArrayList<>(); // candidates
final int nbrOfPaths = candidates.size();
if (nbrOfPaths == 0) {
return c;
}
- for (int i = 0; i < nbrOfPaths;) {
+ for (int i = 0; i < nbrOfPaths; i++) {
+
+ // skip files that end with _Type or
+ // appear to be inner files: have names with a "$" char
+ candidate = candidates.get(i);
+ String lastPartOfPath = candidate.getFileName().toString();
+ if (lastPartOfPath.endsWith(isSource ? "_Type.java" : "_Type.class")) {
+ continue; // skip the _Type files
+ }
+
+ if (lastPartOfPath.contains("$")) {
+ continue; // inner class
+ }
+
if (isSkipTypeCheck) {
- candidate = candidates.get(i);
- if (candidate.getFileName().endsWith(isSource ? "_Type.java" :
"_Type.class")) {
- continue; // skip the _Type files
- }
c.add(candidate);
- i++;
} else {
// 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 returning because doing
_Type checking and no further _Types");
- for (Path x : c) {
- System.out.println("debug " + x);
- }
- return c;
- }
- addIfPreviousIsSameName(c, next_Type);
- i = next_Type + 1;
+ // in the sort order, these follow the file without the _Type suffix
+ // but perhaps there are other names inbetween
+ boolean has_Type = has_Type(candidate, i + 1); // look for the next
_Type file starting at position i + 1
+ if (!has_Type) {
+ continue; // not a JCas class
+ }
+ c.add(candidate);
}
}
return c;
@@ -1074,27 +1199,27 @@ private String outDirLog;
}
};
- // there may be several same-name roots not quite right
- // xxx_Type$1.class
-
- private void addIfPreviousIsSameName(List<Path> c, int i) {
- if (i == 0) return;
- String _Type = candidates.get(i).toString();
-// String prev = r.get(i-1).getPath();
- String prefix = _Type.substring(0, _Type.length() - ("_Type." + (isSource
? "java" : "class")).length());
- i--;
- while (i >= 0) {
- String s = candidates.get(i).toString();
- if ( ! s.startsWith(prefix)) {
- break;
- }
- if (s.substring(prefix.length()).equals((isSource ? ".java" :
".class"))) {
- c.add(candidates.get(i));
- break;
- }
- i--;
- }
- }
+// // there may be several same-name roots not quite right
+// // xxx_Type$1.class
+//
+// private void addIfPreviousIsSameName(List<Path> c, int i) {
+// if (i == 0) return;
+// String _Type = candidates.get(i).toString();
+//// String prev = r.get(i-1).getPath();
+// String prefix = _Type.substring(0, _Type.length() - ("_Type." +
(isSource ? "java" : "class")).length());
+// i--;
+// while (i >= 0) {
+// String s = candidates.get(i).toString();
+// if ( ! s.startsWith(prefix)) {
+// break;
+// }
+// if (s.substring(prefix.length()).equals((isSource ? ".java" :
".class"))) {
+// c.add(candidates.get(i));
+// break;
+// }
+// i--;
+// }
+// }
/**
@@ -1112,7 +1237,7 @@ private String outDirLog;
try {
// URI pathUri = path.toUri();
String pathString = path.toString();
- if (pathString.endsWith(".jar")) { // path.endsWith does mean this !!
+ if (pathString.endsWith(".jar")) { // path.endsWith does not mean this
!!
if (!path.getFileSystem().equals(FileSystems.getDefault())) {
// embedded Jar: extract to temp
Path out = getTempOutputPath(path);
@@ -1120,7 +1245,8 @@ private String outDirLog;
// embeddedJars.add(new PathAndPath(path, out));
path = out;
}
- FileSystem jfs = FileSystems.newFileSystem(path, null);
+ // experiment - see if this makes a copy
+ FileSystem jfs = FileSystems.newFileSystem(Paths.get(path.toUri()),
null);
Path start = jfs.getPath("/");
try (Stream<Path> stream = Files.walk(start)) { // needed to release
file handles
stream.forEachOrdered(
@@ -1153,20 +1279,26 @@ private String outDirLog;
return tempDir;
}
- private int indexOf_Type(int start) {
- int i = start;
+ private boolean has_Type(Path cand, int start) {
if (start >= candidates.size()) {
- return -1;
+ return false;
}
+
+ String sc = cand.toString();
+ String sc_minus_suffix = sc.substring(0, sc.length() - ( isSource ?
".java".length() : ".class".length()));
+ String sc_Type = sc_minus_suffix + ( isSource ? "_Type.java" :
"_Type.class");
+ // a string which sorts beyond the candidate + a suffix of "_"
+ String s_end = sc_minus_suffix + (char) (((int)'_') + 1);
for (Path p : candidates.subList(start, candidates.size())) {
String s = p.toString();
- if (s.endsWith("_Type.java") ||
- s.endsWith("_Type.class")) {
- return i;
+ if (s_end.compareTo(s) < 0) {
+ return false; // not found, we're already beyond where it would be
found
+ }
+ if (s.equals(sc_Type)) {
+ return true;
}
- i++;
}
- return -1;
+ return false;
}
@@ -1176,6 +1308,8 @@ private String outDirLog;
parser.addParameter(CLASS_FILE_ROOTS, true);
parser.addParameter(OUTPUT_DIRECTORY, true);
parser.addParameter(SKIP_TYPE_CHECK, false);
+ parser.addParameter(MIGRATE_CLASSPATH, true);
+ parser.addParameter(CLASSES, true);
return parser;
}
@@ -1207,14 +1341,44 @@ private String outDirLog;
System.err.println("-outputDirectory is a required parameter, must be a
path to a writable file directory.");
return false;
}
+
+ if (clp.isInArgsList(MIGRATE_CLASSPATH)) {
+ migrateClasspath = clp.getParamArgument(MIGRATE_CLASSPATH);
+ }
+
+ if (clp.isInArgsList(CLASSES)) {
+ individualClasses = clp.getParamArgument(CLASSES);
+ }
return true;
}
private String decompile(byte[] b) {
- UimaDecompiler ud = new UimaDecompiler();
+ ClassLoader cl = getClassLoader();
+ UimaDecompiler ud = new UimaDecompiler(cl, null);
return ud.decompile(b);
}
+ private String decompile(String classname) {
+ ClassLoader cl = getClassLoader();
+ UimaDecompiler ud = new UimaDecompiler(cl, null);
+ return ud.decompileToString(classname);
+ }
+
+// private String getFullyQualifiedClassNameWithSlashes(byte[] b) {
+// ClassLoader cl = getClassLoader();
+// UimaDecompiler ud = new UimaDecompiler(cl, null);
+// return ud.extractClassNameSlashes(b);
+// }
+
+ private ClassLoader getClassLoader() {
+ if (null == migrateClassLoader) {
+ migrateClassLoader = (migrateClasspath == null)
+ ? this.getClass().getClassLoader()
+ : new
URLClassLoader(Misc.classpath2urls(migrateClasspath));
+ }
+ return migrateClassLoader;
+ }
+
private void addImport(String s) {
cu.getImports().add(new ImportDeclaration(new NameExpr(s), false, false));
}
@@ -1505,22 +1669,28 @@ private String outDirLog;
}
private void reportPathWorkaround(String orig, String modified) {
-
+ pathWorkaround.add(new String1AndString2(orig, modified));
}
/***********************************************/
private void getBaseOutputPath() {
String s = packageAndClassNameSlash;
- int i = 1;
+ int i = 0;
while (!usedPackageAndClassNames.add(s)) {
- s = packageAndClassNameSlash + i++;
+ i = i + 1;
+ s = packageAndClassNameSlash + "_dupid_" + i;
}
- currentPackageAndClassNameSlash = s;
+ packageAndClassNameSlash_i = i;
}
private String getBaseOutputPath(boolean wasConverted, boolean isV2) {
- return (wasConverted ? outDirConverted : outDirSkipped) + (isV2 ? "v2/" :
"v3/") + currentPackageAndClassNameSlash + ".java";
+ return (wasConverted ? outDirConverted : outDirSkipped) + (isV2 ? "v2/" :
"v3/")
+ + ((packageAndClassNameSlash_i > 0)
+ ? (Integer.toString(packageAndClassNameSlash_i) + "/")
+ : "")
+ + packageAndClassNameSlash
+ + ".java";
}
private void writeV2Orig(String data, boolean wasConverted) throws
IOException {
@@ -1539,10 +1709,14 @@ private String outDirLog;
"Usage: java org.apache.uima.migratev3.jcas.MigrateJCas \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"
+ + " [-outputDirectory a-writable-directory-path (required)\n"
+ + " [-migrateClasspath a-class-path to use in decompiling, required
if -classesRoots is specified, or \n"
+ + " to provide disambiguation information when
-sourcesRoots is specified\n"
+ + " and more than one instance of a class is
found in the roots]\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"
+ + " The decompiling requires that the classes being scanned be
on the migrateClasspath when this is invoked.\n"
+ " NOTE: -outputDirectory is required\n");
}
@@ -1550,4 +1724,125 @@ private String outDirLog;
private String fixImplementsBug(String data) {
return implementsEmpty.matcher(data).replaceAll("{");
}
+
+// /**
+// * Called after class is migrated
+// * Given a path to a class (source or class file),
+// * return the URL to the class as found in the classpath.
+// * This returns the "first" one found in the classpath, in the case of
duplicates.
+// * @param path
+// * @return the location of the class in the class path
+// */
+// private URL getPathForClass(Path path) {
+// return (null == packageAndClassNameSlash)
+// ? null
+// : migrateClassLoader.getResource(packageAndClassNameSlash +
".class");
+// }
+
+ /**
+ * prepare to migrate one class
+ */
+ private String prepare(Path c) {
+ candidate = c;
+ packageName = null;
+ className = null;
+ packageAndClassNameSlash = null;
+ cu = null;
+ return getSource(c);
+ }
+
+ private String prepareIndividual(String classname) {
+ candidate = Paths.get(classname); // a pseudo path
+ packageName = null;
+ className = null;
+ packageAndClassNameSlash = null;
+ cu = null;
+ return decompile(classname); // always look up in classpath
+ // to decompile individual source - put in
sourcesRoots
+ }
+
+ /*********************************************************************
+ * Reporting classes
+ *********************************************************************/
+
+ 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;
+ String1AndString2(String s1, String s2) {
+ this.s1 = s1;
+ this.s2 = s2;
+ }
+ @Override
+ public Comparable<String> getFirst() { return s1; }
+ @Override
+ public Comparable<String> getSecond() { return s2; }
+ @Override
+ int getFirstLength() { return s1.toString().length(); }
+ }
+
}