2362N/A * Copyright (c) 1997, 2007, Oracle and/or its affiliates. All rights reserved. 0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 0N/A * This code is free software; you can redistribute it and/or modify it 0N/A * under the terms of the GNU General Public License version 2 only, as 2362N/A * published by the Free Software Foundation. Oracle designates this 0N/A * particular file as subject to the "Classpath" exception as provided 2362N/A * by Oracle in the LICENSE file that accompanied this code. 0N/A * This code is distributed in the hope that it will be useful, but WITHOUT 0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 0N/A * version 2 for more details (a copy is included in the LICENSE file that 0N/A * accompanied this code). 0N/A * You should have received a copy of the GNU General Public License version 0N/A * 2 along with this work; if not, write to the Free Software Foundation, 0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 2362N/A * or visit www.oracle.com if you need additional information or have any 0N/A/*****************************************************************************/ 0N/A/* Copyright (c) IBM Corporation 1998 */ 0N/A/* (C) Copyright IBM Corp. 1998 */ 0N/A/*****************************************************************************/ 0N/A * A Generator object will generate the Java source code of the stub 0N/A * and skeleton classes for an RMI remote implementation class, using 0N/A * a particular stub protocol version. 0N/A * WARNING: The contents of this source file are not part of any 0N/A * supported API. Code that depends on them does so at its own risk: 0N/A * they are subject to change or removal without notice. 0N/A * @author Peter Jones, Bryan Atsatt 0N/A * Default constructor for Main to use. 0N/A * Examine and consume command line arguments. 0N/A * @param argv The command line arguments. Ignore null 0N/A * and unknown arguments. Set each consumed argument to null. 0N/A * @param error Report any errors using the main.error() methods. 0N/A * @return true if no errors, false otherwise. 0N/A * Generate the source files for the stub and/or skeleton classes 0N/A * needed by RMI for the given remote implementation class. 0N/A * @param env compiler environment 0N/A * @param cdef definition of remote implementation class 0N/A * to generate stubs and/or skeletons for 0N/A * @param destDir directory for the root of the package hierarchy 0N/A * for generated files 0N/A * For bugid 4135136: if skeleton files are not being generated 0N/A * for this compilation run, delete old skeleton source or class 0N/A * files for this remote implementation class that were 0N/A * (presumably) left over from previous runs, to avoid user 0N/A * confusion from extraneous or inconsistent generated files. 0N/A * Return the File object that should be used as the source file 0N/A * for the given Java class, using the supplied destination 0N/A * directory for the top of the package hierarchy. 0N/A // Is there any existing _Tie equivalent leftover from a 0N/A // previous invocation of rmic -iiop? Only do this once per 0N/A // class by looking for skeleton generation... 0N/A // Found a tie. Is IIOP generation also being done? 0N/A // No, so write a warning... 0N/A /** rmic environment for this object */ 0N/A /** the remote class that this instance is generating code for */ 0N/A /** version of the stub protocol to use in code generation */ 0N/A /** remote methods for remote class, indexed by operation number */ 0N/A * Names for the remote class and the stub and skeleton classes 0N/A * to be generated for it. 0N/A * Names to use for the java.lang.reflect.Method static fields 0N/A * corresponding to each remote method. 0N/A /** cached definition for certain exception classes in this environment */ 0N/A * remote implementation class to generate code according to 0N/A * the given stub protocol version. 0N/A * Initialize cached definitions for exception classes used 0N/A * in the generation process. 0N/A * Write the stub for the remote class to a stream. 0N/A * Write boiler plate comment. 0N/A p.
pln(
"// Stub class generated by rmic, do not edit.");
0N/A p.
pln(
"// Contents subject to change without notice.");
0N/A * If remote implementation class was in a particular package, 0N/A * declare the stub class to be in the same package. 0N/A * Declare the stub class; implement all remote interfaces. 0N/A p.
pln(
"private static final long serialVersionUID = " +
0N/A * We only need to declare and initialize the static fields of 0N/A * Method objects for each remote method if there are any remote 0N/A * methods; otherwise, skip this code entirely, to avoid generating 0N/A * a try/catch block for a checked exception that cannot occur 0N/A * (see bugid 4125181). 0N/A p.
pln(
"private static boolean useNewInvoke;");
0N/A * Initialize java.lang.reflect.Method fields for each remote 0N/A * method in a static initializer. 0N/A * Fat stubs must determine whether the API required for 0N/A * the JDK 1.2 stub protocol is supported in the current 0N/A * runtime, so that it can use it if supported. This is 0N/A * determined by using the Reflection API to test if the 0N/A * new invoke method on RemoteRef exists, and setting the 0N/A * static boolean "useNewInvoke" to true if it does, or 0N/A * to false if a NoSuchMethodException is thrown. 0N/A p.
pln(
"java.lang.reflect.Method.class,");
0N/A p.
pln(
"java.lang.Object[].class,");
0N/A p.
pln(
"useNewInvoke = true;");
0N/A p.
pOlnI(
"} catch (java.lang.NoSuchMethodException e) {");
0N/A p.
pln(
"useNewInvoke = false;");
0N/A * REMIND: By throwing an Error here, the application will 0N/A * get the NoSuchMethodError directly when the stub class 0N/A * is initialized. If we throw a RuntimeException 0N/A * instead, the application would get an 0N/A * ExceptionInInitializerError. Would that be more 0N/A * appropriate, and if so, which RuntimeException should 0N/A p.
plnI(
"throw new java.lang.NoSuchMethodError(");
0N/A p.
pln(
"\"stub class initialization failed\");");
0N/A p.
pOln(
"}");
// end static initializer 0N/A * Write each stub method. 0N/A p.
pln(
"// methods from remote interfaces");
0N/A * Write the constructors for the stub class. 0N/A * Only stubs compatible with the JDK 1.1 stub protocol need 0N/A * a no-arg constructor; later versions use reflection to find 0N/A * the constructor that directly takes a RemoteRef argument. 0N/A * Write the stub method for the remote method with the given "opnum". 0N/A * Declare stub method; throw exceptions declared in remote 0N/A p.
pln(
"// implementation of " +
0N/A * The RemoteRef.invoke methods throw Exception, but unless this 0N/A * stub method throws Exception as well, we must catch Exceptions 0N/A * thrown from the invocation. So we must catch Exception and 0N/A * rethrow something we can throw: UnexpectedException, which is a 0N/A * subclass of RemoteException. But for any subclasses of Exception 0N/A * that we can throw, like RemoteException, RuntimeException, and 0N/A * any of the exceptions declared by this stub method, we want them 0N/A * to pass through unharmed, so first we must catch any such 0N/A * exceptions and rethrow it directly. 0N/A * We have to be careful generating the rethrowing catch blocks 0N/A * here, because javac will flag an error if there are any 0N/A * unreachable catch blocks, i.e. if the catch of an exception class 0N/A * follows a previous catch of it or of one of its superclasses. 0N/A * The following method invocation takes care of these details. 0N/A * If we need to catch any particular exceptions (i.e. this method 0N/A * does not declare java.lang.Exception), put the entire stub 0N/A * method in a try block. 0N/A p.p(
"Object $result = ");
// REMIND: why $? 0N/A p.p(
"new java.lang.Object[] {");
0N/A ") this, operations, " +
opnum +
", interfaceHash);");
0N/A p.
pln(
"java.io.ObjectOutput out = call.getOutputStream();");
0N/A p.
pOlnI(
"} catch (java.io.IOException e) {");
0N/A "(\"error marshalling arguments\", e);");
0N/A p.
pln(
"java.io.ObjectInput in = call.getInputStream();");
0N/A p.
pOlnI(
"} catch (java.io.IOException e) {");
0N/A "(\"error unmarshalling return\", e);");
0N/A * If any only if readObject has been invoked, we must catch 0N/A * ClassNotFoundException as well as IOException. 0N/A p.
pOlnI(
"} catch (java.lang.ClassNotFoundException e) {");
0N/A "(\"error unmarshalling return\", e);");
0N/A * If we need to catch any particular exceptions, finally write 0N/A * the catch blocks for them, rethrow any other Exceptions with an 0N/A * UnexpectedException, and end the try block. 0N/A p.
pOlnI(
"} catch (java.lang.Exception e) {");
0N/A "(\"undeclared checked exception\", e);");
0N/A * Compute the exceptions which need to be caught and rethrown in a 0N/A * stub method before wrapping Exceptions in UnexpectedExceptions, 0N/A * given the exceptions declared in the throws clause of the method. 0N/A * Returns a Vector containing ClassDefinition objects for each 0N/A * exception to catch. Each exception is guaranteed to be unique, 0N/A * i.e. not a subclass of any of the other exceptions in the Vector, 0N/A * so the catch blocks for these exceptions may be generated in any 0N/A * order relative to each other. 0N/A * RemoteException and RuntimeException are each automatically placed 0N/A * in the returned Vector (if none of their superclasses are already 0N/A * present), since those exceptions should always be directly rethrown 0N/A * The returned Vector will be empty if java.lang.Exception or one 0N/A * of its superclasses is in the throws clause of the method, indicating 0N/A * that no exceptions need to be caught. 0N/A /* For each exception declared by the stub method's throws clause: */ 0N/A * (If java.lang.Exception (or a superclass) was declared 0N/A * in the throws clause of this stub method, then we don't 0N/A * have to bother catching anything; clear the list and 0N/A * Ignore other Throwables that do not extend Exception, 0N/A * since they do not need to be caught anyway. 0N/A * Compare this exception against the current list of 0N/A * exceptions that need to be caught: 0N/A * If a superclass of this exception is already on 0N/A * the list to catch, then ignore and continue; 0N/A * If a subclass of this exception is on the list 0N/A * to catch, then remove it. 0N/A j++;
// else continue comparing 0N/A /* This exception is unique: add it to the list to catch. */ 0N/A * REMIND: We do not exit from this exceptional condition, 0N/A * generating questionable code and likely letting the 0N/A * compiler report a resulting error later. 0N/A * Write the skeleton for the remote class to a stream. 0N/A throw new Error(
"should not generate skeleton for version");
0N/A * Write boiler plate comment. 0N/A p.
pln(
"// Skeleton class generated by rmic, do not edit.");
0N/A p.
pln(
"// Contents subject to change without notice.");
0N/A * If remote implementation class was in a particular package, 0N/A * declare the skeleton class to be in the same package. 0N/A * Declare the skeleton class. 0N/A * Define the getOperations() method. 0N/A * Define the dispatch() method. 0N/A p.
pln(
"throws java.lang.Exception");
0N/A * Skeleton throws UnmarshalException if it does not recognize 0N/A * the method hash; this is what UnicastServerRef.dispatch() 0N/A * Ignore the validation of the interface hash if the 0N/A * operation number was negative, since it is really a 0N/A * method hash instead. 0N/A p.
plnI(
"if (hash != interfaceHash)");
0N/A * Cast remote object instance to our specific implementation class. 0N/A * Process call according to the operation number. 0N/A * Skeleton throws UnmarshalException if it does not recognize 0N/A * the operation number; this is consistent with the case of an 0N/A * unrecognized method hash. 0N/A "(\"invalid method number\");");
0N/A p.
pOln(
"}");
// end switch statement 0N/A p.
pOln(
"}");
// end dispatch() method 0N/A * Write the case block for the skeleton's dispatch method for 0N/A * the remote method with the given "opnum". 0N/A * Use nested block statement inside case to provide an independent 0N/A * namespace for local variables used to unmarshal parameters for 0N/A * this remote method. 0N/A * Declare local variables to hold arguments. 0N/A * Unmarshal arguments from call stream. 0N/A p.
pln(
"java.io.ObjectInput in = call.getInputStream();");
0N/A p.
pOlnI(
"} catch (java.io.IOException e) {");
0N/A "(\"error unmarshalling arguments\", e);");
0N/A * If any only if readObject has been invoked, we must catch 0N/A * ClassNotFoundException as well as IOException. 0N/A p.
pOlnI(
"} catch (java.lang.ClassNotFoundException e) {");
0N/A "(\"error unmarshalling arguments\", e);");
0N/A p.
pln(
"call.releaseInputStream();");
0N/A p.
pln(
"call.releaseInputStream();");
0N/A * Declare variable to hold return type, if not void. 0N/A * Invoke the method on the server object. 0N/A * Always invoke getResultStream(true) on the call object to send 0N/A * the indication of a successful invocation to the caller. If 0N/A * the return type is not void, keep the result stream and marshal 0N/A p.p(
"java.io.ObjectOutput out = ");
0N/A p.
pln(
"call.getResultStream(true);");
0N/A p.
pOlnI(
"} catch (java.io.IOException e) {");
0N/A p.
pln(
"break;");
// break from switch statement 0N/A p.
pOlnI(
"}");
// end nested block statement 0N/A * Write declaration and initializer for "operations" static array. 0N/A * Write declaration and initializer for "interfaceHash" static field. 0N/A p.
pln(
"private static final long interfaceHash = " +
0N/A * Write declaration for java.lang.reflect.Method static fields 0N/A * corresponding to each remote method in a stub. 0N/A p.
pln(
"private static java.lang.reflect.Method " +
0N/A * Write code to initialize the static fields for each method 0N/A * using the Java Reflection API. 0N/A * Here we look up the Method object in the arbitrary interface 0N/A * that we find in the RemoteClass.Method object. 0N/A * REMIND: Is this arbitrary choice OK? 0N/A * REMIND: Should this access be part of RemoteClass.Method's 0N/A * Following are a series of static utility methods useful during 0N/A * the code generation process: 0N/A * Generate an array of names for fields that correspond to the given 0N/A * array of remote methods. Each name in the returned array is 0N/A * guaranteed to be unique. 0N/A * The name of a method is included in its corresponding field name 0N/A * to enhance readability of the generated code. 0N/A * Generate an array of names for parameters corresponding to the 0N/A * given array of types for the parameters. Each name in the returned 0N/A * array is guaranteed to be unique. 0N/A * A representation of the type of a parameter is included in its 0N/A * corresponding field name to enhance the readability of the generated 0N/A * Generate a readable string representing the given type suitable 0N/A * for embedding within a Java identifier. 0N/A * Write a snippet of Java code to marshal a value named "name" of 0N/A * type "type" to the java.io.ObjectOutput stream named "stream". 0N/A * Primitive types are marshalled with their corresponding methods 0N/A * in the java.io.DataOutput interface, and objects (including arrays) 0N/A * are marshalled using the writeObject method. 0N/A * Write Java statements to marshal a series of values in order as 0N/A * named in the "names" array, with types as specified in the "types" 0N/A * array", to the java.io.ObjectOutput stream named "stream". 0N/A throw new Error(
"paramter type and name arrays different sizes");
0N/A * Write a snippet of Java code to unmarshal a value of type "type" 0N/A * from the java.io.ObjectInput stream named "stream" into a variable 0N/A * named "name" (if "name" is null, the value in unmarshalled and 0N/A * Primitive types are unmarshalled with their corresponding methods 0N/A * in the java.io.DataInput interface, and objects (including arrays) 0N/A * are unmarshalled using the readObject method. 0N/A * Write Java statements to unmarshal a series of values in order of 0N/A * types as in the "types" array from the java.io.ObjectInput stream 0N/A * named "stream" into variables as named in "names" (for any element 0N/A * of "names" that is null, the corresponding value is unmarshalled 0N/A throw new Error(
"paramter type and name arrays different sizes");
0N/A * Return a snippet of Java code to wrap a value named "name" of 0N/A * type "type" into an object as appropriate for use by the 0N/A * Java Reflection API. 0N/A * For primitive types, an appropriate wrapper class instantiated 0N/A * with the primitive value. For object types (including arrays), 0N/A * no wrapping is necessary, so the value is named directly. 0N/A " ? java.lang.Boolean.TRUE : java.lang.Boolean.FALSE)");
0N/A return "new java.lang.Byte(" +
name +
")";
0N/A return "new java.lang.Character(" +
name +
")";
0N/A return "new java.lang.Short(" +
name +
")";
0N/A return "new java.lang.Integer(" +
name +
")";
0N/A return "new java.lang.Long(" +
name +
")";
0N/A return "new java.lang.Float(" +
name +
")";
0N/A return "new java.lang.Double(" +
name +
")";
0N/A * Return a snippet of Java code to unwrap a value named "name" into 0N/A * a value of type "type", as appropriate for the Java Reflection API. 0N/A * For primitive types, the value is assumed to be of the corresponding 0N/A * wrapper type, and a method is called on the wrapper type to retrieve 0N/A * the primitive value. For object types (include arrays), no 0N/A * unwrapping is necessary; the value is simply cast to the expected 0N/A return "((java.lang.Boolean) " +
name +
").booleanValue()";
0N/A return "((java.lang.Byte) " +
name +
").byteValue()";
0N/A return "((java.lang.Character) " +
name +
").charValue()";
0N/A return "((java.lang.Short) " +
name +
").shortValue()";
0N/A return "((java.lang.Integer) " +
name +
").intValue()";
0N/A return "((java.lang.Long) " +
name +
").longValue()";
0N/A return "((java.lang.Float) " +
name +
").floatValue()";
0N/A return "((java.lang.Double) " +
name +
").doubleValue()";