src/share/classes/com/sun/tools/javah/JavahTask.java

Tue, 13 Oct 2009 15:26:30 -0700

author
jjg
date
Tue, 13 Oct 2009 15:26:30 -0700
changeset 423
8a4543b30586
parent 416
c287d51c57da
child 508
af75fd6155de
permissions
-rw-r--r--

6891079: Compiler allows invalid binary literals 0b and oBL
Reviewed-by: darcy

     1 /*
     2  * Copyright 2002-2009 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.javah;
    28 import java.io.File;
    29 import java.io.IOException;
    30 import java.io.OutputStream;
    31 import java.io.PrintWriter;
    32 import java.io.Writer;
    33 import java.text.MessageFormat;
    34 import java.util.ArrayList;
    35 import java.util.Arrays;
    36 import java.util.Collections;
    37 import java.util.HashMap;
    38 import java.util.Iterator;
    39 import java.util.LinkedHashSet;
    40 import java.util.List;
    41 import java.util.Locale;
    42 import java.util.Map;
    43 import java.util.MissingResourceException;
    44 import java.util.ResourceBundle;
    45 import java.util.Set;
    47 import javax.annotation.processing.AbstractProcessor;
    48 import javax.annotation.processing.Messager;
    49 import javax.annotation.processing.RoundEnvironment;
    50 import javax.annotation.processing.SupportedAnnotationTypes;
    51 import javax.annotation.processing.SupportedSourceVersion;
    53 import javax.lang.model.SourceVersion;
    54 import javax.lang.model.element.ExecutableElement;
    55 import javax.lang.model.element.TypeElement;
    56 import javax.lang.model.element.VariableElement;
    57 import javax.lang.model.type.ArrayType;
    58 import javax.lang.model.type.DeclaredType;
    59 import javax.lang.model.type.TypeMirror;
    60 import javax.lang.model.type.TypeVisitor;
    61 import javax.lang.model.util.ElementFilter;
    62 import javax.lang.model.util.SimpleTypeVisitor6;
    63 import javax.lang.model.util.Types;
    65 import javax.tools.Diagnostic;
    66 import javax.tools.DiagnosticListener;
    67 import javax.tools.JavaCompiler;
    68 import javax.tools.JavaCompiler.CompilationTask;
    69 import javax.tools.JavaFileManager;
    70 import javax.tools.JavaFileObject;
    71 import javax.tools.StandardJavaFileManager;
    72 import javax.tools.StandardLocation;
    73 import javax.tools.ToolProvider;
    75 /**
    76  * Javah generates support files for native methods.
    77  * Parse commandline options & Invokes javadoc to execute those commands.
    78  *
    79  * <p><b>This is NOT part of any API supported by Sun Microsystems.
    80  * If you write code that depends on this, you do so at your own
    81  * risk.  This code and its internal interfaces are subject to change
    82  * or deletion without notice.</b></p>
    83  *
    84  * @author Sucheta Dambalkar
    85  * @author Jonathan Gibbons
    86  */
    87 public class JavahTask implements NativeHeaderTool.NativeHeaderTask {
    88     public class BadArgs extends Exception {
    89         private static final long serialVersionUID = 1479361270874789045L;
    90         BadArgs(String key, Object... args) {
    91             super(JavahTask.this.getMessage(key, args));
    92             this.key = key;
    93             this.args = args;
    94         }
    96         BadArgs showUsage(boolean b) {
    97             showUsage = b;
    98             return this;
    99         }
   101         final String key;
   102         final Object[] args;
   103         boolean showUsage;
   104     }
   106     static abstract class Option {
   107         Option(boolean hasArg, String... aliases) {
   108             this.hasArg = hasArg;
   109             this.aliases = aliases;
   110         }
   112         boolean isHidden() {
   113             return false;
   114         }
   116         boolean matches(String opt) {
   117             for (String a: aliases) {
   118                 if (a.equals(opt))
   119                     return true;
   120             }
   121             return false;
   122         }
   124         boolean ignoreRest() {
   125             return false;
   126         }
   128         abstract void process(JavahTask task, String opt, String arg) throws BadArgs;
   130         final boolean hasArg;
   131         final String[] aliases;
   132     }
   134     static abstract class HiddenOption extends Option {
   135         HiddenOption(boolean hasArg, String... aliases) {
   136             super(hasArg, aliases);
   137         }
   139         @Override
   140         boolean isHidden() {
   141             return true;
   142         }
   143     }
   145     static Option[] recognizedOptions = {
   146         new Option(true, "-o") {
   147             void process(JavahTask task, String opt, String arg) {
   148                 task.ofile = new File(arg);
   149             }
   150         },
   152         new Option(true, "-d") {
   153             void process(JavahTask task, String opt, String arg) {
   154                 task.odir = new File(arg);
   155             }
   156         },
   158         new HiddenOption(true, "-td") {
   159             void process(JavahTask task, String opt, String arg) {
   160                  // ignored; for backwards compatibility
   161             }
   162         },
   164         new HiddenOption(false, "-stubs") {
   165             void process(JavahTask task, String opt, String arg) {
   166                  // ignored; for backwards compatibility
   167             }
   168         },
   170         new Option(false, "-v", "-verbose") {
   171             void process(JavahTask task, String opt, String arg) {
   172                 task.verbose = true;
   173             }
   174         },
   176         new Option(false, "-help", "--help", "-?") {
   177             void process(JavahTask task, String opt, String arg) {
   178                 task.help = true;
   179             }
   180         },
   182         new HiddenOption(false, "-trace") {
   183             void process(JavahTask task, String opt, String arg) {
   184                 task.trace = true;
   185             }
   186         },
   188         new Option(false, "-version") {
   189             void process(JavahTask task, String opt, String arg) {
   190                 task.version = true;
   191             }
   192         },
   194         new HiddenOption(false, "-fullversion") {
   195             void process(JavahTask task, String opt, String arg) {
   196                 task.fullVersion = true;
   197             }
   198         },
   200         new Option(false, "-jni") {
   201             void process(JavahTask task, String opt, String arg) {
   202                 task.jni = true;
   203             }
   204         },
   206         new Option(false, "-force") {
   207             void process(JavahTask task, String opt, String arg) {
   208                 task.force = true;
   209             }
   210         },
   212         new HiddenOption(false, "-Xnew") {
   213             void process(JavahTask task, String opt, String arg) {
   214                 // we're already using the new javah
   215             }
   216         },
   218         new HiddenOption(false, "-old") {
   219             void process(JavahTask task, String opt, String arg) {
   220                 task.old = true;
   221             }
   222         },
   224         new HiddenOption(false, "-llni", "-Xllni") {
   225             void process(JavahTask task, String opt, String arg) {
   226                 task.llni = true;
   227             }
   228         },
   230         new HiddenOption(false, "-llnidouble") {
   231             void process(JavahTask task, String opt, String arg) {
   232                 task.llni = true;
   233                 task.doubleAlign = true;
   234             }
   235         },
   236     };
   238     JavahTask() {
   239     }
   241     JavahTask(Writer out,
   242             JavaFileManager fileManager,
   243             DiagnosticListener<? super JavaFileObject> diagnosticListener,
   244             Iterable<String> options,
   245             Iterable<String> classes) {
   246         this();
   247         this.log = getPrintWriterForWriter(out);
   248         this.fileManager = fileManager;
   249         this.diagnosticListener = diagnosticListener;
   251         try {
   252             handleOptions(options, false);
   253         } catch (BadArgs e) {
   254             throw new IllegalArgumentException(e.getMessage());
   255         }
   257         this.classes = new ArrayList<String>();
   258         for (String classname: classes) {
   259             classname.getClass(); // null-check
   260             this.classes.add(classname);
   261         }
   262     }
   264     public void setLocale(Locale locale) {
   265         if (locale == null)
   266             locale = Locale.getDefault();
   267         task_locale = locale;
   268     }
   270     public void setLog(PrintWriter log) {
   271         this.log = log;
   272     }
   274     public void setLog(OutputStream s) {
   275         setLog(getPrintWriterForStream(s));
   276     }
   278     static PrintWriter getPrintWriterForStream(OutputStream s) {
   279         return new PrintWriter(s, true);
   280     }
   282     static PrintWriter getPrintWriterForWriter(Writer w) {
   283         if (w == null)
   284             return getPrintWriterForStream(null);
   285         else if (w instanceof PrintWriter)
   286             return (PrintWriter) w;
   287         else
   288             return new PrintWriter(w, true);
   289     }
   291     public void setDiagnosticListener(DiagnosticListener<? super JavaFileObject> dl) {
   292         diagnosticListener = dl;
   293     }
   295     public void setDiagnosticListener(OutputStream s) {
   296         setDiagnosticListener(getDiagnosticListenerForStream(s));
   297     }
   299     private DiagnosticListener<JavaFileObject> getDiagnosticListenerForStream(OutputStream s) {
   300         return getDiagnosticListenerForWriter(getPrintWriterForStream(s));
   301     }
   303     private DiagnosticListener<JavaFileObject> getDiagnosticListenerForWriter(Writer w) {
   304         final PrintWriter pw = getPrintWriterForWriter(w);
   305         return new DiagnosticListener<JavaFileObject> () {
   306             public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
   307                 if (diagnostic.getKind() == Diagnostic.Kind.ERROR) {
   308                     pw.print(getMessage("err.prefix"));
   309                     pw.print(" ");
   310                 }
   311                 pw.println(diagnostic.getMessage(null));
   312             }
   313         };
   314     }
   316     int run(String[] args) {
   317         try {
   318             handleOptions(args);
   319             boolean ok = run();
   320             return ok ? 0 : 1;
   321         } catch (BadArgs e) {
   322             diagnosticListener.report(createDiagnostic(e.key, e.args));
   323             return 1;
   324         } catch (InternalError e) {
   325             diagnosticListener.report(createDiagnostic("err.internal.error", e.getMessage()));
   326             return 1;
   327         } finally {
   328             log.flush();
   329         }
   330     }
   332     public void handleOptions(String[] args) throws BadArgs {
   333         handleOptions(Arrays.asList(args), true);
   334     }
   336     private void handleOptions(Iterable<String> args, boolean allowClasses) throws BadArgs {
   337         if (log == null) {
   338             log = getPrintWriterForStream(System.out);
   339             if (diagnosticListener == null)
   340               diagnosticListener = getDiagnosticListenerForStream(System.err);
   341         } else {
   342             if (diagnosticListener == null)
   343               diagnosticListener = getDiagnosticListenerForWriter(log);
   344         }
   346         if (fileManager == null)
   347             fileManager = getDefaultFileManager(diagnosticListener, log);
   349         Iterator<String> iter = args.iterator();
   350         if (!iter.hasNext())
   351             help = true;
   353         while (iter.hasNext()) {
   354             String arg = iter.next();
   355             if (arg.startsWith("-"))
   356                 handleOption(arg, iter);
   357             else if (allowClasses) {
   358                 if (classes == null)
   359                     classes = new ArrayList<String>();
   360                 classes.add(arg);
   361                 while (iter.hasNext())
   362                     classes.add(iter.next());
   363             } else
   364                 throw new BadArgs("err.unknown.option", arg).showUsage(true);
   365         }
   367         if ((classes == null || classes.size() == 0) &&
   368                 !(help || version || fullVersion)) {
   369             throw new BadArgs("err.no.classes.specified");
   370         }
   372         if (jni && llni)
   373             throw new BadArgs("jni.llni.mixed");
   375         if (odir != null && ofile != null)
   376             throw new BadArgs("dir.file.mixed");
   377     }
   379     private void handleOption(String name, Iterator<String> rest) throws BadArgs {
   380         for (Option o: recognizedOptions) {
   381             if (o.matches(name)) {
   382                 if (o.hasArg) {
   383                     if (rest.hasNext())
   384                         o.process(this, name, rest.next());
   385                     else
   386                         throw new BadArgs("err.missing.arg", name).showUsage(true);
   387                 } else
   388                     o.process(this, name, null);
   390                 if (o.ignoreRest()) {
   391                     while (rest.hasNext())
   392                         rest.next();
   393                 }
   394                 return;
   395             }
   396         }
   398         if (fileManager.handleOption(name, rest))
   399             return;
   401         throw new BadArgs("err.unknown.option", name).showUsage(true);
   402     }
   404     public Boolean call() {
   405         return run();
   406     }
   408     public boolean run() throws Util.Exit {
   410         Util util = new Util(log, diagnosticListener);
   412         if (help) {
   413             showHelp();
   414             return true;
   415         }
   417         if (version || fullVersion) {
   418             showVersion(fullVersion);
   419             return true;
   420         }
   422         util.verbose = verbose;
   424         Gen g;
   426         if (llni)
   427             g = new LLNI(doubleAlign, util);
   428         else {
   429 //            if (stubs)
   430 //                throw new BadArgs("jni.no.stubs");
   431             g = new JNI(util);
   432         }
   434         if (ofile != null) {
   435             if (!(fileManager instanceof StandardJavaFileManager)) {
   436                 diagnosticListener.report(createDiagnostic("err.cant.use.option.for.fm", "-o"));
   437                 return false;
   438             }
   439             Iterable<? extends JavaFileObject> iter =
   440                     ((StandardJavaFileManager) fileManager).getJavaFileObjectsFromFiles(Collections.singleton(ofile));
   441             JavaFileObject fo = iter.iterator().next();
   442             g.setOutFile(fo);
   443         } else {
   444             if (odir != null) {
   445                 if (!(fileManager instanceof StandardJavaFileManager)) {
   446                     diagnosticListener.report(createDiagnostic("err.cant.use.option.for.fm", "-d"));
   447                     return false;
   448                 }
   450                 if (!odir.exists())
   451                     if (!odir.mkdirs())
   452                         util.error("cant.create.dir", odir.toString());
   453                 try {
   454                     ((StandardJavaFileManager) fileManager).setLocation(StandardLocation.CLASS_OUTPUT, Collections.singleton(odir));
   455                 } catch (IOException e) {
   456                     Object msg = e.getLocalizedMessage();
   457                     if (msg == null) {
   458                         msg = e;
   459                     }
   460                     diagnosticListener.report(createDiagnostic("err.ioerror", odir, msg));
   461                     return false;
   462                 }
   463             }
   464             g.setFileManager(fileManager);
   465         }
   467         /*
   468          * Force set to false will turn off smarts about checking file
   469          * content before writing.
   470          */
   471         g.setForce(force);
   473         if (fileManager instanceof JavahFileManager)
   474             ((JavahFileManager) fileManager).setIgnoreSymbolFile(true);
   476         JavaCompiler c = ToolProvider.getSystemJavaCompiler();
   477         List<String> opts = Arrays.asList("-proc:only");
   478         CompilationTask t = c.getTask(log, fileManager, diagnosticListener, opts, internalize(classes), null);
   479         JavahProcessor p = new JavahProcessor(g);
   480         t.setProcessors(Collections.singleton(p));
   482         boolean ok = t.call();
   483         if (p.exit != null)
   484             throw new Util.Exit(p.exit);
   485         return ok;
   486     }
   488     private List<String> internalize(List<String> classes) {
   489         List<String> l = new ArrayList<String>();
   490         for (String c: classes) {
   491             l.add(c.replace('$', '.'));
   492         }
   493         return l;
   494     }
   496     private List<File> pathToFiles(String path) {
   497         List<File> files = new ArrayList<File>();
   498         for (String f: path.split(File.pathSeparator)) {
   499             if (f.length() > 0)
   500                 files.add(new File(f));
   501         }
   502         return files;
   503     }
   505     static StandardJavaFileManager getDefaultFileManager(final DiagnosticListener<? super JavaFileObject> dl, PrintWriter log) {
   506         return JavahFileManager.create(dl, log);
   507     }
   509     private void showHelp() {
   510         log.println(getMessage("main.usage", progname));
   511         for (Option o: recognizedOptions) {
   512             if (o.isHidden())
   513                 continue;
   514             String name = o.aliases[0].substring(1); // there must always be at least one name
   515             log.println(getMessage("main.opt." + name));
   516         }
   517         String[] fmOptions = { "-classpath", "-bootclasspath" };
   518         for (String o: fmOptions) {
   519             if (fileManager.isSupportedOption(o) == -1)
   520                 continue;
   521             String name = o.substring(1);
   522             log.println(getMessage("main.opt." + name));
   523         }
   524         log.println(getMessage("main.usage.foot"));
   525     }
   527     private void showVersion(boolean full) {
   528         log.println(version(full ? "full" : "release"));
   529     }
   531     private static final String versionRBName = "com.sun.tools.javah.resources.version";
   532     private static ResourceBundle versionRB;
   534     private String version(String key) {
   535         // key=version:  mm.nn.oo[-milestone]
   536         // key=full:     mm.mm.oo[-milestone]-build
   537         if (versionRB == null) {
   538             try {
   539                 versionRB = ResourceBundle.getBundle(versionRBName);
   540             } catch (MissingResourceException e) {
   541                 return getMessage("version.resource.missing", System.getProperty("java.version"));
   542             }
   543         }
   544         try {
   545             return versionRB.getString(key);
   546         }
   547         catch (MissingResourceException e) {
   548             return getMessage("version.unknown", System.getProperty("java.version"));
   549         }
   550     }
   552     private Diagnostic<JavaFileObject> createDiagnostic(final String key, final Object... args) {
   553         return new Diagnostic<JavaFileObject>() {
   554             public Kind getKind() {
   555                 return Diagnostic.Kind.ERROR;
   556             }
   558             public JavaFileObject getSource() {
   559                 return null;
   560             }
   562             public long getPosition() {
   563                 return Diagnostic.NOPOS;
   564             }
   566             public long getStartPosition() {
   567                 return Diagnostic.NOPOS;
   568             }
   570             public long getEndPosition() {
   571                 return Diagnostic.NOPOS;
   572             }
   574             public long getLineNumber() {
   575                 return Diagnostic.NOPOS;
   576             }
   578             public long getColumnNumber() {
   579                 return Diagnostic.NOPOS;
   580             }
   582             public String getCode() {
   583                 return key;
   584             }
   586             public String getMessage(Locale locale) {
   587                 return JavahTask.this.getMessage(locale, key, args);
   588             }
   590         };
   592     }
   593     private String getMessage(String key, Object... args) {
   594         return getMessage(task_locale, key, args);
   595     }
   597     private String getMessage(Locale locale, String key, Object... args) {
   598         if (bundles == null) {
   599             // could make this a HashMap<Locale,SoftReference<ResourceBundle>>
   600             // and for efficiency, keep a hard reference to the bundle for the task
   601             // locale
   602             bundles = new HashMap<Locale, ResourceBundle>();
   603         }
   605         if (locale == null)
   606             locale = Locale.getDefault();
   608         ResourceBundle b = bundles.get(locale);
   609         if (b == null) {
   610             try {
   611                 b = ResourceBundle.getBundle("com.sun.tools.javah.resources.l10n", locale);
   612                 bundles.put(locale, b);
   613             } catch (MissingResourceException e) {
   614                 throw new InternalError("Cannot find javah resource bundle for locale " + locale, e);
   615             }
   616         }
   618         try {
   619             return MessageFormat.format(b.getString(key), args);
   620         } catch (MissingResourceException e) {
   621             return key;
   622             //throw new InternalError(e, key);
   623         }
   624     }
   626     File ofile;
   627     File odir;
   628     String bootcp;
   629     String usercp;
   630     List<String> classes;
   631     boolean verbose;
   632     boolean help;
   633     boolean trace;
   634     boolean version;
   635     boolean fullVersion;
   636     boolean jni;
   637     boolean llni;
   638     boolean doubleAlign;
   639     boolean force;
   640     boolean old;
   642     PrintWriter log;
   643     JavaFileManager fileManager;
   644     DiagnosticListener<? super JavaFileObject> diagnosticListener;
   645     Locale task_locale;
   646     Map<Locale, ResourceBundle> bundles;
   648     private static final String progname = "javah";
   650     @SupportedAnnotationTypes("*")
   651     @SupportedSourceVersion(SourceVersion.RELEASE_7)
   652     class JavahProcessor extends AbstractProcessor {
   653         JavahProcessor(Gen g) {
   654             this.g = g;
   655         }
   657         public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
   658             Messager messager  = processingEnv.getMessager();
   659             Set<TypeElement> classes = getAllClasses(ElementFilter.typesIn(roundEnv.getRootElements()));
   660             if (classes.size() > 0) {
   661                 checkMethodParameters(classes);
   662                 g.setProcessingEnvironment(processingEnv);
   663                 g.setClasses(classes);
   665                 try {
   666                     g.run();
   667                 } catch (ClassNotFoundException cnfe) {
   668                     messager.printMessage(Diagnostic.Kind.ERROR, getMessage("class.not.found", cnfe.getMessage()));
   669                 } catch (IOException ioe) {
   670                     messager.printMessage(Diagnostic.Kind.ERROR, getMessage("io.exception", ioe.getMessage()));
   671                 } catch (Util.Exit e) {
   672                     exit = e;
   673                 }
   674             }
   675             return true;
   676         }
   678         private Set<TypeElement> getAllClasses(Set<? extends TypeElement> classes) {
   679             Set<TypeElement> allClasses = new LinkedHashSet<TypeElement>();
   680             getAllClasses0(classes, allClasses);
   681             return allClasses;
   682         }
   684         private void getAllClasses0(Iterable<? extends TypeElement> classes, Set<TypeElement> allClasses) {
   685             for (TypeElement c: classes) {
   686                 allClasses.add(c);
   687                 getAllClasses0(ElementFilter.typesIn(c.getEnclosedElements()), allClasses);
   688             }
   689         }
   691         // 4942232:
   692         // check that classes exist for all the parameters of native methods
   693         private void checkMethodParameters(Set<TypeElement> classes) {
   694             Types types = processingEnv.getTypeUtils();
   695             for (TypeElement te: classes) {
   696                 for (ExecutableElement ee: ElementFilter.methodsIn(te.getEnclosedElements())) {
   697                     for (VariableElement ve: ee.getParameters()) {
   698                         TypeMirror tm = ve.asType();
   699                         checkMethodParametersVisitor.visit(tm, types);
   700                     }
   701                 }
   702             }
   703         }
   705         private TypeVisitor<Void,Types> checkMethodParametersVisitor =
   706                 new SimpleTypeVisitor6<Void,Types>() {
   707             @Override
   708             public Void visitArray(ArrayType t, Types types) {
   709                 visit(t.getComponentType(), types);
   710                 return null;
   711             }
   712             @Override
   713             public Void visitDeclared(DeclaredType t, Types types) {
   714                 t.asElement().getKind(); // ensure class exists
   715                 for (TypeMirror st: types.directSupertypes(t))
   716                     visit(st, types);
   717                 return null;
   718             }
   719         };
   721         private Gen g;
   722         private Util.Exit exit;
   723     }
   724 }

mercurial