Tue, 08 Sep 2009 11:43:57 -0700
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);
1008 }
1009 }
1011 try {
1012 return MessageFormat.format(b.getString(key), args);
1013 } catch (MissingResourceException e) {
1014 throw new InternalError(e, key);
1015 }
1016 }
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);
1035 }
1037 int size() {
1038 return size;
1039 }
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;
1047 }
1049 @Override
1050 public int read() throws IOException {
1051 int b = super.read();
1052 size += 1;
1053 return b;
1054 }
1056 private int size;
1057 }
1058 }