/*
* Copyright (c) 2012, the Dart project authors.
*
* Licensed under the Eclipse Public License v1.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.eclipse.org/legal/epl-v10.html
*
* 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 com.github.sdbg.debug.core.internal.webkit.protocol;
import com.github.sdbg.debug.core.internal.webkit.protocol.WebkitConnection.NotificationHandler;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
/**
* A WIP console domain object.
* <p>
* Console domain defines methods and events for interaction with the JavaScript console. Console
* collects messages created by means of the JavaScript Console API. One needs to enable this domain
* using enable command in order to start receiving the console messages. Browser collects messages
* issued while console domain is not enabled as well and reports them using messageAdded
* notification upon enabling.
*/
public class WebkitConsole extends WebkitDomain {
public static class CallFrame {
/** JavaScript script column number. */
public int columnNumber;
/** JavaScript function name. */
public String functionName;
/** JavaScript script line number. */
public int lineNumber;
/** JavaScript script name or url. */
public String url;
static List<CallFrame> createFrom(JSONArray arr) throws JSONException {
if (arr == null) {
return null;
}
List<CallFrame> frames = new ArrayList<WebkitConsole.CallFrame>(arr.length());
for (int i = 0; i < arr.length(); i++) {
frames.add(CallFrame.createFrom(arr.getJSONObject(i)));
}
return frames;
}
static CallFrame createFrom(JSONObject obj) throws JSONException {
CallFrame frame = new CallFrame();
frame.columnNumber = obj.getInt("columnNumber");
frame.functionName = obj.getString("functionName");
frame.lineNumber = obj.getInt("lineNumber");
frame.url = obj.getString("url");
return frame;
}
@Override
public String toString() {
return functionName + "()";
}
}
public static interface ConsoleListener {
/**
* Issued when new console message is added.
*
* @param message
* @param url an optional parameter indicating the source url
* @param line line number in the resource that generated this message
* @param stackTrace the optional stack trace associated with this message
*/
public void messageAdded(String message, String url, int line, List<CallFrame> stackTrace);
/**
* Issued when subsequent message(s) are equal to the previous one(s).
*
* @param count new repeat count value
*/
public void messageRepeatCountUpdated(int count);
/**
* Issued when console is cleared. This happens either upon clearMessages command or after page
* navigation.
*/
public void messagesCleared();
}
private static final String MESSAGE_ADDED = "Console.messageAdded";
private static final String MESSAGE_CLEARED = "Console.messagesCleared";
private static final String MESSAGE_COUNT_UPDATED = "Console.messageRepeatCountUpdated";
private List<ConsoleListener> listeners = new ArrayList<ConsoleListener>();
public WebkitConsole(WebkitConnection connection) {
super(connection);
connection.registerNotificationHandler("Console.", new NotificationHandler() {
@Override
public void handleNotification(String method, JSONObject params) throws JSONException {
handleConsoleNotification(method, params);
}
});
}
public void addConsoleListener(ConsoleListener listener) {
listeners.add(listener);
}
public void disable() throws IOException {
sendSimpleCommand("Console.disable");
}
public void enable() throws IOException {
sendSimpleCommand("Console.enable");
}
public void removeConsoleListener(ConsoleListener listener) {
listeners.remove(listener);
}
/**
* Toggles monitoring of XMLHttpRequest. If <code>true</code>, console will receive messages upon
* each XHR issued.
*
* @param enabled Monitoring enabled state
* @throws IOException
*/
@WebkitUnsupported
public void setMonitoringXHREnabled(boolean enabled) throws IOException {
try {
JSONObject request = new JSONObject();
request.put("method", "Console.setMonitoringXHREnabled");
request.put("params", new JSONObject().put("enabled", enabled));
connection.sendRequest(request);
} catch (JSONException exception) {
throw new IOException(exception);
}
}
@SuppressWarnings("unused")
protected void handleConsoleNotification(String method, JSONObject params) throws JSONException {
if (method.equals(MESSAGE_ADDED)) {
JSONObject message = params.getJSONObject("message");
String text = message.getString("text");
String url = message.optString("url");
/** Line number in the resource that generated this message. */
int line = message.optInt("line", -1);
/** Message severity. */
String level = message.optString("level");
/** Message source. */
String source = message.optString("source");
/** JavaScript stack trace for assertions and error messages. */
List<CallFrame> stackTrace = null;
// Only include the stack trace if the log level is "error".
if ("error".equals(level)) {
stackTrace = CallFrame.createFrom(message.optJSONArray("stackTrace"));
}
for (ConsoleListener listener : listeners) {
listener.messageAdded(text, url, line, stackTrace);
}
} else if (method.equals(MESSAGE_CLEARED)) {
for (ConsoleListener listener : listeners) {
listener.messagesCleared();
}
} else if (method.equals(MESSAGE_COUNT_UPDATED)) {
for (ConsoleListener listener : listeners) {
listener.messageRepeatCountUpdated(params.getInt("count"));
}
} else {
WIPTrace.trace("unhandled notification: " + method);
}
}
}