private void writeStubMethod(IndentingWriter p, int opnum)
throws IOException
{
RemoteClass.Method method = remoteMethods[opnum];
Identifier methodName = method.getName();
Type methodType = method.getType();
Type paramTypes[] = methodType.getArgumentTypes();
String paramNames[] = nameParameters(paramTypes);
Type returnType = methodType.getReturnType();
ClassDeclaration[] exceptions = method.getExceptions();
/*
* Declare stub method; throw exceptions declared in remote
* interface(s).
*/
p.pln("// implementation of " +
methodType.typeString(methodName.toString(), true, false));
p.p("public " + returnType + " " + methodName + "(");
for (int i = 0; i < paramTypes.length; i++) {
if (i > 0)
p.p(", ");
p.p(paramTypes[i] + " " + 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].getName().toString());
}
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 unharmed, so first we must catch any such
* exceptions and rethrow it 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.
*/
Vector 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 == STUB_VERSION_FAT) {
p.plnI("if (useNewInvoke) {");
}
if (version == STUB_VERSION_FAT ||
version == STUB_VERSION_1_2)
{
if (!returnType.isType(TC_VOID)) {
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.getMethodHash() + "L);");
if (!returnType.isType(TC_VOID)) {
p.pln("return " +
unwrapArgumentCode(returnType, "$result") + ";");
}
}
if (version == STUB_VERSION_FAT) {
p.pOlnI("} else {");
}
if (version == STUB_VERSION_1_1 ||
version == STUB_VERSION_FAT)
{
p.pln(idRemoteCall + " call = ref.newCall((" + idRemoteObject +
") 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 " + idMarshalException +
"(\"error marshalling arguments\", e);");
p.pOln("}");
}
p.pln("ref.invoke(call);");
if (returnType.isType(TC_VOID)) {
p.pln("ref.done(call);");
} else {
p.pln(returnType + " $result;"); // REMIND: why $?
p.plnI("try {");
p.pln("java.io.ObjectInput in = call.getInputStream();");