/*
* Copyright 2012-2014 eBay Software Foundation and selendroid committers.
*
* Licensed 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 io.selendroid.server.common;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.PrintWriter;
import java.io.StringWriter;
public class SelendroidResponse implements Response {
/**
* This is prepended to messages for failures caused by:
* <ul>
* <li>Selendroid itself (usually this is bug that must be fixed)
* <li>Unexpected conditions in the environment we're running in
* </ul>
* If a client sees this they know the error is not their fault.
*/
private static final String CATCH_ALL_ERROR_MESSAGE_PREFIX = "CATCH_ALL: ";
private String sessionId;
private int status;
private Object value;
private SelendroidResponse(String sessionId, int status, Throwable e) throws JSONException {
this.sessionId = sessionId;
this.status = status;
this.value = buildErrorValue(e, status);
}
private SelendroidResponse(String sessionId, int status, Throwable e, String messagePrefix) throws JSONException {
this.sessionId = sessionId;
this.status = status;
this.value = buildErrorValue(e, status, messagePrefix);
}
private SelendroidResponse(String sessionId, int status, Object value) {
this.sessionId = sessionId;
this.status = status;
this.value = value;
}
public SelendroidResponse(String sessionId, Object value) {
this(sessionId, 0, value);
}
public SelendroidResponse(String sessionId, StatusCode status, JSONObject value) {
this(sessionId, status.getCode(), value);
}
public SelendroidResponse(String sessionId, StatusCode status, Object value) {
this(sessionId, status.getCode(), value);
}
public SelendroidResponse(String sessionId, StatusCode status, Throwable e) throws JSONException {
this(sessionId, status.getCode(), e);
}
/**
* It is currently hard to detect whether a test failed because of a legitimate
* error by a developer or because something is going wrong in selendroid
* internals. This response marks error responses from the server that indicate
* something has gone wrong in the internals of selendroid.
*/
public static SelendroidResponse forCatchAllError(String sessionId, Throwable e) {
try {
return new SelendroidResponse(sessionId, StatusCode.UNKNOWN_ERROR.getCode(), e, CATCH_ALL_ERROR_MESSAGE_PREFIX);
} catch (JSONException err) {
return new SelendroidResponse(sessionId, StatusCode.UNKNOWN_ERROR.getCode());
}
}
@Override
public String getSessionId() {
return sessionId;
}
public int getStatus() {
return status;
}
public Object getValue() {
return value;
}
@Override
public String render() {
JSONObject o = new JSONObject();
try {
if (sessionId != null) {
o.put("sessionId", sessionId);
}
o.put("status", status);
if (value != null) {
o.put("value", value);
}
} catch (JSONException e) {
System.out.println("Cannot render response: " + e.getMessage());
}
return o.toString();
}
private JSONObject buildErrorValue(Throwable e, int status) throws JSONException {
return buildErrorValue(e, status, null);
}
private JSONObject buildErrorValue(Throwable e, int status, String messagePrefix) throws JSONException {
JSONObject errorValue = new JSONObject();
errorValue.put("class", e.getClass().getCanonicalName());
StringWriter stringWriter = new StringWriter();
PrintWriter printWriter = new PrintWriter(stringWriter);
if (messagePrefix != null) {
printWriter.append(messagePrefix);
}
// Also include the Selendroid stack trace. Only do this in case of unknown errors for easier debugging.
// In case of an expected error the stack trace is unnecessary and users often find it confusing.
if (status == StatusCode.UNKNOWN_ERROR.getCode()) {
e.printStackTrace(printWriter);
} else {
printWriter.append(e.getMessage());
}
errorValue.put("message", stringWriter.toString());
/*
The WebDriver protocol does not define a way to add exception stack traces to responses.
The workaround above puts the stack trace in the response message.
Apparently Selenium's BeanToJsonConverter would also work.
JSONArray stackTrace = new JSONArray();
for (StackTraceElement el : t.getStackTrace()) {
JSONObject frame = new JSONObject();
frame.put("lineNumber", el.getLineNumber());
frame.put("className", el.getClassName());
frame.put("methodName", el.getMethodName());
frame.put("fileName", el.getFileName());
stackTrace.put(frame);
}
errorValue.put("stackTrace", stackTrace);
*/
return errorValue;
}
}