1303 lines · 48.0 KB · Java
RawDownload
/* * Copyright (c) 1997, 2007, 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. */ /*****************************************************************************//*                    Copyright (c) IBM Corporation 1998                     *//*                                                                           *//* (C) Copyright IBM Corp. 1998                                              *//*                                                                           *//*****************************************************************************/ package sun.rmi.rmic; import java.io.File;import java.io.FileOutputStream;import java.io.OutputStreamWriter;import java.io.IOException;import java.util.Enumeration;import java.util.Hashtable;import java.util.Vector;import sun.tools.java.Type;import sun.tools.java.Identifier;import sun.tools.java.ClassDefinition;import sun.tools.java.ClassDeclaration;import sun.tools.java.ClassNotFound;import sun.tools.java.ClassFile;import sun.tools.java.MemberDefinition;import com.sun.corba.se.impl.util.Utility; /** * A Generator object will generate the Java source code of the stub * and skeleton classes for an RMI remote implementation class, using * a particular stub protocol version. * * 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. * * @author      Peter Jones,  Bryan Atsatt */public class RMIGenerator implements RMIConstants, Generator {     private static final Hashtable versionOptions = new Hashtable();    static {        versionOptions.put("-v1.1", new Integer(STUB_VERSION_1_1));        versionOptions.put("-vcompat", new Integer(STUB_VERSION_FAT));        versionOptions.put("-v1.2", new Integer(STUB_VERSION_1_2));    }     /**     * Default constructor for Main to use.     */    public RMIGenerator() {        version = STUB_VERSION_1_2;     // default is -v1.2 (see 4638155)    }     /**     * Examine and consume command line arguments.     * @param argv The command line arguments. Ignore null     * and unknown arguments. Set each consumed argument to null.     * @param error Report any errors using the main.error() methods.     * @return true if no errors, false otherwise.     */    public boolean parseArgs(String argv[], Main main) {        String explicitVersion = null;        for (int i = 0; i < argv.length; i++) {            if (argv[i] != null) {                String arg = argv[i].toLowerCase();                if (versionOptions.containsKey(arg)) {                    if (explicitVersion != null &&                        !explicitVersion.equals(arg))                    {                        main.error("rmic.cannot.use.both",                                   explicitVersion, arg);                        return false;                    }                    explicitVersion = arg;                    version = ((Integer) versionOptions.get(arg)).intValue();                    argv[i] = null;                }            }        }        return true;    }     /**     * Generate the source files for the stub and/or skeleton classes     * needed by RMI for the given remote implementation class.     *     * @param env       compiler environment     * @param cdef      definition of remote implementation class     *                  to generate stubs and/or skeletons for     * @param destDir   directory for the root of the package hierarchy     *                  for generated files     */    public void generate(BatchEnvironment env, ClassDefinition cdef, File destDir) {        RemoteClass remoteClass = RemoteClass.forClass(env, cdef);        if (remoteClass == null)        // exit if an error occurred            return;         RMIGenerator gen;        try {            gen = new RMIGenerator(env, cdef, destDir, remoteClass, version);        } catch (ClassNotFound e) {            env.error(0, "rmic.class.not.found", e.name);            return;        }        gen.generate();    }     private void generate() {        env.addGeneratedFile(stubFile);         try {            IndentingWriter out = new IndentingWriter(                new OutputStreamWriter(new FileOutputStream(stubFile)));            writeStub(out);            out.close();            if (env.verbose()) {                env.output(Main.getText("rmic.wrote", stubFile.getPath()));            }            env.parseFile(new ClassFile(stubFile));        } catch (IOException e) {            env.error(0, "cant.write", stubFile.toString());            return;        }         if (version == STUB_VERSION_1_1 ||            version == STUB_VERSION_FAT)        {            env.addGeneratedFile(skeletonFile);             try {                IndentingWriter out = new IndentingWriter(                    new OutputStreamWriter(                        new FileOutputStream(skeletonFile)));                writeSkeleton(out);                out.close();                if (env.verbose()) {                    env.output(Main.getText("rmic.wrote",                        skeletonFile.getPath()));                }                env.parseFile(new ClassFile(skeletonFile));            } catch (IOException e) {                env.error(0, "cant.write", stubFile.toString());                return;            }        } else {            /*             * For bugid 4135136: if skeleton files are not being generated             * for this compilation run, delete old skeleton source or class             * files for this remote implementation class that were             * (presumably) left over from previous runs, to avoid user             * confusion from extraneous or inconsistent generated files.             */             File outputDir = Util.getOutputDirectoryFor(remoteClassName,destDir,env);            File skeletonClassFile = new File(outputDir,skeletonClassName.getName().toString() + ".class");             skeletonFile.delete();      // ignore failures (no big deal)            skeletonClassFile.delete();        }    }     /**     * Return the File object that should be used as the source file     * for the given Java class, using the supplied destination     * directory for the top of the package hierarchy.     */    protected static File sourceFileForClass(Identifier className,                                             Identifier outputClassName,                                             File destDir,                                             BatchEnvironment env)    {        File packageDir = Util.getOutputDirectoryFor(className,destDir,env);        String outputName = Names.mangleClass(outputClassName).getName().toString();         // Is there any existing _Tie equivalent leftover from a        // previous invocation of rmic -iiop? Only do this once per        // class by looking for skeleton generation...         if (outputName.endsWith("_Skel")) {            String classNameStr = className.getName().toString();            File temp = new File(packageDir, Utility.tieName(classNameStr) + ".class");            if (temp.exists()) {                 // Found a tie. Is IIOP generation also being done?                 if (!env.getMain().iiopGeneration) {                     // No, so write a warning...                     env.error(0,"warn.rmic.tie.found",                              classNameStr,                              temp.getAbsolutePath());                }            }        }         String outputFileName = outputName + ".java";        return new File(packageDir, outputFileName);    }      /** rmic environment for this object */    private BatchEnvironment env;     /** the remote class that this instance is generating code for */    private RemoteClass remoteClass;     /** version of the stub protocol to use in code generation */    private int version;     /** remote methods for remote class, indexed by operation number */    private RemoteClass.Method[] remoteMethods;     /**     * Names for the remote class and the stub and skeleton classes     * to be generated for it.     */    private Identifier remoteClassName;    private Identifier stubClassName;    private Identifier skeletonClassName;     private ClassDefinition cdef;    private File destDir;    private File stubFile;    private File skeletonFile;     /**     * Names to use for the java.lang.reflect.Method static fields     * corresponding to each remote method.     */    private String[] methodFieldNames;     /** cached definition for certain exception classes in this environment */    private ClassDefinition defException;    private ClassDefinition defRemoteException;    private ClassDefinition defRuntimeException;     /**     * Create a new stub/skeleton Generator object for the given     * remote implementation class to generate code according to     * the given stub protocol version.     */    private RMIGenerator(BatchEnvironment env, ClassDefinition cdef,                           File destDir, RemoteClass remoteClass, int version)        throws ClassNotFound    {        this.destDir     = destDir;        this.cdef        = cdef;        this.env         = env;        this.remoteClass = remoteClass;        this.version     = version;         remoteMethods = remoteClass.getRemoteMethods();         remoteClassName = remoteClass.getName();        stubClassName = Names.stubFor(remoteClassName);        skeletonClassName = Names.skeletonFor(remoteClassName);         methodFieldNames = nameMethodFields(remoteMethods);         stubFile = sourceFileForClass(remoteClassName,stubClassName, destDir , env);        skeletonFile = sourceFileForClass(remoteClassName,skeletonClassName, destDir, env);         /*         * Initialize cached definitions for exception classes used         * in the generation process.         */        defException =            env.getClassDeclaration(idJavaLangException).                getClassDefinition(env);        defRemoteException =            env.getClassDeclaration(idRemoteException).                getClassDefinition(env);        defRuntimeException =            env.getClassDeclaration(idJavaLangRuntimeException).                getClassDefinition(env);    }     /**     * Write the stub for the remote class to a stream.     */    private void writeStub(IndentingWriter p) throws IOException {         /*         * Write boiler plate comment.         */        p.pln("// Stub class generated by rmic, do not edit.");        p.pln("// Contents subject to change without notice.");        p.pln();         /*         * If remote implementation class was in a particular package,         * declare the stub class to be in the same package.         */        if (remoteClassName.isQualified()) {            p.pln("package " + remoteClassName.getQualifier() + ";");            p.pln();        }         /*         * Declare the stub class; implement all remote interfaces.         */        p.plnI("public final class " +            Names.mangleClass(stubClassName.getName()));        p.pln("extends " + idRemoteStub);        ClassDefinition[] remoteInterfaces = remoteClass.getRemoteInterfaces();        if (remoteInterfaces.length > 0) {            p.p("implements ");            for (int i = 0; i < remoteInterfaces.length; i++) {                if (i > 0)                    p.p(", ");                p.p(remoteInterfaces[i].getName().toString());            }            p.pln();        }        p.pOlnI("{");         if (version == STUB_VERSION_1_1 ||            version == STUB_VERSION_FAT)        {            writeOperationsArray(p);            p.pln();            writeInterfaceHash(p);            p.pln();        }         if (version == STUB_VERSION_FAT ||            version == STUB_VERSION_1_2)        {            p.pln("private static final long serialVersionUID = " +                STUB_SERIAL_VERSION_UID + ";");            p.pln();             /*             * We only need to declare and initialize the static fields of             * Method objects for each remote method if there are any remote             * methods; otherwise, skip this code entirely, to avoid generating             * a try/catch block for a checked exception that cannot occur             * (see bugid 4125181).             */            if (methodFieldNames.length > 0) {                if (version == STUB_VERSION_FAT) {                    p.pln("private static boolean useNewInvoke;");                }                writeMethodFieldDeclarations(p);                p.pln();                 /*                 * Initialize java.lang.reflect.Method fields for each remote                 * method in a static initializer.                 */                p.plnI("static {");                p.plnI("try {");                if (version == STUB_VERSION_FAT) {                    /*                     * Fat stubs must determine whether the API required for                     * the JDK 1.2 stub protocol is supported in the current                     * runtime, so that it can use it if supported.  This is                     * determined by using the Reflection API to test if the                     * new invoke method on RemoteRef exists, and setting the                     * static boolean "useNewInvoke" to true if it does, or                     * to false if a NoSuchMethodException is thrown.                     */                    p.plnI(idRemoteRef + ".class.getMethod(\"invoke\",");                    p.plnI("new java.lang.Class[] {");                    p.pln(idRemote + ".class,");                    p.pln("java.lang.reflect.Method.class,");                    p.pln("java.lang.Object[].class,");                    p.pln("long.class");                    p.pOln("});");                    p.pO();                    p.pln("useNewInvoke = true;");                }                writeMethodFieldInitializers(p);                p.pOlnI("} catch (java.lang.NoSuchMethodException e) {");                if (version == STUB_VERSION_FAT) {                    p.pln("useNewInvoke = false;");                } else {                    /*                     * REMIND: By throwing an Error here, the application will                     * get the NoSuchMethodError directly when the stub class                     * is initialized.  If we throw a RuntimeException                     * instead, the application would get an                     * ExceptionInInitializerError.  Would that be more                     * appropriate, and if so, which RuntimeException should                     * be thrown?                     */                    p.plnI("throw new java.lang.NoSuchMethodError(");                    p.pln("\"stub class initialization failed\");");                    p.pO();                }                p.pOln("}");            // end try/catch block                p.pOln("}");            // end static initializer                p.pln();            }        }         writeStubConstructors(p);        p.pln();         /*         * Write each stub method.         */        if (remoteMethods.length > 0) {            p.pln("// methods from remote interfaces");            for (int i = 0; i < remoteMethods.length; ++i) {                p.pln();                writeStubMethod(p, i);            }        }         p.pOln("}");                    // end stub class    }     /**     * Write the constructors for the stub class.     */    private void writeStubConstructors(IndentingWriter p)        throws IOException    {        p.pln("// constructors");         /*         * Only stubs compatible with the JDK 1.1 stub protocol need         * a no-arg constructor; later versions use reflection to find         * the constructor that directly takes a RemoteRef argument.         */        if (version == STUB_VERSION_1_1 ||            version == STUB_VERSION_FAT)        {            p.plnI("public " + Names.mangleClass(stubClassName.getName()) +                "() {");            p.pln("super();");            p.pOln("}");        }         p.plnI("public " + Names.mangleClass(stubClassName.getName()) +            "(" + idRemoteRef + " ref) {");        p.pln("super(ref);");        p.pOln("}");    }     /**     * Write the stub method for the remote method with the given "opnum".     */    private void writeStubMethod(IndentingWriter p, int opnum)        throws IOException    {        RemoteClass.Method method = remoteMethods[opnum];        Identifier methodName = method.getName();        Type methodType = method.getType();        Type paramTypes[] = methodType.getArgumentTypes();        String paramNames[] = nameParameters(paramTypes);        Type returnType = methodType.getReturnType();        ClassDeclaration[] exceptions = method.getExceptions();         /*         * Declare stub method; throw exceptions declared in remote         * interface(s).         */        p.pln("// implementation of " +            methodType.typeString(methodName.toString(), true, false));        p.p("public " + returnType + " " + methodName + "(");        for (int i = 0; i < paramTypes.length; i++) {            if (i > 0)                p.p(", ");            p.p(paramTypes[i] + " " + paramNames[i]);        }        p.plnI(")");        if (exceptions.length > 0) {            p.p("throws ");            for (int i = 0; i < exceptions.length; i++) {                if (i > 0)                    p.p(", ");                p.p(exceptions[i].getName().toString());            }

Lines 1–500 of 1303.