mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 08:14:09 -08:00
Begin implementation of google chrome debugger backend
This commit is contained in:
parent
444c599b17
commit
0cb0bd469b
25
pom.xml
25
pom.xml
|
@ -65,8 +65,10 @@
|
|||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<html4j.version>0.7.5</html4j.version>
|
||||
<sonatypeOssDistMgmtSnapshotsUrl>https://oss.sonatype.org/content/repositories/snapshots/</sonatypeOssDistMgmtSnapshotsUrl>
|
||||
<html4j.version>0.7.5</html4j.version>
|
||||
<jetty.version>9.2.1.v20140609</jetty.version>
|
||||
<slf4j.version>1.7.7</slf4j.version>
|
||||
</properties>
|
||||
|
||||
<modules>
|
||||
|
@ -79,6 +81,7 @@
|
|||
<module>teavm-samples</module>
|
||||
<module>teavm-platform</module>
|
||||
<module>teavm-cli</module>
|
||||
<module>teavm-chrome-rdp</module>
|
||||
</modules>
|
||||
|
||||
<dependencyManagement>
|
||||
|
@ -134,6 +137,26 @@
|
|||
<artifactId>maven-core</artifactId>
|
||||
<version>3.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.websocket</groupId>
|
||||
<artifactId>javax.websocket-api</artifactId>
|
||||
<version>1.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-server</artifactId>
|
||||
<version>${jetty.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.websocket</groupId>
|
||||
<artifactId>javax-websocket-server-impl</artifactId>
|
||||
<version>${jetty.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
<version>${slf4j.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
|
|
4
teavm-chrome-rdp/.gitignore
vendored
Normal file
4
teavm-chrome-rdp/.gitignore
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
/target
|
||||
/.settings
|
||||
/.classpath
|
||||
/.project
|
88
teavm-chrome-rdp/pom.xml
Normal file
88
teavm-chrome-rdp/pom.xml
Normal file
|
@ -0,0 +1,88 @@
|
|||
<!--
|
||||
Copyright 2014 Alexey Andreev.
|
||||
|
||||
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.
|
||||
-->
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>org.teavm</groupId>
|
||||
<artifactId>teavm</artifactId>
|
||||
<version>0.2-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>teavm-chrome-rdp</artifactId>
|
||||
|
||||
<name>TeaVM debugging backend for Google Chrome RDP</name>
|
||||
<description>TeaVM debugging backend for Google Chrome RDP</description>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-server</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.websocket</groupId>
|
||||
<artifactId>javax-websocket-server-impl</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.teavm</groupId>
|
||||
<artifactId>teavm-core</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.websocket</groupId>
|
||||
<artifactId>javax.websocket-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-server</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.websocket</groupId>
|
||||
<artifactId>javax-websocket-server-impl</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.codehaus.jackson</groupId>
|
||||
<artifactId>jackson-core-asl</artifactId>
|
||||
<version>1.9.13</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.codehaus.jackson</groupId>
|
||||
<artifactId>jackson-mapper-asl</artifactId>
|
||||
<version>1.9.13</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-source-plugin</artifactId>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
|
@ -0,0 +1,202 @@
|
|||
/*
|
||||
* Copyright 2014 Alexey Andreev.
|
||||
*
|
||||
* 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 org.teavm.chromerpd;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import javax.websocket.OnMessage;
|
||||
import javax.websocket.OnOpen;
|
||||
import javax.websocket.Session;
|
||||
import javax.websocket.server.ServerEndpoint;
|
||||
import org.codehaus.jackson.JsonNode;
|
||||
import org.codehaus.jackson.JsonProcessingException;
|
||||
import org.codehaus.jackson.map.ObjectMapper;
|
||||
import org.teavm.chromerpd.data.CallFrameDTO;
|
||||
import org.teavm.chromerpd.data.LocationDTO;
|
||||
import org.teavm.chromerpd.data.Message;
|
||||
import org.teavm.chromerpd.messages.ContinueToLocationCommand;
|
||||
import org.teavm.chromerpd.messages.ScriptParsedNotification;
|
||||
import org.teavm.chromerpd.messages.SuspendedNotification;
|
||||
import org.teavm.debugging.*;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev
|
||||
*/
|
||||
@ServerEndpoint("/")
|
||||
public class ChromeRDPDebugger implements JavaScriptDebugger {
|
||||
private List<JavaScriptDebuggerListener> listeners = new ArrayList<>();
|
||||
private Session session;
|
||||
private RDPCallFrame[] callStack = new RDPCallFrame[0];
|
||||
private Map<String, String> scripts = new HashMap<>();
|
||||
private Map<String, String> scriptIds = new HashMap<>();
|
||||
private boolean suspended;
|
||||
private ObjectMapper mapper = new ObjectMapper();
|
||||
|
||||
@OnOpen
|
||||
public void open(Session session) {
|
||||
this.session = session;
|
||||
}
|
||||
|
||||
@OnMessage
|
||||
public void receive(String messageText) throws IOException {
|
||||
Message message = mapper.reader(Message.class).readValue(messageText);
|
||||
switch (message.getMethod()) {
|
||||
case "Debugger.paused":
|
||||
firePaused(parseJson(SuspendedNotification.class, message.getParams()));
|
||||
break;
|
||||
case "Debugger.resumed":
|
||||
fireResumed();
|
||||
break;
|
||||
case "Debugger.scriptParsed":
|
||||
scriptParsed(parseJson(ScriptParsedNotification.class, message.getParams()));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private <T> T parseJson(Class<T> type, JsonNode node) throws IOException {
|
||||
return mapper.reader(type).readValue(node);
|
||||
}
|
||||
|
||||
private void firePaused(SuspendedNotification params) {
|
||||
suspended = true;
|
||||
CallFrameDTO[] callFrameDTOs = params.getCallFrames();
|
||||
RDPCallFrame[] callFrames = new RDPCallFrame[callFrameDTOs.length];
|
||||
for (int i = 0; i < callFrames.length; ++i) {
|
||||
callFrames[i] = map(callFrameDTOs[i]);
|
||||
}
|
||||
for (JavaScriptDebuggerListener listener : listeners) {
|
||||
listener.paused();
|
||||
}
|
||||
}
|
||||
|
||||
RDPCallFrame map(CallFrameDTO dto) {
|
||||
return new RDPCallFrame(dto.getCallFrameId(), map(dto.getLocation()));
|
||||
}
|
||||
|
||||
JavaScriptLocation map(LocationDTO dto) {
|
||||
return new JavaScriptLocation(scripts.get(dto.getScriptId()), dto.getLineNumber(), dto.getColumnNumber());
|
||||
}
|
||||
|
||||
private void fireResumed() {
|
||||
suspended = false;
|
||||
for (JavaScriptDebuggerListener listener : listeners) {
|
||||
listener.resumed();
|
||||
}
|
||||
}
|
||||
|
||||
private void scriptParsed(ScriptParsedNotification params) {
|
||||
if (scripts.containsKey(params.getScriptId())) {
|
||||
return;
|
||||
}
|
||||
scripts.put(params.getScriptId(), params.getUrl());
|
||||
scriptIds.put(params.getUrl(), params.getScriptId());
|
||||
for (JavaScriptDebuggerListener listener : listeners) {
|
||||
listener.scriptAdded(params.getUrl());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addListener(JavaScriptDebuggerListener listener) {
|
||||
listeners.add(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeListener(JavaScriptDebuggerListener listener) {
|
||||
listeners.remove(listener);
|
||||
}
|
||||
|
||||
private void sendMessage(Message message) {
|
||||
try {
|
||||
String messageText = mapper.writer().writeValueAsString(message);
|
||||
session.getAsyncRemote().sendText(messageText);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void suspend() {
|
||||
Message message = new Message();
|
||||
message.setMethod("Debugger.pause");
|
||||
sendMessage(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resume() {
|
||||
Message message = new Message();
|
||||
message.setMethod("Debugger.resume");
|
||||
sendMessage(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stepInto() {
|
||||
Message message = new Message();
|
||||
message.setMethod("Debugger.stepInto");
|
||||
sendMessage(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stepOut() {
|
||||
Message message = new Message();
|
||||
message.setMethod("Debugger.stepOut");
|
||||
sendMessage(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stepOver() {
|
||||
Message message = new Message();
|
||||
message.setMethod("Debugger.stepOver");
|
||||
sendMessage(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void continueToLocation(JavaScriptLocation location) {
|
||||
Message message = new Message();
|
||||
message.setMethod("Debugger.continueToLocation");
|
||||
ContinueToLocationCommand params = new ContinueToLocationCommand();
|
||||
LocationDTO locationDTO = new LocationDTO();
|
||||
locationDTO.setScriptId(scriptIds.get(location.getScript()));
|
||||
locationDTO.setLineNumber(location.getLine());
|
||||
locationDTO.setColumnNumber(location.getColumn());
|
||||
params.setLocation(locationDTO);
|
||||
message.setParams(mapper.valueToTree(params));
|
||||
sendMessage(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSuspended() {
|
||||
return suspended;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JavaScriptCallFrame[] getCallStack() {
|
||||
return callStack;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JavaScriptBreakpoint getCurrentBreakpoint() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JavaScriptBreakpoint createBreakpoint(JavaScriptLocation location) {
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* Copyright 2014 Alexey Andreev.
|
||||
*
|
||||
* 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 org.teavm.chromerpd;
|
||||
|
||||
import org.teavm.debugging.JavaScriptCallFrame;
|
||||
import org.teavm.debugging.JavaScriptLocation;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev
|
||||
*/
|
||||
public class RDPCallFrame implements JavaScriptCallFrame {
|
||||
private String chromeId;
|
||||
private JavaScriptLocation location;
|
||||
|
||||
public RDPCallFrame(String chromeId, JavaScriptLocation location) {
|
||||
this.chromeId = chromeId;
|
||||
this.location = location;
|
||||
}
|
||||
|
||||
public String getChromeId() {
|
||||
return chromeId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JavaScriptLocation getLocation() {
|
||||
return location;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Copyright 2014 Alexey Andreev.
|
||||
*
|
||||
* 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 org.teavm.chromerpd.data;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev
|
||||
*/
|
||||
public class CallFrameDTO {
|
||||
private String callFrameId;
|
||||
private LocationDTO location;
|
||||
|
||||
public String getCallFrameId() {
|
||||
return callFrameId;
|
||||
}
|
||||
|
||||
public void setCallFrameId(String callFrameId) {
|
||||
this.callFrameId = callFrameId;
|
||||
}
|
||||
|
||||
public LocationDTO getLocation() {
|
||||
return location;
|
||||
}
|
||||
|
||||
public void setLocation(LocationDTO location) {
|
||||
this.location = location;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Copyright 2014 Alexey Andreev.
|
||||
*
|
||||
* 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 org.teavm.chromerpd.data;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev
|
||||
*/
|
||||
public class LocationDTO {
|
||||
private int columnNumber;
|
||||
private int lineNumber;
|
||||
private String scriptId;
|
||||
|
||||
public int getColumnNumber() {
|
||||
return columnNumber;
|
||||
}
|
||||
|
||||
public void setColumnNumber(int columnNumber) {
|
||||
this.columnNumber = columnNumber;
|
||||
}
|
||||
|
||||
public int getLineNumber() {
|
||||
return lineNumber;
|
||||
}
|
||||
|
||||
public void setLineNumber(int lineNumber) {
|
||||
this.lineNumber = lineNumber;
|
||||
}
|
||||
|
||||
public String getScriptId() {
|
||||
return scriptId;
|
||||
}
|
||||
|
||||
public void setScriptId(String scriptId) {
|
||||
this.scriptId = scriptId;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* Copyright 2014 Alexey Andreev.
|
||||
*
|
||||
* 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 org.teavm.chromerpd.data;
|
||||
|
||||
import org.codehaus.jackson.JsonNode;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev
|
||||
*/
|
||||
public class Message {
|
||||
private String method;
|
||||
private JsonNode params;
|
||||
|
||||
public String getMethod() {
|
||||
return method;
|
||||
}
|
||||
|
||||
public void setMethod(String method) {
|
||||
this.method = method;
|
||||
}
|
||||
|
||||
public JsonNode getParams() {
|
||||
return params;
|
||||
}
|
||||
|
||||
public void setParams(JsonNode params) {
|
||||
this.params = params;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* Copyright 2014 Alexey Andreev.
|
||||
*
|
||||
* 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 org.teavm.chromerpd.messages;
|
||||
|
||||
import org.teavm.chromerpd.data.LocationDTO;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev
|
||||
*/
|
||||
public class ContinueToLocationCommand {
|
||||
private LocationDTO location;
|
||||
|
||||
public LocationDTO getLocation() {
|
||||
return location;
|
||||
}
|
||||
|
||||
public void setLocation(LocationDTO location) {
|
||||
this.location = location;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Copyright 2014 Alexey Andreev.
|
||||
*
|
||||
* 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 org.teavm.chromerpd.messages;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev
|
||||
*/
|
||||
public class ScriptParsedNotification {
|
||||
private String scriptId;
|
||||
private String url;
|
||||
|
||||
public String getScriptId() {
|
||||
return scriptId;
|
||||
}
|
||||
|
||||
public void setScriptId(String scriptId) {
|
||||
this.scriptId = scriptId;
|
||||
}
|
||||
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
public void setUrl(String url) {
|
||||
this.url = url;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* Copyright 2014 Alexey Andreev.
|
||||
*
|
||||
* 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 org.teavm.chromerpd.messages;
|
||||
|
||||
import org.codehaus.jackson.JsonNode;
|
||||
import org.teavm.chromerpd.data.CallFrameDTO;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev
|
||||
*/
|
||||
public class SuspendedNotification {
|
||||
private CallFrameDTO[] callFrames;
|
||||
private String reason;
|
||||
private JsonNode data;
|
||||
|
||||
public CallFrameDTO[] getCallFrames() {
|
||||
return callFrames;
|
||||
}
|
||||
|
||||
public void setCallFrames(CallFrameDTO[] callFrames) {
|
||||
this.callFrames = callFrames;
|
||||
}
|
||||
|
||||
public String getReason() {
|
||||
return reason;
|
||||
}
|
||||
|
||||
public void setReason(String reason) {
|
||||
this.reason = reason;
|
||||
}
|
||||
|
||||
public JsonNode getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
public void setData(JsonNode data) {
|
||||
this.data = data;
|
||||
}
|
||||
}
|
|
@ -41,6 +41,10 @@ public class DebugInformation {
|
|||
Mapping methodMapping;
|
||||
Mapping lineMapping;
|
||||
|
||||
public String[] getCoveredSourceFiles() {
|
||||
return fileNames.clone();
|
||||
}
|
||||
|
||||
public Collection<GeneratedLocation> getGeneratedLocations(String fileName, int line) {
|
||||
Integer fileIndex = fileNameMap.get(fileName);
|
||||
if (fileIndex == null) {
|
||||
|
@ -90,6 +94,10 @@ public class DebugInformation {
|
|||
return new MethodReference(className, MethodDescriptor.parse(method));
|
||||
}
|
||||
|
||||
public MethodReference getMethodAt(int line, int column) {
|
||||
return getMethodAt(new GeneratedLocation(line, column));
|
||||
}
|
||||
|
||||
private <T> T componentByKey(Mapping mapping, T[] values, GeneratedLocation location) {
|
||||
int keyIndex = indexByKey(mapping, location);
|
||||
int valueIndex = keyIndex >= 0 ? mapping.values[keyIndex] : -1;
|
||||
|
@ -106,7 +114,7 @@ public class DebugInformation {
|
|||
writer.write(this);
|
||||
}
|
||||
|
||||
public DebugInformation read(InputStream input) throws IOException {
|
||||
public static DebugInformation read(InputStream input) throws IOException {
|
||||
DebugInformationReader reader = new DebugInformationReader(input);
|
||||
return reader.read();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* Copyright 2014 Alexey Andreev.
|
||||
*
|
||||
* 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 org.teavm.debugging;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev
|
||||
*/
|
||||
public interface DebugInformationProvider {
|
||||
DebugInformation getDebugInformation(String script);
|
||||
}
|
|
@ -27,14 +27,17 @@ import org.teavm.model.MethodReference;
|
|||
public class Debugger {
|
||||
private List<DebuggerListener> listeners = new ArrayList<>();
|
||||
private JavaScriptDebugger javaScriptDebugger;
|
||||
private DebugInformation debugInformation;
|
||||
private DebugInformationProvider debugInformationProvider;
|
||||
private List<JavaScriptBreakpoint> temporaryJsBreakpoints = new ArrayList<>();
|
||||
private Map<String, DebugInformation> debugInformationMap = new HashMap<>();
|
||||
private Map<String, List<DebugInformation>> debugInformationFileMap = new HashMap<>();
|
||||
private Map<DebugInformation, String> scriptMap = new HashMap<>();
|
||||
Map<String, Breakpoint> breakpointMap = new HashMap<>();
|
||||
private CallFrame[] callStack;
|
||||
|
||||
public Debugger(JavaScriptDebugger javaScriptDebugger, DebugInformation debugInformation) {
|
||||
public Debugger(JavaScriptDebugger javaScriptDebugger, DebugInformationProvider debugInformationProvider) {
|
||||
this.javaScriptDebugger = javaScriptDebugger;
|
||||
this.debugInformation = debugInformation;
|
||||
this.debugInformationProvider = debugInformationProvider;
|
||||
javaScriptDebugger.addListener(javaScriptListener);
|
||||
}
|
||||
|
||||
|
@ -65,7 +68,6 @@ public class Debugger {
|
|||
if (!javaScriptDebugger.isSuspended()) {
|
||||
return;
|
||||
}
|
||||
// TODO: lookup all locations that are "out of" the current location and create temporary breakpoints
|
||||
javaScriptDebugger.stepOut();
|
||||
}
|
||||
|
||||
|
@ -74,20 +76,28 @@ public class Debugger {
|
|||
return;
|
||||
}
|
||||
javaScriptDebugger.stepOver();
|
||||
// TODO: lookup all locations that are "after" the current location and create temporary breakpoints
|
||||
}
|
||||
|
||||
private List<DebugInformation> debugInformationBySource(String sourceFile) {
|
||||
List<DebugInformation> list = debugInformationFileMap.get(sourceFile);
|
||||
return list != null ? list : Collections.<DebugInformation>emptyList();
|
||||
}
|
||||
|
||||
public void continueToLocation(String fileName, int line) {
|
||||
if (!javaScriptDebugger.isSuspended()) {
|
||||
return;
|
||||
}
|
||||
for (DebugInformation debugInformation : debugInformationBySource(fileName)) {
|
||||
Collection<GeneratedLocation> locations = debugInformation.getGeneratedLocations(fileName, line);
|
||||
for (GeneratedLocation location : locations) {
|
||||
JavaScriptBreakpoint jsBreakpoint = javaScriptDebugger.createBreakpoint(location);
|
||||
JavaScriptLocation jsLocation = new JavaScriptLocation(scriptMap.get(debugInformation),
|
||||
location.getLine(), location.getColumn());
|
||||
JavaScriptBreakpoint jsBreakpoint = javaScriptDebugger.createBreakpoint(jsLocation);
|
||||
if (jsBreakpoint != null) {
|
||||
temporaryJsBreakpoints.add(jsBreakpoint);
|
||||
}
|
||||
}
|
||||
}
|
||||
javaScriptDebugger.resume();
|
||||
}
|
||||
|
||||
|
@ -96,14 +106,18 @@ public class Debugger {
|
|||
}
|
||||
|
||||
public Breakpoint createBreakpoint(String fileName, int line) {
|
||||
Collection<GeneratedLocation> locations = debugInformation.getGeneratedLocations(fileName, line);
|
||||
List<JavaScriptBreakpoint> jsBreakpoints = new ArrayList<>();
|
||||
for (DebugInformation debugInformation : debugInformationBySource(fileName)) {
|
||||
Collection<GeneratedLocation> locations = debugInformation.getGeneratedLocations(fileName, line);
|
||||
for (GeneratedLocation location : locations) {
|
||||
JavaScriptBreakpoint jsBreakpoint = javaScriptDebugger.createBreakpoint(location);
|
||||
JavaScriptLocation jsLocation = new JavaScriptLocation(scriptMap.get(debugInformation),
|
||||
location.getLine(), location.getColumn());
|
||||
JavaScriptBreakpoint jsBreakpoint = javaScriptDebugger.createBreakpoint(jsLocation);
|
||||
if (jsBreakpoint != null) {
|
||||
jsBreakpoints.add(jsBreakpoint);
|
||||
}
|
||||
}
|
||||
}
|
||||
return !jsBreakpoints.isEmpty() ? new Breakpoint(this, jsBreakpoints, fileName, line) : null;
|
||||
}
|
||||
|
||||
|
@ -117,9 +131,17 @@ public class Debugger {
|
|||
List<CallFrame> frames = new ArrayList<>();
|
||||
boolean wasEmpty = false;
|
||||
for (JavaScriptCallFrame jsFrame : javaScriptDebugger.getCallStack()) {
|
||||
SourceLocation loc = debugInformation.getSourceLocation(jsFrame.getLocation());
|
||||
DebugInformation debugInformation = debugInformationMap.get(jsFrame.getLocation().getScript());
|
||||
SourceLocation loc;
|
||||
if (debugInformation != null) {
|
||||
loc = debugInformation.getSourceLocation(jsFrame.getLocation().getLine(),
|
||||
jsFrame.getLocation().getColumn());
|
||||
} else {
|
||||
loc = null;
|
||||
}
|
||||
boolean empty = loc == null || (loc.getFileName() == null && loc.getLine() < 0);
|
||||
MethodReference method = !empty ? debugInformation.getMethodAt(jsFrame.getLocation()) : null;
|
||||
MethodReference method = !empty ? debugInformation.getMethodAt(jsFrame.getLocation().getLine(),
|
||||
jsFrame.getLocation().getColumn()) : null;
|
||||
if (!empty || !wasEmpty) {
|
||||
frames.add(new CallFrame(loc, method));
|
||||
}
|
||||
|
@ -130,6 +152,23 @@ public class Debugger {
|
|||
return callStack.clone();
|
||||
}
|
||||
|
||||
private void addScript(String name) {
|
||||
if (debugInformationMap.containsKey(name)) {
|
||||
return;
|
||||
}
|
||||
DebugInformation debugInfo = debugInformationProvider.getDebugInformation(name);
|
||||
debugInformationMap.put(name, debugInfo);
|
||||
for (String sourceFile : debugInfo.getCoveredSourceFiles()) {
|
||||
List<DebugInformation> list = debugInformationFileMap.get(sourceFile);
|
||||
if (list == null) {
|
||||
list = new ArrayList<>();
|
||||
debugInformationFileMap.put(sourceFile, list);
|
||||
}
|
||||
list.add(debugInfo);
|
||||
}
|
||||
scriptMap.put(debugInfo, name);
|
||||
}
|
||||
|
||||
private JavaScriptDebuggerListener javaScriptListener = new JavaScriptDebuggerListener() {
|
||||
@Override
|
||||
public void resumed() {
|
||||
|
@ -148,5 +187,10 @@ public class Debugger {
|
|||
listener.paused();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void scriptAdded(String name) {
|
||||
addScript(name);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@ public interface JavaScriptBreakpoint {
|
|||
|
||||
String getFileName();
|
||||
|
||||
GeneratedLocation getLocation();
|
||||
JavaScriptLocation getLocation();
|
||||
|
||||
void destroy();
|
||||
}
|
||||
|
|
|
@ -20,5 +20,5 @@ package org.teavm.debugging;
|
|||
* @author Alexey Andreev
|
||||
*/
|
||||
public interface JavaScriptCallFrame {
|
||||
GeneratedLocation getLocation();
|
||||
JavaScriptLocation getLocation();
|
||||
}
|
||||
|
|
|
@ -34,7 +34,7 @@ public interface JavaScriptDebugger {
|
|||
|
||||
void stepOver();
|
||||
|
||||
void continueToLocation(GeneratedLocation location);
|
||||
void continueToLocation(JavaScriptLocation location);
|
||||
|
||||
boolean isSuspended();
|
||||
|
||||
|
@ -42,5 +42,5 @@ public interface JavaScriptDebugger {
|
|||
|
||||
JavaScriptBreakpoint getCurrentBreakpoint();
|
||||
|
||||
JavaScriptBreakpoint createBreakpoint(GeneratedLocation location);
|
||||
JavaScriptBreakpoint createBreakpoint(JavaScriptLocation location);
|
||||
}
|
||||
|
|
|
@ -23,4 +23,6 @@ public interface JavaScriptDebuggerListener {
|
|||
void paused();
|
||||
|
||||
void resumed();
|
||||
|
||||
void scriptAdded(String name);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Copyright 2014 Alexey Andreev.
|
||||
*
|
||||
* 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 org.teavm.debugging;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev
|
||||
*/
|
||||
public class JavaScriptLocation {
|
||||
private String script;
|
||||
private int line;
|
||||
private int column;
|
||||
|
||||
public JavaScriptLocation(String script, int line, int column) {
|
||||
this.script = script;
|
||||
this.line = line;
|
||||
this.column = column;
|
||||
}
|
||||
|
||||
public String getScript() {
|
||||
return script;
|
||||
}
|
||||
|
||||
public int getLine() {
|
||||
return line;
|
||||
}
|
||||
|
||||
public int getColumn() {
|
||||
return column;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Copyright 2014 Alexey Andreev.
|
||||
*
|
||||
* 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 org.teavm.debugging;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev
|
||||
*/
|
||||
public class URLDebugInformationProvider implements DebugInformationProvider {
|
||||
private String baseURL;
|
||||
|
||||
public URLDebugInformationProvider(String baseURL) {
|
||||
this.baseURL = baseURL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DebugInformation getDebugInformation(String script) {
|
||||
try {
|
||||
URL url = new URL(baseURL + script);
|
||||
try (InputStream input = url.openStream()) {
|
||||
return DebugInformation.read(input);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user