langtools/src/share/classes/com/sun/tools/apt/main/Main.java
changeset 11914 d1311b0c757f
parent 11913 be61e1597cc6
parent 11872 c51754cddc03
child 11915 33f703959597
child 11986 6f383069eb6d
equal deleted inserted replaced
11913:be61e1597cc6 11914:d1311b0c757f
     1 /*
       
     2  * Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.  Oracle designates this
       
     8  * particular file as subject to the "Classpath" exception as provided
       
     9  * by Oracle in the LICENSE file that accompanied this code.
       
    10  *
       
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    14  * version 2 for more details (a copy is included in the LICENSE file that
       
    15  * accompanied this code).
       
    16  *
       
    17  * You should have received a copy of the GNU General Public License version
       
    18  * 2 along with this work; if not, write to the Free Software Foundation,
       
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    20  *
       
    21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
       
    22  * or visit www.oracle.com if you need additional information or have any
       
    23  * questions.
       
    24  */
       
    25 
       
    26 package com.sun.tools.apt.main;
       
    27 
       
    28 import java.io.File;
       
    29 import java.io.FileWriter;
       
    30 import java.io.IOException;
       
    31 import java.io.PrintWriter;
       
    32 import java.text.MessageFormat;
       
    33 import java.util.ResourceBundle;
       
    34 import java.util.MissingResourceException;
       
    35 import java.util.StringTokenizer;
       
    36 import java.util.Map;
       
    37 import java.util.HashMap;
       
    38 import java.util.Collections;
       
    39 
       
    40 import java.net.URLClassLoader;
       
    41 import java.net.URL;
       
    42 import java.net.MalformedURLException;
       
    43 
       
    44 import javax.tools.JavaFileManager;
       
    45 import javax.tools.StandardLocation;
       
    46 
       
    47 import com.sun.tools.javac.file.JavacFileManager;
       
    48 import com.sun.tools.javac.code.Source;
       
    49 import com.sun.tools.javac.code.Symbol;
       
    50 import com.sun.tools.javac.code.Type;
       
    51 import com.sun.tools.javac.jvm.Target;
       
    52 import com.sun.tools.javac.util.*;
       
    53 
       
    54 import com.sun.tools.apt.comp.AnnotationProcessingError;
       
    55 import com.sun.tools.apt.comp.UsageMessageNeededException;
       
    56 import com.sun.tools.apt.util.Bark;
       
    57 import com.sun.mirror.apt.AnnotationProcessorFactory;
       
    58 
       
    59 import static com.sun.tools.javac.file.Locations.pathToURLs;
       
    60 
       
    61 /** This class provides a commandline interface to the apt build-time
       
    62  *  tool.
       
    63  *
       
    64  *  <p><b>This is NOT part of any supported API.
       
    65  *  If you write code that depends on this, you do so at your own
       
    66  *  risk.  This code and its internal interfaces are subject to change
       
    67  *  or deletion without notice.</b>
       
    68  */
       
    69 @SuppressWarnings("deprecation")
       
    70 public class Main {
       
    71 
       
    72     /** For testing: enter any options you want to be set implicitly
       
    73      *  here.
       
    74      */
       
    75     static String[] forcedOpts = {
       
    76         // Preserve parameter names from class files if the class was
       
    77         // compiled with debug enabled
       
    78         "-XDsave-parameter-names"
       
    79     };
       
    80 
       
    81     /** The name of the compiler, for use in diagnostics.
       
    82      */
       
    83     String ownName;
       
    84 
       
    85     /** The writer to use for diagnostic output.
       
    86      */
       
    87     PrintWriter out;
       
    88 
       
    89 
       
    90     /** Instantiated factory to use in lieu of discovery process.
       
    91      */
       
    92     AnnotationProcessorFactory providedFactory = null;
       
    93 
       
    94     /** Map representing original command-line arguments.
       
    95      */
       
    96     Map<String,String> origOptions = new HashMap<String, String>();
       
    97 
       
    98     /** Classloader to use for finding factories.
       
    99      */
       
   100     ClassLoader aptCL = null;
       
   101 
       
   102     /** Result codes.
       
   103      */
       
   104     static final int
       
   105         EXIT_OK = 0,        // Compilation completed with no errors.
       
   106         EXIT_ERROR = 1,     // Completed but reported errors.
       
   107         EXIT_CMDERR = 2,    // Bad command-line arguments
       
   108         EXIT_SYSERR = 3,    // System error or resource exhaustion.
       
   109         EXIT_ABNORMAL = 4;  // Compiler terminated abnormally
       
   110 
       
   111     /** This class represents an option recognized by the main program
       
   112      */
       
   113     private class Option {
       
   114         /** Whether or not the option is used only aptOnly.
       
   115          */
       
   116         boolean aptOnly = false;
       
   117 
       
   118         /** Option string.
       
   119          */
       
   120         String name;
       
   121 
       
   122         /** Documentation key for arguments.
       
   123          */
       
   124         String argsNameKey;
       
   125 
       
   126         /** Documentation key for description.
       
   127          */
       
   128         String descrKey;
       
   129 
       
   130         /** Suffix option (-foo=bar or -foo:bar)
       
   131          */
       
   132         boolean hasSuffix;
       
   133 
       
   134         Option(String name, String argsNameKey, String descrKey) {
       
   135             this.name = name;
       
   136             this.argsNameKey = argsNameKey;
       
   137             this.descrKey = descrKey;
       
   138             char lastChar = name.charAt(name.length()-1);
       
   139             hasSuffix = lastChar == ':' || lastChar == '=';
       
   140         }
       
   141         Option(String name, String descrKey) {
       
   142             this(name, null, descrKey);
       
   143         }
       
   144 
       
   145         public String toString() {
       
   146             return name;
       
   147         }
       
   148 
       
   149         /** Does this option take a (separate) operand?
       
   150          */
       
   151         boolean hasArg() {
       
   152             return argsNameKey != null && !hasSuffix;
       
   153         }
       
   154 
       
   155         /** Does argument string match option pattern?
       
   156          *  @param arg        The command line argument string.
       
   157          */
       
   158         boolean matches(String arg) {
       
   159             return hasSuffix ? arg.startsWith(name) : arg.equals(name);
       
   160         }
       
   161 
       
   162         /** For javac-only options, print nothing.
       
   163          */
       
   164         void help() {
       
   165         }
       
   166 
       
   167         String helpSynopsis() {
       
   168             return name +
       
   169                 (argsNameKey == null ? "" :
       
   170                  ((hasSuffix ? "" : " ") +
       
   171                   getLocalizedString(argsNameKey)));
       
   172         }
       
   173 
       
   174         /** Print a line of documentation describing this option, if non-standard.
       
   175          */
       
   176         void xhelp() {}
       
   177 
       
   178         /** Process the option (with arg). Return true if error detected.
       
   179          */
       
   180         boolean process(String option, String arg) {
       
   181             options.put(option, arg);
       
   182             return false;
       
   183         }
       
   184 
       
   185         /** Process the option (without arg). Return true if error detected.
       
   186          */
       
   187         boolean process(String option) {
       
   188             if (hasSuffix)
       
   189                 return process(name, option.substring(name.length()));
       
   190             else
       
   191                 return process(option, option);
       
   192         }
       
   193     };
       
   194 
       
   195     private class SharedOption extends Option {
       
   196         SharedOption(String name, String argsNameKey, String descrKey) {
       
   197             super(name, argsNameKey, descrKey);
       
   198         }
       
   199 
       
   200         SharedOption(String name, String descrKey) {
       
   201             super(name, descrKey);
       
   202         }
       
   203 
       
   204         void help() {
       
   205             String s = "  " + helpSynopsis();
       
   206             out.print(s);
       
   207             for (int j = s.length(); j < 29; j++) out.print(" ");
       
   208             Bark.printRawLines(out, getLocalizedString(descrKey));
       
   209         }
       
   210 
       
   211     }
       
   212 
       
   213     private class AptOption extends Option {
       
   214         AptOption(String name, String argsNameKey, String descrKey) {
       
   215             super(name, argsNameKey, descrKey);
       
   216             aptOnly = true;
       
   217         }
       
   218 
       
   219         AptOption(String name, String descrKey) {
       
   220             super(name, descrKey);
       
   221             aptOnly = true;
       
   222         }
       
   223 
       
   224         /** Print a line of documentation describing this option, if standard.
       
   225          */
       
   226         void help() {
       
   227             String s = "  " + helpSynopsis();
       
   228             out.print(s);
       
   229             for (int j = s.length(); j < 29; j++) out.print(" ");
       
   230             Bark.printRawLines(out, getLocalizedString(descrKey));
       
   231         }
       
   232 
       
   233     }
       
   234 
       
   235     /** A nonstandard or extended (-X) option
       
   236      */
       
   237     private class XOption extends Option {
       
   238         XOption(String name, String argsNameKey, String descrKey) {
       
   239             super(name, argsNameKey, descrKey);
       
   240         }
       
   241         XOption(String name, String descrKey) {
       
   242             this(name, null, descrKey);
       
   243         }
       
   244         void help() {}
       
   245         void xhelp() {}
       
   246     };
       
   247 
       
   248     /** A nonstandard or extended (-X) option
       
   249      */
       
   250     private class AptXOption extends Option {
       
   251         AptXOption(String name, String argsNameKey, String descrKey) {
       
   252             super(name, argsNameKey, descrKey);
       
   253             aptOnly = true;
       
   254         }
       
   255         AptXOption(String name, String descrKey) {
       
   256             this(name, null, descrKey);
       
   257         }
       
   258         void xhelp() {
       
   259             String s = "  " + helpSynopsis();
       
   260             out.print(s);
       
   261             for (int j = s.length(); j < 29; j++) out.print(" ");
       
   262             Log.printRawLines(out, getLocalizedString(descrKey));
       
   263         }
       
   264     };
       
   265 
       
   266     /** A hidden (implementor) option
       
   267      */
       
   268     private class HiddenOption extends Option {
       
   269         HiddenOption(String name) {
       
   270             super(name, null, null);
       
   271         }
       
   272         HiddenOption(String name, String argsNameKey) {
       
   273             super(name, argsNameKey, null);
       
   274         }
       
   275         void help() {}
       
   276         void xhelp() {}
       
   277     };
       
   278 
       
   279     private class AptHiddenOption extends HiddenOption {
       
   280         AptHiddenOption(String name) {
       
   281             super(name);
       
   282             aptOnly = true;
       
   283         }
       
   284         AptHiddenOption(String name, String argsNameKey) {
       
   285             super(name, argsNameKey);
       
   286             aptOnly = true;
       
   287         }
       
   288     }
       
   289 
       
   290     private Option[] recognizedOptions = {
       
   291         new Option("-g",                                        "opt.g"),
       
   292         new Option("-g:none",                                   "opt.g.none") {
       
   293             boolean process(String option) {
       
   294                 options.put("-g:", "none");
       
   295                 return false;
       
   296             }
       
   297         },
       
   298 
       
   299         new Option("-g:{lines,vars,source}",                    "opt.g.lines.vars.source") {
       
   300             boolean matches(String s) {
       
   301                 return s.startsWith("-g:");
       
   302             }
       
   303             boolean process(String option) {
       
   304                 String suboptions = option.substring(3);
       
   305                 options.put("-g:", suboptions);
       
   306                 // enter all the -g suboptions as "-g:suboption"
       
   307                 for (StringTokenizer t = new StringTokenizer(suboptions, ","); t.hasMoreTokens(); ) {
       
   308                     String tok = t.nextToken();
       
   309                     String opt = "-g:" + tok;
       
   310                     options.put(opt, opt);
       
   311                 }
       
   312                 return false;
       
   313             }
       
   314         },
       
   315 
       
   316         new XOption("-Xlint",                                   "opt.Xlint"),
       
   317         new XOption("-Xlint:{"
       
   318                     + "all,"
       
   319                     + "cast,deprecation,divzero,empty,unchecked,fallthrough,path,serial,finally,overrides,"
       
   320                     + "-cast,-deprecation,-divzero,-empty,-unchecked,-fallthrough,-path,-serial,-finally,-overrides,"
       
   321                     + "none}",
       
   322                                                                 "opt.Xlint.suboptlist") {
       
   323             boolean matches(String s) {
       
   324                 return s.startsWith("-Xlint:");
       
   325             }
       
   326             boolean process(String option) {
       
   327                 String suboptions = option.substring(7);
       
   328                 options.put("-Xlint:", suboptions);
       
   329                 // enter all the -Xlint suboptions as "-Xlint:suboption"
       
   330                 for (StringTokenizer t = new StringTokenizer(suboptions, ","); t.hasMoreTokens(); ) {
       
   331                     String tok = t.nextToken();
       
   332                     String opt = "-Xlint:" + tok;
       
   333                     options.put(opt, opt);
       
   334                 }
       
   335                 return false;
       
   336             }
       
   337         },
       
   338 
       
   339         new Option("-nowarn",                                   "opt.nowarn"),
       
   340         new Option("-verbose",                                  "opt.verbose"),
       
   341 
       
   342         // -deprecation is retained for command-line backward compatibility
       
   343         new Option("-deprecation",                              "opt.deprecation") {
       
   344                 boolean process(String option) {
       
   345                     options.put("-Xlint:deprecation", option);
       
   346                     return false;
       
   347                 }
       
   348             },
       
   349 
       
   350         new SharedOption("-classpath",     "opt.arg.path",      "opt.classpath"),
       
   351         new SharedOption("-cp",            "opt.arg.path",      "opt.classpath") {
       
   352             boolean process(String option, String arg) {
       
   353                 return super.process("-classpath", arg);
       
   354             }
       
   355         },
       
   356         new Option("-sourcepath",          "opt.arg.path",      "opt.sourcepath"),
       
   357         new Option("-bootclasspath",       "opt.arg.path",      "opt.bootclasspath") {
       
   358             boolean process(String option, String arg) {
       
   359                 options.remove("-Xbootclasspath/p:");
       
   360                 options.remove("-Xbootclasspath/a:");
       
   361                 return super.process(option, arg);
       
   362             }
       
   363         },
       
   364         new XOption("-Xbootclasspath/p:",  "opt.arg.path", "opt.Xbootclasspath.p"),
       
   365         new XOption("-Xbootclasspath/a:",  "opt.arg.path", "opt.Xbootclasspath.a"),
       
   366         new XOption("-Xbootclasspath:",    "opt.arg.path", "opt.bootclasspath") {
       
   367             boolean process(String option, String arg) {
       
   368                 options.remove("-Xbootclasspath/p:");
       
   369                 options.remove("-Xbootclasspath/a:");
       
   370                 return super.process("-bootclasspath", arg);
       
   371             }
       
   372         },
       
   373         new Option("-extdirs",             "opt.arg.dirs",      "opt.extdirs"),
       
   374         new XOption("-Djava.ext.dirs=",    "opt.arg.dirs",      "opt.extdirs") {
       
   375             boolean process(String option, String arg) {
       
   376                 return super.process("-extdirs", arg);
       
   377             }
       
   378         },
       
   379         new Option("-endorseddirs",        "opt.arg.dirs",      "opt.endorseddirs"),
       
   380         new XOption("-Djava.endorsed.dirs=","opt.arg.dirs",     "opt.endorseddirs") {
       
   381             boolean process(String option, String arg) {
       
   382                 return super.process("-endorseddirs", arg);
       
   383             }
       
   384         },
       
   385         new Option("-proc:{none, only}",                        "opt.proc.none.only") {
       
   386             public boolean matches(String s) {
       
   387                 return s.equals("-proc:none") || s.equals("-proc:only");
       
   388             }
       
   389         },
       
   390         new Option("-processor",        "opt.arg.class",        "opt.processor"),
       
   391         new Option("-processorpath",    "opt.arg.path",         "opt.processorpath"),
       
   392 
       
   393         new SharedOption("-d",          "opt.arg.path", "opt.d"),
       
   394         new SharedOption("-s",          "opt.arg.path", "opt.s"),
       
   395         new Option("-encoding",         "opt.arg.encoding",     "opt.encoding"),
       
   396         new SharedOption("-source",             "opt.arg.release",      "opt.source") {
       
   397             boolean process(String option, String operand) {
       
   398                 Source source = Source.lookup(operand);
       
   399                 if (source == null) {
       
   400                     error("err.invalid.source", operand);
       
   401                     return true;
       
   402                 } else if (source.compareTo(Source.JDK1_5) > 0) {
       
   403                     error("err.unsupported.source.version", operand);
       
   404                     return true;
       
   405                 }
       
   406                 return super.process(option, operand);
       
   407             }
       
   408         },
       
   409         new Option("-target",           "opt.arg.release",      "opt.target") {
       
   410             boolean process(String option, String operand) {
       
   411                 Target target = Target.lookup(operand);
       
   412                 if (target == null) {
       
   413                     error("err.invalid.target", operand);
       
   414                     return true;
       
   415                 } else if (target.compareTo(Target.JDK1_5) > 0) {
       
   416                     error("err.unsupported.target.version", operand);
       
   417                     return true;
       
   418                 }
       
   419                 return super.process(option, operand);
       
   420             }
       
   421         },
       
   422         new AptOption("-version",               "opt.version") {
       
   423             boolean process(String option) {
       
   424                 Bark.printRawLines(out, ownName + " " + AptJavaCompiler.version());
       
   425                 return super.process(option);
       
   426             }
       
   427         },
       
   428         new HiddenOption("-fullversion"),
       
   429         new AptOption("-help",                                  "opt.help") {
       
   430             boolean process(String option) {
       
   431                 Main.this.help();
       
   432                 return super.process(option);
       
   433             }
       
   434         },
       
   435         new SharedOption("-X",                                  "opt.X") {
       
   436             boolean process(String option) {
       
   437                 Main.this.xhelp();
       
   438                 return super.process(option);
       
   439             }
       
   440         },
       
   441 
       
   442         // This option exists only for the purpose of documenting itself.
       
   443         // It's actually implemented by the launcher.
       
   444         new AptOption("-J",             "opt.arg.flag",         "opt.J") {
       
   445             String helpSynopsis() {
       
   446                 hasSuffix = true;
       
   447                 return super.helpSynopsis();
       
   448             }
       
   449             boolean process(String option) {
       
   450                 throw new AssertionError
       
   451                     ("the -J flag should be caught by the launcher.");
       
   452             }
       
   453         },
       
   454 
       
   455 
       
   456         new SharedOption("-A",          "opt.proc.flag",        "opt.A") {
       
   457                 String helpSynopsis() {
       
   458                     hasSuffix = true;
       
   459                     return super.helpSynopsis();
       
   460                 }
       
   461 
       
   462                 boolean matches(String arg) {
       
   463                     return arg.startsWith("-A");
       
   464                 }
       
   465 
       
   466                 boolean hasArg() {
       
   467                     return false;
       
   468                 }
       
   469 
       
   470                 boolean process(String option) {
       
   471                     return process(option, option);
       
   472                 }
       
   473             },
       
   474 
       
   475         new AptOption("-nocompile",     "opt.nocompile"),
       
   476 
       
   477         new AptOption("-print",         "opt.print"),
       
   478 
       
   479         new AptOption("-factorypath", "opt.arg.path", "opt.factorypath"),
       
   480 
       
   481         new AptOption("-factory",     "opt.arg.class", "opt.factory"),
       
   482 
       
   483         new AptXOption("-XListAnnotationTypes", "opt.XListAnnotationTypes"),
       
   484 
       
   485         new AptXOption("-XListDeclarations",    "opt.XListDeclarations"),
       
   486 
       
   487         new AptXOption("-XPrintAptRounds",      "opt.XPrintAptRounds"),
       
   488 
       
   489         new AptXOption("-XPrintFactoryInfo",    "opt.XPrintFactoryInfo"),
       
   490 
       
   491         /*
       
   492          * Option to treat both classes and source files as
       
   493          * declarations that can be given on the command line and
       
   494          * processed as the result of an apt round.
       
   495          */
       
   496         new AptXOption("-XclassesAsDecls", "opt.XClassesAsDecls"),
       
   497 
       
   498         // new Option("-moreinfo",                                      "opt.moreinfo") {
       
   499         new HiddenOption("-moreinfo") {
       
   500             boolean process(String option) {
       
   501                 Type.moreInfo = true;
       
   502                 return super.process(option);
       
   503             }
       
   504         },
       
   505 
       
   506         // treat warnings as errors
       
   507         new HiddenOption("-Werror"),
       
   508 
       
   509         // use complex inference from context in the position of a method call argument
       
   510         new HiddenOption("-complexinference"),
       
   511 
       
   512         // prompt after each error
       
   513         // new Option("-prompt",                                        "opt.prompt"),
       
   514         new HiddenOption("-prompt"),
       
   515 
       
   516         // dump stack on error
       
   517         new HiddenOption("-doe"),
       
   518 
       
   519         // display warnings for generic unchecked and unsafe operations
       
   520         new HiddenOption("-warnunchecked") {
       
   521             boolean process(String option) {
       
   522                 options.put("-Xlint:unchecked", option);
       
   523                 return false;
       
   524             }
       
   525         },
       
   526 
       
   527         new HiddenOption("-Xswitchcheck") {
       
   528             boolean process(String option) {
       
   529                 options.put("-Xlint:switchcheck", option);
       
   530                 return false;
       
   531             }
       
   532         },
       
   533 
       
   534         // generate trace output for subtyping operations
       
   535         new HiddenOption("-debugsubtyping"),
       
   536 
       
   537         new XOption("-Xmaxerrs",        "opt.arg.number",       "opt.maxerrs"),
       
   538         new XOption("-Xmaxwarns",       "opt.arg.number",       "opt.maxwarns"),
       
   539         new XOption("-Xstdout",         "opt.arg.file",         "opt.Xstdout") {
       
   540             boolean process(String option, String arg) {
       
   541                 try {
       
   542                     out = new PrintWriter(new FileWriter(arg), true);
       
   543                 } catch (java.io.IOException e) {
       
   544                     error("err.error.writing.file", arg, e);
       
   545                     return true;
       
   546                 }
       
   547                 return super.process(option, arg);
       
   548             }
       
   549         },
       
   550 
       
   551         new XOption("-Xprint",                                  "opt.print"),
       
   552 
       
   553         new XOption("-XprintRounds",                            "opt.printRounds"),
       
   554 
       
   555         new XOption("-XprintProcessorInfo",                     "opt.printProcessorInfo"),
       
   556 
       
   557 
       
   558         /* -O is a no-op, accepted for backward compatibility. */
       
   559         new HiddenOption("-O"),
       
   560 
       
   561         /* -Xjcov produces tables to support the code coverage tool jcov. */
       
   562         new HiddenOption("-Xjcov"),
       
   563 
       
   564         /* This is a back door to the compiler's option table.
       
   565          * -Dx=y sets the option x to the value y.
       
   566          * -Dx sets the option x to the value x.
       
   567          */
       
   568         new HiddenOption("-XD") {
       
   569             String s;
       
   570             boolean matches(String s) {
       
   571                 this.s = s;
       
   572                 return s.startsWith(name);
       
   573             }
       
   574             boolean process(String option) {
       
   575                 s = s.substring(name.length());
       
   576                 int eq = s.indexOf('=');
       
   577                 String key = (eq < 0) ? s : s.substring(0, eq);
       
   578                 String value = (eq < 0) ? s : s.substring(eq+1);
       
   579                 options.put(key, value);
       
   580                 return false;
       
   581             }
       
   582         },
       
   583 
       
   584         new HiddenOption("sourcefile") {
       
   585                 String s;
       
   586                 boolean matches(String s) {
       
   587                     this.s = s;
       
   588                     return s.endsWith(".java") ||
       
   589                         (options.get("-XclassesAsDecls") != null);
       
   590                 }
       
   591                 boolean process(String option) {
       
   592                     if (s.endsWith(".java")) {
       
   593                         if (!sourceFileNames.contains(s))
       
   594                             sourceFileNames.add(s);
       
   595                     } else if (options.get("-XclassesAsDecls") != null) {
       
   596                         classFileNames.add(s);
       
   597                     }
       
   598                     return false;
       
   599                 }
       
   600             },
       
   601     };
       
   602 
       
   603     /**
       
   604      * Construct a compiler instance.
       
   605      */
       
   606     public Main(String name) {
       
   607         this(name, new PrintWriter(System.err, true));
       
   608     }
       
   609 
       
   610     /**
       
   611      * Construct a compiler instance.
       
   612      */
       
   613     public Main(String name, PrintWriter out) {
       
   614         this.ownName = name;
       
   615         this.out = out;
       
   616     }
       
   617 
       
   618     /** A table of all options that's passed to the JavaCompiler constructor.  */
       
   619     private Options options = null;
       
   620 
       
   621     /** The list of source files to process
       
   622      */
       
   623     java.util.List<String> sourceFileNames = new java.util.LinkedList<String>();
       
   624 
       
   625     /** The list of class files to process
       
   626      */
       
   627     java.util.List<String> classFileNames = new java.util.LinkedList<String>();
       
   628 
       
   629     /** List of top level names of generated source files from most recent apt round.
       
   630      */
       
   631     java.util.Set<String> genSourceFileNames = new java.util.LinkedHashSet<String>();
       
   632 
       
   633     /** List of names of generated class files from most recent apt round.
       
   634      */
       
   635     java.util.Set<String> genClassFileNames  = new java.util.LinkedHashSet<String>();
       
   636 
       
   637     /**
       
   638      * List of all the generated source file names across all apt rounds.
       
   639      */
       
   640     java.util.Set<String> aggregateGenSourceFileNames = new java.util.LinkedHashSet<String>();
       
   641 
       
   642     /**
       
   643      * List of all the generated class file names across all apt rounds.
       
   644      */
       
   645     java.util.Set<String> aggregateGenClassFileNames  = new java.util.LinkedHashSet<String>();
       
   646 
       
   647     /**
       
   648      * List of all the generated file names across all apt rounds.
       
   649      */
       
   650     java.util.Set<java.io.File> aggregateGenFiles = new java.util.LinkedHashSet<java.io.File>();
       
   651 
       
   652     /**
       
   653      * Set of all factories that have provided a processor on some apt round.
       
   654      */
       
   655     java.util.Set<Class<? extends AnnotationProcessorFactory> > productiveFactories  =
       
   656         new java.util.LinkedHashSet<Class<? extends AnnotationProcessorFactory> >();
       
   657 
       
   658 
       
   659 
       
   660     /** Print a string that explains usage.
       
   661      */
       
   662     void help() {
       
   663         Bark.printRawLines(out, getLocalizedString("msg.usage.header", ownName));
       
   664         for (int i=0; i < recognizedOptions.length; i++) {
       
   665             recognizedOptions[i].help();
       
   666         }
       
   667         Bark.printRawLines(out, getLocalizedString("msg.usage.footer"));
       
   668         out.println();
       
   669     }
       
   670 
       
   671     /** Print a string that explains usage for X options.
       
   672      */
       
   673     void xhelp() {
       
   674         for (int i=0; i<recognizedOptions.length; i++) {
       
   675             recognizedOptions[i].xhelp();
       
   676         }
       
   677         out.println();
       
   678         Bark.printRawLines(out, getLocalizedString("msg.usage.nonstandard.footer"));
       
   679     }
       
   680 
       
   681     /** Report a usage error.
       
   682      */
       
   683     void error(String key, Object... args) {
       
   684         warning(key, args);
       
   685         help();
       
   686     }
       
   687 
       
   688     /** Report a warning.
       
   689      */
       
   690     void warning(String key, Object... args) {
       
   691         Bark.printRawLines(out, ownName + ": "
       
   692                        + getLocalizedString(key, args));
       
   693     }
       
   694 
       
   695     /** Process command line arguments: store all command line options
       
   696      *  in `options' table and return all source filenames.
       
   697      *  @param args    The array of command line arguments.
       
   698      */
       
   699     protected java.util.List<String> processArgs(String[] flags) {
       
   700         int ac = 0;
       
   701         while (ac < flags.length) {
       
   702             String flag = flags[ac];
       
   703             ac++;
       
   704 
       
   705             int j;
       
   706             for (j=0; j < recognizedOptions.length; j++)
       
   707                 if (recognizedOptions[j].matches(flag))
       
   708                     break;
       
   709 
       
   710             if (j == recognizedOptions.length) {
       
   711                 error("err.invalid.flag", flag);
       
   712                 return null;
       
   713             }
       
   714 
       
   715             Option option = recognizedOptions[j];
       
   716             if (option.hasArg()) {
       
   717                 if (ac == flags.length) {
       
   718                     error("err.req.arg", flag);
       
   719                     return null;
       
   720                 }
       
   721                 String operand = flags[ac];
       
   722                 ac++;
       
   723                 if (option.process(flag, operand))
       
   724                     return null;
       
   725             } else {
       
   726                 if (option.process(flag))
       
   727                     return null;
       
   728             }
       
   729         }
       
   730 
       
   731         String sourceString = options.get("-source");
       
   732         Source source = (sourceString != null)
       
   733             ? Source.lookup(sourceString)
       
   734             : Source.JDK1_5; // JDK 5 is the latest supported source version
       
   735         String targetString = options.get("-target");
       
   736         Target target = (targetString != null)
       
   737             ? Target.lookup(targetString)
       
   738             : Target.JDK1_5; // JDK 5 is the latest supported source version
       
   739         // We don't check source/target consistency for CLDC, as J2ME
       
   740         // profiles are not aligned with J2SE targets; moreover, a
       
   741         // single CLDC target may have many profiles.  In addition,
       
   742         // this is needed for the continued functioning of the JSR14
       
   743         // prototype.
       
   744         if (Character.isDigit(target.name.charAt(0)) &&
       
   745             target.compareTo(source.requiredTarget()) < 0) {
       
   746             if (targetString != null) {
       
   747                 if (sourceString == null) {
       
   748                     warning("warn.target.default.source.conflict",
       
   749                             targetString,
       
   750                             source.requiredTarget().name);
       
   751                 } else {
       
   752                     warning("warn.source.target.conflict",
       
   753                             sourceString,
       
   754                             source.requiredTarget().name);
       
   755                 }
       
   756                 return null;
       
   757             } else {
       
   758                 options.put("-target", source.requiredTarget().name);
       
   759             }
       
   760         }
       
   761         return sourceFileNames;
       
   762     }
       
   763 
       
   764     /** Programmatic interface for main function.
       
   765      * @param args    The command line parameters.
       
   766      */
       
   767     public int compile(String[] args, AnnotationProcessorFactory factory) {
       
   768         int returnCode = 0;
       
   769         providedFactory = factory;
       
   770 
       
   771         Context context = new Context();
       
   772         JavacFileManager.preRegister(context);
       
   773         options = Options.instance(context);
       
   774         Bark bark;
       
   775 
       
   776         /*
       
   777          * Process the command line options to create the intial
       
   778          * options data.  This processing is at least partially reused
       
   779          * by any recursive apt calls.
       
   780          */
       
   781 
       
   782         // For testing: assume all arguments in forcedOpts are
       
   783         // prefixed to command line arguments.
       
   784         processArgs(forcedOpts);
       
   785 
       
   786         /*
       
   787          * A run of apt only gets passed the most recently generated
       
   788          * files; the initial run of apt gets passed the files from
       
   789          * the command line.
       
   790          */
       
   791 
       
   792         java.util.List<String> origFilenames;
       
   793         try {
       
   794             // assign args the result of parse to capture results of
       
   795             // '@file' expansion
       
   796             origFilenames = processArgs((args=CommandLine.parse(args)));
       
   797 
       
   798             if (options.get("suppress-tool-api-removal-message") == null) {
       
   799                 Bark.printRawLines(out, getLocalizedString("misc.Deprecation"));
       
   800             }
       
   801 
       
   802             if (origFilenames == null) {
       
   803                 return EXIT_CMDERR;
       
   804             } else if (origFilenames.size() == 0) {
       
   805                 // it is allowed to compile nothing if just asking for help
       
   806                 if (options.get("-help") != null ||
       
   807                     options.get("-X") != null)
       
   808                     return EXIT_OK;
       
   809             }
       
   810         } catch (java.io.FileNotFoundException e) {
       
   811             Bark.printRawLines(out, ownName + ": " +
       
   812                            getLocalizedString("err.file.not.found",
       
   813                                               e.getMessage()));
       
   814             return EXIT_SYSERR;
       
   815         } catch (IOException ex) {
       
   816             ioMessage(ex);
       
   817             return EXIT_SYSERR;
       
   818         } catch (OutOfMemoryError ex) {
       
   819             resourceMessage(ex);
       
   820             return EXIT_SYSERR;
       
   821         } catch (StackOverflowError ex) {
       
   822             resourceMessage(ex);
       
   823             return EXIT_SYSERR;
       
   824         } catch (FatalError ex) {
       
   825             feMessage(ex);
       
   826             return EXIT_SYSERR;
       
   827         } catch (sun.misc.ServiceConfigurationError sce) {
       
   828             sceMessage(sce);
       
   829             return EXIT_ABNORMAL;
       
   830         } catch (Throwable ex) {
       
   831             bugMessage(ex);
       
   832             return EXIT_ABNORMAL;
       
   833         }
       
   834 
       
   835 
       
   836         boolean firstRound = true;
       
   837         boolean needSourcePath = false;
       
   838         boolean needClassPath  = false;
       
   839         boolean classesAsDecls = options.get("-XclassesAsDecls") != null;
       
   840 
       
   841         /*
       
   842          * Create augumented classpath and sourcepath values.
       
   843          *
       
   844          * If any of the prior apt rounds generated any new source
       
   845          * files, the n'th apt round (and any javac invocation) has the
       
   846          * source destination path ("-s path") as the last element of
       
   847          * the "-sourcepath" to the n'th call.
       
   848          *
       
   849          * If any of the prior apt rounds generated any new class files,
       
   850          * the n'th apt round (and any javac invocation) has the class
       
   851          * destination path ("-d path") as the last element of the
       
   852          * "-classpath" to the n'th call.
       
   853          */
       
   854         String augmentedSourcePath = "";
       
   855         String augmentedClassPath = "";
       
   856         String baseClassPath = "";
       
   857 
       
   858         try {
       
   859             /*
       
   860              * Record original options for future annotation processor
       
   861              * invocations.
       
   862              */
       
   863             origOptions = new HashMap<String, String>(options.size());
       
   864             for(String s: options.keySet()) {
       
   865                 String value;
       
   866                 if (s.equals(value = options.get(s)))
       
   867                     origOptions.put(s, (String)null);
       
   868                 else
       
   869                     origOptions.put(s, value);
       
   870             }
       
   871             origOptions = Collections.unmodifiableMap(origOptions);
       
   872 
       
   873             JavacFileManager fm = (JavacFileManager) context.get(JavaFileManager.class);
       
   874             {
       
   875                 // Note: it might be necessary to check for an empty
       
   876                 // component ("") of the source path or class path
       
   877 
       
   878                 String sourceDest = options.get("-s");
       
   879                 if (fm.hasLocation(StandardLocation.SOURCE_PATH)) {
       
   880                     for(File f: fm.getLocation(StandardLocation.SOURCE_PATH))
       
   881                         augmentedSourcePath += (f + File.pathSeparator);
       
   882                     augmentedSourcePath += (sourceDest == null)?".":sourceDest;
       
   883                 } else {
       
   884                     augmentedSourcePath = ".";
       
   885 
       
   886                     if (sourceDest != null)
       
   887                         augmentedSourcePath += (File.pathSeparator + sourceDest);
       
   888                 }
       
   889 
       
   890                 String classDest = options.get("-d");
       
   891                 if (fm.hasLocation(StandardLocation.CLASS_PATH)) {
       
   892                     for(File f: fm.getLocation(StandardLocation.CLASS_PATH))
       
   893                         baseClassPath += (f + File.pathSeparator);
       
   894                     // put baseClassPath into map to handle any
       
   895                     // value needed for the classloader
       
   896                     options.put("-classpath", baseClassPath);
       
   897 
       
   898                     augmentedClassPath = baseClassPath + ((classDest == null)?".":classDest);
       
   899                 } else {
       
   900                     baseClassPath = ".";
       
   901                     if (classDest != null)
       
   902                         augmentedClassPath = baseClassPath + (File.pathSeparator + classDest);
       
   903                 }
       
   904                 assert options.get("-classpath") != null;
       
   905             }
       
   906 
       
   907             /*
       
   908              * Create base and augmented class loaders
       
   909              */
       
   910             ClassLoader augmentedAptCL = null;
       
   911             {
       
   912             /*
       
   913              * Use a url class loader to look for classes on the
       
   914              * user-specified class path. Prepend computed bootclass
       
   915              * path, which includes extdirs, to the URLClassLoader apt
       
   916              * uses.
       
   917              */
       
   918                 String aptclasspath = "";
       
   919                 String bcp = "";
       
   920                 Iterable<? extends File> bootclasspath = fm.getLocation(StandardLocation.PLATFORM_CLASS_PATH);
       
   921 
       
   922                 if (bootclasspath != null) {
       
   923                     for(File f: bootclasspath)
       
   924                         bcp += (f + File.pathSeparator);
       
   925                 }
       
   926 
       
   927                 // If the factory path is set, use that path
       
   928                 if (providedFactory == null)
       
   929                     aptclasspath = options.get("-factorypath");
       
   930                 if (aptclasspath == null)
       
   931                     aptclasspath = options.get("-classpath");
       
   932 
       
   933                 assert aptclasspath != null;
       
   934                 aptclasspath = (bcp + aptclasspath);
       
   935                 aptCL = new URLClassLoader(pathToURLs(aptclasspath));
       
   936 
       
   937                 if (providedFactory == null &&
       
   938                     options.get("-factorypath") != null) // same CL even if new class files written
       
   939                     augmentedAptCL = aptCL;
       
   940                 else {
       
   941                     // Create class loader in case new class files are
       
   942                     // written
       
   943                     augmentedAptCL = new URLClassLoader(pathToURLs(augmentedClassPath.
       
   944                                                                    substring(baseClassPath.length())),
       
   945                                                         aptCL);
       
   946                 }
       
   947             }
       
   948 
       
   949             int round = 0; // For -XPrintAptRounds
       
   950             do {
       
   951                 round++;
       
   952 
       
   953                 Context newContext = new Context();
       
   954                 Options newOptions = Options.instance(newContext); // creates a new context
       
   955                 newOptions.putAll(options);
       
   956 
       
   957                 // populate with old options... don't bother reparsing command line, etc.
       
   958 
       
   959                 // if genSource files, must add destination to source path
       
   960                 if (genSourceFileNames.size() > 0 && !firstRound) {
       
   961                     newOptions.put("-sourcepath", augmentedSourcePath);
       
   962                     needSourcePath = true;
       
   963                 }
       
   964                 aggregateGenSourceFileNames.addAll(genSourceFileNames);
       
   965                 sourceFileNames.addAll(genSourceFileNames);
       
   966                 genSourceFileNames.clear();
       
   967 
       
   968                 // Don't really need to track this; just have to add -d
       
   969                 // "foo" to class path if any class files are generated
       
   970                 if (genClassFileNames.size() > 0) {
       
   971                     newOptions.put("-classpath", augmentedClassPath);
       
   972                     aptCL = augmentedAptCL;
       
   973                     needClassPath = true;
       
   974                 }
       
   975                 aggregateGenClassFileNames.addAll(genClassFileNames);
       
   976                 classFileNames.addAll(genClassFileNames);
       
   977                 genClassFileNames.clear();
       
   978 
       
   979                 options = newOptions;
       
   980 
       
   981                 if (options.get("-XPrintAptRounds") != null) {
       
   982                     out.println("apt Round : " + round);
       
   983                     out.println("filenames: " + sourceFileNames);
       
   984                     if (classesAsDecls)
       
   985                         out.println("classnames: " + classFileNames);
       
   986                     out.println("options: " + options);
       
   987                 }
       
   988 
       
   989                 returnCode = compile(args, newContext);
       
   990                 firstRound = false;
       
   991 
       
   992                 // Check for reported errors before continuing
       
   993                 bark = Bark.instance(newContext);
       
   994             } while(((genSourceFileNames.size() != 0 ) ||
       
   995                      (classesAsDecls && genClassFileNames.size() != 0)) &&
       
   996                     bark.nerrors == 0);
       
   997         } catch (UsageMessageNeededException umne) {
       
   998             help();
       
   999             return EXIT_CMDERR; // will cause usage message to be printed
       
  1000         }
       
  1001 
       
  1002         /*
       
  1003          * Do not compile if a processor has reported an error or if
       
  1004          * there are no source files to process.  A more sophisticated
       
  1005          * test would also fail for syntax errors caught by javac.
       
  1006          */
       
  1007         if (options.get("-nocompile") == null &&
       
  1008             options.get("-print")     == null &&
       
  1009             bark.nerrors == 0 &&
       
  1010             (origFilenames.size() > 0 || aggregateGenSourceFileNames.size() > 0 )) {
       
  1011             /*
       
  1012              * Need to create new argument string for calling javac:
       
  1013              * 1. apt specific arguments (e.g. -factory) must be stripped out
       
  1014              * 2. proper settings for sourcepath and classpath must be used
       
  1015              * 3. generated class names must be added
       
  1016              * 4. class file names as declarations must be removed
       
  1017              */
       
  1018 
       
  1019             int newArgsLength = args.length +
       
  1020                 (needSourcePath?1:0) +
       
  1021                 (needClassPath?1:0) +
       
  1022                 aggregateGenSourceFileNames.size();
       
  1023 
       
  1024             // Null out apt-specific options and don't copy over into
       
  1025             // newArgs. This loop should be a lot faster; the options
       
  1026             // array should be replaced with a better data structure
       
  1027             // which includes a map from strings to options.
       
  1028             //
       
  1029             // If treating classes as declarations, must strip out
       
  1030             // class names from the javac argument list
       
  1031             argLoop:
       
  1032             for(int i = 0; i < args.length; i++) {
       
  1033                 int matchPosition = -1;
       
  1034 
       
  1035                 // "-A" by itself is recognized by apt but not javac
       
  1036                 if (args[i] != null && args[i].equals("-A")) {
       
  1037                     newArgsLength--;
       
  1038                     args[i] = null;
       
  1039                     continue argLoop;
       
  1040                 } else {
       
  1041                     optionLoop:
       
  1042                     for(int j = 0; j < recognizedOptions.length; j++) {
       
  1043                         if (args[i] != null && recognizedOptions[j].matches(args[i])) {
       
  1044                             matchPosition = j;
       
  1045                             break optionLoop;
       
  1046                         }
       
  1047                     }
       
  1048 
       
  1049                     if (matchPosition != -1) {
       
  1050                         Option op = recognizedOptions[matchPosition];
       
  1051                         if (op.aptOnly) {
       
  1052                             newArgsLength--;
       
  1053                             args[i] = null;
       
  1054                             if (op.hasArg()) {
       
  1055                                 newArgsLength--;
       
  1056                                 args[i+1] = null;
       
  1057                             }
       
  1058                         } else {
       
  1059                             if (op.hasArg()) { // skip over next string
       
  1060                                 i++;
       
  1061                                 continue argLoop;
       
  1062                             }
       
  1063 
       
  1064                             if ((options.get("-XclassesAsDecls") != null) &&
       
  1065                                 (matchPosition == (recognizedOptions.length-1)) ){
       
  1066                                 // Remove class file names from
       
  1067                                 // consideration by javac.
       
  1068                                 if (! args[i].endsWith(".java")) {
       
  1069                                     newArgsLength--;
       
  1070                                     args[i] = null;
       
  1071                                 }
       
  1072                             }
       
  1073                         }
       
  1074                     }
       
  1075                 }
       
  1076             }
       
  1077 
       
  1078             String newArgs[] = new String[newArgsLength];
       
  1079 
       
  1080             int j = 0;
       
  1081             for(int i=0; i < args.length; i++) {
       
  1082                 if (args[i] != null)
       
  1083                     newArgs[j++] = args[i];
       
  1084             }
       
  1085 
       
  1086             if (needClassPath)
       
  1087                 newArgs[j++] = "-XD-classpath=" + augmentedClassPath;
       
  1088 
       
  1089             if (needSourcePath) {
       
  1090                 newArgs[j++] = "-XD-sourcepath=" + augmentedSourcePath;
       
  1091 
       
  1092                 for(String s: aggregateGenSourceFileNames)
       
  1093                     newArgs[j++] = s;
       
  1094             }
       
  1095 
       
  1096             returnCode = com.sun.tools.javac.Main.compile(newArgs);
       
  1097         }
       
  1098 
       
  1099         return returnCode;
       
  1100     }
       
  1101 
       
  1102     /** Programmatic interface for main function.
       
  1103      * @param args    The command line parameters.
       
  1104      */
       
  1105     int compile(String[] args, Context context) {
       
  1106         boolean assertionsEnabled = false;
       
  1107         assert assertionsEnabled = true;
       
  1108         if (!assertionsEnabled) {
       
  1109             // Bark.printLines(out, "fatal error: assertions must be enabled when running javac");
       
  1110             // return EXIT_ABNORMAL;
       
  1111         }
       
  1112         int exitCode = EXIT_OK;
       
  1113 
       
  1114         AptJavaCompiler comp = null;
       
  1115         try {
       
  1116             context.put(Bark.outKey, out);
       
  1117 
       
  1118             comp = AptJavaCompiler.instance(context);
       
  1119             if (comp == null)
       
  1120                 return EXIT_SYSERR;
       
  1121 
       
  1122             java.util.List<String> nameList = new java.util.LinkedList<String>();
       
  1123             nameList.addAll(sourceFileNames);
       
  1124             if (options.get("-XclassesAsDecls") != null)
       
  1125                 nameList.addAll(classFileNames);
       
  1126 
       
  1127             List<Symbol.ClassSymbol> cs
       
  1128                 = comp.compile(List.from(nameList.toArray(new String[0])),
       
  1129                                origOptions,
       
  1130                                aptCL,
       
  1131                                providedFactory,
       
  1132                                productiveFactories,
       
  1133                                aggregateGenFiles);
       
  1134 
       
  1135             /*
       
  1136              * If there aren't new source files, we shouldn't bother
       
  1137              *  running javac if there were errors.
       
  1138              *
       
  1139              * If there are new files, we should try running javac in
       
  1140              * case there were typing errors.
       
  1141              *
       
  1142              */
       
  1143 
       
  1144             if (comp.errorCount() != 0 ||
       
  1145                 options.get("-Werror") != null && comp.warningCount() != 0)
       
  1146                 return EXIT_ERROR;
       
  1147         } catch (IOException ex) {
       
  1148             ioMessage(ex);
       
  1149             return EXIT_SYSERR;
       
  1150         } catch (OutOfMemoryError ex) {
       
  1151             resourceMessage(ex);
       
  1152             return EXIT_SYSERR;
       
  1153         } catch (StackOverflowError ex) {
       
  1154             resourceMessage(ex);
       
  1155             return EXIT_SYSERR;
       
  1156         } catch (FatalError ex) {
       
  1157             feMessage(ex);
       
  1158             return EXIT_SYSERR;
       
  1159         } catch (UsageMessageNeededException umne) {
       
  1160             help();
       
  1161             return EXIT_CMDERR; // will cause usage message to be printed
       
  1162         } catch (AnnotationProcessingError ex) {
       
  1163             apMessage(ex);
       
  1164             return EXIT_ABNORMAL;
       
  1165         } catch (sun.misc.ServiceConfigurationError sce) {
       
  1166             sceMessage(sce);
       
  1167             return EXIT_ABNORMAL;
       
  1168         } catch (Throwable ex) {
       
  1169             bugMessage(ex);
       
  1170             return EXIT_ABNORMAL;
       
  1171         } finally {
       
  1172             if (comp != null) {
       
  1173                 comp.close();
       
  1174                 genSourceFileNames.addAll(comp.getSourceFileNames());
       
  1175                 genClassFileNames.addAll(comp.getClassFileNames());
       
  1176             }
       
  1177             sourceFileNames = new java.util.LinkedList<String>();
       
  1178             classFileNames  = new java.util.LinkedList<String>();
       
  1179         }
       
  1180         return exitCode;
       
  1181     }
       
  1182 
       
  1183     /** Print a message reporting an internal error.
       
  1184      */
       
  1185     void bugMessage(Throwable ex) {
       
  1186         Bark.printRawLines(out, getLocalizedString("msg.bug",
       
  1187                                                AptJavaCompiler.version()));
       
  1188         ex.printStackTrace(out);
       
  1189     }
       
  1190 
       
  1191     /** Print a message reporting an fatal error.
       
  1192      */
       
  1193     void apMessage(AnnotationProcessingError ex) {
       
  1194         Bark.printRawLines(out, getLocalizedString("misc.Problem"));
       
  1195         ex.getCause().printStackTrace(out);
       
  1196     }
       
  1197 
       
  1198     /** Print a message about sun.misc.Service problem.
       
  1199      */
       
  1200     void sceMessage(sun.misc.ServiceConfigurationError ex) {
       
  1201         Bark.printRawLines(out, getLocalizedString("misc.SunMiscService"));
       
  1202         ex.printStackTrace(out);
       
  1203     }
       
  1204 
       
  1205     /** Print a message reporting an fatal error.
       
  1206      */
       
  1207     void feMessage(Throwable ex) {
       
  1208         Bark.printRawLines(out, ex.toString());
       
  1209     }
       
  1210 
       
  1211     /** Print a message reporting an input/output error.
       
  1212      */
       
  1213     void ioMessage(Throwable ex) {
       
  1214         Bark.printRawLines(out, getLocalizedString("msg.io"));
       
  1215         ex.printStackTrace(out);
       
  1216     }
       
  1217 
       
  1218     /** Print a message reporting an out-of-resources error.
       
  1219      */
       
  1220     void resourceMessage(Throwable ex) {
       
  1221         Bark.printRawLines(out, getLocalizedString("msg.resource"));
       
  1222         ex.printStackTrace(out);
       
  1223     }
       
  1224 
       
  1225     /* ************************************************************************
       
  1226      * Internationalization
       
  1227      *************************************************************************/
       
  1228 
       
  1229     /** Find a localized string in the resource bundle.
       
  1230      *  @param key     The key for the localized string.
       
  1231      */
       
  1232     private static String getLocalizedString(String key, Object... args) {
       
  1233         return getText(key, args);
       
  1234     }
       
  1235 
       
  1236     private static final String javacRB =
       
  1237         "com.sun.tools.javac.resources.javac";
       
  1238 
       
  1239     private static final String aptRB =
       
  1240         "com.sun.tools.apt.resources.apt";
       
  1241 
       
  1242     private static ResourceBundle messageRBjavac;
       
  1243     private static ResourceBundle messageRBapt;
       
  1244 
       
  1245     /** Initialize ResourceBundle.
       
  1246      */
       
  1247     private static void initResource() {
       
  1248         try {
       
  1249             messageRBapt   = ResourceBundle.getBundle(aptRB);
       
  1250             messageRBjavac = ResourceBundle.getBundle(javacRB);
       
  1251         } catch (MissingResourceException e) {
       
  1252             Error x = new FatalError("Fatal Error: Resource for apt or javac is missing");
       
  1253             x.initCause(e);
       
  1254             throw x;
       
  1255         }
       
  1256     }
       
  1257 
       
  1258     /** Get and format message string from resource.
       
  1259      */
       
  1260     private static String getText(String key, Object... _args) {
       
  1261         String[] args = new String[_args.length];
       
  1262         for (int i=0; i<_args.length; i++) {
       
  1263             args[i] = "" + _args[i];
       
  1264         }
       
  1265         if (messageRBapt == null || messageRBjavac == null )
       
  1266             initResource();
       
  1267         try {
       
  1268             return MessageFormat.format(messageRBapt.getString("apt." + key),
       
  1269                                         (Object[]) args);
       
  1270         } catch (MissingResourceException e) {
       
  1271             try {
       
  1272                 return MessageFormat.format(messageRBjavac.getString("javac." + key),
       
  1273                                             (Object[]) args);
       
  1274             } catch (MissingResourceException f) {
       
  1275                 String msg = "apt or javac message file broken: key={0} "
       
  1276                     + "arguments={1}, {2}";
       
  1277                 return MessageFormat.format(msg, (Object[]) args);
       
  1278             }
       
  1279         }
       
  1280     }
       
  1281 }