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

Tue, 08 Sep 2009 11:43:57 -0700

author
jjg
date
Tue, 08 Sep 2009 11:43:57 -0700
changeset 402
261c54b2312e
parent 350
526de25e0b28
child 404
14735c7932d7
permissions
-rw-r--r--

6879371: javap does not close internal default file manager
Reviewed-by: darcy

     1 /*
     2  * Copyright 2007-2008 Sun Microsystems, Inc.  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.  Sun designates this
     8  * particular file as subject to the "Classpath" exception as provided
     9  * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
    22  * CA 95054 USA or visit www.sun.com if you need additional information or
    23  * have any 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 API supported by Sun Microsystems.  If
    73  *  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 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, "-XDjsr277") {
   240             void process(JavapTask task, String opt, String arg) {
   241                 task.options.jsr277 = true;
   242             }
   243         },
   245         new Option(false, "-XDdetails") {
   246             void process(JavapTask task, String opt, String arg) {
   247                 task.options.details = EnumSet.allOf(InstructionDetailWriter.Kind.class);
   248             }
   250         },
   252         new Option(false, "-XDdetails:") {
   253             @Override
   254             boolean matches(String opt) {
   255                 int sep = opt.indexOf(":");
   256                 return sep != -1 && super.matches(opt.substring(0, sep + 1));
   257             }
   259             void process(JavapTask task, String opt, String arg) throws BadArgs {
   260                 int sep = opt.indexOf(":");
   261                 for (String v: opt.substring(sep + 1).split("[,: ]+")) {
   262                     if (!handleArg(task, v))
   263                         throw task.new BadArgs("err.invalid.arg.for.option", v);
   264                 }
   265             }
   267             boolean handleArg(JavapTask task, String arg) {
   268                 if (arg.length() == 0)
   269                     return true;
   271                 if (arg.equals("all")) {
   272                     task.options.details = EnumSet.allOf(InstructionDetailWriter.Kind.class);
   273                     return true;
   274                 }
   276                 boolean on = true;
   277                 if (arg.startsWith("-")) {
   278                     on = false;
   279                     arg = arg.substring(1);
   280                 }
   282                 for (InstructionDetailWriter.Kind k: InstructionDetailWriter.Kind.values()) {
   283                     if (arg.equalsIgnoreCase(k.option)) {
   284                         if (on)
   285                             task.options.details.add(k);
   286                         else
   287                             task.options.details.remove(k);
   288                         return true;
   289                     }
   290                 }
   291                 return false;
   292             }
   293         },
   295         new Option(false, "-constants") {
   296             void process(JavapTask task, String opt, String arg) {
   297                 task.options.showConstants = true;
   298             }
   299         },
   301         new Option(false, "-XDinner") {
   302             void process(JavapTask task, String opt, String arg) {
   303                 task.options.showInnerClasses = true;
   304             }
   305         },
   307         new Option(false, "-XDindent:") {
   308             @Override
   309             boolean matches(String opt) {
   310                 int sep = opt.indexOf(":");
   311                 return sep != -1 && super.matches(opt.substring(0, sep + 1));
   312             }
   314             void process(JavapTask task, String opt, String arg) throws BadArgs {
   315                 int sep = opt.indexOf(":");
   316                 try {
   317                     task.options.indentWidth = Integer.valueOf(opt.substring(sep + 1));
   318                 } catch (NumberFormatException e) {
   319                 }
   320             }
   321         },
   323         new Option(false, "-XDtab:") {
   324             @Override
   325             boolean matches(String opt) {
   326                 int sep = opt.indexOf(":");
   327                 return sep != -1 && super.matches(opt.substring(0, sep + 1));
   328             }
   330             void process(JavapTask task, String opt, String arg) throws BadArgs {
   331                 int sep = opt.indexOf(":");
   332                 try {
   333                     task.options.tabColumn = Integer.valueOf(opt.substring(sep + 1));
   334                 } catch (NumberFormatException e) {
   335                 }
   336             }
   337         }
   339     };
   341     public JavapTask() {
   342         context = new Context();
   343         context.put(Messages.class, this);
   344         options = Options.instance(context);
   345         attributeFactory = new Attribute.Factory();
   346     }
   348     public JavapTask(Writer out,
   349             JavaFileManager fileManager,
   350             DiagnosticListener<? super JavaFileObject> diagnosticListener) {
   351         this();
   352         this.log = getPrintWriterForWriter(out);
   353         this.fileManager = fileManager;
   354         this.diagnosticListener = diagnosticListener;
   355     }
   357     public JavapTask(Writer out,
   358             JavaFileManager fileManager,
   359             DiagnosticListener<? super JavaFileObject> diagnosticListener,
   360             Iterable<String> options,
   361             Iterable<String> classes) {
   362         this(out, fileManager, diagnosticListener);
   364         this.classes = new ArrayList<String>();
   365         for (String classname: classes) {
   366             classname.getClass(); // null-check
   367             this.classes.add(classname);
   368         }
   370         try {
   371             handleOptions(options, false);
   372         } catch (BadArgs e) {
   373             throw new IllegalArgumentException(e.getMessage());
   374         }
   375     }
   377     public void setLocale(Locale locale) {
   378         if (locale == null)
   379             locale = Locale.getDefault();
   380         task_locale = locale;
   381     }
   383     public void setLog(PrintWriter log) {
   384         this.log = log;
   385     }
   387     public void setLog(OutputStream s) {
   388         setLog(getPrintWriterForStream(s));
   389     }
   391     private static PrintWriter getPrintWriterForStream(OutputStream s) {
   392         return new PrintWriter(s, true);
   393     }
   395     private static PrintWriter getPrintWriterForWriter(Writer w) {
   396         if (w == null)
   397             return getPrintWriterForStream(null);
   398         else if (w instanceof PrintWriter)
   399             return (PrintWriter) w;
   400         else
   401             return new PrintWriter(w, true);
   402     }
   404     public void setDiagnosticListener(DiagnosticListener<? super JavaFileObject> dl) {
   405         diagnosticListener = dl;
   406     }
   408     public void setDiagnosticListener(OutputStream s) {
   409         setDiagnosticListener(getDiagnosticListenerForStream(s));
   410     }
   412     private DiagnosticListener<JavaFileObject> getDiagnosticListenerForStream(OutputStream s) {
   413         return getDiagnosticListenerForWriter(getPrintWriterForStream(s));
   414     }
   416     private DiagnosticListener<JavaFileObject> getDiagnosticListenerForWriter(Writer w) {
   417         final PrintWriter pw = getPrintWriterForWriter(w);
   418         return new DiagnosticListener<JavaFileObject> () {
   419             public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
   420                 switch (diagnostic.getKind()) {
   421                     case ERROR:
   422                         pw.print(getMessage("err.prefix"));
   423                         break;
   424                     case WARNING:
   425                         pw.print(getMessage("warn.prefix"));
   426                         break;
   427                     case NOTE:
   428                         pw.print(getMessage("note.prefix"));
   429                         break;
   430                 }
   431                 pw.print(" ");
   432                 pw.println(diagnostic.getMessage(null));
   433             }
   434         };
   435     }
   437     /** Result codes.
   438      */
   439     static final int
   440         EXIT_OK = 0,        // Compilation completed with no errors.
   441         EXIT_ERROR = 1,     // Completed but reported errors.
   442         EXIT_CMDERR = 2,    // Bad command-line arguments
   443         EXIT_SYSERR = 3,    // System error or resource exhaustion.
   444         EXIT_ABNORMAL = 4;  // Compiler terminated abnormally
   446     int run(String[] args) {
   447         try {
   448             handleOptions(args);
   450             // the following gives consistent behavior with javac
   451             if (classes == null || classes.size() == 0) {
   452                 if (options.help || options.version || options.fullVersion)
   453                     return EXIT_OK;
   454                 else
   455                     return EXIT_CMDERR;
   456             }
   458             try {
   459                 boolean ok = run();
   460                 return ok ? EXIT_OK : EXIT_ERROR;
   461             } finally {
   462                 if (defaultFileManager != null) {
   463                     try {
   464                         defaultFileManager.close();
   465                         defaultFileManager = null;
   466                     } catch (IOException e) {
   467                         throw new InternalError(e);
   468                     }
   469                 }
   470             }
   471         } catch (BadArgs e) {
   472             reportError(e.key, e.args);
   473             if (e.showUsage) {
   474                 log.println(getMessage("main.usage.summary", progname));
   475             }
   476             return EXIT_CMDERR;
   477         } catch (InternalError e) {
   478             Object[] e_args;
   479             if (e.getCause() == null)
   480                 e_args = e.args;
   481             else {
   482                 e_args = new Object[e.args.length + 1];
   483                 e_args[0] = e.getCause();
   484                 System.arraycopy(e.args, 0, e_args, 1, e.args.length);
   485             }
   486             reportError("err.internal.error", e_args);
   487             return EXIT_ABNORMAL;
   488         } finally {
   489             log.flush();
   490         }
   491     }
   493     public void handleOptions(String[] args) throws BadArgs {
   494         handleOptions(Arrays.asList(args), true);
   495     }
   497     private void handleOptions(Iterable<String> args, boolean allowClasses) throws BadArgs {
   498         if (log == null) {
   499             log = getPrintWriterForStream(System.out);
   500             if (diagnosticListener == null)
   501               diagnosticListener = getDiagnosticListenerForStream(System.err);
   502         } else {
   503             if (diagnosticListener == null)
   504               diagnosticListener = getDiagnosticListenerForWriter(log);
   505         }
   508         if (fileManager == null)
   509             fileManager = getDefaultFileManager(diagnosticListener, log);
   511         Iterator<String> iter = args.iterator();
   512         boolean noArgs = !iter.hasNext();
   514         while (iter.hasNext()) {
   515             String arg = iter.next();
   516             if (arg.startsWith("-"))
   517                 handleOption(arg, iter);
   518             else if (allowClasses) {
   519                 if (classes == null)
   520                     classes = new ArrayList<String>();
   521                 classes.add(arg);
   522                 while (iter.hasNext())
   523                     classes.add(iter.next());
   524             } else
   525                 throw new BadArgs("err.unknown.option", arg).showUsage(true);
   526         }
   528         if (!options.compat && options.accessOptions.size() > 1) {
   529             StringBuilder sb = new StringBuilder();
   530             for (String opt: options.accessOptions) {
   531                 if (sb.length() > 0)
   532                     sb.append(" ");
   533                 sb.append(opt);
   534             }
   535             throw new BadArgs("err.incompatible.options", sb);
   536         }
   538         if ((classes == null || classes.size() == 0) &&
   539                 !(noArgs || options.help || options.version || options.fullVersion)) {
   540             throw new BadArgs("err.no.classes.specified");
   541         }
   543         if (noArgs || options.help)
   544             showHelp();
   546         if (options.version || options.fullVersion)
   547             showVersion(options.fullVersion);
   548     }
   550     private void handleOption(String name, Iterator<String> rest) throws BadArgs {
   551         for (Option o: recognizedOptions) {
   552             if (o.matches(name)) {
   553                 if (o.hasArg) {
   554                     if (rest.hasNext())
   555                         o.process(this, name, rest.next());
   556                     else
   557                         throw new BadArgs("err.missing.arg", name).showUsage(true);
   558                 } else
   559                     o.process(this, name, null);
   561                 if (o.ignoreRest()) {
   562                     while (rest.hasNext())
   563                         rest.next();
   564                 }
   565                 return;
   566             }
   567         }
   569         if (fileManager.handleOption(name, rest))
   570             return;
   572         throw new BadArgs("err.unknown.option", name).showUsage(true);
   573     }
   575     public Boolean call() {
   576         return run();
   577     }
   579     public boolean run() {
   580         if (classes == null || classes.size() == 0)
   581             return false;
   583         context.put(PrintWriter.class, log);
   584         ClassWriter classWriter = ClassWriter.instance(context);
   585         SourceWriter sourceWriter = SourceWriter.instance(context);
   586         sourceWriter.setFileManager(fileManager);
   588         attributeFactory.setCompat(options.compat);
   589         attributeFactory.setJSR277(options.jsr277);
   591         boolean ok = true;
   593         for (String className: classes) {
   594             JavaFileObject fo;
   595             try {
   596                 writeClass(classWriter, className);
   597             } catch (ConstantPoolException e) {
   598                 reportError("err.bad.constant.pool", className, e.getLocalizedMessage());
   599                 ok = false;
   600             } catch (EOFException e) {
   601                 reportError("err.end.of.file", className);
   602                 ok = false;
   603             } catch (FileNotFoundException e) {
   604                 reportError("err.file.not.found", e.getLocalizedMessage());
   605                 ok = false;
   606             } catch (IOException e) {
   607                 //e.printStackTrace();
   608                 Object msg = e.getLocalizedMessage();
   609                 if (msg == null)
   610                     msg = e;
   611                 reportError("err.ioerror", className, msg);
   612                 ok = false;
   613             } catch (Throwable t) {
   614                 StringWriter sw = new StringWriter();
   615                 PrintWriter pw = new PrintWriter(sw);
   616                 t.printStackTrace(pw);
   617                 pw.close();
   618                 reportError("err.crash", t.toString(), sw.toString());
   619                 ok = false;
   620             }
   621         }
   623         return ok;
   624     }
   626     protected boolean writeClass(ClassWriter classWriter, String className)
   627             throws IOException, ConstantPoolException {
   628         JavaFileObject fo = open(className);
   629         if (fo == null) {
   630             reportError("err.class.not.found", className);
   631             return false;
   632         }
   634         ClassFileInfo cfInfo = read(fo);
   635         if (!className.endsWith(".class")) {
   636             String cfName = cfInfo.cf.getName();
   637             if (!cfName.replaceAll("[/$]", ".").equals(className.replaceAll("[/$]", ".")))
   638                 reportWarning("warn.unexpected.class", className, cfName.replace('/', '.'));
   639         }
   640         write(cfInfo);
   642         if (options.showInnerClasses) {
   643             ClassFile cf = cfInfo.cf;
   644             Attribute a = cf.getAttribute(Attribute.InnerClasses);
   645             if (a instanceof InnerClasses_attribute) {
   646                 InnerClasses_attribute inners = (InnerClasses_attribute) a;
   647                 try {
   648                     boolean ok = true;
   649                     for (int i = 0; i < inners.classes.length; i++) {
   650                         int outerIndex = inners.classes[i].outer_class_info_index;
   651                         ConstantPool.CONSTANT_Class_info outerClassInfo = cf.constant_pool.getClassInfo(outerIndex);
   652                         String outerClassName = outerClassInfo.getName();
   653                         if (outerClassName.equals(cf.getName())) {
   654                             int innerIndex = inners.classes[i].inner_class_info_index;
   655                             ConstantPool.CONSTANT_Class_info innerClassInfo = cf.constant_pool.getClassInfo(innerIndex);
   656                             String innerClassName = innerClassInfo.getName();
   657                             classWriter.println("// inner class " + innerClassName.replaceAll("[/$]", "."));
   658                             classWriter.println();
   659                             ok = ok & writeClass(classWriter, innerClassName);
   660                         }
   661                     }
   662                     return ok;
   663                 } catch (ConstantPoolException e) {
   664                     reportError("err.bad.innerclasses.attribute", className);
   665                     return false;
   666                 }
   667             } else if (a != null) {
   668                 reportError("err.bad.innerclasses.attribute", className);
   669                 return false;
   670             }
   671         }
   673         return true;
   674     }
   676     protected JavaFileObject open(String className) throws IOException {
   677         // for compatibility, first see if it is a class name
   678         JavaFileObject fo = getClassFileObject(className);
   679         if (fo != null)
   680             return fo;
   682         // see if it is an inner class, by replacing dots to $, starting from the right
   683         String cn = className;
   684         int lastDot;
   685         while ((lastDot = cn.lastIndexOf(".")) != -1) {
   686             cn = cn.substring(0, lastDot) + "$" + cn.substring(lastDot + 1);
   687             fo = getClassFileObject(cn);
   688             if (fo != null)
   689                 return fo;
   690         }
   692         if (!className.endsWith(".class"))
   693             return null;
   695         if (fileManager instanceof StandardJavaFileManager) {
   696             StandardJavaFileManager sfm = (StandardJavaFileManager) fileManager;
   697             fo = sfm.getJavaFileObjects(className).iterator().next();
   698             if (fo != null && fo.getLastModified() != 0) {
   699                 return fo;
   700             }
   701         }
   703         // see if it is a URL, and if so, wrap it in just enough of a JavaFileObject
   704         // to suit javap's needs
   705         if (className.matches("^[A-Za-z]+:.*")) {
   706             try {
   707                 final URI uri = new URI(className);
   708                 final URL url = uri.toURL();
   709                 final URLConnection conn = url.openConnection();
   710                 return new JavaFileObject() {
   711                     public Kind getKind() {
   712                         return JavaFileObject.Kind.CLASS;
   713                     }
   715                     public boolean isNameCompatible(String simpleName, Kind kind) {
   716                         throw new UnsupportedOperationException();
   717                     }
   719                     public NestingKind getNestingKind() {
   720                         throw new UnsupportedOperationException();
   721                     }
   723                     public Modifier getAccessLevel() {
   724                         throw new UnsupportedOperationException();
   725                     }
   727                     public URI toUri() {
   728                         return uri;
   729                     }
   731                     public String getName() {
   732                         return url.toString();
   733                     }
   735                     public InputStream openInputStream() throws IOException {
   736                         return conn.getInputStream();
   737                     }
   739                     public OutputStream openOutputStream() throws IOException {
   740                         throw new UnsupportedOperationException();
   741                     }
   743                     public Reader openReader(boolean ignoreEncodingErrors) throws IOException {
   744                         throw new UnsupportedOperationException();
   745                     }
   747                     public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
   748                         throw new UnsupportedOperationException();
   749                     }
   751                     public Writer openWriter() throws IOException {
   752                         throw new UnsupportedOperationException();
   753                     }
   755                     public long getLastModified() {
   756                         return conn.getLastModified();
   757                     }
   759                     public boolean delete() {
   760                         throw new UnsupportedOperationException();
   761                     }
   763                 };
   764             } catch (URISyntaxException ignore) {
   765             } catch (IOException ignore) {
   766             }
   767         }
   769         return null;
   770     }
   772     public static class ClassFileInfo {
   773         ClassFileInfo(JavaFileObject fo, ClassFile cf, byte[] digest, int size) {
   774             this.fo = fo;
   775             this.cf = cf;
   776             this.digest = digest;
   777             this.size = size;
   778         }
   779         public final JavaFileObject fo;
   780         public final ClassFile cf;
   781         public final byte[] digest;
   782         public final int size;
   783     }
   785     public ClassFileInfo read(JavaFileObject fo) throws IOException, ConstantPoolException {
   786         InputStream in = fo.openInputStream();
   787         try {
   788             SizeInputStream sizeIn = null;
   789             MessageDigest md  = null;
   790             if (options.sysInfo || options.verbose) {
   791                 try {
   792                     md = MessageDigest.getInstance("MD5");
   793                 } catch (NoSuchAlgorithmException ignore) {
   794                 }
   795                 in = new DigestInputStream(in, md);
   796                 in = sizeIn = new SizeInputStream(in);
   797             }
   799             ClassFile cf = ClassFile.read(in, attributeFactory);
   800             byte[] digest = (md == null) ? null : md.digest();
   801             int size = (sizeIn == null) ? -1 : sizeIn.size();
   802             return new ClassFileInfo(fo, cf, digest, size);
   803         } finally {
   804             in.close();
   805         }
   806     }
   808     public void write(ClassFileInfo info) {
   809         ClassWriter classWriter = ClassWriter.instance(context);
   810         if (options.sysInfo || options.verbose) {
   811             classWriter.setFile(info.fo.toUri());
   812             classWriter.setLastModified(info.fo.getLastModified());
   813             classWriter.setDigest("MD5", info.digest);
   814             classWriter.setFileSize(info.size);
   815         }
   817         classWriter.write(info.cf);
   818     }
   820     protected void setClassFile(ClassFile classFile) {
   821         ClassWriter classWriter = ClassWriter.instance(context);
   822         classWriter.setClassFile(classFile);
   823     }
   825     protected void setMethod(Method enclosingMethod) {
   826         ClassWriter classWriter = ClassWriter.instance(context);
   827         classWriter.setMethod(enclosingMethod);
   828     }
   830     protected void write(Attribute value) {
   831         AttributeWriter attrWriter = AttributeWriter.instance(context);
   832         ClassWriter classWriter = ClassWriter.instance(context);
   833         ClassFile cf = classWriter.getClassFile();
   834         attrWriter.write(cf, value, cf.constant_pool);
   835     }
   837     protected void write(Attributes attrs) {
   838         AttributeWriter attrWriter = AttributeWriter.instance(context);
   839         ClassWriter classWriter = ClassWriter.instance(context);
   840         ClassFile cf = classWriter.getClassFile();
   841         attrWriter.write(cf, attrs, cf.constant_pool);
   842     }
   844     protected void write(ConstantPool constant_pool) {
   845         ConstantWriter constantWriter = ConstantWriter.instance(context);
   846         constantWriter.writeConstantPool(constant_pool);
   847     }
   849     protected void write(ConstantPool constant_pool, int value) {
   850         ConstantWriter constantWriter = ConstantWriter.instance(context);
   851         constantWriter.write(value);
   852     }
   854     protected void write(ConstantPool.CPInfo value) {
   855         ConstantWriter constantWriter = ConstantWriter.instance(context);
   856         constantWriter.println(value);
   857     }
   859     protected void write(Field value) {
   860         ClassWriter classWriter = ClassWriter.instance(context);
   861         classWriter.writeField(value);
   862     }
   864     protected void write(Method value) {
   865         ClassWriter classWriter = ClassWriter.instance(context);
   866         classWriter.writeMethod(value);
   867     }
   869     private JavaFileManager getDefaultFileManager(final DiagnosticListener<? super JavaFileObject> dl, PrintWriter log) {
   870         if (defaultFileManager == null)
   871             defaultFileManager = JavapFileManager.create(dl, log);
   872         return defaultFileManager;
   873     }
   875     private JavaFileObject getClassFileObject(String className) throws IOException {
   876         JavaFileObject fo;
   877         fo = fileManager.getJavaFileForInput(StandardLocation.PLATFORM_CLASS_PATH, className, JavaFileObject.Kind.CLASS);
   878         if (fo == null)
   879             fo = fileManager.getJavaFileForInput(StandardLocation.CLASS_PATH, className, JavaFileObject.Kind.CLASS);
   880         return fo;
   881     }
   883     private void showHelp() {
   884         log.println(getMessage("main.usage", progname));
   885         for (Option o: recognizedOptions) {
   886             String name = o.aliases[0].substring(1); // there must always be at least one name
   887             if (name.startsWith("X") || name.equals("fullversion") || name.equals("h") || name.equals("verify"))
   888                 continue;
   889             log.println(getMessage("main.opt." + name));
   890         }
   891         String[] fmOptions = { "-classpath", "-bootclasspath" };
   892         for (String o: fmOptions) {
   893             if (fileManager.isSupportedOption(o) == -1)
   894                 continue;
   895             String name = o.substring(1);
   896             log.println(getMessage("main.opt." + name));
   897         }
   899     }
   901     private void showVersion(boolean full) {
   902         log.println(version(full ? "full" : "release"));
   903     }
   905     private static final String versionRBName = "com.sun.tools.javap.resources.version";
   906     private static ResourceBundle versionRB;
   908     private String version(String key) {
   909         // key=version:  mm.nn.oo[-milestone]
   910         // key=full:     mm.mm.oo[-milestone]-build
   911         if (versionRB == null) {
   912             try {
   913                 versionRB = ResourceBundle.getBundle(versionRBName);
   914             } catch (MissingResourceException e) {
   915                 return getMessage("version.resource.missing", System.getProperty("java.version"));
   916             }
   917         }
   918         try {
   919             return versionRB.getString(key);
   920         }
   921         catch (MissingResourceException e) {
   922             return getMessage("version.unknown", System.getProperty("java.version"));
   923         }
   924     }
   926     private void reportError(String key, Object... args) {
   927         diagnosticListener.report(createDiagnostic(Diagnostic.Kind.ERROR, key, args));
   928     }
   930     private void reportNote(String key, Object... args) {
   931         diagnosticListener.report(createDiagnostic(Diagnostic.Kind.NOTE, key, args));
   932     }
   934     private void reportWarning(String key, Object... args) {
   935         diagnosticListener.report(createDiagnostic(Diagnostic.Kind.WARNING, key, args));
   936     }
   938     private Diagnostic<JavaFileObject> createDiagnostic(
   939             final Diagnostic.Kind kind, final String key, final Object... args) {
   940         return new Diagnostic<JavaFileObject>() {
   941             public Kind getKind() {
   942                 return kind;
   943             }
   945             public JavaFileObject getSource() {
   946                 return null;
   947             }
   949             public long getPosition() {
   950                 return Diagnostic.NOPOS;
   951             }
   953             public long getStartPosition() {
   954                 return Diagnostic.NOPOS;
   955             }
   957             public long getEndPosition() {
   958                 return Diagnostic.NOPOS;
   959             }
   961             public long getLineNumber() {
   962                 return Diagnostic.NOPOS;
   963             }
   965             public long getColumnNumber() {
   966                 return Diagnostic.NOPOS;
   967             }
   969             public String getCode() {
   970                 return key;
   971             }
   973             public String getMessage(Locale locale) {
   974                 return JavapTask.this.getMessage(locale, key, args);
   975             }
   977             @Override
   978             public String toString() {
   979                 return getClass().getName() + "[key=" + key + ",args=" + Arrays.asList(args) + "]";
   980             }
   982         };
   984     }
   986     public String getMessage(String key, Object... args) {
   987         return getMessage(task_locale, key, args);
   988     }
   990     public String getMessage(Locale locale, String key, Object... args) {
   991         if (bundles == null) {
   992             // could make this a HashMap<Locale,SoftReference<ResourceBundle>>
   993             // and for efficiency, keep a hard reference to the bundle for the task
   994             // locale
   995             bundles = new HashMap<Locale, ResourceBundle>();
   996         }
   998         if (locale == null)
   999             locale = Locale.getDefault();
  1001         ResourceBundle b = bundles.get(locale);
  1002         if (b == null) {
  1003             try {
  1004                 b = ResourceBundle.getBundle("com.sun.tools.javap.resources.javap", locale);
  1005                 bundles.put(locale, b);
  1006             } catch (MissingResourceException e) {
  1007                 throw new InternalError("Cannot find javap resource bundle for locale " + locale);
  1011         try {
  1012             return MessageFormat.format(b.getString(key), args);
  1013         } catch (MissingResourceException e) {
  1014             throw new InternalError(e, key);
  1018     protected Context context;
  1019     JavaFileManager fileManager;
  1020     JavaFileManager defaultFileManager;
  1021     PrintWriter log;
  1022     DiagnosticListener<? super JavaFileObject> diagnosticListener;
  1023     List<String> classes;
  1024     Options options;
  1025     //ResourceBundle bundle;
  1026     Locale task_locale;
  1027     Map<Locale, ResourceBundle> bundles;
  1028     protected Attribute.Factory attributeFactory;
  1030     private static final String progname = "javap";
  1032     private static class SizeInputStream extends FilterInputStream {
  1033         SizeInputStream(InputStream in) {
  1034             super(in);
  1037         int size() {
  1038             return size;
  1041         @Override
  1042         public int read(byte[] buf, int offset, int length) throws IOException {
  1043             int n = super.read(buf, offset, length);
  1044             if (n > 0)
  1045                 size += n;
  1046             return n;
  1049         @Override
  1050         public int read() throws IOException {
  1051             int b = super.read();
  1052             size += 1;
  1053             return b;
  1056         private int size;

mercurial