src/jdk.rmic/share/classes/sun/rmi/rmic/newrmic/jrmp/StubSkeletonWriter.java
changeset 47519 b1f360639517
parent 47518 783d04ecccc3
parent 47496 66e2e3f62eb5
child 47701 be620a591379
child 47716 c9181704b389
child 47803 2cd7d700217f
--- a/src/jdk.rmic/share/classes/sun/rmi/rmic/newrmic/jrmp/StubSkeletonWriter.java	Fri Nov 03 09:56:02 2017 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1079 +0,0 @@
-/*
- * Copyright (c) 2003, 2013, 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.jrmp;
-
-import com.sun.javadoc.ClassDoc;
-import com.sun.javadoc.MethodDoc;
-import com.sun.javadoc.Type;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-import sun.rmi.rmic.newrmic.BatchEnvironment;
-import sun.rmi.rmic.newrmic.IndentingWriter;
-
-import static sun.rmi.rmic.newrmic.Constants.*;
-import static sun.rmi.rmic.newrmic.jrmp.Constants.*;
-
-/**
- * Writes the source code for the stub class and (optionally) skeleton
- * class for a particular remote implementation class.
- *
- * 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
- **/
-class StubSkeletonWriter {
-
-    /** rmic environment for this object */
-    private final BatchEnvironment env;
-
-    /** the remote implementation class to generate code for */
-    private final RemoteClass remoteClass;
-
-    /** version of the JRMP stub protocol to generate code for */
-    private final StubVersion version;
-
-    /*
-     * binary names of the stub and skeleton classes to generate for
-     * the remote class
-     */
-    private final String stubClassName;
-    private final String skeletonClassName;
-
-    /* package name and simple names of the stub and skeleton classes */
-    private final String packageName;
-    private final String stubClassSimpleName;
-    private final String skeletonClassSimpleName;
-
-    /** remote methods of class, indexed by operation number */
-    private final RemoteClass.Method[] remoteMethods;
-
-    /**
-     * Names to use for the java.lang.reflect.Method static fields in
-     * the generated stub class corresponding to each remote method.
-     **/
-    private final String[] methodFieldNames;
-
-    /**
-     * Creates a StubSkeletonWriter instance for the specified remote
-     * implementation class.  The generated code will implement the
-     * specified JRMP stub protocol version.
-     **/
-    StubSkeletonWriter(BatchEnvironment env,
-                       RemoteClass remoteClass,
-                       StubVersion version)
-    {
-        this.env = env;
-        this.remoteClass = remoteClass;
-        this.version = version;
-
-        stubClassName = Util.binaryNameOf(remoteClass.classDoc()) + "_Stub";
-        skeletonClassName =
-            Util.binaryNameOf(remoteClass.classDoc()) + "_Skel";
-
-        int i = stubClassName.lastIndexOf('.');
-        packageName = (i != -1 ? stubClassName.substring(0, i) : "");
-        stubClassSimpleName = stubClassName.substring(i + 1);
-        skeletonClassSimpleName = skeletonClassName.substring(i + 1);
-
-        remoteMethods = remoteClass.remoteMethods();
-        methodFieldNames = nameMethodFields(remoteMethods);
-    }
-
-    /**
-     * Returns the binary name of the stub class to generate for the
-     * remote implementation class.
-     **/
-    String stubClassName() {
-        return stubClassName;
-    }
-
-    /**
-     * Returns the binary name of the skeleton class to generate for
-     * the remote implementation class.
-     **/
-    String skeletonClassName() {
-        return skeletonClassName;
-    }
-
-    /**
-     * Writes the stub class for the remote class to a stream.
-     **/
-    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 (!packageName.equals("")) {
-            p.pln("package " + packageName + ";");
-            p.pln();
-        }
-
-        /*
-         * Declare the stub class; implement all remote interfaces.
-         */
-        p.plnI("public final class " + stubClassSimpleName);
-        p.pln("extends " + REMOTE_STUB);
-        ClassDoc[] remoteInterfaces = remoteClass.remoteInterfaces();
-        if (remoteInterfaces.length > 0) {
-            p.p("implements ");
-            for (int i = 0; i < remoteInterfaces.length; i++) {
-                if (i > 0) {
-                    p.p(", ");
-                }
-                p.p(remoteInterfaces[i].qualifiedName());
-            }
-            p.pln();
-        }
-        p.pOlnI("{");
-
-        if (version == StubVersion.V1_1 ||
-            version == StubVersion.VCOMPAT)
-        {
-            writeOperationsArray(p);
-            p.pln();
-            writeInterfaceHash(p);
-            p.pln();
-        }
-
-        if (version == StubVersion.VCOMPAT ||
-            version == StubVersion.V1_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 == StubVersion.VCOMPAT) {
-                    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 == StubVersion.VCOMPAT) {
-                    /*
-                     * 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(REMOTE_REF + ".class.getMethod(\"invoke\",");
-                    p.plnI("new java.lang.Class[] {");
-                    p.pln(REMOTE + ".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 == StubVersion.VCOMPAT) {
-                    p.pln("useNewInvoke = false;");
-                } else {
-                    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
-    }
-
-    /**
-     * Writes 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 == StubVersion.V1_1 ||
-            version == StubVersion.VCOMPAT)
-        {
-            p.plnI("public " + stubClassSimpleName + "() {");
-            p.pln("super();");
-            p.pOln("}");
-        }
-
-        p.plnI("public " + stubClassSimpleName + "(" + REMOTE_REF + " ref) {");
-        p.pln("super(ref);");
-        p.pOln("}");
-    }
-
-    /**
-     * Writes the stub method for the remote method with the given
-     * operation number.
-     **/
-    private void writeStubMethod(IndentingWriter p, int opnum)
-        throws IOException
-    {
-        RemoteClass.Method method = remoteMethods[opnum];
-        MethodDoc methodDoc = method.methodDoc();
-        String methodName = methodDoc.name();
-        Type[] paramTypes = method.parameterTypes();
-        String paramNames[] = nameParameters(paramTypes);
-        Type returnType = methodDoc.returnType();
-        ClassDoc[] exceptions = method.exceptionTypes();
-
-        /*
-         * Declare stub method; throw exceptions declared in remote
-         * interface(s).
-         */
-        p.pln("// implementation of " +
-              Util.getFriendlyUnqualifiedSignature(methodDoc));
-        p.p("public " + returnType.toString() + " " + methodName + "(");
-        for (int i = 0; i < paramTypes.length; i++) {
-            if (i > 0) {
-                p.p(", ");
-            }
-            p.p(paramTypes[i].toString() + " " + 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].qualifiedName());
-            }
-            p.pln();
-        }
-        p.pOlnI("{");
-
-        /*
-         * The RemoteRef.invoke methods throw Exception, but unless
-         * this stub method throws Exception as well, we must catch
-         * Exceptions thrown from the invocation.  So we must catch
-         * Exception and rethrow something we can throw:
-         * UnexpectedException, which is a subclass of
-         * RemoteException.  But for any subclasses of Exception that
-         * we can throw, like RemoteException, RuntimeException, and
-         * any of the exceptions declared by this stub method, we want
-         * them to pass through unmodified, so first we must catch any
-         * such exceptions and rethrow them directly.
-         *
-         * We have to be careful generating the rethrowing catch
-         * blocks here, because javac will flag an error if there are
-         * any unreachable catch blocks, i.e. if the catch of an
-         * exception class follows a previous catch of it or of one of
-         * its superclasses.  The following method invocation takes
-         * care of these details.
-         */
-        List<ClassDoc> catchList = computeUniqueCatchList(exceptions);
-
-        /*
-         * If we need to catch any particular exceptions (i.e. this method
-         * does not declare java.lang.Exception), put the entire stub
-         * method in a try block.
-         */
-        if (catchList.size() > 0) {
-            p.plnI("try {");
-        }
-
-        if (version == StubVersion.VCOMPAT) {
-            p.plnI("if (useNewInvoke) {");
-        }
-        if (version == StubVersion.VCOMPAT ||
-            version == StubVersion.V1_2)
-        {
-            if (!Util.isVoid(returnType)) {
-                p.p("Object $result = ");               // REMIND: why $?
-            }
-            p.p("ref.invoke(this, " + methodFieldNames[opnum] + ", ");
-            if (paramTypes.length > 0) {
-                p.p("new java.lang.Object[] {");
-                for (int i = 0; i < paramTypes.length; i++) {
-                    if (i > 0)
-                        p.p(", ");
-                    p.p(wrapArgumentCode(paramTypes[i], paramNames[i]));
-                }
-                p.p("}");
-            } else {
-                p.p("null");
-            }
-            p.pln(", " + method.methodHash() + "L);");
-            if (!Util.isVoid(returnType)) {
-                p.pln("return " +
-                    unwrapArgumentCode(returnType, "$result") + ";");
-            }
-        }
-        if (version == StubVersion.VCOMPAT) {
-            p.pOlnI("} else {");
-        }
-        if (version == StubVersion.V1_1 ||
-            version == StubVersion.VCOMPAT)
-        {
-            p.pln(REMOTE_CALL + " call = ref.newCall((" + REMOTE_OBJECT +
-                ") this, operations, " + opnum + ", interfaceHash);");
-
-            if (paramTypes.length > 0) {
-                p.plnI("try {");
-                p.pln("java.io.ObjectOutput out = call.getOutputStream();");
-                writeMarshalArguments(p, "out", paramTypes, paramNames);
-                p.pOlnI("} catch (java.io.IOException e) {");
-                p.pln("throw new " + MARSHAL_EXCEPTION +
-                    "(\"error marshalling arguments\", e);");
-                p.pOln("}");
-            }
-
-            p.pln("ref.invoke(call);");
-
-            if (Util.isVoid(returnType)) {
-                p.pln("ref.done(call);");
-            } else {
-                p.pln(returnType.toString() + " $result;");
-                                                        // REMIND: why $?
-                p.plnI("try {");
-                p.pln("java.io.ObjectInput in = call.getInputStream();");
-                boolean objectRead =
-                    writeUnmarshalArgument(p, "in", returnType, "$result");
-                p.pln(";");
-                p.pOlnI("} catch (java.io.IOException e) {");
-                p.pln("throw new " + UNMARSHAL_EXCEPTION +
-                    "(\"error unmarshalling return\", e);");
-                /*
-                 * If any only if readObject has been invoked, we must catch
-                 * ClassNotFoundException as well as IOException.
-                 */
-                if (objectRead) {
-                    p.pOlnI("} catch (java.lang.ClassNotFoundException e) {");
-                    p.pln("throw new " + UNMARSHAL_EXCEPTION +
-                        "(\"error unmarshalling return\", e);");
-                }
-                p.pOlnI("} finally {");
-                p.pln("ref.done(call);");
-                p.pOln("}");
-                p.pln("return $result;");
-            }
-        }
-        if (version == StubVersion.VCOMPAT) {
-            p.pOln("}");                // end if/else (useNewInvoke) block
-        }
-
-        /*
-         * If we need to catch any particular exceptions, finally write
-         * the catch blocks for them, rethrow any other Exceptions with an
-         * UnexpectedException, and end the try block.
-         */
-        if (catchList.size() > 0) {
-            for (ClassDoc catchClass : catchList) {
-                p.pOlnI("} catch (" + catchClass.qualifiedName() + " e) {");
-                p.pln("throw e;");
-            }
-            p.pOlnI("} catch (java.lang.Exception e) {");
-            p.pln("throw new " + UNEXPECTED_EXCEPTION +
-                "(\"undeclared checked exception\", e);");
-            p.pOln("}");                // end try/catch block
-        }
-
-        p.pOln("}");                    // end stub method
-    }
-
-    /**
-     * Computes the exceptions that need to be caught and rethrown in
-     * a stub method before wrapping Exceptions in
-     * UnexpectedExceptions, given the exceptions declared in the
-     * throws clause of the method.  Returns a list containing the
-     * exception to catch.  Each exception is guaranteed to be unique,
-     * i.e. not a subclass of any of the other exceptions in the list,
-     * so the catch blocks for these exceptions may be generated in
-     * any order relative to each other.
-     *
-     * RemoteException and RuntimeException are each automatically
-     * placed in the returned list (unless any of their superclasses
-     * are already present), since those exceptions should always be
-     * directly rethrown by a stub method.
-     *
-     * The returned list will be empty if java.lang.Exception or one
-     * of its superclasses is in the throws clause of the method,
-     * indicating that no exceptions need to be caught.
-     **/
-    private List<ClassDoc> computeUniqueCatchList(ClassDoc[] exceptions) {
-        List<ClassDoc> uniqueList = new ArrayList<ClassDoc>();
-
-        uniqueList.add(env.docRuntimeException());
-        uniqueList.add(env.docRemoteException()); // always catch/rethrow these
-
-        /* For each exception declared by the stub method's throws clause: */
-    nextException:
-        for (ClassDoc ex : exceptions) {
-            if (env.docException().subclassOf(ex)) {
-                /*
-                 * If java.lang.Exception (or a superclass) was declared
-                 * in the throws clause of this stub method, then we don't
-                 * have to bother catching anything; clear the list and
-                 * return.
-                 */
-                uniqueList.clear();
-                break;
-            } else if (!ex.subclassOf(env.docException())) {
-                /*
-                 * Ignore other Throwables that do not extend Exception,
-                 * because they cannot be thrown by the invoke methods.
-                 */
-                continue;
-            }
-            /*
-             * Compare this exception against the current list of
-             * exceptions that need to be caught:
-             */
-            for (Iterator<ClassDoc> i = uniqueList.iterator(); i.hasNext();) {
-                ClassDoc ex2 = i.next();
-                if (ex.subclassOf(ex2)) {
-                    /*
-                     * If a superclass of this exception is already on
-                     * the list to catch, then ignore this one and continue;
-                     */
-                    continue nextException;
-                } else if (ex2.subclassOf(ex)) {
-                    /*
-                     * If a subclass of this exception is on the list
-                     * to catch, then remove it;
-                     */
-                    i.remove();
-                }
-            }
-            /* This exception is unique: add it to the list to catch. */
-            uniqueList.add(ex);
-        }
-        return uniqueList;
-    }
-
-    /**
-     * Writes the skeleton for the remote class to a stream.
-     **/
-    void writeSkeleton(IndentingWriter p) throws IOException {
-        if (version == StubVersion.V1_2) {
-            throw new AssertionError(
-                "should not generate skeleton for version " + version);
-        }
-
-        /*
-         * Write boiler plate comment.
-         */
-        p.pln("// Skeleton 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 skeleton class to be in the same package.
-         */
-        if (!packageName.equals("")) {
-            p.pln("package " + packageName + ";");
-            p.pln();
-        }
-
-        /*
-         * Declare the skeleton class.
-         */
-        p.plnI("public final class " + skeletonClassSimpleName);
-        p.pln("implements " + SKELETON);
-        p.pOlnI("{");
-
-        writeOperationsArray(p);
-        p.pln();
-
-        writeInterfaceHash(p);
-        p.pln();
-
-        /*
-         * Define the getOperations() method.
-         */
-        p.plnI("public " + OPERATION + "[] getOperations() {");
-        p.pln("return (" + OPERATION + "[]) operations.clone();");
-        p.pOln("}");
-        p.pln();
-
-        /*
-         * Define the dispatch() method.
-         */
-        p.plnI("public void dispatch(" + REMOTE + " obj, " +
-            REMOTE_CALL + " call, int opnum, long hash)");
-        p.pln("throws java.lang.Exception");
-        p.pOlnI("{");
-
-        if (version == StubVersion.VCOMPAT) {
-            p.plnI("if (opnum < 0) {");
-            if (remoteMethods.length > 0) {
-                for (int opnum = 0; opnum < remoteMethods.length; opnum++) {
-                    if (opnum > 0)
-                        p.pO("} else ");
-                    p.plnI("if (hash == " +
-                        remoteMethods[opnum].methodHash() + "L) {");
-                    p.pln("opnum = " + opnum + ";");
-                }
-                p.pOlnI("} else {");
-            }
-            /*
-             * Skeleton throws UnmarshalException if it does not recognize
-             * the method hash; this is what UnicastServerRef.dispatch()
-             * would do.
-             */
-            p.pln("throw new " +
-                UNMARSHAL_EXCEPTION + "(\"invalid method hash\");");
-            if (remoteMethods.length > 0) {
-                p.pOln("}");
-            }
-            /*
-             * Ignore the validation of the interface hash if the
-             * operation number was negative, since it is really a
-             * method hash instead.
-             */
-            p.pOlnI("} else {");
-        }
-
-        p.plnI("if (hash != interfaceHash)");
-        p.pln("throw new " +
-            SKELETON_MISMATCH_EXCEPTION + "(\"interface hash mismatch\");");
-        p.pO();
-
-        if (version == StubVersion.VCOMPAT) {
-            p.pOln("}");                // end if/else (opnum < 0) block
-        }
-        p.pln();
-
-        /*
-         * Cast remote object reference to the remote implementation
-         * class, if it's not private.  We don't use the binary name
-         * of the class like previous implementations did because that
-         * would not compile with javac (since 1.4.1).  If the remote
-         * implementation class is private, then we can't cast to it
-         * like previous implementations did because that also would
-         * not compile with javac-- so instead, we'll have to try to
-         * cast to the remote interface for each remote method.
-         */
-        if (!remoteClass.classDoc().isPrivate()) {
-            p.pln(remoteClass.classDoc().qualifiedName() + " server = (" +
-                  remoteClass.classDoc().qualifiedName() + ") obj;");
-        }
-
-        /*
-         * Process call according to the operation number.
-         */
-        p.plnI("switch (opnum) {");
-        for (int opnum = 0; opnum < remoteMethods.length; opnum++) {
-            writeSkeletonDispatchCase(p, opnum);
-        }
-        p.pOlnI("default:");
-        /*
-         * Skeleton throws UnmarshalException if it does not recognize
-         * the operation number; this is consistent with the case of an
-         * unrecognized method hash.
-         */
-        p.pln("throw new " + UNMARSHAL_EXCEPTION +
-            "(\"invalid method number\");");
-        p.pOln("}");                    // end switch statement
-
-        p.pOln("}");                    // end dispatch() method
-
-        p.pOln("}");                    // end skeleton class
-    }
-
-    /**
-     * Writes the case block for the skeleton's dispatch method for
-     * the remote method with the given "opnum".
-     **/
-    private void writeSkeletonDispatchCase(IndentingWriter p, int opnum)
-        throws IOException
-    {
-        RemoteClass.Method method = remoteMethods[opnum];
-        MethodDoc methodDoc = method.methodDoc();
-        String methodName = methodDoc.name();
-        Type paramTypes[] = method.parameterTypes();
-        String paramNames[] = nameParameters(paramTypes);
-        Type returnType = methodDoc.returnType();
-
-        p.pOlnI("case " + opnum + ": // " +
-            Util.getFriendlyUnqualifiedSignature(methodDoc));
-        /*
-         * Use nested block statement inside case to provide an independent
-         * namespace for local variables used to unmarshal parameters for
-         * this remote method.
-         */
-        p.pOlnI("{");
-
-        if (paramTypes.length > 0) {
-            /*
-             * Declare local variables to hold arguments.
-             */
-            for (int i = 0; i < paramTypes.length; i++) {
-                p.pln(paramTypes[i].toString() + " " + paramNames[i] + ";");
-            }
-
-            /*
-             * Unmarshal arguments from call stream.
-             */
-            p.plnI("try {");
-            p.pln("java.io.ObjectInput in = call.getInputStream();");
-            boolean objectsRead = writeUnmarshalArguments(p, "in",
-                paramTypes, paramNames);
-            p.pOlnI("} catch (java.io.IOException e) {");
-            p.pln("throw new " + UNMARSHAL_EXCEPTION +
-                "(\"error unmarshalling arguments\", e);");
-            /*
-             * If any only if readObject has been invoked, we must catch
-             * ClassNotFoundException as well as IOException.
-             */
-            if (objectsRead) {
-                p.pOlnI("} catch (java.lang.ClassNotFoundException e) {");
-                p.pln("throw new " + UNMARSHAL_EXCEPTION +
-                    "(\"error unmarshalling arguments\", e);");
-            }
-            p.pOlnI("} finally {");
-            p.pln("call.releaseInputStream();");
-            p.pOln("}");
-        } else {
-            p.pln("call.releaseInputStream();");
-        }
-
-        if (!Util.isVoid(returnType)) {
-            /*
-             * Declare variable to hold return type, if not void.
-             */
-            p.p(returnType.toString() + " $result = ");
-                                                        // REMIND: why $?
-        }
-
-        /*
-         * Invoke the method on the server object.  If the remote
-         * implementation class is private, then we don't have a
-         * reference cast to it, and so we try to cast to the remote
-         * object reference to the method's declaring interface here.
-         */
-        String target = remoteClass.classDoc().isPrivate() ?
-            "((" + methodDoc.containingClass().qualifiedName() + ") obj)" :
-            "server";
-        p.p(target + "." + methodName + "(");
-        for (int i = 0; i < paramNames.length; i++) {
-            if (i > 0)
-                p.p(", ");
-            p.p(paramNames[i]);
-        }
-        p.pln(");");
-
-        /*
-         * Always invoke getResultStream(true) on the call object to send
-         * the indication of a successful invocation to the caller.  If
-         * the return type is not void, keep the result stream and marshal
-         * the return value.
-         */
-        p.plnI("try {");
-        if (!Util.isVoid(returnType)) {
-            p.p("java.io.ObjectOutput out = ");
-        }
-        p.pln("call.getResultStream(true);");
-        if (!Util.isVoid(returnType)) {
-            writeMarshalArgument(p, "out", returnType, "$result");
-            p.pln(";");
-        }
-        p.pOlnI("} catch (java.io.IOException e) {");
-        p.pln("throw new " +
-            MARSHAL_EXCEPTION + "(\"error marshalling return\", e);");
-        p.pOln("}");
-
-        p.pln("break;");                // break from switch statement
-
-        p.pOlnI("}");                   // end nested block statement
-        p.pln();
-    }
-
-    /**
-     * Writes declaration and initializer for "operations" static array.
-     **/
-    private void writeOperationsArray(IndentingWriter p)
-        throws IOException
-    {
-        p.plnI("private static final " + OPERATION + "[] operations = {");
-        for (int i = 0; i < remoteMethods.length; i++) {
-            if (i > 0)
-                p.pln(",");
-            p.p("new " + OPERATION + "(\"" +
-                remoteMethods[i].operationString() + "\")");
-        }
-        p.pln();
-        p.pOln("};");
-    }
-
-    /**
-     * Writes declaration and initializer for "interfaceHash" static field.
-     **/
-    private void writeInterfaceHash(IndentingWriter p)
-        throws IOException
-    {
-        p.pln("private static final long interfaceHash = " +
-            remoteClass.interfaceHash() + "L;");
-    }
-
-    /**
-     * Writes declaration for java.lang.reflect.Method static fields
-     * corresponding to each remote method in a stub.
-     **/
-    private void writeMethodFieldDeclarations(IndentingWriter p)
-        throws IOException
-    {
-        for (String name : methodFieldNames) {
-            p.pln("private static java.lang.reflect.Method " + name + ";");
-        }
-    }
-
-    /**
-     * Writes code to initialize the static fields for each method
-     * using the Java Reflection API.
-     **/
-    private void writeMethodFieldInitializers(IndentingWriter p)
-        throws IOException
-    {
-        for (int i = 0; i < methodFieldNames.length; i++) {
-            p.p(methodFieldNames[i] + " = ");
-            /*
-             * Look up the Method object in the somewhat arbitrary
-             * interface that we find in the Method object.
-             */
-            RemoteClass.Method method = remoteMethods[i];
-            MethodDoc methodDoc = method.methodDoc();
-            String methodName = methodDoc.name();
-            Type paramTypes[] = method.parameterTypes();
-
-            p.p(methodDoc.containingClass().qualifiedName() + ".class.getMethod(\"" +
-                methodName + "\", new java.lang.Class[] {");
-            for (int j = 0; j < paramTypes.length; j++) {
-                if (j > 0)
-                    p.p(", ");
-                p.p(paramTypes[j].toString() + ".class");
-            }
-            p.pln("});");
-        }
-    }
-
-
-    /*
-     * Following are a series of static utility methods useful during
-     * the code generation process:
-     */
-
-    /**
-     * Generates an array of names for fields correspondins to the
-     * given array of remote methods.  Each name in the returned array
-     * is guaranteed to be unique.
-     *
-     * The name of a method is included in its corresponding field
-     * name to enhance readability of the generated code.
-     **/
-    private static String[] nameMethodFields(RemoteClass.Method[] methods) {
-        String[] names = new String[methods.length];
-        for (int i = 0; i < names.length; i++) {
-            names[i] = "$method_" + methods[i].methodDoc().name() + "_" + i;
-        }
-        return names;
-    }
-
-    /**
-     * Generates an array of names for parameters corresponding to the
-     * given array of types for the parameters.  Each name in the
-     * returned array is guaranteed to be unique.
-     *
-     * A representation of the type of a parameter is included in its
-     * corresponding parameter name to enhance the readability of the
-     * generated code.
-     **/
-    private static String[] nameParameters(Type[] types) {
-        String[] names = new String[types.length];
-        for (int i = 0; i < names.length; i++) {
-            names[i] = "$param_" +
-                generateNameFromType(types[i]) + "_" + (i + 1);
-        }
-        return names;
-    }
-
-    /**
-     * Generates a readable string representing the given type
-     * suitable for embedding within a Java identifier.
-     **/
-    private static String generateNameFromType(Type type) {
-        String name = type.typeName().replace('.', '$');
-        int dimensions = type.dimension().length() / 2;
-        for (int i = 0; i < dimensions; i++) {
-            name = "arrayOf_" + name;
-        }
-        return name;
-    }
-
-    /**
-     * Writes a snippet of Java code to marshal a value named "name"
-     * of type "type" to the java.io.ObjectOutput stream named
-     * "stream".
-     *
-     * Primitive types are marshalled with their corresponding methods
-     * in the java.io.DataOutput interface, and objects (including
-     * arrays) are marshalled using the writeObject method.
-     **/
-    private static void writeMarshalArgument(IndentingWriter p,
-                                             String streamName,
-                                             Type type, String name)
-        throws IOException
-    {
-        if (type.dimension().length() > 0 || type.asClassDoc() != null) {
-            p.p(streamName + ".writeObject(" + name + ")");
-        } else if (type.typeName().equals("boolean")) {
-            p.p(streamName + ".writeBoolean(" + name + ")");
-        } else if (type.typeName().equals("byte")) {
-            p.p(streamName + ".writeByte(" + name + ")");
-        } else if (type.typeName().equals("char")) {
-            p.p(streamName + ".writeChar(" + name + ")");
-        } else if (type.typeName().equals("short")) {
-            p.p(streamName + ".writeShort(" + name + ")");
-        } else if (type.typeName().equals("int")) {
-            p.p(streamName + ".writeInt(" + name + ")");
-        } else if (type.typeName().equals("long")) {
-            p.p(streamName + ".writeLong(" + name + ")");
-        } else if (type.typeName().equals("float")) {
-            p.p(streamName + ".writeFloat(" + name + ")");
-        } else if (type.typeName().equals("double")) {
-            p.p(streamName + ".writeDouble(" + name + ")");
-        } else {
-            throw new AssertionError(type);
-        }
-    }
-
-    /**
-     * Writes Java statements to marshal a series of values in order
-     * as named in the "names" array, with types as specified in the
-     * "types" array, to the java.io.ObjectOutput stream named
-     * "stream".
-     **/
-    private static void writeMarshalArguments(IndentingWriter p,
-                                              String streamName,
-                                              Type[] types, String[] names)
-        throws IOException
-    {
-        assert types.length == names.length;
-
-        for (int i = 0; i < types.length; i++) {
-            writeMarshalArgument(p, streamName, types[i], names[i]);
-            p.pln(";");
-        }
-    }
-
-    /**
-     * Writes a snippet of Java code to unmarshal a value of type
-     * "type" from the java.io.ObjectInput stream named "stream" into
-     * a variable named "name" (if "name" is null, the value is
-     * unmarshalled and discarded).
-     *
-     * Primitive types are unmarshalled with their corresponding
-     * methods in the java.io.DataInput interface, and objects
-     * (including arrays) are unmarshalled using the readObject
-     * method.
-     *
-     * Returns true if code to invoke readObject was written, and
-     * false otherwise.
-     **/
-    private static boolean writeUnmarshalArgument(IndentingWriter p,
-                                                  String streamName,
-                                                  Type type, String name)
-        throws IOException
-    {
-        boolean readObject = false;
-
-        if (name != null) {
-            p.p(name + " = ");
-        }
-
-        if (type.dimension().length() > 0 || type.asClassDoc() != null) {
-            p.p("(" + type.toString() + ") " + streamName + ".readObject()");
-            readObject = true;
-        } else if (type.typeName().equals("boolean")) {
-            p.p(streamName + ".readBoolean()");
-        } else if (type.typeName().equals("byte")) {
-            p.p(streamName + ".readByte()");
-        } else if (type.typeName().equals("char")) {
-            p.p(streamName + ".readChar()");
-        } else if (type.typeName().equals("short")) {
-            p.p(streamName + ".readShort()");
-        } else if (type.typeName().equals("int")) {
-            p.p(streamName + ".readInt()");
-        } else if (type.typeName().equals("long")) {
-            p.p(streamName + ".readLong()");
-        } else if (type.typeName().equals("float")) {
-            p.p(streamName + ".readFloat()");
-        } else if (type.typeName().equals("double")) {
-            p.p(streamName + ".readDouble()");
-        } else {
-            throw new AssertionError(type);
-        }
-
-        return readObject;
-    }
-
-    /**
-     * Writes Java statements to unmarshal a series of values in order
-     * of types as in the "types" array from the java.io.ObjectInput
-     * stream named "stream" into variables as named in "names" (for
-     * any element of "names" that is null, the corresponding value is
-     * unmarshalled and discarded).
-     **/
-    private static boolean writeUnmarshalArguments(IndentingWriter p,
-                                                   String streamName,
-                                                   Type[] types,
-                                                   String[] names)
-        throws IOException
-    {
-        assert types.length == names.length;
-
-        boolean readObject = false;
-        for (int i = 0; i < types.length; i++) {
-            if (writeUnmarshalArgument(p, streamName, types[i], names[i])) {
-                readObject = true;
-            }
-            p.pln(";");
-        }
-        return readObject;
-    }
-
-    /**
-     * Returns a snippet of Java code to wrap a value named "name" of
-     * type "type" into an object as appropriate for use by the Java
-     * Reflection API.
-     *
-     * For primitive types, an appropriate wrapper class is
-     * instantiated with the primitive value.  For object types
-     * (including arrays), no wrapping is necessary, so the value is
-     * named directly.
-     **/
-    private static String wrapArgumentCode(Type type, String name) {
-        if (type.dimension().length() > 0 || type.asClassDoc() != null) {
-            return name;
-        } else if (type.typeName().equals("boolean")) {
-            return ("(" + name +
-                    " ? java.lang.Boolean.TRUE : java.lang.Boolean.FALSE)");
-        } else if (type.typeName().equals("byte")) {
-            return "new java.lang.Byte(" + name + ")";
-        } else if (type.typeName().equals("char")) {
-            return "new java.lang.Character(" + name + ")";
-        } else if (type.typeName().equals("short")) {
-            return "new java.lang.Short(" + name + ")";
-        } else if (type.typeName().equals("int")) {
-            return "new java.lang.Integer(" + name + ")";
-        } else if (type.typeName().equals("long")) {
-            return "new java.lang.Long(" + name + ")";
-        } else if (type.typeName().equals("float")) {
-            return "new java.lang.Float(" + name + ")";
-        } else if (type.typeName().equals("double")) {
-            return "new java.lang.Double(" + name + ")";
-        } else {
-            throw new AssertionError(type);
-        }
-    }
-
-    /**
-     * Returns a snippet of Java code to unwrap a value named "name"
-     * into a value of type "type", as appropriate for the Java
-     * Reflection API.
-     *
-     * For primitive types, the value is assumed to be of the
-     * corresponding wrapper class, and a method is called on the
-     * wrapper to retrieve the primitive value.  For object types
-     * (include arrays), no unwrapping is necessary; the value is
-     * simply cast to the expected real object type.
-     **/
-    private static String unwrapArgumentCode(Type type, String name) {
-        if (type.dimension().length() > 0 || type.asClassDoc() != null) {
-            return "((" + type.toString() + ") " + name + ")";
-        } else if (type.typeName().equals("boolean")) {
-            return "((java.lang.Boolean) " + name + ").booleanValue()";
-        } else if (type.typeName().equals("byte")) {
-            return "((java.lang.Byte) " + name + ").byteValue()";
-        } else if (type.typeName().equals("char")) {
-            return "((java.lang.Character) " + name + ").charValue()";
-        } else if (type.typeName().equals("short")) {
-            return "((java.lang.Short) " + name + ").shortValue()";
-        } else if (type.typeName().equals("int")) {
-            return "((java.lang.Integer) " + name + ").intValue()";
-        } else if (type.typeName().equals("long")) {
-            return "((java.lang.Long) " + name + ").longValue()";
-        } else if (type.typeName().equals("float")) {
-            return "((java.lang.Float) " + name + ").floatValue()";
-        } else if (type.typeName().equals("double")) {
-            return "((java.lang.Double) " + name + ").doubleValue()";
-        } else {
-            throw new AssertionError(type);
-        }
-    }
-}