Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@

import com.google.gson.JsonElement;
import com.microsoft.java.debug.core.adapter.AdapterUtils;
import com.microsoft.java.debug.core.adapter.JsonUtils;
import com.microsoft.java.debug.core.adapter.Messages.Request;
import com.microsoft.java.debug.core.adapter.Messages.Response;
import com.microsoft.java.debug.core.protocol.JsonUtils;
import com.microsoft.java.debug.core.protocol.Messages.Request;
import com.microsoft.java.debug.core.protocol.Messages.Response;
import com.sun.jdi.event.Event;

public class UsageDataSession {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
import java.util.Map;
import java.util.concurrent.ConcurrentLinkedQueue;

import com.microsoft.java.debug.core.adapter.JsonUtils;
import com.microsoft.java.debug.core.protocol.JsonUtils;

public class UsageDataStore {
private ConcurrentLinkedQueue<Object> queue;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@

import org.apache.commons.lang3.StringUtils;

import com.microsoft.java.debug.core.adapter.Messages.Response;
import com.microsoft.java.debug.core.protocol.Messages.Response;
import com.microsoft.java.debug.core.protocol.Responses;
import com.microsoft.java.debug.core.protocol.Types;

public class AdapterUtils {
private static final String OS_NAME = System.getProperty("os.name", "").toLowerCase();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,6 @@
import java.util.logging.Logger;

import com.microsoft.java.debug.core.Configuration;
import com.microsoft.java.debug.core.adapter.Requests.Arguments;
import com.microsoft.java.debug.core.adapter.Requests.Command;
import com.microsoft.java.debug.core.adapter.handler.AttachRequestHandler;
import com.microsoft.java.debug.core.adapter.handler.ConfigurationDoneRequestHandler;
import com.microsoft.java.debug.core.adapter.handler.DisconnectRequestHandler;
Expand All @@ -36,6 +34,11 @@
import com.microsoft.java.debug.core.adapter.handler.StackTraceRequestHandler;
import com.microsoft.java.debug.core.adapter.handler.ThreadsRequestHandler;
import com.microsoft.java.debug.core.adapter.handler.VariablesRequestHandler;
import com.microsoft.java.debug.core.protocol.Events;
import com.microsoft.java.debug.core.protocol.JsonUtils;
import com.microsoft.java.debug.core.protocol.Messages;
import com.microsoft.java.debug.core.protocol.Requests.Arguments;
import com.microsoft.java.debug.core.protocol.Requests.Command;

public class DebugAdapter implements IDebugAdapter {
private static final Logger logger = Logger.getLogger(Configuration.LOGGER_NAME);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@
import java.util.Map;

import com.microsoft.java.debug.core.IDebugSession;
import com.microsoft.java.debug.core.adapter.Events.DebugEvent;
import com.microsoft.java.debug.core.adapter.variables.IVariableFormatter;
import com.microsoft.java.debug.core.adapter.variables.VariableFormatterFactory;
import com.microsoft.java.debug.core.protocol.Events.DebugEvent;

public class DebugAdapterContext implements IDebugAdapterContext {
private static final int MAX_CACHE_ITEMS = 10000;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@

package com.microsoft.java.debug.core.adapter;

import com.microsoft.java.debug.core.protocol.Messages;

public interface IDebugAdapter {
Messages.Response dispatchRequest(Messages.Request request);
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

import com.microsoft.java.debug.core.IDebugSession;
import com.microsoft.java.debug.core.adapter.variables.IVariableFormatter;
import com.microsoft.java.debug.core.protocol.Events;

public interface IDebugAdapterContext {
/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@

import java.util.List;

import com.microsoft.java.debug.core.protocol.Messages;
import com.microsoft.java.debug.core.protocol.Requests;

public interface IDebugRequestHandler {
List<Requests.Command> getTargetCommands();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,48 +11,15 @@

package com.microsoft.java.debug.core.adapter;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.Reader;
import java.io.Writer;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import com.microsoft.java.debug.core.Configuration;
import com.microsoft.java.debug.core.UsageDataSession;
import com.microsoft.java.debug.core.protocol.AbstractProtocolServer;
import com.microsoft.java.debug.core.protocol.Messages;

public class ProtocolServer {
private static final Logger logger = Logger.getLogger(Configuration.LOGGER_NAME);
private static final int BUFFER_SIZE = 4096;
private static final String TWO_CRLF = "\r\n\r\n";
private static final Pattern CONTENT_LENGTH_MATCHER = Pattern.compile("Content-Length: (\\d+)");
private static final Charset PROTOCOL_ENCODING = StandardCharsets.UTF_8; // vscode protocol uses UTF-8 as encoding format.

private Reader reader;
private Writer writer;

private ByteBuffer rawData;
private boolean terminateSession = false;
private int contentLength = -1;
private AtomicInteger sequenceNumber = new AtomicInteger(1);

private boolean isDispatchingData;
private ConcurrentLinkedQueue<Messages.Event> eventQueue;

public class ProtocolServer extends AbstractProtocolServer {
private IDebugAdapter debugAdapter;

private UsageDataSession usageDataSession = new UsageDataSession();

/**
Expand All @@ -65,18 +32,14 @@ public class ProtocolServer {
* provider context for a series of provider implementation
*/
public ProtocolServer(InputStream input, OutputStream output, IProviderContext context) {
this.reader = new BufferedReader(new InputStreamReader(input, PROTOCOL_ENCODING));
this.writer = new PrintWriter(new BufferedWriter(new OutputStreamWriter(output, PROTOCOL_ENCODING)));
this.contentLength = -1;
this.rawData = new ByteBuffer();
this.eventQueue = new ConcurrentLinkedQueue<>();
super(input, output);
this.debugAdapter = new DebugAdapter((debugEvent, willSendLater) -> {
// If the protocolServer has been stopped, it'll no longer receive any event.
if (!terminateSession) {
if (willSendLater) {
this.sendEventLater(debugEvent.type, debugEvent);
sendEventLater(debugEvent.type, debugEvent);
} else {
this.sendEvent(debugEvent.type, debugEvent);
sendEvent(debugEvent.type, debugEvent);
}
}
}, context);
Expand All @@ -87,178 +50,25 @@ public ProtocolServer(InputStream input, OutputStream output, IProviderContext c
*/
public void start() {
usageDataSession.reportStart();
char[] buffer = new char[BUFFER_SIZE];
try {
while (!this.terminateSession) {
int read = this.reader.read(buffer, 0, BUFFER_SIZE);
if (read == -1) {
break;
}

this.rawData.append(new String(buffer, 0, read).getBytes(PROTOCOL_ENCODING));
this.processData();
}
} catch (IOException e) {
logger.log(Level.SEVERE, String.format("Read data from io exception: %s", e.toString()), e);
}
super.start();
}

/**
* Sets terminateSession flag to true. And the dispatcher loop will be terminated after current dispatching operation finishes.
*/
public void stop() {
usageDataSession.reportStop();
this.terminateSession = true;
super.stop();
usageDataSession.submitUsageData();
}

/**
* Send event to DA immediately.
* @param eventType
* event type
* @param body
* event body
*/
private void sendEvent(String eventType, Object body) {
sendMessage(new Messages.Event(eventType, body));
}

/**
* If the the dispatcher is idle, then send the event immediately.
* Else add the new event to an eventQueue first and send them when dispatcher becomes idle again.
* @param eventType
* event type
* @param body
* event content
*/
private void sendEventLater(String eventType, Object body) {
synchronized (this) {
if (this.isDispatchingData) {
this.eventQueue.offer(new Messages.Event(eventType, body));
} else {
sendMessage(new Messages.Event(eventType, body));
}
protected void dispatchRequest(Messages.Request request) {
Messages.Response response = this.debugAdapter.dispatchRequest(request);
if (request.command.equals("disconnect")) {
stop();
}
sendMessage(response);
usageDataSession.recordResponse(response);
}

private void sendMessage(Messages.ProtocolMessage message) {
message.seq = this.sequenceNumber.getAndIncrement();

String jsonMessage = JsonUtils.toJson(message);
byte[] jsonBytes = jsonMessage.getBytes(PROTOCOL_ENCODING);

String header = String.format("Content-Length: %d%s", jsonBytes.length, TWO_CRLF);
byte[] headerBytes = header.getBytes(PROTOCOL_ENCODING);

byte[] data = new byte[headerBytes.length + jsonBytes.length];
System.arraycopy(headerBytes, 0, data, 0, headerBytes.length);
System.arraycopy(jsonBytes, 0, data, headerBytes.length, jsonBytes.length);

String utf8Data = new String(data, PROTOCOL_ENCODING);

try {
logger.fine("\n[[RESPONSE]]\n" + new String(data));
this.writer.write(utf8Data);
this.writer.flush();
} catch (IOException e) {
logger.log(Level.SEVERE, String.format("Write data to io exception: %s", e.toString()), e);
}
}

private void processData() {
while (true) {
/**
* In vscode debug protocol, the content length represents the message's byte length with utf8 format.
*/
if (this.contentLength >= 0) {
if (this.rawData.length() >= this.contentLength) {
byte[] buf = this.rawData.removeFirst(this.contentLength);
this.contentLength = -1;
dispatchRequest(new String(buf, PROTOCOL_ENCODING));
continue;
}
} else {
String rawMessage = this.rawData.getString(PROTOCOL_ENCODING);
int idx = rawMessage.indexOf(TWO_CRLF);
if (idx != -1) {
Matcher matcher = CONTENT_LENGTH_MATCHER.matcher(rawMessage);
if (matcher.find()) {
this.contentLength = Integer.parseInt(matcher.group(1));
int headerByteLength = rawMessage.substring(0, idx + TWO_CRLF.length()).getBytes(PROTOCOL_ENCODING).length;
this.rawData.removeFirst(headerByteLength); // Remove the header from the raw message.
continue;
}
}
}
break;
}
}

private void dispatchRequest(String request) {
try {
logger.fine("\n[REQUEST]\n" + request);
Messages.Request message = JsonUtils.fromJson(request, Messages.Request.class);
usageDataSession.recordRequest(message);
if (message.type.equals("request")) {
synchronized (this) {
this.isDispatchingData = true;
}

try {
Messages.Response response = this.debugAdapter.dispatchRequest(message);
if (message.command.equals("disconnect")) {
this.stop();
}
sendMessage(response);
usageDataSession.recordResponse(response);
} catch (Exception e) {
logger.log(Level.SEVERE, String.format("Dispatch debug protocol error: %s", e.toString()), e);
}
}
} finally {
synchronized (this) {
this.isDispatchingData = false;
}

while (this.eventQueue.peek() != null) {
sendMessage(this.eventQueue.poll());
}
}
}

class ByteBuffer {
private byte[] buffer;

public ByteBuffer() {
this.buffer = new byte[0];
}

public int length() {
return this.buffer.length;
}

public String getString(Charset cs) {
return new String(this.buffer, cs);
}

public void append(byte[] b) {
append(b, b.length);
}

public void append(byte[] b, int length) {
byte[] newBuffer = new byte[this.buffer.length + length];
System.arraycopy(buffer, 0, newBuffer, 0, this.buffer.length);
System.arraycopy(b, 0, newBuffer, this.buffer.length, length);
this.buffer = newBuffer;
}

public byte[] removeFirst(int n) {
byte[] b = new byte[n];
System.arraycopy(this.buffer, 0, b, 0, n);
byte[] newBuffer = new byte[this.buffer.length - n];
System.arraycopy(this.buffer, n, newBuffer, 0, this.buffer.length - n);
this.buffer = newBuffer;
return b;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,10 @@
import com.microsoft.java.debug.core.adapter.IDebugRequestHandler;
import com.microsoft.java.debug.core.adapter.ISourceLookUpProvider;
import com.microsoft.java.debug.core.adapter.IVirtualMachineManagerProvider;
import com.microsoft.java.debug.core.adapter.Messages.Response;
import com.microsoft.java.debug.core.adapter.Requests.Arguments;
import com.microsoft.java.debug.core.adapter.Requests.AttachArguments;
import com.microsoft.java.debug.core.adapter.Requests.Command;
import com.microsoft.java.debug.core.protocol.Messages.Response;
import com.microsoft.java.debug.core.protocol.Requests.Arguments;
import com.microsoft.java.debug.core.protocol.Requests.AttachArguments;
import com.microsoft.java.debug.core.protocol.Requests.Command;
import com.sun.jdi.connect.IllegalConnectorArgumentsException;

public class AttachRequestHandler implements IDebugRequestHandler {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,12 @@
import com.microsoft.java.debug.core.UsageDataSession;
import com.microsoft.java.debug.core.adapter.AdapterUtils;
import com.microsoft.java.debug.core.adapter.ErrorCode;
import com.microsoft.java.debug.core.adapter.Events;
import com.microsoft.java.debug.core.adapter.IDebugAdapterContext;
import com.microsoft.java.debug.core.adapter.IDebugRequestHandler;
import com.microsoft.java.debug.core.adapter.Messages.Response;
import com.microsoft.java.debug.core.adapter.Requests.Arguments;
import com.microsoft.java.debug.core.adapter.Requests.Command;
import com.microsoft.java.debug.core.protocol.Events;
import com.microsoft.java.debug.core.protocol.Messages.Response;
import com.microsoft.java.debug.core.protocol.Requests.Arguments;
import com.microsoft.java.debug.core.protocol.Requests.Command;
import com.sun.jdi.ThreadReference;
import com.sun.jdi.event.BreakpointEvent;
import com.sun.jdi.event.Event;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@
import com.microsoft.java.debug.core.IDebugSession;
import com.microsoft.java.debug.core.adapter.IDebugAdapterContext;
import com.microsoft.java.debug.core.adapter.IDebugRequestHandler;
import com.microsoft.java.debug.core.adapter.Messages.Response;
import com.microsoft.java.debug.core.adapter.Requests.Arguments;
import com.microsoft.java.debug.core.adapter.Requests.Command;
import com.microsoft.java.debug.core.adapter.Requests.DisconnectArguments;
import com.microsoft.java.debug.core.protocol.Messages.Response;
import com.microsoft.java.debug.core.protocol.Requests.Arguments;
import com.microsoft.java.debug.core.protocol.Requests.Command;
import com.microsoft.java.debug.core.protocol.Requests.DisconnectArguments;

public class DisconnectRequestHandler implements IDebugRequestHandler {

Expand Down
Loading