
org.openqa.selenium.remote.ErrorHandler Maven / Gradle / Ivy
The newest version!
package org.openqa.selenium.remote;
import org.openqa.selenium.WebDriverException;
import com.google.common.base.Function;
import com.google.common.base.Predicates;
import com.google.common.collect.Iterables;
import static org.openqa.selenium.remote.ErrorCodes.SUCCESS;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.List;
import java.util.Map;
/**
* Maps exceptions to status codes for sending over the wire.
*
* @author [email protected] (Jason Leyba)
*/
public class ErrorHandler {
private static final String MESSAGE = "message";
private static final String SCREEN_SHOT = "screen";
private static final String CLASS = "class";
private static final String STACK_TRACE = "stackTrace";
private static final String LINE_NUMBER = "lineNumber";
private static final String METHOD_NAME = "methodName";
private static final String CLASS_NAME = "className";
private static final String FILE_NAME = "fileName";
private static final String UNKNOWN_CLASS = "";
private static final String UNKNOWN_METHOD = "";
private static final String UNKNOWN_FILE = "";
private final ErrorCodes errorCodes = new ErrorCodes();
private boolean includeServerErrors;
public ErrorHandler() {
this(true);
}
/**
* @param includeServerErrors Whether to include server-side details in thrown
* exceptions if the information is available.
*/
public ErrorHandler(boolean includeServerErrors) {
this.includeServerErrors = includeServerErrors;
}
public boolean isIncludeServerErrors() {
return includeServerErrors;
}
public void setIncludeServerErrors(boolean includeServerErrors) {
this.includeServerErrors = includeServerErrors;
}
@SuppressWarnings({"unchecked", "ThrowableInstanceNeverThrown"})
public Response throwIfResponseFailed(Response response) throws RuntimeException {
if (response.getStatus() == SUCCESS) {
return response;
}
Class extends RuntimeException> outerErrorType =
errorCodes.getExceptionType(response.getStatus());
Object value = response.getValue();
String message = null;
Throwable cause = null;
if (value instanceof Map) {
Map rawErrorData = (Map) value;
try {
message = (String) rawErrorData.get(MESSAGE);
} catch (ClassCastException e) {
// Ok, try to recover gracefully.
message = String.valueOf(e);
}
@SuppressWarnings({"ThrowableResultOfMethodCallIgnored"})
Throwable serverError = rebuildServerError(rawErrorData);
// If serverError is null, then the server did not provide a className (only expected if
// the server is a Java process) or a stack trace. The lack of a className is OK, but
// not having a stacktrace really hurts our ability to debug problems.
if (serverError == null) {
if (includeServerErrors) {
// TODO: this should probably link to a wiki article with more info.
message += " (WARNING: The server did not provide any stacktrace information)";
}
} else if (!includeServerErrors) {
// TODO: wiki article with more info.
message += " (WARNING: The client has suppressed server-side stacktraces)";
} else {
cause = serverError;
}
if (rawErrorData.get(SCREEN_SHOT) != null) {
cause = new ScreenshotException(String.valueOf(rawErrorData.get(SCREEN_SHOT)), cause);
}
} else if (value != null) {
message = String.valueOf(value);
}
Throwable toThrow = createThrowable(outerErrorType,
new Class>[] { String.class, Throwable.class },
new Object[] { message, cause });
if (toThrow == null) {
toThrow = createThrowable(outerErrorType,
new Class>[] { String.class },
new Object[] { message });
}
if (toThrow == null) {
throw new WebDriverException(message, cause);
}
if (toThrow instanceof RuntimeException) {
throw (RuntimeException) toThrow;
} else {
throw new WebDriverException(toThrow);
}
}
@SuppressWarnings({"ErrorNotRethrown"})
private T createThrowable(
Class clazz, Class>[] parameterTypes, Object[] parameters) {
try {
Constructor constructor = clazz.getConstructor(parameterTypes);
return constructor.newInstance(parameters);
} catch (NoSuchMethodException e) {
// Do nothing - fall through.
} catch (InvocationTargetException e) {
// Do nothing - fall through.
} catch (InstantiationException e) {
// Do nothing - fall through.
} catch (IllegalAccessException e) {
// Do nothing - fall through.
} catch (OutOfMemoryError error) {
// It can happen...
}
return null;
}
private Throwable rebuildServerError(Map rawErrorData) {
if (!rawErrorData.containsKey(CLASS) && !rawErrorData.containsKey(STACK_TRACE)) {
// Not enough information for us to try to rebuild an error.
return null;
}
Throwable toReturn = null;
String message = (String) rawErrorData.get(MESSAGE);
if (rawErrorData.containsKey(CLASS)) {
String className = (String) rawErrorData.get(CLASS);
try {
Class clazz = Class.forName(className);
if (Throwable.class.isAssignableFrom(clazz)) {
@SuppressWarnings({"unchecked"})
Class extends Throwable> throwableType = (Class extends Throwable>) clazz;
toReturn = createThrowable(throwableType, new Class>[] { String.class },
new Object[] { message });
}
} catch (ClassNotFoundException ignored) {
// Ok, fall-through
}
}
if (toReturn == null) {
toReturn = new UnknownServerException(message);
}
// Note: if we have a class name above, we should always have a stack trace.
// The inverse is not always true.
StackTraceElement[] stackTrace = new StackTraceElement[0];
if (rawErrorData.containsKey(STACK_TRACE)) {
@SuppressWarnings({"unchecked"})
List
© 2015 - 2025 Weber Informatics LLC | Privacy Policy