alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Java example source code file (StubSkeletonWriter.java)

This example Java source code file (StubSkeletonWriter.java) is included in the alvinalexander.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Learn more about this Java project at its project page.

Java - Java tags/keywords

assertionerror, batchenvironment, classdoc, contents, ioexception, javadoc, list, methoddoc, operation, remoteclass, string, stubskeletonwriter, stubversion, type, unmarshal_exception, util

The StubSkeletonWriter.java Java example source code

/*
 * 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();

        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);
        }
    }
}

Other Java examples (source code examples)

Here is a short list of links related to this Java StubSkeletonWriter.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2024 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.