GetDeps.java revision 3014:a3dd196e5341
1/* 2 * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24import java.io.*; 25import java.util.*; 26import java.util.regex.Pattern; 27import javax.tools.*; 28 29import com.sun.tools.classfile.*; 30import com.sun.tools.classfile.Dependencies.*; 31import com.sun.tools.classfile.Dependency.Location; 32import com.sun.tools.javac.file.JavacFileManager; 33import com.sun.tools.javac.util.Context; 34 35/** 36 * Demo utility for using the classfile dependency analysis API framework. 37 * 38 * Usage: 39 * getdeps [options] classes 40 * where options include: 41 * -classpath path where to find classes to analyze 42 * -p package-name restrict analysis to classes in this package 43 * (may be given multiple times) 44 * -r regex restrict analysis to packages matching pattern 45 * (-p and -r are exclusive) 46 * -rev invert the dependencies in the output 47 * -t transitive closure of dependencies 48 */ 49public class GetDeps { 50 public static void main(String... args) throws Exception { 51 new GetDeps().run(args); 52 } 53 54 void run(String... args) throws IOException, ClassFileNotFoundException { 55 PrintWriter pw = new PrintWriter(System.out); 56 try { 57 run(pw, args); 58 } finally { 59 pw.flush(); 60 } 61 } 62 63 void run(PrintWriter out, String... args) throws IOException, ClassFileNotFoundException { 64 decodeArgs(args); 65 66 final StandardJavaFileManager fm = new JavacFileManager(new Context(), false, null); 67 if (classpath != null) 68 fm.setLocation(StandardLocation.CLASS_PATH, classpath); 69 70 ClassFileReader reader = new ClassFileReader(fm); 71 72 Dependencies d = new Dependencies(); 73 74 if (regex != null) 75 d.setFilter(Dependencies.getRegexFilter(Pattern.compile(regex))); 76 77 if (packageNames.size() > 0) 78 d.setFilter(Dependencies.getPackageFilter(packageNames, false)); 79 80 SortedRecorder r = new SortedRecorder(reverse); 81 82 d.findAllDependencies(reader, rootClassNames, transitiveClosure, r); 83 84 SortedMap<Location,SortedSet<Dependency>> deps = r.getMap(); 85 for (Map.Entry<Location, SortedSet<Dependency>> e: deps.entrySet()) { 86 out.println(e.getKey()); 87 for (Dependency dep: e.getValue()) { 88 out.println(" " + dep.getTarget()); 89 } 90 } 91 } 92 93 void decodeArgs(String... args) { 94 rootClassNames = new TreeSet<String>(); 95 packageNames = new TreeSet<String>(); 96 97 for (int i = 0; i < args.length; i++) { 98 String arg = args[i]; 99 if (arg.equals("-classpath") && (i + 1 < args.length)) 100 classpath = getPathFiles(args[++i]); 101 else if (arg.equals("-p") && (i + 1 < args.length)) 102 packageNames.add(args[++i]); 103 else if (arg.equals("-r") && (i + 1 < args.length)) 104 regex = args[++i]; 105 else if (arg.equals("-rev")) 106 reverse = true; 107 else if (arg.equals("-t")) 108 transitiveClosure = true; 109 else if (arg.startsWith("-")) 110 throw new Error(arg); 111 else { 112 for ( ; i < args.length; i++) 113 rootClassNames.add(args[i]); 114 } 115 } 116 } 117 118 List<File> getPathFiles(String path) { 119 List<File> files = new ArrayList<File>(); 120 for (String p: path.split(File.pathSeparator)) { 121 if (p.length() > 0) 122 files.add(new File(p)); 123 } 124 return files; 125 } 126 127 boolean transitiveClosure; 128 List<File> classpath; 129 Set<String> rootClassNames; 130 Set<String> packageNames; 131 String regex; 132 boolean reverse; 133 134 135 static class ClassFileReader implements Dependencies.ClassFileReader { 136 private JavaFileManager fm; 137 138 ClassFileReader(JavaFileManager fm) { 139 this.fm = fm; 140 } 141 142 @Override 143 public ClassFile getClassFile(String className) throws ClassFileNotFoundException { 144 try { 145 JavaFileObject fo = fm.getJavaFileForInput( 146 StandardLocation.CLASS_PATH, className, JavaFileObject.Kind.CLASS); 147 if (fo == null) 148 fo = fm.getJavaFileForInput( 149 StandardLocation.PLATFORM_CLASS_PATH, className, JavaFileObject.Kind.CLASS); 150 if (fo == null) 151 throw new ClassFileNotFoundException(className); 152 InputStream in = fo.openInputStream(); 153 try { 154 return ClassFile.read(in); 155 } finally { 156 in.close(); 157 } 158 } catch (ConstantPoolException e) { 159 throw new ClassFileNotFoundException(className, e); 160 } catch (IOException e) { 161 throw new ClassFileNotFoundException(className, e); 162 } 163 } 164 }; 165 166 static class SortedRecorder implements Recorder { 167 public SortedRecorder(boolean reverse) { 168 this.reverse = reverse; 169 } 170 171 public void addDependency(Dependency d) { 172 Location o = (reverse ? d.getTarget() : d.getOrigin()); 173 SortedSet<Dependency> odeps = map.get(o); 174 if (odeps == null) { 175 Comparator<Dependency> c = (reverse ? originComparator : targetComparator); 176 map.put(o, odeps = new TreeSet<Dependency>(c)); 177 } 178 odeps.add(d); 179 } 180 181 public SortedMap<Location, SortedSet<Dependency>> getMap() { 182 return map; 183 } 184 185 private Comparator<Dependency> originComparator = new Comparator<Dependency>() { 186 public int compare(Dependency o1, Dependency o2) { 187 return o1.getOrigin().toString().compareTo(o2.getOrigin().toString()); 188 } 189 }; 190 191 private Comparator<Dependency> targetComparator = new Comparator<Dependency>() { 192 public int compare(Dependency o1, Dependency o2) { 193 return o1.getTarget().toString().compareTo(o2.getTarget().toString()); 194 } 195 }; 196 197 private Comparator<Location> locationComparator = new Comparator<Location>() { 198 public int compare(Location o1, Location o2) { 199 return o1.toString().compareTo(o2.toString()); 200 } 201 }; 202 203 private final SortedMap<Location, SortedSet<Dependency>> map = 204 new TreeMap<Location, SortedSet<Dependency>>(locationComparator); 205 206 boolean reverse; 207 } 208 209} 210