Fri, 28 Dec 2012 22:25:21 -0800
8003562: Provide a CLI tool to analyze class dependencies
Reviewed-by: jjg, alanb, ulfzibis, erikj
1.1 --- a/make/build.properties Tue Dec 25 17:23:59 2012 -0800 1.2 +++ b/make/build.properties Fri Dec 28 22:25:21 2012 -0800 1.3 @@ -153,6 +153,7 @@ 1.4 javap.includes = \ 1.5 com/sun/tools/classfile/ \ 1.6 com/sun/tools/javap/ \ 1.7 + com/sun/tools/jdeps/ \ 1.8 sun/tools/javap/ 1.9 1.10 javap.tests = \
2.1 --- a/makefiles/BuildLangtools.gmk Tue Dec 25 17:23:59 2012 -0800 2.2 +++ b/makefiles/BuildLangtools.gmk Fri Dec 28 22:25:21 2012 -0800 2.3 @@ -75,6 +75,7 @@ 2.4 printf "jdk=$(JDK_VERSION)\nfull=$(FULL_VERSION)\nrelease=$(RELEASE)\n" > $(LANGTOOLS_OUTPUTDIR)/gensrc/com/sun/tools/javah/resources/version.properties 2.5 printf "jdk=$(JDK_VERSION)\nfull=$(FULL_VERSION)\nrelease=$(RELEASE)\n" > $(LANGTOOLS_OUTPUTDIR)/gensrc/com/sun/tools/javap/resources/version.properties 2.6 printf "jdk=$(JDK_VERSION)\nfull=$(FULL_VERSION)\nrelease=$(RELEASE)\n" > $(LANGTOOLS_OUTPUTDIR)/gensrc/com/sun/tools/javac/resources/version.properties 2.7 + printf "jdk=$(JDK_VERSION)\nfull=$(FULL_VERSION)\nrelease=$(RELEASE)\n" > $(LANGTOOLS_OUTPUTDIR)/gensrc/com/sun/tools/jdeps/resources/version.properties 2.8 echo Compiling $(words $(PROPSOURCES) v1 v2 v3) properties into resource bundles 2.9 $(TOOL_COMPILEPROPS_CMD) $(PROPCMDLINE) \ 2.10 -compile $(LANGTOOLS_OUTPUTDIR)/gensrc/com/sun/tools/javah/resources/version.properties \ 2.11 @@ -85,6 +86,9 @@ 2.12 java.util.ListResourceBundle \ 2.13 -compile $(LANGTOOLS_OUTPUTDIR)/gensrc/com/sun/tools/javac/resources/version.properties \ 2.14 $(LANGTOOLS_OUTPUTDIR)/gensrc/com/sun/tools/javac/resources/version.java \ 2.15 + java.util.ListResourceBundle \ 2.16 + -compile $(LANGTOOLS_OUTPUTDIR)/gensrc/com/sun/tools/jdeps/resources/version.properties \ 2.17 + $(LANGTOOLS_OUTPUTDIR)/gensrc/com/sun/tools/jdeps/resources/version.java \ 2.18 java.util.ListResourceBundle 2.19 echo PROPS_ARE_CREATED=yes > $@ 2.20
3.1 --- a/src/share/classes/com/sun/tools/classfile/Dependencies.java Tue Dec 25 17:23:59 2012 -0800 3.2 +++ b/src/share/classes/com/sun/tools/classfile/Dependencies.java Fri Dec 28 22:25:21 2012 -0800 3.3 @@ -142,6 +142,15 @@ 3.4 } 3.5 3.6 /** 3.7 + * Get a finder to do class dependency analysis. 3.8 + * 3.9 + * @return a Class dependency finder 3.10 + */ 3.11 + public static Finder getClassDependencyFinder() { 3.12 + return new ClassDependencyFinder(); 3.13 + } 3.14 + 3.15 + /** 3.16 * Get the finder used to locate the dependencies for a class. 3.17 * @return the finder 3.18 */ 3.19 @@ -246,8 +255,6 @@ 3.20 return results; 3.21 } 3.22 3.23 - 3.24 - 3.25 /** 3.26 * Find the dependencies of a class, using the current 3.27 * {@link Dependencies#getFinder finder} and 3.28 @@ -306,38 +313,44 @@ 3.29 * A location identifying a class. 3.30 */ 3.31 static class SimpleLocation implements Location { 3.32 - public SimpleLocation(String className) { 3.33 - this.className = className; 3.34 + public SimpleLocation(String name) { 3.35 + this.name = name; 3.36 + this.className = name.replace('/', '.').replace('$', '.'); 3.37 } 3.38 3.39 - /** 3.40 - * Get the name of the class being depended on. This name will be used to 3.41 - * locate the class file for transitive dependency analysis. 3.42 - * @return the name of the class being depended on 3.43 - */ 3.44 + public String getName() { 3.45 + return name; 3.46 + } 3.47 + 3.48 public String getClassName() { 3.49 return className; 3.50 } 3.51 3.52 + public String getPackageName() { 3.53 + int i = name.lastIndexOf('/'); 3.54 + return (i > 0) ? name.substring(0, i).replace('/', '.') : ""; 3.55 + } 3.56 + 3.57 @Override 3.58 public boolean equals(Object other) { 3.59 if (this == other) 3.60 return true; 3.61 if (!(other instanceof SimpleLocation)) 3.62 return false; 3.63 - return (className.equals(((SimpleLocation) other).className)); 3.64 + return (name.equals(((SimpleLocation) other).name)); 3.65 } 3.66 3.67 @Override 3.68 public int hashCode() { 3.69 - return className.hashCode(); 3.70 + return name.hashCode(); 3.71 } 3.72 3.73 @Override 3.74 public String toString() { 3.75 - return className; 3.76 + return name; 3.77 } 3.78 3.79 + private String name; 3.80 private String className; 3.81 } 3.82 3.83 @@ -431,9 +444,7 @@ 3.84 } 3.85 3.86 public boolean accepts(Dependency dependency) { 3.87 - String cn = dependency.getTarget().getClassName(); 3.88 - int lastSep = cn.lastIndexOf("/"); 3.89 - String pn = (lastSep == -1 ? "" : cn.substring(0, lastSep)); 3.90 + String pn = dependency.getTarget().getPackageName(); 3.91 if (packageNames.contains(pn)) 3.92 return true; 3.93 3.94 @@ -451,8 +462,6 @@ 3.95 private final boolean matchSubpackages; 3.96 } 3.97 3.98 - 3.99 - 3.100 /** 3.101 * This class identifies class names directly or indirectly in the constant pool. 3.102 */ 3.103 @@ -462,6 +471,26 @@ 3.104 for (CPInfo cpInfo: classfile.constant_pool.entries()) { 3.105 v.scan(cpInfo); 3.106 } 3.107 + try { 3.108 + v.addClass(classfile.super_class); 3.109 + v.addClasses(classfile.interfaces); 3.110 + v.scan(classfile.attributes); 3.111 + 3.112 + for (Field f : classfile.fields) { 3.113 + v.scan(f.descriptor, f.attributes); 3.114 + } 3.115 + for (Method m : classfile.methods) { 3.116 + v.scan(m.descriptor, m.attributes); 3.117 + Exceptions_attribute e = 3.118 + (Exceptions_attribute)m.attributes.get(Attribute.Exceptions); 3.119 + if (e != null) { 3.120 + v.addClasses(e.exception_index_table); 3.121 + } 3.122 + } 3.123 + } catch (ConstantPoolException e) { 3.124 + throw new ClassFileError(e); 3.125 + } 3.126 + 3.127 return v.deps; 3.128 } 3.129 } 3.130 @@ -558,9 +587,7 @@ 3.131 void scan(Descriptor d, Attributes attrs) { 3.132 try { 3.133 scan(new Signature(d.index).getType(constant_pool)); 3.134 - Signature_attribute sa = (Signature_attribute) attrs.get(Attribute.Signature); 3.135 - if (sa != null) 3.136 - scan(new Signature(sa.signature_index).getType(constant_pool)); 3.137 + scan(attrs); 3.138 } catch (ConstantPoolException e) { 3.139 throw new ClassFileError(e); 3.140 } 3.141 @@ -574,6 +601,43 @@ 3.142 t.accept(this, null); 3.143 } 3.144 3.145 + void scan(Attributes attrs) { 3.146 + try { 3.147 + Signature_attribute sa = (Signature_attribute)attrs.get(Attribute.Signature); 3.148 + if (sa != null) 3.149 + scan(sa.getParsedSignature().getType(constant_pool)); 3.150 + 3.151 + scan((RuntimeVisibleAnnotations_attribute) 3.152 + attrs.get(Attribute.RuntimeVisibleAnnotations)); 3.153 + scan((RuntimeVisibleParameterAnnotations_attribute) 3.154 + attrs.get(Attribute.RuntimeVisibleParameterAnnotations)); 3.155 + } catch (ConstantPoolException e) { 3.156 + throw new ClassFileError(e); 3.157 + } 3.158 + } 3.159 + 3.160 + private void scan(RuntimeAnnotations_attribute attr) throws ConstantPoolException { 3.161 + if (attr == null) { 3.162 + return; 3.163 + } 3.164 + for (int i = 0; i < attr.annotations.length; i++) { 3.165 + int index = attr.annotations[i].type_index; 3.166 + scan(new Signature(index).getType(constant_pool)); 3.167 + } 3.168 + } 3.169 + 3.170 + private void scan(RuntimeParameterAnnotations_attribute attr) throws ConstantPoolException { 3.171 + if (attr == null) { 3.172 + return; 3.173 + } 3.174 + for (int param = 0; param < attr.parameter_annotations.length; param++) { 3.175 + for (int i = 0; i < attr.parameter_annotations[param].length; i++) { 3.176 + int index = attr.parameter_annotations[param][i].type_index; 3.177 + scan(new Signature(index).getType(constant_pool)); 3.178 + } 3.179 + } 3.180 + } 3.181 + 3.182 void addClass(int index) throws ConstantPoolException { 3.183 if (index != 0) { 3.184 String name = constant_pool.getClassInfo(index).getBaseName(); 3.185 @@ -698,6 +762,7 @@ 3.186 findDependencies(type.paramTypes); 3.187 findDependencies(type.returnType); 3.188 findDependencies(type.throwsTypes); 3.189 + findDependencies(type.typeParamTypes); 3.190 return null; 3.191 } 3.192 3.193 @@ -709,7 +774,7 @@ 3.194 3.195 public Void visitClassType(ClassType type, Void p) { 3.196 findDependencies(type.outerType); 3.197 - addDependency(type.name); 3.198 + addDependency(type.getBinaryName()); 3.199 findDependencies(type.typeArgs); 3.200 return null; 3.201 }
4.1 --- a/src/share/classes/com/sun/tools/classfile/Dependency.java Tue Dec 25 17:23:59 2012 -0800 4.2 +++ b/src/share/classes/com/sun/tools/classfile/Dependency.java Fri Dec 28 22:25:21 2012 -0800 4.3 @@ -71,7 +71,19 @@ 4.4 * dependency analysis. 4.5 * @return the name of the class containing the location. 4.6 */ 4.7 + String getName(); 4.8 + 4.9 + /** 4.10 + * Get the fully-qualified name of the class containing the location. 4.11 + * @return the fully-qualified name of the class containing the location. 4.12 + */ 4.13 String getClassName(); 4.14 + 4.15 + /** 4.16 + * Get the package name of the class containing the location. 4.17 + * @return the package name of the class containing the location. 4.18 + */ 4.19 + String getPackageName(); 4.20 } 4.21 4.22
5.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 5.2 +++ b/src/share/classes/com/sun/tools/jdeps/Archive.java Fri Dec 28 22:25:21 2012 -0800 5.3 @@ -0,0 +1,173 @@ 5.4 +/* 5.5 + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. 5.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 5.7 + * 5.8 + * This code is free software; you can redistribute it and/or modify it 5.9 + * under the terms of the GNU General Public License version 2 only, as 5.10 + * published by the Free Software Foundation. Oracle designates this 5.11 + * particular file as subject to the "Classpath" exception as provided 5.12 + * by Oracle in the LICENSE file that accompanied this code. 5.13 + * 5.14 + * This code is distributed in the hope that it will be useful, but WITHOUT 5.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 5.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 5.17 + * version 2 for more details (a copy is included in the LICENSE file that 5.18 + * accompanied this code). 5.19 + * 5.20 + * You should have received a copy of the GNU General Public License version 5.21 + * 2 along with this work; if not, write to the Free Software Foundation, 5.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 5.23 + * 5.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 5.25 + * or visit www.oracle.com if you need additional information or have any 5.26 + * questions. 5.27 + */ 5.28 +package com.sun.tools.jdeps; 5.29 + 5.30 +import com.sun.tools.classfile.Dependency; 5.31 +import com.sun.tools.classfile.Dependency.Location; 5.32 +import java.io.File; 5.33 +import java.util.Comparator; 5.34 +import java.util.HashMap; 5.35 +import java.util.HashSet; 5.36 +import java.util.Map; 5.37 +import java.util.Set; 5.38 +import java.util.SortedMap; 5.39 +import java.util.SortedSet; 5.40 +import java.util.TreeMap; 5.41 +import java.util.TreeSet; 5.42 + 5.43 +/** 5.44 + * Represents the source of the class files. 5.45 + */ 5.46 +public class Archive { 5.47 + private static Map<String,Archive> archiveForClass = new HashMap<String,Archive>(); 5.48 + public static Archive find(Location loc) { 5.49 + return archiveForClass.get(loc.getName()); 5.50 + } 5.51 + 5.52 + private final File file; 5.53 + private final String filename; 5.54 + private final DependencyRecorder recorder; 5.55 + private final ClassFileReader reader; 5.56 + public Archive(String name) { 5.57 + this.file = null; 5.58 + this.filename = name; 5.59 + this.recorder = new DependencyRecorder(); 5.60 + this.reader = null; 5.61 + } 5.62 + 5.63 + public Archive(File f, ClassFileReader reader) { 5.64 + this.file = f; 5.65 + this.filename = f.getName(); 5.66 + this.recorder = new DependencyRecorder(); 5.67 + this.reader = reader; 5.68 + } 5.69 + 5.70 + public ClassFileReader reader() { 5.71 + return reader; 5.72 + } 5.73 + 5.74 + public String getFileName() { 5.75 + return filename; 5.76 + } 5.77 + 5.78 + public void addClass(String classFileName) { 5.79 + Archive a = archiveForClass.get(classFileName); 5.80 + assert(a == null || a == this); // ## issue warning? 5.81 + if (!archiveForClass.containsKey(classFileName)) { 5.82 + archiveForClass.put(classFileName, this); 5.83 + } 5.84 + } 5.85 + 5.86 + public void addDependency(Dependency d) { 5.87 + recorder.addDependency(d); 5.88 + } 5.89 + 5.90 + /** 5.91 + * Returns a sorted map of a class to its dependencies. 5.92 + */ 5.93 + public SortedMap<Location, SortedSet<Location>> getDependencies() { 5.94 + DependencyRecorder.Filter filter = new DependencyRecorder.Filter() { 5.95 + public boolean accept(Location origin, Location target) { 5.96 + return (archiveForClass.get(origin.getName()) != 5.97 + archiveForClass.get(target.getName())); 5.98 + }}; 5.99 + 5.100 + SortedMap<Location, SortedSet<Location>> result = 5.101 + new TreeMap<Location, SortedSet<Location>>(locationComparator); 5.102 + for (Map.Entry<Location, Set<Location>> e : recorder.dependencies().entrySet()) { 5.103 + Location o = e.getKey(); 5.104 + for (Location t : e.getValue()) { 5.105 + if (filter.accept(o, t)) { 5.106 + SortedSet<Location> odeps = result.get(o); 5.107 + if (odeps == null) { 5.108 + odeps = new TreeSet<Location>(locationComparator); 5.109 + result.put(o, odeps); 5.110 + } 5.111 + odeps.add(t); 5.112 + } 5.113 + } 5.114 + } 5.115 + return result; 5.116 + } 5.117 + 5.118 + /** 5.119 + * Returns the set of archives this archive requires. 5.120 + */ 5.121 + public Set<Archive> getRequiredArchives() { 5.122 + SortedSet<Archive> deps = new TreeSet<Archive>(new Comparator<Archive>() { 5.123 + public int compare(Archive a1, Archive a2) { 5.124 + return a1.toString().compareTo(a2.toString()); 5.125 + } 5.126 + }); 5.127 + 5.128 + for (Map.Entry<Location, Set<Location>> e : recorder.dependencies().entrySet()) { 5.129 + Location o = e.getKey(); 5.130 + Archive origin = Archive.find(o); 5.131 + for (Location t : e.getValue()) { 5.132 + Archive target = Archive.find(t); 5.133 + assert(origin != null && target != null); 5.134 + if (origin != target) { 5.135 + if (!deps.contains(target)) { 5.136 + deps.add(target); 5.137 + } 5.138 + } 5.139 + } 5.140 + } 5.141 + return deps; 5.142 + } 5.143 + 5.144 + public String toString() { 5.145 + return file != null ? file.getPath() : filename; 5.146 + } 5.147 + 5.148 + private static class DependencyRecorder { 5.149 + static interface Filter { 5.150 + boolean accept(Location origin, Location target); 5.151 + } 5.152 + 5.153 + public void addDependency(Dependency d) { 5.154 + Set<Location> odeps = map.get(d.getOrigin()); 5.155 + if (odeps == null) { 5.156 + odeps = new HashSet<Location>(); 5.157 + map.put(d.getOrigin(), odeps); 5.158 + } 5.159 + odeps.add(d.getTarget()); 5.160 + } 5.161 + 5.162 + public Map<Location, Set<Location>> dependencies() { 5.163 + return map; 5.164 + } 5.165 + 5.166 + private final Map<Location, Set<Location>> map = 5.167 + new HashMap<Location, Set<Location>>(); 5.168 + } 5.169 + 5.170 + private static Comparator<Location> locationComparator = 5.171 + new Comparator<Location>() { 5.172 + public int compare(Location o1, Location o2) { 5.173 + return o1.toString().compareTo(o2.toString()); 5.174 + } 5.175 + }; 5.176 +}
6.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 6.2 +++ b/src/share/classes/com/sun/tools/jdeps/ClassFileReader.java Fri Dec 28 22:25:21 2012 -0800 6.3 @@ -0,0 +1,326 @@ 6.4 +/* 6.5 + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. 6.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 6.7 + * 6.8 + * This code is free software; you can redistribute it and/or modify it 6.9 + * under the terms of the GNU General Public License version 2 only, as 6.10 + * published by the Free Software Foundation. Oracle designates this 6.11 + * particular file as subject to the "Classpath" exception as provided 6.12 + * by Oracle in the LICENSE file that accompanied this code. 6.13 + * 6.14 + * This code is distributed in the hope that it will be useful, but WITHOUT 6.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 6.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 6.17 + * version 2 for more details (a copy is included in the LICENSE file that 6.18 + * accompanied this code). 6.19 + * 6.20 + * You should have received a copy of the GNU General Public License version 6.21 + * 2 along with this work; if not, write to the Free Software Foundation, 6.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 6.23 + * 6.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 6.25 + * or visit www.oracle.com if you need additional information or have any 6.26 + * questions. 6.27 + */ 6.28 +package com.sun.tools.jdeps; 6.29 + 6.30 +import com.sun.tools.classfile.ClassFile; 6.31 +import com.sun.tools.classfile.ConstantPoolException; 6.32 +import com.sun.tools.classfile.Dependencies.ClassFileError; 6.33 +import java.io.*; 6.34 +import java.nio.file.FileVisitResult; 6.35 +import java.nio.file.Files; 6.36 +import java.nio.file.Path; 6.37 +import java.nio.file.SimpleFileVisitor; 6.38 +import java.nio.file.attribute.BasicFileAttributes; 6.39 +import java.util.*; 6.40 +import java.util.jar.JarEntry; 6.41 +import java.util.jar.JarFile; 6.42 + 6.43 +/** 6.44 + * ClassFileReader reads ClassFile(s) of a given path that can be 6.45 + * a .class file, a directory, or a JAR file. 6.46 + */ 6.47 +public class ClassFileReader { 6.48 + /** 6.49 + * Returns a ClassFileReader instance of a given path. 6.50 + */ 6.51 + public static ClassFileReader newInstance(File path) throws IOException { 6.52 + if (!path.exists()) { 6.53 + throw new FileNotFoundException(path.getAbsolutePath()); 6.54 + } 6.55 + 6.56 + if (path.isDirectory()) { 6.57 + return new DirectoryReader(path.toPath()); 6.58 + } else if (path.getName().endsWith(".jar")) { 6.59 + return new JarFileReader(path.toPath()); 6.60 + } else { 6.61 + return new ClassFileReader(path.toPath()); 6.62 + } 6.63 + } 6.64 + 6.65 + protected final Path path; 6.66 + protected final String baseFileName; 6.67 + private ClassFileReader(Path path) { 6.68 + this.path = path; 6.69 + this.baseFileName = path.getFileName() != null 6.70 + ? path.getFileName().toString() 6.71 + : path.toString(); 6.72 + } 6.73 + 6.74 + public String getFileName() { 6.75 + return baseFileName; 6.76 + } 6.77 + 6.78 + /** 6.79 + * Returns the ClassFile matching the given binary name 6.80 + * or a fully-qualified class name. 6.81 + */ 6.82 + public ClassFile getClassFile(String name) throws IOException { 6.83 + if (name.indexOf('.') > 0) { 6.84 + int i = name.lastIndexOf('.'); 6.85 + String pathname = name.replace('.', File.separatorChar) + ".class"; 6.86 + if (baseFileName.equals(pathname) || 6.87 + baseFileName.equals(pathname.substring(0, i) + "$" + 6.88 + pathname.substring(i+1, pathname.length()))) { 6.89 + return readClassFile(path); 6.90 + } 6.91 + } else { 6.92 + if (baseFileName.equals(name.replace('/', File.separatorChar) + ".class")) { 6.93 + return readClassFile(path); 6.94 + } 6.95 + } 6.96 + return null; 6.97 + } 6.98 + 6.99 + public Iterable<ClassFile> getClassFiles() throws IOException { 6.100 + return new Iterable<ClassFile>() { 6.101 + public Iterator<ClassFile> iterator() { 6.102 + return new FileIterator(); 6.103 + } 6.104 + }; 6.105 + } 6.106 + 6.107 + protected ClassFile readClassFile(Path p) throws IOException { 6.108 + InputStream is = null; 6.109 + try { 6.110 + is = Files.newInputStream(p); 6.111 + return ClassFile.read(is); 6.112 + } catch (ConstantPoolException e) { 6.113 + throw new ClassFileError(e); 6.114 + } finally { 6.115 + if (is != null) { 6.116 + is.close(); 6.117 + } 6.118 + } 6.119 + } 6.120 + 6.121 + class FileIterator implements Iterator<ClassFile> { 6.122 + int count; 6.123 + FileIterator() { 6.124 + this.count = 0; 6.125 + } 6.126 + public boolean hasNext() { 6.127 + return count == 0 && baseFileName.endsWith(".class"); 6.128 + } 6.129 + 6.130 + public ClassFile next() { 6.131 + if (!hasNext()) { 6.132 + throw new NoSuchElementException(); 6.133 + } 6.134 + try { 6.135 + ClassFile cf = readClassFile(path); 6.136 + count++; 6.137 + return cf; 6.138 + } catch (IOException e) { 6.139 + throw new ClassFileError(e); 6.140 + } 6.141 + } 6.142 + 6.143 + public void remove() { 6.144 + throw new UnsupportedOperationException("Not supported yet."); 6.145 + } 6.146 + } 6.147 + 6.148 + public String toString() { 6.149 + return path.toString(); 6.150 + } 6.151 + 6.152 + private static class DirectoryReader extends ClassFileReader { 6.153 + DirectoryReader(Path path) throws IOException { 6.154 + super(path); 6.155 + } 6.156 + 6.157 + public ClassFile getClassFile(String name) throws IOException { 6.158 + if (name.indexOf('.') > 0) { 6.159 + int i = name.lastIndexOf('.'); 6.160 + String pathname = name.replace('.', File.separatorChar) + ".class"; 6.161 + Path p = path.resolve(pathname); 6.162 + if (!p.toFile().exists()) { 6.163 + p = path.resolve(pathname.substring(0, i) + "$" + 6.164 + pathname.substring(i+1, pathname.length())); 6.165 + } 6.166 + if (p.toFile().exists()) { 6.167 + return readClassFile(p); 6.168 + } 6.169 + } else { 6.170 + Path p = path.resolve(name + ".class"); 6.171 + if (p.toFile().exists()) { 6.172 + return readClassFile(p); 6.173 + } 6.174 + } 6.175 + return null; 6.176 + } 6.177 + 6.178 + public Iterable<ClassFile> getClassFiles() throws IOException { 6.179 + final Iterator<ClassFile> iter = new DirectoryIterator(); 6.180 + return new Iterable<ClassFile>() { 6.181 + public Iterator<ClassFile> iterator() { 6.182 + return iter; 6.183 + } 6.184 + }; 6.185 + } 6.186 + 6.187 + private List<Path> walkTree(Path dir) throws IOException { 6.188 + final List<Path> files = new ArrayList<Path>(); 6.189 + Files.walkFileTree(dir, new SimpleFileVisitor<Path>() { 6.190 + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) 6.191 + throws IOException { 6.192 + if (file.toFile().getName().endsWith(".class")) { 6.193 + files.add(file); 6.194 + } 6.195 + return FileVisitResult.CONTINUE; 6.196 + } 6.197 + }); 6.198 + return files; 6.199 + } 6.200 + 6.201 + class DirectoryIterator implements Iterator<ClassFile> { 6.202 + private List<Path> entries; 6.203 + private int index = 0; 6.204 + DirectoryIterator() throws IOException { 6.205 + entries = walkTree(path); 6.206 + index = 0; 6.207 + } 6.208 + 6.209 + public boolean hasNext() { 6.210 + return index != entries.size(); 6.211 + } 6.212 + 6.213 + public ClassFile next() { 6.214 + if (!hasNext()) { 6.215 + throw new NoSuchElementException(); 6.216 + } 6.217 + Path path = entries.get(index++); 6.218 + try { 6.219 + return readClassFile(path); 6.220 + } catch (IOException e) { 6.221 + throw new ClassFileError(e); 6.222 + } 6.223 + } 6.224 + 6.225 + public void remove() { 6.226 + throw new UnsupportedOperationException("Not supported yet."); 6.227 + } 6.228 + } 6.229 + } 6.230 + 6.231 + private static class JarFileReader extends ClassFileReader { 6.232 + final JarFile jarfile; 6.233 + JarFileReader(Path path) throws IOException { 6.234 + super(path); 6.235 + this.jarfile = new JarFile(path.toFile()); 6.236 + } 6.237 + 6.238 + public ClassFile getClassFile(String name) throws IOException { 6.239 + if (name.indexOf('.') > 0) { 6.240 + int i = name.lastIndexOf('.'); 6.241 + String entryName = name.replace('.', '/') + ".class"; 6.242 + JarEntry e = jarfile.getJarEntry(entryName); 6.243 + if (e == null) { 6.244 + e = jarfile.getJarEntry(entryName.substring(0, i) + "$" 6.245 + + entryName.substring(i + 1, entryName.length())); 6.246 + } 6.247 + if (e != null) { 6.248 + return readClassFile(e); 6.249 + } 6.250 + } else { 6.251 + JarEntry e = jarfile.getJarEntry(name + ".class"); 6.252 + if (e != null) { 6.253 + return readClassFile(e); 6.254 + } 6.255 + } 6.256 + return null; 6.257 + } 6.258 + 6.259 + private ClassFile readClassFile(JarEntry e) throws IOException { 6.260 + InputStream is = null; 6.261 + try { 6.262 + is = jarfile.getInputStream(e); 6.263 + return ClassFile.read(is); 6.264 + } catch (ConstantPoolException ex) { 6.265 + throw new ClassFileError(ex); 6.266 + } finally { 6.267 + if (is != null) 6.268 + is.close(); 6.269 + } 6.270 + } 6.271 + 6.272 + public Iterable<ClassFile> getClassFiles() throws IOException { 6.273 + final Iterator<ClassFile> iter = new JarFileIterator(); 6.274 + return new Iterable<ClassFile>() { 6.275 + public Iterator<ClassFile> iterator() { 6.276 + return iter; 6.277 + } 6.278 + }; 6.279 + } 6.280 + 6.281 + class JarFileIterator implements Iterator<ClassFile> { 6.282 + private Enumeration<JarEntry> entries; 6.283 + private JarEntry nextEntry; 6.284 + JarFileIterator() { 6.285 + this.entries = jarfile.entries(); 6.286 + while (entries.hasMoreElements()) { 6.287 + JarEntry e = entries.nextElement(); 6.288 + String name = e.getName(); 6.289 + if (name.endsWith(".class")) { 6.290 + this.nextEntry = e; 6.291 + break; 6.292 + } 6.293 + } 6.294 + } 6.295 + 6.296 + public boolean hasNext() { 6.297 + return nextEntry != null; 6.298 + } 6.299 + 6.300 + public ClassFile next() { 6.301 + if (!hasNext()) { 6.302 + throw new NoSuchElementException(); 6.303 + } 6.304 + 6.305 + ClassFile cf; 6.306 + try { 6.307 + cf = readClassFile(nextEntry); 6.308 + } catch (IOException ex) { 6.309 + throw new ClassFileError(ex); 6.310 + } 6.311 + JarEntry entry = nextEntry; 6.312 + nextEntry = null; 6.313 + while (entries.hasMoreElements()) { 6.314 + JarEntry e = entries.nextElement(); 6.315 + String name = e.getName(); 6.316 + if (name.endsWith(".class")) { 6.317 + nextEntry = e; 6.318 + break; 6.319 + } 6.320 + } 6.321 + return cf; 6.322 + } 6.323 + 6.324 + public void remove() { 6.325 + throw new UnsupportedOperationException("Not supported yet."); 6.326 + } 6.327 + } 6.328 + } 6.329 +}
7.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 7.2 +++ b/src/share/classes/com/sun/tools/jdeps/JdepsTask.java Fri Dec 28 22:25:21 2012 -0800 7.3 @@ -0,0 +1,650 @@ 7.4 +/* 7.5 + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. 7.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 7.7 + * 7.8 + * This code is free software; you can redistribute it and/or modify it 7.9 + * under the terms of the GNU General Public License version 2 only, as 7.10 + * published by the Free Software Foundation. Oracle designates this 7.11 + * particular file as subject to the "Classpath" exception as provided 7.12 + * by Oracle in the LICENSE file that accompanied this code. 7.13 + * 7.14 + * This code is distributed in the hope that it will be useful, but WITHOUT 7.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 7.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 7.17 + * version 2 for more details (a copy is included in the LICENSE file that 7.18 + * accompanied this code). 7.19 + * 7.20 + * You should have received a copy of the GNU General Public License version 7.21 + * 2 along with this work; if not, write to the Free Software Foundation, 7.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 7.23 + * 7.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 7.25 + * or visit www.oracle.com if you need additional information or have any 7.26 + * questions. 7.27 + */ 7.28 +package com.sun.tools.jdeps; 7.29 + 7.30 +import com.sun.tools.classfile.ClassFile; 7.31 +import com.sun.tools.classfile.ConstantPoolException; 7.32 +import com.sun.tools.classfile.Dependencies; 7.33 +import com.sun.tools.classfile.Dependencies.ClassFileError; 7.34 +import com.sun.tools.classfile.Dependency; 7.35 +import com.sun.tools.classfile.Dependency.Location; 7.36 +import java.io.*; 7.37 +import java.text.MessageFormat; 7.38 +import java.util.*; 7.39 +import java.util.regex.Pattern; 7.40 + 7.41 +/** 7.42 + * Implementation for the jdeps tool for static class dependency analysis. 7.43 + */ 7.44 +class JdepsTask { 7.45 + class BadArgs extends Exception { 7.46 + static final long serialVersionUID = 8765093759964640721L; 7.47 + BadArgs(String key, Object... args) { 7.48 + super(JdepsTask.this.getMessage(key, args)); 7.49 + this.key = key; 7.50 + this.args = args; 7.51 + } 7.52 + 7.53 + BadArgs showUsage(boolean b) { 7.54 + showUsage = b; 7.55 + return this; 7.56 + } 7.57 + final String key; 7.58 + final Object[] args; 7.59 + boolean showUsage; 7.60 + } 7.61 + 7.62 + static abstract class Option { 7.63 + Option(boolean hasArg, String... aliases) { 7.64 + this.hasArg = hasArg; 7.65 + this.aliases = aliases; 7.66 + } 7.67 + 7.68 + boolean isHidden() { 7.69 + return false; 7.70 + } 7.71 + 7.72 + boolean matches(String opt) { 7.73 + for (String a : aliases) { 7.74 + if (a.equals(opt)) { 7.75 + return true; 7.76 + } else if (opt.startsWith("--") && hasArg && opt.startsWith(a + "=")) { 7.77 + return true; 7.78 + } 7.79 + } 7.80 + return false; 7.81 + } 7.82 + 7.83 + boolean ignoreRest() { 7.84 + return false; 7.85 + } 7.86 + 7.87 + abstract void process(JdepsTask task, String opt, String arg) throws BadArgs; 7.88 + final boolean hasArg; 7.89 + final String[] aliases; 7.90 + } 7.91 + 7.92 + static abstract class HiddenOption extends Option { 7.93 + HiddenOption(boolean hasArg, String... aliases) { 7.94 + super(hasArg, aliases); 7.95 + } 7.96 + 7.97 + boolean isHidden() { 7.98 + return true; 7.99 + } 7.100 + } 7.101 + 7.102 + static Option[] recognizedOptions = { 7.103 + new Option(false, "-h", "-?", "--help") { 7.104 + void process(JdepsTask task, String opt, String arg) { 7.105 + task.options.help = true; 7.106 + } 7.107 + }, 7.108 + new Option(false, "-s", "--summary") { 7.109 + void process(JdepsTask task, String opt, String arg) { 7.110 + task.options.showSummary = true; 7.111 + task.options.verbose = Options.Verbose.SUMMARY; 7.112 + } 7.113 + }, 7.114 + new Option(false, "-v", "--verbose") { 7.115 + void process(JdepsTask task, String opt, String arg) { 7.116 + task.options.verbose = Options.Verbose.VERBOSE; 7.117 + } 7.118 + }, 7.119 + new Option(true, "-V", "--verbose-level") { 7.120 + void process(JdepsTask task, String opt, String arg) throws BadArgs { 7.121 + switch (arg) { 7.122 + case "package": 7.123 + task.options.verbose = Options.Verbose.PACKAGE; 7.124 + break; 7.125 + case "class": 7.126 + task.options.verbose = Options.Verbose.CLASS; 7.127 + break; 7.128 + default: 7.129 + throw task.new BadArgs("err.invalid.arg.for.option", opt); 7.130 + } 7.131 + } 7.132 + }, 7.133 + new Option(true, "-c", "--classpath") { 7.134 + void process(JdepsTask task, String opt, String arg) { 7.135 + task.options.classpath = arg; 7.136 + } 7.137 + }, 7.138 + new Option(true, "-p", "--package") { 7.139 + void process(JdepsTask task, String opt, String arg) { 7.140 + task.options.packageNames.add(arg); 7.141 + } 7.142 + }, 7.143 + new Option(true, "-e", "--regex") { 7.144 + void process(JdepsTask task, String opt, String arg) { 7.145 + task.options.regex = arg; 7.146 + } 7.147 + }, 7.148 + new Option(false, "-P", "--profile") { 7.149 + void process(JdepsTask task, String opt, String arg) { 7.150 + task.options.showProfile = true; 7.151 + } 7.152 + }, 7.153 + new Option(false, "-R", "--recursive") { 7.154 + void process(JdepsTask task, String opt, String arg) { 7.155 + task.options.depth = 0; 7.156 + } 7.157 + }, 7.158 + new HiddenOption(true, "-d", "--depth") { 7.159 + void process(JdepsTask task, String opt, String arg) throws BadArgs { 7.160 + try { 7.161 + task.options.depth = Integer.parseInt(arg); 7.162 + } catch (NumberFormatException e) { 7.163 + throw task.new BadArgs("err.invalid.arg.for.option", opt); 7.164 + } 7.165 + } 7.166 + }, 7.167 + new Option(false, "--version") { 7.168 + void process(JdepsTask task, String opt, String arg) { 7.169 + task.options.version = true; 7.170 + } 7.171 + }, 7.172 + new HiddenOption(false, "--fullversion") { 7.173 + void process(JdepsTask task, String opt, String arg) { 7.174 + task.options.fullVersion = true; 7.175 + } 7.176 + }, 7.177 + 7.178 + }; 7.179 + 7.180 + private static final String PROGNAME = "jdeps"; 7.181 + private final Options options = new Options(); 7.182 + private final List<String> classes = new ArrayList<String>(); 7.183 + 7.184 + private PrintWriter log; 7.185 + void setLog(PrintWriter out) { 7.186 + log = out; 7.187 + } 7.188 + 7.189 + /** 7.190 + * Result codes. 7.191 + */ 7.192 + static final int EXIT_OK = 0, // Completed with no errors. 7.193 + EXIT_ERROR = 1, // Completed but reported errors. 7.194 + EXIT_CMDERR = 2, // Bad command-line arguments 7.195 + EXIT_SYSERR = 3, // System error or resource exhaustion. 7.196 + EXIT_ABNORMAL = 4;// terminated abnormally 7.197 + 7.198 + int run(String[] args) { 7.199 + if (log == null) { 7.200 + log = new PrintWriter(System.out); 7.201 + } 7.202 + try { 7.203 + handleOptions(args); 7.204 + if (options.help) { 7.205 + showHelp(); 7.206 + } 7.207 + if (options.version || options.fullVersion) { 7.208 + showVersion(options.fullVersion); 7.209 + } 7.210 + if (classes.isEmpty() && !options.wildcard) { 7.211 + if (options.help || options.version || options.fullVersion) { 7.212 + return EXIT_OK; 7.213 + } else { 7.214 + showHelp(); 7.215 + return EXIT_CMDERR; 7.216 + } 7.217 + } 7.218 + if (options.regex != null && options.packageNames.size() > 0) { 7.219 + showHelp(); 7.220 + return EXIT_CMDERR; 7.221 + } 7.222 + if (options.showSummary && options.verbose != Options.Verbose.SUMMARY) { 7.223 + showHelp(); 7.224 + return EXIT_CMDERR; 7.225 + } 7.226 + boolean ok = run(); 7.227 + return ok ? EXIT_OK : EXIT_ERROR; 7.228 + } catch (BadArgs e) { 7.229 + reportError(e.key, e.args); 7.230 + if (e.showUsage) { 7.231 + log.println(getMessage("main.usage.summary", PROGNAME)); 7.232 + } 7.233 + return EXIT_CMDERR; 7.234 + } catch (IOException e) { 7.235 + return EXIT_ABNORMAL; 7.236 + } finally { 7.237 + log.flush(); 7.238 + } 7.239 + } 7.240 + 7.241 + private final List<Archive> sourceLocations = new ArrayList<Archive>(); 7.242 + private final Archive NOT_FOUND = new Archive(getMessage("artifact.not.found")); 7.243 + private boolean run() throws IOException { 7.244 + findDependencies(); 7.245 + switch (options.verbose) { 7.246 + case VERBOSE: 7.247 + case CLASS: 7.248 + printClassDeps(log); 7.249 + break; 7.250 + case PACKAGE: 7.251 + printPackageDeps(log); 7.252 + break; 7.253 + case SUMMARY: 7.254 + for (Archive origin : sourceLocations) { 7.255 + for (Archive target : origin.getRequiredArchives()) { 7.256 + log.format("%-30s -> %s%n", origin, target); 7.257 + } 7.258 + } 7.259 + break; 7.260 + default: 7.261 + throw new InternalError("Should not reach here"); 7.262 + } 7.263 + return true; 7.264 + } 7.265 + 7.266 + private boolean isValidClassName(String name) { 7.267 + if (!Character.isJavaIdentifierStart(name.charAt(0))) { 7.268 + return false; 7.269 + } 7.270 + for (int i=1; i < name.length(); i++) { 7.271 + char c = name.charAt(i); 7.272 + if (c != '.' && !Character.isJavaIdentifierPart(c)) { 7.273 + return false; 7.274 + } 7.275 + } 7.276 + return true; 7.277 + } 7.278 + 7.279 + private void findDependencies() throws IOException { 7.280 + Dependency.Finder finder = Dependencies.getClassDependencyFinder(); 7.281 + Dependency.Filter filter; 7.282 + if (options.regex != null) { 7.283 + filter = Dependencies.getRegexFilter(Pattern.compile(options.regex)); 7.284 + } else if (options.packageNames.size() > 0) { 7.285 + filter = Dependencies.getPackageFilter(options.packageNames, false); 7.286 + } else { 7.287 + filter = new Dependency.Filter() { 7.288 + public boolean accepts(Dependency dependency) { 7.289 + return !dependency.getOrigin().equals(dependency.getTarget()); 7.290 + } 7.291 + }; 7.292 + } 7.293 + 7.294 + List<Archive> archives = new ArrayList<Archive>(); 7.295 + Deque<String> roots = new LinkedList<String>(); 7.296 + for (String s : classes) { 7.297 + File f = new File(s); 7.298 + if (f.exists()) { 7.299 + archives.add(new Archive(f, ClassFileReader.newInstance(f))); 7.300 + } else { 7.301 + if (isValidClassName(s)) { 7.302 + roots.add(s); 7.303 + } else { 7.304 + warning("warn.invalid.arg", s); 7.305 + } 7.306 + } 7.307 + } 7.308 + 7.309 + List<Archive> classpaths = new ArrayList<Archive>(); // for class file lookup 7.310 + if (options.wildcard) { 7.311 + // include all archives from classpath to the initial list 7.312 + archives.addAll(getClassPathArchives(options.classpath)); 7.313 + } else { 7.314 + classpaths.addAll(getClassPathArchives(options.classpath)); 7.315 + } 7.316 + classpaths.addAll(PlatformClassPath.getArchives()); 7.317 + 7.318 + // add all archives to the source locations for reporting 7.319 + sourceLocations.addAll(archives); 7.320 + sourceLocations.addAll(classpaths); 7.321 + 7.322 + // Work queue of names of classfiles to be searched. 7.323 + // Entries will be unique, and for classes that do not yet have 7.324 + // dependencies in the results map. 7.325 + Deque<String> deque = new LinkedList<String>(); 7.326 + Set<String> doneClasses = new HashSet<String>(); 7.327 + 7.328 + // get the immediate dependencies of the input files 7.329 + for (Archive a : archives) { 7.330 + for (ClassFile cf : a.reader().getClassFiles()) { 7.331 + String classFileName; 7.332 + try { 7.333 + classFileName = cf.getName(); 7.334 + } catch (ConstantPoolException e) { 7.335 + throw new ClassFileError(e); 7.336 + } 7.337 + a.addClass(classFileName); 7.338 + if (!doneClasses.contains(classFileName)) { 7.339 + doneClasses.add(classFileName); 7.340 + } 7.341 + for (Dependency d : finder.findDependencies(cf)) { 7.342 + if (filter.accepts(d)) { 7.343 + String cn = d.getTarget().getName(); 7.344 + if (!doneClasses.contains(cn) && !deque.contains(cn)) { 7.345 + deque.add(cn); 7.346 + } 7.347 + a.addDependency(d); 7.348 + } 7.349 + } 7.350 + } 7.351 + } 7.352 + 7.353 + // add Archive for looking up classes from the classpath 7.354 + // for transitive dependency analysis 7.355 + Deque<String> unresolved = roots; 7.356 + int depth = options.depth > 0 ? options.depth : Integer.MAX_VALUE; 7.357 + do { 7.358 + String name; 7.359 + while ((name = unresolved.poll()) != null) { 7.360 + if (doneClasses.contains(name)) { 7.361 + continue; 7.362 + } 7.363 + ClassFile cf = null; 7.364 + for (Archive a : classpaths) { 7.365 + cf = a.reader().getClassFile(name); 7.366 + if (cf != null) { 7.367 + String classFileName; 7.368 + try { 7.369 + classFileName = cf.getName(); 7.370 + } catch (ConstantPoolException e) { 7.371 + throw new ClassFileError(e); 7.372 + } 7.373 + a.addClass(classFileName); 7.374 + if (!doneClasses.contains(classFileName)) { 7.375 + // if name is a fully-qualified class name specified 7.376 + // from command-line, this class might already be parsed 7.377 + doneClasses.add(classFileName); 7.378 + if (depth > 0) { 7.379 + for (Dependency d : finder.findDependencies(cf)) { 7.380 + if (filter.accepts(d)) { 7.381 + String cn = d.getTarget().getName(); 7.382 + if (!doneClasses.contains(cn) && !deque.contains(cn)) { 7.383 + deque.add(cn); 7.384 + } 7.385 + a.addDependency(d); 7.386 + } 7.387 + } 7.388 + } 7.389 + } 7.390 + break; 7.391 + } 7.392 + } 7.393 + if (cf == null) { 7.394 + NOT_FOUND.addClass(name); 7.395 + } 7.396 + } 7.397 + unresolved = deque; 7.398 + deque = new LinkedList<String>(); 7.399 + } while (!unresolved.isEmpty() && depth-- > 0); 7.400 + } 7.401 + 7.402 + private void printPackageDeps(PrintWriter out) { 7.403 + for (Archive source : sourceLocations) { 7.404 + SortedMap<Location, SortedSet<Location>> deps = source.getDependencies(); 7.405 + if (deps.isEmpty()) 7.406 + continue; 7.407 + 7.408 + for (Archive target : source.getRequiredArchives()) { 7.409 + out.format("%s -> %s%n", source, target); 7.410 + } 7.411 + 7.412 + Map<String, Archive> pkgs = new TreeMap<String, Archive>(); 7.413 + SortedMap<String, Archive> targets = new TreeMap<String, Archive>(); 7.414 + String pkg = ""; 7.415 + for (Map.Entry<Location, SortedSet<Location>> e : deps.entrySet()) { 7.416 + String cn = e.getKey().getClassName(); 7.417 + String p = packageOf(e.getKey()); 7.418 + Archive origin = Archive.find(e.getKey()); 7.419 + assert origin != null; 7.420 + if (!pkgs.containsKey(p)) { 7.421 + pkgs.put(p, origin); 7.422 + } else if (pkgs.get(p) != origin) { 7.423 + warning("warn.split.package", p, origin, pkgs.get(p)); 7.424 + } 7.425 + 7.426 + if (!p.equals(pkg)) { 7.427 + printTargets(out, targets); 7.428 + pkg = p; 7.429 + targets.clear(); 7.430 + out.format(" %s (%s)%n", p, origin.getFileName()); 7.431 + } 7.432 + 7.433 + for (Location t : e.getValue()) { 7.434 + p = packageOf(t); 7.435 + Archive target = Archive.find(t); 7.436 + if (!targets.containsKey(p)) { 7.437 + targets.put(p, target); 7.438 + } 7.439 + } 7.440 + } 7.441 + printTargets(out, targets); 7.442 + out.println(); 7.443 + } 7.444 + } 7.445 + 7.446 + private void printTargets(PrintWriter out, Map<String, Archive> targets) { 7.447 + for (Map.Entry<String, Archive> t : targets.entrySet()) { 7.448 + String pn = t.getKey(); 7.449 + out.format(" -> %-40s %s%n", pn, getPackageInfo(pn, t.getValue())); 7.450 + } 7.451 + } 7.452 + 7.453 + private String getPackageInfo(String pn, Archive source) { 7.454 + if (PlatformClassPath.contains(source)) { 7.455 + String name = PlatformClassPath.getProfileName(pn); 7.456 + if (name.isEmpty()) { 7.457 + return "JDK internal API (" + source.getFileName() + ")"; 7.458 + } 7.459 + return options.showProfile ? name : ""; 7.460 + } 7.461 + return source.getFileName(); 7.462 + } 7.463 + 7.464 + private static String packageOf(Location loc) { 7.465 + String pkg = loc.getPackageName(); 7.466 + return pkg.isEmpty() ? "<unnamed>" : pkg; 7.467 + } 7.468 + 7.469 + private void printClassDeps(PrintWriter out) { 7.470 + for (Archive source : sourceLocations) { 7.471 + SortedMap<Location, SortedSet<Location>> deps = source.getDependencies(); 7.472 + if (deps.isEmpty()) 7.473 + continue; 7.474 + 7.475 + for (Archive target : source.getRequiredArchives()) { 7.476 + out.format("%s -> %s%n", source, target); 7.477 + } 7.478 + out.format("%s%n", source); 7.479 + for (Map.Entry<Location, SortedSet<Location>> e : deps.entrySet()) { 7.480 + String cn = e.getKey().getClassName(); 7.481 + Archive origin = Archive.find(e.getKey()); 7.482 + out.format(" %s (%s)%n", cn, origin.getFileName()); 7.483 + for (Location t : e.getValue()) { 7.484 + cn = t.getClassName(); 7.485 + Archive target = Archive.find(t); 7.486 + out.format(" -> %-60s %s%n", cn, getPackageInfo(t.getPackageName(), target)); 7.487 + } 7.488 + } 7.489 + out.println(); 7.490 + } 7.491 + } 7.492 + public void handleOptions(String[] args) throws BadArgs { 7.493 + // process options 7.494 + for (int i=0; i < args.length; i++) { 7.495 + if (args[i].charAt(0) == '-') { 7.496 + String name = args[i]; 7.497 + Option option = getOption(name); 7.498 + String param = null; 7.499 + if (option.hasArg) { 7.500 + if (name.startsWith("--") && name.indexOf('=') > 0) { 7.501 + param = name.substring(name.indexOf('=') + 1, name.length()); 7.502 + } else if (i + 1 < args.length) { 7.503 + param = args[++i]; 7.504 + } 7.505 + if (param == null || param.isEmpty() || param.charAt(0) == '-') { 7.506 + throw new BadArgs("err.missing.arg", name).showUsage(true); 7.507 + } 7.508 + } 7.509 + option.process(this, name, param); 7.510 + if (option.ignoreRest()) { 7.511 + i = args.length; 7.512 + } 7.513 + } else { 7.514 + // process rest of the input arguments 7.515 + for (; i < args.length; i++) { 7.516 + String name = args[i]; 7.517 + if (name.charAt(0) == '-') { 7.518 + throw new BadArgs("err.option.after.class", name).showUsage(true); 7.519 + } 7.520 + if (name.equals("*") || name.equals("\"*\"")) { 7.521 + options.wildcard = true; 7.522 + } else { 7.523 + classes.add(name); 7.524 + } 7.525 + } 7.526 + } 7.527 + } 7.528 + } 7.529 + 7.530 + private Option getOption(String name) throws BadArgs { 7.531 + for (Option o : recognizedOptions) { 7.532 + if (o.matches(name)) { 7.533 + return o; 7.534 + } 7.535 + } 7.536 + throw new BadArgs("err.unknown.option", name).showUsage(true); 7.537 + } 7.538 + 7.539 + private void reportError(String key, Object... args) { 7.540 + log.println(getMessage("error.prefix") + " " + getMessage(key, args)); 7.541 + } 7.542 + 7.543 + private void warning(String key, Object... args) { 7.544 + log.println(getMessage("warn.prefix") + " " + getMessage(key, args)); 7.545 + } 7.546 + 7.547 + private void showHelp() { 7.548 + log.println(getMessage("main.usage", PROGNAME)); 7.549 + for (Option o : recognizedOptions) { 7.550 + String name = o.aliases[0].substring(1); // there must always be at least one name 7.551 + name = name.charAt(0) == '-' ? name.substring(1) : name; 7.552 + if (o.isHidden() || name.equals("h")) { 7.553 + continue; 7.554 + } 7.555 + log.println(getMessage("main.opt." + name)); 7.556 + } 7.557 + } 7.558 + 7.559 + private void showVersion(boolean full) { 7.560 + log.println(version(full ? "full" : "release")); 7.561 + } 7.562 + 7.563 + private String version(String key) { 7.564 + // key=version: mm.nn.oo[-milestone] 7.565 + // key=full: mm.mm.oo[-milestone]-build 7.566 + if (ResourceBundleHelper.versionRB == null) { 7.567 + return System.getProperty("java.version"); 7.568 + } 7.569 + try { 7.570 + return ResourceBundleHelper.versionRB.getString(key); 7.571 + } catch (MissingResourceException e) { 7.572 + return getMessage("version.unknown", System.getProperty("java.version")); 7.573 + } 7.574 + } 7.575 + 7.576 + public String getMessage(String key, Object... args) { 7.577 + try { 7.578 + return MessageFormat.format(ResourceBundleHelper.bundle.getString(key), args); 7.579 + } catch (MissingResourceException e) { 7.580 + throw new InternalError("Missing message: " + key); 7.581 + } 7.582 + } 7.583 + 7.584 + private static class Options { 7.585 + enum Verbose { 7.586 + CLASS, 7.587 + PACKAGE, 7.588 + SUMMARY, 7.589 + VERBOSE 7.590 + }; 7.591 + 7.592 + boolean help; 7.593 + boolean version; 7.594 + boolean fullVersion; 7.595 + boolean showFlags; 7.596 + boolean showProfile; 7.597 + boolean showSummary; 7.598 + boolean wildcard; 7.599 + String regex; 7.600 + String classpath = ""; 7.601 + int depth = 1; 7.602 + Verbose verbose = Verbose.PACKAGE; 7.603 + Set<String> packageNames = new HashSet<String>(); 7.604 + } 7.605 + 7.606 + private static class ResourceBundleHelper { 7.607 + static final ResourceBundle versionRB; 7.608 + static final ResourceBundle bundle; 7.609 + 7.610 + static { 7.611 + Locale locale = Locale.getDefault(); 7.612 + try { 7.613 + bundle = ResourceBundle.getBundle("com.sun.tools.jdeps.resources.jdeps", locale); 7.614 + } catch (MissingResourceException e) { 7.615 + throw new InternalError("Cannot find jdeps resource bundle for locale " + locale); 7.616 + } 7.617 + try { 7.618 + versionRB = ResourceBundle.getBundle("com.sun.tools.jdeps.resources.version"); 7.619 + } catch (MissingResourceException e) { 7.620 + throw new InternalError("version.resource.missing"); 7.621 + } 7.622 + } 7.623 + } 7.624 + 7.625 + private List<Archive> getArchives(List<String> filenames) throws IOException { 7.626 + List<Archive> result = new ArrayList<Archive>(); 7.627 + for (String s : filenames) { 7.628 + File f = new File(s); 7.629 + if (f.exists()) { 7.630 + result.add(new Archive(f, ClassFileReader.newInstance(f))); 7.631 + } else { 7.632 + warning("warn.file.not.exist", s); 7.633 + } 7.634 + } 7.635 + return result; 7.636 + } 7.637 + 7.638 + private List<Archive> getClassPathArchives(String paths) throws IOException { 7.639 + List<Archive> result = new ArrayList<Archive>(); 7.640 + if (paths.isEmpty()) { 7.641 + return result; 7.642 + } 7.643 + for (String p : paths.split(File.pathSeparator)) { 7.644 + if (p.length() > 0) { 7.645 + File f = new File(p); 7.646 + if (f.exists()) { 7.647 + result.add(new Archive(f, ClassFileReader.newInstance(f))); 7.648 + } 7.649 + } 7.650 + } 7.651 + return result; 7.652 + } 7.653 +}
8.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 8.2 +++ b/src/share/classes/com/sun/tools/jdeps/Main.java Fri Dec 28 22:25:21 2012 -0800 8.3 @@ -0,0 +1,66 @@ 8.4 +/* 8.5 + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. 8.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 8.7 + * 8.8 + * This code is free software; you can redistribute it and/or modify it 8.9 + * under the terms of the GNU General Public License version 2 only, as 8.10 + * published by the Free Software Foundation. Oracle designates this 8.11 + * particular file as subject to the "Classpath" exception as provided 8.12 + * by Oracle in the LICENSE file that accompanied this code. 8.13 + * 8.14 + * This code is distributed in the hope that it will be useful, but WITHOUT 8.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 8.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 8.17 + * version 2 for more details (a copy is included in the LICENSE file that 8.18 + * accompanied this code). 8.19 + * 8.20 + * You should have received a copy of the GNU General Public License version 8.21 + * 2 along with this work; if not, write to the Free Software Foundation, 8.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 8.23 + * 8.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 8.25 + * or visit www.oracle.com if you need additional information or have any 8.26 + * questions. 8.27 + */ 8.28 + 8.29 +package com.sun.tools.jdeps; 8.30 + 8.31 +import java.io.*; 8.32 + 8.33 +/** 8.34 + * 8.35 + * Usage: 8.36 + * jdeps [options] files ... 8.37 + * where options include: 8.38 + * -p package-name restrict analysis to classes in this package 8.39 + * (may be given multiple times) 8.40 + * -e regex restrict analysis to packages matching pattern 8.41 + * (-p and -e are exclusive) 8.42 + * -v show class-level dependencies 8.43 + * default: package-level dependencies 8.44 + * -r --recursive transitive dependencies analysis 8.45 + * -classpath paths Classpath to locate class files 8.46 + * -all process all class files in the given classpath 8.47 + */ 8.48 +public class Main { 8.49 + public static void main(String... args) throws Exception { 8.50 + JdepsTask t = new JdepsTask(); 8.51 + int rc = t.run(args); 8.52 + System.exit(rc); 8.53 + } 8.54 + 8.55 + 8.56 + /** 8.57 + * Entry point that does <i>not</i> call System.exit. 8.58 + * 8.59 + * @param args command line arguments 8.60 + * @param out output stream 8.61 + * @return an exit code. 0 means success, non-zero means an error occurred. 8.62 + */ 8.63 + public static int run(String[] args, PrintWriter out) { 8.64 + JdepsTask t = new JdepsTask(); 8.65 + t.setLog(out); 8.66 + return t.run(args); 8.67 + } 8.68 +} 8.69 +
9.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 9.2 +++ b/src/share/classes/com/sun/tools/jdeps/PlatformClassPath.java Fri Dec 28 22:25:21 2012 -0800 9.3 @@ -0,0 +1,169 @@ 9.4 +/* 9.5 + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. 9.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 9.7 + * 9.8 + * This code is free software; you can redistribute it and/or modify it 9.9 + * under the terms of the GNU General Public License version 2 only, as 9.10 + * published by the Free Software Foundation. Oracle designates this 9.11 + * particular file as subject to the "Classpath" exception as provided 9.12 + * by Oracle in the LICENSE file that accompanied this code. 9.13 + * 9.14 + * This code is distributed in the hope that it will be useful, but WITHOUT 9.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 9.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 9.17 + * version 2 for more details (a copy is included in the LICENSE file that 9.18 + * accompanied this code). 9.19 + * 9.20 + * You should have received a copy of the GNU General Public License version 9.21 + * 2 along with this work; if not, write to the Free Software Foundation, 9.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 9.23 + * 9.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 9.25 + * or visit www.oracle.com if you need additional information or have any 9.26 + * questions. 9.27 + */ 9.28 +package com.sun.tools.jdeps; 9.29 + 9.30 +import java.io.File; 9.31 +import java.io.IOException; 9.32 +import java.nio.file.FileVisitResult; 9.33 +import java.nio.file.Files; 9.34 +import java.nio.file.Path; 9.35 +import java.nio.file.SimpleFileVisitor; 9.36 +import java.nio.file.attribute.BasicFileAttributes; 9.37 +import java.util.*; 9.38 + 9.39 +/** 9.40 + * ClassPath for Java SE and JDK 9.41 + */ 9.42 +class PlatformClassPath { 9.43 + /* 9.44 + * Profiles for Java SE 9.45 + * 9.46 + * This is a temporary workaround until a common API is defined for langtools 9.47 + * to determine which profile a given classname belongs to. The list of 9.48 + * packages and profile names are hardcoded in jdk.properties and 9.49 + * split packages are not supported. 9.50 + */ 9.51 + static class Profile { 9.52 + final String name; 9.53 + final Set<String> packages; 9.54 + 9.55 + Profile(String name) { 9.56 + this.name = name; 9.57 + this.packages = new HashSet<String>(); 9.58 + } 9.59 + } 9.60 + 9.61 + private final static String JAVAFX = "javafx"; 9.62 + private final static Map<String,Profile> map = getProfilePackages(); 9.63 + static String getProfileName(String packageName) { 9.64 + Profile profile = map.get(packageName); 9.65 + if (packageName.startsWith(JAVAFX + ".")) { 9.66 + profile = map.get(JAVAFX); 9.67 + } 9.68 + return profile != null ? profile.name : ""; 9.69 + } 9.70 + 9.71 + private final static List<Archive> javaHomeArchives = init(); 9.72 + static List<Archive> getArchives() { 9.73 + return javaHomeArchives; 9.74 + } 9.75 + 9.76 + static boolean contains(Archive archive) { 9.77 + return javaHomeArchives.contains(archive); 9.78 + } 9.79 + 9.80 + private static List<Archive> init() { 9.81 + List<Archive> result = new ArrayList<Archive>(); 9.82 + String javaHome = System.getProperty("java.home"); 9.83 + List<File> files = new ArrayList<File>(); 9.84 + File jre = new File(javaHome, "jre"); 9.85 + File lib = new File(javaHome, "lib"); 9.86 + 9.87 + try { 9.88 + if (jre.exists() && jre.isDirectory()) { 9.89 + result.addAll(addJarFiles(new File(jre, "lib"))); 9.90 + result.addAll(addJarFiles(lib)); 9.91 + } else if (lib.exists() && lib.isDirectory()) { 9.92 + // either a JRE or a jdk build image 9.93 + File classes = new File(javaHome, "classes"); 9.94 + if (classes.exists() && classes.isDirectory()) { 9.95 + // jdk build outputdir 9.96 + result.add(new Archive(classes, ClassFileReader.newInstance(classes))); 9.97 + } 9.98 + // add other JAR files 9.99 + result.addAll(addJarFiles(lib)); 9.100 + } else { 9.101 + throw new RuntimeException("\"" + javaHome + "\" not a JDK home"); 9.102 + } 9.103 + } catch (IOException e) { 9.104 + throw new RuntimeException(e); 9.105 + } 9.106 + 9.107 + // add a JavaFX profile if there is jfxrt.jar 9.108 + for (Archive archive : result) { 9.109 + if (archive.getFileName().equals("jfxrt.jar")) { 9.110 + map.put(JAVAFX, new Profile("jfxrt.jar")); 9.111 + } 9.112 + } 9.113 + return result; 9.114 + } 9.115 + 9.116 + private static List<Archive> addJarFiles(File f) throws IOException { 9.117 + final List<Archive> result = new ArrayList<Archive>(); 9.118 + final Path root = f.toPath(); 9.119 + final Path ext = root.resolve("ext"); 9.120 + Files.walkFileTree(root, new SimpleFileVisitor<Path>() { 9.121 + @Override 9.122 + public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) 9.123 + throws IOException 9.124 + { 9.125 + if (dir.equals(root) || dir.equals(ext)) { 9.126 + return FileVisitResult.CONTINUE; 9.127 + } else { 9.128 + // skip other cobundled JAR files 9.129 + return FileVisitResult.SKIP_SUBTREE; 9.130 + } 9.131 + } 9.132 + @Override 9.133 + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) 9.134 + throws IOException 9.135 + { 9.136 + File f = file.toFile(); 9.137 + String fn = f.getName(); 9.138 + if (fn.endsWith(".jar") && !fn.equals("alt-rt.jar")) { 9.139 + result.add(new Archive(f, ClassFileReader.newInstance(f))); 9.140 + } 9.141 + return FileVisitResult.CONTINUE; 9.142 + } 9.143 + }); 9.144 + return result; 9.145 + } 9.146 + 9.147 + private static Map<String,Profile> getProfilePackages() { 9.148 + Map<String,Profile> map = new HashMap<String,Profile>(); 9.149 + 9.150 + // read the properties as a ResourceBundle as the build compiles 9.151 + // the properties file into Java class. Another alternative is 9.152 + // to load it as Properties and fix the build to exclude this file. 9.153 + ResourceBundle profileBundle = 9.154 + ResourceBundle.getBundle("com.sun.tools.jdeps.resources.jdk"); 9.155 + 9.156 + int i=1; 9.157 + String key; 9.158 + while (profileBundle.containsKey((key = "profile." + i + ".name"))) { 9.159 + Profile profile = new Profile(profileBundle.getString(key)); 9.160 + String n = profileBundle.getString("profile." + i + ".packages"); 9.161 + String[] pkgs = n.split("\\s+"); 9.162 + for (String p : pkgs) { 9.163 + if (p.isEmpty()) continue; 9.164 + assert(map.containsKey(p) == false); 9.165 + profile.packages.add(p); 9.166 + map.put(p, profile); 9.167 + } 9.168 + i++; 9.169 + } 9.170 + return map; 9.171 + } 9.172 +}
10.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 10.2 +++ b/src/share/classes/com/sun/tools/jdeps/resources/jdeps.properties Fri Dec 28 22:25:21 2012 -0800 10.3 @@ -0,0 +1,57 @@ 10.4 +main.usage.summary=\ 10.5 +Usage: {0} <options> <classes...>\n\ 10.6 +use -h, -? or --help for a list of possible options 10.7 + 10.8 +main.usage=\ 10.9 +Usage: {0} <options> <classes...>\n\ 10.10 +where <classes> can be a pathname to a .class file, a directory, a JAR file,\n\ 10.11 +or a fully-qualified classname or wildcard "*". Possible options include: 10.12 + 10.13 +error.prefix=Error: 10.14 +warn.prefix=Warning: 10.15 + 10.16 +main.opt.h=\ 10.17 +\ -h -? --help Print this usage message 10.18 + 10.19 +main.opt.version=\ 10.20 +\ --version Version information 10.21 + 10.22 +main.opt.V=\ 10.23 +\ -V <level> --verbose-level=<level> Print package-level or class-level dependencies\n\ 10.24 +\ Valid levels are: "package" and "class" 10.25 + 10.26 +main.opt.v=\ 10.27 +\ -v --verbose Print additional information 10.28 + 10.29 +main.opt.s=\ 10.30 +\ -s --summary Print dependency summary only 10.31 + 10.32 +main.opt.p=\ 10.33 +\ -p <pkg name> --package=<pkg name> Restrict analysis to classes in this package\n\ 10.34 +\ (may be given multiple times) 10.35 + 10.36 +main.opt.e=\ 10.37 +\ -e <regex> --regex=<regex> Restrict analysis to packages matching pattern\n\ 10.38 +\ (-p and -e are exclusive) 10.39 + 10.40 +main.opt.P=\ 10.41 +\ -P --profile Show profile or the file containing a package 10.42 + 10.43 +main.opt.c=\ 10.44 +\ -c <path> --classpath=<path> Specify where to find class files 10.45 + 10.46 +main.opt.R=\ 10.47 +\ -R --recursive Recursively traverse all dependencies 10.48 + 10.49 +main.opt.d=\ 10.50 +\ -d <depth> --depth=<depth> Specify the depth of the transitive dependency analysis 10.51 + 10.52 +err.unknown.option=unknown option: {0} 10.53 +err.missing.arg=no value given for {0} 10.54 +err.internal.error=internal error: {0} {1} {2} 10.55 +err.invalid.arg.for.option=invalid argument for option: {0} 10.56 +err.option.after.class=option must be specified before classes: {0} 10.57 +warn.invalid.arg=Invalid classname or pathname not exist: {0} 10.58 +warn.split.package=package {0} defined in {1} {2} 10.59 + 10.60 +artifact.not.found=not found
11.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 11.2 +++ b/src/share/classes/com/sun/tools/jdeps/resources/jdk.properties Fri Dec 28 22:25:21 2012 -0800 11.3 @@ -0,0 +1,262 @@ 11.4 +# This properties file does not need localization. 11.5 + 11.6 +profile.1.name = compact1 11.7 +profile.1.packages = \ 11.8 + java.io \ 11.9 + java.lang \ 11.10 + java.lang.annotation \ 11.11 + java.lang.invoke \ 11.12 + java.lang.ref \ 11.13 + java.lang.reflect \ 11.14 + java.math \ 11.15 + java.net \ 11.16 + java.nio \ 11.17 + java.nio.channels \ 11.18 + java.nio.channels.spi \ 11.19 + java.nio.charset \ 11.20 + java.nio.charset.spi \ 11.21 + java.nio.file \ 11.22 + java.nio.file.attribute \ 11.23 + java.nio.file.spi \ 11.24 + java.security \ 11.25 + java.security.cert \ 11.26 + java.security.interfaces \ 11.27 + java.security.spec \ 11.28 + java.text \ 11.29 + java.text.spi \ 11.30 + java.util \ 11.31 + java.util.concurrent \ 11.32 + java.util.concurrent.atomic \ 11.33 + java.util.concurrent.locks \ 11.34 + java.util.jar \ 11.35 + java.util.logging \ 11.36 + java.util.regex \ 11.37 + java.util.spi \ 11.38 + java.util.zip \ 11.39 + javax.crypto \ 11.40 + javax.crypto.interfaces \ 11.41 + javax.crypto.spec \ 11.42 + javax.security.auth \ 11.43 + javax.security.auth.callback \ 11.44 + javax.security.auth.login \ 11.45 + javax.security.auth.spi \ 11.46 + javax.security.auth.x500 \ 11.47 + javax.net \ 11.48 + javax.net.ssl \ 11.49 + javax.security.cert \ 11.50 + \ 11.51 + com.sun.net.ssl \ 11.52 + com.sun.nio.file \ 11.53 + com.sun.nio.sctp \ 11.54 + com.sun.security.auth \ 11.55 + com.sun.security.auth.login 11.56 + 11.57 +profile.2.name = compact2 11.58 +profile.2.packages = \ 11.59 + java.sql \ 11.60 + javax.sql \ 11.61 + javax.xml \ 11.62 + javax.xml.datatype \ 11.63 + javax.xml.namespace \ 11.64 + javax.xml.parsers \ 11.65 + javax.xml.stream \ 11.66 + javax.xml.stream.events \ 11.67 + javax.xml.stream.util \ 11.68 + javax.xml.transform \ 11.69 + javax.xml.transform.dom \ 11.70 + javax.xml.transform.sax \ 11.71 + javax.xml.transform.stax \ 11.72 + javax.xml.transform.stream \ 11.73 + javax.xml.validation \ 11.74 + javax.xml.xpath \ 11.75 + org.w3c.dom \ 11.76 + org.w3c.dom.bootstrap \ 11.77 + org.w3c.dom.events \ 11.78 + org.w3c.dom.ls \ 11.79 + org.xml.sax \ 11.80 + org.xml.sax.ext \ 11.81 + org.xml.sax.helpers \ 11.82 + java.rmi \ 11.83 + java.rmi.activation \ 11.84 + java.rmi.dgc \ 11.85 + java.rmi.registry \ 11.86 + java.rmi.server \ 11.87 + javax.rmi.ssl \ 11.88 + javax.transaction \ 11.89 + javax.transaction.xa \ 11.90 + \ 11.91 + com.sun.net.httpserver \ 11.92 + com.sun.net.httpserver.spi 11.93 + 11.94 +profile.3.name = compact3 11.95 +profile.3.packages = \ 11.96 + java.lang.instrument \ 11.97 + java.lang.management \ 11.98 + java.security.acl \ 11.99 + java.util.prefs \ 11.100 + javax.management \ 11.101 + javax.management.loading \ 11.102 + javax.management.modelmbean \ 11.103 + javax.management.monitor \ 11.104 + javax.management.openmbean \ 11.105 + javax.management.relation \ 11.106 + javax.management.remote \ 11.107 + javax.management.remote.rmi \ 11.108 + javax.management.timer \ 11.109 + javax.naming \ 11.110 + javax.naming.directory \ 11.111 + javax.naming.event \ 11.112 + javax.naming.ldap \ 11.113 + javax.naming.spi \ 11.114 + javax.sql.rowset \ 11.115 + javax.sql.rowset.serial \ 11.116 + javax.sql.rowset.spi \ 11.117 + javax.security.auth.kerberos \ 11.118 + javax.security.sasl \ 11.119 + javax.script \ 11.120 + javax.smartcardio \ 11.121 + javax.xml.crypto \ 11.122 + javax.xml.crypto.dom \ 11.123 + javax.xml.crypto.dsig \ 11.124 + javax.xml.crypto.dsig.dom \ 11.125 + javax.xml.crypto.dsig.keyinfo \ 11.126 + javax.xml.crypto.dsig.spec \ 11.127 + javax.annotation.processing \ 11.128 + javax.lang.model \ 11.129 + javax.lang.model.element \ 11.130 + javax.lang.model.type \ 11.131 + javax.lang.model.util \ 11.132 + javax.tools \ 11.133 + javax.tools.annotation \ 11.134 + org.ietf.jgss \ 11.135 + \ 11.136 + com.sun.management \ 11.137 + com.sun.security.auth.callback \ 11.138 + com.sun.security.auth.module \ 11.139 + com.sun.security.jgss 11.140 + 11.141 +profile.4.name = Full JRE 11.142 +profile.4.packages = \ 11.143 + java.applet \ 11.144 + java.awt \ 11.145 + java.awt.color \ 11.146 + java.awt.datatransfer \ 11.147 + java.awt.dnd \ 11.148 + java.awt.dnd.peer \ 11.149 + java.awt.event \ 11.150 + java.awt.font \ 11.151 + java.awt.geom \ 11.152 + java.awt.im \ 11.153 + java.awt.im.spi \ 11.154 + java.awt.image \ 11.155 + java.awt.image.renderable \ 11.156 + java.awt.peer \ 11.157 + java.awt.print \ 11.158 + java.beans \ 11.159 + java.beans.beancontext \ 11.160 + javax.accessibility \ 11.161 + javax.imageio \ 11.162 + javax.imageio.event \ 11.163 + javax.imageio.metadata \ 11.164 + javax.imageio.plugins.bmp \ 11.165 + javax.imageio.plugins.jpeg \ 11.166 + javax.imageio.spi \ 11.167 + javax.imageio.stream \ 11.168 + javax.print \ 11.169 + javax.print.attribute \ 11.170 + javax.print.attribute.standard \ 11.171 + javax.print.event \ 11.172 + javax.sound.midi \ 11.173 + javax.sound.midi.spi \ 11.174 + javax.sound.sampled \ 11.175 + javax.sound.sampled.spi \ 11.176 + javax.swing \ 11.177 + javax.swing.border \ 11.178 + javax.swing.colorchooser \ 11.179 + javax.swing.event \ 11.180 + javax.swing.filechooser \ 11.181 + javax.swing.plaf \ 11.182 + javax.swing.plaf.basic \ 11.183 + javax.swing.plaf.metal \ 11.184 + javax.swing.plaf.multi \ 11.185 + javax.swing.plaf.nimbus \ 11.186 + javax.swing.plaf.synth \ 11.187 + javax.swing.table \ 11.188 + javax.swing.text \ 11.189 + javax.swing.text.html \ 11.190 + javax.swing.text.html.parser \ 11.191 + javax.swing.text.rtf \ 11.192 + javax.swing.tree \ 11.193 + javax.swing.undo \ 11.194 + javax.activation \ 11.195 + javax.jws \ 11.196 + javax.jws.soap \ 11.197 + javax.rmi \ 11.198 + javax.rmi.CORBA \ 11.199 + javax.xml.bind \ 11.200 + javax.xml.bind.annotation \ 11.201 + javax.xml.bind.annotation.adapters \ 11.202 + javax.xml.bind.attachment \ 11.203 + javax.xml.bind.helpers \ 11.204 + javax.xml.bind.util \ 11.205 + javax.xml.soap \ 11.206 + javax.xml.ws \ 11.207 + javax.xml.ws.handler \ 11.208 + javax.xml.ws.handler.soap \ 11.209 + javax.xml.ws.http \ 11.210 + javax.xml.ws.soap \ 11.211 + javax.xml.ws.spi \ 11.212 + javax.xml.ws.spi.http \ 11.213 + javax.xml.ws.wsaddressing \ 11.214 + javax.annotation \ 11.215 + org.omg.CORBA \ 11.216 + org.omg.CORBA.DynAnyPackage \ 11.217 + org.omg.CORBA.ORBPackage \ 11.218 + org.omg.CORBA.TypeCodePackage \ 11.219 + org.omg.CORBA.portable \ 11.220 + org.omg.CORBA_2_3 \ 11.221 + org.omg.CORBA_2_3.portable \ 11.222 + org.omg.CosNaming \ 11.223 + org.omg.CosNaming.NamingContextExtPackage \ 11.224 + org.omg.CosNaming.NamingContextPackage \ 11.225 + org.omg.Dynamic \ 11.226 + org.omg.DynamicAny \ 11.227 + org.omg.DynamicAny.DynAnyFactoryPackage \ 11.228 + org.omg.DynamicAny.DynAnyPackage \ 11.229 + org.omg.IOP \ 11.230 + org.omg.IOP.CodecFactoryPackage \ 11.231 + org.omg.IOP.CodecPackage \ 11.232 + org.omg.Messaging \ 11.233 + org.omg.PortableInterceptor \ 11.234 + org.omg.PortableInterceptor.ORBInitInfoPackage \ 11.235 + org.omg.PortableServer \ 11.236 + org.omg.PortableServer.CurrentPackage \ 11.237 + org.omg.PortableServer.POAManagerPackage \ 11.238 + org.omg.PortableServer.POAPackage \ 11.239 + org.omg.PortableServer.ServantLocatorPackage \ 11.240 + org.omg.PortableServer.portable \ 11.241 + org.omg.SendingContext \ 11.242 + org.omg.stub.java.rmi \ 11.243 + org.omg.stub.javax.management.remote.rmi 11.244 + 11.245 +# Remaining JDK supported API 11.246 +profile.5.name = JDK tools 11.247 +profile.5.packages = \ 11.248 + com.sun.jdi \ 11.249 + com.sun.jdi.connect \ 11.250 + com.sun.jdi.connect.spi \ 11.251 + com.sun.jdi.event \ 11.252 + com.sun.jdi.request \ 11.253 + com.sun.javadoc \ 11.254 + com.sun.tools.doclets \ 11.255 + com.sun.tools.doctree \ 11.256 + com.sun.source.tree \ 11.257 + com.sun.source.util \ 11.258 + com.sun.tools.attach \ 11.259 + com.sun.tools.attach.spi \ 11.260 + com.sun.tools.jconsole \ 11.261 + com.sun.tools.javac \ 11.262 + com.sun.tools.javah \ 11.263 + com.sun.tools.javap \ 11.264 + com.sun.tools.javadoc \ 11.265 + com.sun.servicetag
12.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 12.2 +++ b/src/share/classes/com/sun/tools/jdeps/resources/version.properties-template Fri Dec 28 22:25:21 2012 -0800 12.3 @@ -0,0 +1,28 @@ 12.4 +# 12.5 +# Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. 12.6 +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 12.7 +# 12.8 +# This code is free software; you can redistribute it and/or modify it 12.9 +# under the terms of the GNU General Public License version 2 only, as 12.10 +# published by the Free Software Foundation. Oracle designates this 12.11 +# particular file as subject to the "Classpath" exception as provided 12.12 +# by Oracle in the LICENSE file that accompanied this code. 12.13 +# 12.14 +# This code is distributed in the hope that it will be useful, but WITHOUT 12.15 +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12.16 +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12.17 +# version 2 for more details (a copy is included in the LICENSE file that 12.18 +# accompanied this code). 12.19 +# 12.20 +# You should have received a copy of the GNU General Public License version 12.21 +# 2 along with this work; if not, write to the Free Software Foundation, 12.22 +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 12.23 +# 12.24 +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 12.25 +# or visit www.oracle.com if you need additional information or have any 12.26 +# questions. 12.27 +# 12.28 + 12.29 +jdk=$(JDK_VERSION) 12.30 +full=$(FULL_VERSION) 12.31 +release=$(RELEASE)
13.1 --- a/test/Makefile Tue Dec 25 17:23:59 2012 -0800 13.2 +++ b/test/Makefile Fri Dec 28 22:25:21 2012 -0800 13.3 @@ -229,7 +229,7 @@ 13.4 all: $(JPRT_CLEAN) jtreg-tests jck-compiler-tests jck-runtime-tests $(JPRT_ARCHIVE_BUNDLE) all-summary 13.5 @echo "Testing completed successfully" 13.6 13.7 -jtreg apt javac javadoc javah javap: $(JPRT_CLEAN) jtreg-tests $(JPRT_ARCHIVE_BUNDLE) jtreg-summary 13.8 +jtreg apt javac javadoc javah javap jdeps: $(JPRT_CLEAN) jtreg-tests $(JPRT_ARCHIVE_BUNDLE) jtreg-summary 13.9 @echo "Testing completed successfully" 13.10 13.11 jck-compiler: $(JPRT_CLEAN) jck-compiler-tests $(JPRT_ARCHIVE_BUNDLE) jck-compiler-summary 13.12 @@ -246,6 +246,7 @@ 13.13 javadoc: JTREG_TESTDIRS = tools/javadoc com/sun/javadoc 13.14 javah: JTREG_TESTDIRS = tools/javah 13.15 javap: JTREG_TESTDIRS = tools/javap 13.16 +jdeps: JTREG_TESTDIRS = tools/jdeps 13.17 13.18 # Run jtreg tests 13.19 # 13.20 @@ -426,7 +427,7 @@ 13.21 13.22 # Phony targets (e.g. these are not filenames) 13.23 .PHONY: all clean \ 13.24 - jtreg javac javadoc javah javap jtreg-tests jtreg-summary check-jtreg \ 13.25 + jtreg javac javadoc javah javap jdeps jtreg-tests jtreg-summary check-jtreg \ 13.26 jck-compiler jck-compiler-tests jck-compiler-summary \ 13.27 jck-runtime jck-runtime-tests jck-runtime-summary check-jck 13.28
14.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 14.2 +++ b/test/tools/jdeps/Basic.java Fri Dec 28 22:25:21 2012 -0800 14.3 @@ -0,0 +1,149 @@ 14.4 +/* 14.5 + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. 14.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 14.7 + * 14.8 + * This code is free software; you can redistribute it and/or modify it 14.9 + * under the terms of the GNU General Public License version 2 only, as 14.10 + * published by the Free Software Foundation. 14.11 + * 14.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 14.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14.15 + * version 2 for more details (a copy is included in the LICENSE file that 14.16 + * accompanied this code). 14.17 + * 14.18 + * You should have received a copy of the GNU General Public License version 14.19 + * 2 along with this work; if not, write to the Free Software Foundation, 14.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 14.21 + * 14.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 14.23 + * or visit www.oracle.com if you need additional information or have any 14.24 + * questions. 14.25 + */ 14.26 + 14.27 +/* 14.28 + * @test 14.29 + * @bug 8003562 14.30 + * @summary Basic tests for jdeps tool 14.31 + * @build Test p.Foo 14.32 + * @run main Basic 14.33 + */ 14.34 + 14.35 +import java.io.File; 14.36 +import java.io.IOException; 14.37 +import java.io.PrintWriter; 14.38 +import java.io.StringWriter; 14.39 +import java.util.*; 14.40 +import java.util.regex.*; 14.41 + 14.42 +public class Basic { 14.43 + public static void main(String... args) throws Exception { 14.44 + int errors = 0; 14.45 + 14.46 + errors += new Basic().run(); 14.47 + if (errors > 0) 14.48 + throw new Exception(errors + " errors found"); 14.49 + } 14.50 + 14.51 + int run() throws IOException { 14.52 + File testDir = new File(System.getProperty("test.classes", ".")); 14.53 + // test a .class file 14.54 + test(new File(testDir, "Test.class"), 14.55 + new String[] {"java.lang", "p"}); 14.56 + // test a directory 14.57 + test(new File(testDir, "p"), 14.58 + new String[] {"java.lang", "java.util"}); 14.59 + // test class-level dependency output 14.60 + test(new File(testDir, "Test.class"), 14.61 + new String[] {"java.lang.Object", "p.Foo"}, 14.62 + new String[] {"-V", "class"}); 14.63 + // test -p option 14.64 + test(new File(testDir, "Test.class"), 14.65 + new String[] {"p.Foo"}, 14.66 + new String[] {"--verbose-level=class", "-p", "p"}); 14.67 + // test -e option 14.68 + test(new File(testDir, "Test.class"), 14.69 + new String[] {"p.Foo"}, 14.70 + new String[] {"-V", "class", "-e", "p\\..*"}); 14.71 + test(new File(testDir, "Test.class"), 14.72 + new String[] {"java.lang"}, 14.73 + new String[] {"-V", "package", "-e", "java\\.lang\\..*"}); 14.74 + // test -classpath and -all options 14.75 + test(null, 14.76 + new String[] {"com.sun.tools.jdeps", "java.lang", "java.util", 14.77 + "java.util.regex", "java.io", "p"}, 14.78 + new String[] {"--classpath", testDir.getPath(), "*"}); 14.79 + return errors; 14.80 + } 14.81 + 14.82 + void test(File file, String[] expect) { 14.83 + test(file, expect, new String[0]); 14.84 + } 14.85 + 14.86 + void test(File file, String[] expect, String[] options) { 14.87 + String[] args; 14.88 + if (file != null) { 14.89 + args = Arrays.copyOf(options, options.length+1); 14.90 + args[options.length] = file.getPath(); 14.91 + } else { 14.92 + args = options; 14.93 + } 14.94 + String[] deps = jdeps(args); 14.95 + checkEqual("dependencies", expect, deps); 14.96 + } 14.97 + 14.98 + String[] jdeps(String... args) { 14.99 + StringWriter sw = new StringWriter(); 14.100 + PrintWriter pw = new PrintWriter(sw); 14.101 + System.err.println("jdeps " + Arrays.toString(args)); 14.102 + int rc = com.sun.tools.jdeps.Main.run(args, pw); 14.103 + pw.close(); 14.104 + String out = sw.toString(); 14.105 + if (!out.isEmpty()) 14.106 + System.err.println(out); 14.107 + if (rc != 0) 14.108 + throw new Error("jdeps failed: rc=" + rc); 14.109 + return findDeps(out); 14.110 + } 14.111 + 14.112 + // Pattern used to parse lines 14.113 + private static Pattern linePattern = Pattern.compile(".*\r?\n"); 14.114 + private static Pattern pattern = Pattern.compile("\\s+ -> (\\S+) +.*"); 14.115 + 14.116 + // Use the linePattern to break the given String into lines, applying 14.117 + // the pattern to each line to see if we have a match 14.118 + private static String[] findDeps(String out) { 14.119 + List<String> result = new ArrayList<>(); 14.120 + Matcher lm = linePattern.matcher(out); // Line matcher 14.121 + Matcher pm = null; // Pattern matcher 14.122 + int lines = 0; 14.123 + while (lm.find()) { 14.124 + lines++; 14.125 + CharSequence cs = lm.group(); // The current line 14.126 + if (pm == null) 14.127 + pm = pattern.matcher(cs); 14.128 + else 14.129 + pm.reset(cs); 14.130 + if (pm.find()) 14.131 + result.add(pm.group(1)); 14.132 + if (lm.end() == out.length()) 14.133 + break; 14.134 + } 14.135 + return result.toArray(new String[0]); 14.136 + } 14.137 + 14.138 + void checkEqual(String label, String[] expect, String[] found) { 14.139 + Set<String> s1 = new HashSet<>(Arrays.asList(expect)); 14.140 + Set<String> s2 = new HashSet<>(Arrays.asList(found)); 14.141 + 14.142 + if (!s1.equals(s2)) 14.143 + error("Unexpected " + label + " found: '" + s2 + "', expected: '" + s1 + "'"); 14.144 + } 14.145 + 14.146 + void error(String msg) { 14.147 + System.err.println("Error: " + msg); 14.148 + errors++; 14.149 + } 14.150 + 14.151 + int errors; 14.152 +}
15.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 15.2 +++ b/test/tools/jdeps/Test.java Fri Dec 28 22:25:21 2012 -0800 15.3 @@ -0,0 +1,28 @@ 15.4 +/* 15.5 + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. 15.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 15.7 + * 15.8 + * This code is free software; you can redistribute it and/or modify it 15.9 + * under the terms of the GNU General Public License version 2 only, as 15.10 + * published by the Free Software Foundation. 15.11 + * 15.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 15.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 15.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 15.15 + * version 2 for more details (a copy is included in the LICENSE file that 15.16 + * accompanied this code). 15.17 + * 15.18 + * You should have received a copy of the GNU General Public License version 15.19 + * 2 along with this work; if not, write to the Free Software Foundation, 15.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 15.21 + * 15.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 15.23 + * or visit www.oracle.com if you need additional information or have any 15.24 + * questions. 15.25 + */ 15.26 + 15.27 +public class Test { 15.28 + public void test() { 15.29 + p.Foo f = new p.Foo(); 15.30 + } 15.31 +}
16.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 16.2 +++ b/test/tools/jdeps/p/Foo.java Fri Dec 28 22:25:21 2012 -0800 16.3 @@ -0,0 +1,35 @@ 16.4 +/* 16.5 + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. 16.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 16.7 + * 16.8 + * This code is free software; you can redistribute it and/or modify it 16.9 + * under the terms of the GNU General Public License version 2 only, as 16.10 + * published by the Free Software Foundation. 16.11 + * 16.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 16.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 16.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 16.15 + * version 2 for more details (a copy is included in the LICENSE file that 16.16 + * accompanied this code). 16.17 + * 16.18 + * You should have received a copy of the GNU General Public License version 16.19 + * 2 along with this work; if not, write to the Free Software Foundation, 16.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 16.21 + * 16.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 16.23 + * or visit www.oracle.com if you need additional information or have any 16.24 + * questions. 16.25 + */ 16.26 + 16.27 +package p; 16.28 + 16.29 +import java.util.List; 16.30 +import java.util.Collections; 16.31 +public class Foo { 16.32 + public static List foo() { 16.33 + return Collections.emptyList(); 16.34 + } 16.35 + 16.36 + public Foo() { 16.37 + } 16.38 +}