make/tools/classanalyzer/src/com/sun/classanalyzer/ClassPaths.java

Print this page

        

*** 17,276 **** * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. - * */ package com.sun.classanalyzer; import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; ! import java.util.ArrayList; ! import java.util.Enumeration; ! import java.util.HashSet; ! import java.util.List; ! import java.util.Set; import java.util.jar.JarEntry; import java.util.jar.JarFile; /** * ! * @author mchung */ ! public class ClassPath { ! public class FileInfo { ! File file; ! JarFile jarfile; ! int classCount; ! long filesize; ! FileInfo(File f) throws IOException { ! this.file = f; ! this.classCount = 0; ! if (file.getName().endsWith(".jar")) { ! this.filesize = file.length(); ! jarfile = new JarFile(f); } } ! File getFile() { ! return file; } ! JarFile getJarFile() { ! return jarfile; } ! String getName() throws IOException { ! return file.getCanonicalPath(); } } - private List<FileInfo> fileList = new ArrayList<FileInfo>(); - private static ClassPath instance = new ClassPath(); ! static List<FileInfo> getFileInfos() { ! return instance.fileList; } ! static ClassPath setJDKHome(String jdkhome) throws IOException { List<File> files = new ArrayList<File>(); File jre = new File(jdkhome, "jre"); File lib = new File(jdkhome, "lib"); if (jre.exists() && jre.isDirectory()) { ! listFiles(new File(jre, "lib"), ".jar", files); ! listFiles(lib, ".jar", files); } else if (lib.exists() && lib.isDirectory()) { // either a JRE or a jdk build image - listFiles(lib, ".jar", files); - File classes = new File(jdkhome, "classes"); if (classes.exists() && classes.isDirectory()) { // jdk build outputdir ! instance.add(classes); } } else { throw new RuntimeException("\"" + jdkhome + "\" not a JDK home"); } ! for (File f : files) { ! instance.add(f); } - return instance; } ! static ClassPath setClassPath(String path) throws IOException { ! if (path.endsWith(".class")) { ! // one class file ! File f = new File(path); ! if (!f.exists()) { ! throw new RuntimeException("Classfile \"" + f + "\" doesn't exist"); } ! instance.add(f); ! } else { ! List<File> jarFiles = new ArrayList<File>(); ! String[] locs = path.split(File.pathSeparator); ! for (String p : locs) { ! File f = new File(p); ! if (!f.exists()) { ! throw new RuntimeException("\"" + f + "\" doesn't exist"); } ! if (f.isDirectory()) { ! instance.add(f); // add the directory to look up .class files ! listFiles(f, ".jar", jarFiles); ! } else if (p.endsWith(".jar")) { ! // jar files ! jarFiles.add(f); ! } else { ! throw new RuntimeException("Invalid file \"" + f); } } ! // add jarFiles if any ! for (File f : jarFiles) { ! instance.add(f); } } ! return instance; } ! private void add(File f) throws IOException { ! fileList.add(new FileInfo(f)); } ! public static InputStream open(String pathname) throws IOException { ! for (FileInfo fi : instance.fileList) { ! if (fi.getName().endsWith(".jar")) { ! String path = pathname.replace(File.separatorChar, '/'); ! JarEntry e = fi.jarfile.getJarEntry(path); ! if (e != null) { ! return fi.jarfile.getInputStream(e); } ! } else if (fi.getFile().isDirectory()) { ! File f = new File(fi.getFile(), pathname); ! if (f.exists()) { ! return new FileInputStream(f); } - } else if (fi.file.isFile()) { - if (fi.getName().endsWith(File.separator + pathname)) { - return new FileInputStream(fi.file); } } } - return null; } ! static ClassFileParser parserForClass(String classname) throws IOException { ! String pathname = classname.replace('.', File.separatorChar) + ".class"; ! ClassFileParser cfparser = null; ! for (FileInfo fi : instance.fileList) { ! if (fi.getName().endsWith(".class")) { ! if (fi.getName().endsWith(File.separator + pathname)) { ! cfparser = ClassFileParser.newParser(fi.getFile(), true); ! break; } ! } else if (fi.getName().endsWith(".jar")) { ! JarEntry e = fi.jarfile.getJarEntry(classname.replace('.', '/') + ".class"); ! if (e != null) { ! cfparser = ClassFileParser.newParser(fi.jarfile.getInputStream(e), e.getSize(), true); ! break; } - } else if (fi.getFile().isDirectory()) { - File f = new File(fi.getFile(), pathname); - if (f.exists()) { - cfparser = ClassFileParser.newParser(f, true); - break; } } } ! return cfparser; } ! public static void parseAllClassFiles() throws IOException { ! instance.parseFiles(); } ! private void parseFiles() throws IOException { ! Set<Klass> classes = new HashSet<Klass>(); ! int count = 0; ! for (FileInfo fi : fileList) { ! // filter out public generated classes (i.e. not public API) ! // javax.management.remote.rmi._RMIConnectionImpl_Tie ! // javax.management.remote.rmi._RMIServerImpl_Tie ! if (fi.getName().endsWith(".class")) { ! parseClass(fi); ! } else if (fi.getName().endsWith(".jar")) { ! Enumeration<JarEntry> entries = fi.jarfile.entries(); ! while (entries.hasMoreElements()) { ! JarEntry e = entries.nextElement(); ! if (e.getName().endsWith(".class")) { ! ClassFileParser cfparser = ClassFileParser.newParser(fi.jarfile.getInputStream(e), e.getSize(), true); ! cfparser.parseDependency(false); ! fi.classCount++; ! } else if (!e.isDirectory() && ResourceFile.isResource(e.getName())) { ! ResourceFile.addResource(e.getName(), fi.jarfile.getInputStream(e)); } } ! } else if (fi.getFile().isDirectory()) { ! List<File> files = new ArrayList<File>(); ! listFiles(fi.getFile(), "", files); ! for (File f : files) { ! if (f.getName().endsWith(".class")) { ! parseClass(fi, f); ! } else if (!f.isDirectory() && ResourceFile.isResource(f.getCanonicalPath())) { String pathname = f.getCanonicalPath(); ! String dir = fi.getName(); ! if (!pathname.startsWith(dir)) { throw new RuntimeException("Incorrect pathname " + pathname); } ! String name = pathname.substring(dir.length() + 1, pathname.length()); ! BufferedInputStream in = new BufferedInputStream(new FileInputStream(f)); ! try { ! ResourceFile.addResource(name, in); ! } finally { ! in.close(); } } } } else { ! // should not reach here ! throw new RuntimeException("Unexpected class path: " + fi.getFile()); } } } ! private void parseClass(FileInfo fi) throws IOException { ! parseClass(fi, fi.getFile()); } ! private void parseClass(FileInfo fi, File f) throws IOException { ! ClassFileParser cfparser = ClassFileParser.newParser(f, true); ! cfparser.parseDependency(false); ! fi.classCount++; ! // need to update the filesize for this directory ! fi.filesize += fi.getFile().length(); } ! public static void listFiles(File path, String suffix, List<File> result) { ! if (path.isDirectory()) { ! File[] children = path.listFiles(); ! for (File c : children) { ! listFiles(c, suffix, result); } } else { ! if (suffix.isEmpty() || path.getName().endsWith(suffix)) { ! result.add(path); } } } } --- 17,488 ---- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package com.sun.classanalyzer; + import com.sun.classanalyzer.ClassPaths.*; import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; ! import java.util.*; import java.util.jar.JarEntry; import java.util.jar.JarFile; /** + * Legacy class path. Each entry can be a directory containing + * classes and resources, or a jar file. It supports classpath + * wildcard "*" that lists all jar files in the given directory + * and also recursive wildcard "**" that lists all jar files + * recursively in the given directory and its subdirectories. * ! * @author Mandy Chung */ ! public class ClassPaths { ! protected final List<ClassPath> entries = new LinkedList<ClassPath>(); ! private final Set<Klass> classes = new LinkedHashSet<Klass>(); ! private final Set<ResourceFile> resources = new LinkedHashSet<ResourceFile>(); ! private ClassPaths() { ! } ! public ClassPaths(String... paths) throws IOException { ! for (String p : paths) { ! String cp = p; ! int index = p.indexOf("*"); ! String wildcard = ""; ! if (index >= 0) { ! cp = p.substring(0, index); ! wildcard = p.substring(index, p.length()); } + + File f = new File(cp); + if (!f.exists()) { + throw new RuntimeException("\"" + f + "\" doesn't exist"); } + if (wildcard.isEmpty()) { + if (f.isDirectory()) { + entries.add(new DirClassPath(f)); + } else if (cp.endsWith(".jar")) { + entries.add(new JarFileClassPath(f)); + } else { + entries.add(new ClassPath(f)); + } + } else { + if (wildcard.equals("*")) { + // add jar files in the specified directory + String[] ls = Files.list(f); + for (String s : ls) { + File sf = new File(f, s); + if (s.endsWith(".jar")) { + entries.add(new JarFileClassPath(f)); + } + } + } else if (wildcard.equals("**")) { + // add all jar files in all directories under f + addJarFileEntries(f); + } + } + } + } ! public List<ClassPath> entries() { ! return Collections.unmodifiableList(entries); } ! /** ! * Returns the modules containing the classes and resources being ! * processed. ! */ ! public Set<Module> getModules() { ! Set<Module> modules = new LinkedHashSet<Module>(); ! for (Klass k : classes) { ! modules.add(k.getModule().group()); } + for (ResourceFile r : resources) { + modules.add(r.getModule().group()); + } + return modules; + } ! public void parse() throws IOException { ! parse(null, true, false); } + + public void parse(boolean deps, boolean apiOnly) throws IOException { + parse(null, deps, apiOnly); } ! public void parse(Filter filter, boolean deps, boolean apiOnly) throws IOException { ! ClassResourceVisitor crv = new ClassResourceVisitor(classes, resources, deps, apiOnly); ! ClassPathVisitor cpvisitor = new ClassPathVisitor(crv, filter); ! visit(cpvisitor, filter, null); } ! public void printStats() { ! System.out.format("%d classes %d resource files processed%n", ! classes.size(), resources.size()); ! } ! ! protected void addJarFileEntries(File f) throws IOException { ! List<File> ls; ! if (f.isDirectory()) { ! ls = Files.walkTree(f, new Files.Filter<File>() { ! @Override ! public boolean accept(File f) throws IOException { ! return f.isDirectory() || f.getName().endsWith(".jar"); ! } ! }); ! } else { ! ls = Collections.singletonList(f); ! } ! for (File jf : ls) { ! entries.add(new JarFileClassPath(jf)); ! } ! } ! // FIXME - used by open() method ! static ClassPaths instance = null; ! ! static ClassPaths newInstance(String cpaths) throws IOException { ! String[] paths = cpaths.split(File.pathSeparator); ! instance = new ClassPaths(paths); ! return instance; ! } ! ! static ClassPaths newJDKClassPaths(String jdkhome) throws IOException { ! instance = new JDKClassPaths(jdkhome); ! return instance; ! } ! ! static class JDKClassPaths extends ClassPaths { ! JDKClassPaths(String jdkhome) throws IOException { ! super(); List<File> files = new ArrayList<File>(); File jre = new File(jdkhome, "jre"); File lib = new File(jdkhome, "lib"); + if (jre.exists() && jre.isDirectory()) { ! addJarFiles(new File(jre, "lib")); ! addJarFiles(lib); } else if (lib.exists() && lib.isDirectory()) { // either a JRE or a jdk build image File classes = new File(jdkhome, "classes"); if (classes.exists() && classes.isDirectory()) { // jdk build outputdir ! this.entries.add(new DirClassPath(classes)); } + addJarFiles(lib); } else { throw new RuntimeException("\"" + jdkhome + "\" not a JDK home"); } + } ! // Filter the jigsaw module library, if any ! final void addJarFiles(File dir) throws IOException { ! String[] ls = dir.list(); ! for (String fn : ls) { ! File f = new File(dir, fn); ! if (f.isDirectory() && !fn.equals("modules")) { ! addJarFileEntries(f); ! } else if (f.isFile() && fn.endsWith(".jar")) { ! addJarFileEntries(f); } } + } + } ! /** ! * Visits all entries in the class path. ! */ ! public <R, P> List<R> visit(final ClassPath.Visitor<R, P> visitor, ! final Filter filter, P p) ! throws IOException { ! List<R> result = new ArrayList<R>(); ! for (ClassPath cp : entries) { ! if (filter != null && !filter.accept(cp.file)) { ! continue; } + R r = cp.accept(visitor, p); + result.add(r); + } + return result; + } ! public static interface FileVisitor { ! public void visitClass(File f, String cn) throws IOException; ! public void visitClass(JarFile jf, JarEntry e) throws IOException; ! public void visitResource(File f, String rn) throws IOException; ! public void visitResource(JarFile jf, JarEntry e) throws IOException; } ! public static interface Filter { ! // any file, jar file, directory ! public boolean accept(File f) throws IOException; ! public boolean accept(JarFile jf, JarEntry e) throws IOException; } + + public static class ClassPath { + + private final File file; + private final String name; + + ClassPath(File f) throws IOException { + this.file = f; + this.name = file.getCanonicalPath(); } ! ! File getFile() { ! return file; } + + String getName() { + return name; } ! <R, P> R accept(Visitor<R, P> visitor, P p) throws IOException { ! return visitor.visitFile(file, this, p); } ! public interface Visitor<R, P> { ! public R visitFile(File f, ClassPath cp, P p) throws IOException; ! public R visitDir(File dir, ClassPath cp, P p) throws IOException; ! public R visitJarFile(JarFile jf, ClassPath cp, P p) throws IOException; } + } ! static class JarFileClassPath extends ClassPath { ! JarFile jarfile; ! JarFileClassPath(File f) throws IOException { ! super(f); ! this.jarfile = new JarFile(f); } ! ! @Override ! <R, P> R accept(Visitor<R, P> visitor, P p) throws IOException { ! return visitor.visitJarFile(jarfile, this, p); } } + + class DirClassPath extends ClassPath { + + DirClassPath(File f) throws IOException { + super(f); } + + @Override + <R, P> R accept(final Visitor<R, P> visitor, P p) throws IOException { + return visitor.visitDir(getFile(), this, p); } } ! static class ClassResourceVisitor implements FileVisitor { ! private final Set<Klass> classes; ! private final Set<ResourceFile> resources; ! private final boolean parseDeps; ! private final boolean apiOnly; ! ! ClassResourceVisitor(Set<Klass> classes, ! Set<ResourceFile> resources, ! boolean parseDeps, ! boolean apiOnly) { ! this.classes = classes; ! this.resources = resources; ! this.apiOnly = apiOnly; ! this.parseDeps = parseDeps; } ! ! @Override ! public void visitClass(File f, String cn) throws IOException { ! ClassFileParser cfparser = ClassFileParser.newParser(f, true); ! classes.add(cfparser.this_klass); ! if (parseDeps) { ! cfparser.parseDependency(apiOnly); } } + + @Override + public void visitClass(JarFile jf, JarEntry e) throws IOException { + ClassFileParser cfparser = ClassFileParser.newParser(jf.getInputStream(e), e.getSize(), true); + classes.add(cfparser.this_klass); + if (parseDeps) { + cfparser.parseDependency(apiOnly); } } ! ! @Override ! public void visitResource(File f, String rn) throws IOException { ! BufferedInputStream in = new BufferedInputStream(new FileInputStream(f)); ! try { ! ResourceFile res = ResourceFile.addResource(rn, in); ! resources.add(res); ! } finally { ! in.close(); } + } ! @Override ! public void visitResource(JarFile jf, JarEntry e) throws IOException { ! ResourceFile res = ResourceFile.addResource(e.getName(), jf.getInputStream(e)); ! resources.add(res); } + } ! static class ClassPathVisitor implements ClassPath.Visitor<Void, Void> { ! private final FileVisitor visitor; ! private final Filter filter; ! ! ClassPathVisitor(FileVisitor fv, Filter filter) { ! this.visitor = fv; ! this.filter = filter; } + + @Override + public Void visitFile(File f, ClassPath cp, Void v) throws IOException { + if (filter != null && !filter.accept(f)) { + return null; } ! ! String name = f.getName(); String pathname = f.getCanonicalPath(); ! String root = cp.getName(); ! if (!name.equals(root) && !pathname.equals(root)) { ! if (!pathname.startsWith(root)) { throw new RuntimeException("Incorrect pathname " + pathname); } ! ! name = pathname.substring(root.length() + 1, pathname.length()); } + + if (name.endsWith(".class")) { + visitor.visitClass(f, name); + } else if (!f.isDirectory() && ResourceFile.isResource(f.getCanonicalPath())) { + visitor.visitResource(f, name); } + return null; } + + @Override + public Void visitDir(final File dir, final ClassPath cp, Void v) throws IOException { + List<File> ls = Files.walkTree(dir, null); + for (File f : ls) { + visitFile(f, (ClassPath) cp, null); + } + return null; + } + + @Override + public Void visitJarFile(JarFile jf, ClassPath cp, Void v) throws IOException { + if (filter != null && !filter.accept(cp.getFile())) { + return null; + } + + Enumeration<JarEntry> entries = jf.entries(); + while (entries.hasMoreElements()) { + JarEntry e = entries.nextElement(); + String name = e.getName(); + if (filter != null && !filter.accept(jf, e)) { + continue; + } + if (name.endsWith(".class")) { + visitor.visitClass(jf, e); + } else if (!e.isDirectory() && ResourceFile.isResource(name)) { + visitor.visitResource(jf, e); + } + } + return null; + } + }; + + public static InputStream open(String pathname) throws IOException { + ClassPath.Visitor<InputStream, String> fv = new ClassPath.Visitor<InputStream, String>() { + + @Override + public InputStream visitFile(File f, ClassPath cp, String pathname) throws IOException { + if (cp.getName().endsWith(File.separator + pathname)) { + return new FileInputStream(f); } else { ! return null; } } + + @Override + public InputStream visitDir(File dir, ClassPath cp, String pathname) throws IOException { + File f = new File(cp.getFile(), pathname); + if (f.exists()) { + return new FileInputStream(f); + } else { + return null; } + } ! @Override ! public InputStream visitJarFile(JarFile jf, ClassPath cp, String pathname) throws IOException { ! String p = pathname.replace(File.separatorChar, '/'); ! JarEntry e = jf.getJarEntry(p); ! if (e != null) { ! return jf.getInputStream(e); ! } else { ! return null; } + } + }; ! for (ClassPath cp : instance.entries) { ! InputStream in = cp.accept(fv, pathname); ! if (in != null) { ! return in; ! } ! } ! return null; ! } + public ClassFileParser parserForClass(String classname) throws IOException { + String pathname = classname.replace('.', File.separatorChar) + ".class"; + ClassPath.Visitor<ClassFileParser, String> fv = new ClassPath.Visitor<ClassFileParser, String>() { + + @Override + public ClassFileParser visitFile(File f, ClassPath cp, String pathname) throws IOException { + if (cp.getName().endsWith(File.separator + pathname)) { + return ClassFileParser.newParser(f, true); + } else { + return null; } + } ! @Override ! public ClassFileParser visitDir(File dir, ClassPath cp, String pathname) throws IOException { ! File f = new File(cp.getFile(), pathname); ! if (f.exists()) { ! return ClassFileParser.newParser(f, true); ! } else { ! return null; } + } + @Override + public ClassFileParser visitJarFile(JarFile jf, ClassPath cp, String pathname) throws IOException { + String p = pathname.replace(File.separatorChar, '/'); + JarEntry e = jf.getJarEntry(p); + if (e != null) { + return ClassFileParser.newParser(jf.getInputStream(e), e.getSize(), true); } else { ! return null; } } + }; + + for (ClassPath cp : entries) { + ClassFileParser cfparser = cp.accept(fv, pathname); + if (cfparser != null) { + return cfparser; } + } + return null; + } }