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

Tue, 19 Feb 2013 17:19:01 -0800

author
ksrini
date
Tue, 19 Feb 2013 17:19:01 -0800
changeset 1592
9345394ac8fe
parent 1578
040f02711b73
child 1819
7fe655cad9b1
permissions
-rw-r--r--

8006948: Update javac for MethodParameters format change
Reviewed-by: ksrini, forax
Contributed-by: eric.mccorkle@oracle.com

     1 /*
     2  * Copyright (c) 2007, 2013, 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.showDescriptors = true;
   144                 task.options.showFlags = true;
   145                 task.options.showAllAttrs = true;
   146             }
   147         },
   149         new Option(false, "-l") {
   150             void process(JavapTask task, String opt, String arg) {
   151                 task.options.showLineAndLocalVariableTables = true;
   152             }
   153         },
   155         new Option(false, "-public") {
   156             void process(JavapTask task, String opt, String arg) {
   157                 task.options.accessOptions.add(opt);
   158                 task.options.showAccess = AccessFlags.ACC_PUBLIC;
   159             }
   160         },
   162         new Option(false, "-protected") {
   163             void process(JavapTask task, String opt, String arg) {
   164                 task.options.accessOptions.add(opt);
   165                 task.options.showAccess = AccessFlags.ACC_PROTECTED;
   166             }
   167         },
   169         new Option(false, "-package") {
   170             void process(JavapTask task, String opt, String arg) {
   171                 task.options.accessOptions.add(opt);
   172                 task.options.showAccess = 0;
   173             }
   174         },
   176         new Option(false, "-p", "-private") {
   177             void process(JavapTask task, String opt, String arg) {
   178                 if (!task.options.accessOptions.contains("-p") &&
   179                         !task.options.accessOptions.contains("-private")) {
   180                     task.options.accessOptions.add(opt);
   181                 }
   182                 task.options.showAccess = AccessFlags.ACC_PRIVATE;
   183             }
   184         },
   186         new Option(false, "-c") {
   187             void process(JavapTask task, String opt, String arg) {
   188                 task.options.showDisassembled = true;
   189             }
   190         },
   192         new Option(false, "-s") {
   193             void process(JavapTask task, String opt, String arg) {
   194                 task.options.showDescriptors = true;
   195             }
   196         },
   198 //        new Option(false, "-all") {
   199 //            void process(JavapTask task, String opt, String arg) {
   200 //                task.options.showAllAttrs = true;
   201 //            }
   202 //        },
   204         new Option(false, "-h") {
   205             void process(JavapTask task, String opt, String arg) throws BadArgs {
   206                 throw task.new BadArgs("err.h.not.supported");
   207             }
   208         },
   210         new Option(false, "-verify", "-verify-verbose") {
   211             void process(JavapTask task, String opt, String arg) throws BadArgs {
   212                 throw task.new BadArgs("err.verify.not.supported");
   213             }
   214         },
   216         new Option(false, "-sysinfo") {
   217             void process(JavapTask task, String opt, String arg) {
   218                 task.options.sysInfo = true;
   219             }
   220         },
   222         new Option(false, "-Xold") {
   223             void process(JavapTask task, String opt, String arg) throws BadArgs {
   224                 task.log.println(task.getMessage("warn.Xold.not.supported"));
   225             }
   226         },
   228         new Option(false, "-Xnew") {
   229             void process(JavapTask task, String opt, String arg) throws BadArgs {
   230                 // ignore: this _is_ the new version
   231             }
   232         },
   234         new Option(false, "-XDcompat") {
   235             void process(JavapTask task, String opt, String arg) {
   236                 task.options.compat = true;
   237             }
   238         },
   240         new Option(false, "-XDdetails") {
   241             void process(JavapTask task, String opt, String arg) {
   242                 task.options.details = EnumSet.allOf(InstructionDetailWriter.Kind.class);
   243             }
   245         },
   247         new Option(false, "-XDdetails:") {
   248             @Override
   249             boolean matches(String opt) {
   250                 int sep = opt.indexOf(":");
   251                 return sep != -1 && super.matches(opt.substring(0, sep + 1));
   252             }
   254             void process(JavapTask task, String opt, String arg) throws BadArgs {
   255                 int sep = opt.indexOf(":");
   256                 for (String v: opt.substring(sep + 1).split("[,: ]+")) {
   257                     if (!handleArg(task, v))
   258                         throw task.new BadArgs("err.invalid.arg.for.option", v);
   259                 }
   260             }
   262             boolean handleArg(JavapTask task, String arg) {
   263                 if (arg.length() == 0)
   264                     return true;
   266                 if (arg.equals("all")) {
   267                     task.options.details = EnumSet.allOf(InstructionDetailWriter.Kind.class);
   268                     return true;
   269                 }
   271                 boolean on = true;
   272                 if (arg.startsWith("-")) {
   273                     on = false;
   274                     arg = arg.substring(1);
   275                 }
   277                 for (InstructionDetailWriter.Kind k: InstructionDetailWriter.Kind.values()) {
   278                     if (arg.equalsIgnoreCase(k.option)) {
   279                         if (on)
   280                             task.options.details.add(k);
   281                         else
   282                             task.options.details.remove(k);
   283                         return true;
   284                     }
   285                 }
   286                 return false;
   287             }
   288         },
   290         new Option(false, "-constants") {
   291             void process(JavapTask task, String opt, String arg) {
   292                 task.options.showConstants = true;
   293             }
   294         },
   296         new Option(false, "-XDinner") {
   297             void process(JavapTask task, String opt, String arg) {
   298                 task.options.showInnerClasses = true;
   299             }
   300         },
   302         new Option(false, "-XDindent:") {
   303             @Override
   304             boolean matches(String opt) {
   305                 int sep = opt.indexOf(":");
   306                 return sep != -1 && super.matches(opt.substring(0, sep + 1));
   307             }
   309             void process(JavapTask task, String opt, String arg) throws BadArgs {
   310                 int sep = opt.indexOf(":");
   311                 try {
   312                     task.options.indentWidth = Integer.valueOf(opt.substring(sep + 1));
   313                 } catch (NumberFormatException e) {
   314                 }
   315             }
   316         },
   318         new Option(false, "-XDtab:") {
   319             @Override
   320             boolean matches(String opt) {
   321                 int sep = opt.indexOf(":");
   322                 return sep != -1 && super.matches(opt.substring(0, sep + 1));
   323             }
   325             void process(JavapTask task, String opt, String arg) throws BadArgs {
   326                 int sep = opt.indexOf(":");
   327                 try {
   328                     task.options.tabColumn = Integer.valueOf(opt.substring(sep + 1));
   329                 } catch (NumberFormatException e) {
   330                 }
   331             }
   332         }
   334     };
   336     public JavapTask() {
   337         context = new Context();
   338         context.put(Messages.class, this);
   339         options = Options.instance(context);
   340         attributeFactory = new Attribute.Factory();
   341     }
   343     public JavapTask(Writer out,
   344             JavaFileManager fileManager,
   345             DiagnosticListener<? super JavaFileObject> diagnosticListener) {
   346         this();
   347         this.log = getPrintWriterForWriter(out);
   348         this.fileManager = fileManager;
   349         this.diagnosticListener = diagnosticListener;
   350     }
   352     public JavapTask(Writer out,
   353             JavaFileManager fileManager,
   354             DiagnosticListener<? super JavaFileObject> diagnosticListener,
   355             Iterable<String> options,
   356             Iterable<String> classes) {
   357         this(out, fileManager, diagnosticListener);
   359         this.classes = new ArrayList<String>();
   360         for (String classname: classes) {
   361             classname.getClass(); // null-check
   362             this.classes.add(classname);
   363         }
   365         try {
   366             if (options != null)
   367                 handleOptions(options, false);
   368         } catch (BadArgs e) {
   369             throw new IllegalArgumentException(e.getMessage());
   370         }
   371     }
   373     public void setLocale(Locale locale) {
   374         if (locale == null)
   375             locale = Locale.getDefault();
   376         task_locale = locale;
   377     }
   379     public void setLog(Writer log) {
   380         this.log = getPrintWriterForWriter(log);
   381     }
   383     public void setLog(OutputStream s) {
   384         setLog(getPrintWriterForStream(s));
   385     }
   387     private static PrintWriter getPrintWriterForStream(OutputStream s) {
   388         return new PrintWriter(s == null ? System.err : s, true);
   389     }
   391     private static PrintWriter getPrintWriterForWriter(Writer w) {
   392         if (w == null)
   393             return getPrintWriterForStream(null);
   394         else if (w instanceof PrintWriter)
   395             return (PrintWriter) w;
   396         else
   397             return new PrintWriter(w, true);
   398     }
   400     public void setDiagnosticListener(DiagnosticListener<? super JavaFileObject> dl) {
   401         diagnosticListener = dl;
   402     }
   404     public void setDiagnosticListener(OutputStream s) {
   405         setDiagnosticListener(getDiagnosticListenerForStream(s));
   406     }
   408     private DiagnosticListener<JavaFileObject> getDiagnosticListenerForStream(OutputStream s) {
   409         return getDiagnosticListenerForWriter(getPrintWriterForStream(s));
   410     }
   412     private DiagnosticListener<JavaFileObject> getDiagnosticListenerForWriter(Writer w) {
   413         final PrintWriter pw = getPrintWriterForWriter(w);
   414         return new DiagnosticListener<JavaFileObject> () {
   415             public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
   416                 switch (diagnostic.getKind()) {
   417                     case ERROR:
   418                         pw.print(getMessage("err.prefix"));
   419                         break;
   420                     case WARNING:
   421                         pw.print(getMessage("warn.prefix"));
   422                         break;
   423                     case NOTE:
   424                         pw.print(getMessage("note.prefix"));
   425                         break;
   426                 }
   427                 pw.print(" ");
   428                 pw.println(diagnostic.getMessage(null));
   429             }
   430         };
   431     }
   433     /** Result codes.
   434      */
   435     static final int
   436         EXIT_OK = 0,        // Compilation completed with no errors.
   437         EXIT_ERROR = 1,     // Completed but reported errors.
   438         EXIT_CMDERR = 2,    // Bad command-line arguments
   439         EXIT_SYSERR = 3,    // System error or resource exhaustion.
   440         EXIT_ABNORMAL = 4;  // Compiler terminated abnormally
   442     int run(String[] args) {
   443         try {
   444             handleOptions(args);
   446             // the following gives consistent behavior with javac
   447             if (classes == null || classes.size() == 0) {
   448                 if (options.help || options.version || options.fullVersion)
   449                     return EXIT_OK;
   450                 else
   451                     return EXIT_CMDERR;
   452             }
   454             try {
   455                 boolean ok = run();
   456                 return ok ? EXIT_OK : EXIT_ERROR;
   457             } finally {
   458                 if (defaultFileManager != null) {
   459                     try {
   460                         defaultFileManager.close();
   461                         defaultFileManager = null;
   462                     } catch (IOException e) {
   463                         throw new InternalError(e);
   464                     }
   465                 }
   466             }
   467         } catch (BadArgs e) {
   468             reportError(e.key, e.args);
   469             if (e.showUsage) {
   470                 log.println(getMessage("main.usage.summary", progname));
   471             }
   472             return EXIT_CMDERR;
   473         } catch (InternalError e) {
   474             Object[] e_args;
   475             if (e.getCause() == null)
   476                 e_args = e.args;
   477             else {
   478                 e_args = new Object[e.args.length + 1];
   479                 e_args[0] = e.getCause();
   480                 System.arraycopy(e.args, 0, e_args, 1, e.args.length);
   481             }
   482             reportError("err.internal.error", e_args);
   483             return EXIT_ABNORMAL;
   484         } finally {
   485             log.flush();
   486         }
   487     }
   489     public void handleOptions(String[] args) throws BadArgs {
   490         handleOptions(Arrays.asList(args), true);
   491     }
   493     private void handleOptions(Iterable<String> args, boolean allowClasses) throws BadArgs {
   494         if (log == null) {
   495             log = getPrintWriterForStream(System.out);
   496             if (diagnosticListener == null)
   497               diagnosticListener = getDiagnosticListenerForStream(System.err);
   498         } else {
   499             if (diagnosticListener == null)
   500               diagnosticListener = getDiagnosticListenerForWriter(log);
   501         }
   504         if (fileManager == null)
   505             fileManager = getDefaultFileManager(diagnosticListener, log);
   507         Iterator<String> iter = args.iterator();
   508         boolean noArgs = !iter.hasNext();
   510         while (iter.hasNext()) {
   511             String arg = iter.next();
   512             if (arg.startsWith("-"))
   513                 handleOption(arg, iter);
   514             else if (allowClasses) {
   515                 if (classes == null)
   516                     classes = new ArrayList<String>();
   517                 classes.add(arg);
   518                 while (iter.hasNext())
   519                     classes.add(iter.next());
   520             } else
   521                 throw new BadArgs("err.unknown.option", arg).showUsage(true);
   522         }
   524         if (!options.compat && options.accessOptions.size() > 1) {
   525             StringBuilder sb = new StringBuilder();
   526             for (String opt: options.accessOptions) {
   527                 if (sb.length() > 0)
   528                     sb.append(" ");
   529                 sb.append(opt);
   530             }
   531             throw new BadArgs("err.incompatible.options", sb);
   532         }
   534         if ((classes == null || classes.size() == 0) &&
   535                 !(noArgs || options.help || options.version || options.fullVersion)) {
   536             throw new BadArgs("err.no.classes.specified");
   537         }
   539         if (noArgs || options.help)
   540             showHelp();
   542         if (options.version || options.fullVersion)
   543             showVersion(options.fullVersion);
   544     }
   546     private void handleOption(String name, Iterator<String> rest) throws BadArgs {
   547         for (Option o: recognizedOptions) {
   548             if (o.matches(name)) {
   549                 if (o.hasArg) {
   550                     if (rest.hasNext())
   551                         o.process(this, name, rest.next());
   552                     else
   553                         throw new BadArgs("err.missing.arg", name).showUsage(true);
   554                 } else
   555                     o.process(this, name, null);
   557                 if (o.ignoreRest()) {
   558                     while (rest.hasNext())
   559                         rest.next();
   560                 }
   561                 return;
   562             }
   563         }
   565         if (fileManager.handleOption(name, rest))
   566             return;
   568         throw new BadArgs("err.unknown.option", name).showUsage(true);
   569     }
   571     public Boolean call() {
   572         return run();
   573     }
   575     public boolean run() {
   576         if (classes == null || classes.size() == 0)
   577             return false;
   579         context.put(PrintWriter.class, log);
   580         ClassWriter classWriter = ClassWriter.instance(context);
   581         SourceWriter sourceWriter = SourceWriter.instance(context);
   582         sourceWriter.setFileManager(fileManager);
   584         attributeFactory.setCompat(options.compat);
   586         boolean ok = true;
   588         for (String className: classes) {
   589             JavaFileObject fo;
   590             try {
   591                 writeClass(classWriter, className);
   592             } catch (ConstantPoolException e) {
   593                 reportError("err.bad.constant.pool", className, e.getLocalizedMessage());
   594                 ok = false;
   595             } catch (EOFException e) {
   596                 reportError("err.end.of.file", className);
   597                 ok = false;
   598             } catch (FileNotFoundException e) {
   599                 reportError("err.file.not.found", e.getLocalizedMessage());
   600                 ok = false;
   601             } catch (IOException e) {
   602                 //e.printStackTrace();
   603                 Object msg = e.getLocalizedMessage();
   604                 if (msg == null)
   605                     msg = e;
   606                 reportError("err.ioerror", className, msg);
   607                 ok = false;
   608             } catch (Throwable t) {
   609                 StringWriter sw = new StringWriter();
   610                 PrintWriter pw = new PrintWriter(sw);
   611                 t.printStackTrace(pw);
   612                 pw.close();
   613                 reportError("err.crash", t.toString(), sw.toString());
   614                 ok = false;
   615             }
   616         }
   618         return ok;
   619     }
   621     protected boolean writeClass(ClassWriter classWriter, String className)
   622             throws IOException, ConstantPoolException {
   623         JavaFileObject fo = open(className);
   624         if (fo == null) {
   625             reportError("err.class.not.found", className);
   626             return false;
   627         }
   629         ClassFileInfo cfInfo = read(fo);
   630         if (!className.endsWith(".class")) {
   631             String cfName = cfInfo.cf.getName();
   632             if (!cfName.replaceAll("[/$]", ".").equals(className.replaceAll("[/$]", ".")))
   633                 reportWarning("warn.unexpected.class", className, cfName.replace('/', '.'));
   634         }
   635         write(cfInfo);
   637         if (options.showInnerClasses) {
   638             ClassFile cf = cfInfo.cf;
   639             Attribute a = cf.getAttribute(Attribute.InnerClasses);
   640             if (a instanceof InnerClasses_attribute) {
   641                 InnerClasses_attribute inners = (InnerClasses_attribute) a;
   642                 try {
   643                     boolean ok = true;
   644                     for (int i = 0; i < inners.classes.length; i++) {
   645                         int outerIndex = inners.classes[i].outer_class_info_index;
   646                         ConstantPool.CONSTANT_Class_info outerClassInfo = cf.constant_pool.getClassInfo(outerIndex);
   647                         String outerClassName = outerClassInfo.getName();
   648                         if (outerClassName.equals(cf.getName())) {
   649                             int innerIndex = inners.classes[i].inner_class_info_index;
   650                             ConstantPool.CONSTANT_Class_info innerClassInfo = cf.constant_pool.getClassInfo(innerIndex);
   651                             String innerClassName = innerClassInfo.getName();
   652                             classWriter.println("// inner class " + innerClassName.replaceAll("[/$]", "."));
   653                             classWriter.println();
   654                             ok = ok & writeClass(classWriter, innerClassName);
   655                         }
   656                     }
   657                     return ok;
   658                 } catch (ConstantPoolException e) {
   659                     reportError("err.bad.innerclasses.attribute", className);
   660                     return false;
   661                 }
   662             } else if (a != null) {
   663                 reportError("err.bad.innerclasses.attribute", className);
   664                 return false;
   665             }
   666         }
   668         return true;
   669     }
   671     protected JavaFileObject open(String className) throws IOException {
   672         // for compatibility, first see if it is a class name
   673         JavaFileObject fo = getClassFileObject(className);
   674         if (fo != null)
   675             return fo;
   677         // see if it is an inner class, by replacing dots to $, starting from the right
   678         String cn = className;
   679         int lastDot;
   680         while ((lastDot = cn.lastIndexOf(".")) != -1) {
   681             cn = cn.substring(0, lastDot) + "$" + cn.substring(lastDot + 1);
   682             fo = getClassFileObject(cn);
   683             if (fo != null)
   684                 return fo;
   685         }
   687         if (!className.endsWith(".class"))
   688             return null;
   690         if (fileManager instanceof StandardJavaFileManager) {
   691             StandardJavaFileManager sfm = (StandardJavaFileManager) fileManager;
   692             fo = sfm.getJavaFileObjects(className).iterator().next();
   693             if (fo != null && fo.getLastModified() != 0) {
   694                 return fo;
   695             }
   696         }
   698         // see if it is a URL, and if so, wrap it in just enough of a JavaFileObject
   699         // to suit javap's needs
   700         if (className.matches("^[A-Za-z]+:.*")) {
   701             try {
   702                 final URI uri = new URI(className);
   703                 final URL url = uri.toURL();
   704                 final URLConnection conn = url.openConnection();
   705                 return new JavaFileObject() {
   706                     public Kind getKind() {
   707                         return JavaFileObject.Kind.CLASS;
   708                     }
   710                     public boolean isNameCompatible(String simpleName, Kind kind) {
   711                         throw new UnsupportedOperationException();
   712                     }
   714                     public NestingKind getNestingKind() {
   715                         throw new UnsupportedOperationException();
   716                     }
   718                     public Modifier getAccessLevel() {
   719                         throw new UnsupportedOperationException();
   720                     }
   722                     public URI toUri() {
   723                         return uri;
   724                     }
   726                     public String getName() {
   727                         return url.toString();
   728                     }
   730                     public InputStream openInputStream() throws IOException {
   731                         return conn.getInputStream();
   732                     }
   734                     public OutputStream openOutputStream() throws IOException {
   735                         throw new UnsupportedOperationException();
   736                     }
   738                     public Reader openReader(boolean ignoreEncodingErrors) throws IOException {
   739                         throw new UnsupportedOperationException();
   740                     }
   742                     public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
   743                         throw new UnsupportedOperationException();
   744                     }
   746                     public Writer openWriter() throws IOException {
   747                         throw new UnsupportedOperationException();
   748                     }
   750                     public long getLastModified() {
   751                         return conn.getLastModified();
   752                     }
   754                     public boolean delete() {
   755                         throw new UnsupportedOperationException();
   756                     }
   758                 };
   759             } catch (URISyntaxException ignore) {
   760             } catch (IOException ignore) {
   761             }
   762         }
   764         return null;
   765     }
   767     public static class ClassFileInfo {
   768         ClassFileInfo(JavaFileObject fo, ClassFile cf, byte[] digest, int size) {
   769             this.fo = fo;
   770             this.cf = cf;
   771             this.digest = digest;
   772             this.size = size;
   773         }
   774         public final JavaFileObject fo;
   775         public final ClassFile cf;
   776         public final byte[] digest;
   777         public final int size;
   778     }
   780     public ClassFileInfo read(JavaFileObject fo) throws IOException, ConstantPoolException {
   781         InputStream in = fo.openInputStream();
   782         try {
   783             SizeInputStream sizeIn = null;
   784             MessageDigest md  = null;
   785             if (options.sysInfo || options.verbose) {
   786                 try {
   787                     md = MessageDigest.getInstance("MD5");
   788                 } catch (NoSuchAlgorithmException ignore) {
   789                 }
   790                 in = new DigestInputStream(in, md);
   791                 in = sizeIn = new SizeInputStream(in);
   792             }
   794             ClassFile cf = ClassFile.read(in, attributeFactory);
   795             byte[] digest = (md == null) ? null : md.digest();
   796             int size = (sizeIn == null) ? -1 : sizeIn.size();
   797             return new ClassFileInfo(fo, cf, digest, size);
   798         } finally {
   799             in.close();
   800         }
   801     }
   803     public void write(ClassFileInfo info) {
   804         ClassWriter classWriter = ClassWriter.instance(context);
   805         if (options.sysInfo || options.verbose) {
   806             classWriter.setFile(info.fo.toUri());
   807             classWriter.setLastModified(info.fo.getLastModified());
   808             classWriter.setDigest("MD5", info.digest);
   809             classWriter.setFileSize(info.size);
   810         }
   812         classWriter.write(info.cf);
   813     }
   815     protected void setClassFile(ClassFile classFile) {
   816         ClassWriter classWriter = ClassWriter.instance(context);
   817         classWriter.setClassFile(classFile);
   818     }
   820     protected void setMethod(Method enclosingMethod) {
   821         ClassWriter classWriter = ClassWriter.instance(context);
   822         classWriter.setMethod(enclosingMethod);
   823     }
   825     protected void write(Attribute value) {
   826         AttributeWriter attrWriter = AttributeWriter.instance(context);
   827         ClassWriter classWriter = ClassWriter.instance(context);
   828         ClassFile cf = classWriter.getClassFile();
   829         attrWriter.write(cf, value, cf.constant_pool);
   830     }
   832     protected void write(Attributes attrs) {
   833         AttributeWriter attrWriter = AttributeWriter.instance(context);
   834         ClassWriter classWriter = ClassWriter.instance(context);
   835         ClassFile cf = classWriter.getClassFile();
   836         attrWriter.write(cf, attrs, cf.constant_pool);
   837     }
   839     protected void write(ConstantPool constant_pool) {
   840         ConstantWriter constantWriter = ConstantWriter.instance(context);
   841         constantWriter.writeConstantPool(constant_pool);
   842     }
   844     protected void write(ConstantPool constant_pool, int value) {
   845         ConstantWriter constantWriter = ConstantWriter.instance(context);
   846         constantWriter.write(value);
   847     }
   849     protected void write(ConstantPool.CPInfo value) {
   850         ConstantWriter constantWriter = ConstantWriter.instance(context);
   851         constantWriter.println(value);
   852     }
   854     protected void write(Field value) {
   855         ClassWriter classWriter = ClassWriter.instance(context);
   856         classWriter.writeField(value);
   857     }
   859     protected void write(Method value) {
   860         ClassWriter classWriter = ClassWriter.instance(context);
   861         classWriter.writeMethod(value);
   862     }
   864     private JavaFileManager getDefaultFileManager(final DiagnosticListener<? super JavaFileObject> dl, PrintWriter log) {
   865         if (defaultFileManager == null)
   866             defaultFileManager = JavapFileManager.create(dl, log);
   867         return defaultFileManager;
   868     }
   870     private JavaFileObject getClassFileObject(String className) throws IOException {
   871         JavaFileObject fo;
   872         fo = fileManager.getJavaFileForInput(StandardLocation.PLATFORM_CLASS_PATH, className, JavaFileObject.Kind.CLASS);
   873         if (fo == null)
   874             fo = fileManager.getJavaFileForInput(StandardLocation.CLASS_PATH, className, JavaFileObject.Kind.CLASS);
   875         return fo;
   876     }
   878     private void showHelp() {
   879         log.println(getMessage("main.usage", progname));
   880         for (Option o: recognizedOptions) {
   881             String name = o.aliases[0].substring(1); // there must always be at least one name
   882             if (name.startsWith("X") || name.equals("fullversion") || name.equals("h") || name.equals("verify"))
   883                 continue;
   884             log.println(getMessage("main.opt." + name));
   885         }
   886         String[] fmOptions = { "-classpath", "-bootclasspath" };
   887         for (String o: fmOptions) {
   888             if (fileManager.isSupportedOption(o) == -1)
   889                 continue;
   890             String name = o.substring(1);
   891             log.println(getMessage("main.opt." + name));
   892         }
   894     }
   896     private void showVersion(boolean full) {
   897         log.println(version(full ? "full" : "release"));
   898     }
   900     private static final String versionRBName = "com.sun.tools.javap.resources.version";
   901     private static ResourceBundle versionRB;
   903     private String version(String key) {
   904         // key=version:  mm.nn.oo[-milestone]
   905         // key=full:     mm.mm.oo[-milestone]-build
   906         if (versionRB == null) {
   907             try {
   908                 versionRB = ResourceBundle.getBundle(versionRBName);
   909             } catch (MissingResourceException e) {
   910                 return getMessage("version.resource.missing", System.getProperty("java.version"));
   911             }
   912         }
   913         try {
   914             return versionRB.getString(key);
   915         }
   916         catch (MissingResourceException e) {
   917             return getMessage("version.unknown", System.getProperty("java.version"));
   918         }
   919     }
   921     private void reportError(String key, Object... args) {
   922         diagnosticListener.report(createDiagnostic(Diagnostic.Kind.ERROR, key, args));
   923     }
   925     private void reportNote(String key, Object... args) {
   926         diagnosticListener.report(createDiagnostic(Diagnostic.Kind.NOTE, key, args));
   927     }
   929     private void reportWarning(String key, Object... args) {
   930         diagnosticListener.report(createDiagnostic(Diagnostic.Kind.WARNING, key, args));
   931     }
   933     private Diagnostic<JavaFileObject> createDiagnostic(
   934             final Diagnostic.Kind kind, final String key, final Object... args) {
   935         return new Diagnostic<JavaFileObject>() {
   936             public Kind getKind() {
   937                 return kind;
   938             }
   940             public JavaFileObject getSource() {
   941                 return null;
   942             }
   944             public long getPosition() {
   945                 return Diagnostic.NOPOS;
   946             }
   948             public long getStartPosition() {
   949                 return Diagnostic.NOPOS;
   950             }
   952             public long getEndPosition() {
   953                 return Diagnostic.NOPOS;
   954             }
   956             public long getLineNumber() {
   957                 return Diagnostic.NOPOS;
   958             }
   960             public long getColumnNumber() {
   961                 return Diagnostic.NOPOS;
   962             }
   964             public String getCode() {
   965                 return key;
   966             }
   968             public String getMessage(Locale locale) {
   969                 return JavapTask.this.getMessage(locale, key, args);
   970             }
   972             @Override
   973             public String toString() {
   974                 return getClass().getName() + "[key=" + key + ",args=" + Arrays.asList(args) + "]";
   975             }
   977         };
   979     }
   981     public String getMessage(String key, Object... args) {
   982         return getMessage(task_locale, key, args);
   983     }
   985     public String getMessage(Locale locale, String key, Object... args) {
   986         if (bundles == null) {
   987             // could make this a HashMap<Locale,SoftReference<ResourceBundle>>
   988             // and for efficiency, keep a hard reference to the bundle for the task
   989             // locale
   990             bundles = new HashMap<Locale, ResourceBundle>();
   991         }
   993         if (locale == null)
   994             locale = Locale.getDefault();
   996         ResourceBundle b = bundles.get(locale);
   997         if (b == null) {
   998             try {
   999                 b = ResourceBundle.getBundle("com.sun.tools.javap.resources.javap", locale);
  1000                 bundles.put(locale, b);
  1001             } catch (MissingResourceException e) {
  1002                 throw new InternalError("Cannot find javap resource bundle for locale " + locale);
  1006         try {
  1007             return MessageFormat.format(b.getString(key), args);
  1008         } catch (MissingResourceException e) {
  1009             throw new InternalError(e, key);
  1013     protected Context context;
  1014     JavaFileManager fileManager;
  1015     JavaFileManager defaultFileManager;
  1016     PrintWriter log;
  1017     DiagnosticListener<? super JavaFileObject> diagnosticListener;
  1018     List<String> classes;
  1019     Options options;
  1020     //ResourceBundle bundle;
  1021     Locale task_locale;
  1022     Map<Locale, ResourceBundle> bundles;
  1023     protected Attribute.Factory attributeFactory;
  1025     private static final String progname = "javap";
  1027     private static class SizeInputStream extends FilterInputStream {
  1028         SizeInputStream(InputStream in) {
  1029             super(in);
  1032         int size() {
  1033             return size;
  1036         @Override
  1037         public int read(byte[] buf, int offset, int length) throws IOException {
  1038             int n = super.read(buf, offset, length);
  1039             if (n > 0)
  1040                 size += n;
  1041             return n;
  1044         @Override
  1045         public int read() throws IOException {
  1046             int b = super.read();
  1047             size += 1;
  1048             return b;
  1051         private int size;

mercurial