689 lines · 23.7 KB · Java
RawDownload
/* * Copyright (c) 2003, 2005, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation.  Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package sun.rmi.rmic.newrmic; import com.sun.javadoc.ClassDoc;import com.sun.javadoc.RootDoc;import java.io.File;import java.io.FileNotFoundException;import java.io.IOException;import java.io.OutputStream;import java.io.PrintStream;import java.io.PrintWriter;import java.lang.reflect.Constructor;import java.lang.reflect.InvocationTargetException;import java.util.ArrayList;import java.util.Collections;import java.util.HashMap;import java.util.HashSet;import java.util.List;import java.util.Map;import java.util.Set;import sun.rmi.rmic.newrmic.jrmp.JrmpGenerator;import sun.tools.util.CommandLine; /** * The rmic front end.  This class contains the "main" method for rmic * command line invocation. * * A Main instance contains the stream to output error messages and * other diagnostics to. * * An rmic compilation batch (for example, one rmic command line * invocation) is executed by invoking the "compile" method of a Main * instance. * * WARNING: The contents of this source file are not part of any * supported API.  Code that depends on them does so at its own risk: * they are subject to change or removal without notice. * * NOTE: If and when there is a J2SE API for invoking SDK tools, this * class should be updated to support that API. * * NOTE: This class is the front end for a "new" rmic implementation, * which uses javadoc and the doclet API for reading class files and * javac for compiling generated source files.  This implementation is * incomplete: it lacks any CORBA-based back end implementations, and * thus the command line options "-idl", "-iiop", and their related * options are not yet supported.  The front end for the "old", * oldjavac-based rmic implementation is sun.rmi.rmic.Main. * * @author Peter Jones **/public class Main {     /*     * Implementation note:     *     * In order to use the doclet API to read class files, much of     * this implementation of rmic executes as a doclet within an     * invocation of javadoc.  This class is used as the doclet class     * for such javadoc invocations, via its static "start" and     * "optionLength" methods.  There is one javadoc invocation per     * rmic compilation batch.     *     * The only guaranteed way to pass data to a doclet through a     * javadoc invocation is through doclet-specific options on the     * javadoc "command line".  Rather than passing numerous pieces of     * individual data in string form as javadoc options, we use a     * single doclet-specific option ("-batchID") to pass a numeric     * identifier that uniquely identifies the rmic compilation batch     * that the javadoc invocation is for, and that identifier can     * then be used as a key in a global table to retrieve an object     * containing all of batch-specific data (rmic command line     * arguments, etc.).     */     /** guards "batchCount" */    private static final Object batchCountLock = new Object();     /** number of batches run; used to generated batch IDs */    private static long batchCount = 0;     /** maps batch ID to batch data */    private static final Map<Long,Batch> batchTable =        Collections.synchronizedMap(new HashMap<Long,Batch>());     /** stream to output error messages and other diagnostics to */    private final PrintStream out;     /** name of this program, to use in error messages */    private final String program;     /**     * Command line entry point.     **/    public static void main(String[] args) {        Main rmic = new Main(System.err, "rmic");        System.exit(rmic.compile(args) ? 0 : 1);    }     /**     * Creates a Main instance that writes output to the specified     * stream.  The specified program name is used in error messages.     **/    public Main(OutputStream out, String program) {        this.out = out instanceof PrintStream ?            (PrintStream) out : new PrintStream(out);        this.program = program;    }     /**     * Compiles a batch of input classes, as given by the specified     * command line arguments.  Protocol-specific generators are     * determined by the choice options on the command line.  Returns     * true if successful, or false if an error occurred.     *     * NOTE: This method is retained for transitional consistency with     * previous implementations.     **/    public boolean compile(String[] args) {        long startTime = System.currentTimeMillis();         long batchID;        synchronized (batchCountLock) {            batchID = batchCount++;     // assign batch ID        }         // process command line        Batch batch = parseArgs(args);        if (batch == null) {            return false;               // terminate if error occurred        }         /*         * With the batch data retrievable in the global table, run         * javadoc to continue the rest of the batch's compliation as         * a doclet.         */        boolean status;        try {            batchTable.put(batchID, batch);            status = invokeJavadoc(batch, batchID);        } finally {            batchTable.remove(batchID);        }         if (batch.verbose) {            long deltaTime = System.currentTimeMillis() - startTime;            output(Resources.getText("rmic.done_in",                                     Long.toString(deltaTime)));        }         return status;    }     /**     * Prints the specified string to the output stream of this Main     * instance.     **/    public void output(String msg) {        out.println(msg);    }     /**     * Prints an error message to the output stream of this Main     * instance.  The first argument is used as a key in rmic's     * resource bundle, and the rest of the arguments are used as     * arguments in the formatting of the resource string.     **/    public void error(String msg, String... args) {        output(Resources.getText(msg, args));    }     /**     * Prints rmic's usage message to the output stream of this Main     * instance.     *     * This method is public so that it can be used by the "parseArgs"     * methods of Generator implementations.     **/    public void usage() {        error("rmic.usage", program);    }     /**     * Processes rmic command line arguments.  Returns a Batch object     * representing the command line arguments if successful, or null     * if an error occurred.  Processed elements of the args array are     * set to null.     **/    private Batch parseArgs(String[] args) {        Batch batch = new Batch();         /*         * Pre-process command line for @file arguments.         */        try {            args = CommandLine.parse(args);        } catch (FileNotFoundException e) {            error("rmic.cant.read", e.getMessage());            return null;        } catch (IOException e) {            e.printStackTrace(out);            return null;        }         for (int i = 0; i < args.length; i++) {             if (args[i] == null) {                // already processed by a generator                continue;             } else if (args[i].equals("-Xnew")) {                // we're already using the "new" implementation                args[i] = null;             } else if (args[i].equals("-show")) {                // obselete: fail                error("rmic.option.unsupported", args[i]);                usage();                return null;             } else if (args[i].equals("-O")) {                // obselete: warn but tolerate                error("rmic.option.unsupported", args[i]);                args[i] = null;             } else if (args[i].equals("-debug")) {                // obselete: warn but tolerate                error("rmic.option.unsupported", args[i]);                args[i] = null;             } else if (args[i].equals("-depend")) {                // obselete: warn but tolerate                // REMIND: should this fail instead?                error("rmic.option.unsupported", args[i]);                args[i] = null;             } else if (args[i].equals("-keep") ||                       args[i].equals("-keepgenerated"))            {                batch.keepGenerated = true;                args[i] = null;             } else if (args[i].equals("-g")) {                batch.debug = true;                args[i] = null;             } else if (args[i].equals("-nowarn")) {                batch.noWarn = true;                args[i] = null;             } else if (args[i].equals("-nowrite")) {                batch.noWrite = true;                args[i] = null;             } else if (args[i].equals("-verbose")) {                batch.verbose = true;                args[i] = null;             } else if (args[i].equals("-Xnocompile")) {                batch.noCompile = true;                batch.keepGenerated = true;                args[i] = null;             } else if (args[i].equals("-bootclasspath")) {                if ((i + 1) >= args.length) {                    error("rmic.option.requires.argument", args[i]);                    usage();                    return null;                }                if (batch.bootClassPath != null) {                    error("rmic.option.already.seen", args[i]);                    usage();                    return null;                }                args[i] = null;                batch.bootClassPath = args[++i];                assert batch.bootClassPath != null;                args[i] = null;             } else if (args[i].equals("-extdirs")) {                if ((i + 1) >= args.length) {                    error("rmic.option.requires.argument", args[i]);                    usage();                    return null;                }                if (batch.extDirs != null) {                    error("rmic.option.already.seen", args[i]);                    usage();                    return null;                }                args[i] = null;                batch.extDirs = args[++i];                assert batch.extDirs != null;                args[i] = null;             } else if (args[i].equals("-classpath")) {                if ((i + 1) >= args.length) {                    error("rmic.option.requires.argument", args[i]);                    usage();                    return null;                }                if (batch.classPath != null) {                    error("rmic.option.already.seen", args[i]);                    usage();                    return null;                }                args[i] = null;                batch.classPath = args[++i];                assert batch.classPath != null;                args[i] = null;             } else if (args[i].equals("-d")) {                if ((i + 1) >= args.length) {                    error("rmic.option.requires.argument", args[i]);                    usage();                    return null;                }                if (batch.destDir != null) {                    error("rmic.option.already.seen", args[i]);                    usage();                    return null;                }                args[i] = null;                batch.destDir = new File(args[++i]);                assert batch.destDir != null;                args[i] = null;                if (!batch.destDir.exists()) {                    error("rmic.no.such.directory", batch.destDir.getPath());                    usage();                    return null;                }             } else if (args[i].equals("-v1.1") ||                       args[i].equals("-vcompat") ||                       args[i].equals("-v1.2"))            {                Generator gen = new JrmpGenerator();                batch.generators.add(gen);                // JrmpGenerator only requires base BatchEnvironment class                if (!gen.parseArgs(args, this)) {                    return null;                }             } else if (args[i].equalsIgnoreCase("-iiop")) {                error("rmic.option.unimplemented", args[i]);                return null;                 // Generator gen = new IiopGenerator();                // batch.generators.add(gen);                // if (!batch.envClass.isAssignableFrom(gen.envClass())) {                //   error("rmic.cannot.use.both",                //         batch.envClass.getName(), gen.envClass().getName());                //   return null;                // }                // batch.envClass = gen.envClass();                // if (!gen.parseArgs(args, this)) {                //   return null;                // }             } else if (args[i].equalsIgnoreCase("-idl")) {                error("rmic.option.unimplemented", args[i]);                return null;                 // see implementation sketch above             } else if (args[i].equalsIgnoreCase("-xprint")) {                error("rmic.option.unimplemented", args[i]);                return null;                 // see implementation sketch above            }        }         /*         * At this point, all that remains non-null in the args         * array are input class names or illegal options.         */        for (int i = 0; i < args.length; i++) {            if (args[i] != null) {                if (args[i].startsWith("-")) {                    error("rmic.no.such.option", args[i]);                    usage();                    return null;                } else {                    batch.classes.add(args[i]);                }            }        }        if (batch.classes.isEmpty()) {            usage();            return null;        }         /*         * If options did not specify at least one protocol-specific         * generator, then JRMP is the default.         */        if (batch.generators.isEmpty()) {            batch.generators.add(new JrmpGenerator());        }        return batch;    }     /**     * Doclet class entry point.     **/    public static boolean start(RootDoc rootDoc) {         /*         * Find batch ID among javadoc options, and retrieve         * corresponding batch data from global table.         */        long batchID = -1;        for (String[] option : rootDoc.options()) {            if (option[0].equals("-batchID")) {                try {                    batchID = Long.parseLong(option[1]);                } catch (NumberFormatException e) {                    throw new AssertionError(e);                }            }        }        Batch batch = batchTable.get(batchID);        assert batch != null;         /*         * Construct batch environment using class agreed upon by         * generator implementations.         */        BatchEnvironment env;        try {            Constructor<? extends BatchEnvironment> cons =                batch.envClass.getConstructor(new Class[] { RootDoc.class });            env = cons.newInstance(rootDoc);        } catch (NoSuchMethodException e) {            throw new AssertionError(e);        } catch (IllegalAccessException e) {            throw new AssertionError(e);        } catch (InstantiationException e) {            throw new AssertionError(e);        } catch (InvocationTargetException e) {            throw new AssertionError(e);        }         env.setVerbose(batch.verbose);         /*         * Determine the destination directory (the top of the package         * hierarchy) for the output of this batch; if no destination         * directory was specified on the command line, then the         * default is the current working directory.         */        File destDir = batch.destDir;        if (destDir == null) {            destDir = new File(System.getProperty("user.dir"));        }         /*         * Run each input class through each generator.         */        for (String inputClassName : batch.classes) {            ClassDoc inputClass = rootDoc.classNamed(inputClassName);            try {                for (Generator gen : batch.generators) {                    gen.generate(env, inputClass, destDir);                }            } catch (NullPointerException e) {                /*                 * We assume that this means that some class that was                 * needed (perhaps even a bootstrap class) was not                 * found, and that javadoc has already reported this                 * as an error.  There is nothing for us to do here                 * but try to continue with the next input class.                 *                 * REMIND: More explicit error checking throughout

Lines 1–500 of 689.