diff --git a/kernel/base/src/main/java/com/twosigma/beakerx/DefaultJVMVariables.java b/kernel/base/src/main/java/com/twosigma/beakerx/DefaultJVMVariables.java index e39f275f1c..b7069a39c0 100644 --- a/kernel/base/src/main/java/com/twosigma/beakerx/DefaultJVMVariables.java +++ b/kernel/base/src/main/java/com/twosigma/beakerx/DefaultJVMVariables.java @@ -43,6 +43,7 @@ public class DefaultJVMVariables { public DefaultJVMVariables() { addImports( "com.twosigma.beakerx.NamespaceClient", + "com.twosigma.beakerx.widgets.OutputManager", "com.twosigma.beakerx.chart.Color", "com.twosigma.beakerx.chart.GradientColor", "com.twosigma.beakerx.chart.legend.*", diff --git a/kernel/base/src/main/java/com/twosigma/beakerx/NamespaceClient.java b/kernel/base/src/main/java/com/twosigma/beakerx/NamespaceClient.java index 98135bf493..b1cb3ec399 100644 --- a/kernel/base/src/main/java/com/twosigma/beakerx/NamespaceClient.java +++ b/kernel/base/src/main/java/com/twosigma/beakerx/NamespaceClient.java @@ -25,6 +25,7 @@ import com.twosigma.beakerx.jvm.serialization.BasicObjectSerializer; import com.twosigma.beakerx.jvm.serialization.BeakerObjectConverter; import com.twosigma.beakerx.table.TableDisplayToJson; + import java.io.IOException; import java.io.Serializable; import java.io.StringWriter; @@ -35,10 +36,11 @@ import java.util.concurrent.SynchronousQueue; import static com.fasterxml.jackson.databind.SerializationFeature.WRITE_ENUMS_USING_TO_STRING; +import static com.twosigma.beakerx.kernel.msg.JupyterMessages.COMM_MSG; public class NamespaceClient { - - private static Map nsClients = new ConcurrentHashMap<>(); + + private static Map nsClients = new ConcurrentHashMap<>(); private static String currentSession; private static Map> messagePool = new HashMap<>(); private ObjectMapper objectMapper; @@ -68,14 +70,14 @@ public SimpleEvaluationObject getOutputObj() { public synchronized void setOutputObj(SimpleEvaluationObject input) { currentCeo = input; } - + public synchronized static NamespaceClient getBeaker() { - if (currentSession!=null){ + if (currentSession != null) { return nsClients.get(currentSession); } return null; } - + public synchronized static NamespaceClient getBeaker(String session) { currentSession = session; if (!nsClients.containsKey(session)) { @@ -83,7 +85,7 @@ public synchronized static NamespaceClient getBeaker(String session) { } return nsClients.get(currentSession); } - + public synchronized static void delBeaker(String sessionId) { nsClients.remove(sessionId); currentSession = null; @@ -98,12 +100,11 @@ public synchronized Object set(String name, Object value) throws IOException { state.put("sync", true); data.put("state", state); data.put("buffer_paths", new HashMap<>()); - c.setData(data); - c.send(); + c.send(COMM_MSG, Comm.Buffer.EMPTY, new Comm.Data(data)); return value; } - - protected String getJson(Object value) throws IOException{ + + protected String getJson(Object value) throws IOException { StringWriter sw = new StringWriter(); JsonGenerator jgen = objectMapper.getFactory().createGenerator(sw); objectSerializer.writeObject(value, jgen, true); @@ -114,17 +115,17 @@ protected String getJson(Object value) throws IOException{ //TODO : Not Implemented public Object setFast(String name, Object value) { - throw new RuntimeException("This option is not implemented now") ; + throw new RuntimeException("This option is not implemented now"); } //TODO : Not Implemented public Object unset(String name) { - throw new RuntimeException("This option is not implemented now") ; + throw new RuntimeException("This option is not implemented now"); } //TODO : Not Implemented public synchronized Object get(final String name) { - throw new RuntimeException("This option is not implemented now") ; + throw new RuntimeException("This option is not implemented now"); } public static SynchronousQueue getMessageQueue(String channel) { @@ -137,7 +138,7 @@ public static SynchronousQueue getMessageQueue(String channel) { } protected Comm getAutotranslationComm() { - if(autotranslationComm == null){ + if (autotranslationComm == null) { autotranslationComm = new Comm(TargetNamesEnum.BEAKER_AUTOTRANSLATION); autotranslationComm.open(); } @@ -145,21 +146,21 @@ protected Comm getAutotranslationComm() { } protected Comm getCodeCellsComm() { - if(codeCellsComm == null){ + if (codeCellsComm == null) { codeCellsComm = new Comm(TargetNamesEnum.BEAKER_GETCODECELLS); codeCellsComm.open(); } return codeCellsComm; } - + protected Comm getTagRunComm() { - if(tagRunComm == null){ + if (tagRunComm == null) { tagRunComm = new Comm(TargetNamesEnum.BEAKER_TAG_RUN); tagRunComm.open(); } return tagRunComm; } - + public List getCodeCells(String tagFilter) throws IOException, InterruptedException { // first send message to get cells @@ -170,11 +171,10 @@ public List getCodeCells(String tagFilter) throws IOException, Interru state.put("value", getJson(tagFilter)); data.put("state", state); data.put("buffer_paths", new HashMap<>()); - c.setData(data); - c.send(); + c.send(COMM_MSG, Comm.Buffer.EMPTY, new Comm.Data(data)); // block Object cells = getMessageQueue("CodeCells").take(); - return (List)cells; + return (List) cells; } public synchronized void runByTag(String tag) { @@ -184,8 +184,7 @@ public synchronized void runByTag(String tag) { state.put("runByTag", tag); data.put("state", state); data.put("buffer_paths", new HashMap<>()); - c.setData(data); - c.send(); + c.send(COMM_MSG, Comm.Buffer.EMPTY, new Comm.Data(data)); } } \ No newline at end of file diff --git a/kernel/base/src/main/java/com/twosigma/beakerx/evaluator/BaseEvaluator.java b/kernel/base/src/main/java/com/twosigma/beakerx/evaluator/BaseEvaluator.java index 2d9fe6e34c..15f72458ca 100644 --- a/kernel/base/src/main/java/com/twosigma/beakerx/evaluator/BaseEvaluator.java +++ b/kernel/base/src/main/java/com/twosigma/beakerx/evaluator/BaseEvaluator.java @@ -19,6 +19,7 @@ import com.twosigma.beakerx.DefaultJVMVariables; import com.twosigma.beakerx.NamespaceClient; import com.twosigma.beakerx.TryResult; +import com.twosigma.beakerx.jvm.object.SimpleEvaluationObject; import com.twosigma.beakerx.jvm.threads.CellExecutor; import com.twosigma.beakerx.kernel.AddImportStatus; import com.twosigma.beakerx.kernel.Classpath; @@ -38,6 +39,9 @@ import java.util.List; import java.util.Map; import java.util.concurrent.Callable; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; public abstract class BaseEvaluator implements Evaluator { @@ -51,6 +55,7 @@ public abstract class BaseEvaluator implements Evaluator { private final CellExecutor executor; private Path tempFolder; protected Repos repos; + protected ExecutorService executorService; public BaseEvaluator(String id, String sId, CellExecutor cellExecutor, TempFolderFactory tempFolderFactory, EvaluatorParameters evaluatorParameters) { shellId = id; @@ -61,9 +66,21 @@ public BaseEvaluator(String id, String sId, CellExecutor cellExecutor, TempFolde classPath = new Classpath(); classPath.add(new PathToJar(outDir)); repos = new Repos(); + executorService = Executors.newSingleThreadExecutor(); init(evaluatorParameters); } + protected TryResult evaluate(SimpleEvaluationObject seo, Callable callable) { + Future submit = executorService.submit(callable); + TryResult either = null; + try { + either = submit.get(); + } catch (Exception e) { + either = TryResult.createError(e.getLocalizedMessage()); + } + return either; + } + protected abstract void addJarToClassLoader(PathToJar pathToJar); protected abstract void addImportToClassLoader(ImportPath anImport); diff --git a/kernel/base/src/main/java/com/twosigma/beakerx/handler/KernelHandler.java b/kernel/base/src/main/java/com/twosigma/beakerx/handler/KernelHandler.java index f52c38d9cc..dc6d764519 100644 --- a/kernel/base/src/main/java/com/twosigma/beakerx/handler/KernelHandler.java +++ b/kernel/base/src/main/java/com/twosigma/beakerx/handler/KernelHandler.java @@ -18,6 +18,8 @@ import com.twosigma.beakerx.kernel.KernelFunctionality; import com.twosigma.beakerx.message.Message; +import java.util.Collections; + import static com.google.common.base.Preconditions.checkNotNull; public abstract class KernelHandler implements Handler { @@ -33,7 +35,7 @@ public void send(Message message) { } public void publish(Message message) { - kernel.publish(message); + kernel.publish(Collections.singletonList(message)); } public void exit() { diff --git a/kernel/base/src/main/java/com/twosigma/beakerx/jvm/object/SimpleEvaluationObject.java b/kernel/base/src/main/java/com/twosigma/beakerx/jvm/object/SimpleEvaluationObject.java index 8b66539c86..cc4ca6877b 100644 --- a/kernel/base/src/main/java/com/twosigma/beakerx/jvm/object/SimpleEvaluationObject.java +++ b/kernel/base/src/main/java/com/twosigma/beakerx/jvm/object/SimpleEvaluationObject.java @@ -23,19 +23,16 @@ import java.util.List; import java.util.Observable; import java.util.Queue; +import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentLinkedQueue; import com.twosigma.beakerx.message.Message; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; /** * Abstraction around an evaluation, for communication of the state over REST to the plugin. */ public class SimpleEvaluationObject extends Observable { - private final static Logger logger = LoggerFactory.getLogger(SimpleEvaluationObject.class.getName()); - private Message jupyterMessage; private int executionCount; private EvaluationStatus status; @@ -43,13 +40,22 @@ public class SimpleEvaluationObject extends Observable { private Object payload; private BeakerOutputHandler stdout; private BeakerOutputHandler stderr; - private Queue consoleOutput = new ConcurrentLinkedQueue(); + private Queue consoleOutput = new ConcurrentLinkedQueue<>(); private ProgressReporting progressReporting; private boolean showResult = true; + public SimpleEvaluationObject(String e, BeakerOutputHandler stdout, BeakerOutputHandler stderr) { + expression = e; + status = EvaluationStatus.QUEUED; + this.stdout = stdout; + this.stderr = stderr; + } + public SimpleEvaluationObject(String e) { expression = e; status = EvaluationStatus.QUEUED; + this.stdout = new SimpleOutputHandler(false); + this.stderr = new SimpleOutputHandler(true); } public boolean isShowResult() { @@ -57,7 +63,6 @@ public boolean isShowResult() { } public synchronized void started() { - setOutputHandler(); this.status = EvaluationStatus.RUNNING; setChanged(); notifyObservers(); @@ -71,7 +76,6 @@ public synchronized void finished(Object r) { notifyObservers(); } - public synchronized void error(Object r) { clrOutputHandler(); this.status = EvaluationStatus.ERROR; @@ -148,14 +152,10 @@ public void write(byte[] b, int off, int len) { } public synchronized BeakerOutputHandler getStdOutputHandler() { - if (stdout == null) - stdout = new SimpleOutputHandler(false); return stdout; } public synchronized BeakerOutputHandler getStdErrorHandler() { - if (stderr == null) - stderr = new SimpleOutputHandler(true); return stderr; } diff --git a/kernel/base/src/main/java/com/twosigma/beakerx/jvm/threads/BeakerStdOutErrHandler.java b/kernel/base/src/main/java/com/twosigma/beakerx/jvm/threads/BeakerStdOutErrHandler.java index 40a09ee0d3..dae65a9691 100644 --- a/kernel/base/src/main/java/com/twosigma/beakerx/jvm/threads/BeakerStdOutErrHandler.java +++ b/kernel/base/src/main/java/com/twosigma/beakerx/jvm/threads/BeakerStdOutErrHandler.java @@ -15,17 +15,25 @@ */ package com.twosigma.beakerx.jvm.threads; +import com.twosigma.beakerx.jvm.object.ConsoleOutput; +import com.twosigma.beakerx.widgets.Output; + import java.io.IOException; import java.io.OutputStream; import java.io.PrintStream; import java.io.UnsupportedEncodingException; import java.nio.charset.StandardCharsets; -import java.util.HashMap; -import java.util.Map; public class BeakerStdOutErrHandler { + private static BeakerStdOutErrHandler instance; + private PrintStream orig_out; + private PrintStream orig_err; + private BeakerOutputHandler out_handler; + private BeakerOutputHandler err_handler; + private Output outputWidget; + static synchronized public void init() { if (instance == null) { instance = new BeakerStdOutErrHandler(); @@ -41,13 +49,9 @@ static synchronized public void fini() { } static synchronized public void setOutputHandler(BeakerOutputHandler out, BeakerOutputHandler err) { - if (instance != null) + if (instance != null) { instance.theSetOutputHandler(out, err); - } - - static synchronized public void setDefaultOutputHandler(BeakerOutputHandler out, BeakerOutputHandler err) { - if (instance != null) - instance.theSetDefaultOutputHandler(out, err); + } } static synchronized public void clrOutputHandler() { @@ -55,39 +59,8 @@ static synchronized public void clrOutputHandler() { instance.theClrOutputHandler(); } - static synchronized public PrintStream out() { - if (instance != null && instance.orig_out!=null) - return instance.orig_out; - return System.out; - } - - static synchronized public PrintStream err() { - if (instance != null && instance.orig_err!=null) - return instance.orig_err; - return System.err; - } - - private PrintStream orig_out; - private PrintStream orig_err; - - private class MyOutputStream extends OutputStream { - private boolean is_out; - - public MyOutputStream(boolean isout) { - is_out = isout; - } - @Override - public void write(int b) throws IOException { - instance.write(is_out, b); - } - @Override - public void write(byte[] b) throws IOException { - instance.write(is_out, b); - } - @Override - public void write(byte[] b, int off, int len) throws IOException { - instance.write(is_out, b, off, len); - } + public static void setOuputWidget(Output out) { + instance.outputWidget = out; } private void theinit() { @@ -106,80 +79,99 @@ private void thefini() { System.setErr(orig_err); } - private class threadOutputHandler { - public BeakerOutputHandler out_handler; - public BeakerOutputHandler err_handler; - } - - private Map thrHandlers = new HashMap(); - private BeakerOutputHandler def_out; - private BeakerOutputHandler def_err; - private synchronized void theSetOutputHandler(BeakerOutputHandler out, BeakerOutputHandler err) { - long id = Thread.currentThread().getId(); - threadOutputHandler t; - if (!thrHandlers.containsKey(id)) { - t = new threadOutputHandler(); - thrHandlers.put(id, t); - } else { - t = thrHandlers.get(id); - } - t.out_handler = out; - t.err_handler = err; - } - - private synchronized void theSetDefaultOutputHandler(BeakerOutputHandler out, BeakerOutputHandler err) { - def_out = out; - def_err = err; + out_handler = out; + err_handler = err; } private synchronized void theClrOutputHandler() { - long id = Thread.currentThread().getId(); - thrHandlers.remove(id); + out_handler = null; + err_handler = null; } private BeakerOutputHandler getHandler(boolean out) { - long id = Thread.currentThread().getId(); - if (thrHandlers.containsKey(id)) { - threadOutputHandler t = thrHandlers.get(id); - if (out) - return t.out_handler; - return t.err_handler; - } else if (def_out!=null || def_err!=null) { - // WARNING: memory leak - we never clean up these if the thread exit - threadOutputHandler t = new threadOutputHandler(); - t.out_handler = def_out; - t.err_handler = def_err; - thrHandlers.put(id, t); + if (out_handler != null && err_handler != null) { + if (out) { + return out_handler; + } else { + return err_handler; + } } - if(out) - return def_out; - return def_err; + return null; } private synchronized void write(boolean isout, int b) throws IOException { - BeakerOutputHandler hdl = getHandler(isout); - if (hdl!=null) hdl.write(b); - else if(isout) - orig_out.write(b); - else - orig_err.write(b); + if (outputWidget != null) { + byte[] ba = new byte[1]; + ba[0] = (byte) b; + outputWidget.sendOutput(new ConsoleOutput(!isout, new String(ba, StandardCharsets.UTF_8))); + } else { + BeakerOutputHandler hdl = getHandler(isout); + if (hdl != null) { + hdl.write(b); + } else if (isout) { + orig_out.write(b); + } else { + orig_err.write(b); + } + } } + private synchronized void write(boolean isout, byte[] b) throws IOException { - BeakerOutputHandler hdl = getHandler(isout); - if (hdl!=null) hdl.write(b); - else if(isout) - orig_out.write(b); - else - orig_err.write(b); + if (outputWidget != null) { + outputWidget.sendOutput(new ConsoleOutput(!isout, new String(b, StandardCharsets.UTF_8))); + } else { + BeakerOutputHandler hdl = getHandler(isout); + if (hdl != null) hdl.write(b); + else if (isout) + orig_out.write(b); + else + orig_err.write(b); + } } + private synchronized void write(boolean isout, byte[] b, int off, int len) throws IOException { - BeakerOutputHandler hdl = getHandler(isout); - if (hdl != null) hdl.write(b, off, len); - else if (isout) - orig_out.write(b, off, len); - else - orig_err.write(b, off, len); + if (outputWidget != null) { + outputWidget.sendOutput(new ConsoleOutput(!isout, new String(b, off, len, StandardCharsets.UTF_8))); + } else { + BeakerOutputHandler hdl = getHandler(isout); + if (hdl != null) { + hdl.write(b, off, len); + } else if (isout) { + orig_out.write(b, off, len); + } else { + orig_err.write(b, off, len); + } + } + } + + public static void clearOutput() { + if (instance.outputWidget != null) { + instance.outputWidget.clearOutput(); + } + } + + private class MyOutputStream extends OutputStream { + private boolean is_out; + + public MyOutputStream(boolean isout) { + is_out = isout; + } + + @Override + public void write(int b) throws IOException { + instance.write(is_out, b); + } + + @Override + public void write(byte[] b) throws IOException { + instance.write(is_out, b); + } + + @Override + public void write(byte[] b, int off, int len) throws IOException { + instance.write(is_out, b, off, len); + } } } diff --git a/kernel/base/src/main/java/com/twosigma/beakerx/kernel/Kernel.java b/kernel/base/src/main/java/com/twosigma/beakerx/kernel/Kernel.java index cfd7db28a0..9d2e98fc63 100644 --- a/kernel/base/src/main/java/com/twosigma/beakerx/kernel/Kernel.java +++ b/kernel/base/src/main/java/com/twosigma/beakerx/kernel/Kernel.java @@ -16,6 +16,8 @@ package com.twosigma.beakerx.kernel; import static com.twosigma.beakerx.kernel.KernelSignalHandler.addSigIntHandler; +import static java.util.Arrays.asList; +import static java.util.Collections.singletonList; import com.twosigma.beakerx.BeakerxDefaultDisplayers; import com.twosigma.beakerx.DisplayerDataMapper; @@ -151,7 +153,7 @@ public synchronized void removeComm(String hash) { } } - public synchronized void publish(Message message) { + public synchronized void publish(List message) { this.kernelSockets.publish(message); } @@ -194,12 +196,12 @@ public List addJarsToClasspath(List paths) { @Override public void sendBusyMessage(Message message) { - publish(MessageCreator.createBusyMessage(message)); + publish(singletonList(MessageCreator.createBusyMessage(message))); } @Override public void sendIdleMessage(Message message) { - publish(MessageCreator.createIdleMessage(message)); + publish(singletonList(MessageCreator.createIdleMessage(message))); } @Override diff --git a/kernel/base/src/main/java/com/twosigma/beakerx/kernel/KernelFunctionality.java b/kernel/base/src/main/java/com/twosigma/beakerx/kernel/KernelFunctionality.java index 50a27d88ad..3c09fd8262 100644 --- a/kernel/base/src/main/java/com/twosigma/beakerx/kernel/KernelFunctionality.java +++ b/kernel/base/src/main/java/com/twosigma/beakerx/kernel/KernelFunctionality.java @@ -31,7 +31,7 @@ public interface KernelFunctionality { - void publish(Message message); + void publish(List message); void addComm(String commId, Comm comm); diff --git a/kernel/base/src/main/java/com/twosigma/beakerx/kernel/KernelSockets.java b/kernel/base/src/main/java/com/twosigma/beakerx/kernel/KernelSockets.java index 13f8c700f6..916bb7ab57 100644 --- a/kernel/base/src/main/java/com/twosigma/beakerx/kernel/KernelSockets.java +++ b/kernel/base/src/main/java/com/twosigma/beakerx/kernel/KernelSockets.java @@ -17,9 +17,11 @@ import com.twosigma.beakerx.message.Message; +import java.util.List; + public abstract class KernelSockets extends Thread { - public abstract void publish(Message message); + public abstract void publish(List message); public abstract void send(Message message); } diff --git a/kernel/base/src/main/java/com/twosigma/beakerx/kernel/Utils.java b/kernel/base/src/main/java/com/twosigma/beakerx/kernel/Utils.java index 77f4885900..e0ef343287 100644 --- a/kernel/base/src/main/java/com/twosigma/beakerx/kernel/Utils.java +++ b/kernel/base/src/main/java/com/twosigma/beakerx/kernel/Utils.java @@ -31,6 +31,10 @@ public class Utils { public static final String DATE_FORMAT = "yyyy-MM-dd'T'HH:mmZ"; public static final String EMPTY_STRING = ""; + private static UUIDStrategy UUID_STRATEGY_DEFAULT = () -> UUID.randomUUID().toString(); + + private static UUIDStrategy commUUIDStrategy = UUID_STRATEGY_DEFAULT; + public static String timestamp() { // SimpleDateFormat is not thread-safe so we need to create a new one for // each @@ -44,6 +48,10 @@ public static String uuid() { return UUID.randomUUID().toString(); } + public static String commUUID() { + return commUUIDStrategy.get(); + } + public static String getUsString(String[] input) { StringBuilder ret = new StringBuilder(); if (input != null && input.length > 0) { @@ -61,4 +69,23 @@ public static String getAsString(Collection input) { return getUsString(input.toArray(new String[input.size()])); } + private static int fixedUUIDCounter; + + public static synchronized void setFixedCommUUID(String uuid) { + fixedUUIDCounter = 0; + commUUIDStrategy = () -> { + fixedUUIDCounter++; + return uuid + fixedUUIDCounter; + }; + } + + public static synchronized void setDefaultCommUUID() { + commUUIDStrategy = UUID_STRATEGY_DEFAULT; + } + + interface UUIDStrategy { + String get(); + } + + } \ No newline at end of file diff --git a/kernel/base/src/main/java/com/twosigma/beakerx/kernel/comm/Comm.java b/kernel/base/src/main/java/com/twosigma/beakerx/kernel/comm/Comm.java index dac132f7c6..11194475e9 100644 --- a/kernel/base/src/main/java/com/twosigma/beakerx/kernel/comm/Comm.java +++ b/kernel/base/src/main/java/com/twosigma/beakerx/kernel/comm/Comm.java @@ -29,11 +29,13 @@ import java.util.Arrays; import java.util.HashMap; import java.util.List; +import java.util.Map; import static com.twosigma.beakerx.kernel.msg.JupyterMessages.COMM_CLOSE; import static com.twosigma.beakerx.kernel.msg.JupyterMessages.COMM_MSG; import static com.twosigma.beakerx.kernel.msg.JupyterMessages.COMM_OPEN; import static java.util.Collections.EMPTY_LIST; +import static java.util.Collections.singletonList; public class Comm { @@ -52,7 +54,7 @@ public class Comm { private String commId; private String targetName; - private HashMap data; + private Comm.Data data; private HashMap metadata; private String targetModule; private KernelFunctionality kernel; @@ -64,7 +66,7 @@ public Comm(String commId, String targetName) { this.kernel = KernelManager.get(); this.commId = commId; this.targetName = targetName; - this.data = new HashMap<>(); + this.data = new Comm.Data(new HashMap<>()); this.metadata = new HashMap<>(); } @@ -73,11 +75,11 @@ public Comm(String commId, TargetNamesEnum targetName) { } public Comm(TargetNamesEnum targetName) { - this(Utils.uuid(), targetName.getTargetName()); + this(Utils.commUUID(), targetName.getTargetName()); } public Comm(String targetName) { - this(Utils.uuid(), targetName); + this(Utils.commUUID(), targetName); } public String getCommId() { @@ -88,12 +90,12 @@ public String getTargetName() { return targetName; } - public HashMap getData() { - return data; + public Comm.Data getData() { + return new Comm.Data(new HashMap<>(data.getData())); } public void setData(HashMap data) { - this.data = data; + this.data = new Comm.Data(data); } public void setMetaData(HashMap metadata) { @@ -152,8 +154,8 @@ private void doOpen(Message parentMessage, Buffer buffer) { map.put(TARGET_NAME, getTargetName()); HashMap state = new HashMap<>(); - state.put(STATE, data); - state.put(METHOD, (Serializable) data.get(METHOD)); + state.put(STATE, data.getData()); + state.put(METHOD, (Serializable) data.getData().get(METHOD)); if (!buffer.isEmpty()) { state.put(BUFFER_PATHS, buffer.getBufferPaths()); message.setBuffers(buffer.getBuffers()); @@ -164,7 +166,7 @@ private void doOpen(Message parentMessage, Buffer buffer) { map.put(TARGET_MODULE, getTargetModule()); message.setContent(map); message.setMetadata(buildMetadata()); - kernel.publish(message); + kernel.publish(singletonList(message)); kernel.addComm(getCommId(), this); } @@ -189,42 +191,49 @@ public void close() { message.setMetadata(buildMetadata()); kernel.removeComm(getCommId()); - kernel.publish(message); + kernel.publish(singletonList(message)); } - public void send() { - send(COMM_MSG, Buffer.EMPTY); + public void send(Comm.Buffer buffer, Comm.Data data) { + send(COMM_MSG, buffer, data); } - public void send(Comm.Buffer buffer) { - send(COMM_MSG, buffer); + public void send(JupyterMessages type, Comm.Data data) { + send(type, Buffer.EMPTY, data); } - public void send(JupyterMessages type) { - send(type, Buffer.EMPTY); + public void send(JupyterMessages type, Comm.Buffer buffer, Comm.Data data) { + Message message = createMessage(type, buffer, data); + kernel.publish(singletonList(message)); } - public void send(JupyterMessages type, Comm.Buffer buffer) { + public Message createMessage(JupyterMessages type, Buffer buffer, Comm.Data data) { + HashMap map = new HashMap<>(6); + if (type != JupyterMessages.DISPLAY_DATA) { + map.put(COMM_ID, getCommId()); + } + map.put(DATA, data.getData()); + map.put(METADATA, metadata); + return create(type, buffer, map); + } + + private Message create(JupyterMessages type, Comm.Buffer buffer, Map content) { Message parentMessage = getParentMessage();// can be null Message message = new Message(); message.setHeader(new Header(type, parentMessage != null ? parentMessage.getHeader().getSession() : null)); if (parentMessage != null) { message.setParentHeader(getParentMessage().getHeader()); } - HashMap map = new HashMap<>(6); - - if (type != JupyterMessages.DISPLAY_DATA) { - map.put(COMM_ID, getCommId()); - } - - map.put(DATA, data); - map.put(METADATA, metadata); - message.setContent(map); + message.setContent(content); message.setMetadata(buildMetadata()); if (!buffer.isEmpty()) { message.setBuffers(buffer.getBuffers()); } - kernel.publish(message); + return message; + } + + public void publish(List list) { + kernel.publish(list); } public void sendUpdate(Comm.Buffer buffer) { @@ -233,19 +242,26 @@ public void sendUpdate(Comm.Buffer buffer) { HashMap state = new HashMap<>(); content.put(STATE, state); content.put(BUFFER_PATHS, buffer.getBufferPaths()); - this.setData(content); - this.send(buffer); + this.send(buffer, new Comm.Data(content)); + } + + public Message createOutputContent(final Map content) { + return this.create(JupyterMessages.STREAM, Buffer.EMPTY, content); } public void sendUpdate(final String propertyName, final Object value) { + Message message = createUpdateMessage(propertyName, value); + kernel.publish(singletonList(message)); + } + + public Message createUpdateMessage(String propertyName, Object value) { HashMap content = new HashMap<>(); content.put(METHOD, UPDATE); HashMap state = new HashMap<>(); state.put(propertyName, value); content.put(STATE, state); content.put(BUFFER_PATHS, new HashMap<>()); - this.setData(content); - this.send(); + return this.createMessage(COMM_MSG, Buffer.EMPTY, new Comm.Data(content)); } public void handleMsg(Message parentMessage) { @@ -276,6 +292,19 @@ interface GetParentMessageStrategy { Message getParentMessage(); } + public static class Data { + + private HashMap data; + + public Data(HashMap data) { + this.data = data; + } + + public HashMap getData() { + return data; + } + } + public static class Buffer { public final static Buffer EMPTY = new Buffer(EMPTY_LIST, new ArrayList<>()); diff --git a/kernel/base/src/main/java/com/twosigma/beakerx/kernel/handler/ExecuteRequestHandler.java b/kernel/base/src/main/java/com/twosigma/beakerx/kernel/handler/ExecuteRequestHandler.java index bdfe15a134..167847d514 100644 --- a/kernel/base/src/main/java/com/twosigma/beakerx/kernel/handler/ExecuteRequestHandler.java +++ b/kernel/base/src/main/java/com/twosigma/beakerx/kernel/handler/ExecuteRequestHandler.java @@ -30,6 +30,7 @@ import java.util.concurrent.Executors; import static com.twosigma.beakerx.kernel.msg.JupyterMessages.EXECUTE_INPUT; +import static java.util.Collections.singletonList; /** * Does the actual work of executing user code. @@ -82,7 +83,7 @@ private void announceTheCode(Message message, String code) { map1.put("execution_count", executionCount); map1.put("code", code); reply.setContent(map1); - kernel.publish(reply); + kernel.publish(singletonList(reply)); } @Override diff --git a/kernel/base/src/main/java/com/twosigma/beakerx/kernel/handler/MagicCommandExecutor.java b/kernel/base/src/main/java/com/twosigma/beakerx/kernel/handler/MagicCommandExecutor.java index ea88476726..a56d2d4043 100644 --- a/kernel/base/src/main/java/com/twosigma/beakerx/kernel/handler/MagicCommandExecutor.java +++ b/kernel/base/src/main/java/com/twosigma/beakerx/kernel/handler/MagicCommandExecutor.java @@ -21,6 +21,7 @@ import com.twosigma.beakerx.message.Message; import com.twosigma.beakerx.mimetype.MIMEContainer; +import java.util.Collections; import java.util.List; import static java.util.Collections.singletonList; @@ -55,10 +56,10 @@ private static void handleOkStatus(KernelFunctionality kernel, Message message, private static void publishOutcome(KernelFunctionality kernel, Message message, int executionCount, MagicCommandOutcomeItem item, boolean hasError) { if (item.getMIMEContainer().isPresent()) { if (item.getOutcome().equals(MagicCommandOutcomeItem.Outcome.OUTPUT)) { - kernel.publish(MessageCreator.buildOutputMessage(message, (String) item.getMIMEContainer().get().getData(), hasError)); + kernel.publish(Collections.singletonList(MessageCreator.buildOutputMessage(message, (String) item.getMIMEContainer().get().getData(), hasError))); } else { MIMEContainer mimeContainer = item.getMIMEContainer().get(); - kernel.publish(MessageCreator.buildMessage(message, singletonList(mimeContainer), executionCount)); + kernel.publish(Collections.singletonList(MessageCreator.buildMessage(message, singletonList(mimeContainer), executionCount))); } } } diff --git a/kernel/base/src/main/java/com/twosigma/beakerx/kernel/threads/ExecutionResultSender.java b/kernel/base/src/main/java/com/twosigma/beakerx/kernel/threads/ExecutionResultSender.java index 75096be191..183aa1cefb 100644 --- a/kernel/base/src/main/java/com/twosigma/beakerx/kernel/threads/ExecutionResultSender.java +++ b/kernel/base/src/main/java/com/twosigma/beakerx/kernel/threads/ExecutionResultSender.java @@ -28,6 +28,8 @@ import com.twosigma.beakerx.kernel.msg.MessageHolder; import com.twosigma.beakerx.kernel.SocketEnum; +import static java.util.Collections.singletonList; + public class ExecutionResultSender implements Observer { public static Logger logger = LoggerFactory.getLogger(ExecutionResultSender.class); @@ -44,7 +46,7 @@ public synchronized void update(Observable o, Object arg) { List message = MessageCreator.createMessage(seo); message.forEach(job -> { if (SocketEnum.IOPUB_SOCKET.equals(job.getSocketType())) { - kernel.publish(job.getMessage()); + kernel.publish(singletonList(job.getMessage())); } else if (SocketEnum.SHELL_SOCKET.equals(job.getSocketType())) { kernel.send(job.getMessage()); } diff --git a/kernel/base/src/main/java/com/twosigma/beakerx/message/Header.java b/kernel/base/src/main/java/com/twosigma/beakerx/message/Header.java index 6f71683f24..18fca193c3 100644 --- a/kernel/base/src/main/java/com/twosigma/beakerx/message/Header.java +++ b/kernel/base/src/main/java/com/twosigma/beakerx/message/Header.java @@ -25,8 +25,10 @@ @JsonPropertyOrder({ "id", "username", "session", "date", "type", "version" }) public class Header { + public static final String MSG_ID = "msg_id"; + private String date; - @JsonProperty("msg_id") + @JsonProperty(MSG_ID) private String id; private String username; private String session; @@ -43,7 +45,7 @@ public Header(JupyterMessages type, String session) { username = "kernel"; this.type = type; this.session = session; - this.version = "5.0"; + this.version = "5.3"; } public String asJson() { diff --git a/kernel/base/src/main/java/com/twosigma/beakerx/socket/KernelSocketsZMQ.java b/kernel/base/src/main/java/com/twosigma/beakerx/socket/KernelSocketsZMQ.java index e41eb4a1c7..f93efa14fd 100644 --- a/kernel/base/src/main/java/com/twosigma/beakerx/socket/KernelSocketsZMQ.java +++ b/kernel/base/src/main/java/com/twosigma/beakerx/socket/KernelSocketsZMQ.java @@ -34,12 +34,15 @@ import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.LinkedHashMap; +import java.util.List; import static com.twosigma.beakerx.kernel.msg.JupyterMessages.SHUTDOWN_REPLY; import static com.twosigma.beakerx.kernel.msg.JupyterMessages.SHUTDOWN_REQUEST; import static java.util.Arrays.asList; import static com.twosigma.beakerx.message.MessageSerializer.toJson; +import static java.util.Collections.singletonList; public class KernelSocketsZMQ extends KernelSockets { @@ -84,34 +87,35 @@ private void configureSockets(Config configuration) { sockets.register(stdinSocket, ZMQ.Poller.POLLIN); } - public void publish(Message message) { + public void publish(List message) { sendMsg(this.iopubSocket, message); } public void send(Message message) { - sendMsg(this.shellSocket, message); + sendMsg(this.shellSocket, singletonList(message)); } - private synchronized void sendMsg(ZMQ.Socket socket, Message message) { - String header = toJson(message.getHeader()); - String parent = toJson(message.getParentHeader()); - String meta = toJson(message.getMetadata()); - String content = toJson(message.getContent()); - String digest = hmac.sign(Arrays.asList(header, parent, meta, content)); - - ZMsg newZmsg = new ZMsg(); - message.getIdentities().forEach(newZmsg::add); - newZmsg.add(DELIM); - newZmsg.add(digest.getBytes(StandardCharsets.UTF_8)); - newZmsg.add(header.getBytes(StandardCharsets.UTF_8)); - newZmsg.add(parent.getBytes(StandardCharsets.UTF_8)); - newZmsg.add(meta.getBytes(StandardCharsets.UTF_8)); - newZmsg.add(content.getBytes(StandardCharsets.UTF_8)); - message.getBuffers().forEach( x-> newZmsg.add(x)); - newZmsg.send(socket); + private synchronized void sendMsg(ZMQ.Socket socket, List messages) { + messages.forEach(message -> { + String header = toJson(message.getHeader()); + String parent = toJson(message.getParentHeader()); + String meta = toJson(message.getMetadata()); + String content = toJson(message.getContent()); + String digest = hmac.sign(Arrays.asList(header, parent, meta, content)); + + ZMsg newZmsg = new ZMsg(); + message.getIdentities().forEach(newZmsg::add); + newZmsg.add(DELIM); + newZmsg.add(digest.getBytes(StandardCharsets.UTF_8)); + newZmsg.add(header.getBytes(StandardCharsets.UTF_8)); + newZmsg.add(parent.getBytes(StandardCharsets.UTF_8)); + newZmsg.add(meta.getBytes(StandardCharsets.UTF_8)); + newZmsg.add(content.getBytes(StandardCharsets.UTF_8)); + message.getBuffers().forEach(x -> newZmsg.add(x)); + newZmsg.send(socket); + }); } - private Message readMessage(ZMQ.Socket socket) { ZMsg zmsg = null; Message message = new Message(); @@ -194,7 +198,7 @@ private void handleControlMsg() { reply.setHeader(new Header(SHUTDOWN_REPLY, message.getHeader().getSession())); reply.setParentHeader(message.getHeader()); reply.setContent(message.getContent()); - sendMsg(controlSocket, reply); + sendMsg(controlSocket, Collections.singletonList(reply)); shutdown(); } } diff --git a/kernel/base/src/main/java/com/twosigma/beakerx/widgets/CompiledCodeRunner.java b/kernel/base/src/main/java/com/twosigma/beakerx/widgets/CompiledCodeRunner.java index eaddfb0a26..63f325e6b5 100644 --- a/kernel/base/src/main/java/com/twosigma/beakerx/widgets/CompiledCodeRunner.java +++ b/kernel/base/src/main/java/com/twosigma/beakerx/widgets/CompiledCodeRunner.java @@ -28,10 +28,13 @@ import java.io.PrintWriter; import java.io.Serializable; import java.io.StringWriter; +import java.util.Collections; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; +import static java.util.Collections.singletonList; + public class CompiledCodeRunner { private static final Logger logger = LoggerFactory.getLogger(CompiledCodeRunner.class); @@ -74,12 +77,12 @@ public static void runCompiledCode(Message message, ExecuteCompiledCode handler, public static void runCompiledCodeAndPublish(Message message, ExecuteCompiledCode handler, Object... params) { final SimpleEvaluationObject seo = initOutput(message); InternalVariable.setValue(seo); - KernelManager.get().publish(MessageCreator.buildClearOutput(message, true)); + KernelManager.get().publish(singletonList(MessageCreator.buildClearOutput(message, true))); try { Object result = handler.executeCode(params); if (result != null) { List resultString = SerializeToString.doit(result); - KernelManager.get().publish(MessageCreator.buildDisplayData(message, resultString)); + KernelManager.get().publish(singletonList(MessageCreator.buildDisplayData(message, resultString))); } } catch (Exception e) { printError(message, seo, e); diff --git a/kernel/base/src/main/java/com/twosigma/beakerx/widgets/DOMWidget.java b/kernel/base/src/main/java/com/twosigma/beakerx/widgets/DOMWidget.java index 388b2d82ad..3b3a420b4e 100644 --- a/kernel/base/src/main/java/com/twosigma/beakerx/widgets/DOMWidget.java +++ b/kernel/base/src/main/java/com/twosigma/beakerx/widgets/DOMWidget.java @@ -70,6 +70,8 @@ public Optional getSyncDataValue(Message msg) { ret = Optional.of(sync_data.get(VALUE)); } else if (sync_data.containsKey(INDEX)) { ret = Optional.of(sync_data.get(INDEX)); + } else if (sync_data.containsKey("outputs")){ + ret = Optional.of(sync_data.get("outputs")); } } } diff --git a/kernel/base/src/main/java/com/twosigma/beakerx/widgets/Output.java b/kernel/base/src/main/java/com/twosigma/beakerx/widgets/Output.java new file mode 100644 index 0000000000..e6d49eb732 --- /dev/null +++ b/kernel/base/src/main/java/com/twosigma/beakerx/widgets/Output.java @@ -0,0 +1,133 @@ +/* + * Copyright 2018 TWO SIGMA OPEN SOURCE, LLC + * + * 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 com.twosigma.beakerx.widgets; + +import com.twosigma.beakerx.jvm.object.ConsoleOutput; +import com.twosigma.beakerx.kernel.comm.Comm; +import com.twosigma.beakerx.message.Message; +import com.twosigma.beakerx.mimetype.MIMEContainer; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static com.twosigma.beakerx.kernel.msg.JupyterMessages.DISPLAY_DATA; +import static com.twosigma.beakerx.message.Header.MSG_ID; +import static java.util.Collections.emptyList; + +public class Output extends DOMWidget { + + public static final String VIEW_NAME_VALUE = "OutputView"; + public static final String MODEL_NAME_VALUE = "OutputModel"; + + public static final String MODEL_MODULE_VALUE = "@jupyter-widgets/output"; + public static final String VIEW_MODULE_VALUE = "@jupyter-widgets/output"; + public static final String OUTPUTS = "outputs"; + public static final String OUTPUT_TYPE = "output_type"; + public static final String NAME = "name"; + public static final String TEXT = "text"; + public static final String STREAM = "stream"; + public static final String STDERR = "stderr"; + public static final String STDOUT = "stdout"; + + private List> outputs = Collections.synchronizedList(new ArrayList<>()); + + public Output() { + super(); + openComm(); + } + + @Override + public String getModelNameValue() { + return MODEL_NAME_VALUE; + } + + @Override + public String getViewNameValue() { + return VIEW_NAME_VALUE; + } + + @Override + public String getModelModuleValue() { + return MODEL_MODULE_VALUE; + } + + @Override + public String getViewModuleValue() { + return VIEW_MODULE_VALUE; + } + + @Override + protected HashMap content(HashMap content) { + super.content(content); + content.put(MSG_ID, ""); + content.put(OUTPUTS, new ArrayList<>().toArray()); + return content; + } + + @Override + public void updateValue(Object value) { + } + + public synchronized void sendOutput(ConsoleOutput co) { + List list = new ArrayList<>(); + list.add(getComm().createUpdateMessage(MSG_ID, getComm().getParentMessage().getHeader().getId())); + Map asMap = addOutput(co); + list.add(getComm().createOutputContent(asMap)); + list.add(getComm().createUpdateMessage(MSG_ID, "")); + getComm().publish(list); + } + + public void display(MIMEContainer mimeContainer) { + List list = new ArrayList<>(); + list.add(getComm().createUpdateMessage(MSG_ID, getComm().getParentMessage().getHeader().getId())); + HashMap content = new HashMap<>(); + content.put(mimeContainer.getMime().asString(), (Serializable) mimeContainer.getData()); + list.add(getComm().createMessage(DISPLAY_DATA, Comm.Buffer.EMPTY, new Comm.Data(content))); + list.add(getComm().createUpdateMessage(MSG_ID, "")); + getComm().publish(list); + } + + public void appendStdout(String text) { + sendOutput(new ConsoleOutput(false, text + "\n")); + } + + public void appendStderr(String text) { + sendOutput(new ConsoleOutput(true, text + "\n")); + } + + private Map addOutput(ConsoleOutput co) { + Map value = createOutput(co); + outputs.add(value); + return value; + } + + public void clearOutput() { + outputs = Collections.synchronizedList(new ArrayList<>()); + sendUpdate(OUTPUTS, emptyList()); + } + + private Map createOutput(ConsoleOutput co) { + Map outputs = new HashMap<>(); + outputs.put(OUTPUT_TYPE, STREAM); + outputs.put(NAME, co.isError() ? STDERR : STDOUT); + outputs.put(TEXT, co.getText()); + return outputs; + } +} diff --git a/kernel/base/src/main/java/com/twosigma/beakerx/widgets/OutputManager.java b/kernel/base/src/main/java/com/twosigma/beakerx/widgets/OutputManager.java new file mode 100644 index 0000000000..0b28ce5b45 --- /dev/null +++ b/kernel/base/src/main/java/com/twosigma/beakerx/widgets/OutputManager.java @@ -0,0 +1,29 @@ +/* + * Copyright 2018 TWO SIGMA OPEN SOURCE, LLC + * + * 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 com.twosigma.beakerx.widgets; + +import com.twosigma.beakerx.jvm.threads.BeakerStdOutErrHandler; + +public class OutputManager { + + public static void setOutput(Output out) { + BeakerStdOutErrHandler.setOuputWidget(out); + } + + public static void clearOutput() { + BeakerStdOutErrHandler.clearOutput(); + } +} diff --git a/kernel/base/src/main/java/com/twosigma/beakerx/widgets/Widget.java b/kernel/base/src/main/java/com/twosigma/beakerx/widgets/Widget.java index a7bd4cfdf9..47add7ccf7 100644 --- a/kernel/base/src/main/java/com/twosigma/beakerx/widgets/Widget.java +++ b/kernel/base/src/main/java/com/twosigma/beakerx/widgets/Widget.java @@ -95,11 +95,9 @@ private void sendDisplay() { data.put("version_major", 2); data.put("version_minor", 0); data.put(MODEL_ID, getComm().getCommId()); - content.put(METHOD, DISPLAY); content.put(APPLICATION_VND_JUPYTER_WIDGET_VIEW_JSON, data); - getComm().setData(content); - getComm().send(DISPLAY_DATA); + getComm().send(DISPLAY_DATA,new Comm.Data(content)); } private HashMap createContent() { diff --git a/kernel/base/src/test/java/com/twosigma/beakerx/KernelSocketsTest.java b/kernel/base/src/test/java/com/twosigma/beakerx/KernelSocketsTest.java index 304672c200..364e8d445d 100644 --- a/kernel/base/src/test/java/com/twosigma/beakerx/KernelSocketsTest.java +++ b/kernel/base/src/test/java/com/twosigma/beakerx/KernelSocketsTest.java @@ -30,8 +30,8 @@ public class KernelSocketsTest extends KernelSockets { private volatile List sentMessages = synchronizedList(new ArrayList<>()); @Override - public void publish(Message message) { - publishedMessages.add(message); + public void publish(List message) { + publishedMessages.addAll(message); } @Override diff --git a/kernel/base/src/test/java/com/twosigma/beakerx/KernelTest.java b/kernel/base/src/test/java/com/twosigma/beakerx/KernelTest.java index 5c7ab1bf87..ff4230f5a5 100644 --- a/kernel/base/src/test/java/com/twosigma/beakerx/KernelTest.java +++ b/kernel/base/src/test/java/com/twosigma/beakerx/KernelTest.java @@ -64,6 +64,7 @@ import java.io.IOException; import java.nio.file.Path; import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -147,8 +148,8 @@ private void initMagicCommands() { } @Override - public void publish(Message message) { - this.publishedMessages.add(message); + public void publish(List message) { + this.publishedMessages.addAll(message); } @Override @@ -334,13 +335,13 @@ public AutocompleteResult autocomplete(String code, int cursorPos) { @Override public void sendBusyMessage(Message message) { Message busyMessage = MessageCreator.createBusyMessage(message); - publish(busyMessage); + publish(Collections.singletonList(busyMessage)); } @Override public void sendIdleMessage(Message message) { Message idleMessage = MessageCreator.createIdleMessage(message); - publish(idleMessage); + publish(Collections.singletonList(idleMessage)); } public void exit() { diff --git a/kernel/base/src/test/java/com/twosigma/beakerx/evaluator/EvaluatorResultTestWatcher.java b/kernel/base/src/test/java/com/twosigma/beakerx/evaluator/EvaluatorResultTestWatcher.java index 2e73954035..bf4e8f05ee 100644 --- a/kernel/base/src/test/java/com/twosigma/beakerx/evaluator/EvaluatorResultTestWatcher.java +++ b/kernel/base/src/test/java/com/twosigma/beakerx/evaluator/EvaluatorResultTestWatcher.java @@ -102,18 +102,30 @@ public static Optional waitForErrorMessage(KernelSocketsTest socketsTes return idleMessage; } - public static Optional waitForUpdateMessage(KernelTest socketsTest) throws InterruptedException { + + public static Optional waitForUpdateMessage(KernelSocketsTest socketsTest) throws InterruptedException { + int count = 0; + Optional idleMessage = getUpdate(socketsTest.getPublishedMessages()); + while (!idleMessage.isPresent() && count < ATTEMPT) { + Thread.sleep(SLEEP_IN_MILLIS); + idleMessage = getUpdate(socketsTest.getPublishedMessages()); + count++; + } + return idleMessage; + } + + public static Optional waitForUpdateMessage(KernelTest kernelTest) throws InterruptedException { int count = 0; - Optional idleMessage = getUpdate(socketsTest); + Optional idleMessage = getUpdate(kernelTest.getPublishedMessages()); while (!idleMessage.isPresent() && count < ATTEMPT) { Thread.sleep(SLEEP_IN_MILLIS); - idleMessage = getUpdate(socketsTest); + idleMessage = getUpdate(kernelTest.getPublishedMessages()); count++; } return idleMessage; } - private static Optional getStreamMessage(KernelTest kernelTest) { + public static Optional getStreamMessage(KernelTest kernelTest) { List listMessagesByType = SearchMessages.getListMessagesByType(kernelTest.getPublishedMessages(), JupyterMessages.STREAM); return listMessagesByType.stream().findFirst(); } @@ -139,8 +151,8 @@ private static Optional getError(KernelSocketsTest socketsTest) { } - private static Optional getUpdate(KernelTest kernel) { - return kernel.getPublishedMessages().stream(). + private static Optional getUpdate(List messages) { + return messages.stream(). filter(x -> x.type().equals(JupyterMessages.COMM_MSG)). filter(x -> TestWidgetUtils.getData(x).get("method").equals("update")). findFirst(); diff --git a/kernel/base/src/test/java/com/twosigma/beakerx/jupyter/comm/CommTest.java b/kernel/base/src/test/java/com/twosigma/beakerx/jupyter/comm/CommTest.java index cd5c89fdb3..434db728e2 100644 --- a/kernel/base/src/test/java/com/twosigma/beakerx/jupyter/comm/CommTest.java +++ b/kernel/base/src/test/java/com/twosigma/beakerx/jupyter/comm/CommTest.java @@ -32,6 +32,7 @@ import java.util.HashMap; import java.util.Map; +import static com.twosigma.beakerx.kernel.msg.JupyterMessages.COMM_MSG; import static org.assertj.core.api.Assertions.assertThat; public class CommTest { @@ -61,7 +62,7 @@ public void commCreatedWithParentMessageShouldAlwaysSendHeaderFromThisParentMess assertThat(kernel.getPublishedMessages().get(0).getParentHeader()).isEqualTo(parentMessage.getHeader()); kernel.clearPublishedMessages(); //then - comm.send(); + comm.send(COMM_MSG, Comm.Buffer.EMPTY, comm.getData()); assertThat(kernel.getPublishedMessages().get(0).getParentHeader()).isEqualTo(parentMessage.getHeader()); } @@ -74,7 +75,7 @@ public void commCreatedWithoutParentMessageShouldAlwaysSendHeaderFromMessageGive kernel.clearPublishedMessages(); // code from second execution Message message2 = submitCodeToExecution(); - comm.send(); + comm.send(COMM_MSG, Comm.Buffer.EMPTY, comm.getData()); assertThat(kernel.getPublishedMessages().get(0).getParentHeader()).isEqualTo(message2.getHeader()); } @@ -199,7 +200,7 @@ public void commClose_sentMessageHasEmptyData() throws NoSuchAlgorithmException @Test public void commSend_shouldSendIOPubSocketMessage() throws NoSuchAlgorithmException { //when - comm.send(); + comm.send(COMM_MSG, Comm.Buffer.EMPTY, comm.getData()); //then assertThat(kernel.getPublishedMessages()).isNotEmpty(); assertThat(kernel.getPublishedMessages().get(0)).isNotNull(); @@ -208,7 +209,7 @@ public void commSend_shouldSendIOPubSocketMessage() throws NoSuchAlgorithmExcept @Test public void commSend_sentMessageHasTypeIsCommClose() throws NoSuchAlgorithmException { //when - comm.send(); + comm.send(COMM_MSG, Comm.Buffer.EMPTY, comm.getData()); //then assertThat(kernel.getPublishedMessages()).isNotEmpty(); Message sendMessage = kernel.getPublishedMessages().get(0); @@ -219,7 +220,7 @@ public void commSend_sentMessageHasTypeIsCommClose() throws NoSuchAlgorithmExcep @Test public void commSend_sentMessageHasCommId() throws NoSuchAlgorithmException { //when - comm.send(); + comm.send(COMM_MSG, Comm.Buffer.EMPTY, comm.getData()); //then assertThat(kernel.getPublishedMessages()).isNotEmpty(); Message sendMessage = kernel.getPublishedMessages().get(0); @@ -230,7 +231,7 @@ public void commSend_sentMessageHasCommId() throws NoSuchAlgorithmException { public void commClose_sentMessageHasData() throws NoSuchAlgorithmException { initCommData(comm); //when - comm.send(); + comm.send(COMM_MSG, Comm.Buffer.EMPTY, comm.getData()); //then assertThat(kernel.getPublishedMessages()).isNotEmpty(); Message sendMessage = kernel.getPublishedMessages().get(0); diff --git a/kernel/base/src/test/java/com/twosigma/beakerx/jupyter/handler/ExecuteRequestHandlerTest.java b/kernel/base/src/test/java/com/twosigma/beakerx/jupyter/handler/ExecuteRequestHandlerTest.java index 35cab225f5..a9b65f153f 100644 --- a/kernel/base/src/test/java/com/twosigma/beakerx/jupyter/handler/ExecuteRequestHandlerTest.java +++ b/kernel/base/src/test/java/com/twosigma/beakerx/jupyter/handler/ExecuteRequestHandlerTest.java @@ -37,6 +37,7 @@ import java.util.LinkedHashMap; import java.util.List; +import java.util.stream.Collectors; public class ExecuteRequestHandlerTest { @@ -51,8 +52,8 @@ public static void setUpClass() { evaluatorTest = new EvaluatorTest(); kernel = new KernelTest("sid", evaluatorTest) { @Override - public void publish(Message message) { - super.publish(copyMessage(message)); + public void publish(List message) { + super.publish(message.stream().map(ExecuteRequestHandlerTest::copyMessage).collect(Collectors.toList())); } }; } diff --git a/kernel/base/src/test/java/com/twosigma/beakerx/jvm/threads/BeakerStdOutErrHandlerTest.java b/kernel/base/src/test/java/com/twosigma/beakerx/jvm/threads/BeakerStdOutErrHandlerTest.java index 93da1fd085..7016ea8b87 100644 --- a/kernel/base/src/test/java/com/twosigma/beakerx/jvm/threads/BeakerStdOutErrHandlerTest.java +++ b/kernel/base/src/test/java/com/twosigma/beakerx/jvm/threads/BeakerStdOutErrHandlerTest.java @@ -17,139 +17,92 @@ package com.twosigma.beakerx.jvm.threads; import com.twosigma.beakerx.jvm.object.SimpleEvaluationObject; -import org.assertj.core.api.Assertions; -import org.junit.AfterClass; +import org.junit.After; import org.junit.Before; -import org.junit.BeforeClass; import org.junit.Test; -import java.io.PrintStream; -import java.lang.reflect.Field; -import java.util.Map; +import static org.assertj.core.api.Assertions.assertThat; public class BeakerStdOutErrHandlerTest { private static SimpleEvaluationObject seo; - private static BeakerStdOutErrHandler handler; - private static Field instanceField; - private static Field thrHandlersField; - private static Field defOutField; - private static Field defErrField; - private static Field originOutField; - private static Field originErrField; - - @BeforeClass - public static void setUpClass() throws Exception { - instanceField = BeakerStdOutErrHandler.class.getDeclaredField("instance"); - instanceField.setAccessible(true); - thrHandlersField = BeakerStdOutErrHandler.class.getDeclaredField("thrHandlers"); - thrHandlersField.setAccessible(true); - defOutField = BeakerStdOutErrHandler.class.getDeclaredField("def_out"); - defOutField.setAccessible(true); - defErrField = BeakerStdOutErrHandler.class.getDeclaredField("def_err"); - defErrField.setAccessible(true); - originOutField = BeakerStdOutErrHandler.class.getDeclaredField("orig_out"); - originOutField.setAccessible(true); - originErrField = BeakerStdOutErrHandler.class.getDeclaredField("orig_err"); - originErrField.setAccessible(true); - handler = new BeakerStdOutErrHandler(); - seo = new SimpleEvaluationObject("code"); - } + private SimpleOutputHandlerTest stdout; + private SimpleErrHandlerTest stderr; @Before public void setUp() throws Exception { BeakerStdOutErrHandler.init(); + stdout = new SimpleOutputHandlerTest(); + stderr = new SimpleErrHandlerTest(); + seo = new SimpleEvaluationObject("code", stdout, stderr); + seo.setOutputHandler(); } - @AfterClass - public static void tearDownClass() throws Exception { + @After + public void tearDownClass() throws Exception { + seo.clrOutputHandler(); BeakerStdOutErrHandler.fini(); } @Test - public void init_instanceIsNotNull() throws Exception { + public void shouldHandleStdout() throws Exception { + //given //when - BeakerStdOutErrHandler.init(); + System.out.print("Hello"); //then - Assertions.assertThat(getInstance(handler)).isNotNull(); + assertThat(stdout.bList).isNotEmpty(); } @Test - public void fini_instanceIsNull() throws Exception { + public void shouldHandleStderr() throws Exception { + //given //when - BeakerStdOutErrHandler.init(); - BeakerStdOutErrHandler.fini(); + System.err.print("Error"); //then - Assertions.assertThat(getInstance(handler)).isNull(); + assertThat(stderr.bList).isNotEmpty(); } - @Test - public void out_returnOriginOut() throws Exception { - //when - PrintStream printStream = BeakerStdOutErrHandler.out(); - //then - Assertions.assertThat(getOriginOut(getInstance(handler))).isEqualTo(printStream); - } + static class SimpleOutputHandlerTest implements BeakerOutputHandler { - @Test - public void err_returnOriginErr() throws Exception { - //when - PrintStream printStream = BeakerStdOutErrHandler.err(); - //then - Assertions.assertThat(getOriginErr(getInstance(handler))).isEqualTo(printStream); - } + private int b; + private byte[] bList; - @Test - public void setOutputHandler_threadHandlersMapIsNotEmpty() throws Exception { - //when - BeakerStdOutErrHandler.setOutputHandler(seo.getStdOutputHandler(), seo.getStdErrorHandler()); - //then - Assertions.assertThat(getThrHandlers(getInstance(handler))).isNotEmpty(); - } + @Override + public void write(int b) { + this.b = b; + } - @Test - public void theClrOutputHandler_threadHandlersMapIsEmpty() throws Exception { - //given - BeakerStdOutErrHandler.setOutputHandler(seo.getStdOutputHandler(), seo.getStdErrorHandler()); - //when - BeakerStdOutErrHandler.clrOutputHandler(); - //then - Assertions.assertThat(getThrHandlers(getInstance(handler))).isEmpty(); - } + @Override + public void write(byte[] b) { + this.bList = b; + } - @Test - public void setDefaultOutputHandler_shouldSetUpDefOutAndDefErr() throws Exception { - BeakerOutputHandler stdOut = seo.getStdOutputHandler(); - BeakerOutputHandler stdErr = seo.getStdErrorHandler(); - //when - BeakerStdOutErrHandler.setDefaultOutputHandler(stdOut, stdErr); - //then - Assertions.assertThat(getDefOut(getInstance(handler))).isEqualTo(stdOut); - Assertions.assertThat(getDefErr(getInstance(handler))).isEqualTo(stdErr); + @Override + public void write(byte[] b, int off, int len) { + this.bList = b; + } } - private BeakerStdOutErrHandler getInstance(BeakerStdOutErrHandler handler) throws Exception { - return (BeakerStdOutErrHandler) instanceField.get(handler); - } + static class SimpleErrHandlerTest implements BeakerOutputHandler { - private Map getThrHandlers(BeakerStdOutErrHandler handler) throws Exception { - return (Map) thrHandlersField.get(handler); - } + private int b; + private byte[] bList; - private BeakerOutputHandler getDefOut(BeakerStdOutErrHandler handler) throws Exception { - return (BeakerOutputHandler) defOutField.get(handler); - } + @Override + public void write(int b) { + this.b = b; + } - private BeakerOutputHandler getDefErr(BeakerStdOutErrHandler handler) throws Exception { - return (BeakerOutputHandler) defErrField.get(handler); - } + @Override + public void write(byte[] b) { + this.bList = b; + } - private PrintStream getOriginOut(BeakerStdOutErrHandler handler) throws Exception { - return (PrintStream) originOutField.get(handler); + @Override + public void write(byte[] b, int off, int len) { + this.bList = b; + } } - private PrintStream getOriginErr(BeakerStdOutErrHandler handler) throws Exception { - return (PrintStream) originErrField.get(handler); - } } diff --git a/kernel/base/src/test/java/com/twosigma/beakerx/widgets/DisplayWidgetTest.java b/kernel/base/src/test/java/com/twosigma/beakerx/widgets/DisplayWidgetTest.java index 824b7c5a3b..36096f5ab3 100644 --- a/kernel/base/src/test/java/com/twosigma/beakerx/widgets/DisplayWidgetTest.java +++ b/kernel/base/src/test/java/com/twosigma/beakerx/widgets/DisplayWidgetTest.java @@ -17,19 +17,16 @@ import com.twosigma.beakerx.KernelTest; import com.twosigma.beakerx.kernel.KernelManager; +import com.twosigma.beakerx.kernel.msg.JupyterMessages; +import com.twosigma.beakerx.message.Message; import com.twosigma.beakerx.widgets.integers.IntSlider; import org.junit.After; import org.junit.Before; import org.junit.Test; -import com.twosigma.beakerx.message.Message; import static com.twosigma.beakerx.kernel.comm.Comm.COMM_ID; -import static com.twosigma.beakerx.kernel.comm.Comm.METHOD; -import static com.twosigma.beakerx.kernel.msg.JupyterMessages.COMM_MSG; -import static com.twosigma.beakerx.kernel.msg.JupyterMessages.DISPLAY_DATA; import static com.twosigma.beakerx.widgets.TestWidgetUtils.getContent; import static com.twosigma.beakerx.widgets.TestWidgetUtils.getData; -import static com.twosigma.beakerx.widgets.TestWidgetUtils.verifyDisplayMsg; import static org.assertj.core.api.Assertions.assertThat; public class DisplayWidgetTest { @@ -61,8 +58,8 @@ public void shouldSendCommOpenWhenCreate() throws Exception { private void verifyCommDisplayMsg(IntSlider widget) { assertThat(groovyKernel.getPublishedMessages().size()).isEqualTo(1); Message message = groovyKernel.getPublishedMessages().get(0); - assertThat(getData(message).get(METHOD)).isEqualTo(DISPLAY_DATA.getName()); - verifyDisplayMsg(message); + assertThat(getData(message).get(Widget.APPLICATION_VND_JUPYTER_WIDGET_VIEW_JSON)).isNotNull(); + assertThat(message.type()).isEqualTo(JupyterMessages.DISPLAY_DATA); assertThat(getContent(message).get(COMM_ID)).isNull(); } } \ No newline at end of file diff --git a/kernel/base/src/test/java/com/twosigma/beakerx/widgets/OutputWidgetTest.java b/kernel/base/src/test/java/com/twosigma/beakerx/widgets/OutputWidgetTest.java new file mode 100644 index 0000000000..6214cabd8c --- /dev/null +++ b/kernel/base/src/test/java/com/twosigma/beakerx/widgets/OutputWidgetTest.java @@ -0,0 +1,109 @@ +/* + * Copyright 2018 TWO SIGMA OPEN SOURCE, LLC + * + * 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 com.twosigma.beakerx.widgets; + +import com.twosigma.beakerx.KernelTest; +import com.twosigma.beakerx.evaluator.EvaluatorResultTestWatcher; +import com.twosigma.beakerx.evaluator.InternalVariable; +import com.twosigma.beakerx.jvm.object.SimpleEvaluationObject; +import com.twosigma.beakerx.kernel.KernelManager; +import com.twosigma.beakerx.message.Message; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import java.util.List; + +import static com.twosigma.beakerx.widgets.Output.OUTPUT_TYPE; +import static com.twosigma.beakerx.widgets.TestWidgetUtils.getValueForProperty; +import static com.twosigma.beakerx.widgets.TestWidgetUtils.verifyOpenCommMsg; +import static org.assertj.core.api.Assertions.assertThat; + +public class OutputWidgetTest { + + private KernelTest groovyKernel; + + @Before + public void setUp() throws Exception { + groovyKernel = new KernelTest(); + KernelManager.register(groovyKernel); + submitCodeToExecution(); + } + + @After + public void tearDown() throws Exception { + KernelManager.register(null); + } + + private Message submitCodeToExecution() { + SimpleEvaluationObject value = new SimpleEvaluationObject("output"); + Message jupyterMessage = new Message(); + value.setJupyterMessage(jupyterMessage); + InternalVariable.setValue(value); + return jupyterMessage; + } + + @Test + public void shouldSendCommOpenWhenCreate() throws Exception { + //given + //when + new Output(); + //then + verifyOpenCommMsg(groovyKernel.getPublishedMessages(), Output.MODEL_NAME_VALUE, Output.VIEW_NAME_VALUE); + } + + @Test + public void shouldSendCommMsgWhenAppendStdout() throws Exception { + //given + Output output = new Output(); + groovyKernel.clearPublishedMessages(); + //when + output.appendStdout("Hello 1"); + //then + Message streamMessage = EvaluatorResultTestWatcher.getStreamMessage(groovyKernel).get(); + assertThat(streamMessage.getContent().get(OUTPUT_TYPE)).isEqualTo(Output.STREAM.toString()); + assertThat(streamMessage.getContent().get(Output.NAME)).isEqualTo(Output.STDOUT); + assertThat(streamMessage.getContent().get(Output.TEXT)).isEqualTo("Hello 1\n"); + } + + @Test + public void shouldSendCommMsgWhenAppendStderr() throws Exception { + //given + Output output = new Output(); + groovyKernel.clearPublishedMessages(); + //when + output.appendStderr("Error 1"); + //then + Message streamMessage = EvaluatorResultTestWatcher.getStreamMessage(groovyKernel).get(); + assertThat(streamMessage.getContent().get(OUTPUT_TYPE)).isEqualTo(Output.STREAM.toString()); + assertThat(streamMessage.getContent().get(Output.NAME)).isEqualTo(Output.STDERR); + assertThat(streamMessage.getContent().get(Output.TEXT)).isEqualTo("Error 1\n"); + } + + @Test + public void shouldSendCommMsgClear() throws Exception { + //given + Output output = new Output(); + output.appendStderr("Error 1"); + groovyKernel.clearPublishedMessages(); + //when + output.clearOutput(); + //then + List value = getValueForProperty(groovyKernel, Output.OUTPUTS, List.class); + assertThat(value).isEmpty(); + } + +} \ No newline at end of file diff --git a/kernel/clojure/src/main/java/com/twosigma/beakerx/clojure/evaluator/ClojureCodeRunner.java b/kernel/clojure/src/main/java/com/twosigma/beakerx/clojure/evaluator/ClojureCodeRunner.java index f18bb78d88..25c7779e20 100644 --- a/kernel/clojure/src/main/java/com/twosigma/beakerx/clojure/evaluator/ClojureCodeRunner.java +++ b/kernel/clojure/src/main/java/com/twosigma/beakerx/clojure/evaluator/ClojureCodeRunner.java @@ -43,9 +43,8 @@ public TryResult call() throws Exception { ClassLoader oldLoader = Thread.currentThread().getContextClassLoader(); Thread.currentThread().setContextClassLoader(clojureEvaluator.getClassLoader()); TryResult either; - - theOutput.setOutputHandler(); try { + theOutput.setOutputHandler(); InternalVariable.setValue(theOutput); Object o = clojureEvaluator.runCode(theCode); try { @@ -67,9 +66,10 @@ public TryResult call() throws Exception { } either = TryResult.createError(sw.toString()); } + } finally { + theOutput.setOutputHandler(); + Thread.currentThread().setContextClassLoader(oldLoader); } - theOutput.setOutputHandler(); - Thread.currentThread().setContextClassLoader(oldLoader); return either; } diff --git a/kernel/clojure/src/main/java/com/twosigma/beakerx/clojure/evaluator/ClojureEvaluator.java b/kernel/clojure/src/main/java/com/twosigma/beakerx/clojure/evaluator/ClojureEvaluator.java index 29eaae2774..bef2ab1050 100644 --- a/kernel/clojure/src/main/java/com/twosigma/beakerx/clojure/evaluator/ClojureEvaluator.java +++ b/kernel/clojure/src/main/java/com/twosigma/beakerx/clojure/evaluator/ClojureEvaluator.java @@ -44,9 +44,7 @@ import java.net.URL; import java.util.ArrayList; import java.util.List; -import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; -import java.util.concurrent.Future; public class ClojureEvaluator extends BaseEvaluator { @@ -54,7 +52,6 @@ public class ClojureEvaluator extends BaseEvaluator { private final static Logger logger = LoggerFactory.getLogger(ClojureEvaluator.class.getName()); private List requirements; - private ExecutorService executorService; private DynamicClassLoader loader; private Var clojureLoadString = null; @@ -62,7 +59,6 @@ public ClojureEvaluator(String id, String sId, CellExecutor cellExecutor, TempFo super(id, sId, cellExecutor, tempFolderFactory, evaluatorParameters); requirements = new ArrayList<>(); init(); - executorService = Executors.newSingleThreadExecutor(); } public ClojureEvaluator(String id, String sId, EvaluatorParameters evaluatorParameters) { @@ -146,14 +142,7 @@ public ClassLoader getClassLoader() { @Override public TryResult evaluate(SimpleEvaluationObject seo, String code) { - Future submit = executorService.submit(new ClojureWorkerThread(this, new JobDescriptor(code, seo))); - TryResult either = null; - try { - either = submit.get(); - } catch (Exception e) { - either = TryResult.createError(e.getLocalizedMessage()); - } - return either; + return evaluate(seo, new ClojureWorkerThread(this, new JobDescriptor(code, seo))); } @Override diff --git a/kernel/groovy/src/main/java/com/twosigma/beakerx/groovy/evaluator/GroovyEvaluator.java b/kernel/groovy/src/main/java/com/twosigma/beakerx/groovy/evaluator/GroovyEvaluator.java index fb87d2c8d3..b23ed6de94 100644 --- a/kernel/groovy/src/main/java/com/twosigma/beakerx/groovy/evaluator/GroovyEvaluator.java +++ b/kernel/groovy/src/main/java/com/twosigma/beakerx/groovy/evaluator/GroovyEvaluator.java @@ -36,9 +36,7 @@ import org.codehaus.groovy.control.customizers.ImportCustomizer; import java.io.File; -import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; -import java.util.concurrent.Future; import static com.twosigma.beakerx.groovy.evaluator.EnvVariablesFilter.envVariablesFilter; import static com.twosigma.beakerx.groovy.evaluator.GroovyClassLoaderFactory.addImportPathToImportCustomizer; @@ -52,7 +50,6 @@ public class GroovyEvaluator extends BaseEvaluator { private GroovyClasspathScanner cps; private GroovyAutocomplete gac; - private ExecutorService executorService; private GroovyClassLoader groovyClassLoader; private Binding scriptBinding = null; private ImportCustomizer icz; @@ -68,19 +65,11 @@ public GroovyEvaluator(String id, String sId, CellExecutor cellExecutor, TempFol gac = createGroovyAutocomplete(cps); outDir = envVariablesFilter(outDir, System.getenv()); reloadClassloader(); - executorService = Executors.newSingleThreadExecutor(); } @Override public TryResult evaluate(SimpleEvaluationObject seo, String code) { - Future submit = executorService.submit(new GroovyWorkerThread(this, new JobDescriptor(code, seo))); - TryResult either; - try { - either = submit.get(); - } catch (Exception e) { - either = TryResult.createError(e.getLocalizedMessage()); - } - return either; + return evaluate(seo, new GroovyWorkerThread(this, new JobDescriptor(code, seo))); } @Override diff --git a/kernel/groovy/src/test/java/com/twosigma/beakerx/groovy/kernel/GroovyKernelTest.java b/kernel/groovy/src/test/java/com/twosigma/beakerx/groovy/kernel/GroovyKernelTest.java index 971fec520d..832e47625a 100644 --- a/kernel/groovy/src/test/java/com/twosigma/beakerx/groovy/kernel/GroovyKernelTest.java +++ b/kernel/groovy/src/test/java/com/twosigma/beakerx/groovy/kernel/GroovyKernelTest.java @@ -19,16 +19,25 @@ import com.twosigma.beakerx.kernel.CloseKernelAction; import com.twosigma.beakerx.kernel.Kernel; import com.twosigma.beakerx.kernel.KernelSocketsFactory; +import com.twosigma.beakerx.kernel.Utils; import com.twosigma.beakerx.kernel.comm.Comm; +import com.twosigma.beakerx.kernel.msg.JupyterMessages; +import com.twosigma.beakerx.message.Header; import com.twosigma.beakerx.message.Message; import org.junit.Test; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.stream.Collectors; import static com.twosigma.beakerx.MessageFactoryTest.getExecuteRequestMessage; import static com.twosigma.beakerx.evaluator.EvaluatorResultTestWatcher.waitForIdleMessage; import static com.twosigma.beakerx.evaluator.EvaluatorResultTestWatcher.waitForResult; +import static com.twosigma.beakerx.evaluator.EvaluatorResultTestWatcher.waitForUpdateMessage; import static com.twosigma.beakerx.evaluator.EvaluatorTest.getCacheFolderFactory; import static com.twosigma.beakerx.groovy.TestGroovyEvaluator.groovyEvaluator; import static org.assertj.core.api.Assertions.assertThat; @@ -60,4 +69,81 @@ private void verifyResult(Message result) { assertThat(value).isEqualTo("[false, false, false]"); } + @Test + public void outputWidget() throws Exception { + //given + String outputCommId = "outputCommId"; + addOutputWidget(outputCommId); + //when + String println = "" + + "println(\"Hello 1\")\n" + + "2+5"; + evaluateCode(println); + simulateSendingUpdateMessageFromUI(outputCommId + "1"); + //then + verifyOutputWidgetResult(); + verifyIfStreamMsgIsEarlierThanResult(); + } + + private void simulateSendingUpdateMessageFromUI(String outputCommId) { + kernelSocketsService.handleMsg(outputWidgetUpdateMessage(outputCommId)); + } + + private void verifyIfStreamMsgIsEarlierThanResult() { + List publishedMessages = kernelSocketsService.getKernelSockets().getPublishedMessages(); + List collect = publishedMessages.stream() + .filter(x -> (x.type().equals(JupyterMessages.STREAM) || x.type().equals(JupyterMessages.EXECUTE_RESULT))) + .collect(Collectors.toList()); + assertThat(collect.get(0).type()).isEqualTo(JupyterMessages.STREAM); + assertThat(collect.get(1).type()).isEqualTo(JupyterMessages.STREAM); + assertThat(collect.get(2).type()).isEqualTo(JupyterMessages.EXECUTE_RESULT); + } + + private void verifyOutputWidgetResult() throws InterruptedException { + Optional result = waitForResult(kernelSocketsService.getKernelSockets()); + assertThat(result).isPresent(); + Map actual = ((Map) result.get().getContent().get(Comm.DATA)); + String value = (String) actual.get("text/plain"); + assertThat(value).isEqualTo("7"); + } + + private void evaluateCode(String println) throws InterruptedException { + Message printlnMessage = getExecuteRequestMessage(println); + kernelSocketsService.handleMsg(printlnMessage); + Optional updateMessage = waitForUpdateMessage(kernelSocketsService.getKernelSockets()); + assertThat(updateMessage).isPresent(); + } + + private void addOutputWidget(String outputCommId) throws InterruptedException { + Utils.setFixedCommUUID(outputCommId); + String addWidget = "" + + "import com.twosigma.beakerx.widgets.Output\n" + + "out2 = new Output()\n" + + "OutputManager.setOutput(out2)\n" + + "out2"; + Message addWidgetMessage = getExecuteRequestMessage(addWidget); + kernelSocketsService.handleMsg(addWidgetMessage); + Optional idleAddWidget = waitForIdleMessage(kernelSocketsService.getKernelSockets()); + assertThat(idleAddWidget).isPresent(); + kernelSocketsService.clear(); + Utils.setDefaultCommUUID(); + } + + private Message outputWidgetUpdateMessage(String outputCommId) { + Message message = new Message(); + Header header = new Header(); + header.setTypeEnum(JupyterMessages.COMM_MSG); + message.setHeader(header); + HashMap content = new HashMap<>(); + HashMap data = new HashMap<>(); + data.put("method", "update"); + HashMap state = new HashMap<>(); + state.put("outputs", new ArrayList<>()); + data.put("state", state); + content.put("comm_id", outputCommId); + content.put("data", data); + message.setContent(content); + return message; + } + } \ No newline at end of file diff --git a/kernel/java/src/main/java/com/twosigma/beakerx/javash/evaluator/JavaCodeRunner.java b/kernel/java/src/main/java/com/twosigma/beakerx/javash/evaluator/JavaCodeRunner.java index c87cc4b7f1..eb91fe7e0b 100644 --- a/kernel/java/src/main/java/com/twosigma/beakerx/javash/evaluator/JavaCodeRunner.java +++ b/kernel/java/src/main/java/com/twosigma/beakerx/javash/evaluator/JavaCodeRunner.java @@ -52,10 +52,10 @@ public JavaCodeRunner(JavaEvaluator javaEvaluator, SimpleEvaluationObject out, J public TryResult call() throws Exception { ClassLoader oldld = Thread.currentThread().getContextClassLoader(); Thread.currentThread().setContextClassLoader(javaEvaluator.getJavaClassLoader()); - theOutput.setOutputHandler(); InternalVariable.setValue(theOutput); TryResult either; try { + theOutput.setOutputHandler(); InternalVariable.setValue(theOutput); either = runCode(j); } catch (Throwable e) { @@ -69,9 +69,10 @@ public TryResult call() throws Exception { e.printStackTrace(pw); either = TryResult.createError(sw.toString()); } + } finally { + theOutput.clrOutputHandler(); + Thread.currentThread().setContextClassLoader(oldld); } - theOutput.clrOutputHandler(); - Thread.currentThread().setContextClassLoader(oldld); return either; } diff --git a/kernel/java/src/main/java/com/twosigma/beakerx/javash/evaluator/JavaEvaluator.java b/kernel/java/src/main/java/com/twosigma/beakerx/javash/evaluator/JavaEvaluator.java index 6f226e9f3b..b5a9302269 100644 --- a/kernel/java/src/main/java/com/twosigma/beakerx/javash/evaluator/JavaEvaluator.java +++ b/kernel/java/src/main/java/com/twosigma/beakerx/javash/evaluator/JavaEvaluator.java @@ -34,9 +34,7 @@ import com.twosigma.beakerx.kernel.PathToJar; import java.io.File; -import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; -import java.util.concurrent.Future; public class JavaEvaluator extends BaseEvaluator { @@ -44,7 +42,6 @@ public class JavaEvaluator extends BaseEvaluator { private final String packageId; private ClasspathScanner cps; private JavaAutocomplete jac; - private ExecutorService executorService; private BeakerxUrlClassLoader loader = null; public JavaEvaluator(String id, String sId, EvaluatorParameters evaluatorParameters) { @@ -57,7 +54,6 @@ public JavaEvaluator(String id, String sId, CellExecutor cellExecutor, TempFolde cps = new ClasspathScanner(); jac = createJavaAutocomplete(cps); loader = newClassLoader(); - executorService = Executors.newSingleThreadExecutor(); } @Override @@ -95,14 +91,7 @@ public ClassLoader getClassLoader() { @Override public TryResult evaluate(SimpleEvaluationObject seo, String code) { - Future submit = executorService.submit(new JavaWorkerThread(this, new JobDescriptor(code, seo))); - TryResult either = null; - try { - either = submit.get(); - } catch (Exception e) { - either = TryResult.createError(e.getLocalizedMessage()); - } - return either; + return evaluate(seo, new JavaWorkerThread(this, new JobDescriptor(code, seo))); } @Override diff --git a/kernel/kotlin/src/main/java/com/twosigma/beakerx/kotlin/evaluator/KotlinCodeRunner.java b/kernel/kotlin/src/main/java/com/twosigma/beakerx/kotlin/evaluator/KotlinCodeRunner.java index 609169f1a8..4cf4f2f9fe 100644 --- a/kernel/kotlin/src/main/java/com/twosigma/beakerx/kotlin/evaluator/KotlinCodeRunner.java +++ b/kernel/kotlin/src/main/java/com/twosigma/beakerx/kotlin/evaluator/KotlinCodeRunner.java @@ -48,9 +48,9 @@ public TryResult call() throws Exception { TryResult either; ClassLoader oldld = Thread.currentThread().getContextClassLoader(); Thread.currentThread().setContextClassLoader(loader); - theOutput.setOutputHandler(); InternalVariable.setValue(theOutput); try { + theOutput.setOutputHandler(); InternalVariable.setValue(theOutput); ReplEvalResult eval = repl.eval(this.codeToBeExecuted); either = interpretResult(eval); @@ -65,9 +65,10 @@ public TryResult call() throws Exception { e.printStackTrace(pw); either = TryResult.createError(sw.toString()); } + }finally { + theOutput.clrOutputHandler(); + Thread.currentThread().setContextClassLoader(oldld); } - theOutput.clrOutputHandler(); - Thread.currentThread().setContextClassLoader(oldld); return either; } diff --git a/kernel/kotlin/src/main/java/com/twosigma/beakerx/kotlin/evaluator/KotlinEvaluator.java b/kernel/kotlin/src/main/java/com/twosigma/beakerx/kotlin/evaluator/KotlinEvaluator.java index 63c4fce50e..2d30890fcc 100644 --- a/kernel/kotlin/src/main/java/com/twosigma/beakerx/kotlin/evaluator/KotlinEvaluator.java +++ b/kernel/kotlin/src/main/java/com/twosigma/beakerx/kotlin/evaluator/KotlinEvaluator.java @@ -36,20 +36,17 @@ import java.io.File; import java.util.ArrayList; import java.util.List; -import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; -import java.util.concurrent.Future; +import static com.twosigma.beakerx.kotlin.evaluator.ReplWithClassLoaderFactory.createParentClassLoader; import static com.twosigma.beakerx.kotlin.evaluator.ReplWithClassLoaderFactory.createReplWithKotlinParentClassLoader; import static com.twosigma.beakerx.kotlin.evaluator.ReplWithClassLoaderFactory.createReplWithReplClassLoader; import static com.twosigma.beakerx.kotlin.evaluator.ReplWithClassLoaderFactory.getImportString; -import static com.twosigma.beakerx.kotlin.evaluator.ReplWithClassLoaderFactory.createParentClassLoader; import static java.util.Collections.singletonList; public class KotlinEvaluator extends BaseEvaluator { private ClasspathScanner cps; - private ExecutorService executorService; private ReplInterpreter repl; private ReplClassLoader loader = null; private BeakerxUrlClassLoader kotlinClassLoader; @@ -62,7 +59,6 @@ public KotlinEvaluator(String id, String sId, CellExecutor cellExecutor, TempFol super(id, sId, cellExecutor, tempFolderFactory, evaluatorParameters); cps = new ClasspathScanner(); createRepl(); - executorService = Executors.newSingleThreadExecutor(); } @Override @@ -106,14 +102,7 @@ public void exit() { @Override public TryResult evaluate(SimpleEvaluationObject seo, String code) { - Future submit = executorService.submit(new KotlinWorkerThread(this, new JobDescriptor(code, seo))); - TryResult either = null; - try { - either = submit.get(); - } catch (Exception e) { - either = TryResult.createError(e.getLocalizedMessage()); - } - return either; + return evaluate(seo, new KotlinWorkerThread(this, new JobDescriptor(code, seo))); } @Override diff --git a/kernel/scala/src/main/java/com/twosigma/beakerx/scala/evaluator/ScalaCodeRunner.java b/kernel/scala/src/main/java/com/twosigma/beakerx/scala/evaluator/ScalaCodeRunner.java index 9d992f8947..8b97954bab 100644 --- a/kernel/scala/src/main/java/com/twosigma/beakerx/scala/evaluator/ScalaCodeRunner.java +++ b/kernel/scala/src/main/java/com/twosigma/beakerx/scala/evaluator/ScalaCodeRunner.java @@ -41,8 +41,8 @@ public ScalaCodeRunner(ScalaEvaluator scalaEvaluator, String code, SimpleEvaluat @Override public TryResult call() throws Exception { TryResult either; - theOutput.setOutputHandler(); try { + theOutput.setOutputHandler(); InternalVariable.setValue(theOutput); either = scalaEvaluator.getShell().evaluate(theOutput, theCode); } catch (Throwable e) { @@ -54,8 +54,9 @@ public TryResult call() throws Exception { e.printStackTrace(pw); either = TryResult.createError(sw.toString()); } + } finally { + theOutput.clrOutputHandler(); } - theOutput.setOutputHandler(); return either; } diff --git a/kernel/scala/src/main/java/com/twosigma/beakerx/scala/evaluator/ScalaEvaluator.java b/kernel/scala/src/main/java/com/twosigma/beakerx/scala/evaluator/ScalaEvaluator.java index c0c21980ea..4cb4fa7ef5 100644 --- a/kernel/scala/src/main/java/com/twosigma/beakerx/scala/evaluator/ScalaEvaluator.java +++ b/kernel/scala/src/main/java/com/twosigma/beakerx/scala/evaluator/ScalaEvaluator.java @@ -41,21 +41,17 @@ import com.twosigma.beakerx.scala.serializers.ScalaPrimitiveTypeListOfListSerializer; import com.twosigma.beakerx.scala.serializers.ScalaPrimitiveTypeMapSerializer; import com.twosigma.beakerx.scala.serializers.ScalaTableDeSerializer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.io.File; import java.util.List; -import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; -import java.util.concurrent.Future; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; public class ScalaEvaluator extends BaseEvaluator { private final static Logger logger = LoggerFactory.getLogger(ScalaEvaluator.class.getName()); private BeakerxObjectFactory beakerxObjectFactory; - private ExecutorService executorService; private final Provider objectSerializerProvider; private static boolean autoTranslationSetup = false; private BeakerxUrlClassLoader classLoader; @@ -73,19 +69,11 @@ public ScalaEvaluator(String id, String sId, Provider osp this.classLoader = newClassLoader(); this.shell = createNewEvaluator(); this.acshell = newAutoCompleteEvaluator(); - this.executorService = Executors.newSingleThreadExecutor(); } @Override public TryResult evaluate(SimpleEvaluationObject seo, String code) { - Future submit = executorService.submit(new ScalaWorkerThread(this, new JobDescriptor(code, seo))); - TryResult either = null; - try { - either = submit.get(); - } catch (Exception e) { - either = TryResult.createError(e.getLocalizedMessage()); - } - return either; + return evaluate(seo, new ScalaWorkerThread(this, new JobDescriptor(code, seo))); } @Override diff --git a/kernel/scala/src/main/scala/com/twosigma/beakerx/scala/evaluator/ScalaEvaluatorGlue.scala b/kernel/scala/src/main/scala/com/twosigma/beakerx/scala/evaluator/ScalaEvaluatorGlue.scala index b6087001af..f62d3ecd64 100644 --- a/kernel/scala/src/main/scala/com/twosigma/beakerx/scala/evaluator/ScalaEvaluatorGlue.scala +++ b/kernel/scala/src/main/scala/com/twosigma/beakerx/scala/evaluator/ScalaEvaluatorGlue.scala @@ -112,9 +112,9 @@ class ScalaEvaluatorGlue(val cl: ClassLoader, var cp: String, val replClassdir: def evaluate(out: SimpleEvaluationObject, code: String): TryResult = { var either: TryResult = null baos.reset() - out.setOutputHandler() out.started() try { + out.setOutputHandler() interpreter.interpret(code) match { case Success => { val value = getOut.asInstanceOf[Object] @@ -131,8 +131,9 @@ class ScalaEvaluatorGlue(val cl: ClassLoader, var cp: String, val replClassdir: case ex: Throwable => { either = TryResult.createError(ex.getMessage()) } + } finally { + out.clrOutputHandler() } - out.clrOutputHandler() either } diff --git a/kernel/sql/src/main/java/com/twosigma/beakerx/sql/evaluator/SQLEvaluator.java b/kernel/sql/src/main/java/com/twosigma/beakerx/sql/evaluator/SQLEvaluator.java index 7eac2fecb8..3846f273a0 100644 --- a/kernel/sql/src/main/java/com/twosigma/beakerx/sql/evaluator/SQLEvaluator.java +++ b/kernel/sql/src/main/java/com/twosigma/beakerx/sql/evaluator/SQLEvaluator.java @@ -53,9 +53,7 @@ import java.util.Map.Entry; import java.util.Optional; import java.util.Scanner; -import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; -import java.util.concurrent.Future; public class SQLEvaluator extends BaseEvaluator { @@ -68,7 +66,6 @@ public class SQLEvaluator extends BaseEvaluator { private SQLAutocomplete sac; private final QueryExecutor queryExecutor; private JDBCClient jdbcClient; - private ExecutorService executorService; private DynamicClassLoaderSimple loader; public SQLEvaluator(String id, String sId, EvaluatorParameters evaluatorParameters) { @@ -94,14 +91,7 @@ public ClassLoader getClassLoader() { @Override public TryResult evaluate(SimpleEvaluationObject seo, String code) { - Future submit = executorService.submit(new SQLWorkerThread(this, new JobDescriptor(code, seo))); - TryResult either = null; - try { - either = submit.get(); - } catch (Exception e) { - either = TryResult.createError(e.getLocalizedMessage()); - } - return either; + return evaluate(seo, new SQLWorkerThread(this, new JobDescriptor(code, seo))); } @Override diff --git a/kernel/sql/src/main/java/com/twosigma/beakerx/sql/evaluator/SQLWorkerThread.java b/kernel/sql/src/main/java/com/twosigma/beakerx/sql/evaluator/SQLWorkerThread.java index 649e24ab7f..47571fe97f 100644 --- a/kernel/sql/src/main/java/com/twosigma/beakerx/sql/evaluator/SQLWorkerThread.java +++ b/kernel/sql/src/main/java/com/twosigma/beakerx/sql/evaluator/SQLWorkerThread.java @@ -36,17 +36,21 @@ class SQLWorkerThread implements Callable { @Override public TryResult call() throws Exception { - NamespaceClient namespaceClient; + NamespaceClient namespaceClient = null; TryResult r; job.getSimpleEvaluationObject().started(); - - job.getSimpleEvaluationObject().setOutputHandler(); - namespaceClient = NamespaceClient.getBeaker(sqlEvaluator.getSessionId()); - namespaceClient.setOutputObj(job.getSimpleEvaluationObject()); - - r = sqlEvaluator.executeTask(new SQLCodeRunner(sqlEvaluator, job.getSimpleEvaluationObject(), namespaceClient)); - job.getSimpleEvaluationObject().clrOutputHandler(); - namespaceClient.setOutputObj(null); + try { + job.getSimpleEvaluationObject().setOutputHandler(); + namespaceClient = NamespaceClient.getBeaker(sqlEvaluator.getSessionId()); + namespaceClient.setOutputObj(job.getSimpleEvaluationObject()); + + r = sqlEvaluator.executeTask(new SQLCodeRunner(sqlEvaluator, job.getSimpleEvaluationObject(), namespaceClient)); + } finally { + job.getSimpleEvaluationObject().clrOutputHandler(); + if (namespaceClient != null) { + namespaceClient.setOutputObj(null); + } + } return r; } diff --git a/test/notebooks/groovy/JavaWidgetsTest.ipynb b/test/notebooks/groovy/JavaWidgetsTest.ipynb index e7273f6f6f..deea84a566 100644 --- a/test/notebooks/groovy/JavaWidgetsTest.ipynb +++ b/test/notebooks/groovy/JavaWidgetsTest.ipynb @@ -156,6 +156,142 @@ "//bar.orientation = \"vertical\"" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Output usage" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import com.twosigma.beakerx.widgets.Output\n", + "out = new Output()\n", + "OutputManager.setOutput(out)\n", + "out" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "for (i = 0; i <10; i++) {\n", + " println(\"Hello \"+ i)\n", + "}\n", + "\"result loop\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "out.appendStdout(\"Hello 2\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "out.appendStderr(\"Error 1\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "out.clearOutput()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "println(\"Hello 3\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "OutputManager.setOutput(null)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "println(\"Hello 6\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Rich material can also be directed to the output area" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import com.twosigma.beakerx.widgets.Output\n", + "out2 = new Output()\n", + "OutputManager.setOutput(out2)\n", + "out2" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "println(\"before\")\n", + "out2.display(YoutubeVideo(\"gSVvxOchT8Y\"))\n", + "println(\"inside\")\n", + "out2.display(SVG(\"https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/car.svg\"))\n", + "println(\"after\")\n", + "\"done\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "out2.display(YoutubeVideo(\"gSVvxOchT8Y\"))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "out2.clearOutput()" + ] + }, { "cell_type": "code", "execution_count": null, diff --git a/test/notebooks/java/JavaTest.ipynb b/test/notebooks/java/JavaTest.ipynb index 46b002170f..1f062d2528 100644 --- a/test/notebooks/java/JavaTest.ipynb +++ b/test/notebooks/java/JavaTest.ipynb @@ -131,12 +131,80 @@ "System.out.println(t.getObjectTest());" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Output usage" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import com.twosigma.beakerx.widgets.Output;\n", + "Output out2 = new Output();\n", + "OutputManager.setOutput(out2);\n", + "return out2;" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import static java.lang.System.out;\n", + "\n", + "Thread t = new Thread(() -> {\n", + " out.println(\"Some output init\");\n", + " try {\n", + " Thread.sleep(2000);\n", + " } catch (InterruptedException e) {\n", + " }\n", + " for (int i = 0; i <10 ; i++){\n", + " out.println(\"Some output \"+ i); \n", + " }\n", + "});\n", + "out.println(\"Start\");\n", + "t.start();\n", + "//t.join();\n", + "out.println(\"end\");\n", + "return \"Thread example result\";" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "OutputManager.clearOutput();" + ] + }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], - "source": [] + "source": [ + "import static java.lang.System.out;\n", + "for (int i = 0; i <30 ; i++){\n", + " out.println(\"Done \"+ i); \n", + "}\n", + "return 3+5;" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "OutputManager.setOutput(null);" + ] } ], "metadata": {