|
Java example source code file (StubSkeletonWriter.java)
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
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 |
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.