mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-01-04 17:20:55 +07:00
Java REPL support for JDK9 (project Kulla, JShell) (IDEA-161611)
This commit is contained in:
13
java/execution/jshell-protocol/jshell-protocol.iml
Normal file
13
java/execution/jshell-protocol/jshell-protocol.iml
Normal file
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="JAVA_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/testStrc" isTestSource="true" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="library" scope="TEST" name="JUnit4" level="project" />
|
||||
</component>
|
||||
</module>
|
||||
@@ -0,0 +1,200 @@
|
||||
package com.intellij.execution.jshell.protocol;
|
||||
|
||||
import javax.xml.bind.annotation.XmlAttribute;
|
||||
import javax.xml.bind.annotation.XmlElement;
|
||||
import javax.xml.bind.annotation.XmlEnum;
|
||||
import javax.xml.bind.annotation.XmlType;
|
||||
|
||||
/**
|
||||
* @author Eugene Zhuravlev
|
||||
* Date: 14-Jun-17
|
||||
*/
|
||||
@XmlType
|
||||
public class CodeSnippet {
|
||||
|
||||
@XmlEnum
|
||||
public enum Status {
|
||||
VALID(true, true),
|
||||
RECOVERABLE_DEFINED(true, true),
|
||||
RECOVERABLE_NOT_DEFINED(true, false),
|
||||
DROPPED(false, false),
|
||||
OVERWRITTEN(false, false),
|
||||
REJECTED(false, false),
|
||||
NONEXISTENT(false, false),
|
||||
UNKNOWN (false, false);
|
||||
|
||||
private final boolean myIsActive;
|
||||
private final boolean myIsDefined;
|
||||
|
||||
Status(boolean isActive, boolean isDefined) {
|
||||
this.myIsActive = isActive;
|
||||
this.myIsDefined = isDefined;
|
||||
}
|
||||
|
||||
public boolean isActive() {
|
||||
return myIsActive;
|
||||
}
|
||||
|
||||
public boolean isDefined() {
|
||||
return myIsDefined;
|
||||
}
|
||||
}
|
||||
|
||||
@XmlEnum
|
||||
public enum Kind {
|
||||
IMPORT(true),
|
||||
TYPE_DECL(true),
|
||||
METHOD(true),
|
||||
VAR(true),
|
||||
EXPRESSION(false),
|
||||
STATEMENT(false),
|
||||
ERRONEOUS(false),
|
||||
UNKNOWN(false);
|
||||
|
||||
private final boolean isPersistent;
|
||||
Kind(boolean isPersistent) {
|
||||
this.isPersistent = isPersistent;
|
||||
}
|
||||
public boolean isPersistent() {
|
||||
return isPersistent;
|
||||
}
|
||||
}
|
||||
|
||||
@XmlEnum
|
||||
public enum SubKind {
|
||||
SINGLE_TYPE_IMPORT_SUBKIND(Kind.IMPORT),
|
||||
TYPE_IMPORT_ON_DEMAND_SUBKIND(Kind.IMPORT),
|
||||
SINGLE_STATIC_IMPORT_SUBKIND(Kind.IMPORT),
|
||||
STATIC_IMPORT_ON_DEMAND_SUBKIND(Kind.IMPORT),
|
||||
CLASS_SUBKIND(Kind.TYPE_DECL),
|
||||
INTERFACE_SUBKIND(Kind.TYPE_DECL),
|
||||
ENUM_SUBKIND(Kind.TYPE_DECL),
|
||||
ANNOTATION_TYPE_SUBKIND(Kind.TYPE_DECL),
|
||||
METHOD_SUBKIND(Kind.METHOD),
|
||||
VAR_DECLARATION_SUBKIND(Kind.VAR),
|
||||
VAR_DECLARATION_WITH_INITIALIZER_SUBKIND(Kind.VAR, true, true),
|
||||
TEMP_VAR_EXPRESSION_SUBKIND(Kind.VAR, true, true),
|
||||
VAR_VALUE_SUBKIND(Kind.EXPRESSION, true, true),
|
||||
ASSIGNMENT_SUBKIND(Kind.EXPRESSION, true, true),
|
||||
OTHER_EXPRESSION_SUBKIND(Kind.EXPRESSION, true, true),
|
||||
STATEMENT_SUBKIND(Kind.STATEMENT, true, false),
|
||||
UNKNOWN_SUBKIND(Kind.ERRONEOUS, false, false);
|
||||
|
||||
private final boolean isExecutable;
|
||||
private final boolean hasValue;
|
||||
private final Kind kind;
|
||||
|
||||
SubKind(Kind kind) {
|
||||
this.kind = kind;
|
||||
this.isExecutable = false;
|
||||
this.hasValue = false;
|
||||
}
|
||||
|
||||
SubKind(Kind kind, boolean isExecutable, boolean hasValue) {
|
||||
this.kind = kind;
|
||||
this.isExecutable = isExecutable;
|
||||
this.hasValue = hasValue;
|
||||
}
|
||||
|
||||
public boolean isExecutable() {
|
||||
return isExecutable;
|
||||
}
|
||||
|
||||
public boolean hasValue() {
|
||||
return hasValue;
|
||||
}
|
||||
|
||||
public Kind kind() {
|
||||
return kind;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private String myId;
|
||||
private Kind myKind;
|
||||
private SubKind mySubKind;
|
||||
private String myCodeText;
|
||||
private String myPresentation;
|
||||
|
||||
public CodeSnippet() {
|
||||
}
|
||||
|
||||
public CodeSnippet(String id, Kind kind, SubKind subKind, String codeText, String presentation) {
|
||||
myId = id;
|
||||
myKind = kind;
|
||||
mySubKind = subKind;
|
||||
myCodeText = codeText;
|
||||
myPresentation = presentation;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return myId;
|
||||
}
|
||||
|
||||
@XmlAttribute
|
||||
public void setId(String id) {
|
||||
myId = id;
|
||||
}
|
||||
|
||||
public Kind getKind() {
|
||||
return myKind;
|
||||
}
|
||||
|
||||
@XmlAttribute
|
||||
public void setKind(Kind kind) {
|
||||
myKind = kind;
|
||||
}
|
||||
|
||||
public SubKind getSubKind() {
|
||||
return mySubKind;
|
||||
}
|
||||
|
||||
@XmlAttribute
|
||||
public void setSubKind(SubKind subKind) {
|
||||
mySubKind = subKind;
|
||||
}
|
||||
|
||||
public String getCodeText() {
|
||||
return myCodeText;
|
||||
}
|
||||
|
||||
@XmlElement
|
||||
public void setCodeText(String codeText) {
|
||||
myCodeText = codeText;
|
||||
}
|
||||
|
||||
public String getPresentation() {
|
||||
return myPresentation;
|
||||
}
|
||||
|
||||
@XmlElement
|
||||
public void setPresentation(String presentation) {
|
||||
myPresentation = presentation;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
CodeSnippet snippet = (CodeSnippet)o;
|
||||
|
||||
if (myId != null ? !myId.equals(snippet.myId) : snippet.myId != null) return false;
|
||||
if (myKind != snippet.myKind) return false;
|
||||
if (mySubKind != snippet.mySubKind) return false;
|
||||
if (myCodeText != null ? !myCodeText.equals(snippet.myCodeText) : snippet.myCodeText != null) return false;
|
||||
if (myPresentation != null ? !myPresentation.equals(snippet.myPresentation) : snippet.myPresentation != null) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = myId != null ? myId.hashCode() : 0;
|
||||
result = 31 * result + (myKind != null ? myKind.hashCode() : 0);
|
||||
result = 31 * result + (mySubKind != null ? mySubKind.hashCode() : 0);
|
||||
result = 31 * result + (myCodeText != null ? myCodeText.hashCode() : 0);
|
||||
result = 31 * result + (myPresentation != null ? myPresentation.hashCode() : 0);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.intellij.execution.jshell.protocol;
|
||||
|
||||
/**
|
||||
* @author Eugene Zhuravlev
|
||||
* Date: 12-Jun-17
|
||||
*/
|
||||
public class Endpoint {
|
||||
public static final String MSG_BEGIN = "__#begin#__";
|
||||
public static final String MSG_END = "__#end#__";
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
package com.intellij.execution.jshell.protocol;
|
||||
|
||||
|
||||
import javax.xml.bind.annotation.XmlElement;
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
|
||||
/**
|
||||
* @author Eugene Zhuravlev
|
||||
* Date: 12-Jun-17
|
||||
*/
|
||||
@XmlRootElement
|
||||
public class Event {
|
||||
|
||||
private CodeSnippet myCauseSnippet;
|
||||
private CodeSnippet mySnippet;
|
||||
private CodeSnippet.Status myPreviousStatus;
|
||||
private CodeSnippet.Status myStatus;
|
||||
private String myValue;
|
||||
private String myExceptionText;
|
||||
private String myDiagnostic;
|
||||
|
||||
public Event() {
|
||||
}
|
||||
|
||||
public Event(CodeSnippet snippet, CodeSnippet causeSnippet,
|
||||
CodeSnippet.Status status, CodeSnippet.Status previousStatus,
|
||||
String value) {
|
||||
myCauseSnippet = causeSnippet;
|
||||
mySnippet = snippet;
|
||||
myPreviousStatus = previousStatus;
|
||||
myStatus = status;
|
||||
myValue = value;
|
||||
}
|
||||
|
||||
public CodeSnippet.Status getPreviousStatus() {
|
||||
return myPreviousStatus;
|
||||
}
|
||||
|
||||
@XmlElement
|
||||
public void setPreviousStatus(CodeSnippet.Status previousStatus) {
|
||||
myPreviousStatus = previousStatus;
|
||||
}
|
||||
|
||||
public CodeSnippet.Status getStatus() {
|
||||
return myStatus;
|
||||
}
|
||||
|
||||
@XmlElement
|
||||
public void setStatus(CodeSnippet.Status status) {
|
||||
myStatus = status;
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return myValue;
|
||||
}
|
||||
|
||||
@XmlElement
|
||||
public void setValue(String value) {
|
||||
myValue = value;
|
||||
}
|
||||
|
||||
public CodeSnippet getCauseSnippet() {
|
||||
return myCauseSnippet;
|
||||
}
|
||||
|
||||
@XmlElement
|
||||
public void setCauseSnippet(CodeSnippet causeSnippet) {
|
||||
myCauseSnippet = causeSnippet;
|
||||
}
|
||||
|
||||
public CodeSnippet getSnippet() {
|
||||
return mySnippet;
|
||||
}
|
||||
|
||||
@XmlElement
|
||||
public void setSnippet(CodeSnippet snippet) {
|
||||
mySnippet = snippet;
|
||||
}
|
||||
|
||||
public String getExceptionText() {
|
||||
return myExceptionText;
|
||||
}
|
||||
|
||||
@XmlElement
|
||||
public void setExceptionText(String exceptionText) {
|
||||
myExceptionText = exceptionText;
|
||||
}
|
||||
|
||||
public String getDiagnostic() {
|
||||
return myDiagnostic;
|
||||
}
|
||||
|
||||
@XmlElement
|
||||
public void setDiagnostic(String diagnostic) {
|
||||
myDiagnostic = diagnostic;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.intellij.execution.jshell.protocol;
|
||||
|
||||
import javax.xml.bind.annotation.XmlAttribute;
|
||||
|
||||
/**
|
||||
* @author Eugene Zhuravlev
|
||||
* Date: 12-Jun-17
|
||||
*/
|
||||
public abstract class Message {
|
||||
private String myUid;
|
||||
|
||||
public Message() {
|
||||
}
|
||||
|
||||
public Message(String uid) {
|
||||
myUid = uid;
|
||||
}
|
||||
|
||||
public String getUid() {
|
||||
return myUid;
|
||||
}
|
||||
|
||||
@XmlAttribute
|
||||
public void setUid(String uid) {
|
||||
myUid = uid;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package com.intellij.execution.jshell.protocol;
|
||||
|
||||
import javax.xml.bind.JAXBContext;
|
||||
import javax.xml.bind.JAXBException;
|
||||
import java.io.*;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* @author Eugene Zhuravlev
|
||||
* Date: 12-Jun-17
|
||||
*/
|
||||
public class MessageReader<T> extends Endpoint {
|
||||
private final BufferedReader myIn;
|
||||
private final JAXBContext myContext;
|
||||
|
||||
public MessageReader(InputStream input, Class<T> msgType) throws Exception {
|
||||
myIn = new BufferedReader(new InputStreamReader(input));
|
||||
myContext = JAXBContext.newInstance(msgType);
|
||||
}
|
||||
|
||||
public T receive(final Consumer<String> unparsedOutputSink) throws IOException {
|
||||
while (true) {
|
||||
String line = myIn.readLine();
|
||||
if (line == null) {
|
||||
return null;
|
||||
}
|
||||
if (MSG_BEGIN.equals(line)) {
|
||||
final StringBuilder buf = new StringBuilder();
|
||||
for (String body = myIn.readLine(); !MSG_END.equals(body.trim()); body = myIn.readLine()) {
|
||||
buf.append(body).append("\n");
|
||||
}
|
||||
try {
|
||||
//noinspection unchecked
|
||||
return (T)myContext.createUnmarshaller().unmarshal(new StringReader(buf.toString()));
|
||||
}
|
||||
catch (JAXBException e) {
|
||||
throw new IOException(e);
|
||||
}
|
||||
}
|
||||
else {
|
||||
unparsedOutputSink.accept(line + "\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package com.intellij.execution.jshell.protocol;
|
||||
|
||||
import javax.xml.bind.JAXBContext;
|
||||
import javax.xml.bind.JAXBException;
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
|
||||
/**
|
||||
* @author Eugene Zhuravlev
|
||||
* Date: 12-Jun-17
|
||||
*/
|
||||
public class MessageWriter<T extends Message> extends Endpoint {
|
||||
private final BufferedWriter myOut;
|
||||
private final JAXBContext myContext;
|
||||
|
||||
public MessageWriter(OutputStream output, Class<T> msgType) throws Exception {
|
||||
myOut = new BufferedWriter(new OutputStreamWriter(output));
|
||||
myContext = JAXBContext.newInstance(msgType);
|
||||
}
|
||||
|
||||
public void send(T message) throws IOException {
|
||||
try {
|
||||
myOut.newLine();
|
||||
myOut.write(MSG_BEGIN);
|
||||
myOut.newLine();
|
||||
myContext.createMarshaller().marshal(message, myOut);
|
||||
}
|
||||
catch (JAXBException e) {
|
||||
throw new IOException(e);
|
||||
}
|
||||
finally {
|
||||
myOut.newLine();
|
||||
myOut.write(MSG_END);
|
||||
myOut.newLine();
|
||||
myOut.flush();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package com.intellij.execution.jshell.protocol;
|
||||
|
||||
import javax.xml.bind.annotation.XmlElement;
|
||||
import javax.xml.bind.annotation.XmlEnum;
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
|
||||
/**
|
||||
* @author Eugene Zhuravlev
|
||||
* Date: 12-Jun-17
|
||||
*/
|
||||
@XmlRootElement
|
||||
public class Request extends Message{
|
||||
private Command myCommand;
|
||||
private String myCodeText;
|
||||
|
||||
@XmlEnum
|
||||
public enum Command{
|
||||
EVAL, DROP_STATE, EXIT
|
||||
}
|
||||
|
||||
public Request() {
|
||||
}
|
||||
|
||||
public Request(String uid, Command cmd, String codeText) {
|
||||
super(uid);
|
||||
myCommand = cmd;
|
||||
myCodeText = codeText;
|
||||
}
|
||||
|
||||
public Command getCommand() {
|
||||
return myCommand;
|
||||
}
|
||||
|
||||
@XmlElement
|
||||
public void setCommand(Command command) {
|
||||
myCommand = command;
|
||||
}
|
||||
|
||||
public String getCodeText() {
|
||||
return myCodeText;
|
||||
}
|
||||
|
||||
@XmlElement
|
||||
public void setCodeText(String codeText) {
|
||||
myCodeText = codeText;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package com.intellij.execution.jshell.protocol;
|
||||
|
||||
import com.sun.xml.internal.txw2.annotation.XmlElement;
|
||||
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Eugene Zhuravlev
|
||||
* Date: 12-Jun-17
|
||||
*/
|
||||
@XmlRootElement
|
||||
public class Response extends Message{
|
||||
private List<Event> myEvents;
|
||||
|
||||
public Response() {
|
||||
}
|
||||
|
||||
public Response(String uid, Event... events) {
|
||||
super(uid);
|
||||
Collections.addAll(myEvents = new ArrayList<>(), events);
|
||||
}
|
||||
|
||||
@XmlElement
|
||||
public List<Event> getEvents() {
|
||||
return myEvents;
|
||||
}
|
||||
|
||||
@XmlElement
|
||||
public void setEvents(List<Event> events) {
|
||||
myEvents = events;
|
||||
}
|
||||
|
||||
public void addEvent(Event event) {
|
||||
List<Event> events = myEvents;
|
||||
if (events == null) {
|
||||
events = new ArrayList<>();
|
||||
myEvents = events;
|
||||
}
|
||||
events.add(event);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
package com.intellij.execution.jshell.protocol;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import java.io.PipedInputStream;
|
||||
import java.io.PipedOutputStream;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* @author Eugene Zhuravlev
|
||||
* Date: 12-Jun-17
|
||||
*/
|
||||
public class JShellMessageMarshallingTest extends TestCase {
|
||||
|
||||
private static final Event[] EMPTY_EVENT_ARRAY = new Event[0];
|
||||
|
||||
public void testSendReceive() throws Exception {
|
||||
final PipedInputStream clientIn = new PipedInputStream();
|
||||
final PipedOutputStream serverOut = new PipedOutputStream(clientIn);
|
||||
|
||||
final PipedInputStream serverIn = new PipedInputStream();
|
||||
final PipedOutputStream clientOut = new PipedOutputStream(serverIn);
|
||||
|
||||
final MessageWriter<Request> clientWriter = new MessageWriter<>(clientOut, Request.class);
|
||||
final MessageReader<Request> serverReader = new MessageReader<>(serverIn, Request.class);
|
||||
final MessageWriter<Response> serverWriter = new MessageWriter<>(serverOut, Response.class);
|
||||
final MessageReader<Response> clientReader = new MessageReader<>(clientIn, Response.class);
|
||||
|
||||
final Request request = new Request(UUID.randomUUID().toString(), Request.Command.EVAL,
|
||||
"System.out.println(\"Hello, World!\");\n int var = 7 + 7;");
|
||||
clientWriter.send(request);
|
||||
final Request receivedRequest = serverReader.receive(s -> {});
|
||||
assertEquals(request.getUid(), receivedRequest.getUid());
|
||||
assertEquals(request.getCodeText(), receivedRequest.getCodeText());
|
||||
|
||||
final CodeSnippet snippet = new CodeSnippet("code-snippet-id", CodeSnippet.Kind.EXPRESSION, CodeSnippet.SubKind.OTHER_EXPRESSION_SUBKIND, "a+b", "expression:a+b");
|
||||
final Event event1 = new Event(null, null, CodeSnippet.Status.UNKNOWN, CodeSnippet.Status.NONEXISTENT, null);
|
||||
event1.setExceptionText("some exception");
|
||||
event1.setDiagnostic("error diagnostic");
|
||||
final Event event2 = new Event(snippet, null, CodeSnippet.Status.VALID, CodeSnippet.Status.NONEXISTENT, "14");
|
||||
final Response response = new Response(request.getUid(), event1, event2);
|
||||
serverWriter.send(response);
|
||||
|
||||
final Response receivedResponse = clientReader.receive(s -> {});
|
||||
assertEquals(response.getUid(), receivedResponse.getUid());
|
||||
final Event[] events = response.getEvents().toArray(EMPTY_EVENT_ARRAY);
|
||||
final Event[] receivedEvents = receivedResponse.getEvents().toArray(EMPTY_EVENT_ARRAY);
|
||||
|
||||
assertEquals(events.length, receivedEvents.length);
|
||||
for (int i = 0; i < events.length; i++) {
|
||||
final Event expectedEvent = events[i];
|
||||
final Event receivedEvent = receivedEvents[i];
|
||||
assertEquals(expectedEvent.getSnippet(), receivedEvent.getSnippet());
|
||||
assertEquals(expectedEvent.getCauseSnippet(), receivedEvent.getCauseSnippet());
|
||||
assertEquals(expectedEvent.getStatus(), receivedEvent.getStatus());
|
||||
assertEquals(expectedEvent.getPreviousStatus(), receivedEvent.getPreviousStatus());
|
||||
assertEquals(expectedEvent.getValue(), receivedEvent.getValue());
|
||||
assertEquals(expectedEvent.getExceptionText(), receivedEvent.getExceptionText());
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user