src/share/classes/com/sun/tools/jdeps/ClassFileReader.java

Fri, 18 Jul 2014 10:43:41 -0700

author
mchung
date
Fri, 18 Jul 2014 10:43:41 -0700
changeset 2539
a51b7fd0543b
parent 2538
1e39ae45d8ac
child 2702
9ca8d8713094
child 3368
f206126308bc
permissions
-rw-r--r--

8050804: (jdeps) Recommend supported API to replace use of JDK internal API
Reviewed-by: dfuchs

     1 /*
     2  * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4  *
     5  * This code is free software; you can redistribute it and/or modify it
     6  * under the terms of the GNU General Public License version 2 only, as
     7  * published by the Free Software Foundation.  Oracle designates this
     8  * particular file as subject to the "Classpath" exception as provided
     9  * by Oracle in the LICENSE file that accompanied this code.
    10  *
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    14  * version 2 for more details (a copy is included in the LICENSE file that
    15  * accompanied this code).
    16  *
    17  * You should have received a copy of the GNU General Public License version
    18  * 2 along with this work; if not, write to the Free Software Foundation,
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    20  *
    21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    22  * or visit www.oracle.com if you need additional information or have any
    23  * questions.
    24  */
    25 package com.sun.tools.jdeps;
    27 import com.sun.tools.classfile.ClassFile;
    28 import com.sun.tools.classfile.ConstantPoolException;
    29 import com.sun.tools.classfile.Dependencies.ClassFileError;
    30 import java.io.*;
    31 import java.nio.file.FileVisitResult;
    32 import java.nio.file.Files;
    33 import java.nio.file.Path;
    34 import java.nio.file.SimpleFileVisitor;
    35 import java.nio.file.attribute.BasicFileAttributes;
    36 import java.util.*;
    37 import java.util.jar.JarEntry;
    38 import java.util.jar.JarFile;
    40 /**
    41  * ClassFileReader reads ClassFile(s) of a given path that can be
    42  * a .class file, a directory, or a JAR file.
    43  */
    44 public class ClassFileReader {
    45     /**
    46      * Returns a ClassFileReader instance of a given path.
    47      */
    48     public static ClassFileReader newInstance(Path path) throws IOException {
    49         if (!Files.exists(path)) {
    50             throw new FileNotFoundException(path.toString());
    51         }
    53         if (Files.isDirectory(path)) {
    54             return new DirectoryReader(path);
    55         } else if (path.getFileName().toString().endsWith(".jar")) {
    56             return new JarFileReader(path);
    57         } else {
    58             return new ClassFileReader(path);
    59         }
    60     }
    62     /**
    63      * Returns a ClassFileReader instance of a given JarFile.
    64      */
    65     public static ClassFileReader newInstance(Path path, JarFile jf) throws IOException {
    66         return new JarFileReader(path, jf);
    67     }
    69     protected final Path path;
    70     protected final String baseFileName;
    71     protected final List<String> skippedEntries = new ArrayList<>();
    72     protected ClassFileReader(Path path) {
    73         this.path = path;
    74         this.baseFileName = path.getFileName() != null
    75                                 ? path.getFileName().toString()
    76                                 : path.toString();
    77     }
    79     public String getFileName() {
    80         return baseFileName;
    81     }
    83     public List<String> skippedEntries() {
    84         return skippedEntries;
    85     }
    87     /**
    88      * Returns the ClassFile matching the given binary name
    89      * or a fully-qualified class name.
    90      */
    91     public ClassFile getClassFile(String name) throws IOException {
    92         if (name.indexOf('.') > 0) {
    93             int i = name.lastIndexOf('.');
    94             String pathname = name.replace('.', File.separatorChar) + ".class";
    95             if (baseFileName.equals(pathname) ||
    96                     baseFileName.equals(pathname.substring(0, i) + "$" +
    97                                         pathname.substring(i+1, pathname.length()))) {
    98                 return readClassFile(path);
    99             }
   100         } else {
   101             if (baseFileName.equals(name.replace('/', File.separatorChar) + ".class")) {
   102                 return readClassFile(path);
   103             }
   104         }
   105         return null;
   106     }
   108     public Iterable<ClassFile> getClassFiles() throws IOException {
   109         return new Iterable<ClassFile>() {
   110             public Iterator<ClassFile> iterator() {
   111                 return new FileIterator();
   112             }
   113         };
   114     }
   116     protected ClassFile readClassFile(Path p) throws IOException {
   117         InputStream is = null;
   118         try {
   119             is = Files.newInputStream(p);
   120             return ClassFile.read(is);
   121         } catch (ConstantPoolException e) {
   122             throw new ClassFileError(e);
   123         } finally {
   124             if (is != null) {
   125                 is.close();
   126             }
   127         }
   128     }
   130     class FileIterator implements Iterator<ClassFile> {
   131         int count;
   132         FileIterator() {
   133             this.count = 0;
   134         }
   135         public boolean hasNext() {
   136             return count == 0 && baseFileName.endsWith(".class");
   137         }
   139         public ClassFile next() {
   140             if (!hasNext()) {
   141                 throw new NoSuchElementException();
   142             }
   143             try {
   144                 ClassFile cf = readClassFile(path);
   145                 count++;
   146                 return cf;
   147             } catch (IOException e) {
   148                 throw new ClassFileError(e);
   149             }
   150         }
   152         public void remove() {
   153             throw new UnsupportedOperationException("Not supported yet.");
   154         }
   155     }
   157     public String toString() {
   158         return path.toString();
   159     }
   161     private static class DirectoryReader extends ClassFileReader {
   162         DirectoryReader(Path path) throws IOException {
   163             super(path);
   164         }
   166         public ClassFile getClassFile(String name) throws IOException {
   167             if (name.indexOf('.') > 0) {
   168                 int i = name.lastIndexOf('.');
   169                 String pathname = name.replace('.', File.separatorChar) + ".class";
   170                 Path p = path.resolve(pathname);
   171                 if (!Files.exists(p)) {
   172                     p = path.resolve(pathname.substring(0, i) + "$" +
   173                                      pathname.substring(i+1, pathname.length()));
   174                 }
   175                 if (Files.exists(p)) {
   176                     return readClassFile(p);
   177                 }
   178             } else {
   179                 Path p = path.resolve(name + ".class");
   180                 if (Files.exists(p)) {
   181                     return readClassFile(p);
   182                 }
   183             }
   184             return null;
   185         }
   187         public Iterable<ClassFile> getClassFiles() throws IOException {
   188             final Iterator<ClassFile> iter = new DirectoryIterator();
   189             return new Iterable<ClassFile>() {
   190                 public Iterator<ClassFile> iterator() {
   191                     return iter;
   192                 }
   193             };
   194         }
   196         private List<Path> walkTree(Path dir) throws IOException {
   197             final List<Path> files = new ArrayList<Path>();
   198             Files.walkFileTree(dir, new SimpleFileVisitor<Path>() {
   199                 public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
   200                         throws IOException {
   201                     if (file.getFileName().toString().endsWith(".class")) {
   202                         files.add(file);
   203                     }
   204                     return FileVisitResult.CONTINUE;
   205                 }
   206             });
   207             return files;
   208         }
   210         class DirectoryIterator implements Iterator<ClassFile> {
   211             private List<Path> entries;
   212             private int index = 0;
   213             DirectoryIterator() throws IOException {
   214                 entries = walkTree(path);
   215                 index = 0;
   216             }
   218             public boolean hasNext() {
   219                 return index != entries.size();
   220             }
   222             public ClassFile next() {
   223                 if (!hasNext()) {
   224                     throw new NoSuchElementException();
   225                 }
   226                 Path path = entries.get(index++);
   227                 try {
   228                     return readClassFile(path);
   229                 } catch (IOException e) {
   230                     throw new ClassFileError(e);
   231                 }
   232             }
   234             public void remove() {
   235                 throw new UnsupportedOperationException("Not supported yet.");
   236             }
   237         }
   238     }
   240     static class JarFileReader extends ClassFileReader {
   241         private final JarFile jarfile;
   242         JarFileReader(Path path) throws IOException {
   243             this(path, new JarFile(path.toFile(), false));
   244         }
   246         JarFileReader(Path path, JarFile jf) throws IOException {
   247             super(path);
   248             this.jarfile = jf;
   249         }
   251         public ClassFile getClassFile(String name) throws IOException {
   252             if (name.indexOf('.') > 0) {
   253                 int i = name.lastIndexOf('.');
   254                 String entryName = name.replace('.', '/') + ".class";
   255                 JarEntry e = jarfile.getJarEntry(entryName);
   256                 if (e == null) {
   257                     e = jarfile.getJarEntry(entryName.substring(0, i) + "$"
   258                             + entryName.substring(i + 1, entryName.length()));
   259                 }
   260                 if (e != null) {
   261                     return readClassFile(jarfile, e);
   262                 }
   263             } else {
   264                 JarEntry e = jarfile.getJarEntry(name + ".class");
   265                 if (e != null) {
   266                     return readClassFile(jarfile, e);
   267                 }
   268             }
   269             return null;
   270         }
   272         protected ClassFile readClassFile(JarFile jarfile, JarEntry e) throws IOException {
   273             InputStream is = null;
   274             try {
   275                 is = jarfile.getInputStream(e);
   276                 return ClassFile.read(is);
   277             } catch (ConstantPoolException ex) {
   278                 throw new ClassFileError(ex);
   279             } finally {
   280                 if (is != null)
   281                     is.close();
   282             }
   283         }
   285         public Iterable<ClassFile> getClassFiles() throws IOException {
   286             final Iterator<ClassFile> iter = new JarFileIterator(this, jarfile);
   287             return new Iterable<ClassFile>() {
   288                 public Iterator<ClassFile> iterator() {
   289                     return iter;
   290                 }
   291             };
   292         }
   293     }
   295     class JarFileIterator implements Iterator<ClassFile> {
   296         protected final JarFileReader reader;
   297         protected Enumeration<JarEntry> entries;
   298         protected JarFile jf;
   299         protected JarEntry nextEntry;
   300         protected ClassFile cf;
   301         JarFileIterator(JarFileReader reader) {
   302             this(reader, null);
   303         }
   304         JarFileIterator(JarFileReader reader, JarFile jarfile) {
   305             this.reader = reader;
   306             setJarFile(jarfile);
   307         }
   309         void setJarFile(JarFile jarfile) {
   310             if (jarfile == null) return;
   312             this.jf = jarfile;
   313             this.entries = jf.entries();
   314             this.nextEntry = nextEntry();
   315         }
   317         public boolean hasNext() {
   318             if (nextEntry != null && cf != null) {
   319                 return true;
   320             }
   321             while (nextEntry != null) {
   322                 try {
   323                     cf = reader.readClassFile(jf, nextEntry);
   324                     return true;
   325                 } catch (ClassFileError | IOException ex) {
   326                     skippedEntries.add(nextEntry.getName());
   327                 }
   328                 nextEntry = nextEntry();
   329             }
   330             return false;
   331         }
   333         public ClassFile next() {
   334             if (!hasNext()) {
   335                 throw new NoSuchElementException();
   336             }
   337             ClassFile classFile = cf;
   338             cf = null;
   339             nextEntry = nextEntry();
   340             return classFile;
   341         }
   343         protected JarEntry nextEntry() {
   344             while (entries.hasMoreElements()) {
   345                 JarEntry e = entries.nextElement();
   346                 String name = e.getName();
   347                 if (name.endsWith(".class")) {
   348                     return e;
   349                 }
   350             }
   351             return null;
   352         }
   354         public void remove() {
   355             throw new UnsupportedOperationException("Not supported yet.");
   356         }
   357     }
   358 }

mercurial