Package org.apache.harmony.rmi.compiler

Source Code of org.apache.harmony.rmi.compiler.ClassStub$MethodStub

/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements.  See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License.  You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/**
* @author  Vasily Zakharov
* @version $Revision: 1.1.2.3 $
*/
package org.apache.harmony.rmi.compiler;

import java.lang.reflect.Method;

import java.rmi.Remote;
import java.rmi.RemoteException;

import java.util.Arrays;
import java.util.Iterator;
import java.util.TreeMap;
import java.util.Vector;

import org.apache.harmony.rmi.common.ClassList;
import org.apache.harmony.rmi.common.RMIHash;
import org.apache.harmony.rmi.common.RMIHashException;
import org.apache.harmony.rmi.common.RMIUtil;
import org.apache.harmony.rmi.internal.nls.Messages;


/**
* Generates RMI stub code for a particular class.
*
* @author  Vasily Zakharov
* @version $Revision: 1.1.2.3 $
*/
final class ClassStub implements RmicConstants {

    /**
     * Should the stub support v1.1.
     */
    final boolean v11;

    /**
     * Should the stub support v1.2.
     */
    final boolean v12;

    /**
     * Should the stub support both v1.1 and v1.2.
     */
    final boolean vCompat;

    /**
     * Indenter to write source files.
     */
    Indenter indenter;

    /**
     * Name of the class to generate stub for.
     */
    private final String className;

    /**
     * Package of the class to generate stub for.
     */
    private final String packageName;

    /**
     * Stub class name.
     */
    private final String stubName;

    /**
     * Skeleton class name.
     */
    private final String skelName;

    /**
     * List of remote interfaces for the class.
     */
    private final Class[] interfaces;

    /**
     * List of remote interfaces methods for the class.
     */
    private final Vector methods;

    /**
     * <code>true</code> if methods exist in {@link #methods} vector.
     */
    private final boolean methodsExist;

    /**
     * Class interface hash.
     */
    private final long interfaceHash;

    /**
     * Creates <code>ClassStub</code> instance for specified version and class.
     *
     * @param   version
     *          Version of the stub to create.
     *
     * @param   className
     *          Name of the class to load.
     *
     * @throws  RMICompilerException
     *          If version number is incorrect or some other error occurs.
     */
    ClassStub(int version, String className) throws RMICompilerException {
        this(version, getClass(className));
    }

    /**
     * Creates <code>ClassStub</code> instance for specified version and class.
     *
     * @param   version
     *          Version of the stub to create.
     *
     * @param   cls
     *          Class to load.
     *
     * @throws  RMICompilerException
     *          If version number is incorrect or some other error occurs.
     */
    ClassStub(int version, Class cls) throws RMICompilerException {
        // Check version.
        if ((version < MIN_VERSION) || (version > MAX_VERSION)) {
            // rmi.50=Incorrect version specified.
            throw new RMICompilerException(Messages.getString("rmi.50")); //$NON-NLS-1$
        }

        // Set appropriate version flags.
        switch (version) {
        case VERSION_V11:
            v11 = true;
            v12 = false;
            vCompat = false;
            break;
        case VERSION_V12:
            v11 = false;
            v12 = true;
            vCompat = false;
            break;
        case VERSION_VCOMPAT:
            v11 = true;
            v12 = true;
            vCompat = true;
            break;
        default:
            // rmi.51=Version currently unsupported.
            throw new RMICompilerException(Messages.getString("rmi.51")); //$NON-NLS-1$
        }

        className = RMIUtil.getCanonicalName(cls);

        // Check if the specified class is interface.
        if (cls.isInterface()) {
            // rmi.52=Class {0} is interface, and so does not need an RMI stub.
            throw new RMICompilerException(Messages.getString("rmi.52", className)); //$NON-NLS-1$
        }

        // Check if the specified class is remote.
        if (!Remote.class.isAssignableFrom(cls)) {
            // rmi.53=Class {0} does not implement a remote interface, and so does not need an RMI stub.
            throw new RMICompilerException(Messages.getString("rmi.53", className)); //$NON-NLS-1$
        }

        // Check if the specified class implements any remote interfaces.
        if (!new ClassList(cls.getInterfaces()).contains(Remote.class)) {
            // rmi.54=Class {0} does not directly implement a remote interface, and so does not need an RMI stub.
            throw new RMICompilerException(Messages.getString("rmi.54", className)); //$NON-NLS-1$
        }

        // Initialize class variables.
        packageName = RMIUtil.getPackageName(cls);

        String shortClassName = RMIUtil.getShortName(cls);
        stubName = shortClassName + stubSuffix;
        skelName = shortClassName + skelSuffix;

        try {
            interfaces = RMIUtil.getRemoteInterfaces(cls);
        } catch (IllegalArgumentException e) {
            throw new RMICompilerException(e);
        }

        methods = new Vector();

        // Create temporal method stubs table (sorted, no duplicates).
        TreeMap methodMap = new TreeMap();

        // Extract remote methods from remote interfaces of cls and ancestors.
        for (int i = 0; i < interfaces.length; i++) {
            // Add public methods from this interface to the map.
            RMIHash.getSortedMethodMap(methodMap, interfaces[i].getMethods());
        }

        if (v11) {
            try {
                // Calculate interface hash value for the set of methods found.
                interfaceHash = RMIHash.getInterfaceHash(methodMap);
            } catch (RMIHashException e) {
                throw new RMICompilerException(e.getMessage(), e.getCause());
            }
        } else {
            interfaceHash = (-1L);
        }

        // Put the complete MethodStub objects to methods list.
        int n = 0;
        for (Iterator i = methodMap.values().iterator(); i.hasNext(); ) {
            methods.add(new MethodStub((Method) i.next(), n++));
        }

        methodsExist = (n > 0);
    }

    /**
     * Returns the class object for the specified class name.
     *
     * @param   className
     *          Class name.
     *
     * @return  Class object for the specified class name.
     *
     * @throws  RMICompilerException
     *          If class is not found.
     */
    private static Class getClass(String className)
            throws RMICompilerException {
        try {
            return Class.forName(className);
        } catch (ClassNotFoundException e) {
            // rmi.55=Class not found: {0}
            throw new RMICompilerException(Messages.getString("rmi.55", className)); //$NON-NLS-1$
        }
    }

    /**
     * Returns stub class name for loaded class.
     *
     * @return  Stub class name.
     */
    String getStubClassName() {
        return stubName;
    }

    /**
     * Returns skeleton class name for loaded class.
     *
     * @return  Skeleton class name.
     */
    String getSkeletonClassName() {
        return skelName;
    }

    /**
     * Returns stub source code for the loaded class (v1.1/v1.2).
     *
     * @return  String containing the stub source code for loaded class.
     */
    String getStubSource() {
        indenter = new Indenter();

        return (getStubHeader("stub") + getPackageStatement() + EOLN //$NON-NLS-1$
                + getStubClassDeclaration() + indenter.hIncrease()
                + (v12 ? (EOLN + getSerialVersionUID()) : "") //$NON-NLS-1$
                + (v11 ? (EOLN + getInterfaceHash() + (methodsExist
                        ? ((vCompat ? EOLN + getNewInvoke() : "") //$NON-NLS-1$
                        + EOLN + getOperationsArrayDeclaration()) : "")) : "") //$NON-NLS-1$ //$NON-NLS-2$
                + ((v12 && methodsExist) ? (EOLN
                        + getMethodVariablesDeclaration() + EOLN
                        + getStaticInitializationBlock()) : "") + EOLN //$NON-NLS-1$
                + getStubConstructors()
                + (methodsExist ? getMethodImplementations() : "") //$NON-NLS-1$
                + indenter.decrease() + '}' + EOLN + indenter.assertEmpty());
    }

    /**
     * Returns skeleton source code for the loaded class (v1.1).
     *
     * @return  String containing the skeleton source code for loaded class.
     */
    String getSkeletonSource() {
        indenter = new Indenter();

        return (getStubHeader("skeleton") + getPackageStatement() + EOLN //$NON-NLS-1$
                + getSkeletonClassDeclaration()
                + indenter.hIncrease() + EOLN + getInterfaceHash() + EOLN
                + getOperationsArrayDeclaration() + EOLN
                + getOperationsMethod() + EOLN + getDispatchMethod()
                + indenter.decrease() + '}' + EOLN + indenter.assertEmpty());
    }

    /**
     * Returns stub source code header
     * (Stub/Skeleton v1.1/v1.2/vCompat).
     *
     * @param   type
     *          Header type, <code>"stub"</code> or <code>"skeleton"</code>.
     *
     * @return  Stub/skeleton header.
     */
    private String getStubHeader(String type) {
        return ("/*" + EOLN + " * RMI " + type + " class" + EOLN //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
                + " * for class " + className + EOLN //$NON-NLS-1$
                + " * Compatible with stub protocol version " //$NON-NLS-1$
                + (v11 ? "1.1" : "") + (vCompat ? "/" : "") //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
                + (v12 ? "1.2" : "") + EOLN + " *" + EOLN //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
                + " * Generated by DRL RMI Compiler (rmic)." + EOLN //$NON-NLS-1$
                + " *" + EOLN + " * DO NOT EDIT!!!" + EOLN //$NON-NLS-1$ //$NON-NLS-2$
                + " * Contents subject to change without notice!" + EOLN //$NON-NLS-1$
                + " */" + EOLN); //$NON-NLS-1$
    }

    /**
     * Returns <code>package</code> statement
     * (Stub/Skeleton v1.1/v1.2/vCompat).
     *
     * @return  <code>package</code> statement for stub/skeleton class.
     */
    private String getPackageStatement() {
        return ((packageName == null) ? "" //$NON-NLS-1$
                : ("package " + packageName + ';' + EOLN + EOLN)); //$NON-NLS-1$
    }

    /**
     * Returns stub class declaration
     * (Stub v1.1/v1.2/vCompat).
     *
     * @return  Stub class declaration statement.
     */
    private String getStubClassDeclaration() {
        StringBuilder buffer = new StringBuilder("public final class " //$NON-NLS-1$
                + stubName + " extends java.rmi.server.RemoteStub" + EOLN //$NON-NLS-1$
                + indenter.tIncrease(2) + "implements "); //$NON-NLS-1$

        // Add implemented interfaces list.
        for (int i = 0; i < interfaces.length; i++) {
            buffer.append(((i > 0) ? ", " : "" ) + interfaces[i].getName()); //$NON-NLS-1$ //$NON-NLS-2$
        }

        buffer.append(" {" + EOLN); //$NON-NLS-1$

        return buffer.toString();
    }

    /**
     * Returns skeleton class declaration
     * (Skeleton v1.1/vCompat).
     *
     * @return  Skeleton class declaration statement.
     */
    private String getSkeletonClassDeclaration() {
        return ("public final class " + skelName //$NON-NLS-1$
                + " implements java.rmi.server.Skeleton {" + EOLN); //$NON-NLS-1$
    }

    /**
     * Returns <code>serialVersionUID</code> declaration
     * (Stub v1.2/vCompat).
     *
     * @return  <code>serialVersionUID</code> declaration statement.
     */
    private String getSerialVersionUID() {
        return (indenter.indent()
                    + "private static final long serialVersionUID = 2;" + EOLN); //$NON-NLS-1$
    }

    /**
     * Returns <code>interfaceHash</code> declaration
     * (Stub/Skeleton v1.1/vCompat).
     *
     * @return  <code>interfaceHash</code> declaration statement.
     */
    private String getInterfaceHash() {
        return (indenter.indent() + "private static final long " //$NON-NLS-1$
                + interfaceHashVarName + " = " + interfaceHash + "L;" + EOLN); //$NON-NLS-1$ //$NON-NLS-2$
    }

    /**
     * Returns <code>useNewInvoke</code> declaration
     * (Stub vCompat).
     *
     * @return  <code>useNewInvoke</code> declaration statement.
     */
    private String getNewInvoke() {
        return (indenter.indent()
                + "private static boolean " + useNewInvoke + ';'+ EOLN); //$NON-NLS-1$
    }

    /**
     * Returns <code>operations</code> array declaration
     * (Stub/Skeleton v1.1/vCompat).
     *
     * @return  <code>operations</code> array declaration statement.
     */
    private String getOperationsArrayDeclaration() {
        StringBuilder buffer = new StringBuilder(indenter.indent()
                + "private static final java.rmi.server.Operation[]" //$NON-NLS-1$
                + " operations = {"); //$NON-NLS-1$

        if (methodsExist) {
            buffer.append(EOLN + indenter.hIncrease());

            for (Iterator i = methods.iterator(); i.hasNext(); ) {
                buffer.append(((MethodStub) i.next()).getOpsArrayElement()
                        + (i.hasNext() ? "," : "" ) + EOLN); //$NON-NLS-1$ //$NON-NLS-2$
            }

            buffer.append(indenter.decrease());
        }

        buffer.append("};" + EOLN); //$NON-NLS-1$

        return buffer.toString();
    }

    /**
     * Returns <code>getOperations()</code> method declaration
     * (Skeleton v1.1/vCompat).
     *
     * @return  <code>getOperations()</code> declaration statement.
     */
    private String getOperationsMethod() {
        return (indenter.indent()
                + "public java.rmi.server.Operation[] getOperations() {" + EOLN //$NON-NLS-1$
                + indenter.tIncrease()
                + "return (java.rmi.server.Operation[]) operations.clone();" //$NON-NLS-1$
                + EOLN + indenter.indent() + '}' + EOLN);
    }

    /**
     * Returns <code>dispatch()</code> method declaration
     * (Skeleton v1.1/vCompat).
     *
     * @return  <code>dispatch()</code> method declaration statement.
     */
    private String getDispatchMethod() {
        StringBuilder buffer = new StringBuilder(indenter.indent()
                + "public void dispatch(java.rmi.Remote obj, " //$NON-NLS-1$
                + "java.rmi.server.RemoteCall call, int opnum, long hash) " //$NON-NLS-1$
                + "throws java.lang.Exception {" + EOLN + indenter.hIncrease()); //$NON-NLS-1$

        if (vCompat) {
            buffer.append(indenter.indent() + "if (opnum < 0) {" + EOLN //$NON-NLS-1$
                    + indenter.increase());

            if (methodsExist) {
                for (Iterator i = methods.iterator(); i.hasNext(); ) {
                    buffer.append(((MethodStub) i.next()).getHashCheck());
                }
                buffer.append('{' + EOLN + indenter.increase());
            }

            buffer.append("throw new java.rmi.UnmarshalException(" //$NON-NLS-1$
                    + "\"Invalid method hash: \" + hash);" + EOLN //$NON-NLS-1$
                    + indenter.decrease() + '}' + EOLN
                    + (methodsExist ? (indenter.tDecrease() + "} else {") : "") //$NON-NLS-1$ //$NON-NLS-2$
                    + EOLN);
        }

        buffer.append(indenter.indent() + "if (hash != interfaceHash) {" + EOLN //$NON-NLS-1$
                + indenter.increase()
                + "throw new java.rmi.server.SkeletonMismatchException(" + EOLN //$NON-NLS-1$
                + indenter.tIncrease(2)
                + "\"Interface hash mismatch, expected: \" + interfaceHash" //$NON-NLS-1$
                + " + \", received: \" + hash);" + EOLN //$NON-NLS-1$
                + indenter.decrease() + '}' + EOLN + ((vCompat && methodsExist)
                        ? (indenter.decrease() + '}' + EOLN) : "") + EOLN //$NON-NLS-1$
                + indenter.indent() + className + " server = " //$NON-NLS-1$
                    + '(' + className + ") obj;" + EOLN + EOLN); //$NON-NLS-1$

        if (methodsExist) {
            buffer.append(indenter.indent() + "switch (opnum) {" + EOLN); //$NON-NLS-1$

            for (Iterator i = methods.iterator(); i.hasNext(); ) {
                buffer.append(EOLN + ((MethodStub) i.next()).getDispatchCase());
            }

            buffer.append(EOLN + indenter.indent() + "default:" + EOLN); //$NON-NLS-1$

            indenter.increase();
        }

        buffer.append(indenter.indent()
                + "throw new java.rmi.UnmarshalException(" //$NON-NLS-1$
                + "\"Invalid method number: \" + opnum);" + EOLN //$NON-NLS-1$
                + (methodsExist ? (indenter.decrease() + '}' + EOLN) : "") //$NON-NLS-1$
                + indenter.decrease() + '}' + EOLN);

        return buffer.toString();
    }

    /**
     * Returns method variables declaration block
     * (Stub v1.2/vCompat).
     *
     * @return  Variables declaration block.
     */
    private String getMethodVariablesDeclaration() {
        StringBuilder buffer = new StringBuilder();

        for (Iterator i = methods.iterator(); i.hasNext(); ) {
            buffer.append(((MethodStub) i.next()).getVariableDecl());
        }

        return buffer.toString();
    }

    /**
     * Creates static initialization block
     * (Stub v1.2/vCompat).
     *
     * @return  Static initialization declaration block.
     */
    private String getStaticInitializationBlock() {
        StringBuilder buffer = new StringBuilder(indenter.indent()
                + "static {" + EOLN + indenter.increase() + "try {" + EOLN //$NON-NLS-1$ //$NON-NLS-2$
                + indenter.hIncrease());

        if (vCompat) {
            buffer.append(indenter.indent()
                    + "java.rmi.server.RemoteRef.class.getMethod(\"invoke\", " //$NON-NLS-1$
                    + "new java.lang.Class[] {java.rmi.Remote.class, " //$NON-NLS-1$
                    + "java.lang.reflect.Method.class, java.lang.Object[].class" //$NON-NLS-1$
                    + ", long.class});" + EOLN + EOLN); //$NON-NLS-1$
        }

        for (Iterator i = methods.iterator(); i.hasNext(); ) {
            buffer.append(((MethodStub) i.next()).getVariableInit());
        }

        buffer.append((vCompat ? (EOLN + indenter.indent() + useNewInvoke
                + " = true;" + EOLN) : "") + indenter.decrease() //$NON-NLS-1$ //$NON-NLS-2$
                + "} catch (java.lang.NoSuchMethodException e) {" + EOLN //$NON-NLS-1$
                + indenter.increase()
                + (vCompat ? (useNewInvoke + " = false;") //$NON-NLS-1$
                        : ("throw new java.lang.NoSuchMethodError(" + EOLN //$NON-NLS-1$
                                + indenter.tIncrease(2)
                                + "\"Stub class initialization failed: " //$NON-NLS-1$
                                + ((packageName != null)
                                        ? (packageName + '.') : "") //$NON-NLS-1$
                                + stubName + "\");")) + EOLN //$NON-NLS-1$
                + indenter.decrease() + '}' + EOLN
                + indenter.decrease() + '}' + EOLN);

        return buffer.toString();
    }

    /**
     * Returns stub constructors
     * (Stub v1.1/v1.2/vCompat).
     *
     * @return  Stub constructors code.
     */
    private String getStubConstructors() {
        StringBuilder buffer = new StringBuilder();

        if (v11) {
            buffer.append(indenter.indent() + "public " + stubName //$NON-NLS-1$
                    + "() {" + EOLN + indenter.tIncrease() + "super();" + EOLN //$NON-NLS-1$ //$NON-NLS-2$
                    + indenter.indent() + '}' + EOLN + EOLN);
        }

        buffer.append(indenter.indent() + "public " + stubName //$NON-NLS-1$
                + "(java.rmi.server.RemoteRef ref) {" + EOLN //$NON-NLS-1$
                + indenter.tIncrease() + "super(ref);" + EOLN //$NON-NLS-1$
                + indenter.indent() + '}' + EOLN);

        return buffer.toString();
    }

    /**
     * Returns remote methods implementation
     * (Stub v1.1/v1.2/vCompat).
     *
     * @return  Stub method implementations code.
     */
    private String getMethodImplementations() {
        StringBuilder buffer = new StringBuilder();

        for (Iterator i = methods.iterator(); i.hasNext(); ) {
            buffer.append(EOLN + ((MethodStub) i.next()).getStubImpl());
        }

        return buffer.toString();
    }

    /**
     * Generates RMI stub code for a particular method.
     */
    private final class MethodStub {

        /**
         * The method name (via {@link Method#getName()}).
         */
        private final String name;

        /**
         * The name of the interface declaring this method.
         */
        private final String interfaceName;

        /**
         * The method parameters (via {@link Method#getParameterTypes()}).
         */
        private final Class[] parameters;

        /**
         * The method parameters class names.
         */
        private final String[] paramClassNames;

        /**
         * The method parameters names.
         */
        private final String[] paramNames;

        /**
         * Number of parameters for this method.
         */
        private final int numParams;

        /**
         * The method return type (via {@link Method#getReturnType()}).
         */
        private final Class retType;

        /**
         * The method return type name.
         */
        private final String retTypeName;

        /**
         * Exceptions that this method throws.
         */
        private final Vector exceptions;

        /**
         * Exceptions that must be caught in method stub.
         */
        private final ClassList catches;

        /**
         * The method long signature
         * (via {@link RMIUtil#getLongMethodSignature(Method)
         * getLongMethodSignature()}).
         */
        private final String longSign;

        /**
         * The method short signature
         * (via {@link RMIUtil#getShortMethodSignature(Method)
         * getShortMethodSignature()}).
         */
        private final String shortSign;

        /**
         * The method hash (via {@link RMIHash#getMethodHash(Method)
         * getMethodHash()}).
         */
        private final long hash;

        /**
         * The method number in the stub.
         */
        private final int number;

        /**
         * Name of the variable containing this method in the stub
         * (<code>$method_<em>name</em>_<em>number</em></code>).
         */
        private final String varName;

        /**
         * Whether this method throws {@link Exception}.
         */
        private final boolean throwsException;

        /**
         * Creates method stub instance.
         *
         * @param   method
         *          Method to process.
         *
         * @param   number
         *          Method number in sorted methods table.
         *
         * @throws  RMICompilerException
         *          If some error occurs.
         */
        MethodStub(Method method, int number) throws RMICompilerException {
            this.name = method.getName();
            this.interfaceName = method.getDeclaringClass().getName();
            this.parameters = method.getParameterTypes();
            this.numParams = parameters.length;
            this.retType = method.getReturnType();
            this.retTypeName = RMIUtil.getCanonicalName(retType);
            this.longSign = RMIUtil.getLongMethodSignature(method);
            this.shortSign = RMIUtil.getShortMethodSignature(method);
            this.number = number;
            this.varName = (methodVarPrefix + name + '_' + number);

            try {
                this.hash = RMIHash.getMethodHash(method);
            } catch (RMIHashException e) {
                throw new RMICompilerException(e.getMessage(), e);
            }

            // Create parameter names array.
            paramClassNames = new String[numParams];
            paramNames = new String[numParams];
            for (int i = 0; i < numParams; i++) {
                Class parameter = parameters[i];
                paramClassNames[i] = RMIUtil.getCanonicalName(parameter);
                paramNames[i] = RmicUtil.getParameterName(parameter, i + 1);
            }

            // Create list of exceptions declared thrown.
            Class[] exceptionsArray = method.getExceptionTypes();
            exceptions = new Vector(exceptionsArray.length);
            exceptions.addAll(Arrays.asList(exceptionsArray));

            // Create list of exceptions to be caught.
            catches = new ClassList(true);

            // Add standard exceptions to make sure they are first in the list.
            catches.add(RuntimeException.class);
            catches.add(RemoteException.class);

            // Add declared thrown exceptions.
            catches.addAll(exceptions);

            throwsException = catches.contains(Exception.class);
        }

        /**
         * Returns <code>operations</code> array element for this method
         * (Stub/Skeleton v1.1/vCompat)
         *
         * @return  <code>operations</code> array element for this method.
         */
        String getOpsArrayElement() {
            return (indenter.indent() +
                        "new java.rmi.server.Operation(\"" + longSign + "\")"); //$NON-NLS-1$ //$NON-NLS-2$
        }

        /**
         * Returns hash checking code for this method
         * (Skeleton vCompat).
         *
         * @return  Hash checking code for this method..
         */
        String getHashCheck() {
            return ("if (hash == " + hash + "L) {" + EOLN //$NON-NLS-1$ //$NON-NLS-2$
                    + indenter.tIncrease() + "opnum = " + number + ';' + EOLN //$NON-NLS-1$
                    + indenter.indent() + "} else "); //$NON-NLS-1$
        }

        /**
         * Returns <code>dispatch()</code> method case for this method
         * (Skeleton v1.1/vCompat).
         *
         * @return  <code>dispatch()</code> method case for this method.
         */
        String getDispatchCase() {
            StringBuilder buffer = new StringBuilder(indenter.indent()
                    + "case " + number + ": {    // " + shortSign + EOLN + EOLN //$NON-NLS-1$ //$NON-NLS-2$
                    + indenter.hIncrease());

            if (numParams > 0) {
                // Add parameters declaration.
                for (int i = 0; i < numParams; i++) {
                    buffer.append(indenter.indent() + paramClassNames[i]
                            + ' ' + paramNames[i] + ';' + EOLN);
                }

                // Access input stream.
                buffer.append(EOLN + indenter.indent() + "try {" + EOLN //$NON-NLS-1$
                        + indenter.increase() + "java.io.ObjectInput " //$NON-NLS-1$
                        + inputStreamName + " = call.getInputStream();" + EOLN); //$NON-NLS-1$

                boolean objectParametersExist = false;

                // Add parameters initialization, read them from the stream.
                for (int i = 0; i < numParams; i++) {
                    buffer.append(indenter.indent() + paramNames[i] + " = " //$NON-NLS-1$
                            + RmicUtil.getReadObjectString(parameters[i],
                                    inputStreamName) + ';' + EOLN);

                    if (!parameters[i].isPrimitive()) {
                        objectParametersExist = true;
                    }
                }

                // Add catch block.
                buffer.append(indenter.tDecrease()
                        + "} catch (java.io.IOException e) {" + EOLN //$NON-NLS-1$
                        + indenter.indent()
                        + "throw new java.rmi.UnmarshalException(" //$NON-NLS-1$
                        + "\"Error unmarshalling arguments\", e);" + EOLN //$NON-NLS-1$
                        + (objectParametersExist ? (indenter.tDecrease()
                        + "} catch (java.lang.ClassNotFoundException e) {" //$NON-NLS-1$
                        + EOLN + indenter.indent()
                        + "throw new java.rmi.UnmarshalException(" //$NON-NLS-1$
                        + "\"Error unmarshalling arguments\", e);" + EOLN) : "") //$NON-NLS-1$ //$NON-NLS-2$
                        + indenter.tDecrease() + "} finally {" + EOLN); //$NON-NLS-1$
            }
            // Release input stream.
            buffer.append(indenter.indent()
                    + "call.releaseInputStream();" + EOLN); //$NON-NLS-1$

            if (numParams > 0) {
                buffer.append(indenter.decrease() + '}' + EOLN);
            }

            buffer.append(EOLN + indenter.indent() + ((retType != void.class)
                    ? (retTypeName + ' ' + retVarName + " = ") : "") //$NON-NLS-1$ //$NON-NLS-2$
                    + "server." + name + '('); //$NON-NLS-1$

            for (int i = 0; i < numParams; i++) {
                buffer.append(((i > 0) ? ", " : "") + paramNames[i]); //$NON-NLS-1$ //$NON-NLS-2$
            }

            buffer.append(");" + EOLN + EOLN + indenter.indent() + "try {" //$NON-NLS-1$ //$NON-NLS-2$
                    + EOLN + indenter.increase() + ((retType != void.class)
                    ? ("java.io.ObjectOutput " + outputStreamName + " = ") : "") //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
                    + "call.getResultStream(true);" + EOLN //$NON-NLS-1$
                    + ((retType != void.class) ? (indenter.indent()
                            + RmicUtil.getWriteObjectString(retType, retVarName,
                                    outputStreamName) + ';' + EOLN) : "") //$NON-NLS-1$
                    + indenter.decrease() + "} catch (java.io.IOException e) {" //$NON-NLS-1$
                    + EOLN + indenter.tIncrease()
                    + "throw new java.rmi.MarshalException(" //$NON-NLS-1$
                    + "\"Error marshalling return\", e);" + EOLN //$NON-NLS-1$
                    + indenter.indent() + '}' + EOLN + EOLN
                    + indenter.indent() + "break;" + EOLN //$NON-NLS-1$
                    + indenter.decrease() + '}' + EOLN);

            return buffer.toString();
        }

        /**
         * Returns source code for the method variable declaration
         * (Stub v1.2/vCompat).
         *
         * @return  Method variable declaration.
         */
        String getVariableDecl() {
            return (indenter.indent()
                    + "private static java.lang.reflect.Method" //$NON-NLS-1$
                    + ' ' + varName + ';' + EOLN);
        }

        /**
         * Returns source code for the method variable initialization
         * (Stub v1.2/vCompat).
         *
         * @return  Method variable initialization.
         */
        String getVariableInit() {
            StringBuilder buffer = new StringBuilder(indenter.indent()
                    + varName + " = " + interfaceName + ".class.getMethod(\"" //$NON-NLS-1$ //$NON-NLS-2$
                    + name + "\", new java.lang.Class[] {"); //$NON-NLS-1$

            if (numParams > 0) {
                // Write method parameters.
                for (int i = 0; i < numParams; i++) {
                    buffer.append(((i > 0) ? ", " : "") //$NON-NLS-1$ //$NON-NLS-2$
                            + paramClassNames[i] + ".class"); //$NON-NLS-1$
                }
            }

            buffer.append("});" + EOLN); //$NON-NLS-1$

            return buffer.toString();
        }

        /**
         * Returns stub implementation for this method
         * (Stub v1.1/v1.2/vCompat).
         *
         * @return  Stub implementation for this method.
         */
        String getStubImpl() {
            return (getStubImplHeader()
                    + (vCompat ? (indenter.indent() + "if (" + useNewInvoke //$NON-NLS-1$
                            + ") {" + EOLN + indenter.hIncrease()) : "") //$NON-NLS-1$ //$NON-NLS-2$
                    + (v12 ? getStubImplCodeV12() : "") + (vCompat //$NON-NLS-1$
                            ? (indenter.tDecrease() + "} else {" + EOLN) : "") //$NON-NLS-1$ //$NON-NLS-2$
                    + (v11 ? getStubImplCodeV11() : "") //$NON-NLS-1$
                    + (vCompat ? (indenter.decrease() + '}' + EOLN) : "") //$NON-NLS-1$
                    + (throwsException ? "" : (indenter.hDecrease() //$NON-NLS-1$
                            + getStubImplCatchBlock()))
                    + indenter.decrease() + '}' + EOLN);
        }

        /**
         * Returns header for the stub implementation for this method
         * (Stub v1.1/v1.2/vCompat).
         *
         * @return  Stub implementation header for this method.
         */
        private String getStubImplHeader() {
            StringBuilder buffer = new StringBuilder(indenter.indent()
                    + "// Implementation of " + shortSign + EOLN //$NON-NLS-1$
                    + indenter.indent() + "public " + retTypeName //$NON-NLS-1$
                    + ' ' + name + '(');

            // Write method parameters.
            for (int i = 0; i < numParams; i++) {
                buffer.append(((i > 0) ? ", " : "") //$NON-NLS-1$ //$NON-NLS-2$
                        + paramClassNames[i] + ' ' + paramNames[i]);
            }

            buffer.append(')' + EOLN + indenter.tIncrease(2) + "throws "); //$NON-NLS-1$

            // Write exceptions declared thrown.
            for (Iterator i = exceptions.iterator(); i.hasNext(); ) {
                buffer.append(((Class) i.next()).getName()
                        + (i.hasNext() ? ", " : "" )); //$NON-NLS-1$ //$NON-NLS-2$
            }

            buffer.append(" {" + EOLN + indenter.hIncrease() //$NON-NLS-1$
                    + (throwsException ? "" : (indenter.indent() //$NON-NLS-1$
                            + "try {" + EOLN + indenter.hIncrease()))); //$NON-NLS-1$

            return buffer.toString();
        }

        /**
         * Returns the stub implementation code section source for this method
         * (Stub v1.1/vCompat).
         *
         * @return  Stub implementation code for this method.
         */
        private String getStubImplCodeV11() {
            StringBuilder buffer = new StringBuilder(indenter.indent()
                    + "java.rmi.server.RemoteCall call = " //$NON-NLS-1$
                    + "ref.newCall((java.rmi.server.RemoteObject) this, " //$NON-NLS-1$
                    + "operations, " + number + ", " + interfaceHashVarName //$NON-NLS-1$ //$NON-NLS-2$
                    + ");" + EOLN); //$NON-NLS-1$

            if (numParams > 0) {
                buffer.append(EOLN + indenter.indent() + "try {" + EOLN //$NON-NLS-1$
                    + indenter.increase() + "java.io.ObjectOutput " //$NON-NLS-1$
                    + outputStreamName + " = call.getOutputStream();" + EOLN); //$NON-NLS-1$

                for (int i = 0; i < numParams; i++) {
                    buffer.append(indenter.indent()
                            + RmicUtil.getWriteObjectString(parameters[i],
                                    paramNames[i], outputStreamName)
                            + ';' + EOLN);
                }

                buffer.append(indenter.decrease()
                        + "} catch (java.io.IOException e) {" + EOLN //$NON-NLS-1$
                        + indenter.tIncrease()
                        + "throw new java.rmi.MarshalException(" //$NON-NLS-1$
                        + "\"Error marshalling arguments\", e);" + EOLN //$NON-NLS-1$
                        + indenter.indent() + '}' + EOLN);
            }

            buffer.append(EOLN + indenter.indent()
                    + "ref.invoke(call);" + EOLN); //$NON-NLS-1$

            if (retType != void.class) {
                buffer.append(EOLN + indenter.indent()
                        + retTypeName + ' ' + retVarName + ';' + EOLN + EOLN
                        + indenter.indent() + "try {" + EOLN //$NON-NLS-1$
                        + indenter.increase() + "java.io.ObjectInput " //$NON-NLS-1$
                        + inputStreamName + " = call.getInputStream();" + EOLN //$NON-NLS-1$
                        + indenter.indent() + retVarName + " = " //$NON-NLS-1$
                        + RmicUtil.getReadObjectString(retType, inputStreamName)
                        + ';' + EOLN + indenter.decrease()
                        + "} catch (java.io.IOException e) {" + EOLN //$NON-NLS-1$
                        + indenter.tIncrease()
                        + "throw new java.rmi.UnmarshalException(" //$NON-NLS-1$
                        + "\"Error unmarshalling return value\", e);" + EOLN //$NON-NLS-1$
                        + (!retType.isPrimitive() ? (indenter.indent()
                        + "} catch (java.lang.ClassNotFoundException e) {" //$NON-NLS-1$
                        + EOLN + indenter.tIncrease()
                        + "throw new java.rmi.UnmarshalException(" //$NON-NLS-1$
                        + "\"Error unmarshalling return value\", e);" + EOLN) //$NON-NLS-1$
                        : "") + indenter.indent() + "} finally {" + EOLN //$NON-NLS-1$ //$NON-NLS-2$
                        + indenter.tIncrease() + "ref.done(call);" + EOLN //$NON-NLS-1$
                        + indenter.indent() + '}' + EOLN + EOLN
                        + indenter.indent() + "return " + retVarName + ';' //$NON-NLS-1$
                        + EOLN);
            } else {
                buffer.append(EOLN + indenter.indent()
                        + "ref.done(call);" + EOLN); //$NON-NLS-1$
            }

            return buffer.toString();
        }

        /**
         * Returns the stub  implementation code section source for this method
         * (Stub v1.2/vCompat).
         *
         * @return  Stub implementation code for this method.
         */
        private String getStubImplCodeV12() {
            StringBuilder buffer = new StringBuilder(indenter.indent());

            if (retType != void.class) {
                buffer.append("java.lang.Object " + retVarName + " = "); //$NON-NLS-1$ //$NON-NLS-2$
            }

            buffer.append("ref.invoke(this, " + varName + ", "); //$NON-NLS-1$ //$NON-NLS-2$

            if (numParams > 0) {
                buffer.append("new java.lang.Object[] {"); //$NON-NLS-1$

                // Write invocation parameters.
                for (int i = 0; i < numParams; i++) {
                    buffer.append(((i > 0) ? ", " : "") //$NON-NLS-1$ //$NON-NLS-2$
                            + RmicUtil.getObjectParameterString(
                                    parameters[i], paramNames[i]));
                }
                buffer.append('}');
            } else {
                buffer.append("null"); //$NON-NLS-1$
            }

            buffer.append(", " + hash + "L);" + EOLN); //$NON-NLS-1$ //$NON-NLS-2$

            // Write return statement.
            if (retType != void.class) {
                buffer.append(indenter.indent() + "return " //$NON-NLS-1$
                        + RmicUtil.getReturnObjectString(retType, retVarName)
                        + ';' + EOLN);
            }

            return buffer.toString();
        }

        /**
         * Returns the stub implementation catch block for this method
         * (Stub v1.1/v1.2/vCompat).
         *
         * @return  Stub implementation catch block for this method.
         */
        private String getStubImplCatchBlock() {
            StringBuilder buffer = new StringBuilder();

            for (Iterator i = catches.iterator(); i.hasNext(); ) {
                buffer.append(indenter.indent() + "} catch (" //$NON-NLS-1$
                        + ((Class) i.next()).getName() + " e) {" + EOLN //$NON-NLS-1$
                        + indenter.tIncrease() + "throw e;" + EOLN); //$NON-NLS-1$
            }

            buffer.append(indenter.indent()
                    + "} catch (java.lang.Exception e) {" + EOLN //$NON-NLS-1$
                    + indenter.tIncrease()
                    + "throw new java.rmi.UnexpectedException(" //$NON-NLS-1$
                    + "\"Undeclared checked exception\", e);" + EOLN //$NON-NLS-1$
                    + indenter.indent() + '}' + EOLN);

            return buffer.toString();
        }
    }
}
TOP

Related Classes of org.apache.harmony.rmi.compiler.ClassStub$MethodStub

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.