blob: d1a481b25b8dc3b03354f99a5c58c8d21875db19 [file] [log] [blame]
/*
* 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.
*/
package org.apache.geode.test.dunit;
import java.io.PrintWriter;
import org.apache.geode.GemFireException;
/**
* This exception is thrown when an exception occurs during a remote method invocation. This
* {@link RuntimeException} wraps the actual exception. It allows distributed unit tests to verify
* that an exception was thrown in a different VM.
*
* <pre>
* VM vm0 = host0.getVM(0);
* try {
* vm.invoke(() -&gt; this.getUnknownObject());
*
* } catch (RMIException ex) {
* assertIndexDetailsEquals(ex.getCause() instanceof ObjectException);
* }
* </pre>
*
* <p>
* Note that special steps are taken so that the stack trace of the cause exception reflects the
* call stack on the remote machine. The stack trace of the exception returned by
* {@link #getCause()} may not be available.
*/
@SuppressWarnings("serial")
public class RMIException extends GemFireException {
/**
* SHADOWED FIELD that holds the cause exception (as opposed to the HokeyException
*/
private final Throwable cause;
/** The name of the method being invoked */
private final String methodName;
/**
* The name of the class (or class of the object type) whose method was being invoked
*/
private final String className;
/** The VM in which the method was executing */
private final VM vm;
/*
* Creates a new RMIException that was caused by a given Throwable while
* invoking a given method.
*/
public RMIException(VM vm, String className, String methodName, Throwable cause) {
super("While invoking " + className + "." + methodName + " in " + vm, cause);
this.cause = cause;
this.className = className;
this.methodName = methodName;
this.vm = vm;
}
/**
* Creates a new {@code RMIException} to indicate that an exception of a given type was
* thrown while invoking a given method.
*
* @param vm The VM in which the method was executing
* @param className The name of the class whose method was being invoked remotely
* @param methodName The name of the method that was being invoked remotely
* @param cause The type of exception that was thrown in the remote VM
* @param stackTrace The stack trace of the exception from the remote VM
*/
public RMIException(VM vm, String className, String methodName, Throwable cause,
String stackTrace) {
super("While invoking " + className + "." + methodName + " in " + vm,
new HokeyException(cause, stackTrace));
this.vm = vm;
this.cause = cause;
this.className = className;
this.methodName = methodName;
}
/*
* Returns the cause of this exception. Note that this is not necessarily the exception that gets
* printed out with the stack trace.
*/
@Override
public Throwable getCause() {
return cause;
}
/*
* Returns the VM in which the remote method was invoked
*/
public VM getVM() {
return vm;
}
/**
* A hokey exception class that makes it looks like we have a real cause exception.
*/
private static class HokeyException extends Throwable {
private final String stackTrace;
private final String toString;
HokeyException(Throwable cause, String stackTrace) {
toString = cause.toString();
this.stackTrace = stackTrace;
}
@Override
public void printStackTrace(PrintWriter pw) {
pw.print(stackTrace);
pw.flush();
}
public String toString() {
return toString;
}
}
}