src/share/classes/com/sun/tools/javap/JavapTask.java

Mon, 10 Dec 2012 16:21:26 +0000

author
vromero
date
Mon, 10 Dec 2012 16:21:26 +0000
changeset 1442
fcf89720ae71
parent 1321
489905e5018e
child 1561
073696f59241
permissions
-rw-r--r--

8003967: detect and remove all mutable implicit static enum fields in langtools
Reviewed-by: jjg

     1 /*
     2  * Copyright (c) 2007, 2012, 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  */
    26 package com.sun.tools.javap;
    28 import java.io.EOFException;
    29 import java.io.FileNotFoundException;
    30 import java.io.FilterInputStream;
    31 import java.io.InputStream;
    32 import java.io.IOException;
    33 import java.io.OutputStream;
    34 import java.io.PrintWriter;
    35 import java.io.Reader;
    36 import java.io.StringWriter;
    37 import java.io.Writer;
    38 import java.net.URI;
    39 import java.security.DigestInputStream;
    40 import java.security.MessageDigest;
    41 import java.security.NoSuchAlgorithmException;
    42 import java.text.MessageFormat;
    43 import java.util.ArrayList;
    44 import java.util.Arrays;
    45 import java.util.EnumSet;
    46 import java.util.HashMap;
    47 import java.util.Iterator;
    48 import java.util.List;
    49 import java.util.Locale;
    50 import java.util.Map;
    51 import java.util.MissingResourceException;
    52 import java.util.ResourceBundle;
    54 import javax.lang.model.element.Modifier;
    55 import javax.lang.model.element.NestingKind;
    56 import javax.tools.Diagnostic;
    57 import javax.tools.DiagnosticListener;
    58 import javax.tools.JavaFileManager;
    59 import javax.tools.JavaFileObject;
    60 import javax.tools.StandardJavaFileManager;
    61 import javax.tools.StandardLocation;
    63 import com.sun.tools.classfile.*;
    64 import java.net.URISyntaxException;
    65 import java.net.URL;
    66 import java.net.URLConnection;
    68 /**
    69  *  "Main" class for javap, normally accessed from the command line
    70  *  via Main, or from JSR199 via DisassemblerTool.
    71  *
    72  *  <p><b>This is NOT part of any supported API.
    73  *  If you write code that depends on this, you do so at your own risk.
    74  *  This code and its internal interfaces are subject to change or
    75  *  deletion without notice.</b>
    76  */
    77 public class JavapTask implements DisassemblerTool.DisassemblerTask, Messages {
    78     public class BadArgs extends Exception {
    79         static final long serialVersionUID = 8765093759964640721L;
    80         BadArgs(String key, Object... args) {
    81             super(JavapTask.this.getMessage(key, args));
    82             this.key = key;
    83             this.args = args;
    84         }
    86         BadArgs showUsage(boolean b) {
    87             showUsage = b;
    88             return this;
    89         }
    91         final String key;
    92         final Object[] args;
    93         boolean showUsage;
    94     }
    96     static abstract class Option {
    97         Option(boolean hasArg, String... aliases) {
    98             this.hasArg = hasArg;
    99             this.aliases = aliases;
   100         }
   102         boolean matches(String opt) {
   103             for (String a: aliases) {
   104                 if (a.equals(opt))
   105                     return true;
   106             }
   107             return false;
   108         }
   110         boolean ignoreRest() {
   111             return false;
   112         }
   114         abstract void process(JavapTask task, String opt, String arg) throws BadArgs;
   116         final boolean hasArg;
   117         final String[] aliases;
   118     }
   120     static final Option[] recognizedOptions = {
   122         new Option(false, "-help", "--help", "-?") {
   123             void process(JavapTask task, String opt, String arg) {
   124                 task.options.help = true;
   125             }
   126         },
   128         new Option(false, "-version") {
   129             void process(JavapTask task, String opt, String arg) {
   130                 task.options.version = true;
   131             }
   132         },
   134         new Option(false, "-fullversion") {
   135             void process(JavapTask task, String opt, String arg) {
   136                 task.options.fullVersion = true;
   137             }
   138         },
   140         new Option(false, "-v", "-verbose", "-all") {
   141             void process(JavapTask task, String opt, String arg) {
   142                 task.options.verbose = true;
   143                 task.options.showFlags = true;
   144                 task.options.showAllAttrs = true;
   145             }
   146         },
   148         new Option(false, "-l") {
   149             void process(JavapTask task, String opt, String arg) {
   150                 task.options.showLineAndLocalVariableTables = true;
   151             }
   152         },
   154         new Option(false, "-public") {
   155             void process(JavapTask task, String opt, String arg) {
   156                 task.options.accessOptions.add(opt);
   157                 task.options.showAccess = AccessFlags.ACC_PUBLIC;
   158             }
   159         },
   161         new Option(false, "-protected") {
   162             void process(JavapTask task, String opt, String arg) {
   163                 task.options.accessOptions.add(opt);
   164                 task.options.showAccess = AccessFlags.ACC_PROTECTED;
   165             }
   166         },
   168         new Option(false, "-package") {
   169             void process(JavapTask task, String opt, String arg) {
   170                 task.options.accessOptions.add(opt);
   171                 task.options.showAccess = 0;
   172             }
   173         },
   175         new Option(false, "-p", "-private") {
   176             void process(JavapTask task, String opt, String arg) {
   177                 if (!task.options.accessOptions.contains("-p") &&
   178                         !task.options.accessOptions.contains("-private")) {
   179                     task.options.accessOptions.add(opt);
   180                 }
   181                 task.options.showAccess = AccessFlags.ACC_PRIVATE;
   182             }
   183         },
   185         new Option(false, "-c") {
   186             void process(JavapTask task, String opt, String arg) {
   187                 task.options.showDisassembled = true;
   188             }
   189         },
   191         new Option(false, "-s") {
   192             void process(JavapTask task, String opt, String arg) {
   193                 task.options.showInternalSignatures = true;
   194             }
   195         },
   197 //        new Option(false, "-all") {
   198 //            void process(JavapTask task, String opt, String arg) {
   199 //                task.options.showAllAttrs = true;
   200 //            }
   201 //        },
   203         new Option(false, "-h") {
   204             void process(JavapTask task, String opt, String arg) throws BadArgs {
   205                 throw task.new BadArgs("err.h.not.supported");
   206             }
   207         },
   209         new Option(false, "-verify", "-verify-verbose") {
   210             void process(JavapTask task, String opt, String arg) throws BadArgs {
   211                 throw task.new BadArgs("err.verify.not.supported");
   212             }
   213         },
   215         new Option(false, "-sysinfo") {
   216             void process(JavapTask task, String opt, String arg) {
   217                 task.options.sysInfo = true;
   218             }
   219         },
   221         new Option(false, "-Xold") {
   222             void process(JavapTask task, String opt, String arg) throws BadArgs {
   223                 task.log.println(task.getMessage("warn.Xold.not.supported"));
   224             }
   225         },
   227         new Option(false, "-Xnew") {
   228             void process(JavapTask task, String opt, String arg) throws BadArgs {
   229                 // ignore: this _is_ the new version
   230             }
   231         },
   233         new Option(false, "-XDcompat") {
   234             void process(JavapTask task, String opt, String arg) {
   235                 task.options.compat = true;
   236             }
   237         },
   239         new Option(false, "-XDdetails") {
   240             void process(JavapTask task, String opt, String arg) {
   241                 task.options.details = EnumSet.allOf(InstructionDetailWriter.Kind.class);
   242             }
   244         },
   246         new Option(false, "-XDdetails:") {
   247             @Override
   248             boolean matches(String opt) {
   249                 int sep = opt.indexOf(":");
   250                 return sep != -1 && super.matches(opt.substring(0, sep + 1));
   251             }
   253             void process(JavapTask task, String opt, String arg) throws BadArgs {
   254                 int sep = opt.indexOf(":");
   255                 for (String v: opt.substring(sep + 1).split("[,: ]+")) {
   256                     if (!handleArg(task, v))
   257                         throw task.new BadArgs("err.invalid.arg.for.option", v);
   258                 }
   259             }
   261             boolean handleArg(JavapTask task, String arg) {
   262                 if (arg.length() == 0)
   263                     return true;
   265                 if (arg.equals("all")) {
   266                     task.options.details = EnumSet.allOf(InstructionDetailWriter.Kind.class);
   267                     return true;
   268                 }
   270                 boolean on = true;
   271                 if (arg.startsWith("-")) {
   272                     on = false;
   273                     arg = arg.substring(1);
   274                 }
   276                 for (InstructionDetailWriter.Kind k: InstructionDetailWriter.Kind.values()) {
   277                     if (arg.equalsIgnoreCase(k.option)) {
   278                         if (on)
   279                             task.options.details.add(k);
   280                         else
   281                             task.options.details.remove(k);
   282                         return true;
   283                     }
   284                 }
   285                 return false;
   286             }
   287         },
   289         new Option(false, "-constants") {
   290             void process(JavapTask task, String opt, String arg) {
   291                 task.options.showConstants = true;
   292             }
   293         },
   295         new Option(false, "-XDinner") {
   296             void process(JavapTask task, String opt, String arg) {
   297                 task.options.showInnerClasses = true;
   298             }
   299         },
   301         new Option(false, "-XDindent:") {
   302             @Override
   303             boolean matches(String opt) {
   304                 int sep = opt.indexOf(":");
   305                 return sep != -1 && super.matches(opt.substring(0, sep + 1));
   306             }
   308             void process(JavapTask task, String opt, String arg) throws BadArgs {
   309                 int sep = opt.indexOf(":");
   310                 try {
   311                     task.options.indentWidth = Integer.valueOf(opt.substring(sep + 1));
   312                 } catch (NumberFormatException e) {
   313                 }
   314             }
   315         },
   317         new Option(false, "-XDtab:") {
   318             @Override
   319             boolean matches(String opt) {
   320                 int sep = opt.indexOf(":");
   321                 return sep != -1 && super.matches(opt.substring(0, sep + 1));
   322             }
   324             void process(JavapTask task, String opt, String arg) throws BadArgs {
   325                 int sep = opt.indexOf(":");
   326                 try {
   327                     task.options.tabColumn = Integer.valueOf(opt.substring(sep + 1));
   328                 } catch (NumberFormatException e) {
   329                 }
   330             }
   331         }
   333     };
   335     public JavapTask() {
   336         context = new Context();
   337         context.put(Messages.class, this);
   338         options = Options.instance(context);
   339         attributeFactory = new Attribute.Factory();
   340     }
   342     public JavapTask(Writer out,
   343             JavaFileManager fileManager,
   344             DiagnosticListener<? super JavaFileObject> diagnosticListener) {
   345         this();
   346         this.log = getPrintWriterForWriter(out);
   347         this.fileManager = fileManager;
   348         this.diagnosticListener = diagnosticListener;
   349     }
   351     public JavapTask(Writer out,
   352             JavaFileManager fileManager,
   353             DiagnosticListener<? super JavaFileObject> diagnosticListener,
   354             Iterable<String> options,
   355             Iterable<String> classes) {
   356         this(out, fileManager, diagnosticListener);
   358         this.classes = new ArrayList<String>();
   359         for (String classname: classes) {
   360             classname.getClass(); // null-check
   361             this.classes.add(classname);
   362         }
   364         try {
   365             handleOptions(options, false);
   366         } catch (BadArgs e) {
   367             throw new IllegalArgumentException(e.getMessage());
   368         }
   369     }
   371     public void setLocale(Locale locale) {
   372         if (locale == null)
   373             locale = Locale.getDefault();
   374         task_locale = locale;
   375     }
   377     public void setLog(Writer log) {
   378         this.log = getPrintWriterForWriter(log);
   379     }
   381     public void setLog(OutputStream s) {
   382         setLog(getPrintWriterForStream(s));
   383     }
   385     private static PrintWriter getPrintWriterForStream(OutputStream s) {
   386         return new PrintWriter(s == null ? System.err : s, true);
   387     }
   389     private static PrintWriter getPrintWriterForWriter(Writer w) {
   390         if (w == null)
   391             return getPrintWriterForStream(null);
   392         else if (w instanceof PrintWriter)
   393             return (PrintWriter) w;
   394         else
   395             return new PrintWriter(w, true);
   396     }
   398     public void setDiagnosticListener(DiagnosticListener<? super JavaFileObject> dl) {
   399         diagnosticListener = dl;
   400     }
   402     public void setDiagnosticListener(OutputStream s) {
   403         setDiagnosticListener(getDiagnosticListenerForStream(s));
   404     }
   406     private DiagnosticListener<JavaFileObject> getDiagnosticListenerForStream(OutputStream s) {
   407         return getDiagnosticListenerForWriter(getPrintWriterForStream(s));
   408     }
   410     private DiagnosticListener<JavaFileObject> getDiagnosticListenerForWriter(Writer w) {
   411         final PrintWriter pw = getPrintWriterForWriter(w);
   412         return new DiagnosticListener<JavaFileObject> () {
   413             public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
   414                 switch (diagnostic.getKind()) {
   415                     case ERROR:
   416                         pw.print(getMessage("err.prefix"));
   417                         break;
   418                     case WARNING:
   419                         pw.print(getMessage("warn.prefix"));
   420                         break;
   421                     case NOTE:
   422                         pw.print(getMessage("note.prefix"));
   423                         break;
   424                 }
   425                 pw.print(" ");
   426                 pw.println(diagnostic.getMessage(null));
   427             }
   428         };
   429     }
   431     /** Result codes.
   432      */
   433     static final int
   434         EXIT_OK = 0,        // Compilation completed with no errors.
   435         EXIT_ERROR = 1,     // Completed but reported errors.
   436         EXIT_CMDERR = 2,    // Bad command-line arguments
   437         EXIT_SYSERR = 3,    // System error or resource exhaustion.
   438         EXIT_ABNORMAL = 4;  // Compiler terminated abnormally
   440     int run(String[] args) {
   441         try {
   442             handleOptions(args);
   444             // the following gives consistent behavior with javac
   445             if (classes == null || classes.size() == 0) {
   446                 if (options.help || options.version || options.fullVersion)
   447                     return EXIT_OK;
   448                 else
   449                     return EXIT_CMDERR;
   450             }
   452             try {
   453                 boolean ok = run();
   454                 return ok ? EXIT_OK : EXIT_ERROR;
   455             } finally {
   456                 if (defaultFileManager != null) {
   457                     try {
   458                         defaultFileManager.close();
   459                         defaultFileManager = null;
   460                     } catch (IOException e) {
   461                         throw new InternalError(e);
   462                     }
   463                 }
   464             }
   465         } catch (BadArgs e) {
   466             reportError(e.key, e.args);
   467             if (e.showUsage) {
   468                 log.println(getMessage("main.usage.summary", progname));
   469             }
   470             return EXIT_CMDERR;
   471         } catch (InternalError e) {
   472             Object[] e_args;
   473             if (e.getCause() == null)
   474                 e_args = e.args;
   475             else {
   476                 e_args = new Object[e.args.length + 1];
   477                 e_args[0] = e.getCause();
   478                 System.arraycopy(e.args, 0, e_args, 1, e.args.length);
   479             }
   480             reportError("err.internal.error", e_args);
   481             return EXIT_ABNORMAL;
   482         } finally {
   483             log.flush();
   484         }
   485     }
   487     public void handleOptions(String[] args) throws BadArgs {
   488         handleOptions(Arrays.asList(args), true);
   489     }
   491     private void handleOptions(Iterable<String> args, boolean allowClasses) throws BadArgs {
   492         if (log == null) {
   493             log = getPrintWriterForStream(System.out);
   494             if (diagnosticListener == null)
   495               diagnosticListener = getDiagnosticListenerForStream(System.err);
   496         } else {
   497             if (diagnosticListener == null)
   498               diagnosticListener = getDiagnosticListenerForWriter(log);
   499         }
   502         if (fileManager == null)
   503             fileManager = getDefaultFileManager(diagnosticListener, log);
   505         Iterator<String> iter = args.iterator();
   506         boolean noArgs = !iter.hasNext();
   508         while (iter.hasNext()) {
   509             String arg = iter.next();
   510             if (arg.startsWith("-"))
   511                 handleOption(arg, iter);
   512             else if (allowClasses) {
   513                 if (classes == null)
   514                     classes = new ArrayList<String>();
   515                 classes.add(arg);
   516                 while (iter.hasNext())
   517                     classes.add(iter.next());
   518             } else
   519                 throw new BadArgs("err.unknown.option", arg).showUsage(true);
   520         }
   522         if (!options.compat && options.accessOptions.size() > 1) {
   523             StringBuilder sb = new StringBuilder();
   524             for (String opt: options.accessOptions) {
   525                 if (sb.length() > 0)
   526                     sb.append(" ");
   527                 sb.append(opt);
   528             }
   529             throw new BadArgs("err.incompatible.options", sb);
   530         }
   532         if ((classes == null || classes.size() == 0) &&
   533                 !(noArgs || options.help || options.version || options.fullVersion)) {
   534             throw new BadArgs("err.no.classes.specified");
   535         }
   537         if (noArgs || options.help)
   538             showHelp();
   540         if (options.version || options.fullVersion)
   541             showVersion(options.fullVersion);
   542     }
   544     private void handleOption(String name, Iterator<String> rest) throws BadArgs {
   545         for (Option o: recognizedOptions) {
   546             if (o.matches(name)) {
   547                 if (o.hasArg) {
   548                     if (rest.hasNext())
   549                         o.process(this, name, rest.next());
   550                     else
   551                         throw new BadArgs("err.missing.arg", name).showUsage(true);
   552                 } else
   553                     o.process(this, name, null);
   555                 if (o.ignoreRest()) {
   556                     while (rest.hasNext())
   557                         rest.next();
   558                 }
   559                 return;
   560             }
   561         }
   563         if (fileManager.handleOption(name, rest))
   564             return;
   566         throw new BadArgs("err.unknown.option", name).showUsage(true);
   567     }
   569     public Boolean call() {
   570         return run();
   571     }
   573     public boolean run() {
   574         if (classes == null || classes.size() == 0)
   575             return false;
   577         context.put(PrintWriter.class, log);
   578         ClassWriter classWriter = ClassWriter.instance(context);
   579         SourceWriter sourceWriter = SourceWriter.instance(context);
   580         sourceWriter.setFileManager(fileManager);
   582         attributeFactory.setCompat(options.compat);
   584         boolean ok = true;
   586         for (String className: classes) {
   587             JavaFileObject fo;
   588             try {
   589                 writeClass(classWriter, className);
   590             } catch (ConstantPoolException e) {
   591                 reportError("err.bad.constant.pool", className, e.getLocalizedMessage());
   592                 ok = false;
   593             } catch (EOFException e) {
   594                 reportError("err.end.of.file", className);
   595                 ok = false;
   596             } catch (FileNotFoundException e) {
   597                 reportError("err.file.not.found", e.getLocalizedMessage());
   598                 ok = false;
   599             } catch (IOException e) {
   600                 //e.printStackTrace();
   601                 Object msg = e.getLocalizedMessage();
   602                 if (msg == null)
   603                     msg = e;
   604                 reportError("err.ioerror", className, msg);
   605                 ok = false;
   606             } catch (Throwable t) {
   607                 StringWriter sw = new StringWriter();
   608                 PrintWriter pw = new PrintWriter(sw);
   609                 t.printStackTrace(pw);
   610                 pw.close();
   611                 reportError("err.crash", t.toString(), sw.toString());
   612                 ok = false;
   613             }
   614         }
   616         return ok;
   617     }
   619     protected boolean writeClass(ClassWriter classWriter, String className)
   620             throws IOException, ConstantPoolException {
   621         JavaFileObject fo = open(className);
   622         if (fo == null) {
   623             reportError("err.class.not.found", className);
   624             return false;
   625         }
   627         ClassFileInfo cfInfo = read(fo);
   628         if (!className.endsWith(".class")) {
   629             String cfName = cfInfo.cf.getName();
   630             if (!cfName.replaceAll("[/$]", ".").equals(className.replaceAll("[/$]", ".")))
   631                 reportWarning("warn.unexpected.class", className, cfName.replace('/', '.'));
   632         }
   633         write(cfInfo);
   635         if (options.showInnerClasses) {
   636             ClassFile cf = cfInfo.cf;
   637             Attribute a = cf.getAttribute(Attribute.InnerClasses);
   638             if (a instanceof InnerClasses_attribute) {
   639                 InnerClasses_attribute inners = (InnerClasses_attribute) a;
   640                 try {
   641                     boolean ok = true;
   642                     for (int i = 0; i < inners.classes.length; i++) {
   643                         int outerIndex = inners.classes[i].outer_class_info_index;
   644                         ConstantPool.CONSTANT_Class_info outerClassInfo = cf.constant_pool.getClassInfo(outerIndex);
   645                         String outerClassName = outerClassInfo.getName();
   646                         if (outerClassName.equals(cf.getName())) {
   647                             int innerIndex = inners.classes[i].inner_class_info_index;
   648                             ConstantPool.CONSTANT_Class_info innerClassInfo = cf.constant_pool.getClassInfo(innerIndex);
   649                             String innerClassName = innerClassInfo.getName();
   650                             classWriter.println("// inner class " + innerClassName.replaceAll("[/$]", "."));
   651                             classWriter.println();
   652                             ok = ok & writeClass(classWriter, innerClassName);
   653                         }
   654                     }
   655                     return ok;
   656                 } catch (ConstantPoolException e) {
   657                     reportError("err.bad.innerclasses.attribute", className);
   658                     return false;
   659                 }
   660             } else if (a != null) {
   661                 reportError("err.bad.innerclasses.attribute", className);
   662                 return false;
   663             }
   664         }
   666         return true;
   667     }
   669     protected JavaFileObject open(String className) throws IOException {
   670         // for compatibility, first see if it is a class name
   671         JavaFileObject fo = getClassFileObject(className);
   672         if (fo != null)
   673             return fo;
   675         // see if it is an inner class, by replacing dots to $, starting from the right
   676         String cn = className;
   677         int lastDot;
   678         while ((lastDot = cn.lastIndexOf(".")) != -1) {
   679             cn = cn.substring(0, lastDot) + "$" + cn.substring(lastDot + 1);
   680             fo = getClassFileObject(cn);
   681             if (fo != null)
   682                 return fo;
   683         }
   685         if (!className.endsWith(".class"))
   686             return null;
   688         if (fileManager instanceof StandardJavaFileManager) {
   689             StandardJavaFileManager sfm = (StandardJavaFileManager) fileManager;
   690             fo = sfm.getJavaFileObjects(className).iterator().next();
   691             if (fo != null && fo.getLastModified() != 0) {
   692                 return fo;
   693             }
   694         }
   696         // see if it is a URL, and if so, wrap it in just enough of a JavaFileObject
   697         // to suit javap's needs
   698         if (className.matches("^[A-Za-z]+:.*")) {
   699             try {
   700                 final URI uri = new URI(className);
   701                 final URL url = uri.toURL();
   702                 final URLConnection conn = url.openConnection();
   703                 return new JavaFileObject() {
   704                     public Kind getKind() {
   705                         return JavaFileObject.Kind.CLASS;
   706                     }
   708                     public boolean isNameCompatible(String simpleName, Kind kind) {
   709                         throw new UnsupportedOperationException();
   710                     }
   712                     public NestingKind getNestingKind() {
   713                         throw new UnsupportedOperationException();
   714                     }
   716                     public Modifier getAccessLevel() {
   717                         throw new UnsupportedOperationException();
   718                     }
   720                     public URI toUri() {
   721                         return uri;
   722                     }
   724                     public String getName() {
   725                         return url.toString();
   726                     }
   728                     public InputStream openInputStream() throws IOException {
   729                         return conn.getInputStream();
   730                     }
   732                     public OutputStream openOutputStream() throws IOException {
   733                         throw new UnsupportedOperationException();
   734                     }
   736                     public Reader openReader(boolean ignoreEncodingErrors) throws IOException {
   737                         throw new UnsupportedOperationException();
   738                     }
   740                     public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
   741                         throw new UnsupportedOperationException();
   742                     }
   744                     public Writer openWriter() throws IOException {
   745                         throw new UnsupportedOperationException();
   746                     }
   748                     public long getLastModified() {
   749                         return conn.getLastModified();
   750                     }
   752                     public boolean delete() {
   753                         throw new UnsupportedOperationException();
   754                     }
   756                 };
   757             } catch (URISyntaxException ignore) {
   758             } catch (IOException ignore) {
   759             }
   760         }
   762         return null;
   763     }
   765     public static class ClassFileInfo {
   766         ClassFileInfo(JavaFileObject fo, ClassFile cf, byte[] digest, int size) {
   767             this.fo = fo;
   768             this.cf = cf;
   769             this.digest = digest;
   770             this.size = size;
   771         }
   772         public final JavaFileObject fo;
   773         public final ClassFile cf;
   774         public final byte[] digest;
   775         public final int size;
   776     }
   778     public ClassFileInfo read(JavaFileObject fo) throws IOException, ConstantPoolException {
   779         InputStream in = fo.openInputStream();
   780         try {
   781             SizeInputStream sizeIn = null;
   782             MessageDigest md  = null;
   783             if (options.sysInfo || options.verbose) {
   784                 try {
   785                     md = MessageDigest.getInstance("MD5");
   786                 } catch (NoSuchAlgorithmException ignore) {
   787                 }
   788                 in = new DigestInputStream(in, md);
   789                 in = sizeIn = new SizeInputStream(in);
   790             }
   792             ClassFile cf = ClassFile.read(in, attributeFactory);
   793             byte[] digest = (md == null) ? null : md.digest();
   794             int size = (sizeIn == null) ? -1 : sizeIn.size();
   795             return new ClassFileInfo(fo, cf, digest, size);
   796         } finally {
   797             in.close();
   798         }
   799     }
   801     public void write(ClassFileInfo info) {
   802         ClassWriter classWriter = ClassWriter.instance(context);
   803         if (options.sysInfo || options.verbose) {
   804             classWriter.setFile(info.fo.toUri());
   805             classWriter.setLastModified(info.fo.getLastModified());
   806             classWriter.setDigest("MD5", info.digest);
   807             classWriter.setFileSize(info.size);
   808         }
   810         classWriter.write(info.cf);
   811     }
   813     protected void setClassFile(ClassFile classFile) {
   814         ClassWriter classWriter = ClassWriter.instance(context);
   815         classWriter.setClassFile(classFile);
   816     }
   818     protected void setMethod(Method enclosingMethod) {
   819         ClassWriter classWriter = ClassWriter.instance(context);
   820         classWriter.setMethod(enclosingMethod);
   821     }
   823     protected void write(Attribute value) {
   824         AttributeWriter attrWriter = AttributeWriter.instance(context);
   825         ClassWriter classWriter = ClassWriter.instance(context);
   826         ClassFile cf = classWriter.getClassFile();
   827         attrWriter.write(cf, value, cf.constant_pool);
   828     }
   830     protected void write(Attributes attrs) {
   831         AttributeWriter attrWriter = AttributeWriter.instance(context);
   832         ClassWriter classWriter = ClassWriter.instance(context);
   833         ClassFile cf = classWriter.getClassFile();
   834         attrWriter.write(cf, attrs, cf.constant_pool);
   835     }
   837     protected void write(ConstantPool constant_pool) {
   838         ConstantWriter constantWriter = ConstantWriter.instance(context);
   839         constantWriter.writeConstantPool(constant_pool);
   840     }
   842     protected void write(ConstantPool constant_pool, int value) {
   843         ConstantWriter constantWriter = ConstantWriter.instance(context);
   844         constantWriter.write(value);
   845     }
   847     protected void write(ConstantPool.CPInfo value) {
   848         ConstantWriter constantWriter = ConstantWriter.instance(context);
   849         constantWriter.println(value);
   850     }
   852     protected void write(Field value) {
   853         ClassWriter classWriter = ClassWriter.instance(context);
   854         classWriter.writeField(value);
   855     }
   857     protected void write(Method value) {
   858         ClassWriter classWriter = ClassWriter.instance(context);
   859         classWriter.writeMethod(value);
   860     }
   862     private JavaFileManager getDefaultFileManager(final DiagnosticListener<? super JavaFileObject> dl, PrintWriter log) {
   863         if (defaultFileManager == null)
   864             defaultFileManager = JavapFileManager.create(dl, log);
   865         return defaultFileManager;
   866     }
   868     private JavaFileObject getClassFileObject(String className) throws IOException {
   869         JavaFileObject fo;
   870         fo = fileManager.getJavaFileForInput(StandardLocation.PLATFORM_CLASS_PATH, className, JavaFileObject.Kind.CLASS);
   871         if (fo == null)
   872             fo = fileManager.getJavaFileForInput(StandardLocation.CLASS_PATH, className, JavaFileObject.Kind.CLASS);
   873         return fo;
   874     }
   876     private void showHelp() {
   877         log.println(getMessage("main.usage", progname));
   878         for (Option o: recognizedOptions) {
   879             String name = o.aliases[0].substring(1); // there must always be at least one name
   880             if (name.startsWith("X") || name.equals("fullversion") || name.equals("h") || name.equals("verify"))
   881                 continue;
   882             log.println(getMessage("main.opt." + name));
   883         }
   884         String[] fmOptions = { "-classpath", "-bootclasspath" };
   885         for (String o: fmOptions) {
   886             if (fileManager.isSupportedOption(o) == -1)
   887                 continue;
   888             String name = o.substring(1);
   889             log.println(getMessage("main.opt." + name));
   890         }
   892     }
   894     private void showVersion(boolean full) {
   895         log.println(version(full ? "full" : "release"));
   896     }
   898     private static final String versionRBName = "com.sun.tools.javap.resources.version";
   899     private static ResourceBundle versionRB;
   901     private String version(String key) {
   902         // key=version:  mm.nn.oo[-milestone]
   903         // key=full:     mm.mm.oo[-milestone]-build
   904         if (versionRB == null) {
   905             try {
   906                 versionRB = ResourceBundle.getBundle(versionRBName);
   907             } catch (MissingResourceException e) {
   908                 return getMessage("version.resource.missing", System.getProperty("java.version"));
   909             }
   910         }
   911         try {
   912             return versionRB.getString(key);
   913         }
   914         catch (MissingResourceException e) {
   915             return getMessage("version.unknown", System.getProperty("java.version"));
   916         }
   917     }
   919     private void reportError(String key, Object... args) {
   920         diagnosticListener.report(createDiagnostic(Diagnostic.Kind.ERROR, key, args));
   921     }
   923     private void reportNote(String key, Object... args) {
   924         diagnosticListener.report(createDiagnostic(Diagnostic.Kind.NOTE, key, args));
   925     }
   927     private void reportWarning(String key, Object... args) {
   928         diagnosticListener.report(createDiagnostic(Diagnostic.Kind.WARNING, key, args));
   929     }
   931     private Diagnostic<JavaFileObject> createDiagnostic(
   932             final Diagnostic.Kind kind, final String key, final Object... args) {
   933         return new Diagnostic<JavaFileObject>() {
   934             public Kind getKind() {
   935                 return kind;
   936             }
   938             public JavaFileObject getSource() {
   939                 return null;
   940             }
   942             public long getPosition() {
   943                 return Diagnostic.NOPOS;
   944             }
   946             public long getStartPosition() {
   947                 return Diagnostic.NOPOS;
   948             }
   950             public long getEndPosition() {
   951                 return Diagnostic.NOPOS;
   952             }
   954             public long getLineNumber() {
   955                 return Diagnostic.NOPOS;
   956             }
   958             public long getColumnNumber() {
   959                 return Diagnostic.NOPOS;
   960             }
   962             public String getCode() {
   963                 return key;
   964             }
   966             public String getMessage(Locale locale) {
   967                 return JavapTask.this.getMessage(locale, key, args);
   968             }
   970             @Override
   971             public String toString() {
   972                 return getClass().getName() + "[key=" + key + ",args=" + Arrays.asList(args) + "]";
   973             }
   975         };
   977     }
   979     public String getMessage(String key, Object... args) {
   980         return getMessage(task_locale, key, args);
   981     }
   983     public String getMessage(Locale locale, String key, Object... args) {
   984         if (bundles == null) {
   985             // could make this a HashMap<Locale,SoftReference<ResourceBundle>>
   986             // and for efficiency, keep a hard reference to the bundle for the task
   987             // locale
   988             bundles = new HashMap<Locale, ResourceBundle>();
   989         }
   991         if (locale == null)
   992             locale = Locale.getDefault();
   994         ResourceBundle b = bundles.get(locale);
   995         if (b == null) {
   996             try {
   997                 b = ResourceBundle.getBundle("com.sun.tools.javap.resources.javap", locale);
   998                 bundles.put(locale, b);
   999             } catch (MissingResourceException e) {
  1000                 throw new InternalError("Cannot find javap resource bundle for locale " + locale);
  1004         try {
  1005             return MessageFormat.format(b.getString(key), args);
  1006         } catch (MissingResourceException e) {
  1007             throw new InternalError(e, key);
  1011     protected Context context;
  1012     JavaFileManager fileManager;
  1013     JavaFileManager defaultFileManager;
  1014     PrintWriter log;
  1015     DiagnosticListener<? super JavaFileObject> diagnosticListener;
  1016     List<String> classes;
  1017     Options options;
  1018     //ResourceBundle bundle;
  1019     Locale task_locale;
  1020     Map<Locale, ResourceBundle> bundles;
  1021     protected Attribute.Factory attributeFactory;
  1023     private static final String progname = "javap";
  1025     private static class SizeInputStream extends FilterInputStream {
  1026         SizeInputStream(InputStream in) {
  1027             super(in);
  1030         int size() {
  1031             return size;
  1034         @Override
  1035         public int read(byte[] buf, int offset, int length) throws IOException {
  1036             int n = super.read(buf, offset, length);
  1037             if (n > 0)
  1038                 size += n;
  1039             return n;
  1042         @Override
  1043         public int read() throws IOException {
  1044             int b = super.read();
  1045             size += 1;
  1046             return b;
  1049         private int size;

mercurial