diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..60839b8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +# IntelliJ +.idea/ +.iml + +# Gradle +.gradle/ +/build/ +*/build/ \ No newline at end of file diff --git a/README.md b/README.md index 4585e28..7e67457 100644 --- a/README.md +++ b/README.md @@ -1 +1,7 @@ -# an empty repository +# BeakerX: Beaker kernel base + +### Build and Install (linux and mac) + +``` +./gradlew clean install +``` diff --git a/base-api/build.gradle b/base-api/build.gradle new file mode 100644 index 0000000..fec3f30 --- /dev/null +++ b/base-api/build.gradle @@ -0,0 +1,28 @@ +version 'unspecified' + +repositories { + mavenCentral() +} + +dependencies { + compile group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.6.5' + compile group: 'org.apache.commons', name: 'commons-lang3', version: '3.6' + compile group: 'org.apache.commons', name: 'commons-text', version: '1.1' + compile group: 'commons-io', name: 'commons-io', version: '2.5' + compile group: 'org.slf4j', name: 'slf4j-log4j12', version: '1.7.25' + compile group: 'net.sf.py4j', name: 'py4j', version: '0.10.7' + compile group: "commons-codec", name: "commons-codec", version: "1.9" + compile group: 'com.google.code.gson', name: 'gson', version: '2.3.1' + testCompile group: 'junit', name: 'junit', version: '4.12' +} + +publishing { + publications { + maven(MavenPublication) { + groupId 'com.twosigma' + artifactId 'beakerx-kernel-base-api' + version "$beakerxVersion" + from components.java + } + } +} \ No newline at end of file diff --git a/base-api/src/main/java/com/twosigma/beakerx/AutotranslationService.java b/base-api/src/main/java/com/twosigma/beakerx/AutotranslationService.java new file mode 100644 index 0000000..c110201 --- /dev/null +++ b/base-api/src/main/java/com/twosigma/beakerx/AutotranslationService.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; + +public interface AutotranslationService { + + String BEAKERX = "beakerx"; + + String update(String name, String json); + + String get(String name); + + String close(); + + String getContextAsString(); +} diff --git a/base-api/src/main/java/com/twosigma/beakerx/BeakerXClient.java b/base-api/src/main/java/com/twosigma/beakerx/BeakerXClient.java new file mode 100644 index 0000000..2ba1a80 --- /dev/null +++ b/base-api/src/main/java/com/twosigma/beakerx/BeakerXClient.java @@ -0,0 +1,46 @@ +/* + * 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; + +import java.util.List; +import java.util.concurrent.SynchronousQueue; + +public interface BeakerXClient { + + String CODE_CELL_PATH = "codecell"; + + String URL_ARG = "urlarg"; + + void showProgressUpdate(String message, int progress); + + void delBeaker(); + + String update(String name, Object value); + + Object set(String name, Object value); + + Object get(final String name); + + SynchronousQueue getMessageQueue(String channel); + + List getCodeCells(String tagFilter); + + void runByTag(String tag); + + String getContext(); + + String urlArg(String argName); +} diff --git a/base-api/src/main/java/com/twosigma/beakerx/BeakerXClientManager.java b/base-api/src/main/java/com/twosigma/beakerx/BeakerXClientManager.java new file mode 100644 index 0000000..b2e1b31 --- /dev/null +++ b/base-api/src/main/java/com/twosigma/beakerx/BeakerXClientManager.java @@ -0,0 +1,36 @@ +/* + * 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; + + +public class BeakerXClientManager { + + public static String BEAKER_X_CLIENT_MANAGER_PATH = BeakerXClientManager.class.getName(); + public static String BEAKER_X_CLIENT_MANAGER_GET = BeakerXClientManager.class.getSimpleName() + ".get()"; + public static String BEAKER_X_CLIENT_MANAGER = BeakerXClientManager.class.getName() + ".get()"; + + private static BeakerXClient beakerXClientInst; + + public static BeakerXClient register(BeakerXClient beakerXClient) { + beakerXClientInst = beakerXClient; + return beakerXClientInst = beakerXClient; + } + + public static BeakerXClient get() { + return beakerXClientInst; + } + +} diff --git a/base-api/src/main/java/com/twosigma/beakerx/ClassLoaderSwitcher.java b/base-api/src/main/java/com/twosigma/beakerx/ClassLoaderSwitcher.java new file mode 100644 index 0000000..10397ff --- /dev/null +++ b/base-api/src/main/java/com/twosigma/beakerx/ClassLoaderSwitcher.java @@ -0,0 +1,37 @@ +/* + * 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; + +import com.twosigma.beakerx.evaluator.BaseEvaluator; + +public class ClassLoaderSwitcher { + + private ClassLoader oldld; + private BaseEvaluator baseEvaluator; + + public ClassLoaderSwitcher(BaseEvaluator baseEvaluator) { + this.baseEvaluator = baseEvaluator; + } + + public void start() { + this.oldld = Thread.currentThread().getContextClassLoader(); + Thread.currentThread().setContextClassLoader(baseEvaluator.getClassLoader()); + } + + public void end() { + Thread.currentThread().setContextClassLoader(oldld); + } +} diff --git a/base-api/src/main/java/com/twosigma/beakerx/ClasspathManager.java b/base-api/src/main/java/com/twosigma/beakerx/ClasspathManager.java new file mode 100644 index 0000000..d5205da --- /dev/null +++ b/base-api/src/main/java/com/twosigma/beakerx/ClasspathManager.java @@ -0,0 +1,30 @@ +/* + * 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; + +import com.twosigma.beakerx.kernel.KernelManager; + +import java.util.List; +import java.util.stream.Collectors; + +public class ClasspathManager { + + public static List getJars() { + List pathsAsStrings = KernelManager.get().getClasspath().getPathsAsStrings(); + return pathsAsStrings.stream() + .filter(x -> x.endsWith(".jar")).collect(Collectors.toList()); + } +} diff --git a/base-api/src/main/java/com/twosigma/beakerx/CodeCell.java b/base-api/src/main/java/com/twosigma/beakerx/CodeCell.java new file mode 100644 index 0000000..57ee82b --- /dev/null +++ b/base-api/src/main/java/com/twosigma/beakerx/CodeCell.java @@ -0,0 +1,167 @@ +/* + * Copyright 2014 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; + +import java.io.IOException; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonSerializer; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializerProvider; + +import com.twosigma.beakerx.jvm.serialization.BeakerObjectConverter; +import com.twosigma.beakerx.jvm.serialization.ObjectDeserializer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class CodeCell { + private final static Logger logger = LoggerFactory.getLogger(CodeCell.class.getName()); + @JsonProperty("execution_count") + private String executionCount; + @JsonProperty("cell_type") + private String cellType; + private Object outputs; + private Object metadata; + private String source; + + public CodeCell() { } + + public String getExecutionCount() { + return executionCount; + } + + public void setExecutionCount(String executionCount) { + this.executionCount = executionCount; + } + + public String getCellType() { + return cellType; + } + + public void setCellType(String cellType) { + this.cellType = cellType; + } + + public Object getOutputs() { + return outputs; + } + + public void setOutputs(Object outputs) { + this.outputs = outputs; + } + + public Object getMetadata() { + return metadata; + } + + public void setMetadata(Object metadata) { + this.metadata = metadata; + } + + public String getSource() { + return source; + } + + public void setSource(String source) { + this.source = source; + } + + public static class Serializer extends JsonSerializer { + + private final BeakerObjectConverter objectSerializerProvider; + + public Serializer(BeakerObjectConverter osp) { + objectSerializerProvider = osp; + } + + private BeakerObjectConverter getObjectSerializer() { + return objectSerializerProvider; + } + + @Override + public void serialize(CodeCell value, + JsonGenerator jgen, + SerializerProvider provider) + throws IOException, JsonProcessingException { + + synchronized (value) { + jgen.writeStartObject(); + jgen.writeStringField("type", "CodeCell"); + jgen.writeStringField("execution_count", value.executionCount); + jgen.writeStringField("cell_type", value.cellType); + jgen.writeFieldName("outputs"); + if (!getObjectSerializer().writeObject(value.outputs, jgen, true)) + jgen.writeString(value.outputs.toString()); + jgen.writeFieldName("metadata"); + if (!getObjectSerializer().writeObject(value.metadata, jgen, true)) + jgen.writeString(value.metadata.toString()); + jgen.writeStringField("source", value.source); + jgen.writeEndObject(); + } + } + } + + public static class DeSerializer implements ObjectDeserializer { + + private final BeakerObjectConverter parent; + + public DeSerializer(BeakerObjectConverter p) { + parent = p; + parent.addKnownBeakerType("CodeCell"); + } + + @Override + public Object deserialize(JsonNode n, ObjectMapper mapper) { + CodeCell o = null; + try { + String executionCount=null, cellType=null, source=null; + Object outputs=null; + Object metadata=null; + if (n.has("execution_count")) + executionCount = n.get("execution_count").asText(); + if (n.has("cell_type")) + cellType = n.get("cell_type").asText(); + if (n.has("source")) + source = n.get("source").asText(); + if (n.has("outputs")) + outputs = parent.deserialize(n.get("outputs"), mapper); + if (n.has("metadata")) + metadata = parent.deserialize(n.get("metadata"), mapper); + + o = new CodeCell(); + o.setExecutionCount(executionCount); + o.setCellType(cellType); + o.setSource(source); + o.setOutputs(outputs); + o.setMetadata(metadata); + } catch (Exception e) { + logger.error("exception deserializing CodeCell ", e); + e.printStackTrace(); + } + return o; + } + + @Override + public boolean canBeUsed(JsonNode n) { + return n.has("type") && n.get("type").asText().equals("CodeCell"); + } + } + +} diff --git a/base-api/src/main/java/com/twosigma/beakerx/CommRepository.java b/base-api/src/main/java/com/twosigma/beakerx/CommRepository.java new file mode 100644 index 0000000..2a2ad28 --- /dev/null +++ b/base-api/src/main/java/com/twosigma/beakerx/CommRepository.java @@ -0,0 +1,39 @@ +/* + * 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; + +import com.twosigma.beakerx.kernel.comm.Comm; + +import java.util.Set; + +public interface CommRepository { + + Comm getCommByTargetName(String targetName); + + Comm getOrCreateAutotranslationComm(); + + void closeComms(); + + Set getCommHashSet(); + + void addComm(String hash, Comm commObject); + + Comm getComm(String hash); + + void removeComm(String hash); + + boolean isCommPresent(String hash); +} diff --git a/base-api/src/main/java/com/twosigma/beakerx/DefaultJVMVariables.java b/base-api/src/main/java/com/twosigma/beakerx/DefaultJVMVariables.java new file mode 100644 index 0000000..8bb9ffb --- /dev/null +++ b/base-api/src/main/java/com/twosigma/beakerx/DefaultJVMVariables.java @@ -0,0 +1,159 @@ +/* + * Copyright 2017 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; + +import java.util.Arrays; +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; + +import static com.twosigma.beakerx.kernel.Utils.getAsString; + +/** + * @author konst + */ +public class DefaultJVMVariables { + + public static final String IMPORTS = "imports"; + public static final String CLASSPATH = "classpath"; + + /** + * Default imports + */ + private final Set IMPORT = new HashSet<>(); + + /** + * Default class path + */ + private final Set CLASS_PATH = new HashSet<>(); + + public DefaultJVMVariables() { + addImports( + "java.io.*", + "java.math.*", + "java.net.*", + "java.nio.file.*", + "java.util.*", + "java.util.concurrent.*", + "java.util.function.*", + "java.util.prefs.*", + "java.util.regex.*", + "java.util.stream.*", + "com.twosigma.beakerx.NamespaceClient", + "com.twosigma.beakerx.widget.OutputManager", + "com.twosigma.beakerx.ClasspathManager", + "com.twosigma.beakerx.chart.Color", + "com.twosigma.beakerx.chart.GradientColor", + "com.twosigma.beakerx.chart.legend.*", + "com.twosigma.beakerx.chart.Filter", + "com.twosigma.beakerx.chart.xychart.*", + "com.twosigma.beakerx.chart.xychart.plotitem.*", + "com.twosigma.beakerx.chart.categoryplot.*", + "com.twosigma.beakerx.chart.categoryplot.plotitem.*", + "com.twosigma.beakerx.chart.treemap.*", + "com.twosigma.beakerx.chart.treemap.util.*", + "net.sf.jtreemap.swing.*", + "com.twosigma.beakerx.chart.histogram.*", + "com.twosigma.beakerx.chart.heatmap.HeatMap", + //"com.twosigma.beaker.easyform.*", + //"com.twosigma.beaker.easyform.formitem.*", + "com.twosigma.beakerx.easyform.EasyForm", + "com.twosigma.beakerx.table.*", + "com.twosigma.beakerx.fileloader.CSV", + "com.twosigma.beakerx.jvm.object.OutputContainer", + "com.twosigma.beakerx.jvm.object.TabbedOutputContainerLayoutManager", + "com.twosigma.beakerx.jvm.object.GridOutputContainerLayoutManager", + "com.twosigma.beakerx.jvm.object.CyclingOutputContainerLayoutManager", + "com.twosigma.beakerx.jvm.object.OutputCell", + "com.twosigma.beakerx.table.renderer.TableDisplayCellRenderer", + "com.twosigma.beakerx.table.format.TableDisplayStringFormat", + "com.twosigma.beakerx.table.highlight.TableDisplayCellHighlighter", + "com.twosigma.beakerx.table.highlight.ThreeColorHeatmapHighlighter", + "static com.twosigma.beakerx.Display.display", + "com.twosigma.beakerx.kernel.KernelInfo", + "com.twosigma.beakerx.kernel.magic.command.BxMavenManager", + "com.twosigma.beakerx.table.TableDisplayLoadingMode" + + ); + } + + public void addImports(String... input) { + IMPORT.addAll(Arrays.asList(input)); + } + + public void addImports(Collection input) { + IMPORT.addAll(input); + } + + public void removeImports(String... input) { + IMPORT.removeAll(Arrays.asList(input)); + } + + public void removeImports(Collection input) { + IMPORT.removeAll(input); + } + + public void addClassPath(String... input) { + CLASS_PATH.addAll(Arrays.asList(input)); + } + + public void addClassPath(Collection input) { + CLASS_PATH.addAll(input); + } + + public void removeClassPath(String... input) { + CLASS_PATH.removeAll(Arrays.asList(input)); + } + + public void removeClassPath(Collection input) { + CLASS_PATH.removeAll(input); + } + + public String[] getImportsAsArray() { + return getArray(IMPORT); + } + + public String getImportsAsString() { + return getAsString(IMPORT); + } + + public Collection getImports() { + return IMPORT; + } + + public String[] getClassPathAsArray() { + return getArray(CLASS_PATH); + } + + public String getClassPathAsString() { + return getAsString(CLASS_PATH); + } + + public Collection getClassPath() { + return CLASS_PATH; + } + + private static String[] getArray(Set input) { + String[] ret = null; + if (input != null) { + ret = input.toArray(new String[input.size()]); + } else { + ret = new String[0]; + } + return ret; + } + +} diff --git a/base-api/src/main/java/com/twosigma/beakerx/KernelCloseKernelAction.java b/base-api/src/main/java/com/twosigma/beakerx/KernelCloseKernelAction.java new file mode 100644 index 0000000..e962172 --- /dev/null +++ b/base-api/src/main/java/com/twosigma/beakerx/KernelCloseKernelAction.java @@ -0,0 +1,24 @@ +/* + * Copyright 2017 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; + +import com.twosigma.beakerx.kernel.CloseKernelAction; + +public class KernelCloseKernelAction { + + public static CloseKernelAction NO_ACTION = () -> { + }; +} diff --git a/base-api/src/main/java/com/twosigma/beakerx/SimpleOutputHandler.java b/base-api/src/main/java/com/twosigma/beakerx/SimpleOutputHandler.java new file mode 100644 index 0000000..58c9ace --- /dev/null +++ b/base-api/src/main/java/com/twosigma/beakerx/SimpleOutputHandler.java @@ -0,0 +1,41 @@ +/* + * 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; + +import com.twosigma.beakerx.jvm.object.ConsoleOutput; +import com.twosigma.beakerx.jvm.object.EvaluationObject; +import com.twosigma.beakerx.jvm.threads.BeakerOutputHandler; +import com.twosigma.beakerx.kernel.threads.ResultSender; + +public class SimpleOutputHandler implements BeakerOutputHandler { + + private boolean error; + private ResultSender executionResultSender; + private EvaluationObject seo; + + public SimpleOutputHandler(boolean error, ResultSender executionResultSender, EvaluationObject seo) { + this.error = error; + this.executionResultSender = executionResultSender; + this.seo = seo; + } + + @Override + public void write(String b) { + seo.getConsoleOutput().add(new ConsoleOutput(error, b)); + executionResultSender.update(seo); + } + +} diff --git a/base-api/src/main/java/com/twosigma/beakerx/TryResult.java b/base-api/src/main/java/com/twosigma/beakerx/TryResult.java new file mode 100644 index 0000000..724cefb --- /dev/null +++ b/base-api/src/main/java/com/twosigma/beakerx/TryResult.java @@ -0,0 +1,97 @@ +/* + * 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; + +import java.util.NoSuchElementException; + +public interface TryResult { + + boolean isResult(); + + boolean isError(); + + Object result(); + + String error(); + + static CellResult createResult(Object value) { + return new CellResult(value); + } + + static CellError createError(String value) { + return new CellError(value); + } + + + final class CellResult implements TryResult { + + private final Object value; + + private CellResult(Object value) { + this.value = value; + } + + @Override + public boolean isResult() { + return true; + } + + @Override + public boolean isError() { + return false; + } + + @Override + public Object result() { + return value; + } + + @Override + public String error() { + throw new NoSuchElementException("error() on CellResult"); + } + } + + final class CellError implements TryResult { + + private final String value; + + private CellError(String value) { + this.value = value; + } + + @Override + public boolean isResult() { + return false; + } + + @Override + public boolean isError() { + return true; + } + + @Override + public Object result() { + throw new NoSuchElementException("result() on CellError"); + } + + @Override + public String error() { + return value; + } + } + +} diff --git a/base-api/src/main/java/com/twosigma/beakerx/autocomplete/AutocompleteNode.java b/base-api/src/main/java/com/twosigma/beakerx/autocomplete/AutocompleteNode.java new file mode 100644 index 0000000..6d0defc --- /dev/null +++ b/base-api/src/main/java/com/twosigma/beakerx/autocomplete/AutocompleteNode.java @@ -0,0 +1,46 @@ +/* + * 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.autocomplete; + +import java.util.Arrays; +import java.util.Collection; +import java.util.LinkedList; +import java.util.List; +import java.util.Optional; + +public abstract class AutocompleteNode { + + public static final List NO_CHILDREN = Arrays.asList(); + private String name; + private List children; + + public AutocompleteNode(String name, List children) { + this.name = name; + this.children = children; + } + + public String getName() { + return name; + } + + public Collection getChildren() { + return children; + } + + public abstract Optional matchToTheWord(String text, LinkedList parts, String last); + + public abstract Optional findNextWord(String text, LinkedList parts); +} diff --git a/base-api/src/main/java/com/twosigma/beakerx/autocomplete/AutocompleteResult.java b/base-api/src/main/java/com/twosigma/beakerx/autocomplete/AutocompleteResult.java new file mode 100644 index 0000000..cf0189a --- /dev/null +++ b/base-api/src/main/java/com/twosigma/beakerx/autocomplete/AutocompleteResult.java @@ -0,0 +1,58 @@ +/* + * Copyright 2017 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.autocomplete; + +import java.util.List; + +import static org.apache.commons.lang3.builder.EqualsBuilder.reflectionEquals; +import static org.apache.commons.lang3.builder.HashCodeBuilder.reflectionHashCode; +import static org.apache.commons.lang3.builder.ToStringBuilder.reflectionToString; + +public class AutocompleteResult { + + private List matches; + private int startIndex; + + public AutocompleteResult(List matches, int startIndex) { + this.matches = matches; + this.startIndex = startIndex; + + } + + public List getMatches() { + return matches; + } + + public int getStartIndex() { + return startIndex; + } + + @Override + public boolean equals(Object o) { + return reflectionEquals(this, o); + } + + @Override + public int hashCode() { + return reflectionHashCode(this); + } + + @Override + public String toString() { + return reflectionToString(this); + } + +} diff --git a/base-api/src/main/java/com/twosigma/beakerx/autocomplete/MagicCommandAutocompletePatterns.java b/base-api/src/main/java/com/twosigma/beakerx/autocomplete/MagicCommandAutocompletePatterns.java new file mode 100644 index 0000000..2a23b7e --- /dev/null +++ b/base-api/src/main/java/com/twosigma/beakerx/autocomplete/MagicCommandAutocompletePatterns.java @@ -0,0 +1,26 @@ +/* + * 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.autocomplete; + +import java.util.Collection; +import java.util.Optional; + +public interface MagicCommandAutocompletePatterns { + + Optional get(String first); + + Collection values(); +} diff --git a/base-api/src/main/java/com/twosigma/beakerx/evaluator/BaseEvaluator.java b/base-api/src/main/java/com/twosigma/beakerx/evaluator/BaseEvaluator.java new file mode 100644 index 0000000..4712f6b --- /dev/null +++ b/base-api/src/main/java/com/twosigma/beakerx/evaluator/BaseEvaluator.java @@ -0,0 +1,336 @@ +/* + * Copyright 2017 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.evaluator; + +import com.twosigma.beakerx.BeakerXClient; +import com.twosigma.beakerx.BeakerXClientManager; +import com.twosigma.beakerx.ClassLoaderSwitcher; +import com.twosigma.beakerx.DefaultJVMVariables; +import com.twosigma.beakerx.TryResult; +import com.twosigma.beakerx.autocomplete.MagicCommandAutocompletePatterns; +import com.twosigma.beakerx.inspect.Inspect; +import com.twosigma.beakerx.inspect.InspectResult; +import com.twosigma.beakerx.jvm.object.EvaluationObject; +import com.twosigma.beakerx.jvm.threads.CellExecutor; +import com.twosigma.beakerx.kernel.AddImportStatus; +import com.twosigma.beakerx.kernel.Classpath; +import com.twosigma.beakerx.kernel.EvaluatorParameters; +import com.twosigma.beakerx.kernel.ExecutionOptions; +import com.twosigma.beakerx.kernel.GroupName; +import com.twosigma.beakerx.kernel.ImportPath; +import com.twosigma.beakerx.kernel.Imports; +import com.twosigma.beakerx.kernel.PathToJar; +import org.apache.commons.io.FileUtils; + +import java.io.File; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Collection; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.Callable; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; + +public abstract class BaseEvaluator implements Evaluator { + + public static String INTERUPTED_MSG = "interrupted"; + protected final String shellId; + protected final String sessionId; + private final ClasspathScanner classpathScanner; + protected String outDir; + private Inspect inspect; + protected Classpath classPath; + protected Imports imports = new Imports(new ArrayList<>()); + private final CellExecutor executor; + private Path tempFolder; + private BeakerXClient beakerXClient; + protected MagicCommandAutocompletePatterns autocompletePatterns; + protected EvaluatorParameters evaluatorParameters; + private EvaluatorHooks cancelHooks = new EvaluatorHooks(); + private ClassLoaderService classLoaderService = new ClassLoaderService(); + + protected ExecutorService executorService; + protected ExecutorService executorBgkService; + private ClassLoaderSwitcher classLoaderSwitcher; + + public BaseEvaluator(String id, + String sId, + CellExecutor cellExecutor, + TempFolderFactory tempFolderFactory, + EvaluatorParameters evaluatorParameters, + BeakerXClient beakerXClient, + MagicCommandAutocompletePatterns autocompletePatterns, + ClasspathScanner classpathScanner) { + shellId = id; + sessionId = sId; + executor = cellExecutor; + tempFolder = tempFolderFactory.createTempFolder(); + this.classpathScanner = classpathScanner; + this.beakerXClient = BeakerXClientManager.register(beakerXClient); + this.autocompletePatterns = autocompletePatterns; + outDir = getOrCreateFile(tempFolder.toString() + File.separator + "outDir").getPath(); + classPath = new Classpath(); + classPath.add(new PathToJar(outDir)); + inspect = new Inspect(Paths.get(".")); + executorService = Executors.newCachedThreadPool(); + executorBgkService = Executors.newCachedThreadPool(); + this.evaluatorParameters = evaluatorParameters; + init(evaluatorParameters); + } + + @Override + public void startEvaluation() { + classLoaderSwitcher = new ClassLoaderSwitcher(this); + classLoaderSwitcher.start(); + } + + @Override + public void endEvaluation() { + classLoaderSwitcher.end(); + } + + CompletableFuture background; + + protected TryResult evaluate(EvaluationObject seo, Callable callable) { + try { + background = CompletableFuture.supplyAsync(() -> { + try { + InternalVariable.setValue(seo); + Future submit = executorService.submit(callable); + return submit.get(); + } catch (Exception e) { + throw new RuntimeException(e); + } + }, executorBgkService); + + return background.get(); + + } catch (Exception e) { + return TryResult.createError(e.getLocalizedMessage()); + } + } + + @Override + public TryResult evaluate(EvaluationObject seo, String code) { + return evaluate(seo, code, new ExecutionOptions(GroupName.generate())); + } + + @Override + public void putEvaluationInToBackground() { + background.complete(TryResult.createResult("Evaluation in the background")); + } + + protected abstract void addJarToClassLoader(PathToJar pathToJar); + + protected abstract void addImportToClassLoader(ImportPath anImport); + + protected abstract void doResetEnvironment(); + + protected void doReloadEvaluator() { + } + + public abstract ClassLoader getClassLoader(); + + public ClassLoader getClassLoaderForImport() { + return getClassLoader(); + } + + @Override + public BeakerXClient getBeakerX() { + return beakerXClient; + } + + @Override + public List addJarsToClasspath(List paths) { + LinkedList addedPaths = new LinkedList<>(); + paths.forEach(path -> { + if (addJarToClasspath(path)) { + addedPaths.add(Paths.get(path.getPath())); + } + }); + classpathScanner.scan(); + doReloadEvaluator(); + return addedPaths; + } + + private boolean addJarToClasspath(PathToJar path) { + boolean add = classPath.add(path); + if (add) { + addJarToClassLoader(path); + } + return add; + } + + @Override + public AddImportStatus addImport(ImportPath anImport) { + AddImportStatus add = imports.add(anImport, getClassLoaderForImport()); + if (AddImportStatus.ADDED.equals(add)) { + addImportToClassLoader(anImport); + } + return add; + } + + @Override + public void removeImport(ImportPath anImport) { + if (removeImportPath(anImport)) { + resetEnvironment(); + } + } + + protected boolean removeImportPath(ImportPath anImport) { + return imports.remove(anImport); + } + + @Override + public Classpath getClasspath() { + return classPath; + } + + @Override + public Imports getImports() { + return imports; + } + + protected void init(EvaluatorParameters kernelParameters) { + Map params = kernelParameters.getParams(); + initClasspath(params); + initImports(params); + } + + private void initClasspath(Map params) { + Collection listOfClassPath = (Collection) params.get(DefaultJVMVariables.CLASSPATH); + if (listOfClassPath != null) { + for (String line : listOfClassPath) { + if (!line.trim().isEmpty()) { + classPath.add(new PathToJar(line)); + } + } + } + } + + private void initImports(Map params) { + Collection listOfImports = (Collection) params.get(DefaultJVMVariables.IMPORTS); + List importPaths = new ArrayList<>(); + if (listOfImports != null) { + for (String line : listOfImports) { + if (!line.trim().isEmpty()) { + importPaths.add(new ImportPath(line)); + } + } + if (this.imports != null) { + importPaths.addAll(this.imports.getImportPaths()); + } + } + this.imports = new Imports(importPaths); + } + + @Override + public void updateEvaluatorParameters(final EvaluatorParameters kernelParameters) { + init(kernelParameters); + resetEnvironment(); + } + + public TryResult executeTask(Callable codeRunner, ExecutionOptions executionOptions) { + return executor.executeTask(codeRunner, executionOptions); + } + + @Override + public void killAllThreads() { + executor.killAllThreads(); + } + + @Override + public void cancelExecution(GroupName groupName) { + executor.cancelExecution(groupName); + cancelHooks.runHooks(); + } + + @Override + public void resetEnvironment() { + executor.killAllThreads(); + inspect = new Inspect(Paths.get("./")); + doResetEnvironment(); + } + + public String getSessionId() { + return sessionId; + } + + @Override + public String getOutDir() { + return outDir; + } + + @Override + public Path getTempFolder() { + return tempFolder; + } + + @Override + public void exit() { + beakerXClient.delBeaker(); + removeTempFolder(); + } + + private void removeTempFolder() { + try { + FileUtils.deleteQuietly(new File(getTempFolder().toString())); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @Override + public Class loadClass(String clazzName) throws ClassNotFoundException { + return classLoaderService.loadClass(clazzName, getClassLoader()); + } + + private File getOrCreateFile(String pathToMavenRepo) { + File theDir = new File(pathToMavenRepo); + if (!theDir.exists()) { + try { + theDir.mkdirs(); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + return theDir; + } + + @Override + public InspectResult inspect(String code, int caretPosition) { + return inspect.doInspect(code, caretPosition, null, imports); + } + + public Inspect getInspect() { + return inspect; + } + + @Override + public void registerCancelHook(Hook hook) { + this.cancelHooks.registerHook(hook); + } + + @Override + public boolean checkIfClassExistsInClassloader(String clazzName) { + return classLoaderService.checkIfClassExistsInClassloader(clazzName, getClassLoader()); + } +} diff --git a/base-api/src/main/java/com/twosigma/beakerx/evaluator/ClassLoaderService.java b/base-api/src/main/java/com/twosigma/beakerx/evaluator/ClassLoaderService.java new file mode 100644 index 0000000..7306ea5 --- /dev/null +++ b/base-api/src/main/java/com/twosigma/beakerx/evaluator/ClassLoaderService.java @@ -0,0 +1,33 @@ +/* + * 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.evaluator; + +public class ClassLoaderService { + + public boolean checkIfClassExistsInClassloader(String clazzName, ClassLoader classLoader) { + try { + Class.forName(clazzName, false, classLoader); + return true; + } catch (Exception e) { + return false; + } + } + + public Class loadClass(String clazzName, ClassLoader classLoader) throws ClassNotFoundException { + return classLoader.loadClass(clazzName); + } + +} diff --git a/base-api/src/main/java/com/twosigma/beakerx/evaluator/ClasspathScanner.java b/base-api/src/main/java/com/twosigma/beakerx/evaluator/ClasspathScanner.java new file mode 100644 index 0000000..4342a05 --- /dev/null +++ b/base-api/src/main/java/com/twosigma/beakerx/evaluator/ClasspathScanner.java @@ -0,0 +1,20 @@ +/* + * 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.evaluator; + +public interface ClasspathScanner { + void scan(); +} diff --git a/base-api/src/main/java/com/twosigma/beakerx/evaluator/EvaluationObjectFactory.java b/base-api/src/main/java/com/twosigma/beakerx/evaluator/EvaluationObjectFactory.java new file mode 100644 index 0000000..bfd0cc1 --- /dev/null +++ b/base-api/src/main/java/com/twosigma/beakerx/evaluator/EvaluationObjectFactory.java @@ -0,0 +1,24 @@ +/* + * 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.evaluator; + +import com.twosigma.beakerx.jvm.object.EvaluationObject; +import com.twosigma.beakerx.kernel.KernelFunctionality; +import com.twosigma.beakerx.message.Message; + +public interface EvaluationObjectFactory { + EvaluationObject createSeo(String plainCode, KernelFunctionality kernel, Message message, int executionCount); +} diff --git a/base-api/src/main/java/com/twosigma/beakerx/evaluator/Evaluator.java b/base-api/src/main/java/com/twosigma/beakerx/evaluator/Evaluator.java new file mode 100644 index 0000000..fdfbe7e --- /dev/null +++ b/base-api/src/main/java/com/twosigma/beakerx/evaluator/Evaluator.java @@ -0,0 +1,88 @@ +/* + * Copyright 2017 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.evaluator; + +import com.twosigma.beakerx.BeakerXClient; +import com.twosigma.beakerx.TryResult; +import com.twosigma.beakerx.autocomplete.AutocompleteResult; +import com.twosigma.beakerx.inspect.InspectResult; +import com.twosigma.beakerx.jvm.object.EvaluationObject; +import com.twosigma.beakerx.kernel.AddImportStatus; +import com.twosigma.beakerx.kernel.BeakerXClasspath; +import com.twosigma.beakerx.kernel.EvaluatorParameters; +import com.twosigma.beakerx.kernel.ExecutionOptions; +import com.twosigma.beakerx.kernel.GroupName; +import com.twosigma.beakerx.kernel.ImportPath; +import com.twosigma.beakerx.kernel.Imports; +import com.twosigma.beakerx.kernel.PathToJar; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.nio.file.Path; +import java.util.List; + +public interface Evaluator { + + String BEAKER_VARIABLE_NAME = "beakerx"; + + Logger logger = LoggerFactory.getLogger(Evaluator.class.getName()); + + void updateEvaluatorParameters(final EvaluatorParameters kernelParameters); + + AutocompleteResult autocomplete(String code, int caretPosition); + + InspectResult inspect(String code, int caretPosition); + + void killAllThreads(); + + void cancelExecution(GroupName groupName); + + TryResult evaluate(EvaluationObject seo, String code); + + TryResult evaluate(EvaluationObject seo, String code, ExecutionOptions executionOptions); + + void exit(); + + void resetEnvironment(); + + List addJarsToClasspath(List paths); + + BeakerXClasspath getClasspath(); + + Imports getImports(); + + AddImportStatus addImport(ImportPath anImport); + + void removeImport(ImportPath anImport); + + Path getTempFolder(); + + Class loadClass(String clazzName) throws ClassNotFoundException; + + boolean checkIfClassExistsInClassloader(String clazzName); + + String getOutDir(); + + void registerCancelHook(Hook hook); + + BeakerXClient getBeakerX(); + + void putEvaluationInToBackground(); + + void startEvaluation(); + + void endEvaluation(); +} diff --git a/base-api/src/main/java/com/twosigma/beakerx/evaluator/EvaluatorHooks.java b/base-api/src/main/java/com/twosigma/beakerx/evaluator/EvaluatorHooks.java new file mode 100644 index 0000000..007f8ea --- /dev/null +++ b/base-api/src/main/java/com/twosigma/beakerx/evaluator/EvaluatorHooks.java @@ -0,0 +1,35 @@ +/* + * 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.evaluator; + +import com.twosigma.beakerx.util.Preconditions; + +import java.util.ArrayList; +import java.util.List; + +public class EvaluatorHooks { + + private List hooks = new ArrayList<>(); + + void registerHook(Hook hook) { + hooks.add(Preconditions.checkNotNull(hook)); + } + + void runHooks() { + hooks.forEach(hook -> hook.run()); + } + +} diff --git a/base-api/src/main/java/com/twosigma/beakerx/evaluator/Hook.java b/base-api/src/main/java/com/twosigma/beakerx/evaluator/Hook.java new file mode 100644 index 0000000..dd9fdff --- /dev/null +++ b/base-api/src/main/java/com/twosigma/beakerx/evaluator/Hook.java @@ -0,0 +1,20 @@ +/* + * 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.evaluator; + +public interface Hook { + void run(); +} diff --git a/base-api/src/main/java/com/twosigma/beakerx/evaluator/InternalVariable.java b/base-api/src/main/java/com/twosigma/beakerx/evaluator/InternalVariable.java new file mode 100644 index 0000000..c9792a8 --- /dev/null +++ b/base-api/src/main/java/com/twosigma/beakerx/evaluator/InternalVariable.java @@ -0,0 +1,41 @@ +/* + * Copyright 2017 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.evaluator; + +import com.twosigma.beakerx.jvm.object.EvaluationObject; +import com.twosigma.beakerx.message.Message; + +public class InternalVariable { + + private static EvaluationObject simpleEvaluationObject = null; + + public static Message getParentHeader() { + EvaluationObject simpleEvaluationObject = getSimpleEvaluationObject(); + if (simpleEvaluationObject != null && simpleEvaluationObject.getJupyterMessage() != null) { + return simpleEvaluationObject.getJupyterMessage(); + } + return null; + } + + public static EvaluationObject getSimpleEvaluationObject() { + return simpleEvaluationObject; + } + + public static void setValue(EvaluationObject value) { + simpleEvaluationObject = value; + } + +} diff --git a/base-api/src/main/java/com/twosigma/beakerx/evaluator/TempFolderFactory.java b/base-api/src/main/java/com/twosigma/beakerx/evaluator/TempFolderFactory.java new file mode 100644 index 0000000..f2d1fef --- /dev/null +++ b/base-api/src/main/java/com/twosigma/beakerx/evaluator/TempFolderFactory.java @@ -0,0 +1,23 @@ +/* + * Copyright 2017 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.evaluator; + +import java.nio.file.Path; + +public interface TempFolderFactory { + + Path createTempFolder(); +} diff --git a/base-api/src/main/java/com/twosigma/beakerx/handler/Handler.java b/base-api/src/main/java/com/twosigma/beakerx/handler/Handler.java new file mode 100644 index 0000000..dc37179 --- /dev/null +++ b/base-api/src/main/java/com/twosigma/beakerx/handler/Handler.java @@ -0,0 +1,22 @@ +/* + * Copyright 2017 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.handler; + +public interface Handler{ + + void handle(T message) ; + +} \ No newline at end of file diff --git a/base-api/src/main/java/com/twosigma/beakerx/handler/KernelHandlerWrapper.java b/base-api/src/main/java/com/twosigma/beakerx/handler/KernelHandlerWrapper.java new file mode 100644 index 0000000..b61ac2c --- /dev/null +++ b/base-api/src/main/java/com/twosigma/beakerx/handler/KernelHandlerWrapper.java @@ -0,0 +1,32 @@ +/* + * Copyright 2017 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.handler; + +import com.twosigma.beakerx.kernel.KernelFunctionality; +import com.twosigma.beakerx.message.Message; + +public class KernelHandlerWrapper { + + public static void wrapBusyIdle(KernelFunctionality kernel, Message message, HandlerAction handlerAction) { + kernel.sendBusyMessage(message); + handlerAction.execute(); + kernel.sendIdleMessage(message); + } + + public interface HandlerAction { + void execute(); + } +} diff --git a/base-api/src/main/java/com/twosigma/beakerx/inspect/ClassInspect.java b/base-api/src/main/java/com/twosigma/beakerx/inspect/ClassInspect.java new file mode 100644 index 0000000..7eb6a42 --- /dev/null +++ b/base-api/src/main/java/com/twosigma/beakerx/inspect/ClassInspect.java @@ -0,0 +1,61 @@ +/* + * Copyright 2017 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.inspect; + +import java.util.List; + +public class ClassInspect { + String className; + String fullName; + String javadoc; + List methods; + List constructors; + + public ClassInspect(String className, String fullName, String javadoc) { + this.className = className; + this.fullName = fullName; + this.javadoc = javadoc; + } + + public String getClassName() { + return className; + } + + public String getFullName() { + return fullName; + } + + public String getJavadoc() { + return javadoc; + } + + public List getMethods() { + return methods; + } + + public void setMethods(List methods) { + this.methods = methods; + } + + public List getConstructors() { + return constructors; + } + + public void setConstructors(List constructors) { + this.constructors = constructors; + } +} diff --git a/base-api/src/main/java/com/twosigma/beakerx/inspect/CodeParsingTool.java b/base-api/src/main/java/com/twosigma/beakerx/inspect/CodeParsingTool.java new file mode 100644 index 0000000..f443aa5 --- /dev/null +++ b/base-api/src/main/java/com/twosigma/beakerx/inspect/CodeParsingTool.java @@ -0,0 +1,131 @@ +/* + * 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.inspect; + +import java.util.Arrays; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +public class CodeParsingTool { + + private CodeParsingTool(){} + + public static int getCaretPositionInLine(String code, int caretPosition) { + int begOfLine = code.substring(0, caretPosition).lastIndexOf(System.lineSeparator()); + return caretPosition - begOfLine - 1; + } + + public static String getLineWithCursor(String code, int caretPosition) { + int begOfLine = lastIndexOrZero(code.substring(0, caretPosition), System.lineSeparator()); + int endOfLine = firstIndexOrLength(code.substring(caretPosition), System.lineSeparator()); + return code.substring(begOfLine, endOfLine + caretPosition).trim(); + } + + private static int lastIndexOrZero(String string, String pattern) { + return string.lastIndexOf(pattern) == -1 ? 0 : string.lastIndexOf(pattern); + } + + private static int firstIndexOrLength(String string, String pattern) { + return string.indexOf(pattern) == -1 ? string.length() : string.indexOf(pattern); + } + + public static String getSelectedMethodName(String code, int caretPosition) { + int pos = getCaretPositionInLine(code, caretPosition); + String line = getLineWithCursor(code, caretPosition); + int begOfMethod = lastIndexOrZero(line.substring(0, pos), "."); + int bracketStart = firstIndexOrLength(line.substring(begOfMethod), "("); + if (begOfMethod == 0) { + return null; + } else { + return line.substring(begOfMethod + 1, begOfMethod + bracketStart); + } + } + + public static String getClassName(String code, int caretPosition, String methodName) { + String inspectObject = getInspectObject(code, caretPosition, methodName); + return getClassOfInspectObject(code, inspectObject); + } + + public static String getInspectObject(String code, int caretPosition, String methodName) { + String line = getLineWithCursor(code, caretPosition); + if (methodName == null || line.indexOf(methodName) < 1) { + return getClassInspectObject(code, caretPosition).trim(); + } else { + return getMethodInspectObject(methodName, line).trim(); + } + } + + private static String getMethodInspectObject(String methodName, String line) { + String lineToMethodName = line.substring(0, line.indexOf(methodName)- 1); + String lineToClassName = removeLastBracket(lineToMethodName); + return lineToClassName + .substring(lastIndexOrZero(lineToClassName, " ")) + .split("\\.")[0].trim(); + } + + + private static String getClassInspectObject(String code, int caretPosition) { + int caretPos = getCaretPositionInLine(code, caretPosition); + String line = getLineWithCursor(code, caretPosition); + int begOfClass = lastIndexOrZero(line.substring(0, caretPos), " "); + int endOfClass = line.length(); + for (char endChar : Arrays.asList(' ', '(', '.')) { + int index = line.substring(caretPos).indexOf(endChar); + if (index != -1 && index + caretPos < endOfClass) { + endOfClass = index + caretPos; + } + } + return line.substring(begOfClass, endOfClass); + } + + public static String getClassOfInspectObject(String code, String inspectObject) { + Optional inspect = getLinesWithPattern(code, inspectObject).stream() + .map(line -> line.substring(line.indexOf(inspectObject))) + .filter(line -> line.indexOf("= new ") != -1 || line.indexOf("=new ") != -1) + .map(line -> line.substring(line.indexOf("new ")+ 4)) + .filter(line -> line.indexOf("(") != -1) + .map(line -> line.substring(0, line.indexOf("("))) + .findFirst(); + return inspect.orElse(inspectObject); + } + + private static String removeLastBracket(String lineToMethodName) { + int lastBracketPos = lineToMethodName.length(); + int i = lastBracketPos - 1; + if (lineToMethodName.charAt(i) == ')') { + for (int counter = 0; i>0; i--) { + char character = lineToMethodName.charAt(i); + if (character == ')') { + counter++; + } else if (character == '(') { + counter--; + } + if (counter == 0) { + lastBracketPos = i; + break; + } + } + } + return lineToMethodName.substring(0, lastBracketPos); + } + + private static List getLinesWithPattern(String code, String pattern) { + return Arrays.stream(code.split(System.lineSeparator())) + .filter(line -> line.trim().contains(pattern)) + .collect(Collectors.toList()); + } +} diff --git a/base-api/src/main/java/com/twosigma/beakerx/inspect/Inspect.java b/base-api/src/main/java/com/twosigma/beakerx/inspect/Inspect.java new file mode 100644 index 0000000..fcfcc69 --- /dev/null +++ b/base-api/src/main/java/com/twosigma/beakerx/inspect/Inspect.java @@ -0,0 +1,129 @@ +/* + * Copyright 2017 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.inspect; + +import com.twosigma.beakerx.kernel.Imports; +import org.apache.commons.io.IOUtils; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.URLClassLoader; +import java.nio.file.Path; +import java.util.HashMap; +import java.util.List; +import java.util.stream.Collectors; + + +public class Inspect { + + private static final String COLOR_RED = "\u001B[31m"; + private static final String COLOR_RESET = "\033[0m"; + + private static String inspectDataPath = "beakerx_inspect.json"; + private Path pathToBeakerxInspectFile; + + public Inspect(Path pathToBeakerxInspectFile) { + this.pathToBeakerxInspectFile = pathToBeakerxInspectFile; + } + + public InspectResult doInspect(String code, int caretPosition, URLClassLoader classLoader, Imports imports) { + InspectResult inspectResult = new InspectResult(); + if (code.length() >= caretPosition) { + String methodName = CodeParsingTool.getSelectedMethodName(code, caretPosition); + String className = CodeParsingTool.getClassName(code, caretPosition, methodName); + try (InputStream inputStream = new FileInputStream(getInspectFile())) { + String inspectData = IOUtils.toString(inputStream, "UTF-8"); + inspectResult = getInspectResult(caretPosition, methodName, className, inspectData); + } catch (IOException e) { + e.printStackTrace(); + } + } + return inspectResult; + } + + private File getInspectFile() { +// Path workingDirectory = null; +// try { +// workingDirectory= Paths.get( +// BeakerxWidget.class.getProtectionDomain().getCodeSource().getLocation().toURI() +// ).getParent().getParent(); +// workingDirectory = pathToBeakerxInspectFile; +// } catch (URISyntaxException e) { +// e.printStackTrace(); +// } + return new File(pathToBeakerxInspectFile.toFile(), inspectDataPath); + } + + private InspectResult getInspectResult(int caretPosition, String methodName, String className, String everything) { + HashMap stringClassInspectHashMap = new SerializeInspect().fromJson(everything); + InspectResult inspectResult = new InspectResult(); + ClassInspect classInspect = null; + if (stringClassInspectHashMap.containsKey(className)) { + classInspect = stringClassInspectHashMap.get(className); + } else { + for (ClassInspect cls : stringClassInspectHashMap.values()) { + if (cls.getClassName().equals(className)) { + classInspect = cls; + break; + } + } + } + if (methodName == null && classInspect != null) { + List constructors = classInspect.getConstructors(); + String classInfo = parseClassInfo(classInspect) + "\n\n" + parseMethodsInfo(constructors, ""); + inspectResult = new InspectResult(classInfo, caretPosition); + } else { + List methodInspectsList = classInspect == null ? null : classInspect.getMethods(); + if (methodInspectsList == null) { + return new InspectResult(); + } + List methods = methodInspectsList.stream() + .filter(m -> m.getMethodName().equals(methodName)) + .collect(Collectors.toList()); + if (!methods.isEmpty()) { + return new InspectResult(parseMethodsInfo(methods, className), caretPosition); + } + } + return inspectResult; + } + + private String parseClassInfo(ClassInspect classInspect) { + return COLOR_RED + "Class: " + COLOR_RESET + classInspect.fullName + "\n" + + COLOR_RED + "JavaDoc: " + (classInspect.getJavadoc().equals("") + ? "" : COLOR_RESET + classInspect.getJavadoc()); + } + + public static void setInspectFileName(String inspectDataPath) { + Inspect.inspectDataPath = inspectDataPath; + } + + public String parseMethodsInfo(List methods, String className) { + if (methods == null) { + return ""; + } + String parsedMethods = methods.stream() + .map(m -> + COLOR_RED + "Signature: " + COLOR_RESET + className + (className.equals("") ? "" : ".") + + m.getMethodName() + "(" + m.getSignature() + ")" + "\n" + COLOR_RED + "JavaDoc: " + + (m.getJavadoc().equals("") ? "" : COLOR_RESET + m.getJavadoc())) + .collect(Collectors.joining("\n\n")); + return parsedMethods; + } +} + diff --git a/base-api/src/main/java/com/twosigma/beakerx/inspect/InspectData.java b/base-api/src/main/java/com/twosigma/beakerx/inspect/InspectData.java new file mode 100644 index 0000000..9aa4cd2 --- /dev/null +++ b/base-api/src/main/java/com/twosigma/beakerx/inspect/InspectData.java @@ -0,0 +1,33 @@ +/* + * Copyright 2017 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.inspect; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.io.Serializable; + +public class InspectData implements Serializable { + private String textplain; + + public InspectData(String textplain) { + this.textplain = textplain; + } + @JsonProperty("text/plain") + public String getTextplain() { + return textplain; + } + +} diff --git a/base-api/src/main/java/com/twosigma/beakerx/inspect/InspectResult.java b/base-api/src/main/java/com/twosigma/beakerx/inspect/InspectResult.java new file mode 100644 index 0000000..2053c04 --- /dev/null +++ b/base-api/src/main/java/com/twosigma/beakerx/inspect/InspectResult.java @@ -0,0 +1,49 @@ +/* + * Copyright 2017 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.inspect; + +public class InspectResult { + private InspectData data; + private int startIndex; + private Boolean found; + + public InspectResult(){ + this("", 0); + this.setFound(false); + } + public InspectResult(String data, int startIndex) { + this.data = new InspectData(data); + this.startIndex = startIndex; + this.found = true; + + } + + public int getStartIndex() { + return startIndex; + } + + public InspectData getData() { + return data; + } + + public Boolean getFound() { + return found; + } + + public void setFound(Boolean found) { + this.found = found; + } +} diff --git a/base-api/src/main/java/com/twosigma/beakerx/inspect/MethodInspect.java b/base-api/src/main/java/com/twosigma/beakerx/inspect/MethodInspect.java new file mode 100644 index 0000000..5f3314a --- /dev/null +++ b/base-api/src/main/java/com/twosigma/beakerx/inspect/MethodInspect.java @@ -0,0 +1,41 @@ +/* + * Copyright 2017 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.inspect; + +public class MethodInspect { + String methodName; + String javadoc; + String signature; + + public MethodInspect(String methodName, String javadoc, String signature) { + this.methodName = methodName; + this.javadoc = javadoc; + this.signature = signature; + } + + public String getMethodName() { + return methodName; + } + + public String getJavadoc() { + return javadoc; + } + + public String getSignature() { + return signature; + } +} diff --git a/base-api/src/main/java/com/twosigma/beakerx/inspect/SerializeInspect.java b/base-api/src/main/java/com/twosigma/beakerx/inspect/SerializeInspect.java new file mode 100644 index 0000000..3714b43 --- /dev/null +++ b/base-api/src/main/java/com/twosigma/beakerx/inspect/SerializeInspect.java @@ -0,0 +1,51 @@ +/* + * Copyright 2017 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.inspect; + +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.lang.reflect.Type; +import java.util.HashMap; + +public class SerializeInspect { + private Gson gson = new Gson(); + public String toJson(HashMap object){ + Type type = new TypeToken>(){}.getType(); + return gson.toJson(object, type); + } + public void saveToFile(String json){ + try { + File file = new File("beakerx_inspect.json"); + FileWriter fileWriter = new FileWriter(file); + fileWriter.write(json); + fileWriter.flush(); + fileWriter.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + public HashMap fromJson(String json){ + Type type = new TypeToken>(){}.getType(); + return gson.fromJson(json, type); + } + +} diff --git a/base-api/src/main/java/com/twosigma/beakerx/jvm/classloader/BeakerXUrlClassLoader.java b/base-api/src/main/java/com/twosigma/beakerx/jvm/classloader/BeakerXUrlClassLoader.java new file mode 100644 index 0000000..f4b4b19 --- /dev/null +++ b/base-api/src/main/java/com/twosigma/beakerx/jvm/classloader/BeakerXUrlClassLoader.java @@ -0,0 +1,72 @@ +/* + * Copyright 2017 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.jvm.classloader; + +import com.twosigma.beakerx.kernel.PathToJar; + +import java.net.URL; +import java.net.URLClassLoader; +import java.util.ArrayList; +import java.util.List; + +import static com.twosigma.beakerx.util.Preconditions.checkNotNull; + +public class BeakerXUrlClassLoader extends URLClassLoader { + + public BeakerXUrlClassLoader(URL[] urls, ClassLoader parent) { + super(urls, parent); + } + + public BeakerXUrlClassLoader(ClassLoader parent) { + this(new URL[0], parent); + } + + public BeakerXUrlClassLoader() { + this(ClassLoader.getSystemClassLoader()); + } + + public void addJar(URL url) { + super.addURL(checkNotNull(url)); + } + + public void addJar(PathToJar pathToJar) { + super.addURL(checkNotNull(pathToJar.getUrl())); + } + + public void addPathToJars(List paths) { + for (PathToJar dir : paths) { + addJar(dir); + } + } + + public static List createUrls(List dirs) { + List urlList = new ArrayList<>(); + for (PathToJar dir : dirs) { + urlList.add(dir.getUrl()); + } + return urlList; + } + + public Class parseClass(String clazz) { + return null; + } + + + @Override + public Package getPackage(String name) { + return super.getPackage(name); + } +} diff --git a/base-api/src/main/java/com/twosigma/beakerx/jvm/object/Configuration.java b/base-api/src/main/java/com/twosigma/beakerx/jvm/object/Configuration.java new file mode 100644 index 0000000..d993c6f --- /dev/null +++ b/base-api/src/main/java/com/twosigma/beakerx/jvm/object/Configuration.java @@ -0,0 +1,90 @@ +/* + * 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.jvm.object; + +import com.twosigma.beakerx.jvm.threads.BeakerInputHandler; +import com.twosigma.beakerx.jvm.threads.BeakerOutputHandler; +import com.twosigma.beakerx.kernel.threads.ResultSender; +import com.twosigma.beakerx.message.Message; + +import static com.twosigma.beakerx.util.Preconditions.checkNotNull; +import static org.apache.commons.lang3.builder.EqualsBuilder.reflectionEquals; +import static org.apache.commons.lang3.builder.HashCodeBuilder.reflectionHashCode; +import static org.apache.commons.lang3.builder.ToStringBuilder.reflectionToString; + +public class Configuration { + + private final Message message; + private final int executionCount; + private final BeakerInputHandler stdin; + private final ResultSender resultSender; + private final BeakerOutputHandler stdout; + private final BeakerOutputHandler stderr; + + + public Configuration(BeakerInputHandler stdin, + BeakerOutputHandler stdout, + BeakerOutputHandler stderr, + ResultSender resultSender, + Message message, + int executionCount) { + this.stdin = checkNotNull(stdin); + this.resultSender = checkNotNull(resultSender); + this.stdout = checkNotNull(stdout); + this.stderr = checkNotNull(stderr); + this.message = checkNotNull(message); + this.executionCount = executionCount; + } + + public BeakerOutputHandler getStdout() { + return stdout; + } + + public BeakerOutputHandler getStderr() { + return stderr; + } + + public Message getMessage() { + return message; + } + + public int getExecutionCount() { + return executionCount; + } + + public BeakerInputHandler getStdin() { + return stdin; + } + + public ResultSender getResultSender() { + return resultSender; + } + + @Override + public boolean equals(Object o) { + return reflectionEquals(this, o); + } + + @Override + public int hashCode() { + return reflectionHashCode(this); + } + + @Override + public String toString() { + return reflectionToString(this); + } +} diff --git a/base-api/src/main/java/com/twosigma/beakerx/jvm/object/ConfigurationFactory.java b/base-api/src/main/java/com/twosigma/beakerx/jvm/object/ConfigurationFactory.java new file mode 100644 index 0000000..8ce11b1 --- /dev/null +++ b/base-api/src/main/java/com/twosigma/beakerx/jvm/object/ConfigurationFactory.java @@ -0,0 +1,20 @@ +/* + * 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.jvm.object; + +public interface ConfigurationFactory { + Configuration create(EvaluationObject seo); +} diff --git a/base-api/src/main/java/com/twosigma/beakerx/jvm/object/ConsoleOutput.java b/base-api/src/main/java/com/twosigma/beakerx/jvm/object/ConsoleOutput.java new file mode 100644 index 0000000..2d99175 --- /dev/null +++ b/base-api/src/main/java/com/twosigma/beakerx/jvm/object/ConsoleOutput.java @@ -0,0 +1,50 @@ +/* + * Copyright 2017 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.jvm.object; + +public class ConsoleOutput { + + private boolean error; + private String text; + private boolean printed; + + public ConsoleOutput(boolean error, String text){ + this.error = error; + this.text = text; + } + + public boolean isError() { + return error; + } + + public String getText() { + return text; + } + + public boolean isPrinted() { + return printed; + } + + public void setPrinted(boolean printed) { + this.printed = printed; + } + + @Override + public String toString() { + return "Error: " + error + " Text: " + text; + } + +} \ No newline at end of file diff --git a/base-api/src/main/java/com/twosigma/beakerx/jvm/object/EvaluationObject.java b/base-api/src/main/java/com/twosigma/beakerx/jvm/object/EvaluationObject.java new file mode 100644 index 0000000..88c5bc2 --- /dev/null +++ b/base-api/src/main/java/com/twosigma/beakerx/jvm/object/EvaluationObject.java @@ -0,0 +1,55 @@ +/* + * 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.jvm.object; + +import com.twosigma.beakerx.message.Message; + +import java.util.List; +import java.util.Queue; + +public interface EvaluationObject { + boolean isShowResult(); + + void started(); + + void finished(Object r); + + void error(Object r); + + void update(Object r); + + String getExpression(); + + EvaluationStatus getStatus(); + + Object getPayload(); + + void structuredUpdate(String message, int progress); + + void noResult(); + + Message getJupyterMessage(); + + Queue getConsoleOutput(); + + int getExecutionCount(); + + List getOutputdata(); + + void setOutputHandler(); + + void clrOutputHandler(); +} diff --git a/base-api/src/main/java/com/twosigma/beakerx/jvm/object/EvaluationStatus.java b/base-api/src/main/java/com/twosigma/beakerx/jvm/object/EvaluationStatus.java new file mode 100644 index 0000000..9e048d5 --- /dev/null +++ b/base-api/src/main/java/com/twosigma/beakerx/jvm/object/EvaluationStatus.java @@ -0,0 +1,20 @@ +/* + * 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.jvm.object; + +public enum EvaluationStatus { + QUEUED, RUNNING, FINISHED, ERROR +} diff --git a/base-api/src/main/java/com/twosigma/beakerx/jvm/serialization/BeakerObjectConverter.java b/base-api/src/main/java/com/twosigma/beakerx/jvm/serialization/BeakerObjectConverter.java new file mode 100644 index 0000000..29050c1 --- /dev/null +++ b/base-api/src/main/java/com/twosigma/beakerx/jvm/serialization/BeakerObjectConverter.java @@ -0,0 +1,44 @@ +/* + * Copyright 2014 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.jvm.serialization; + +import java.io.IOException; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; + +public interface BeakerObjectConverter { + public boolean isPrimitiveType(String tn); + public boolean writeObject(Object obj, JsonGenerator jgen, boolean expand) throws IOException, JsonProcessingException; + public String convertType(String tn); + public Object deserialize(JsonNode n, ObjectMapper mapper); + + public void addTypeConversion(String from, String to); + public void addTypeDeserializer(ObjectDeserializer o); + public void addTypeSerializer(ObjectSerializer o); + + public void addfTypeDeserializer(ObjectDeserializer o); + public void addfTypeSerializer(ObjectSerializer o); + + public void addThreadSpecificTypeConversion(String from, String to); + public void addThreadSpecificTypeDeserializer(ObjectDeserializer o); + public void addThreadSpecificTypeSerializer(ObjectSerializer o); + + public void addKnownBeakerType(String t); + public boolean isKnownBeakerType(String t); +} diff --git a/base-api/src/main/java/com/twosigma/beakerx/jvm/serialization/ObjectDeserializer.java b/base-api/src/main/java/com/twosigma/beakerx/jvm/serialization/ObjectDeserializer.java new file mode 100644 index 0000000..36be1bf --- /dev/null +++ b/base-api/src/main/java/com/twosigma/beakerx/jvm/serialization/ObjectDeserializer.java @@ -0,0 +1,25 @@ +/* + * Copyright 2014 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.jvm.serialization; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; + +public interface ObjectDeserializer { + public boolean canBeUsed(JsonNode n); + public Object deserialize(JsonNode n, ObjectMapper mapper); +} diff --git a/base-api/src/main/java/com/twosigma/beakerx/jvm/serialization/ObjectSerializer.java b/base-api/src/main/java/com/twosigma/beakerx/jvm/serialization/ObjectSerializer.java new file mode 100644 index 0000000..62c1d11 --- /dev/null +++ b/base-api/src/main/java/com/twosigma/beakerx/jvm/serialization/ObjectSerializer.java @@ -0,0 +1,26 @@ +/* + * Copyright 2014 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.jvm.serialization; + +import java.io.IOException; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.JsonGenerator; + +public interface ObjectSerializer { + public boolean canBeUsed(Object obj, boolean expand); + public boolean writeObject(Object obj, JsonGenerator jgen, boolean expand) throws JsonProcessingException, IOException; +} diff --git a/base-api/src/main/java/com/twosigma/beakerx/jvm/threads/BeakerCellExecutor.java b/base-api/src/main/java/com/twosigma/beakerx/jvm/threads/BeakerCellExecutor.java new file mode 100644 index 0000000..5eb230d --- /dev/null +++ b/base-api/src/main/java/com/twosigma/beakerx/jvm/threads/BeakerCellExecutor.java @@ -0,0 +1,157 @@ +/* + * Copyright 2014 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.jvm.threads; + +import com.twosigma.beakerx.TryResult; +import com.twosigma.beakerx.kernel.ExecutionOptions; +import com.twosigma.beakerx.kernel.GroupName; + +import java.lang.Thread.State; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.Callable; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.FutureTask; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.locks.ReentrantLock; + + +public class BeakerCellExecutor implements CellExecutor { + + private static final int KILL_THREAD_SLEEP_IN_MILLIS = 2000; + private static AtomicInteger count = new AtomicInteger(); + + private final String prefix; + private final ReentrantLock theLock; + private ConcurrentLinkedQueue threadGroups = new ConcurrentLinkedQueue<>(); + private int killThreadSleepInMillis; + + public BeakerCellExecutor(String prf, int killThreadSleepInMillis) { + prefix = prf; + theLock = new ReentrantLock(); + this.killThreadSleepInMillis = killThreadSleepInMillis; + reset(); + } + + public BeakerCellExecutor(String prf) { + this(prf, KILL_THREAD_SLEEP_IN_MILLIS); + } + + private void reset() { + theLock.lock(); + threadGroups = new ConcurrentLinkedQueue<>(); + theLock.unlock(); + } + + @Override + public TryResult executeTask(Callable tsk, ExecutionOptions executionOptions) { + FutureTask ret; + try { + theLock.lock(); + ret = executeTaskInNewThread(tsk, executionOptions.getGroupName()); + } catch (Throwable t) { + t.printStackTrace(); + return TryResult.createError(t.getMessage()); + } finally { + theLock.unlock(); + } + return getResult(ret); + } + + private TryResult getResult(FutureTask ret) { + TryResult o; + try { + o = ret.get(); + } catch (Exception e) { + e.printStackTrace(); + return TryResult.createError(e.getMessage()); + } + + if (ret.isCancelled()) + return TryResult.createError("Cancelled"); + return o; + } + + private FutureTask executeTaskInNewThread(Callable tsk, GroupName groupName) { + ThreadGroup threadGroup = new ThreadGroup(groupName + "_" + prefix + "TG" + count.getAndIncrement()); + threadGroups.add(threadGroup); + FutureTask ret = new FutureTask<>(tsk); + Thread t = new Thread(threadGroup, ret); + t.start(); + return ret; + } + + @Override + public void cancelExecution(GroupName groupName) { + try { + theLock.lock(); + threadGroups.stream() + .filter(thg -> thg.getName().contains(groupName.asString())) + .forEach(thg -> { + List tlist = getThreadList(thg); + for (Thread t : tlist) { + killThread(t); + } + threadGroups.remove(thg); + }); + } finally { + theLock.unlock(); + } + } + + public List getThreadList(ThreadGroup thrGroup) { + int nAlloc = thrGroup.activeCount(); + if (nAlloc == 0) + return new ArrayList(); + int n = 0; + Thread[] threads; + do { + nAlloc *= 2; + threads = new Thread[nAlloc]; + n = thrGroup.enumerate(threads); + } while (n == nAlloc); + return Arrays.asList(threads); + } + + private void killThread(Thread thr) { + if (null == thr) return; + thr.interrupt(); + try { + Thread.sleep(killThreadSleepInMillis); + } catch (InterruptedException ex) { + } + if (!thr.getState().equals(State.TERMINATED)) { + thr.stop(); + } + } + + @Override + public void killAllThreads() { + try { + theLock.lock(); + threadGroups.forEach(y -> { + List tlist = getThreadList(y); + for (Thread t : tlist) { + killThread(t); + } + }); + } finally { + theLock.unlock(); + reset(); + } + } +} diff --git a/base-api/src/main/java/com/twosigma/beakerx/jvm/threads/BeakerInputHandler.java b/base-api/src/main/java/com/twosigma/beakerx/jvm/threads/BeakerInputHandler.java new file mode 100644 index 0000000..6bf8519 --- /dev/null +++ b/base-api/src/main/java/com/twosigma/beakerx/jvm/threads/BeakerInputHandler.java @@ -0,0 +1,20 @@ +/* + * 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.jvm.threads; + +public interface BeakerInputHandler { + int read(); +} diff --git a/base-api/src/main/java/com/twosigma/beakerx/jvm/threads/BeakerOutputHandler.java b/base-api/src/main/java/com/twosigma/beakerx/jvm/threads/BeakerOutputHandler.java new file mode 100644 index 0000000..8389833 --- /dev/null +++ b/base-api/src/main/java/com/twosigma/beakerx/jvm/threads/BeakerOutputHandler.java @@ -0,0 +1,20 @@ +/* + * Copyright 2014 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.jvm.threads; + +public interface BeakerOutputHandler { + void write(String text); +} diff --git a/base-api/src/main/java/com/twosigma/beakerx/jvm/threads/CellExecutor.java b/base-api/src/main/java/com/twosigma/beakerx/jvm/threads/CellExecutor.java new file mode 100644 index 0000000..5423999 --- /dev/null +++ b/base-api/src/main/java/com/twosigma/beakerx/jvm/threads/CellExecutor.java @@ -0,0 +1,31 @@ +/* + * Copyright 2017 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.jvm.threads; + +import com.twosigma.beakerx.TryResult; +import com.twosigma.beakerx.kernel.ExecutionOptions; +import com.twosigma.beakerx.kernel.GroupName; + +import java.util.concurrent.Callable; + +public interface CellExecutor { + + TryResult executeTask(Callable tsk, ExecutionOptions executionOptions); + + void cancelExecution(GroupName groupName); + + void killAllThreads(); +} diff --git a/base-api/src/main/java/com/twosigma/beakerx/kernel/AddImportStatus.java b/base-api/src/main/java/com/twosigma/beakerx/kernel/AddImportStatus.java new file mode 100644 index 0000000..cf55b1a --- /dev/null +++ b/base-api/src/main/java/com/twosigma/beakerx/kernel/AddImportStatus.java @@ -0,0 +1,22 @@ +/* + * Copyright 2017 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.kernel; + +public enum AddImportStatus { + ADDED, + EXISTS, + ERROR +} diff --git a/base-api/src/main/java/com/twosigma/beakerx/kernel/BeakerXClasspath.java b/base-api/src/main/java/com/twosigma/beakerx/kernel/BeakerXClasspath.java new file mode 100644 index 0000000..4b199ca --- /dev/null +++ b/base-api/src/main/java/com/twosigma/beakerx/kernel/BeakerXClasspath.java @@ -0,0 +1,34 @@ +/* + * 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.kernel; + +import java.util.List; + +public interface BeakerXClasspath { + boolean isJarOnClasspath(String jarName); + + boolean add(final PathToJar path); + + List getPaths(); + + List getPathsAsStrings(); + + int size(); + + String get(int index); + + boolean isEmpty(); +} diff --git a/base-api/src/main/java/com/twosigma/beakerx/kernel/BeakerXJson.java b/base-api/src/main/java/com/twosigma/beakerx/kernel/BeakerXJson.java new file mode 100644 index 0000000..6159864 --- /dev/null +++ b/base-api/src/main/java/com/twosigma/beakerx/kernel/BeakerXJson.java @@ -0,0 +1,25 @@ +/* + * 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.kernel; + +import java.util.Map; + +public interface BeakerXJson { + + Map beakerxJsonAsMap(); + + void save(Map map); +} diff --git a/base-api/src/main/java/com/twosigma/beakerx/kernel/CacheFolderFactory.java b/base-api/src/main/java/com/twosigma/beakerx/kernel/CacheFolderFactory.java new file mode 100644 index 0000000..abee7b5 --- /dev/null +++ b/base-api/src/main/java/com/twosigma/beakerx/kernel/CacheFolderFactory.java @@ -0,0 +1,22 @@ +/* + * Copyright 2017 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.kernel; + +import java.nio.file.Path; + +public interface CacheFolderFactory { + Path getCache(); +} \ No newline at end of file diff --git a/base-api/src/main/java/com/twosigma/beakerx/kernel/Classpath.java b/base-api/src/main/java/com/twosigma/beakerx/kernel/Classpath.java new file mode 100644 index 0000000..c009d29 --- /dev/null +++ b/base-api/src/main/java/com/twosigma/beakerx/kernel/Classpath.java @@ -0,0 +1,70 @@ +/* + * Copyright 2017 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.kernel; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +import static com.twosigma.beakerx.util.Preconditions.checkNotNull; +import static java.util.stream.Collectors.toList; + +public class Classpath implements BeakerXClasspath{ + + public static final String DELIMITER = System.lineSeparator(); + + private List paths = new ArrayList<>(); + + public boolean add(final PathToJar path) { + checkNotNull(path); + if (!paths.contains(path)) { + return this.paths.add(path); + } + return false; + } + + public List getPaths() { + return paths; + } + + public List getPathsAsStrings() { + return paths.stream().map(PathToJar::getPath).collect(toList()); + } + + public int size() { + return paths.size(); + } + + public String get(int index) { + return paths.get(index).getPath(); + } + + public boolean isEmpty() { + return paths.isEmpty(); + } + + @Override + public String toString() { + return paths.stream() + .map(PathToJar::getPath) + .collect(Collectors.joining(DELIMITER)); + } + + public boolean isJarOnClasspath(String jarName) { + return getPathsAsStrings().stream() + .anyMatch(x -> x.contains(jarName)); + } +} diff --git a/base-api/src/main/java/com/twosigma/beakerx/kernel/CloseKernelAction.java b/base-api/src/main/java/com/twosigma/beakerx/kernel/CloseKernelAction.java new file mode 100644 index 0000000..78b5ca9 --- /dev/null +++ b/base-api/src/main/java/com/twosigma/beakerx/kernel/CloseKernelAction.java @@ -0,0 +1,21 @@ +/* + * Copyright 2017 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.kernel; + +@FunctionalInterface +public interface CloseKernelAction { + void close(); +} diff --git a/base-api/src/main/java/com/twosigma/beakerx/kernel/Code.java b/base-api/src/main/java/com/twosigma/beakerx/kernel/Code.java new file mode 100644 index 0000000..5b6b63e --- /dev/null +++ b/base-api/src/main/java/com/twosigma/beakerx/kernel/Code.java @@ -0,0 +1,108 @@ +/* + * Copyright 2017 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.kernel; + +import com.twosigma.beakerx.evaluator.EvaluationObjectFactory; +import com.twosigma.beakerx.kernel.magic.command.outcome.MagicCommandOutcomeItem; +import com.twosigma.beakerx.message.Message; + +import java.util.List; + +import static com.twosigma.beakerx.util.Preconditions.checkNotNull; +import static org.apache.commons.lang3.builder.EqualsBuilder.reflectionEquals; +import static org.apache.commons.lang3.builder.HashCodeBuilder.reflectionHashCode; +import static org.apache.commons.lang3.builder.ToStringBuilder.reflectionToString; + +public class Code { + + private final String allCode; + private final List errors; + private final Message message; + private final MessageCreatorService mesasgeCreatorService; + private List codeFrames; + + private Code(String allCode, List codeFrames, List errors, Message message, MessageCreatorService mesasgeCreatorService) { + this.allCode = allCode; + this.codeFrames = checkNotNull(codeFrames); + this.errors = checkNotNull(errors); + this.message = message; + this.mesasgeCreatorService = mesasgeCreatorService; + } + + public static Code createCode(String allCode, List codeFrames, List errors, Message message, MessageCreatorService mesasgeCreatorService, EvaluationObjectFactory evaluationObjectFactory) { + return new Code(allCode, codeFrames, errors, message, mesasgeCreatorService); + } + + public List getCodeFrames() { + return codeFrames; + } + + public String asString() { + return this.allCode; + } + + public boolean hasErrors() { + return !errors.isEmpty(); + } + + public List getErrors() { + return errors; + } + + @Override + public boolean equals(Object o) { + return reflectionEquals(this, o); + } + + @Override + public int hashCode() { + return reflectionHashCode(this); + } + + @Override + public String toString() { + return reflectionToString(this); + } + + public Message getMessage() { + return message; + } + + public void execute(KernelFunctionality kernel, int executionCount) { + if (hasErrors()) { + errors.forEach(item -> { + item.sendMagicCommandOutcome(kernel, message, executionCount); + kernel.send(mesasgeCreatorService.buildReplyWithErrorStatus(message, executionCount)); + }); + } else { + try { + kernel.startEvaluation(); + takeCodeFramesWithoutLast().forEach(frame -> frame.executeFrame(this, kernel, message, executionCount)); + takeLastCodeFrame().executeLastFrame(this, kernel, message, executionCount); + } finally { + kernel.endEvaluation(); + } + } + } + + private CodeFrame takeLastCodeFrame() { + return getCodeFrames().get(getCodeFrames().size() - 1); + } + + private List takeCodeFramesWithoutLast() { + return getCodeFrames().subList(0, getCodeFrames().size() - 1); + } +} diff --git a/base-api/src/main/java/com/twosigma/beakerx/kernel/CodeFrame.java b/base-api/src/main/java/com/twosigma/beakerx/kernel/CodeFrame.java new file mode 100644 index 0000000..4cbad81 --- /dev/null +++ b/base-api/src/main/java/com/twosigma/beakerx/kernel/CodeFrame.java @@ -0,0 +1,49 @@ +/* + * 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.kernel; + +import com.twosigma.beakerx.TryResult; +import com.twosigma.beakerx.kernel.magic.command.outcome.MagicCommandOutcomeItem; +import com.twosigma.beakerx.message.Message; +import com.twosigma.beakerx.jvm.object.EvaluationObject; + +import java.util.Optional; + +public abstract class CodeFrame { + + public CodeFrame() { + } + + public abstract void executeFrame(Code code, KernelFunctionality kernel, Message message, int executionCount); + + public abstract void executeLastFrame(Code code, KernelFunctionality kernel, Message message, int executionCount); + + public abstract Optional getError(); + + public static void handleResult(EvaluationObject seo, TryResult either) { + if (either != null) { + try { + if (either.isResult()) { + seo.finished(either.result()); + } else { + seo.error(either.error()); + } + } catch (Exception e) { + seo.error(e.toString()); + } + } + } +} diff --git a/base-api/src/main/java/com/twosigma/beakerx/kernel/EvaluatorParameters.java b/base-api/src/main/java/com/twosigma/beakerx/kernel/EvaluatorParameters.java new file mode 100644 index 0000000..0e62b92 --- /dev/null +++ b/base-api/src/main/java/com/twosigma/beakerx/kernel/EvaluatorParameters.java @@ -0,0 +1,59 @@ +/* + * Copyright 2017 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.kernel; + +import java.util.Map; +import java.util.Optional; + +import static com.twosigma.beakerx.util.Preconditions.checkNotNull; +import static org.apache.commons.lang3.builder.EqualsBuilder.reflectionEquals; +import static org.apache.commons.lang3.builder.HashCodeBuilder.reflectionHashCode; +import static org.apache.commons.lang3.builder.ToStringBuilder.reflectionToString; + +public class EvaluatorParameters { + + private Map params; + + public EvaluatorParameters(Map params) { + this.params = checkNotNull(params); + } + + public Map getParams() { + return params; + } + + public Optional getParam(String key, Class clazz) { + if (params.containsKey(key)) { + return Optional.of(clazz.cast(params.get(key))); + } + return Optional.empty(); + } + + @Override + public boolean equals(Object o) { + return reflectionEquals(this, o); + } + + @Override + public int hashCode() { + return reflectionHashCode(this); + } + + @Override + public String toString() { + return reflectionToString(this); + } +} diff --git a/base-api/src/main/java/com/twosigma/beakerx/kernel/ExecutionOptions.java b/base-api/src/main/java/com/twosigma/beakerx/kernel/ExecutionOptions.java new file mode 100644 index 0000000..d6624ea --- /dev/null +++ b/base-api/src/main/java/com/twosigma/beakerx/kernel/ExecutionOptions.java @@ -0,0 +1,31 @@ +/* + * 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.kernel; + +import com.twosigma.beakerx.util.Preconditions; + +public class ExecutionOptions { + + private GroupName groupName; + + public ExecutionOptions(GroupName groupName) { + this.groupName = Preconditions.checkNotNull(groupName); + } + + public GroupName getGroupName() { + return groupName; + } +} diff --git a/base-api/src/main/java/com/twosigma/beakerx/kernel/GroupName.java b/base-api/src/main/java/com/twosigma/beakerx/kernel/GroupName.java new file mode 100644 index 0000000..72cb1a0 --- /dev/null +++ b/base-api/src/main/java/com/twosigma/beakerx/kernel/GroupName.java @@ -0,0 +1,60 @@ +/* + * 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.kernel; + +import com.twosigma.beakerx.util.Preconditions; + +import java.util.UUID; + +import static org.apache.commons.lang3.builder.EqualsBuilder.reflectionEquals; +import static org.apache.commons.lang3.builder.HashCodeBuilder.reflectionHashCode; +import static org.apache.commons.lang3.builder.ToStringBuilder.reflectionToString; + +public class GroupName { + + private String groupName; + + private GroupName(String groupName) { + this.groupName = Preconditions.checkNotNull(groupName); + } + + public static GroupName generate() { + return new GroupName(UUID.randomUUID().toString()); + } + + public static GroupName of(String groupname) { + return new GroupName(groupname); + } + + public String asString() { + return groupName; + } + + @Override + public boolean equals(Object o) { + return reflectionEquals(this, o); + } + + @Override + public int hashCode() { + return reflectionHashCode(this); + } + + @Override + public String toString() { + return reflectionToString(this); + } +} diff --git a/base-api/src/main/java/com/twosigma/beakerx/kernel/ImportPath.java b/base-api/src/main/java/com/twosigma/beakerx/kernel/ImportPath.java new file mode 100644 index 0000000..5c24a6e --- /dev/null +++ b/base-api/src/main/java/com/twosigma/beakerx/kernel/ImportPath.java @@ -0,0 +1,59 @@ +/* + * Copyright 2017 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.kernel; + +import static com.twosigma.beakerx.util.Preconditions.checkNotNull; +import static com.twosigma.beakerx.util.Preconditions.checkState; +import static org.apache.commons.lang3.builder.EqualsBuilder.reflectionEquals; +import static org.apache.commons.lang3.builder.HashCodeBuilder.reflectionHashCode; +import static org.apache.commons.lang3.builder.ToStringBuilder.reflectionToString; + +public class ImportPath { + + private String anImport; + + public ImportPath(String anImport) { + checkState(!checkNotNull(anImport).isEmpty()); + this.anImport = anImport; + } + + public String asString() { + return anImport; + } + + public boolean isStatic() { + return anImport.startsWith("static"); + } + + @Override + public boolean equals(Object o) { + return reflectionEquals(this, o); + } + + @Override + public int hashCode() { + return reflectionHashCode(this); + } + + @Override + public String toString() { + return reflectionToString(this); + } + + public String path() { + return isStatic() ? anImport.replace("static ", "") : anImport; + } +} diff --git a/base-api/src/main/java/com/twosigma/beakerx/kernel/Imports.java b/base-api/src/main/java/com/twosigma/beakerx/kernel/Imports.java new file mode 100644 index 0000000..394e9ba --- /dev/null +++ b/base-api/src/main/java/com/twosigma/beakerx/kernel/Imports.java @@ -0,0 +1,178 @@ +/* + * Copyright 2017 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.kernel; + +import com.twosigma.beakerx.util.ClassPath; +import java.io.IOException; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +import static com.twosigma.beakerx.util.Preconditions.checkNotNull; +import static com.twosigma.beakerx.kernel.AddImportStatus.ADDED; +import static com.twosigma.beakerx.kernel.AddImportStatus.EXISTS; + +public class Imports { + + private List imports; + private List importsAsStrings = null; + + public Imports(List importPaths) { + this.imports = checkNotNull(importPaths); + } + + public List getImportPaths() { + return imports; + } + + public AddImportStatus add(ImportPath anImport, ClassLoader classLoader) { + checkNotNull(anImport); + if (this.imports.contains(anImport)) { + return AddImportStatus.EXISTS; + } + if (!isImportPathValid(anImport, classLoader)) { + return AddImportStatus.ERROR; + } + clear(); + this.imports.add(anImport); + return AddImportStatus.ADDED; + } + + public boolean remove(ImportPath anImport) { + checkNotNull(anImport); + if (this.imports.contains(anImport)) { + clear(); + return this.imports.remove(anImport); + } + return false; + } + + public boolean isEmpty() { + return imports.isEmpty(); + } + + public List toListOfStrings() { + if (importsAsStrings == null) { + this.importsAsStrings = importsToStrings(); + } + return this.importsAsStrings; + } + + private List importsToStrings() { + List importsAsStrings = new ArrayList<>(); + for (ImportPath st : getImportPaths()) { + importsAsStrings.add(st.asString()); + } + return importsAsStrings; + } + + private void clear() { + this.importsAsStrings = null; + } + + @Override + public String toString() { + return imports.stream().map(ImportPath::asString).collect(Collectors.joining("\n")); + } + + private boolean isImportPathValid(ImportPath anImport, ClassLoader classLoader) { + if (anImport.isStatic()) { + return isValidStaticImport(anImport, classLoader); + } else { + return isValidImport(anImport, classLoader); + } + } + + private boolean isValidStaticImport(ImportPath anImport, ClassLoader classLoader) { + String importToCheck = anImport.path(); + if (!importToCheck.contains(".")) { + return false; + } + if (importToCheck.endsWith(".*")) { + return isValidStaticImportWithWildcard(classLoader, importToCheck); + } else { + return isValidStatic(classLoader, importToCheck); + } + } + + private boolean isValidImport(ImportPath anImport, ClassLoader classLoader) { + String importToCheck = anImport.path(); + if (importToCheck.endsWith(".*")) { + return isValidImportWithWildcard(importToCheck, classLoader); + } else { + return isValidClassImport(importToCheck, classLoader); + } + } + + private boolean isValidStaticImportWithWildcard(ClassLoader classLoader, String importToCheck) { + String classImport = importToCheck.substring(0, importToCheck.lastIndexOf(".")); + return isValidClassImport(classImport, classLoader); + } + + private boolean isValidStatic(ClassLoader classLoader, String importToCheck) { + String packageImport = importToCheck.substring(0, importToCheck.lastIndexOf(".")); + boolean validClassImport = isValidClassImport(packageImport, classLoader); + if (validClassImport) { + String methodOrName = importToCheck.substring(importToCheck.lastIndexOf("."), importToCheck.length()).replaceFirst(".", ""); + if (methodOrName.isEmpty()) { + return false; + } + try { + Class aClass = classLoader.loadClass(packageImport); + List methods = getMethods(methodOrName, aClass); + if (!methods.isEmpty()) { + return true; + } + List fields = getFields(methodOrName, aClass); + return !fields.isEmpty(); + } catch (ClassNotFoundException e) { + return false; + } + } + return false; + } + + private List getFields(String methodOrName, Class aClass) { + Field[] publicFields = aClass.getFields(); + return Arrays.stream(publicFields).filter(x -> x.getName().equals(methodOrName)).collect(Collectors.toList()); + } + + private List getMethods(String methodOrName, Class aClass) { + Method[] publicMethods = aClass.getMethods(); + return Arrays.stream(publicMethods).filter(x -> x.getName().equals(methodOrName)).collect(Collectors.toList()); + } + + private boolean isValidClassImport(String importToCheck, ClassLoader classLoader) { + try { + classLoader.loadClass(importToCheck); + return true; + } catch (ClassNotFoundException e) { + return false; + } + } + + private boolean isValidImportWithWildcard(String importToCheck, ClassLoader classLoader) { + try { + String packageWithoutWildcard = importToCheck.substring(0, importToCheck.lastIndexOf(".")); + return ClassPath.from(classLoader).packageExists(packageWithoutWildcard); + } catch (IOException e) { + throw new RuntimeException(e); + } + } +} diff --git a/base-api/src/main/java/com/twosigma/beakerx/kernel/KernelFactory.java b/base-api/src/main/java/com/twosigma/beakerx/kernel/KernelFactory.java new file mode 100644 index 0000000..7618387 --- /dev/null +++ b/base-api/src/main/java/com/twosigma/beakerx/kernel/KernelFactory.java @@ -0,0 +1,21 @@ +/* + * 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.kernel; + +public interface KernelFactory { + + KernelFunctionality createKernel(); +} diff --git a/base-api/src/main/java/com/twosigma/beakerx/kernel/KernelFunctionality.java b/base-api/src/main/java/com/twosigma/beakerx/kernel/KernelFunctionality.java new file mode 100644 index 0000000..384135f --- /dev/null +++ b/base-api/src/main/java/com/twosigma/beakerx/kernel/KernelFunctionality.java @@ -0,0 +1,123 @@ +/* + * Copyright 2017 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.kernel; + +import com.twosigma.beakerx.TryResult; +import com.twosigma.beakerx.autocomplete.AutocompleteResult; +import com.twosigma.beakerx.evaluator.Hook; +import com.twosigma.beakerx.handler.Handler; +import com.twosigma.beakerx.inspect.InspectResult; +import com.twosigma.beakerx.jvm.object.EvaluationObject; +import com.twosigma.beakerx.kernel.comm.Comm; +import com.twosigma.beakerx.kernel.magic.command.MagicCommandConfiguration; +import com.twosigma.beakerx.kernel.magic.command.MagicCommandType; +import com.twosigma.beakerx.kernel.msg.JupyterMessages; +import com.twosigma.beakerx.kernel.restserver.BeakerXServer; +import com.twosigma.beakerx.kernel.threads.ResultSender; +import com.twosigma.beakerx.message.Message; + +import java.nio.file.Path; +import java.util.List; +import java.util.Set; + +public interface KernelFunctionality { + + void publish(List message); + + void addComm(String commId, Comm comm); + + void removeComm(String commId); + + void send(Message message); + + String sendStdIn(Message message); + + String getSessionId(); + + ResultSender getExecutionResultSender(); + + Comm getComm(String string); + + boolean isCommPresent(String string); + + Set getCommHashSet(); + + void updateEvaluatorParameters(EvaluatorParameters kernelParameters); + + void cancelExecution(GroupName groupName); + + void killAllThreads(); + + Handler getHandler(JupyterMessages type); + + void run(); + + TryResult executeCode(String code, EvaluationObject seo); + + TryResult executeCode(String code, EvaluationObject seo, ExecutionOptions executionOptions); + + AutocompleteResult autocomplete(String code, int cursorPos); + + InspectResult inspect(String code, int cursorPos); + + void sendBusyMessage(Message message); + + void sendIdleMessage(Message message); + + List addJarsToClasspath(List paths); + + BeakerXClasspath getClasspath(); + + Imports getImports(); + + AddImportStatus addImport(ImportPath anImport); + + void removeImport(ImportPath anImport); + + List getMagicCommandTypes(); + + Path getTempFolder(); + + Path getCacheFolder(); + + Class loadClass(String clazzName) throws ClassNotFoundException; + + boolean checkIfClassExistsInClassloader(String clazzName); + + void registerMagicCommandType(MagicCommandType magicCommandType); + + String getOutDir(); + + void registerCancelHook(Hook hook); + + PythonEntryPoint getPythonEntryPoint(String kernelName) throws NoSuchKernelException; + + MagicKernelManager getManagerByCommId(String commId); + + void addCommIdManagerMapping(String commId, String kernel); + + void putEvaluationInToBackground(); + + BeakerXServer getBeakerXServer(); + + MagicCommandConfiguration magicCommandConfiguration(); + + BeakerXJson getBeakerXJson(); + + void startEvaluation(); + + void endEvaluation(); +} diff --git a/base-api/src/main/java/com/twosigma/beakerx/kernel/KernelManager.java b/base-api/src/main/java/com/twosigma/beakerx/kernel/KernelManager.java new file mode 100644 index 0000000..bc06214 --- /dev/null +++ b/base-api/src/main/java/com/twosigma/beakerx/kernel/KernelManager.java @@ -0,0 +1,31 @@ +/* + * Copyright 2017 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.kernel; + +public class KernelManager { + + private static KernelFunctionality kernelInst; + + public static void register(KernelFunctionality kernelFunctionality) { + kernelInst = kernelFunctionality; + } + + public static KernelFunctionality get() { + return kernelInst; + } + +} diff --git a/base-api/src/main/java/com/twosigma/beakerx/kernel/KernelRunner.java b/base-api/src/main/java/com/twosigma/beakerx/kernel/KernelRunner.java new file mode 100644 index 0000000..8469476 --- /dev/null +++ b/base-api/src/main/java/com/twosigma/beakerx/kernel/KernelRunner.java @@ -0,0 +1,21 @@ +/* + * 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.kernel; + +public interface KernelRunner { + + void run(KernelFactory kernelFactory) ; +} diff --git a/base-api/src/main/java/com/twosigma/beakerx/kernel/KernelSockets.java b/base-api/src/main/java/com/twosigma/beakerx/kernel/KernelSockets.java new file mode 100644 index 0000000..ccd9715 --- /dev/null +++ b/base-api/src/main/java/com/twosigma/beakerx/kernel/KernelSockets.java @@ -0,0 +1,29 @@ +/* + * Copyright 2017 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.kernel; + +import com.twosigma.beakerx.message.Message; + +import java.util.List; + +public abstract class KernelSockets extends Thread { + + public abstract void publish(List message); + + public abstract void send(Message message); + + public abstract String sendStdIn(Message message); +} diff --git a/base-api/src/main/java/com/twosigma/beakerx/kernel/KernelSocketsFactory.java b/base-api/src/main/java/com/twosigma/beakerx/kernel/KernelSocketsFactory.java new file mode 100644 index 0000000..d8de702 --- /dev/null +++ b/base-api/src/main/java/com/twosigma/beakerx/kernel/KernelSocketsFactory.java @@ -0,0 +1,22 @@ +/* + * Copyright 2017 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.kernel; + +public interface KernelSocketsFactory { + + KernelSockets create(final KernelFunctionality kernel, final SocketCloseAction closeAction); + +} diff --git a/base-api/src/main/java/com/twosigma/beakerx/kernel/MagicKernelManager.java b/base-api/src/main/java/com/twosigma/beakerx/kernel/MagicKernelManager.java new file mode 100644 index 0000000..e972e48 --- /dev/null +++ b/base-api/src/main/java/com/twosigma/beakerx/kernel/MagicKernelManager.java @@ -0,0 +1,196 @@ +/* + * Copyright 2017 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.kernel; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.twosigma.beakerx.message.Header; +import com.twosigma.beakerx.message.Message; +import org.apache.commons.codec.binary.Base64; +import py4j.ClientServer; +import py4j.GatewayServer; + +import javax.net.ServerSocketFactory; +import javax.net.SocketFactory; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.ServerSocket; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +public class MagicKernelManager { + + ClientServer clientServer = null; + private PythonEntryPoint pep = null; + private Process pythonProcess = null; + + private static String DEFAULT_PORT = "25333"; + private static String DEFAULT_PYTHON_PORT = "25334"; + private static int NO_SUCH_KERNEL_CODE = 2; + private static String PY4J_INIT_MESSAGE = "Py4j server is running"; + + private Integer port = null; + private Integer pythonPort = null; + + private final String kernelName; + private String context; + + public MagicKernelManager(String kernelName, String context) { + this.kernelName = kernelName; + this.context = context; + } + + private void initPythonProcess() throws NoSuchKernelException { + //cleanup communication resources if already in use + exit(); + + port = findFreePort(); + pythonPort = findFreePort(); + + try { + ProcessBuilder pb = new ProcessBuilder(getPy4jCommand()); + pb.redirectError(ProcessBuilder.Redirect.INHERIT); + pythonProcess = pb.start(); + BufferedReader br = new BufferedReader(new InputStreamReader(pythonProcess.getInputStream())); + while (!PY4J_INIT_MESSAGE.equals(br.readLine()) && pythonProcess.isAlive()) { + //wait for python process to initialize properly + } + if (!pythonProcess.isAlive() && pythonProcess.exitValue() == NO_SUCH_KERNEL_CODE) { + throw new NoSuchKernelException(kernelName); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + + protected String[] getPy4jCommand() { + return new String[]{ + "beakerx", + "py4j_server", + "--port", port == null ? DEFAULT_PORT : String.valueOf(port), + "--pyport", pythonPort == null ? DEFAULT_PYTHON_PORT : String.valueOf(pythonPort), + "--kernel", kernelName, + "--context", Base64.encodeBase64String(this.context.getBytes(StandardCharsets.UTF_8)) + }; + } + + public void exit() { + if (pep != null) { + pep.shutdownKernel(); + pep = null; + } + if (clientServer != null) { + clientServer.shutdown(); + clientServer = null; + } + if (pythonProcess != null) { + pythonProcess.destroy(); + pythonProcess = null; + } + } + + public PythonEntryPoint getPythonEntryPoint() throws NoSuchKernelException { + if (pythonProcess == null || !pythonProcess.isAlive() || clientServer == null) { + initPythonProcess(); + } + if (pep == null) { + this.pep = initPythonEntryPoint(); + } + return pep; + } + + private PythonEntryPoint initPythonEntryPoint() { + if (this.clientServer == null) { + initClientServer(); + } + return (PythonEntryPoint) clientServer.getPythonServerEntryPoint(new Class[]{PythonEntryPoint.class}); + } + + private void initClientServer() { + this.clientServer = new ClientServer(port, GatewayServer.defaultAddress(), pythonPort, + GatewayServer.defaultAddress(), GatewayServer.DEFAULT_CONNECT_TIMEOUT, + GatewayServer.DEFAULT_READ_TIMEOUT, ServerSocketFactory.getDefault(), SocketFactory.getDefault(), null); + } + + private List getIopubMessages() throws IOException { + List messages = new ArrayList<>(); + while (true) { + String iopubMsg = pep.getIopubMsg(); + if (iopubMsg.equals("null")) break; + messages.add(parseMessage(iopubMsg)); + } + return messages; + } + + private Message parseMessage(String stringJson) throws IOException { + ObjectMapper mapper = new ObjectMapper(); + JsonNode json = mapper.readTree(stringJson); + Message msg = new Message(mapper.convertValue(json.get("header"), Header.class)); + msg.setContent(mapper.convertValue(json.get("content"), Map.class)); + msg.setMetadata(mapper.convertValue(json.get("metadata"), Map.class)); + msg.setBuffers(mapper.convertValue(json.get("buffers"), List.class)); + List identities = mapper.convertValue(json.get("comm_id"), List.class); + msg.setIdentities(identities == null ? new ArrayList<>() : identities); + return msg; + } + + public List handleMsg(Message message) { + List messages = new ArrayList<>(); + try { + getPythonEntryPoint(); + } catch (NoSuchKernelException e) { + return messages; + } + pep.sendMessage(new ObjectMapper().valueToTree(message).toString()); + + try { + messages = getIopubMessages(); + } catch (IOException e) { + e.printStackTrace(); + } + + for (Message msg : messages) { + msg.setParentHeader(message.getHeader()); + } + return messages; + } + + public static Integer findFreePort() { + ServerSocket socket = null; + try { + socket = new ServerSocket(0); + socket.setReuseAddress(true); + int port = socket.getLocalPort(); + try { + socket.close(); + } catch (IOException e) { + } + return port; + } catch (IOException e) { + } finally { + if (socket != null) { + try { + socket.close(); + } catch (IOException e) { + } + } + } + return null; + } +} diff --git a/base-api/src/main/java/com/twosigma/beakerx/kernel/MessageCreatorService.java b/base-api/src/main/java/com/twosigma/beakerx/kernel/MessageCreatorService.java new file mode 100644 index 0000000..155828f --- /dev/null +++ b/base-api/src/main/java/com/twosigma/beakerx/kernel/MessageCreatorService.java @@ -0,0 +1,37 @@ +/* + * 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.kernel; + +import com.twosigma.beakerx.jvm.object.EvaluationObject; +import com.twosigma.beakerx.kernel.msg.MessageHolder; +import com.twosigma.beakerx.message.Message; + +import java.util.List; + +public interface MessageCreatorService { + + Message buildReplyWithErrorStatus(Message message, int executionCount); + + List createMessage(EvaluationObject seo); + + Message createBusyMessage(Message parentMessage); + + Message createIdleMessage(Message parentMessage); + + Message buildReplyWithOkStatus(Message message, int executionCount); + + Message buildOutputMessage(Message message, String text, boolean hasError); +} diff --git a/base-api/src/main/java/com/twosigma/beakerx/kernel/NoSuchKernelException.java b/base-api/src/main/java/com/twosigma/beakerx/kernel/NoSuchKernelException.java new file mode 100644 index 0000000..04ba471 --- /dev/null +++ b/base-api/src/main/java/com/twosigma/beakerx/kernel/NoSuchKernelException.java @@ -0,0 +1,26 @@ +/* + * Copyright 2017 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.kernel; + +public class NoSuchKernelException extends Exception { + + private static final long serialVersionUID = 1L; + + public NoSuchKernelException(String message) { + super(message); + } + +} diff --git a/base-api/src/main/java/com/twosigma/beakerx/kernel/PathToJar.java b/base-api/src/main/java/com/twosigma/beakerx/kernel/PathToJar.java new file mode 100644 index 0000000..b76e3a5 --- /dev/null +++ b/base-api/src/main/java/com/twosigma/beakerx/kernel/PathToJar.java @@ -0,0 +1,80 @@ +/* + * Copyright 2017 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.kernel; + +import org.apache.commons.lang3.StringUtils; + +import java.io.File; +import java.net.URL; +import java.nio.file.Paths; + +import static com.twosigma.beakerx.util.Preconditions.checkNotNull; +import static org.apache.commons.lang3.builder.EqualsBuilder.reflectionEquals; +import static org.apache.commons.lang3.builder.HashCodeBuilder.reflectionHashCode; +import static org.apache.commons.lang3.builder.ToStringBuilder.reflectionToString; + +public class PathToJar { + private URL url; + private String canonicalPath; + + public PathToJar(final String path) { + checkNotNull(path); + File file = getFile(path); + try { + canonicalPath = file.getCanonicalPath(); + this.url = Paths.get(canonicalPath).toUri().toURL(); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public String getPath() { + return canonicalPath; + } + + public URL getUrl() { + return url; + } + + private File getFile(String path) { + File file = Paths.get(path).toFile(); + if (!file.exists()) { + throw new RuntimeException("Path does not exist: " + path); + } + return file; + } + + private void checkNotWhitespaces(String path) { + if (StringUtils.containsWhitespace(path)) { + throw new RuntimeException("Can not create path with whitespace."); + } + } + + @Override + public boolean equals(Object o) { + return reflectionEquals(this, o); + } + + @Override + public int hashCode() { + return reflectionHashCode(this); + } + + @Override + public String toString() { + return reflectionToString(this); + } +} diff --git a/base-api/src/main/java/com/twosigma/beakerx/kernel/PlainCode.java b/base-api/src/main/java/com/twosigma/beakerx/kernel/PlainCode.java new file mode 100644 index 0000000..75e4594 --- /dev/null +++ b/base-api/src/main/java/com/twosigma/beakerx/kernel/PlainCode.java @@ -0,0 +1,60 @@ +/* + * 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.kernel; + +import com.twosigma.beakerx.TryResult; +import com.twosigma.beakerx.evaluator.EvaluationObjectFactory; +import com.twosigma.beakerx.jvm.object.EvaluationObject; +import com.twosigma.beakerx.kernel.magic.command.outcome.MagicCommandOutcomeItem; +import com.twosigma.beakerx.message.Message; + +import java.util.Optional; + +public class PlainCode extends CodeFrame { + + private String plainCode; + private EvaluationObjectFactory evaluationObjectFactory; + + public PlainCode(String plainCode, EvaluationObjectFactory evaluationObjectFactory) { + this.plainCode = plainCode; + this.evaluationObjectFactory = evaluationObjectFactory; + } + + public String getPlainCode() { + return plainCode; + } + + @Override + public void executeFrame(Code code, KernelFunctionality kernel, Message message, int executionCount) { + EvaluationObject seo = evaluationObjectFactory.createSeo(this.plainCode, kernel, message, executionCount); + seo.noResult(); + TryResult either = kernel.executeCode(this.plainCode, seo); + handleResult(seo, either); + } + + @Override + public void executeLastFrame(Code code, KernelFunctionality kernel, Message message, int executionCount) { + EvaluationObject seo = evaluationObjectFactory.createSeo(this.plainCode, kernel, message, executionCount); + TryResult either = kernel.executeCode(this.plainCode, seo); + handleResult(seo, either); + } + + @Override + public Optional getError() { + return Optional.empty(); + } + +} diff --git a/base-api/src/main/java/com/twosigma/beakerx/kernel/PythonEntryPoint.java b/base-api/src/main/java/com/twosigma/beakerx/kernel/PythonEntryPoint.java new file mode 100644 index 0000000..b45f54b --- /dev/null +++ b/base-api/src/main/java/com/twosigma/beakerx/kernel/PythonEntryPoint.java @@ -0,0 +1,24 @@ +/* + * Copyright 2017 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.kernel; + +public interface PythonEntryPoint { + String evaluate(String code); + String getIopubMsg(); + String getShellMsg(); + String shutdownKernel(); + String sendMessage(String message); +} diff --git a/base-api/src/main/java/com/twosigma/beakerx/kernel/Runtimetools.java b/base-api/src/main/java/com/twosigma/beakerx/kernel/Runtimetools.java new file mode 100644 index 0000000..677329b --- /dev/null +++ b/base-api/src/main/java/com/twosigma/beakerx/kernel/Runtimetools.java @@ -0,0 +1,23 @@ +/* + * 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.kernel; + +import com.twosigma.beakerx.kernel.KernelFunctionality; + +public interface Runtimetools { + + void configRuntimeJars(KernelFunctionality kernel); +} diff --git a/base-api/src/main/java/com/twosigma/beakerx/kernel/SocketCloseAction.java b/base-api/src/main/java/com/twosigma/beakerx/kernel/SocketCloseAction.java new file mode 100644 index 0000000..9351a58 --- /dev/null +++ b/base-api/src/main/java/com/twosigma/beakerx/kernel/SocketCloseAction.java @@ -0,0 +1,20 @@ +/* + * Copyright 2017 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.kernel; + +public interface SocketCloseAction { + void close(); +} diff --git a/base-api/src/main/java/com/twosigma/beakerx/kernel/SocketEnum.java b/base-api/src/main/java/com/twosigma/beakerx/kernel/SocketEnum.java new file mode 100644 index 0000000..d0d2f2f --- /dev/null +++ b/base-api/src/main/java/com/twosigma/beakerx/kernel/SocketEnum.java @@ -0,0 +1,23 @@ +/* + * Copyright 2017 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.kernel; + +public enum SocketEnum { + + IOPUB_SOCKET,//publish + SHELL_SOCKET//send + +} \ No newline at end of file diff --git a/base-api/src/main/java/com/twosigma/beakerx/kernel/Utils.java b/base-api/src/main/java/com/twosigma/beakerx/kernel/Utils.java new file mode 100644 index 0000000..c1dffd7 --- /dev/null +++ b/base-api/src/main/java/com/twosigma/beakerx/kernel/Utils.java @@ -0,0 +1,88 @@ +/* + * Copyright 2017 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.kernel; + +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.util.Collection; +import java.util.TimeZone; +import java.util.UUID; + +public class Utils { + + /** + * The timezone to use when generating time stamps. + */ + private static final TimeZone UTC = TimeZone.getTimeZone("UTC"); + private static final String DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"; + private static final DateTimeFormatter df = DateTimeFormatter.ofPattern(DATE_FORMAT); + 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() { + ZonedDateTime now = ZonedDateTime.now(ZoneId.of(UTC.getID())); + return df.format(now); + } + + 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) { + for (String s : input) { + ret.append(s + "\n"); + } + } + return ret.toString(); + } + + public static String getAsString(Collection input) { + if (input == null || input.isEmpty()) { + return EMPTY_STRING; + } + 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/base-api/src/main/java/com/twosigma/beakerx/kernel/comm/Buffer.java b/base-api/src/main/java/com/twosigma/beakerx/kernel/comm/Buffer.java new file mode 100644 index 0000000..75240be --- /dev/null +++ b/base-api/src/main/java/com/twosigma/beakerx/kernel/comm/Buffer.java @@ -0,0 +1,45 @@ +/* + * 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.kernel.comm; + +import java.util.ArrayList; +import java.util.List; + +import static java.util.Collections.EMPTY_LIST; + +public class Buffer { + public final static Buffer EMPTY = new Buffer(EMPTY_LIST, new ArrayList<>()); + + private List buffers; + private ArrayList> bufferPaths; + + public Buffer(List buffers, ArrayList> bufferPaths) { + this.buffers = buffers; + this.bufferPaths = bufferPaths; + } + + public List getBuffers() { + return buffers; + } + + public ArrayList> getBufferPaths() { + return bufferPaths; + } + + public boolean isEmpty() { + return buffers.isEmpty(); + } +} diff --git a/base-api/src/main/java/com/twosigma/beakerx/kernel/comm/BxComm.java b/base-api/src/main/java/com/twosigma/beakerx/kernel/comm/BxComm.java new file mode 100644 index 0000000..73a1049 --- /dev/null +++ b/base-api/src/main/java/com/twosigma/beakerx/kernel/comm/BxComm.java @@ -0,0 +1,341 @@ +/* + * 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.kernel.comm; + +import com.twosigma.beakerx.evaluator.InternalVariable; +import com.twosigma.beakerx.handler.Handler; +import com.twosigma.beakerx.kernel.KernelFunctionality; +import com.twosigma.beakerx.kernel.KernelManager; +import com.twosigma.beakerx.kernel.Utils; +import com.twosigma.beakerx.kernel.msg.JupyterMessages; +import com.twosigma.beakerx.message.Header; +import com.twosigma.beakerx.message.Message; +import com.twosigma.beakerx.util.Preconditions; +import com.twosigma.beakerx.widget.ChangeItem; + +import java.io.Serializable; +import java.util.ArrayList; +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 com.twosigma.beakerx.util.Preconditions.checkNotNull; +import static java.util.Collections.singletonList; + +public class BxComm implements Comm { + + private String commId; + private String targetName; + private Data data; + private HashMap metadata; + private String targetModule; + protected KernelFunctionality kernel; + private List> msgCallbackList = new ArrayList<>(); + private List> closeCallbackList = new ArrayList<>(); + + + public BxComm(String commId, String targetName, Message parentMessage) { + this(commId, targetName, KernelManager.get()); + getParentMessageStrategy = () -> parentMessage; + } + + public BxComm(String commId, String targetName, KernelFunctionality kernel) { + super(); + this.kernel = kernel; + this.commId = commId; + this.targetName = targetName; + this.data = new Data(new HashMap<>()); + this.metadata = new HashMap<>(); + } + + public BxComm(String commId, String targetName) { + this(commId, targetName, KernelManager.get()); + } + + public BxComm(String commId, TargetNamesEnum targetName) { + this(commId, targetName.getTargetName(), KernelManager.get()); + } + + public BxComm(TargetNamesEnum targetName) { + this(Utils.commUUID(), targetName.getTargetName(), KernelManager.get()); + } + + public BxComm(String targetName) { + this(Utils.commUUID(), targetName, KernelManager.get()); + } + + public String getCommId() { + return commId; + } + + public String getTargetName() { + return targetName; + } + + public Data getData() { + return new Data(new HashMap<>(data.getData())); + } + + @Override + public Comm createNewComm() { + return createComm(); + } + + public static Comm createComm() { + return new BxComm(TargetNamesEnum.JUPYTER_WIDGET); + } + + public void setData(HashMap data) { + this.data = new Data(data); + } + + public void setMetaData(HashMap metadata) { + this.metadata = metadata; + } + + public String getTargetModule() { + return targetModule; + } + + public void setTargetModule(String targetModule) { + this.targetModule = targetModule; + } + + public void addMsgCallbackList(Handler... handlers) { + this.msgCallbackList.addAll(Arrays.asList(handlers)); + } + + public void clearMsgCallbackList() { + this.msgCallbackList = new ArrayList<>(); + } + + public List> getCloseCallbackList() { + return closeCallbackList; + } + + public void addCloseCallbackList(Handler... handlers) { + this.closeCallbackList.addAll(Arrays.asList(handlers)); + } + + public void clearCloseCallbackList() { + this.closeCallbackList = new ArrayList<>(); + } + + public void open() { + doOpen(getParentMessage(), Buffer.EMPTY); + } + + public void open(Buffer buffer) { + doOpen(getParentMessage(), buffer); + } + + public void open(Message parentMessage) { + getParentMessageStrategy = () -> parentMessage; + doOpen(parentMessage, Buffer.EMPTY); + } + + private void doOpen(Message parentMessage, Buffer buffer) { + Preconditions.checkNotNull(parentMessage, "parent message can not be null"); + Message message = new Message(new Header(COMM_OPEN, parentMessage.getHeader().getSession())); + message.setParentHeader(parentMessage.getHeader()); + HashMap map = new HashMap<>(); + map.put(COMM_ID, getCommId()); + map.put(TARGET_NAME, getTargetName()); + + HashMap state = new HashMap<>(); + 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()); + } + map.put(DATA, state); + map.put(METADATA, metadata); + + map.put(TARGET_MODULE, getTargetModule()); + message.setContent(map); + message.setMetadata(buildMetadata()); + kernel.publish(singletonList(message)); + kernel.addComm(getCommId(), this); + } + + public void close() { + Message parentMessage = getParentMessage(); + + if (this.getCloseCallbackList() != null && !this.getCloseCallbackList().isEmpty()) { + for (Handler handler : getCloseCallbackList()) { + handler.handle(parentMessage); + } + } + Message message = new Message(new Header(COMM_CLOSE, parentMessage.getHeader().getSession())); + if (parentMessage != null) { + message.setParentHeader(parentMessage.getHeader()); + } + HashMap map = new HashMap<>(); + map.put(COMM_ID, getCommId()); + map.put(DATA, new HashMap<>()); + map.put(METADATA, new HashMap<>()); + message.setContent(map); + message.setMetadata(buildMetadata()); + + kernel.removeComm(getCommId()); + kernel.publish(singletonList(message)); + } + + public void send(Buffer buffer, Data data) { + send(COMM_MSG, buffer, data); + } + + public void send(JupyterMessages type, Data data) { + send(type, Buffer.EMPTY, data); + } + + public void send(JupyterMessages type, Buffer buffer, Data data) { + Message message = createMessage(type, buffer, data); + kernel.publish(singletonList(message)); + } + + public Message createMessage(JupyterMessages type, Buffer buffer, Data data, Message parent) { + 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, parent); + } + + public Message createMessage(JupyterMessages type, Buffer buffer, 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, Buffer buffer, Map content, Message parent) { + return messageMessage(type, buffer, content, parent); + } + + private Message create(JupyterMessages type, Buffer buffer, Map content) { + return messageMessage(type, buffer, content, getParentMessage()); + } + + public static Message messageMessage(JupyterMessages type, Buffer buffer, Map content, Message parentMessage) { + Message message = new Message(new Header(type, parentMessage.getHeader().getSession())); + checkNotNull(parentMessage); + message.setParentHeader(parentMessage.getHeader()); + message.setContent(content); + message.setMetadata(buildMetadata()); + if (!buffer.isEmpty()) { + message.setBuffers(buffer.getBuffers()); + } + return message; + } + + public void publish(List list) { + kernel.publish(list); + } + + public void sendUpdate(Buffer buffer) { + HashMap content = new HashMap<>(); + content.put(METHOD, UPDATE); + HashMap state = new HashMap<>(); + content.put(STATE, state); + content.put(BUFFER_PATHS, buffer.getBufferPaths()); + this.send(buffer, new Data(content)); + } + + public Message createOutputContent(final Map content) { + return this.create(JupyterMessages.STREAM, Buffer.EMPTY, content); + } + + public void sendData(String field, HashMap payload) { + Message message = createMessageWithData(field, payload); + kernel.publish(singletonList(message)); + } + + public void sendUpdate(List changes) { + Message message = createUpdateMessage(changes, new HashMap<>()); + kernel.publish(singletonList(message)); + } + + public void sendUpdate(List changes, Message parent) { + Message message = createUpdateMessage(changes, parent); + kernel.publish(singletonList(message)); + } + + public Message createMessageWithData(String field, HashMap payload) { + HashMap content = new HashMap<>(); + content.put(METHOD, UPDATE); + content.put(field, payload); + content.put(BUFFER_PATHS, new HashMap<>()); + return this.createMessage(COMM_MSG, Buffer.EMPTY, new Data(content)); + } + + public Message createUpdateMessage(List changes, Message parent) { + HashMap content = new HashMap<>(); + content.put(METHOD, UPDATE); + HashMap state = new HashMap<>(); + changes.forEach(x -> state.put(x.getPropertyName(), x.getValue())); + content.put(STATE, state); + content.put(BUFFER_PATHS, new HashMap<>()); + return this.createMessage(COMM_MSG, Buffer.EMPTY, new Data(content), parent); + } + + public Message createUpdateMessage(List changes, HashMap state) { + HashMap content = new HashMap<>(); + content.put(METHOD, UPDATE); + changes.forEach(x -> state.put(x.getPropertyName(), x.getValue())); + content.put(STATE, state); + content.put(BUFFER_PATHS, new HashMap<>()); + return this.createMessage(COMM_MSG, Buffer.EMPTY, new Data(content)); + } + + public void handleMsg(Message parentMessage) { + for (Handler handler : this.msgCallbackList) { + handler.handle(parentMessage); + } + } + + private static HashMap buildMetadata() { + HashMap metadata = new HashMap<>(); + metadata.put(VERSION, "2"); + return metadata; + } + + @Override + public String toString() { + return commId + "/" + targetName + "/" + (targetModule != null && !targetModule.isEmpty() ? targetModule : ""); + } + + public Message getParentMessage() { + return getParentMessageStrategy.getParentMessage(); + } + + private GetParentMessageStrategy getParentMessageStrategy = InternalVariable::getParentHeader; + + interface GetParentMessageStrategy { + Message getParentMessage(); + } + +} diff --git a/base-api/src/main/java/com/twosigma/beakerx/kernel/comm/Comm.java b/base-api/src/main/java/com/twosigma/beakerx/kernel/comm/Comm.java new file mode 100644 index 0000000..664c95b --- /dev/null +++ b/base-api/src/main/java/com/twosigma/beakerx/kernel/comm/Comm.java @@ -0,0 +1,98 @@ +/* + * Copyright 2017 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.kernel.comm; + +import com.twosigma.beakerx.handler.Handler; +import com.twosigma.beakerx.kernel.msg.JupyterMessages; +import com.twosigma.beakerx.message.Message; +import com.twosigma.beakerx.widget.ChangeItem; + +import java.io.Serializable; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public interface Comm { + + String METHOD = "method"; + String UPDATE = "update"; + String STATE = "state"; + String VERSION = "version"; + + String COMM_ID = "comm_id"; + String TARGET_NAME = "target_name"; + String DATA = "data"; + String METADATA = "metadata"; + String TARGET_MODULE = "target_module"; + String COMMS = "comms"; + String BUFFER_PATHS = "buffer_paths"; + + + void addMsgCallbackList(Handler... handlers); + + void setData(HashMap data); + + void open(); + + void open(Buffer buffer); + + void open(Message parentMessage); + + void close(); + + String getCommId(); + + void send(Buffer buffer, Data data); + + void send(JupyterMessages type, Data data); + + void send(JupyterMessages type, Buffer buffer, Data data); + + void sendUpdate(Buffer buffer); + + void sendUpdate(List changes); + + void sendUpdate(List changes, Message parent); + + Message createUpdateMessage(List changes, Message parent); + + Message createUpdateMessage(List changes, HashMap state); + + Message createOutputContent(final Map content); + + Message getParentMessage(); + + void publish(List list); + + Message createMessage(JupyterMessages type, Buffer buffer, Data data, Message parent); + + Message createMessage(JupyterMessages type, Buffer buffer, Data data); + + String getTargetName(); + + void handleMsg(Message parentMessage); + + String getTargetModule(); + + void setTargetModule(String targetModule); + + Data getData(); + + Comm createNewComm(); + + void sendData(String event, HashMap payload); + +} diff --git a/base-api/src/main/java/com/twosigma/beakerx/kernel/comm/Data.java b/base-api/src/main/java/com/twosigma/beakerx/kernel/comm/Data.java new file mode 100644 index 0000000..fb8e5bb --- /dev/null +++ b/base-api/src/main/java/com/twosigma/beakerx/kernel/comm/Data.java @@ -0,0 +1,31 @@ +/* + * 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.kernel.comm; + +import java.util.HashMap; + +public class Data { + + private HashMap data; + + public Data(HashMap data) { + this.data = data; + } + + public HashMap getData() { + return data; + } +} diff --git a/base-api/src/main/java/com/twosigma/beakerx/kernel/comm/TargetNamesEnum.java b/base-api/src/main/java/com/twosigma/beakerx/kernel/comm/TargetNamesEnum.java new file mode 100644 index 0000000..b992f3c --- /dev/null +++ b/base-api/src/main/java/com/twosigma/beakerx/kernel/comm/TargetNamesEnum.java @@ -0,0 +1,51 @@ +/* + * Copyright 2017 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.kernel.comm; + +public enum TargetNamesEnum { + + BEAKER_TAG_RUN("beakerx.tag.run"), + BEAKER_GETCODECELLS("beakerx.getcodecells"), + BEAKER_GET_URL_ARG("beakerx.geturlarg"), + BEAKER_AUTOTRANSLATION("beakerx.autotranslation"), + JUPYTER_WIDGET("jupyter.widget"), + JUPYTER_WIDGET_VERSION("jupyter.widget.version"), + KERNEL_CONTROL_CHANNEL("kernel.control.channel"); + + private String targetName; + + TargetNamesEnum(String targetName){ + this.targetName = targetName; + } + + public String getTargetName() { + return targetName; + } + + public static TargetNamesEnum getType(final String input){ + TargetNamesEnum ret = null; + if(input != null){ + for (TargetNamesEnum item : TargetNamesEnum.values()) { + if(item.getTargetName().equalsIgnoreCase(input.trim().toLowerCase())){ + ret = item; + break; + } + } + } + return ret; + } + +} \ No newline at end of file diff --git a/base-api/src/main/java/com/twosigma/beakerx/kernel/magic/command/CodeFactory.java b/base-api/src/main/java/com/twosigma/beakerx/kernel/magic/command/CodeFactory.java new file mode 100644 index 0000000..d978816 --- /dev/null +++ b/base-api/src/main/java/com/twosigma/beakerx/kernel/magic/command/CodeFactory.java @@ -0,0 +1,117 @@ +/* + * Copyright 2017 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.kernel.magic.command; + +import com.twosigma.beakerx.evaluator.EvaluationObjectFactory; +import com.twosigma.beakerx.kernel.Code; +import com.twosigma.beakerx.kernel.CodeFrame; +import com.twosigma.beakerx.kernel.KernelFunctionality; +import com.twosigma.beakerx.kernel.MessageCreatorService; +import com.twosigma.beakerx.kernel.PlainCode; +import com.twosigma.beakerx.kernel.magic.command.outcome.MagicCommandOutcomeItem; +import com.twosigma.beakerx.kernel.magic.command.outcome.MagicCommandOutput; +import com.twosigma.beakerx.message.Message; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.Scanner; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +public class CodeFactory { + + public static final String CELL_COMMAND_MAGIC = "%%"; + public static final String LINE_COMMAND_MAGIC = "%"; + private MessageCreatorService messageCreatorService; + private EvaluationObjectFactory evaluationObjectFactory; + + public CodeFactory(MessageCreatorService messageCreatorService, EvaluationObjectFactory evaluationObjectFactory) { + this.messageCreatorService = messageCreatorService; + this.evaluationObjectFactory = evaluationObjectFactory; + } + + public Code create(String allCode, Message message, KernelFunctionality kernel) { + List frames = takeCodeFrames(allCode, kernel); + List errors = frames.stream() + .filter(x -> x.getError().isPresent()) + .map(y -> y.getError().get()) + .collect(Collectors.toList()); + return Code.createCode(allCode, frames, errors, message, messageCreatorService, evaluationObjectFactory); + } + + private List takeCodeFrames(String allCode, KernelFunctionality kernel) { + Scanner scanner = new Scanner(allCode); + List result = new ArrayList<>(); + while (scanner.hasNextLine()) { + String line = scanner.nextLine().trim(); + if (line.startsWith(CELL_COMMAND_MAGIC)) { + result.add(createFrameForCellMagic(line, scanner, kernel)); + } else if (line.startsWith(LINE_COMMAND_MAGIC)) { + result.add(createFrameForLineMagic(line, kernel)); + } else { + result.add(createFrameForPlainCode(line, scanner)); + } + } + return result; + } + + private CodeFrame createFrameForPlainCode(String line, Scanner scanner) { + List result = new ArrayList<>(); + result.add(line); + Pattern p = Pattern.compile("\\s*%.*"); + while (scanner.hasNext() && !scanner.hasNext(p)) { + String str = scanner.nextLine().trim(); + result.add(str); + } + return new PlainCode(String.join(System.lineSeparator(), result), evaluationObjectFactory); + } + + private CodeFrame createFrameForLineMagic(String line, KernelFunctionality kernel) { + Optional mcOption = findMagicCommandFunctionality(kernel.getMagicCommandTypes(), line); + return mcOption + .map(magicCommandFunctionality -> new MagicCommand(magicCommandFunctionality, line)) + .orElseGet(() -> new ErrorCodeFrame(processIllegalCommand("Inline magic " + line + " not found", messageCreatorService))); + } + + private CodeFrame createFrameForCellMagic(String line, Scanner scanner, KernelFunctionality kernel) { + Optional mcOption = findMagicCommandFunctionality(kernel.getMagicCommandTypes(), line); + return mcOption + .map(magicCommandFunctionality -> new MagicCommand(magicCommandFunctionality, line, takeRestOfTheCode(scanner))) + .orElseGet(() -> new ErrorCodeFrame(processIllegalCommand("Cell magic " + line + " not found", messageCreatorService))); + } + + private String takeRestOfTheCode(Scanner scanner) { + List result = new ArrayList<>(); + while (scanner.hasNextLine()) { + result.add(scanner.nextLine()); + } + return String.join(System.lineSeparator(), result); + } + + public Optional findMagicCommandFunctionality(final List commands, final String command) { + return commands.stream() + .filter(c -> c.getMagicCommandFunctionality().matchCommand(command)) + .map(MagicCommandType::getMagicCommandFunctionality) + .findFirst(); + } + + private MagicCommandOutcomeItem processIllegalCommand(String errorMessage, MessageCreatorService messageCreatorService) { + return new MagicCommandOutput(MagicCommandOutcomeItem.Status.ERROR, errorMessage, messageCreatorService); + } + + +} diff --git a/base-api/src/main/java/com/twosigma/beakerx/kernel/magic/command/ErrorCodeFrame.java b/base-api/src/main/java/com/twosigma/beakerx/kernel/magic/command/ErrorCodeFrame.java new file mode 100644 index 0000000..f6473f9 --- /dev/null +++ b/base-api/src/main/java/com/twosigma/beakerx/kernel/magic/command/ErrorCodeFrame.java @@ -0,0 +1,48 @@ +/* + * 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.kernel.magic.command; + +import com.twosigma.beakerx.kernel.Code; +import com.twosigma.beakerx.kernel.CodeFrame; +import com.twosigma.beakerx.kernel.KernelFunctionality; +import com.twosigma.beakerx.kernel.magic.command.outcome.MagicCommandOutcomeItem; +import com.twosigma.beakerx.message.Message; +import com.twosigma.beakerx.util.Preconditions; + +import java.util.Optional; + + +public class ErrorCodeFrame extends CodeFrame { + + private MagicCommandOutcomeItem magicCommandOutcomeItem; + + public ErrorCodeFrame(MagicCommandOutcomeItem magicCommandOutcomeItem) { + this.magicCommandOutcomeItem = Preconditions.checkNotNull(magicCommandOutcomeItem); + } + + @Override + public void executeFrame(Code code, KernelFunctionality kernel, Message message, int executionCount) { + } + + @Override + public void executeLastFrame(Code code, KernelFunctionality kernel, Message message, int executionCount) { + } + + @Override + public Optional getError() { + return Optional.of(magicCommandOutcomeItem); + } +} diff --git a/base-api/src/main/java/com/twosigma/beakerx/kernel/magic/command/MagicCommand.java b/base-api/src/main/java/com/twosigma/beakerx/kernel/magic/command/MagicCommand.java new file mode 100644 index 0000000..ae80e37 --- /dev/null +++ b/base-api/src/main/java/com/twosigma/beakerx/kernel/magic/command/MagicCommand.java @@ -0,0 +1,90 @@ +/* + * Copyright 2017 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.kernel.magic.command; + +import com.twosigma.beakerx.TryResult; +import com.twosigma.beakerx.jvm.object.EvaluationObject; +import com.twosigma.beakerx.kernel.Code; +import com.twosigma.beakerx.kernel.CodeFrame; +import com.twosigma.beakerx.kernel.KernelFunctionality; +import com.twosigma.beakerx.kernel.magic.command.outcome.MagicCommandOutcomeItem; +import com.twosigma.beakerx.message.Message; + +import java.util.Optional; + +public class MagicCommand extends CodeFrame { + + private MagicCommandFunctionality magicCommandFunctionality; + private String command; + private String commandCodeBlock; + + public MagicCommand(MagicCommandFunctionality magicCommandFunctionality, String command, String commandCodeBlock) { + this.magicCommandFunctionality = magicCommandFunctionality; + this.command = command; + this.commandCodeBlock = commandCodeBlock; + } + + public MagicCommand(MagicCommandFunctionality magicCommandFunctionality, String command) { + this.magicCommandFunctionality = magicCommandFunctionality; + this.command = command; + } + + private MagicCommandOutcomeItem execute(MagicCommandExecutionParam param) { + return this.magicCommandFunctionality.execute(param); + } + + public String getCommand() { + return command; + } + + public String getCommandCodeBlock() { + return commandCodeBlock; + } + + @Override + public void executeFrame(Code code, KernelFunctionality kernel, Message message, int executionCount) { + MagicCommandOutcomeItem execute = execute(code, executionCount, false); + execute.sendMagicCommandOutcome(kernel, message, executionCount); + TryResult result = execute.getResult(); + EvaluationObject seo = execute.getSimpleEvaluationObject(); + handleResult(seo, result); + } + + @Override + public void executeLastFrame(Code code, KernelFunctionality kernel, Message message, int executionCount) { + MagicCommandOutcomeItem execute = execute(code, executionCount, true); + execute.sendRepliesWithStatus(kernel, message, executionCount); + TryResult result = execute.getResult(); + EvaluationObject seo = execute.getSimpleEvaluationObject(); + handleResult(seo, result); + } + + @Override + public Optional getError() { + return Optional.empty(); + } + + private MagicCommandOutcomeItem execute(Code code, int executionCount, boolean showResult) { + MagicCommandExecutionParam param = new MagicCommandExecutionParam( + getCommand(), + getCommandCodeBlock(), + executionCount, + code, + showResult); + return execute(param); + } +} diff --git a/base-api/src/main/java/com/twosigma/beakerx/kernel/magic/command/MagicCommandConfiguration.java b/base-api/src/main/java/com/twosigma/beakerx/kernel/magic/command/MagicCommandConfiguration.java new file mode 100644 index 0000000..2942324 --- /dev/null +++ b/base-api/src/main/java/com/twosigma/beakerx/kernel/magic/command/MagicCommandConfiguration.java @@ -0,0 +1,33 @@ +/* + * 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.kernel.magic.command; + +import com.twosigma.beakerx.autocomplete.MagicCommandAutocompletePatterns; +import com.twosigma.beakerx.kernel.KernelFunctionality; +import com.twosigma.beakerx.kernel.magic.command.functionality.FileService; + +import java.util.List; + +public interface MagicCommandConfiguration { + + List createDefaults(KernelFunctionality kernel); + + MagicCommandAutocompletePatterns patterns(); + + MagicCommandFunctionality getClasspathAddMvnMagicCommand(KernelFunctionality kernel); + + FileService getFileService(); +} diff --git a/base-api/src/main/java/com/twosigma/beakerx/kernel/magic/command/MagicCommandExecutionParam.java b/base-api/src/main/java/com/twosigma/beakerx/kernel/magic/command/MagicCommandExecutionParam.java new file mode 100644 index 0000000..febfc77 --- /dev/null +++ b/base-api/src/main/java/com/twosigma/beakerx/kernel/magic/command/MagicCommandExecutionParam.java @@ -0,0 +1,55 @@ +/* + * Copyright 2017 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.kernel.magic.command; + +import com.twosigma.beakerx.kernel.Code; + +public class MagicCommandExecutionParam { + + private final boolean showResult; + private String command; + private String commandCodeBlock; + private int executionCount; + private Code code; + + public MagicCommandExecutionParam(String command, String commandCodeBlock, int executionCount, Code code, boolean showResult) { + this.command = command; + this.commandCodeBlock = commandCodeBlock; + this.executionCount = executionCount; + this.code = code; + this.showResult = showResult; + } + + public String getCommand() { + return command; + } + + public String getCommandCodeBlock() { + return commandCodeBlock; + } + + public int getExecutionCount() { + return executionCount; + } + + public Code getCode() { + return code; + } + + public boolean isShowResult() { + return showResult; + } +} diff --git a/base-api/src/main/java/com/twosigma/beakerx/kernel/magic/command/MagicCommandFunctionality.java b/base-api/src/main/java/com/twosigma/beakerx/kernel/magic/command/MagicCommandFunctionality.java new file mode 100644 index 0000000..792d07b --- /dev/null +++ b/base-api/src/main/java/com/twosigma/beakerx/kernel/magic/command/MagicCommandFunctionality.java @@ -0,0 +1,35 @@ +/* + * Copyright 2017 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.kernel.magic.command; + +import com.twosigma.beakerx.kernel.magic.command.functionality.MagicCommandUtils; +import com.twosigma.beakerx.kernel.magic.command.outcome.MagicCommandOutcomeItem; + +public interface MagicCommandFunctionality { + + String USAGE_ERROR_MSG = "UsageError: %s is a cell magic, but the cell body is empty."; + String WRONG_FORMAT_MSG = "Wrong format. "; + + MagicCommandOutcomeItem execute(MagicCommandExecutionParam param); + + String getMagicCommandName(); + + default boolean matchCommand(String command){ + String[] commandParts = MagicCommandUtils.splitPath(command); + return commandParts.length > 0 && + getMagicCommandName().equals(commandParts[0]); + } +} diff --git a/base-api/src/main/java/com/twosigma/beakerx/kernel/magic/command/MagicCommandType.java b/base-api/src/main/java/com/twosigma/beakerx/kernel/magic/command/MagicCommandType.java new file mode 100644 index 0000000..a305c84 --- /dev/null +++ b/base-api/src/main/java/com/twosigma/beakerx/kernel/magic/command/MagicCommandType.java @@ -0,0 +1,43 @@ +/* + * Copyright 2017 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.kernel.magic.command; + +public final class MagicCommandType { + + private final String command; + private final String parameters; + private final MagicCommandFunctionality magicCommandFunctionality; + + public MagicCommandType(String command, String parameters, MagicCommandFunctionality magicCommandFunctionality) { + this.command = command; + this.parameters = parameters; + this.magicCommandFunctionality = magicCommandFunctionality; + } + + public String getCommand() { + return command; + } + + public String getParameters() { + return parameters; + } + + public MagicCommandFunctionality getMagicCommandFunctionality() { + return magicCommandFunctionality; + } + +} diff --git a/base-api/src/main/java/com/twosigma/beakerx/kernel/magic/command/functionality/AddImportMagicCommandInfo.java b/base-api/src/main/java/com/twosigma/beakerx/kernel/magic/command/functionality/AddImportMagicCommandInfo.java new file mode 100644 index 0000000..0fb7f1c --- /dev/null +++ b/base-api/src/main/java/com/twosigma/beakerx/kernel/magic/command/functionality/AddImportMagicCommandInfo.java @@ -0,0 +1,20 @@ +/* + * 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.kernel.magic.command.functionality; + +public interface AddImportMagicCommandInfo { + String IMPORT = "%import"; +} diff --git a/base-api/src/main/java/com/twosigma/beakerx/kernel/magic/command/functionality/ClasspathAddJarMagicCommandInfo.java b/base-api/src/main/java/com/twosigma/beakerx/kernel/magic/command/functionality/ClasspathAddJarMagicCommandInfo.java new file mode 100644 index 0000000..c6a5cdf --- /dev/null +++ b/base-api/src/main/java/com/twosigma/beakerx/kernel/magic/command/functionality/ClasspathAddJarMagicCommandInfo.java @@ -0,0 +1,24 @@ +/* + * 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.kernel.magic.command.functionality; + +import static com.twosigma.beakerx.kernel.magic.command.functionality.ClasspathMagicCommandInfo.CLASSPATH; + +public interface ClasspathAddJarMagicCommandInfo { + String ADD = "add"; + String JAR = "jar"; + String CLASSPATH_ADD_JAR = CLASSPATH + " " + ADD + " " + JAR; +} diff --git a/base-api/src/main/java/com/twosigma/beakerx/kernel/magic/command/functionality/ClasspathMagicCommandInfo.java b/base-api/src/main/java/com/twosigma/beakerx/kernel/magic/command/functionality/ClasspathMagicCommandInfo.java new file mode 100644 index 0000000..73fa258 --- /dev/null +++ b/base-api/src/main/java/com/twosigma/beakerx/kernel/magic/command/functionality/ClasspathMagicCommandInfo.java @@ -0,0 +1,20 @@ +/* + * 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.kernel.magic.command.functionality; + +public interface ClasspathMagicCommandInfo { + String CLASSPATH = "%classpath"; +} diff --git a/base-api/src/main/java/com/twosigma/beakerx/kernel/magic/command/functionality/FileService.java b/base-api/src/main/java/com/twosigma/beakerx/kernel/magic/command/functionality/FileService.java new file mode 100644 index 0000000..619908c --- /dev/null +++ b/base-api/src/main/java/com/twosigma/beakerx/kernel/magic/command/functionality/FileService.java @@ -0,0 +1,22 @@ +/* + * 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.kernel.magic.command.functionality; + +import java.io.File; + +public interface FileService { + void delete(File file); +} diff --git a/base-api/src/main/java/com/twosigma/beakerx/kernel/magic/command/functionality/LoadMagicMagicCommandInfo.java b/base-api/src/main/java/com/twosigma/beakerx/kernel/magic/command/functionality/LoadMagicMagicCommandInfo.java new file mode 100644 index 0000000..158d8aa --- /dev/null +++ b/base-api/src/main/java/com/twosigma/beakerx/kernel/magic/command/functionality/LoadMagicMagicCommandInfo.java @@ -0,0 +1,20 @@ +/* + * 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.kernel.magic.command.functionality; + +public interface LoadMagicMagicCommandInfo { + String LOAD_MAGIC = "%load_magic"; +} diff --git a/base-api/src/main/java/com/twosigma/beakerx/kernel/magic/command/functionality/MagicCommandUtils.java b/base-api/src/main/java/com/twosigma/beakerx/kernel/magic/command/functionality/MagicCommandUtils.java new file mode 100644 index 0000000..69c9058 --- /dev/null +++ b/base-api/src/main/java/com/twosigma/beakerx/kernel/magic/command/functionality/MagicCommandUtils.java @@ -0,0 +1,27 @@ +/* + * Copyright 2017 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.kernel.magic.command.functionality; + +import org.apache.commons.text.StrMatcher; +import org.apache.commons.text.StrTokenizer; + +public class MagicCommandUtils { + + public static String[] splitPath(String command) { + StrTokenizer tokenizer = new StrTokenizer(command, StrMatcher.spaceMatcher(), StrMatcher.quoteMatcher()); + return tokenizer.getTokenArray(); + } +} diff --git a/base-api/src/main/java/com/twosigma/beakerx/kernel/magic/command/functionality/UnImportMagicCommandInfo.java b/base-api/src/main/java/com/twosigma/beakerx/kernel/magic/command/functionality/UnImportMagicCommandInfo.java new file mode 100644 index 0000000..e04087f --- /dev/null +++ b/base-api/src/main/java/com/twosigma/beakerx/kernel/magic/command/functionality/UnImportMagicCommandInfo.java @@ -0,0 +1,20 @@ +/* + * 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.kernel.magic.command.functionality; + +public interface UnImportMagicCommandInfo { + String UNIMPORT = "%unimport"; +} diff --git a/base-api/src/main/java/com/twosigma/beakerx/kernel/magic/command/outcome/MagicCommandOutcomeItem.java b/base-api/src/main/java/com/twosigma/beakerx/kernel/magic/command/outcome/MagicCommandOutcomeItem.java new file mode 100644 index 0000000..4e75966 --- /dev/null +++ b/base-api/src/main/java/com/twosigma/beakerx/kernel/magic/command/outcome/MagicCommandOutcomeItem.java @@ -0,0 +1,44 @@ +/* + * Copyright 2017 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.kernel.magic.command.outcome; + +import com.twosigma.beakerx.TryResult; +import com.twosigma.beakerx.kernel.KernelFunctionality; +import com.twosigma.beakerx.message.Message; +import com.twosigma.beakerx.mimetype.MIMEContainer; +import com.twosigma.beakerx.jvm.object.EvaluationObject; + +import java.util.Optional; + +public interface MagicCommandOutcomeItem { + + Optional getMIMEContainer(); + + Status getStatus(); + + TryResult getResult(); + + EvaluationObject getSimpleEvaluationObject(); + + void sendRepliesWithStatus(KernelFunctionality kernel, Message message, int executionCount); + + void sendMagicCommandOutcome(KernelFunctionality kernel, Message message, int executionCount); + + enum Status { + OK, + ERROR + } +} diff --git a/base-api/src/main/java/com/twosigma/beakerx/kernel/magic/command/outcome/MagicCommandOutput.java b/base-api/src/main/java/com/twosigma/beakerx/kernel/magic/command/outcome/MagicCommandOutput.java new file mode 100644 index 0000000..9c3d70f --- /dev/null +++ b/base-api/src/main/java/com/twosigma/beakerx/kernel/magic/command/outcome/MagicCommandOutput.java @@ -0,0 +1,98 @@ +/* + * Copyright 2017 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.kernel.magic.command.outcome; + +import com.twosigma.beakerx.TryResult; +import com.twosigma.beakerx.jvm.object.EvaluationObject; +import com.twosigma.beakerx.kernel.KernelFunctionality; +import com.twosigma.beakerx.kernel.MessageCreatorService; +import com.twosigma.beakerx.message.Message; +import com.twosigma.beakerx.mimetype.MIMEContainer; + +import java.util.Collections; +import java.util.Optional; + +import static com.twosigma.beakerx.util.Preconditions.checkNotNull; + +public class MagicCommandOutput implements MagicCommandOutcomeItem { + + private Optional mineContainer; + private MagicCommandOutput.Status status; + + private TryResult result; + private EvaluationObject seo; + private MessageCreatorService messageCreatorService; + + private MagicCommandOutput(MagicCommandOutput.Status status, Optional mineContainer, TryResult result, EvaluationObject seo, MessageCreatorService messageCreatorService) { + this.mineContainer = mineContainer; + this.status = checkNotNull(status); + this.result = result; + this.seo = seo; + this.messageCreatorService = messageCreatorService; + } + + public MagicCommandOutput(Status status, MessageCreatorService messageCreatorService) { + this(status, Optional.empty(), null, null, messageCreatorService); + } + + public MagicCommandOutput(MagicCommandOutput.Status status, String text, MessageCreatorService messageCreatorService) { + this(status, Optional.of(MIMEContainer.Text(checkNotNull(text).concat("\n"))), null, null, messageCreatorService); + } + + public MagicCommandOutput(Status status, String text, TryResult result, EvaluationObject seo, MessageCreatorService messageCreatorService) { + this(status, Optional.of(MIMEContainer.Text(checkNotNull(text).concat("\n"))), result, seo, messageCreatorService); + } + + @Override + public Optional getMIMEContainer() { + return mineContainer; + } + + public MagicCommandOutput.Status getStatus() { + return status; + } + + @Override + public TryResult getResult() { + return result; + } + + @Override + public EvaluationObject getSimpleEvaluationObject() { + return seo; + } + + @Override + public void sendRepliesWithStatus(KernelFunctionality kernel, Message message, int executionCount) { + if (getStatus().equals(MagicCommandOutcomeItem.Status.OK)) { + if (getMIMEContainer().isPresent()) { + kernel.publish(Collections.singletonList(messageCreatorService.buildOutputMessage(message, (String) getMIMEContainer().get().getData(), false))); + } + kernel.send(messageCreatorService.buildReplyWithOkStatus(message, executionCount)); + } else { + kernel.publish(Collections.singletonList(messageCreatorService.buildOutputMessage(message, (String) getMIMEContainer().get().getData(), true))); + kernel.send(messageCreatorService.buildReplyWithErrorStatus(message, executionCount)); + } + } + + @Override + public void sendMagicCommandOutcome(KernelFunctionality kernel, Message message, int executionCount) { + if (getMIMEContainer().isPresent()) { + boolean hasError = getStatus().equals(MagicCommandOutcomeItem.Status.ERROR); + kernel.publish(Collections.singletonList(messageCreatorService.buildOutputMessage(message, (String) getMIMEContainer().get().getData(), hasError))); + } + } +} diff --git a/base-api/src/main/java/com/twosigma/beakerx/kernel/msg/JupyterMessages.java b/base-api/src/main/java/com/twosigma/beakerx/kernel/msg/JupyterMessages.java new file mode 100644 index 0000000..301ccdd --- /dev/null +++ b/base-api/src/main/java/com/twosigma/beakerx/kernel/msg/JupyterMessages.java @@ -0,0 +1,73 @@ +/* + * Copyright 2017 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.kernel.msg; + +/** + * Definitions of the strings used as message type values. + * + * @author konst + * + */ +public enum JupyterMessages { + + KERNEL_INFO_REQUEST, + KERNEL_INFO_REPLY, + EXECUTE_REQUEST, + EXECUTE_INPUT, + EXECUTE_RESULT, + EXECUTE_REPLY, + COMPLETE_REQUEST, + COMPLETE_REPLY, + HISTORY_REQUEST, + HISTORY_REPLY, + INSPECT_REQUEST, + INSPECT_REPLY, + STATUS, + STREAM, + SHUTDOWN_REQUEST, + SHUTDOWN_REPLY, + COMM_OPEN, + COMM_CLOSE, + COMM_INFO_REQUEST, + COMM_INFO_REPLY, + COMM_MSG, + UNDEFINED, + DISPLAY_DATA, + CLEAR_OUTPUT, + ERROR, + IS_COMPLETE_REQUEST, + INPUT_REQUEST, + IS_COMPLETE_REPLY; + + public String getName() { + return this.name().toLowerCase(); + } + + public static JupyterMessages getType(final String input){ + JupyterMessages ret = null; + if(input != null){ + for (JupyterMessages item : JupyterMessages.values()) { + if(item.getName().equalsIgnoreCase(input.trim().toLowerCase())){ + ret = item; + break; + } + } + } + return ret; + } + +} \ No newline at end of file diff --git a/base-api/src/main/java/com/twosigma/beakerx/kernel/msg/MessageHolder.java b/base-api/src/main/java/com/twosigma/beakerx/kernel/msg/MessageHolder.java new file mode 100644 index 0000000..970f8c4 --- /dev/null +++ b/base-api/src/main/java/com/twosigma/beakerx/kernel/msg/MessageHolder.java @@ -0,0 +1,45 @@ +/* + * Copyright 2017 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.kernel.msg; + +import com.twosigma.beakerx.message.Message; +import com.twosigma.beakerx.kernel.SocketEnum; + +public class MessageHolder { + + private Message message; + private SocketEnum socketType; + + public MessageHolder(SocketEnum socketType, Message message) { + super(); + this.message = message; + this.socketType = socketType; + } + + public Message getMessage() { + return message; + } + + public SocketEnum getSocketType() { + return socketType; + } + + @Override + public String toString() { + return "sendType = " + socketType + " Message: " + message; + } + +} \ No newline at end of file diff --git a/base-api/src/main/java/com/twosigma/beakerx/kernel/restserver/BeakerXServer.java b/base-api/src/main/java/com/twosigma/beakerx/kernel/restserver/BeakerXServer.java new file mode 100644 index 0000000..461f883 --- /dev/null +++ b/base-api/src/main/java/com/twosigma/beakerx/kernel/restserver/BeakerXServer.java @@ -0,0 +1,26 @@ +/* + * 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.kernel.restserver; + +import com.twosigma.beakerx.kernel.KernelFunctionality; + +public interface BeakerXServer { + BeakerXServer get(KernelFunctionality kernel); + + String getURL(); + + void addPostMapping(String path, RESTAction restAction); +} diff --git a/base-api/src/main/java/com/twosigma/beakerx/kernel/restserver/Context.java b/base-api/src/main/java/com/twosigma/beakerx/kernel/restserver/Context.java new file mode 100644 index 0000000..174beb8 --- /dev/null +++ b/base-api/src/main/java/com/twosigma/beakerx/kernel/restserver/Context.java @@ -0,0 +1,22 @@ +/* + * 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.kernel.restserver; + +public interface Context { + + String param(String name); + +} diff --git a/base-api/src/main/java/com/twosigma/beakerx/kernel/restserver/RESTAction.java b/base-api/src/main/java/com/twosigma/beakerx/kernel/restserver/RESTAction.java new file mode 100644 index 0000000..1fbab57 --- /dev/null +++ b/base-api/src/main/java/com/twosigma/beakerx/kernel/restserver/RESTAction.java @@ -0,0 +1,21 @@ +/* + * 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.kernel.restserver; + +public interface RESTAction { + + void run(Context ctx); +} diff --git a/base-api/src/main/java/com/twosigma/beakerx/kernel/threads/ExecutionResultSender.java b/base-api/src/main/java/com/twosigma/beakerx/kernel/threads/ExecutionResultSender.java new file mode 100644 index 0000000..48c34a2 --- /dev/null +++ b/base-api/src/main/java/com/twosigma/beakerx/kernel/threads/ExecutionResultSender.java @@ -0,0 +1,58 @@ +/* + * Copyright 2017 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.kernel.threads; + +import com.twosigma.beakerx.jvm.object.EvaluationObject; +import com.twosigma.beakerx.kernel.KernelFunctionality; +import com.twosigma.beakerx.kernel.MessageCreatorService; +import com.twosigma.beakerx.kernel.SocketEnum; +import com.twosigma.beakerx.kernel.msg.MessageHolder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.List; + +import static java.util.Collections.singletonList; + +public class ExecutionResultSender implements ResultSender { + + public static Logger logger = LoggerFactory.getLogger(ExecutionResultSender.class); + private KernelFunctionality kernel; + private MessageCreatorService messageCreatorService; + + public ExecutionResultSender(KernelFunctionality kernel, MessageCreatorService messageCreatorService) { + this.kernel = kernel; + this.messageCreatorService = messageCreatorService; + } + + @Override + public void update(EvaluationObject seo) { + if (seo != null) { + List message = messageCreatorService.createMessage(seo); + message.forEach(job -> { + if (SocketEnum.IOPUB_SOCKET.equals(job.getSocketType())) { + kernel.publish(singletonList(job.getMessage())); + } else if (SocketEnum.SHELL_SOCKET.equals(job.getSocketType())) { + kernel.send(job.getMessage()); + } + }); + } + } + + public void exit() { + } + +} \ No newline at end of file diff --git a/base-api/src/main/java/com/twosigma/beakerx/kernel/threads/ResultSender.java b/base-api/src/main/java/com/twosigma/beakerx/kernel/threads/ResultSender.java new file mode 100644 index 0000000..73c5215 --- /dev/null +++ b/base-api/src/main/java/com/twosigma/beakerx/kernel/threads/ResultSender.java @@ -0,0 +1,24 @@ +/* + * 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.kernel.threads; + +import com.twosigma.beakerx.jvm.object.EvaluationObject; + +public interface ResultSender { + void update(EvaluationObject seo); + + void exit(); +} diff --git a/base-api/src/main/java/com/twosigma/beakerx/message/Header.java b/base-api/src/main/java/com/twosigma/beakerx/message/Header.java new file mode 100644 index 0000000..b171826 --- /dev/null +++ b/base-api/src/main/java/com/twosigma/beakerx/message/Header.java @@ -0,0 +1,116 @@ +/* + * Copyright 2017 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.message; + +import static com.twosigma.beakerx.kernel.Utils.timestamp; +import static com.twosigma.beakerx.kernel.Utils.uuid; +import static com.twosigma.beakerx.util.Preconditions.checkNotNull; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import com.twosigma.beakerx.kernel.Utils; +import com.twosigma.beakerx.kernel.msg.JupyterMessages; +import com.twosigma.beakerx.util.Preconditions; + +@JsonPropertyOrder({ "id", "username", "session", "date", "type", "version" }) +public class Header { + + public static final String MSG_ID = "msg_id"; + + private String date; + @JsonProperty(MSG_ID) + private String id; + private String username; + private String session; + @JsonProperty("msg_type") + private JupyterMessages type; + private String version; + + private Header(){ + //only for jackson + } + + public Header(JupyterMessages type, String session) { + date = Utils.timestamp(); + id = Utils.uuid(); + username = "kernel"; + this.type = type; + this.session = Preconditions.checkNotNull(session); + this.version = "5.3"; + } + + public String asJson() { + return MessageSerializer.toJson(this); + } + + public String getDate() { + return date; + } + + public void setDate(String date) { + this.date = date; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getSession() { + return session; + } + + public String getType() { + return type != null ? type.getName() : null; + } + + public JupyterMessages getTypeEnum() { + return type; + } + + public void setTypeEnum(JupyterMessages type) { + this.type = type; + } + + public void setType(String type) { + this.type = JupyterMessages.getType(type); + } + + public String getVersion() { + return version; + } + + public void setVersion(String version) { + this.version = version; + } + + @Override + public String toString() { + return "Type = " + this.getType() + " Id = " + this.getId(); + } + +} \ No newline at end of file diff --git a/base-api/src/main/java/com/twosigma/beakerx/message/Message.java b/base-api/src/main/java/com/twosigma/beakerx/message/Message.java new file mode 100644 index 0000000..dfaa167 --- /dev/null +++ b/base-api/src/main/java/com/twosigma/beakerx/message/Message.java @@ -0,0 +1,104 @@ +/* + * Copyright 2017 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.message; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import com.twosigma.beakerx.kernel.Utils; +import com.twosigma.beakerx.kernel.msg.JupyterMessages; +import com.twosigma.beakerx.util.Preconditions; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import static org.apache.commons.lang3.builder.ToStringBuilder.reflectionToString; + +@JsonPropertyOrder({"identities", "header", "parentHeader", "metadata", "content"}) +public class Message { + + private List identities; + private Header header; + @JsonProperty("parent_header") + private Header parentHeader; + private Map metadata; + private Map content; + private List buffers = new ArrayList<>(); + + public Message(Header header, List identities) { + this.identities = identities; + this.header = Preconditions.checkNotNull(header); + header.setDate(Utils.timestamp()); + } + + public Message(Header header) { + this(header, new ArrayList<>()); + } + + public JupyterMessages type() { + return (header != null && header.getTypeEnum() != null) ? header.getTypeEnum() : null; + } + + public List getIdentities() { + return identities; + } + + public void setIdentities(List identities) { + this.identities = identities; + } + + public Header getHeader() { + return header; + } + + public Header getParentHeader() { + return parentHeader; + } + + public void setParentHeader(Header parentHeader) { + this.parentHeader = parentHeader; + } + + public Map getMetadata() { + return metadata; + } + + public void setMetadata(Map metadata) { + this.metadata = metadata; + } + + public Map getContent() { + return content; + } + + public void setContent(Map content) { + this.content = content; + } + + @Override + public String toString() { + return reflectionToString(this); + } + + public void setBuffers(List buffers) { + this.buffers = buffers; + } + + public List getBuffers() { + return buffers; + } +} \ No newline at end of file diff --git a/base-api/src/main/java/com/twosigma/beakerx/message/MessageSerializer.java b/base-api/src/main/java/com/twosigma/beakerx/message/MessageSerializer.java new file mode 100644 index 0000000..0e3de2a --- /dev/null +++ b/base-api/src/main/java/com/twosigma/beakerx/message/MessageSerializer.java @@ -0,0 +1,54 @@ +/* + * Copyright 2017 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.message; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; + +public class MessageSerializer { + + private static ObjectMapper mapper; + + static { + mapper = new ObjectMapper(); + mapper.disable(SerializationFeature.INDENT_OUTPUT); + mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); + } + + private MessageSerializer() { + } + + public static T parse(String json, Class theClass) { + T result = null; + try { + result = mapper.readValue(json, theClass); + } catch (Exception e) { + // Ignored. + } + + return result; + } + + public static String toJson(Object object) { + try { + return mapper.writeValueAsString(object); + } catch (Exception e) { + return null; + } + + } +} \ No newline at end of file diff --git a/base-api/src/main/java/com/twosigma/beakerx/mimetype/MIMEContainer.java b/base-api/src/main/java/com/twosigma/beakerx/mimetype/MIMEContainer.java new file mode 100644 index 0000000..6278975 --- /dev/null +++ b/base-api/src/main/java/com/twosigma/beakerx/mimetype/MIMEContainer.java @@ -0,0 +1,249 @@ +/* + * Copyright 2017 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.mimetype; + +import com.twosigma.beakerx.util.ByteStreams; +import org.apache.commons.lang3.StringUtils; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.net.URL; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +import static org.apache.commons.lang3.builder.EqualsBuilder.reflectionEquals; +import static org.apache.commons.lang3.builder.HashCodeBuilder.reflectionHashCode; +import static org.apache.commons.lang3.builder.ToStringBuilder.reflectionToString; + +public class MIMEContainer { + + private static final int DEFAULT_IFRAME_WIDTH = 400; + private static final int DEFAULT_IFRAME_HEIGHT = 300; + + public static final MIMEContainer HIDDEN = addMimeType(MIME.HIDDEN); + + public static class MIME { + public static final String TEXT_PLAIN = "text/plain"; + public static final String TEXT_HTML = "text/html"; + public static final String TEXT_LATEX = "text/latex"; + public static final String TEXT_MARKDOWN = "text/markdown"; + public static final String APPLICATION_JAVASCRIPT = "application/javascript"; + public static final String IMAGE_PNG = "image/png"; + public static final String IMAGE_JPEG = "image/jpeg"; + public static final String IMAGE_SVG = "image/svg+xml"; + public static final String HIDDEN = "x-beakerx/empty"; + private String mime; + + public MIME(String mime) { + this.mime = mime; + } + + public String asString() { + return mime; + } + + @Override + public boolean equals(Object o) { + return reflectionEquals(this, o); + } + + @Override + public int hashCode() { + return reflectionHashCode(this); + } + + @Override + public String toString() { + return reflectionToString(this); + } + } + + private MIME mime; + private Object data = ""; + + private MIMEContainer(MIME mime) { + this.mime = mime; + } + + public MIMEContainer(String mime, Object code) { + this.mime = new MIME(mime); + this.data = code; + } + + public MIME getMime() { + return mime; + } + + public Object getData() { + return data; + } + + + public static MIMEContainer JavaScript(Object data) { + return addMimeType(MIME.APPLICATION_JAVASCRIPT, data); + } + + public static MIMEContainer HTML(Object data) { + return addMimeType(MIME.TEXT_HTML, data); + } + + public static MIMEContainer Latex(Object data) { + return addMimeType(MIME.TEXT_LATEX, data); + } + + public static MIMEContainer Text(Object data) { + return addMimeType(MIME.TEXT_PLAIN, data); + } + + public static MIMEContainer Markdown(Object data) { + return addMimeType(MIME.TEXT_MARKDOWN, data); + } + + public static MIMEContainer Math(String data) { + data = StringUtils.strip(data, "$"); + return addMimeType(MIME.TEXT_LATEX, "$$" + data + "$$"); + } + + public static MIMEContainer Javascript(Object data) { + return addMimeType(MIME.APPLICATION_JAVASCRIPT, data); + } + + public static MIMEContainer IFrame(String src, Object width, int height) { + String code = String.format("", width.toString(), height, src); + return addMimeType(MIME.TEXT_HTML, code); + } + + private static MIMEContainer IFrame(String srcTemplate, String id, HashMap params) { + Object width = params.getOrDefault("width", DEFAULT_IFRAME_WIDTH); + Integer height = Integer.parseInt(params.getOrDefault("height", DEFAULT_IFRAME_HEIGHT).toString()); + String src = String.format(srcTemplate, id, parseParams(params)); + return IFrame(src, width, height); + } + + public static MIMEContainer VimeoVideo(String id, String ... params) { + HashMap paramsAsMap = paramsToMap(params); + return VimeoVideo(paramsAsMap, id); + } + + public static MIMEContainer VimeoVideo(HashMap params, String id) { + return IFrame("https://player.vimeo.com/video/%1$s", id, params); + } + + public static MIMEContainer YoutubeVideo(String id, String ... params) { + HashMap paramsAsMap = paramsToMap(params); + return YoutubeVideo(paramsAsMap, id); + } + + public static MIMEContainer YoutubeVideo(HashMap params, String id) { + return IFrame("https://www.youtube.com/embed/%1$s%2$s", id, params); + } + + public static MIMEContainer ScribdDocument(String id, String ... params) { + HashMap paramsAsMap = paramsToMap(params); + return ScribdDocument(paramsAsMap, id); + } + + public static MIMEContainer ScribdDocument(HashMap params, String id) { + return IFrame("https://www.scribd.com/embeds/%1$s/content%2$s", id, params); + } + + public static MIMEContainer Video(String src) { + String output = String.format("", src); + return addMimeType(MIME.TEXT_HTML, output); + } + + private static MIMEContainer addMimeType(String mime) { + return new MIMEContainer(new MIME(mime)); + } + + protected static MIMEContainer addMimeType(String mime, Object data) { + return new MIMEContainer(mime, data.toString()); + } + + protected static boolean exists(String data) { + File f = new File(data); + return (f.exists() && !f.isDirectory()); + } + + protected static boolean isValidURL(String urlString) { + try { + URL url = new URL(urlString); + url.toURI(); + return true; + } catch (Exception exception) { + return false; + } + } + + protected static byte[] getBytes(Object data) throws IOException { + byte[] bytes; + if (isValidURL(data.toString())) { + bytes = ByteStreams.toByteArray((new URL(data.toString()).openStream())); + } else if (exists(data.toString())) { + Path path = Paths.get(data.toString()); + bytes = Files.readAllBytes(path); + } else { + throw new FileNotFoundException(data.toString() + " doesn't exist. "); + } + return bytes; + } + + @Override + public String toString() { + return this.getMime() + " CODE = " + this.getData(); + } + + @Override + public boolean equals(Object o) { + return reflectionEquals(this, o); + } + + @Override + public int hashCode() { + return reflectionHashCode(this); + } + + private static HashMap paramsToMap(String ... params) { + HashMap paramsMap = new HashMap<>(); + for (String param : params) { + String parts[] = param.split("="); + if (parts.length == 2){ + paramsMap.put(parts[0], parts[1]); + } + } + return paramsMap; + } + + private static String parseParams(HashMap paramsMap) { + List iframeParamKeys = Arrays.asList("width", "height", "id"); + + StringBuilder sb = new StringBuilder(); + for (Object key : paramsMap.keySet()){ + if (iframeParamKeys.contains(key)){ + continue; + } + sb.append("&").append(key.toString()).append("=").append(paramsMap.get(key).toString()); + } + String result = sb.toString().replaceFirst("&", "?"); + return result.length() > 0 ? result : ""; + } + +} \ No newline at end of file diff --git a/base-api/src/main/java/com/twosigma/beakerx/table/handlers/ChangeAction.java b/base-api/src/main/java/com/twosigma/beakerx/table/handlers/ChangeAction.java new file mode 100644 index 0000000..a85f592 --- /dev/null +++ b/base-api/src/main/java/com/twosigma/beakerx/table/handlers/ChangeAction.java @@ -0,0 +1,20 @@ +/* + * 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.table.handlers; + +public interface ChangeAction { + void execute(); +} diff --git a/base-api/src/main/java/com/twosigma/beakerx/table/handlers/StateRequestMsgCallbackHandler.java b/base-api/src/main/java/com/twosigma/beakerx/table/handlers/StateRequestMsgCallbackHandler.java new file mode 100644 index 0000000..0348066 --- /dev/null +++ b/base-api/src/main/java/com/twosigma/beakerx/table/handlers/StateRequestMsgCallbackHandler.java @@ -0,0 +1,42 @@ +/* + * 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.table.handlers; + +import com.twosigma.beakerx.handler.Handler; +import com.twosigma.beakerx.message.Message; + +import java.util.Map; + +public class StateRequestMsgCallbackHandler implements Handler { + private ChangeAction action; + + public StateRequestMsgCallbackHandler(ChangeAction action) { + this.action = action; + } + + @Override + public void handle(Message message) { + if (message.getContent()!= null && message.getContent().containsKey("data")) { + Map data = (Map) message.getContent().get("data"); + if (data.containsKey("method")) { + String method = (String) data.get("method"); + if (method.equals("request_state")) { + action.execute(); + } + } + } + } +} diff --git a/base-api/src/main/java/com/twosigma/beakerx/util/ByteStreams.java b/base-api/src/main/java/com/twosigma/beakerx/util/ByteStreams.java new file mode 100644 index 0000000..6b04b02 --- /dev/null +++ b/base-api/src/main/java/com/twosigma/beakerx/util/ByteStreams.java @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2012 The Guava Authors + * Modifications copyright (C) 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.util; + +import java.io.ByteArrayOutputStream; +import java.io.Closeable; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +import static com.twosigma.beakerx.util.Preconditions.checkNotNull; + + +public class ByteStreams { + + private static final int BUF_SIZE = 0x1000; // 4K + + public static byte[] toByteArray(InputStream in) throws IOException { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + copy(in, out); + return out.toByteArray(); + } + + public static long copy(InputStream from, OutputStream to) + throws IOException { + checkNotNull(from); + checkNotNull(to); + byte[] buf = new byte[BUF_SIZE]; + long total = 0; + while (true) { + int r = from.read(buf); + if (r == -1) { + break; + } + to.write(buf, 0, r); + total += r; + } + return total; + } + + + public static int read(InputStream in, byte[] b, int off, int len) + throws IOException { + checkNotNull(in); + checkNotNull(b); + if (len < 0) { + throw new IndexOutOfBoundsException("len is negative"); + } + int total = 0; + while (total < len) { + int result = in.read(b, off + total, len - total); + if (result == -1) { + break; + } + total += result; + } + return total; + } + + public static void closeQuietly(InputStream inputStream) { + try { + close(inputStream, true); + } catch (IOException impossible) { + throw new AssertionError(impossible); + } + } + + public static void close(Closeable closeable, + boolean swallowIOException) throws IOException { + if (closeable == null) { + return; + } + try { + closeable.close(); + } catch (IOException e) { + if (swallowIOException) { + } else { + throw e; + } + } + } + +} diff --git a/base-api/src/main/java/com/twosigma/beakerx/util/ClassPath.java b/base-api/src/main/java/com/twosigma/beakerx/util/ClassPath.java new file mode 100644 index 0000000..4f0e19b --- /dev/null +++ b/base-api/src/main/java/com/twosigma/beakerx/util/ClassPath.java @@ -0,0 +1,332 @@ +/* + * Copyright (C) 2012 The Guava Authors + * Modifications copyright (C) 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.util; + +import java.io.File; +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.jar.Attributes; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; +import java.util.jar.Manifest; +import java.util.stream.Collectors; + +public class ClassPath { + + private static final String CLASS_FILE_NAME_EXTENSION = ".class"; + private final Set resources; + + private ClassPath(Set resources) { + this.resources = resources; + } + + public boolean packageExists(String packageName) { + List collect = resources.stream().filter(x -> x.getResourceName().replace("/", ".").contains(packageName)).collect(Collectors.toList()); + return !collect.isEmpty(); + } + + public static ClassPath from(ClassLoader classloader) throws IOException { + Scanner scanner = new Scanner(); + for (Map.Entry entry : getClassPathEntries(classloader).entrySet()) { + scanner.scan(entry.getKey(), entry.getValue()); + } + return new ClassPath(scanner.getResources()); + } + + static Map getClassPathEntries( + ClassLoader classloader) { + Map entries = new HashMap<>(); + // Search parent first, since it's the order ClassLoader#loadClass() uses. + ClassLoader parent = classloader.getParent(); + if (parent != null) { + entries.putAll(getClassPathEntries(parent)); + } + if (classloader instanceof URLClassLoader) { + URLClassLoader urlClassLoader = (URLClassLoader) classloader; + for (URL entry : urlClassLoader.getURLs()) { + URI uri; + try { + uri = entry.toURI(); + } catch (URISyntaxException e) { + throw new IllegalArgumentException(e); + } + if (!entries.containsKey(uri)) { + entries.put(uri, classloader); + } + } + } + return new HashMap<>(entries); + } + + static final class Scanner { + + private final Set resources = new HashSet<>(); + private final Set scannedUris = new HashSet<>(); + + Set getResources() { + return resources; + } + + void scan(URI uri, ClassLoader classloader) throws IOException { + if (uri.getScheme().equals("file") && scannedUris.add(uri)) { + scanFrom(new File(uri), classloader); + } + } + + void scanFrom(File file, ClassLoader classloader) + throws IOException { + if (!file.exists()) { + return; + } + if (file.isDirectory()) { + scanDirectory(file, classloader); + } else { + scanJar(file, classloader); + } + } + + private void scanDirectory(File directory, ClassLoader classloader) throws IOException { + scanDirectory(directory, classloader, "", new HashSet<>()); + } + + private void scanDirectory( + File directory, ClassLoader classloader, String packagePrefix, + Set ancestors) throws IOException { + File canonical = directory.getCanonicalFile(); + if (ancestors.contains(canonical)) { + // A cycle in the filesystem, for example due to a symbolic link. + return; + } + File[] files = directory.listFiles(); + if (files == null) { + // IO error, just skip the directory + return; + } + Set newAncestors = new HashSet<>(); + newAncestors.addAll(ancestors); + newAncestors.add(canonical); + + for (File f : files) { + String name = f.getName(); + if (f.isDirectory()) { + scanDirectory(f, classloader, packagePrefix + name + "/", newAncestors); + } else { + String resourceName = packagePrefix + name; + if (!resourceName.equals(JarFile.MANIFEST_NAME)) { + resources.add(ResourceInfo.of(resourceName, classloader)); + } + } + } + } + + private void scanJar(File file, ClassLoader classloader) throws IOException { + JarFile jarFile; + try { + jarFile = new JarFile(file); + } catch (IOException e) { + // Not a jar file + return; + } + try { + for (URI uri : getClassPathFromManifest(file, jarFile.getManifest())) { + scan(uri, classloader); + } + Enumeration entries = jarFile.entries(); + while (entries.hasMoreElements()) { + JarEntry entry = entries.nextElement(); + if (entry.isDirectory() || entry.getName().equals(JarFile.MANIFEST_NAME)) { + continue; + } + resources.add(ResourceInfo.of(entry.getName(), classloader)); + } + } finally { + try { + jarFile.close(); + } catch (IOException ignored) { + } + } + } + + /** + * Returns the class path URIs specified by the {@code Class-Path} manifest attribute, according + * to + * JAR File Specification. If {@code manifest} is null, it means the jar file has no + * manifest, and an empty set will be returned. + */ + static Set getClassPathFromManifest( + File jarFile, Manifest manifest) { + if (manifest == null) { + return new HashSet<>(); + } + Set builder = new HashSet<>(); + String classpathAttribute = manifest.getMainAttributes() + .getValue(Attributes.Name.CLASS_PATH.toString()); + if (classpathAttribute != null) { + for (String path : classpathAttribute.split(" ")) { + URI uri; + try { + uri = getClassPathEntry(jarFile, path); + } catch (URISyntaxException e) { + // Ignore bad entry + continue; + } + builder.add(uri); + } + } + return builder; + } + + /** + * Returns the absolute uri of the Class-Path entry value as specified in + * + * JAR File Specification. Even though the specification only talks about relative urls, + * absolute urls are actually supported too (for example, in Maven surefire plugin). + */ + static URI getClassPathEntry(File jarFile, String path) + throws URISyntaxException { + URI uri = new URI(path); + if (uri.isAbsolute()) { + return uri; + } else { + return new File(jarFile.getParentFile(), path.replace('/', File.separatorChar)).toURI(); + } + } + } + + public static String getPackageName(String classFullName) { + int lastDot = classFullName.lastIndexOf('.'); + return (lastDot < 0) ? "" : classFullName.substring(0, lastDot); + } + + static String getClassName(String filename) { + int classNameEnd = filename.length() - CLASS_FILE_NAME_EXTENSION.length(); + return filename.substring(0, classNameEnd).replace('/', '.'); + } + + public static final class ClassInfo extends ResourceInfo { + private final String className; + + ClassInfo(String resourceName, ClassLoader loader) { + super(resourceName, loader); + this.className = ClassPath.getClassName(resourceName); + } + + /** + * Returns the package name of the class, without attempting to load the class. + *

+ *

Behaves identically to {@link Package#getName()} but does not require the class (or + * package) to be loaded. + */ + public String getPackageName() { + return ClassPath.getPackageName(className); + } + + /** + * Returns the fully qualified name of the class. + *

+ *

Behaves identically to {@link Class#getName()} but does not require the class to be + * loaded. + */ + public String getName() { + return className; + } + + /** + * Loads (but doesn't link or initialize) the class. + * + * @throws LinkageError when there were errors in loading classes that this class depends on. + * For example, {@link NoClassDefFoundError}. + */ + public Class load() { + try { + return loader.loadClass(className); + } catch (ClassNotFoundException e) { + // Shouldn't happen, since the class name is read from the class path. + throw new IllegalStateException(e); + } + } + + @Override + public String toString() { + return className; + } + } + + public static class ResourceInfo { + private final String resourceName; + final ClassLoader loader; + + static ResourceInfo of(String resourceName, ClassLoader loader) { + if (resourceName.endsWith(CLASS_FILE_NAME_EXTENSION)) { + return new ClassInfo(resourceName, loader); + } else { + return new ResourceInfo(resourceName, loader); + } + } + + ResourceInfo(String resourceName, ClassLoader loader) { + this.resourceName = Preconditions.checkNotNull(resourceName); + this.loader = Preconditions.checkNotNull(loader); + } + + /** + * Returns the url identifying the resource. + */ + public final URL url() { + return Preconditions.checkNotNull(loader.getResource(resourceName)); + } + + /** + * Returns the fully qualified name of the resource. Such as "com/mycomp/foo/bar.txt". + */ + public final String getResourceName() { + return resourceName; + } + + @Override + public int hashCode() { + return resourceName.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof ResourceInfo) { + ResourceInfo that = (ResourceInfo) obj; + return resourceName.equals(that.resourceName) + && loader == that.loader; + } + return false; + } + + // Do not change this arbitrarily. We rely on it for sorting ResourceInfo. + @Override + public String toString() { + return resourceName; + } + } + + +} diff --git a/base-api/src/main/java/com/twosigma/beakerx/util/Preconditions.java b/base-api/src/main/java/com/twosigma/beakerx/util/Preconditions.java new file mode 100644 index 0000000..05466e4 --- /dev/null +++ b/base-api/src/main/java/com/twosigma/beakerx/util/Preconditions.java @@ -0,0 +1,57 @@ +/* + * 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.util; + +public class Preconditions { + + public static T checkNotNull(T reference) { + if (reference == null) { + throw new NullPointerException(); + } + return reference; + } + + public static T checkNotNull(T reference, String message) { + if (reference == null) { + throw new NullPointerException(message); + } + return reference; + } + + public static void checkState(boolean expression, String message) { + if (!expression) { + throw new IllegalStateException(message); + } + } + + public static void checkState(boolean expression) { + if (!expression) { + throw new IllegalStateException(); + } + } + + public static String checkNotEmpty(String text) { + return checkNotEmpty(text, ""); + } + + public static String checkNotEmpty(String text, String errorMessage) { + if (text == null || text.isEmpty()) { + throw new IllegalStateException(errorMessage); + } + return text; + } + +} diff --git a/base-api/src/main/java/com/twosigma/beakerx/widget/BeakerxWidgetInfo.java b/base-api/src/main/java/com/twosigma/beakerx/widget/BeakerxWidgetInfo.java new file mode 100644 index 0000000..15fabb3 --- /dev/null +++ b/base-api/src/main/java/com/twosigma/beakerx/widget/BeakerxWidgetInfo.java @@ -0,0 +1,23 @@ +/* + * 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.widget; + +public interface BeakerxWidgetInfo { + String MODEL_MODULE_VALUE = "beakerx"; + String VIEW_MODULE_VALUE = "beakerx"; + String MODEL = "model"; + String MODEL_UPDATE = "updateData"; +} diff --git a/base-api/src/main/java/com/twosigma/beakerx/widget/ChangeItem.java b/base-api/src/main/java/com/twosigma/beakerx/widget/ChangeItem.java new file mode 100644 index 0000000..df79b69 --- /dev/null +++ b/base-api/src/main/java/com/twosigma/beakerx/widget/ChangeItem.java @@ -0,0 +1,54 @@ +/* + * 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.widget; + +import static org.apache.commons.lang3.builder.EqualsBuilder.reflectionEquals; +import static org.apache.commons.lang3.builder.HashCodeBuilder.reflectionHashCode; +import static org.apache.commons.lang3.builder.ToStringBuilder.reflectionToString; + +public class ChangeItem { + private String propertyName; + private Object value; + + + public ChangeItem(String propertyName, Object value) { + this.propertyName = propertyName; + this.value = value; + } + + public String getPropertyName() { + return propertyName; + } + + public Object getValue() { + return value; + } + + @Override + public boolean equals(Object o) { + return reflectionEquals(this, o); + } + + @Override + public int hashCode() { + return reflectionHashCode(this); + } + + @Override + public String toString() { + return reflectionToString(this); + } +} diff --git a/base-api/src/main/java/com/twosigma/beakerx/widget/CommActions.java b/base-api/src/main/java/com/twosigma/beakerx/widget/CommActions.java new file mode 100644 index 0000000..74e1f6f --- /dev/null +++ b/base-api/src/main/java/com/twosigma/beakerx/widget/CommActions.java @@ -0,0 +1,49 @@ +/* + * Copyright 2017 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.widget; + +public enum CommActions { + + DOUBLE_CLICK("DOUBLE_CLICK"), + ONCLICK("onclick"), + ONKEY("onkey"), + ACTIONDETAILS("actiondetails"), + CONTEXT_MENU_CLICK("CONTEXT_MENU_CLICK"), + CLICK("click"); + + private String action; + + CommActions(String action) { + this.action = action; + } + + public String getAction() { + return action; + } + + public static CommActions getByAction(final String input) { + CommActions ret = null; + if (input != null) { + for (CommActions item : CommActions.values()) { + if (item.getAction().equalsIgnoreCase(input.trim())) { + ret = item; + break; + } + } + } + return ret; + } +} diff --git a/base-api/src/main/java/com/twosigma/beakerx/widget/CommFunctionality.java b/base-api/src/main/java/com/twosigma/beakerx/widget/CommFunctionality.java new file mode 100644 index 0000000..98f28d8 --- /dev/null +++ b/base-api/src/main/java/com/twosigma/beakerx/widget/CommFunctionality.java @@ -0,0 +1,26 @@ +/* + * Copyright 2017 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.widget; + +import com.twosigma.beakerx.kernel.comm.Comm; + +public interface CommFunctionality { + + Comm getComm(); + + void close(); + +} \ No newline at end of file diff --git a/base-api/src/main/java/com/twosigma/beakerx/widget/DisplayableWidget.java b/base-api/src/main/java/com/twosigma/beakerx/widget/DisplayableWidget.java new file mode 100644 index 0000000..aa250fc --- /dev/null +++ b/base-api/src/main/java/com/twosigma/beakerx/widget/DisplayableWidget.java @@ -0,0 +1,22 @@ +/* + * Copyright 2017 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.widget; + +public interface DisplayableWidget { + + void display(); + +} diff --git a/base-api/src/main/java/com/twosigma/beakerx/widget/LayoutInfo.java b/base-api/src/main/java/com/twosigma/beakerx/widget/LayoutInfo.java new file mode 100644 index 0000000..0f239e0 --- /dev/null +++ b/base-api/src/main/java/com/twosigma/beakerx/widget/LayoutInfo.java @@ -0,0 +1,34 @@ +/* + * 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.widget; + +public interface LayoutInfo { + public static final String IPY_MODEL = "IPY_MODEL_"; + public static final String LAYOUT = "layout"; + public static final String DISPLAY = "display"; + public static final String ALIGN_ITEMS = "align_items"; + public static final String FLEX_FLOW = "flex_flow"; + public static final String WIDTH = "width"; + public static final String HEIGHT = "height"; + public static final String PX = "px"; + public static final String VIEW_NAME_VALUE = "LayoutView"; + public static final String MODEL_NAME_VALUE = "LayoutModel"; + public static final String VISIBILITY = "visibility"; + public static final String MODEL_MODULE_VALUE = "@jupyter-widgets/base"; + public static final String VIEW_MODULE_VALUE = "@jupyter-widgets/base"; + + +} diff --git a/base-api/src/main/java/com/twosigma/beakerx/widget/WidgetInfo.java b/base-api/src/main/java/com/twosigma/beakerx/widget/WidgetInfo.java new file mode 100644 index 0000000..2758156 --- /dev/null +++ b/base-api/src/main/java/com/twosigma/beakerx/widget/WidgetInfo.java @@ -0,0 +1,45 @@ +/* + * 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.widget; + +public interface WidgetInfo { + String APPLICATION_VND_JUPYTER_WIDGET_VIEW_JSON = "application/vnd.jupyter.widget-view+json"; + String MODEL_ID = "model_id"; + + String MODEL_MODULE = "_model_module"; + String MODEL_NAME = "_model_name"; + String VIEW_MODULE = "_view_module"; + String VIEW_NAME = "_view_name"; + String VIEW_MODULE_VERSION = "_view_module_version"; + String MODEL_MODULE_VERSION = "_model_module_version"; + + String MODEL_MODULE_VALUE = "@jupyter-widgets/controls"; + String VIEW_MODULE_VALUE = "@jupyter-widgets/controls"; + String MODEL_MODULE_VERSION_VALUE = "*"; + String VIEW_MODULE_VERSION_VALUE = "*"; + + String VALUE = "value"; + String DISABLED = "disabled"; + String VISIBLE = "visible"; + String DESCRIPTION = "description"; + String MSG_THROTTLE = "msg_throttle"; + + String METHOD = "method"; + String DISPLAY = "display_data"; + + String INDEX = "index"; + +} diff --git a/base-test/build.gradle b/base-test/build.gradle new file mode 100644 index 0000000..2999781 --- /dev/null +++ b/base-test/build.gradle @@ -0,0 +1,22 @@ +version 'unspecified' + +repositories { + mavenCentral() +} + +dependencies { + compile project(':base-api') + compile group: 'org.assertj', name: 'assertj-core', version: '3.6.1' + compile group: 'junit', name: 'junit', version: '4.12' +} + +publishing { + publications { + maven(MavenPublication) { + groupId 'com.twosigma' + artifactId 'beakerx-kernel-base-test' + version "$beakerxVersion" + from components.java + } + } +} \ No newline at end of file diff --git a/base-test/src/main/java/com/twosigma/MessageAssertions.java b/base-test/src/main/java/com/twosigma/MessageAssertions.java new file mode 100644 index 0000000..2680db1 --- /dev/null +++ b/base-test/src/main/java/com/twosigma/MessageAssertions.java @@ -0,0 +1,53 @@ +/* + * Copyright 2017 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; + +import com.twosigma.beakerx.kernel.msg.JupyterMessages; +import com.twosigma.beakerx.message.Message; + +import static org.assertj.core.api.Assertions.assertThat; + +public class MessageAssertions { + + public static void verifyExecuteReplyMessage(Message executeReply) { + assertThat(executeReply.type()).isEqualTo(JupyterMessages.EXECUTE_REPLY); + } + + public static boolean isIdleMessage(Message message) { + return message.getContent() != null && + message.getContent().get("execution_state") != null && + message.getContent().get("execution_state").equals("idle"); + } + + public static boolean isBusyMessage(Message message) { + return message.getContent() != null && + message.getContent().get("execution_state") != null && + message.getContent().get("execution_state").equals("busy"); + } + + public static boolean isExecuteResultMessage(Message message) { + return message.type().equals(JupyterMessages.EXECUTE_RESULT); + } + + public static boolean isExecuteInputMessage(Message message) { + return message.type().equals(JupyterMessages.EXECUTE_INPUT); + } + + + public static boolean isErrorMessage(Message message) { + return message.type().equals(JupyterMessages.ERROR); + } +} diff --git a/base-test/src/main/java/com/twosigma/beakerx/AutotranslationServiceTestMock.java b/base-test/src/main/java/com/twosigma/beakerx/AutotranslationServiceTestMock.java new file mode 100644 index 0000000..f6a4770 --- /dev/null +++ b/base-test/src/main/java/com/twosigma/beakerx/AutotranslationServiceTestMock.java @@ -0,0 +1,44 @@ +/* + * 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; + +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +public class AutotranslationServiceTestMock implements AutotranslationService { + + private ConcurrentMap beakerx = new ConcurrentHashMap(); + + @Override + public String update(String name, String json) { + return beakerx.put(name, json); + } + + @Override + public String get(String name) { + return beakerx.get(name); + } + + @Override + public String close() { + return null; + } + + @Override + public String getContextAsString() { + return null; + } +} diff --git a/base-test/src/main/java/com/twosigma/beakerx/BeakerXCommRepositoryMock.java b/base-test/src/main/java/com/twosigma/beakerx/BeakerXCommRepositoryMock.java new file mode 100644 index 0000000..b1ef87c --- /dev/null +++ b/base-test/src/main/java/com/twosigma/beakerx/BeakerXCommRepositoryMock.java @@ -0,0 +1,215 @@ +/* + * 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; + +import com.twosigma.beakerx.handler.Handler; +import com.twosigma.beakerx.kernel.KernelFunctionality; +import com.twosigma.beakerx.kernel.KernelManager; +import com.twosigma.beakerx.kernel.comm.Buffer; +import com.twosigma.beakerx.kernel.comm.Comm; +import com.twosigma.beakerx.kernel.comm.Data; +import com.twosigma.beakerx.kernel.msg.JupyterMessages; +import com.twosigma.beakerx.message.Header; +import com.twosigma.beakerx.message.Message; +import com.twosigma.beakerx.widget.ChangeItem; + +import java.io.Serializable; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +public class BeakerXCommRepositoryMock implements CommRepository { + private Map comms = new HashMap<>(); + + @Override + public Comm getCommByTargetName(String targetName) { + return null; + } + + @Override + public Comm getOrCreateAutotranslationComm() { + return new Comm() { + @Override + public void addMsgCallbackList(Handler... handlers) { + + } + + @Override + public void setData(HashMap data) { + + } + + @Override + public void open() { + + } + + @Override + public void open(Buffer buffer) { + + } + + @Override + public void open(Message parentMessage) { + + } + + @Override + public void close() { + + } + + @Override + public String getCommId() { + return null; + } + + @Override + public void send(Buffer buffer, Data data) { + + } + + @Override + public void send(JupyterMessages type, Data data) { + + } + + @Override + public void send(JupyterMessages type, Buffer buffer, Data data) { + KernelFunctionality kernelFunctionality = KernelManager.get(); + kernelFunctionality.publish(Arrays.asList(new Message(new Header(type, "id")))); + } + + @Override + public void sendUpdate(Buffer buffer) { + + } + + @Override + public void sendUpdate(List changes) { + + } + + @Override + public void sendUpdate(List changes, Message parent) { + + } + + @Override + public Message createUpdateMessage(List changes, Message parent) { + return null; + } + + @Override + public Message createUpdateMessage(List changes, HashMap state) { + return null; + } + + @Override + public Message createOutputContent(Map content) { + return null; + } + + @Override + public Message getParentMessage() { + return null; + } + + @Override + public void publish(List list) { + + } + + @Override + public Message createMessage(JupyterMessages type, Buffer buffer, Data data, Message parent) { + return null; + } + + @Override + public Message createMessage(JupyterMessages type, Buffer buffer, Data data) { + return null; + } + + @Override + public String getTargetName() { + return null; + } + + @Override + public void handleMsg(Message parentMessage) { + + } + + @Override + public String getTargetModule() { + return null; + } + + @Override + public void setTargetModule(String targetModule) { + + } + + @Override + public Data getData() { + return null; + } + + @Override + public Comm createNewComm() { + return null; + } + + @Override + public void sendData(String event, HashMap payload) { + + } + }; + } + + @Override + public void closeComms() { + + } + + @Override + public Set getCommHashSet() { + return this.comms.keySet(); + } + + @Override + public void addComm(String hash, Comm commObject) { + this.comms.put(hash, commObject); + + } + + @Override + public Comm getComm(String hash) { + return this.comms.get(hash); + } + + @Override + public void removeComm(String hash) { + this.comms.remove(hash); + } + + @Override + public boolean isCommPresent(String hash) { + return this.comms.get(hash) != null; + } +} diff --git a/base-test/src/main/java/com/twosigma/beakerx/BeakerXServerMock.java b/base-test/src/main/java/com/twosigma/beakerx/BeakerXServerMock.java new file mode 100644 index 0000000..a285d7e --- /dev/null +++ b/base-test/src/main/java/com/twosigma/beakerx/BeakerXServerMock.java @@ -0,0 +1,43 @@ +/* + * 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; + +import com.twosigma.beakerx.kernel.KernelFunctionality; +import com.twosigma.beakerx.kernel.restserver.BeakerXServer; +import com.twosigma.beakerx.kernel.restserver.RESTAction; + +public class BeakerXServerMock implements BeakerXServer { + + @Override + public BeakerXServer get(KernelFunctionality kernel) { + return this; + } + + @Override + public String getURL() { + return ""; + } + + @Override + public void addPostMapping(String path, RESTAction restAction) { + + } + + + public static BeakerXServer create() { + return new BeakerXServerMock(); + } +} diff --git a/base-test/src/main/java/com/twosigma/beakerx/ClasspathManagerTest.java b/base-test/src/main/java/com/twosigma/beakerx/ClasspathManagerTest.java new file mode 100644 index 0000000..4345608 --- /dev/null +++ b/base-test/src/main/java/com/twosigma/beakerx/ClasspathManagerTest.java @@ -0,0 +1,74 @@ +/* + * 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; + +import com.twosigma.beakerx.kernel.KernelRunner; +import com.twosigma.beakerx.kernel.PathToJar; +import org.junit.Test; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.List; +import java.util.jar.JarOutputStream; +import java.util.jar.Manifest; + +import static java.util.Collections.singletonList; +import static org.assertj.core.api.Assertions.assertThat; + +public abstract class ClasspathManagerTest extends KernelSetUpFixtureTest { + + private static final String JAR_NAME = "classpathManagerFooTest.jar"; + + public ClasspathManagerTest(KernelRunner kernelRunner) { + super(kernelRunner); + } + + @Test + public void returnEmptyListOfJarsFromClasspath() { + //given + //when + List jars = ClasspathManager.getJars(); + //then + assertThat(jars).isEmpty(); + } + + @Test + public void returnOnlyJarsFromClasspath() { + //given + String jar = createJar(); + getKernel().addJarsToClasspath(singletonList(new PathToJar(jar))); + //when + List jars = ClasspathManager.getJars(); + //then + assertThat(jars).isNotEmpty(); + jars.forEach(path -> assertThat(path).endsWith(".jar")); + } + + private String createJar() { + String archiveFile = getKernel().getTempFolder() + File.separator + JAR_NAME; + try { + FileOutputStream stream = new FileOutputStream(archiveFile); + JarOutputStream out = new JarOutputStream(stream, new Manifest()); + out.close(); + stream.close(); + } catch (IOException e) { + throw new RuntimeException(e); + } + + return archiveFile; + } +} \ No newline at end of file diff --git a/base-test/src/main/java/com/twosigma/beakerx/FileServiceMock.java b/base-test/src/main/java/com/twosigma/beakerx/FileServiceMock.java new file mode 100644 index 0000000..5d4a00b --- /dev/null +++ b/base-test/src/main/java/com/twosigma/beakerx/FileServiceMock.java @@ -0,0 +1,21 @@ +package com.twosigma.beakerx; + +import com.twosigma.beakerx.kernel.magic.command.functionality.FileService; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +public class FileServiceMock implements FileService { + + private List deletedFiles = new ArrayList<>(); + + @Override + public void delete(File file) { + this.deletedFiles.add(file.getAbsolutePath()); + } + + public List getDeletedFiles() { + return deletedFiles; + } +} diff --git a/base-test/src/main/java/com/twosigma/beakerx/KernelExecutionTest.java b/base-test/src/main/java/com/twosigma/beakerx/KernelExecutionTest.java new file mode 100644 index 0000000..fd20159 --- /dev/null +++ b/base-test/src/main/java/com/twosigma/beakerx/KernelExecutionTest.java @@ -0,0 +1,306 @@ +/* + * Copyright 2017 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; + +import com.twosigma.beakerx.evaluator.EvaluationObjectFactory; +import com.twosigma.beakerx.evaluator.EvaluatorResultTestWatcher; +import com.twosigma.beakerx.kernel.Code; +import com.twosigma.beakerx.kernel.KernelRunner; +import com.twosigma.beakerx.kernel.MessageCreatorService; +import com.twosigma.beakerx.kernel.comm.Comm; +import com.twosigma.beakerx.kernel.magic.command.CodeFactory; +import com.twosigma.beakerx.kernel.magic.command.functionality.AddImportMagicCommandInfo; +import com.twosigma.beakerx.kernel.magic.command.functionality.ClasspathAddJarMagicCommandInfo; +import com.twosigma.beakerx.kernel.magic.command.functionality.LoadMagicMagicCommandInfo; +import com.twosigma.beakerx.kernel.magic.command.functionality.UnImportMagicCommandInfo; +import com.twosigma.beakerx.message.Message; +import com.twosigma.beakerx.widget.TestWidgetUtils; +import org.junit.Test; + +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.stream.Collectors; + +import static com.twosigma.MessageAssertions.verifyExecuteReplyMessage; +import static com.twosigma.beakerx.MessageFactorTest.commMsg; +import static org.assertj.core.api.Assertions.assertThat; + +public abstract class KernelExecutionTest extends ClasspathManagerTest { + + public static final String DEMO_RESOURCES_JAR = "./src/test/resources"; + public static final String DEMO_JAR_NAME = "demo.jar"; + public static final String DEMO_JAR = DEMO_RESOURCES_JAR + "/" + DEMO_JAR_NAME; + public static final String LOAD_MAGIC_JAR_DEMO_JAR_NAME = "loadMagicJarDemo.jar"; + public static final String LOAD_MAGIC_DEMO_JAR = DEMO_RESOURCES_JAR + "/" + LOAD_MAGIC_JAR_DEMO_JAR_NAME; + private MessageCreatorService messageCreatorService; + private EvaluationObjectFactory evaluationObjectFactory; + + public KernelExecutionTest(KernelRunner kernelRunner, MessageCreatorService messageCreatorService, EvaluationObjectFactory evaluationObjectFactory) { + super(kernelRunner); + this.messageCreatorService = messageCreatorService; + this.evaluationObjectFactory = evaluationObjectFactory; + } + + private CodeFactory getCodeFactory() { + return new CodeFactory(messageCreatorService, evaluationObjectFactory); + } + + @Test + public void evaluate16Divide2() throws Exception { + //given + String code = codeFor16Divide2(); + Message message = MessageFactoryTest.getExecuteRequestMessage(code); + //when + getKernelSocketsService().handleMsg(message); + //then + Optional idleMessage = EvaluatorResultTestWatcher.waitForIdleMessage(getKernelSocketsService().getKernelSockets()); + assertThat(idleMessage).isPresent(); + Optional result = EvaluatorResultTestWatcher.waitForResult(getKernelSocketsService().getKernelSockets()); + checkResultForErrors(result, code); + assertThat(result).isPresent(); + verifyResult(result.get()); + verifyPublishedMsgs(getKernelSocketsService()); + EvaluatorResultTestWatcher.waitForSentMessage(getKernelSocketsService().getKernelSockets()); + verifySentMsgs(getKernelSocketsService()); + } + + protected void checkResultForErrors(Optional result, String code) throws InterruptedException { + if (!result.isPresent()) { + Optional error = EvaluatorResultTestWatcher.waitForErrorMessage(getKernelSocketsService().getKernelSockets()); + String errorMsg; + if (error.isPresent()) { + errorMsg = "Error message received instead of result:\n" + + "Code: " + code + "\n" + + error.get().getContent().toString() + "\n"; + } else { + errorMsg = "Result nor error messages found:\n" + + String.join(",", + getKernelSocketsService().getPublishedMessages().stream() + .map(m -> m.getHeader().getType()) + .collect(Collectors.toList())) + "\n"; + } + throw new AssertionError(errorMsg); + } + } + + protected String codeFor16Divide2() { + return "16/2"; + } + + private void verifyPublishedMsgs(KernelSocketsServiceTest service) { + assertThat(service.getBusyMessage()).isPresent(); + assertThat(service.getExecuteInputMessage()).isPresent(); + assertThat(service.getExecuteResultMessage()).isPresent(); + assertThat(service.getIdleMessage()).isPresent(); + } + + private void verifySentMsgs(KernelSocketsServiceTest service) { + verifyExecuteReplyMessage(service.getReplyMessage()); + } + + private void verifyResult(Message result) { + Map actual = ((Map) result.getContent().get(Comm.DATA)); + String value = (String) actual.get("text/plain"); + assertThat(value).isEqualTo("8"); + } + + @Test + public void loadMagicCommand() throws Exception { + //given + addJarWithCustomMagicCommand(); + //when + loadMagicCommandByClass(); + //then + verifyLoadedMagicCommand(); + } + + protected void verifyLoadedMagicCommand() throws InterruptedException { + String allCode = "%showEnvs"; + Code code = getCodeFactory().create(allCode, commMsg(), getKernel()); + code.execute(getKernel(), 3); + List std = EvaluatorResultTestWatcher.waitForStdouts(getKernelSocketsService().getKernelSockets()); + String text = (String) std.get(1).getContent().get("text"); + assertThat(text).contains("PATH"); + } + + protected void loadMagicCommandByClass() throws InterruptedException { + String allCode = LoadMagicMagicCommandInfo.LOAD_MAGIC + " com.twosigma.beakerx.custom.magic.command.ShowEnvsCustomMagicCommand"; + Code code = getCodeFactory().create(allCode, commMsg(), getKernel()); + code.execute(getKernel(), 2); + List std = EvaluatorResultTestWatcher.waitForStdouts(getKernelSocketsService().getKernelSockets()); + String text = (String) std.get(0).getContent().get("text"); + assertThat(text).contains("Magic command %showEnvs was successfully added."); + } + + protected void addJarWithCustomMagicCommand() throws InterruptedException { + String allCode = ClasspathAddJarMagicCommandInfo.CLASSPATH_ADD_JAR + " " + LOAD_MAGIC_DEMO_JAR; + Code code = getCodeFactory().create(allCode, commMsg(), getKernel()); + code.execute(getKernel(), 1); + Optional updateMessage = EvaluatorResultTestWatcher.waitForUpdateMessage(getKernelSocketsService().getKernelSockets()); + String text = (String) TestWidgetUtils.getState(updateMessage.get()).get("value"); + assertThat(text).contains("loadMagicJarDemo.jar"); + } + + @Test + public void shouldImportFromAddedDemoJar() throws Exception { + //given + //when + addDemoJar(); + //then + verifyAddedDemoJar(); + } + + private void verifyAddedDemoJar() throws InterruptedException { + String code = codeForVerifyingAddedDemoJar(); + Message message = MessageFactoryTest.getExecuteRequestMessage(code); + //when + getKernelSocketsService().handleMsg(message); + //then + Optional idleMessage = EvaluatorResultTestWatcher.waitForIdleMessage(getKernelSocketsService().getKernelSockets()); + assertThat(idleMessage).isPresent(); + Optional result = EvaluatorResultTestWatcher.waitForResult(getKernelSocketsService().getKernelSockets()); + checkResultForErrors(result, code); + verifyResultOfAddedJar(result.get()); + } + + protected String codeForVerifyingAddedDemoJar() { + return "import com.example.Demo\n" + + "new Demo().getObjectTest()"; + } + + private void verifyResultOfAddedJar(Message message) { + Map actual = ((Map) message.getContent().get(Comm.DATA)); + String value = (String) actual.get("text/plain"); + assertThat(value).contains("Demo_test_123"); + } + + protected void addDemoJar() throws InterruptedException { + String allCode = ClasspathAddJarMagicCommandInfo.CLASSPATH_ADD_JAR + " " + DEMO_JAR; + Code code = getCodeFactory().create(allCode, commMsg(), getKernel()); + code.execute(getKernel(), 1); + Optional updateMessage = EvaluatorResultTestWatcher.waitForUpdateMessage(getKernelSocketsService().getKernelSockets()); + String text = (String) TestWidgetUtils.getState(updateMessage.get()).get("value"); + assertThat(text).contains("demo.jar"); + } + + @Test + public void shouldImportDemoClassByMagicCommand() throws Exception { + //given + addDemoJar(); + String path = pathToDemoClassFromAddedDemoJar(); + //when + Code code = getCodeFactory().create(AddImportMagicCommandInfo.IMPORT + " " + path, commMsg(), getKernel()); + code.execute(kernel, 1); + //then + verifyImportedDemoClassByMagicCommand(); + } + + private void verifyImportedDemoClassByMagicCommand() throws InterruptedException { + String allCode = getObjectTestMethodFromAddedDemoJar(); + Message message = MessageFactoryTest.getExecuteRequestMessage(allCode); + getKernelSocketsService().handleMsg(message); + Optional idleMessage = EvaluatorResultTestWatcher.waitForIdleMessage(getKernelSocketsService().getKernelSockets()); + assertThat(idleMessage).isPresent(); + Optional result = EvaluatorResultTestWatcher.waitForResult(getKernelSocketsService().getKernelSockets()); + checkResultForErrors(result, allCode); + assertThat(result).isPresent(); + Map actual = ((Map) result.get().getContent().get(Comm.DATA)); + String value = (String) actual.get("text/plain"); + assertThat(value).contains("Demo_test_123"); + } + + protected String pathToDemoClassFromAddedDemoJar() { + return "com.example.Demo"; + } + + protected String getObjectTestMethodFromAddedDemoJar() { + return "new Demo().getObjectTest()"; + } + + @Test + public void shouldImportDemoClassWithWildcardByMagicCommand() throws Exception { + //given + addDemoJar(); + String path = pathToDemoClassFromAddedDemoJar(); + String allCode = AddImportMagicCommandInfo.IMPORT + " " + path.substring(0, path.lastIndexOf(".")) + ".*"; + //when + Code code = getCodeFactory().create(allCode, commMsg(), getKernel()); + code.execute(kernel, 1); + //then + verifyImportedDemoClassByMagicCommand(); + } + + @Test + public void shouldNotImportClassesFromUnknownPackageWithWildcardByMagicCommand() throws Exception { + //given + String path = pathToDemoClassFromAddedDemoJar(); + String allCode = AddImportMagicCommandInfo.IMPORT + " " + (path.substring(0, path.lastIndexOf(".")) + "Unknown.*"); + addDemoJar(); + //when + Code code = getCodeFactory().create(allCode, commMsg(), getKernel()); + code.execute(kernel, 1); + //then + List std = EvaluatorResultTestWatcher.waitForStderr(getKernelSocketsService().getKernelSockets()); + String text = (String) std.get(0).getContent().get("text"); + assertThat(text).contains("Could not import"); + } + + @Test + public void shouldNotImportUnknownClassByMagicCommand() throws Exception { + //given + String allCode = AddImportMagicCommandInfo.IMPORT + " " + pathToDemoClassFromAddedDemoJar() + "UnknownClass"; + //when + Code code = getCodeFactory().create(allCode, commMsg(), getKernel()); + code.execute(kernel, 1); + //then + List std = EvaluatorResultTestWatcher.waitForStderr(getKernelSocketsService().getKernelSockets()); + String text = (String) std.get(0).getContent().get("text"); + assertThat(text).contains("Could not import"); + } + + @Test + public void shouldUnimportDemoClassByMagicCommand() throws Exception { + //given + addDemoJar(); + String path = pathToDemoClassFromAddedDemoJar(); + Code code = getCodeFactory().create(AddImportMagicCommandInfo.IMPORT + " " + path, commMsg(), getKernel()); + code.execute(kernel, 1); + //when + Code code2 = getCodeFactory().create(UnImportMagicCommandInfo.UNIMPORT + " " + path, commMsg(), getKernel()); + code2.execute(kernel, 2); + //then + //assertThat(status).isEqualTo(MagicCommandOutcomeItem.Status.OK); + verifyUnImportedDemoClassByMagicCommand(); + } + + protected void verifyUnImportedDemoClassByMagicCommand() throws InterruptedException { + String allCode = getObjectTestMethodFromAddedDemoJar(); + Message message = MessageFactoryTest.getExecuteRequestMessage(allCode); + getKernelSocketsService().handleMsg(message); + Optional idleMessage = EvaluatorResultTestWatcher.waitForIdleMessage(getKernelSocketsService().getKernelSockets()); + assertThat(idleMessage).isPresent(); + Optional errorMessage = EvaluatorResultTestWatcher.waitForErrorMessage(getKernelSocketsService().getKernelSockets()); + Object actual = ((Map) errorMessage.get().getContent()).get("text"); + String value = (String) actual; + assertThat(value).contains(unimportErrorMessage()); + } + + protected String unimportErrorMessage() { + return "unable"; + } + +} diff --git a/base-test/src/main/java/com/twosigma/beakerx/KernelSetUpFixtureTest.java b/base-test/src/main/java/com/twosigma/beakerx/KernelSetUpFixtureTest.java new file mode 100644 index 0000000..7441504 --- /dev/null +++ b/base-test/src/main/java/com/twosigma/beakerx/KernelSetUpFixtureTest.java @@ -0,0 +1,61 @@ +/* + * Copyright 2017 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; + +import com.twosigma.beakerx.kernel.CloseKernelAction; +import com.twosigma.beakerx.kernel.KernelFunctionality; +import com.twosigma.beakerx.kernel.KernelRunner; +import com.twosigma.beakerx.kernel.KernelSocketsFactory; +import org.junit.After; +import org.junit.Before; + +public abstract class KernelSetUpFixtureTest { + + protected KernelSocketsServiceTest kernelSocketsService; + protected KernelFunctionality kernel; + private Thread kernelThread; + private KernelRunner kernelRunner; + + public KernelSetUpFixtureTest(KernelRunner kernelRunner) { + this.kernelRunner = kernelRunner; + } + + @Before + public void setUp() throws Exception { + String sessionId = "sessionId2"; + kernelSocketsService = new KernelSocketsServiceTest(); + kernel = createKernel(sessionId, kernelSocketsService, KernelCloseKernelAction.NO_ACTION); + kernelThread = new Thread(() -> kernelRunner.run(() -> kernel)); + kernelThread.start(); + kernelSocketsService.waitForSockets(); + } + + @After + public void tearDown() throws Exception { + kernelSocketsService.shutdown(); + kernelThread.join(); + } + + public KernelSocketsServiceTest getKernelSocketsService() { + return kernelSocketsService; + } + + public KernelFunctionality getKernel() { + return kernel; + } + + protected abstract KernelFunctionality createKernel(String sessionId, KernelSocketsFactory kernelSocketsFactory, CloseKernelAction closeKernelAction); +} diff --git a/base-test/src/main/java/com/twosigma/beakerx/KernelSocketsServiceTest.java b/base-test/src/main/java/com/twosigma/beakerx/KernelSocketsServiceTest.java new file mode 100644 index 0000000..3b85c44 --- /dev/null +++ b/base-test/src/main/java/com/twosigma/beakerx/KernelSocketsServiceTest.java @@ -0,0 +1,123 @@ +/* + * Copyright 2017 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; + +import com.twosigma.MessageAssertions; +import com.twosigma.beakerx.kernel.KernelFunctionality; +import com.twosigma.beakerx.kernel.KernelSockets; +import com.twosigma.beakerx.kernel.KernelSocketsFactory; +import com.twosigma.beakerx.kernel.SocketCloseAction; +import com.twosigma.beakerx.handler.Handler; +import com.twosigma.beakerx.message.Message; + +import java.util.List; +import java.util.Optional; + +public class KernelSocketsServiceTest implements KernelSocketsFactory { + + private volatile boolean shutdown = false; + private volatile boolean started = false; + + private KernelFunctionality kernel; + + public void shutdown() { + this.shutdown = true; + } + + public boolean isStarted() { + return started; + } + + private KernelSocketsTest kernelSockets; + + public void waitForSockets() { + while (!isStarted()) { + //wait for kernel + } + } + + public void handleMsg(final Message message) { + Handler handler = kernel.getHandler(message.type()); + handler.handle(message); + } + + @Override + public KernelSockets create(KernelFunctionality kernel, SocketCloseAction closeAction) { + this.kernel = kernel; + this.kernelSockets = createKernelSockets(); + return kernelSockets; + } + + private KernelSocketsTest createKernelSockets() { + return new KernelSocketsTest() { + @Override + public void run() { + while (!shutdown) { + //do nothing + } + } + + @Override + public synchronized void start() { + super.start(); + started = true; + } + }; + } + + public KernelSocketsTest getKernelSockets() { + return kernelSockets; + } + + public List getPublishedMessages() { + return getKernelSockets().getPublishedMessages(); + } + + public List getSentMessages() { + return getKernelSockets().getSentMessages(); + } + + public Optional getBusyMessage() { + if (MessageAssertions.isBusyMessage(getPublishedMessages().get(0))) { + return Optional.of(getPublishedMessages().get(0)); + } + return Optional.empty(); + } + + public Optional getExecuteInputMessage() { + return getPublishedMessages().stream().filter(MessageAssertions::isExecuteInputMessage).findFirst(); + } + + public Optional getExecuteResultMessage() { + return getPublishedMessages().stream().filter(MessageAssertions::isExecuteResultMessage).findFirst(); + } + + public Optional getIdleMessage() { + return getPublishedMessages().stream().filter(MessageAssertions::isIdleMessage).findFirst(); + } + + public Optional getErrorMessage() { + return getPublishedMessages().stream().filter(MessageAssertions::isErrorMessage).findFirst(); + } + + public Message getReplyMessage() { + return getSentMessages().get(0); + } + + public void clear() { + getKernelSockets().clear(); + } +} diff --git a/base-test/src/main/java/com/twosigma/beakerx/KernelSocketsTest.java b/base-test/src/main/java/com/twosigma/beakerx/KernelSocketsTest.java new file mode 100644 index 0000000..ed0749a --- /dev/null +++ b/base-test/src/main/java/com/twosigma/beakerx/KernelSocketsTest.java @@ -0,0 +1,63 @@ +/* + * Copyright 2017 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; + +import com.twosigma.beakerx.kernel.KernelSockets; +import com.twosigma.beakerx.message.Message; + +import java.util.ArrayList; +import java.util.List; + +import static java.util.Arrays.asList; +import static java.util.Collections.synchronizedList; + +public class KernelSocketsTest extends KernelSockets { + + private volatile List publishedMessages = synchronizedList(new ArrayList<>()); + private volatile List sentMessages = synchronizedList(new ArrayList<>()); + + @Override + public void publish(List message) { + publishedMessages.addAll(message); + } + + @Override + public void send(Message message) { + sentMessages.add(message); + } + + @Override + public String sendStdIn(Message message) { + return "stdin message"; + } + + public List getPublishedMessages() { + return copy(this.publishedMessages); + } + + public List getSentMessages() { + return copy(this.sentMessages); + } + + private List copy(List list) { + return asList(list.toArray(new Message[0])); + } + + public synchronized void clear() { + publishedMessages = synchronizedList(new ArrayList<>()); + sentMessages = synchronizedList(new ArrayList<>()); + } +} diff --git a/base-test/src/main/java/com/twosigma/beakerx/KernelTest.java b/base-test/src/main/java/com/twosigma/beakerx/KernelTest.java new file mode 100644 index 0000000..2151b30 --- /dev/null +++ b/base-test/src/main/java/com/twosigma/beakerx/KernelTest.java @@ -0,0 +1,537 @@ +/* + * Copyright 2017 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; + +import com.twosigma.beakerx.autocomplete.AutocompleteResult; +import com.twosigma.beakerx.evaluator.Evaluator; +import com.twosigma.beakerx.evaluator.EvaluatorTest; +import com.twosigma.beakerx.evaluator.Hook; +import com.twosigma.beakerx.evaluator.InternalVariable; +import com.twosigma.beakerx.handler.Handler; +import com.twosigma.beakerx.inspect.InspectResult; +import com.twosigma.beakerx.jvm.object.Configuration; +import com.twosigma.beakerx.jvm.object.ConfigurationFactory; +import com.twosigma.beakerx.jvm.object.EvaluationObject; +import com.twosigma.beakerx.jvm.threads.BeakerInputHandler; +import com.twosigma.beakerx.jvm.threads.BeakerOutputHandler; +import com.twosigma.beakerx.kernel.AddImportStatus; +import com.twosigma.beakerx.kernel.BeakerXClasspath; +import com.twosigma.beakerx.kernel.BeakerXJson; +import com.twosigma.beakerx.kernel.EvaluatorParameters; +import com.twosigma.beakerx.kernel.ExecutionOptions; +import com.twosigma.beakerx.kernel.GroupName; +import com.twosigma.beakerx.kernel.ImportPath; +import com.twosigma.beakerx.kernel.Imports; +import com.twosigma.beakerx.kernel.KernelFunctionality; +import com.twosigma.beakerx.kernel.KernelManager; +import com.twosigma.beakerx.kernel.MagicKernelManager; +import com.twosigma.beakerx.kernel.MessageCreatorService; +import com.twosigma.beakerx.kernel.NoSuchKernelException; +import com.twosigma.beakerx.kernel.PathToJar; +import com.twosigma.beakerx.kernel.PythonEntryPoint; +import com.twosigma.beakerx.kernel.comm.Comm; +import com.twosigma.beakerx.kernel.magic.command.MagicCommandConfiguration; +import com.twosigma.beakerx.kernel.magic.command.MagicCommandType; +import com.twosigma.beakerx.kernel.msg.JupyterMessages; +import com.twosigma.beakerx.kernel.restserver.BeakerXServer; +import com.twosigma.beakerx.kernel.threads.ExecutionResultSender; +import com.twosigma.beakerx.kernel.threads.ResultSender; +import com.twosigma.beakerx.message.Message; +import org.apache.commons.io.FileUtils; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import static com.twosigma.beakerx.AutotranslationService.BEAKERX; +import static com.twosigma.beakerx.MessageFactorTest.commMsg; +import static java.util.Arrays.asList; +import static java.util.Collections.synchronizedList; + +public class KernelTest implements KernelFunctionality { + + private List publishedMessages = synchronizedList(new ArrayList<>()); + private List sentMessages = synchronizedList(new ArrayList<>()); + private String id; + private CommRepository commRepository; + private ResultSender executionResultSender; + public EvaluatorParameters evaluatorParameters; + private Evaluator evaluator; + private String code; + private Path tempFolder; + private Map magicKernels; + private MagicCommandConfiguration magicCommandConfiguration; + private BeakerXJson beakerXJson; + private MessageCreatorService messageCreatorService; + + private List magicCommandTypes = null; + private LinkedList stdinText = new LinkedList<>(); + + public KernelTest(ResultSender resultSender, MessageCreatorService messageCreatorService, MagicCommandConfiguration magicCommandConfiguration) { + this("KernelTestId1", new BeakerXCommRepositoryMock(), messageCreatorService, magicCommandConfiguration); + this.executionResultSender = resultSender; + } + + public KernelTest(MessageCreatorService messageCreatorService, MagicCommandConfiguration magicCommandConfiguration) { + this("KernelTestId1", new BeakerXCommRepositoryMock(), messageCreatorService, magicCommandConfiguration); + } + + public KernelTest(CommRepository commRepository, MessageCreatorService messageCreatorService, MagicCommandConfiguration magicCommandConfiguration) { + this("KernelTestId1", commRepository, messageCreatorService, magicCommandConfiguration); + } + + public KernelTest(String id, CommRepository commRepository, MessageCreatorService messageCreatorService, MagicCommandConfiguration magicCommandConfiguration) { + this.id = id; + this.commRepository = commRepository; + this.beakerXJson = new BeakerXJsonMock(); + this.magicCommandConfiguration = magicCommandConfiguration; + initMagicCommands(); + this.messageCreatorService = messageCreatorService; + this.executionResultSender = new ExecutionResultSender(this, messageCreatorService); + EvaluationObject value = new SimpleEvaluationObjectMock("ok", new SeoConfigurationFactoryMock(this, commMsg(), messageCreatorService, this.magicCommandConfiguration)); + InternalVariable.setValue(value); + KernelManager.register(this); + + } + + public KernelTest(String id, Evaluator evaluator, MessageCreatorService messageCreatorService, MagicCommandConfiguration magicCommandConfiguration) { + this.id = id; + this.evaluator = evaluator; + this.messageCreatorService = messageCreatorService; + this.magicCommandConfiguration = magicCommandConfiguration; + this.executionResultSender = new ExecutionResultSender(this, messageCreatorService); + this.commRepository = new BeakerXCommRepositoryMock(); + this.beakerXJson = new BeakerXJsonMock(); + initMagicCommands(); + EvaluationObject value = new SimpleEvaluationObjectMock("ok", new SeoConfigurationFactoryMock(this, commMsg(), messageCreatorService, this.magicCommandConfiguration)); + InternalVariable.setValue(value); + KernelManager.register(this); + this.magicKernels = new HashMap<>(); + } + + private void initMagicCommands() { + this.magicCommandTypes = magicCommandConfiguration.createDefaults(this); + } + + @Override + public void publish(List message) { + this.publishedMessages.addAll(message); + } + + @Override + public void send(Message message) { + this.sentMessages.add(message); + } + + @Override + public String sendStdIn(Message message) { + return this.stdinText.pop(); + } + + public void addToStdin(String s) { + this.stdinText.add(s); + } + + public String getSessionId() { + return this.id; + } + + public ResultSender getExecutionResultSender() { + return this.executionResultSender; + } + + + @Override + public void addComm(String hash, Comm commObject) { + commRepository.addComm(hash, commObject); + } + + @Override + public void removeComm(String hash) { + commRepository.removeComm(hash); + } + + @Override + public Comm getComm(String hash) { + return commRepository.getComm(hash); + } + + @Override + public boolean isCommPresent(String hash) { + return commRepository.isCommPresent(hash); + } + + @Override + public Set getCommHashSet() { + return commRepository.getCommHashSet(); + } + + @Override + public void updateEvaluatorParameters(EvaluatorParameters kernelParameters) { + this.evaluatorParameters = kernelParameters; + } + + @Override + public List addJarsToClasspath(List paths) { + return this.evaluator.addJarsToClasspath(paths); + } + + @Override + public BeakerXClasspath getClasspath() { + return this.evaluator.getClasspath(); + } + + @Override + public Imports getImports() { + return this.evaluator.getImports(); + } + + @Override + public AddImportStatus addImport(ImportPath anImport) { + return this.evaluator.addImport(anImport); + } + + @Override + public void removeImport(ImportPath anImport) { + this.evaluator.removeImport(anImport); + } + + @Override + public List getMagicCommandTypes() { + return magicCommandTypes; + } + + @Override + public Path getTempFolder() { + if (this.tempFolder == null) { + this.tempFolder = tempFolder(); + } + return this.tempFolder; + } + + @Override + public Path getCacheFolder() { + return getTempFolder(); + } + + @Override + public Class loadClass(String clazzName) throws ClassNotFoundException { + return null; + } + + @Override + public boolean checkIfClassExistsInClassloader(String clazzName) { + return false; + } + + @Override + public void registerMagicCommandType(MagicCommandType magicCommandType) { + magicCommandTypes.add(magicCommandType); + } + + @Override + public String getOutDir() { + return ""; + } + + private Path tempFolder() { + if (this.evaluator == null) { + return EvaluatorTest.getTestTempFolderFactory().createTempFolder(); + } else { + return evaluator.getTempFolder(); + } + } + + public EvaluatorParameters getEvaluatorParameters() { + return evaluatorParameters; + } + + public List getPublishedMessages() { + return copy(this.publishedMessages); + } + + public List getSentMessages() { + return copy(this.sentMessages); + } + + private List copy(List list) { + return asList(list.toArray(new Message[0])); + } + + public void clearPublishedMessages() { + this.publishedMessages = synchronizedList(new ArrayList<>()); + } + + public void clearSentMessages() { + this.sentMessages = synchronizedList(new ArrayList<>()); + } + + public void clearMessages() { + clearSentMessages(); + clearPublishedMessages(); + } + + @Override + public void cancelExecution(GroupName groupName) { + } + + @Override + public void killAllThreads() { + + } + + @Override + public Handler getHandler(JupyterMessages type) { + return null; + } + + @Override + public void run() { + + } + + @Override + public TryResult executeCode(String code, EvaluationObject seo) { + this.code = code; + return TryResult.createResult(this.code); + } + + @Override + public TryResult executeCode(String code, EvaluationObject seo, ExecutionOptions executionOptions) { + return executeCode(code, seo); + } + + public String getCode() { + return code; + } + + @Override + public AutocompleteResult autocomplete(String code, int cursorPos) { + return this.evaluator.autocomplete(code, cursorPos); + } + + @Override + public InspectResult inspect(String code, int cursorPos) { + return this.evaluator.inspect(code, cursorPos); + } + + @Override + public void sendBusyMessage(Message message) { + Message busyMessage = messageCreatorService.createBusyMessage(message); + publish(Collections.singletonList(busyMessage)); + } + + @Override + public void sendIdleMessage(Message message) { + Message idleMessage = messageCreatorService.createIdleMessage(message); + publish(Collections.singletonList(idleMessage)); + } + + public void exit() { + if (evaluator != null) { + evaluator.exit(); + } else { + removeTempFolder(); + } + if (magicKernels != null) { + for (MagicKernelManager manager : magicKernels.values()) { + manager.exit(); + } + } + } + + private void removeTempFolder() { + try { + FileUtils.deleteDirectory(new File(getTempFolder().toString())); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + @Override + public void registerCancelHook(Hook hook) { + } + + @Override + public PythonEntryPoint getPythonEntryPoint(String kernelName) throws NoSuchKernelException { + MagicKernelManager manager = magicKernels.get(kernelName); + if (manager == null) { + manager = new MagicKernelManager(kernelName, "kernelTestContext"); + magicKernels.put(kernelName, manager); + } + return manager.getPythonEntryPoint(); + } + + @Override + public MagicKernelManager getManagerByCommId(String commId) { + return null; + } + + @Override + public void addCommIdManagerMapping(String commId, String kernel) { + } + + @Override + public void putEvaluationInToBackground() { + + } + + @Override + public BeakerXServer getBeakerXServer() { + return BeakerXServerMock.create(); + } + + @Override + public MagicCommandConfiguration magicCommandConfiguration() { + return magicCommandConfiguration; + } + + @Override + public BeakerXJson getBeakerXJson() { + return this.beakerXJson; + } + + @Override + public void startEvaluation() { + + } + + @Override + public void endEvaluation() { + + } + + public FileServiceMock getFileService() { + return (FileServiceMock) magicCommandConfiguration.getFileService(); + } + + + public static class BeakerXJsonMock implements BeakerXJson { + + @Override + public Map beakerxJsonAsMap() { + HashMap stringMapHashMap = new HashMap<>(); + stringMapHashMap.put(BEAKERX, new HashMap()); + return stringMapHashMap; + } + + @Override + public void save(Map map) { + + } + } + + static class SimpleOutputHandlerTest implements BeakerOutputHandler { + + private String text; + + @Override + public void write(String b) { + this.text = b; + } + } + + static class SimpleErrHandlerTest implements BeakerOutputHandler { + + private String text; + + @Override + public void write(String b) { + this.text = b; + } + } + + + public static class SeoConfigurationFactoryMock implements ConfigurationFactory { + private KernelFunctionality kernel; + private Message message; + private MessageCreatorService messageCreatorService; + private MagicCommandConfiguration magicCommandConfiguration; + private int executionCount; + + public SeoConfigurationFactoryMock(KernelFunctionality kernel, Message message, MessageCreatorService messageCreatorService, MagicCommandConfiguration magicCommandConfiguration) { + this.kernel = kernel; + this.message = message; + this.messageCreatorService = messageCreatorService; + this.magicCommandConfiguration = magicCommandConfiguration; + } + + public SeoConfigurationFactoryMock(MessageCreatorService messageCreatorService, MagicCommandConfiguration magicCommandConfiguration) { + this(new KernelTest(messageCreatorService, magicCommandConfiguration), messageCreatorService, magicCommandConfiguration); + } + + public SeoConfigurationFactoryMock(Message message, MessageCreatorService messageCreatorService, MagicCommandConfiguration magicCommandConfiguration) { + this(new KernelTest(messageCreatorService, magicCommandConfiguration), message, messageCreatorService, magicCommandConfiguration); + } + + public SeoConfigurationFactoryMock(int executionCount, MessageCreatorService messageCreatorService, MagicCommandConfiguration magicCommandConfiguration) { + this(messageCreatorService, magicCommandConfiguration); + this.executionCount = executionCount; + } + + public SeoConfigurationFactoryMock(KernelTest kernel, MessageCreatorService messageCreatorService, MagicCommandConfiguration magicCommandConfiguration) { + this(kernel, commMsg(), messageCreatorService, magicCommandConfiguration); + } + + @Override + public Configuration create(EvaluationObject seo) { + BeakerOutputHandler stdout = new SimpleOutputHandler(false, kernel.getExecutionResultSender(), seo); + BeakerOutputHandler stderr = new SimpleOutputHandler(true, kernel.getExecutionResultSender(), seo); + BeakerInputHandler stdin = () -> 0; + return new Configuration(stdin, stdout, stderr, kernel.getExecutionResultSender(), message, executionCount); + } + + public Message getMessage() { + return message; + } + } + + public static class ExecutionResultSenderMock implements ResultSender { + + private List objectList = new LinkedList<>(); + + @Override + public void update(EvaluationObject seo) { + objectList.add(seo); + } + + @Override + public void exit() { + + } + + public List getObjectList() { + return objectList; + } + } + +// public static EvaluationObject createSeo(String code) { +// return new SimpleEvaluationObject(code, new SeoConfigurationFactoryMock()); +// } +// +// public static EvaluationObject createSeo(String code, Message message) { +// return new SimpleEvaluationObject(code, new SeoConfigurationFactoryMock(message)); +// } + +} + diff --git a/base-test/src/main/java/com/twosigma/beakerx/MessageFactorTest.java b/base-test/src/main/java/com/twosigma/beakerx/MessageFactorTest.java new file mode 100644 index 0000000..4dfe222 --- /dev/null +++ b/base-test/src/main/java/com/twosigma/beakerx/MessageFactorTest.java @@ -0,0 +1,38 @@ +/* + * 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; + +import com.twosigma.beakerx.kernel.msg.JupyterMessages; +import com.twosigma.beakerx.message.Header; +import com.twosigma.beakerx.message.Message; + +import java.util.Arrays; +import java.util.List; + +public class MessageFactorTest { + + public static final List MESSAGE_IDENTITIES = Arrays.asList("MessageIdentities123".getBytes()); + + public static Message commMsg() { + return msg(JupyterMessages.COMM_MSG); + } + + public static Message msg(JupyterMessages type) { + Message msg1 = new Message(new Header(type, "session1")); + msg1.setIdentities(MESSAGE_IDENTITIES); + return msg1; + } +} diff --git a/base-test/src/main/java/com/twosigma/beakerx/MessageFactoryTest.java b/base-test/src/main/java/com/twosigma/beakerx/MessageFactoryTest.java new file mode 100644 index 0000000..920c52a --- /dev/null +++ b/base-test/src/main/java/com/twosigma/beakerx/MessageFactoryTest.java @@ -0,0 +1,37 @@ +/* + * Copyright 2017 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; + +import com.twosigma.beakerx.kernel.msg.JupyterMessages; +import com.twosigma.beakerx.message.Header; +import com.twosigma.beakerx.message.Message; + +import java.io.Serializable; +import java.util.HashMap; + +public class MessageFactoryTest { + + public static Message getExecuteRequestMessage(String code) { + Header header = new Header(JupyterMessages.COMM_MSG,"session1"); + Message message = new Message(header); + header.setTypeEnum(JupyterMessages.EXECUTE_REQUEST); + HashMap content = new HashMap<>(); + content.put("code", code); + message.setContent(content); + return message; + } + +} diff --git a/base-test/src/main/java/com/twosigma/beakerx/MessageFactoryTestMock.java b/base-test/src/main/java/com/twosigma/beakerx/MessageFactoryTestMock.java new file mode 100644 index 0000000..1497bbd --- /dev/null +++ b/base-test/src/main/java/com/twosigma/beakerx/MessageFactoryTestMock.java @@ -0,0 +1,120 @@ +/* + * 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; + +import com.twosigma.beakerx.kernel.msg.JupyterMessages; +import com.twosigma.beakerx.message.Header; +import com.twosigma.beakerx.message.Message; + +import java.io.Serializable; +import java.util.Arrays; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.Map; + +import static com.twosigma.beakerx.kernel.comm.Comm.COMM_ID; +import static com.twosigma.beakerx.kernel.comm.Comm.DATA; +import static com.twosigma.beakerx.kernel.comm.Comm.TARGET_MODULE; +import static com.twosigma.beakerx.kernel.comm.Comm.TARGET_NAME; + +public class MessageFactoryTestMock { + + public static Message initCloseMessage() { + Map content = new LinkedHashMap<>(); + content.put(DATA, new HashMap<>()); + content.put(COMM_ID, "commId"); + content.put(TARGET_NAME, "targetName"); + content.put(TARGET_MODULE, "targetModule"); + + Message message = new Message(initHeader(JupyterMessages.COMM_CLOSE)); + message.setIdentities(Arrays.asList("identities".getBytes())); + message.setContent(content); + return message; + } + + public static Message initOpenMessage() { + Map content = new LinkedHashMap<>(); + content.put(DATA, new HashMap<>()); + content.put(COMM_ID, "commId"); + content.put(TARGET_NAME, "targetName"); + content.put(TARGET_MODULE, "targetModule"); + + Message message = new Message(initHeader(JupyterMessages.COMM_OPEN)); + message.setIdentities(Arrays.asList("identities".getBytes())); + message.setContent(content); + return message; + } + + public static Message initCommMessage() { + Map content = new LinkedHashMap<>(); + content.put(DATA, new HashMap<>()); + content.put(COMM_ID, "commId"); + content.put(TARGET_NAME, "targetName"); + content.put(TARGET_MODULE, "targetModule"); + return initCommMessage(content); + } + + public static Message initCommMessage(Map content) { + Message message = new Message(initHeader(JupyterMessages.COMM_MSG)); + message.setIdentities(Arrays.asList("identities".getBytes())); + message.setContent(content); + return message; + } + + public static Message createExecuteRequestMessage(String code) { + Message message = executeRequestMessage(); + Map content = new LinkedHashMap<>(); + content.put("code", code); + message.setContent(content); + return message; + } + + public static Message initExecuteRequestMessage() { + Map content = new LinkedHashMap<>(); + content.put("allow_stdin", Boolean.TRUE); + content.put("code", "new Plot() << new Line(x: (0..5), y: [0, 1, 6, 5, 2, 8])"); + content.put("stop_on_error", Boolean.TRUE); + content.put("user_expressions", new LinkedHashMap<>()); + content.put("silent", Boolean.FALSE); + content.put("store_history", Boolean.TRUE); + + Message message = executeRequestMessage(); + message.setContent(content); + return message; + } + + private static Message executeRequestMessage() { + Message message = new Message(initHeader(JupyterMessages.EXECUTE_REQUEST)); + message.setIdentities(Arrays.asList("identities".getBytes())); + message.setParentHeader(null); + message.setMetadata(new LinkedHashMap<>()); + return message; + } + + public static Message initInfoMessage() { + Message message = new Message(initHeader(JupyterMessages.COMM_INFO_REQUEST)); + message.setIdentities(Arrays.asList("identities".getBytes())); + return message; + } + + public static Header initHeader(JupyterMessages jupyterMessages) { + Header header = new Header(jupyterMessages, "sessionId" + jupyterMessages.getName()); + header.setId("messageId"); + header.setUsername("username"); + header.setVersion("5.0"); + return header; + } +} diff --git a/base-test/src/main/java/com/twosigma/beakerx/RuntimetoolsMock.java b/base-test/src/main/java/com/twosigma/beakerx/RuntimetoolsMock.java new file mode 100644 index 0000000..f2624ca --- /dev/null +++ b/base-test/src/main/java/com/twosigma/beakerx/RuntimetoolsMock.java @@ -0,0 +1,27 @@ +/* + * 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; + +import com.twosigma.beakerx.kernel.KernelFunctionality; +import com.twosigma.beakerx.kernel.Runtimetools; + +public class RuntimetoolsMock implements Runtimetools { + + @Override + public void configRuntimeJars(KernelFunctionality kernel) { + + } +} diff --git a/base-test/src/main/java/com/twosigma/beakerx/SimpleEvaluationObjectMock.java b/base-test/src/main/java/com/twosigma/beakerx/SimpleEvaluationObjectMock.java new file mode 100644 index 0000000..7a7fbe4 --- /dev/null +++ b/base-test/src/main/java/com/twosigma/beakerx/SimpleEvaluationObjectMock.java @@ -0,0 +1,118 @@ +/* + * 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; + +import com.twosigma.beakerx.jvm.object.ConsoleOutput; +import com.twosigma.beakerx.jvm.object.EvaluationObject; +import com.twosigma.beakerx.jvm.object.EvaluationStatus; +import com.twosigma.beakerx.message.Message; + +import java.util.List; +import java.util.Queue; + +public class SimpleEvaluationObjectMock implements EvaluationObject { + private String code; + private KernelTest.SeoConfigurationFactoryMock seoConfigurationFactoryMock; + + public SimpleEvaluationObjectMock(String code, KernelTest.SeoConfigurationFactoryMock seoConfigurationFactoryMock) { + this.code = code; + this.seoConfigurationFactoryMock = seoConfigurationFactoryMock; + } + + public static SimpleEvaluationObjectMock createSeo(String code) { + return new SimpleEvaluationObjectMock(code, null); + } + + @Override + public boolean isShowResult() { + return false; + } + + @Override + public void started() { + + } + + @Override + public void finished(Object r) { + + } + + @Override + public void error(Object r) { + + } + + @Override + public void update(Object r) { + + } + + @Override + public String getExpression() { + return code; + } + + @Override + public EvaluationStatus getStatus() { + return null; + } + + @Override + public Object getPayload() { + return null; + } + + @Override + public void structuredUpdate(String message, int progress) { + + } + + @Override + public void noResult() { + + } + + @Override + public Message getJupyterMessage() { + return seoConfigurationFactoryMock.getMessage(); + } + + @Override + public Queue getConsoleOutput() { + return null; + } + + @Override + public int getExecutionCount() { + return 0; + } + + @Override + public List getOutputdata() { + return null; + } + + @Override + public void setOutputHandler() { + + } + + @Override + public void clrOutputHandler() { + + } +} diff --git a/base-test/src/main/java/com/twosigma/beakerx/autocomplete/JVMEvaluatorAutocompleteImportTest.java b/base-test/src/main/java/com/twosigma/beakerx/autocomplete/JVMEvaluatorAutocompleteImportTest.java new file mode 100644 index 0000000..7cb2355 --- /dev/null +++ b/base-test/src/main/java/com/twosigma/beakerx/autocomplete/JVMEvaluatorAutocompleteImportTest.java @@ -0,0 +1,69 @@ +/* + * Copyright 2017 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.autocomplete; + +import com.twosigma.beakerx.evaluator.BaseEvaluator; +import org.junit.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +public abstract class JVMEvaluatorAutocompleteImportTest { + + protected abstract BaseEvaluator evaluator(); + + @Test + public void autocompleteForImport_autocompleteIsNotEmpty() throws Exception { + String code = "import java.awt.C"; + //when + AutocompleteResult autocomplete = evaluator().autocomplete(code, code.length()); + //then + assertThat(autocomplete.getMatches()).isNotEmpty(); + assertThat(autocomplete.getStartIndex()).isEqualTo(code.length() - 1); + } + + @Test + public void shouldImportBoolean() throws Exception { + String code = "import java.lang.Boo"; + //when + AutocompleteResult autocomplete = evaluator().autocomplete(code, code.length()); + //then + assertThat(autocomplete.getMatches()).contains("Boolean"); + assertThat(autocomplete.getStartIndex()).isEqualTo(code.length() - 3); + } + + @Test + public void shouldAutocompleteToJavaIo() throws Exception { + String code = "import java.io."; + //when + AutocompleteResult autocomplete = evaluator().autocomplete(code, code.length()); + //then + assertThat(autocomplete.getMatches()).isNotEmpty(); + + assertThat(autocomplete.getStartIndex()).isEqualTo(code.length()); + } + + @Test + public void shouldAutocompleteToJavaBeakerx() throws Exception { + String code = "import com.twosigma.beakerx."; + //when + AutocompleteResult autocomplete = evaluator().autocomplete(code, code.length()); + //then + assertThat(autocomplete.getMatches()).isNotEmpty(); + + assertThat(autocomplete.getStartIndex()).isEqualTo(code.length()); + } + +} diff --git a/base-test/src/main/java/com/twosigma/beakerx/evaluator/ClasspathScannerMock.java b/base-test/src/main/java/com/twosigma/beakerx/evaluator/ClasspathScannerMock.java new file mode 100644 index 0000000..5d1071f --- /dev/null +++ b/base-test/src/main/java/com/twosigma/beakerx/evaluator/ClasspathScannerMock.java @@ -0,0 +1,23 @@ +/* + * 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.evaluator; + +public class ClasspathScannerMock implements ClasspathScanner { + + @Override + public void scan() { + } +} diff --git a/base-test/src/main/java/com/twosigma/beakerx/evaluator/EvaluatorBaseTest.java b/base-test/src/main/java/com/twosigma/beakerx/evaluator/EvaluatorBaseTest.java new file mode 100644 index 0000000..2e57132 --- /dev/null +++ b/base-test/src/main/java/com/twosigma/beakerx/evaluator/EvaluatorBaseTest.java @@ -0,0 +1,139 @@ +/* + * Copyright 2017 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.evaluator; + +import com.twosigma.beakerx.SimpleEvaluationObjectMock; +import com.twosigma.beakerx.TryResult; +import com.twosigma.beakerx.jvm.object.EvaluationObject; +import com.twosigma.beakerx.kernel.GroupName; +import org.junit.Test; + +import java.nio.file.Files; +import java.nio.file.Path; + +import static org.assertj.core.api.Assertions.assertThat; + +public abstract class EvaluatorBaseTest { + + public EvaluatorBaseTest() { + } + + public static final String TEMP_DIR_NAME = "beakerxTest"; + + public abstract BaseEvaluator evaluator(); + + protected abstract BaseEvaluator createNewEvaluator(); + + protected abstract BaseEvaluator createNewEvaluator(TempFolderFactory tempFolderFactory); + + public static TempFolderFactory getTestTempFolderFactoryWithoutDeleteOnExit() { + return new TempFolderFactory() { + @Override + public Path createTempFolder() { + Path path; + try { + path = Files.createTempDirectory(TEMP_DIR_NAME); + } catch (Exception e) { + throw new RuntimeException(e); + } + return path; + } + }; + } + + @Test + public void shouldDivide16By2() throws Exception { + //given + String code = codeForDivide16By2(); + EvaluationObject seo = SimpleEvaluationObjectMock.createSeo(code); + //when + TryResult result = evaluator().evaluate(seo, code); + //then + assertThat(result.result().toString()).isEqualTo("8"); + } + + protected abstract String codeForDivide16By2(); + + @Test + public void shouldCreateErrorResultWithArithmeticExceptionWhenDivisionByZero() throws Exception { + //given + String code = codeForDivisionByZero(); + EvaluationObject seo = SimpleEvaluationObjectMock.createSeo(code); + //when + TryResult either = evaluator().evaluate(seo, code); + //then + assertThat(either.error()).contains(textAssertionForDivisionByZero()); + } + + protected String textAssertionForDivisionByZero() { + return "java.lang.ArithmeticException"; + } + + protected abstract String codeForDivisionByZero(); + + @Test + public void returnHelloString() throws Exception { + //given + String code = codeForHello(); + EvaluationObject seo = SimpleEvaluationObjectMock.createSeo(code); + //when + TryResult result = evaluator().evaluate(seo, code); + //then + assertThat((String) result.result()).contains("Hello"); + } + + protected abstract String codeForHello(); + + @Test + public void returnPrintln() throws Exception { + //given + String code = codeForPrintln(); + EvaluationObject seo = SimpleEvaluationObjectMock.createSeo(code); + //when + TryResult result = evaluator().evaluate(seo, code); + //then + verifyReturnPrintlnStatement(result); + } + + protected void verifyReturnPrintlnStatement(TryResult result) { + assertThat((String) result.result()).isNull(); + } + + protected abstract String codeForPrintln(); + + @Test + public void shouldCreateAndRemoveTempFolder() throws Exception { + //given + BaseEvaluator groovyEvaluator = createNewEvaluator(getTestTempFolderFactoryWithoutDeleteOnExit()); + //when + assertThat(Files.exists(groovyEvaluator.getTempFolder())).isTrue(); + groovyEvaluator.exit(); + //then + assertThat(Files.exists(groovyEvaluator.getTempFolder())).isFalse(); + } + + @Test + public void shouldRunCancelHooks() { + //given + final StringBuilder cancelDone = new StringBuilder(); + BaseEvaluator evaluator = evaluator(); + evaluator.registerCancelHook(() -> cancelDone.append("Done")); + //when + evaluator.cancelExecution(GroupName.generate()); + //then + assertThat(cancelDone.toString()).isEqualTo("Done"); + } +} diff --git a/base-test/src/main/java/com/twosigma/beakerx/evaluator/EvaluatorResultTestWatcher.java b/base-test/src/main/java/com/twosigma/beakerx/evaluator/EvaluatorResultTestWatcher.java new file mode 100644 index 0000000..7f84495 --- /dev/null +++ b/base-test/src/main/java/com/twosigma/beakerx/evaluator/EvaluatorResultTestWatcher.java @@ -0,0 +1,258 @@ +/* + * Copyright 2017 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.evaluator; + +import com.twosigma.beakerx.KernelSocketsTest; +import com.twosigma.beakerx.KernelTest; +import com.twosigma.beakerx.jupyter.SearchMessages; +import com.twosigma.beakerx.kernel.msg.JupyterMessages; +import com.twosigma.beakerx.message.Message; +import com.twosigma.beakerx.widget.TestWidgetUtils; + +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +public class EvaluatorResultTestWatcher { + + public static final int ATTEMPT = 2000; + public static final int SLEEP_IN_MILLIS = 20; + + public static Optional waitForResult(KernelTest kernelTest) throws InterruptedException { + int count = 0; + Optional result = getResult(kernelTest); + while (!result.isPresent() && count < ATTEMPT) { + Thread.sleep(SLEEP_IN_MILLIS); + result = getResult(kernelTest); + count++; + } + return result; + } + + public static Optional waitForResult(KernelSocketsTest socketsTest) throws InterruptedException { + int count = 0; + Optional result = getResult(socketsTest); + while (!result.isPresent() && count < ATTEMPT) { + Thread.sleep(SLEEP_IN_MILLIS); + result = getResult(socketsTest); + count++; + } + return result; + } + + public static Optional waitForIdleMessage(KernelTest kernelTest) throws InterruptedException { + int count = 0; + Optional idleMessage = getIdleMessage(kernelTest.getPublishedMessages()); + while (!idleMessage.isPresent() && count < ATTEMPT) { + Thread.sleep(SLEEP_IN_MILLIS); + idleMessage = getIdleMessage(kernelTest.getPublishedMessages()); + count++; + } + return idleMessage; + } + + public static Optional waitForIdleMessage(KernelSocketsTest socketsTest) throws InterruptedException { + int count = 0; + Optional idleMessage = getIdleMessage(socketsTest.getPublishedMessages()); + while (!idleMessage.isPresent() && count < ATTEMPT) { + Thread.sleep(SLEEP_IN_MILLIS); + idleMessage = getIdleMessage(socketsTest.getPublishedMessages()); + count++; + } + return idleMessage; + } + + public static Optional waitForSentMessage(KernelSocketsTest socketsTest) throws InterruptedException { + int count = 0; + Optional sentMessage = getFirstSentMessage(socketsTest); + while (!sentMessage.isPresent() && count < ATTEMPT) { + Thread.sleep(SLEEP_IN_MILLIS); + sentMessage = getFirstSentMessage(socketsTest); + count++; + } + return sentMessage; + } + + public static Optional waitForStreamMessage(KernelTest kernelTest) throws InterruptedException { + int count = 0; + Optional sentMessage = getStreamMessage(kernelTest); + while (!sentMessage.isPresent() && count < ATTEMPT) { + Thread.sleep(SLEEP_IN_MILLIS); + sentMessage = getStreamMessage(kernelTest); + count++; + } + return sentMessage; + } + + public static Optional waitForErrorMessage(KernelTest kernelTest) throws InterruptedException { + int count = 0; + Optional idleMessage = getError(kernelTest.getPublishedMessages()); + while (!idleMessage.isPresent() && count < ATTEMPT) { + Thread.sleep(SLEEP_IN_MILLIS); + idleMessage = getError(kernelTest.getPublishedMessages()); + count++; + } + return idleMessage; + } + + public static Optional waitForErrorMessage(KernelSocketsTest socketsTest) throws InterruptedException { + int count = 0; + Optional idleMessage = getError(socketsTest.getPublishedMessages()); + while (!idleMessage.isPresent() && count < ATTEMPT) { + Thread.sleep(SLEEP_IN_MILLIS); + idleMessage = getError(socketsTest.getPublishedMessages()); + count++; + } + return idleMessage; + } + + + 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(KernelSocketsTest socketsTest, MessagePreconditions preconditions) throws InterruptedException { + int count = 0; + Optional idleMessage = getUpdate(socketsTest.getPublishedMessages()); + while (!preconditions.match(idleMessage) && 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(kernelTest.getPublishedMessages()); + while (!idleMessage.isPresent() && count < ATTEMPT) { + Thread.sleep(SLEEP_IN_MILLIS); + idleMessage = getUpdate(kernelTest.getPublishedMessages()); + count++; + } + return idleMessage; + } + + public static Optional waitForDisplayDataMessage(KernelTest kernelTest) throws InterruptedException { + int count = 0; + Optional sentMessage = getDisplayDataMessage(kernelTest); + while (!sentMessage.isPresent() && count < ATTEMPT) { + Thread.sleep(SLEEP_IN_MILLIS); + sentMessage = getDisplayDataMessage(kernelTest); + count++; + } + return sentMessage; + } + + public static Optional getDisplayDataMessage(KernelTest kernelTest) { + List listMessagesByType = SearchMessages.getListMessagesByType(kernelTest.getPublishedMessages(), JupyterMessages.DISPLAY_DATA); + return listMessagesByType.stream().findFirst(); + } + + public static Optional getStreamMessage(KernelTest kernelTest) { + List listMessagesByType = SearchMessages.getListMessagesByType(kernelTest.getPublishedMessages(), JupyterMessages.STREAM); + return listMessagesByType.stream().findFirst(); + } + + private static Optional getIdleMessage(List messages) { + return messages.stream(). + filter(x -> (x.type().equals(JupyterMessages.STATUS)) && (x.getContent().get("execution_state").equals("idle"))).findFirst(); + } + + private static Optional getFirstSentMessage(KernelSocketsTest socketsTest) { + return socketsTest.getSentMessages().stream().findFirst(); + } + + private static Optional getResult(KernelTest kernelTest) { + return kernelTest.getPublishedMessages().stream(). + filter(x -> x.type().equals(JupyterMessages.EXECUTE_RESULT)).findFirst(); + } + + private static Optional getResult(KernelSocketsTest socketsTest) { + return socketsTest.getPublishedMessages().stream(). + filter(x -> x.type().equals(JupyterMessages.EXECUTE_RESULT)).findFirst(); + } + + private static Optional getError(List messages) { + return messages.stream(). + filter(x -> x.type().equals(JupyterMessages.ERROR)).findFirst(); + } + + + public 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(); + } + + public static List getStdouts(List messages) { + return messages.stream(). + filter(x -> x.type().equals(JupyterMessages.STREAM)). + filter(x -> TestWidgetUtils.getContent(x).get("name").equals("stdout")).collect(Collectors.toList()); + } + + public static List getStderr(List messages) { + return messages.stream(). + filter(x -> x.type().equals(JupyterMessages.STREAM)). + filter(x -> TestWidgetUtils.getContent(x).get("name").equals("stderr")).collect(Collectors.toList()); + } + + public static List waitForStdouts(KernelSocketsTest socketsTest) throws InterruptedException { + int count = 0; + List result = getStdouts(socketsTest.getPublishedMessages()); + while (result.isEmpty() && count < ATTEMPT) { + Thread.sleep(SLEEP_IN_MILLIS); + result = getStdouts(socketsTest.getPublishedMessages()); + count++; + } + return result; + } + + public static List waitForStderr(KernelSocketsTest socketsTest) throws InterruptedException { + int count = 0; + List result = getStderr(socketsTest.getPublishedMessages()); + while (result.isEmpty() && count < ATTEMPT) { + Thread.sleep(SLEEP_IN_MILLIS); + result = getStderr(socketsTest.getPublishedMessages()); + count++; + } + return result; + } + + public static Optional waitForProperty(PropertyWatcher propertyWatcher) throws InterruptedException { + int count = 0; + Optional property = propertyWatcher.get(); + while (!property.isPresent() && count < ATTEMPT) { + Thread.sleep(SLEEP_IN_MILLIS); + property = propertyWatcher.get(); + count++; + } + return property; + } + + public interface PropertyWatcher { + Optional get(); + } +} diff --git a/base-test/src/main/java/com/twosigma/beakerx/evaluator/EvaluatorTest.java b/base-test/src/main/java/com/twosigma/beakerx/evaluator/EvaluatorTest.java new file mode 100644 index 0000000..84acd30 --- /dev/null +++ b/base-test/src/main/java/com/twosigma/beakerx/evaluator/EvaluatorTest.java @@ -0,0 +1,276 @@ +/* + * Copyright 2017 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.evaluator; + +import com.twosigma.beakerx.BeakerXClient; +import com.twosigma.beakerx.CodeCell; +import com.twosigma.beakerx.TryResult; +import com.twosigma.beakerx.autocomplete.AutocompleteResult; +import com.twosigma.beakerx.inspect.InspectResult; +import com.twosigma.beakerx.jvm.classloader.BeakerXUrlClassLoader; +import com.twosigma.beakerx.jvm.object.EvaluationObject; +import com.twosigma.beakerx.jvm.threads.CellExecutor; +import com.twosigma.beakerx.kernel.CacheFolderFactory; +import com.twosigma.beakerx.kernel.Classpath; +import com.twosigma.beakerx.kernel.EvaluatorParameters; +import com.twosigma.beakerx.kernel.ExecutionOptions; +import com.twosigma.beakerx.kernel.GroupName; +import com.twosigma.beakerx.kernel.ImportPath; +import com.twosigma.beakerx.kernel.Imports; +import com.twosigma.beakerx.kernel.PathToJar; +import org.apache.commons.io.FileUtils; + +import java.io.File; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.concurrent.SynchronousQueue; + +public class EvaluatorTest extends BaseEvaluator { + + + public static final EvaluatorParameters KERNEL_PARAMETERS = new EvaluatorParameters(new HashMap()); + private EvaluationObject seo; + private String code; + private boolean killAllThreads; + private boolean cancelExecution; + private boolean exit; + private Classpath classpath = new Classpath(); + private Imports imports = new Imports(new ArrayList<>()); + private int resetEnvironmentCounter = 0; + private BeakerXUrlClassLoader loader = new BeakerXUrlClassLoader(Thread.currentThread().getContextClassLoader()); + + public EvaluatorTest() { + this(new BeakexClientTestImpl()); + } + + public EvaluatorTest(BeakerXClient beakerXClient) { + this("idEvaluatorTest", "sIdEvaluatorTest", TestBeakerCellExecutor.cellExecutor(), KERNEL_PARAMETERS, beakerXClient); + } + + public EvaluatorTest(String id, String sId, CellExecutor cellExecutor, EvaluatorParameters kernelParameters, BeakerXClient beakerXClient) { + super(id, + sId, + cellExecutor, + getTestTempFolderFactory(), + kernelParameters, + beakerXClient, + new MagicCommandAutocompletePatternsMock(), + new ClasspathScannerMock()); + } + + @Override + public ClassLoader getClassLoader() { + return loader; + } + + public static TempFolderFactory getTestTempFolderFactory() { + return new TempFolderFactory() { + @Override + public Path createTempFolder() { + Path path; + try { + path = Files.createTempDirectory(EvaluatorBaseTest.TEMP_DIR_NAME); + path.toFile().deleteOnExit(); + } catch (Exception e) { + throw new RuntimeException(e); + } + return path; + } + }; + } + + public static CacheFolderFactory getCacheFolderFactory() { + return new CacheFolderFactory() { + @Override + public Path getCache() { + return getTestTempFolderFactory().createTempFolder(); + } + }; + } + + + @Override + public AutocompleteResult autocomplete(String code, int caretPosition) { + return new AutocompleteResult(new ArrayList<>(), 0); + } + + + @Override + public InspectResult inspect(String code, int caretPosition) { + return new InspectResult("", 0); + } + + @Override + public void killAllThreads() { + killAllThreads = true; + } + + @Override + public void cancelExecution(GroupName groupName) { + cancelExecution = true; + } + + @Override + public TryResult evaluate(EvaluationObject seo, String code) { + this.seo = seo; + this.code = code; + return TryResult.createResult(seo.getPayload()); + } + + @Override + public TryResult evaluate(EvaluationObject seo, String code, ExecutionOptions executionOptions) { + return evaluate(seo, code); + } + + @Override + public void exit() { + exit = true; + removeTempFolder(); + } + + private void removeTempFolder() { + try { + FileUtils.deleteQuietly(new File(getTempFolder().toString())); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @Override + public Classpath getClasspath() { + return this.classpath; + } + + @Override + public void resetEnvironment() { + this.resetEnvironmentCounter++; + } + + @Override + protected void doResetEnvironment() { + } + + public EvaluationObject getSeo() { + return seo; + } + + public String getCode() { + return code; + } + + public boolean isCallKillAllThreads() { + return killAllThreads; + } + + public boolean isCallCancelExecution() { + return cancelExecution; + } + + public boolean isCallExit() { + return exit; + } + + @Override + protected void addJarToClassLoader(PathToJar pathToJar) { + classpath.add(pathToJar); + this.loader.addJar(pathToJar); + } + + @Override + protected void addImportToClassLoader(ImportPath anImport) { + imports.add(anImport, loader); + } + + @Override + protected boolean removeImportPath(ImportPath anImport) { + return imports.remove(anImport); + } + + @Override + public Imports getImports() { + return imports; + } + + public int getResetEnvironmentCounter() { + return resetEnvironmentCounter; + } + + public static class BeakexClientTestImpl implements BeakerXClient { + + private String lastRunByTag; + private HashMap variables = new HashMap<>(); + + @Override + public void showProgressUpdate(String message, int progress) { + + } + + @Override + public void delBeaker() { + + } + + @Override + public String update(String name, Object value) { + return null; + } + + @Override + public Object set(String name, Object value) { + variables.put(name, value); + return value; + } + + @Override + public Object get(String name) { + return variables.get(name); + } + + @Override + public SynchronousQueue getMessageQueue(String channel) { + return null; + } + + @Override + public List getCodeCells(String tagFilter) { + return null; + } + + @Override + public void runByTag(String tag) { + lastRunByTag = tag; + } + + @Override + public String getContext() { + return null; + } + + @Override + public String urlArg(String argName) { + return null; + } + + public String getLastRunByTag() { + return lastRunByTag; + } + } + +} diff --git a/base-test/src/main/java/com/twosigma/beakerx/evaluator/MagicCommandAutocompletePatternsMock.java b/base-test/src/main/java/com/twosigma/beakerx/evaluator/MagicCommandAutocompletePatternsMock.java new file mode 100644 index 0000000..afd3fb4 --- /dev/null +++ b/base-test/src/main/java/com/twosigma/beakerx/evaluator/MagicCommandAutocompletePatternsMock.java @@ -0,0 +1,36 @@ +/* + * 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.evaluator; + +import com.twosigma.beakerx.autocomplete.AutocompleteNode; +import com.twosigma.beakerx.autocomplete.MagicCommandAutocompletePatterns; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Optional; + +public class MagicCommandAutocompletePatternsMock implements MagicCommandAutocompletePatterns { + + @Override + public Optional get(String first) { + return Optional.empty(); + } + + @Override + public Collection values() { + return new ArrayList<>(); + } +} diff --git a/base-test/src/main/java/com/twosigma/beakerx/evaluator/MessagePreconditions.java b/base-test/src/main/java/com/twosigma/beakerx/evaluator/MessagePreconditions.java new file mode 100644 index 0000000..7c1d6dc --- /dev/null +++ b/base-test/src/main/java/com/twosigma/beakerx/evaluator/MessagePreconditions.java @@ -0,0 +1,25 @@ +/* + * 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.evaluator; + +import com.twosigma.beakerx.message.Message; + +import java.util.Optional; + +public interface MessagePreconditions { + + boolean match(Optional message); +} diff --git a/base-test/src/main/java/com/twosigma/beakerx/evaluator/TestBeakerCellExecutor.java b/base-test/src/main/java/com/twosigma/beakerx/evaluator/TestBeakerCellExecutor.java new file mode 100644 index 0000000..0f286f5 --- /dev/null +++ b/base-test/src/main/java/com/twosigma/beakerx/evaluator/TestBeakerCellExecutor.java @@ -0,0 +1,28 @@ +/* + * Copyright 2017 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.evaluator; + +import com.twosigma.beakerx.jvm.threads.BeakerCellExecutor; +import com.twosigma.beakerx.jvm.threads.CellExecutor; + +public class TestBeakerCellExecutor { + + private static final int KILL_THREAD_SLEEP_IN_MILLIS = 1; + + public static CellExecutor cellExecutor() { + return new BeakerCellExecutor("test", KILL_THREAD_SLEEP_IN_MILLIS); + } +} diff --git a/base-test/src/main/java/com/twosigma/beakerx/jupyter/SearchMessages.java b/base-test/src/main/java/com/twosigma/beakerx/jupyter/SearchMessages.java new file mode 100644 index 0000000..32ad3c0 --- /dev/null +++ b/base-test/src/main/java/com/twosigma/beakerx/jupyter/SearchMessages.java @@ -0,0 +1,81 @@ +/* + * Copyright 2017 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.jupyter; + +import com.twosigma.beakerx.kernel.comm.Comm; +import com.twosigma.beakerx.kernel.msg.JupyterMessages; +import com.twosigma.beakerx.widget.LayoutInfo; +import com.twosigma.beakerx.message.Message; +import com.twosigma.beakerx.widget.WidgetInfo; + +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +public class SearchMessages { + + public static List getListLayout(List messages){ + return getListByDataAttr(messages, WidgetInfo.VIEW_NAME, LayoutInfo.VIEW_NAME_VALUE); + } + + public static Message getLayoutForWidget(List messages, Message widget){ + Map map = (Map) ((Map) widget.getContent().get(Comm.DATA)).get(Comm.STATE); + if(map == null || map.get(LayoutInfo.LAYOUT) == null) return null; + String id = ((String) map.get(LayoutInfo.LAYOUT)).replace(LayoutInfo.IPY_MODEL, ""); + return getMessageByCommId(messages, id); + } + + public static List getListWidgetsByViewName(List messages, String viewNameValue){ + return getListByDataAttr(messages, WidgetInfo.VIEW_NAME, viewNameValue); + } + + public static List getListWidgetsByModelName(List messages, String modelNameValue){ + return getListByDataAttr(messages, WidgetInfo.MODEL_NAME, modelNameValue); + } + + public static List getListByDataAttr(List messages, String key, String value){ + return messages.stream() + .filter(m -> { + Map map; + if (key.equals(Comm.METHOD)) { + map = (Map) m.getContent().get(Comm.DATA); + } else { + map = (Map) ((Map)m.getContent().get(Comm.DATA)).get(Comm.STATE); + } + + return map != null && map.containsKey(key) && value.equals(map.get(key)); + }) + .collect(Collectors.toList()); + } + + public static Message getMessageByCommId(List messages, String id){ + return messages.stream() + .filter(m -> id.equals((String) m.getContent().get(Comm.COMM_ID))) + .findFirst() + .get(); + } + + public static List getListMessagesByType(List messages, JupyterMessages type){ + return messages.stream() + .filter(m -> m.getHeader() != null + && m.getHeader().getType() != null + && m.getHeader().getType().equalsIgnoreCase(type.toString()) + ) + .collect(Collectors.toList()); + } + +} diff --git a/base-test/src/main/java/com/twosigma/beakerx/kernel/command/ClasspathAddMvnDepsMagicCommandTestInfo.java b/base-test/src/main/java/com/twosigma/beakerx/kernel/command/ClasspathAddMvnDepsMagicCommandTestInfo.java new file mode 100644 index 0000000..79ee948 --- /dev/null +++ b/base-test/src/main/java/com/twosigma/beakerx/kernel/command/ClasspathAddMvnDepsMagicCommandTestInfo.java @@ -0,0 +1,22 @@ +/* + * 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.kernel.command; + +public interface ClasspathAddMvnDepsMagicCommandTestInfo { + String SRC_TEST_RESOURCES_TEST_MVN_CACHE = "src/test/resources/testMvnCache"; + String BUILD_PATH = "build"; + String TEST_MVN_CACHE = BUILD_PATH + "/testMvnCache"; +} diff --git a/base-test/src/main/java/com/twosigma/beakerx/kernel/command/MagicCommandWhichThrowsException.java b/base-test/src/main/java/com/twosigma/beakerx/kernel/command/MagicCommandWhichThrowsException.java new file mode 100644 index 0000000..894fbb6 --- /dev/null +++ b/base-test/src/main/java/com/twosigma/beakerx/kernel/command/MagicCommandWhichThrowsException.java @@ -0,0 +1,35 @@ +/* + * 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.kernel.command; + +import com.twosigma.beakerx.kernel.magic.command.MagicCommandExecutionParam; +import com.twosigma.beakerx.kernel.magic.command.MagicCommandFunctionality; +import com.twosigma.beakerx.kernel.magic.command.outcome.MagicCommandOutcomeItem; + +public class MagicCommandWhichThrowsException implements MagicCommandFunctionality { + + public static final String MAGIC_COMMAND_WHICH_THROWS_EXCEPTION = "%MagicCommandWhichThrowsException"; + + @Override + public MagicCommandOutcomeItem execute(MagicCommandExecutionParam param) { + throw new RuntimeException("Please handle me."); + } + + @Override + public String getMagicCommandName() { + return MAGIC_COMMAND_WHICH_THROWS_EXCEPTION; + } +} diff --git a/base-test/src/main/java/com/twosigma/beakerx/kernel/magic/command/functionality/ClasspathAddDynamicMagicCommandTest.java b/base-test/src/main/java/com/twosigma/beakerx/kernel/magic/command/functionality/ClasspathAddDynamicMagicCommandTest.java new file mode 100644 index 0000000..2c12556 --- /dev/null +++ b/base-test/src/main/java/com/twosigma/beakerx/kernel/magic/command/functionality/ClasspathAddDynamicMagicCommandTest.java @@ -0,0 +1,93 @@ +/* + * 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.kernel.magic.command.functionality; + +import com.twosigma.beakerx.MessageFactoryTestMock; +import com.twosigma.beakerx.KernelExecutionTest; +import com.twosigma.beakerx.KernelSetUpFixtureTest; +import com.twosigma.beakerx.evaluator.EvaluatorResultTestWatcher; +import com.twosigma.beakerx.kernel.KernelRunner; +import com.twosigma.beakerx.message.Message; +import com.twosigma.beakerx.widget.TestWidgetUtils; +import org.junit.Test; + +import java.util.Optional; + +import static com.twosigma.beakerx.KernelExecutionTest.DEMO_JAR_NAME; +import static com.twosigma.beakerx.KernelExecutionTest.LOAD_MAGIC_JAR_DEMO_JAR_NAME; +import static com.twosigma.beakerx.evaluator.EvaluatorResultTestWatcher.waitForIdleMessage; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.Assert.assertTrue; + +public abstract class ClasspathAddDynamicMagicCommandTest extends KernelSetUpFixtureTest { + + public ClasspathAddDynamicMagicCommandTest(KernelRunner kernelRunner) { + super(kernelRunner); + } + + @Test + public void handleDynamicMagics() throws InterruptedException { + //given + String code = "" + + "a = true" + "\n" + + "b = \"" + KernelExecutionTest.DEMO_JAR + "\"" + "\n" + + "c = \"/tmp/dictC\"" + "\n"; + runCode(code); + //when + String magicCode = "%classpath add dynamic a ? b : c" + "\n"; + Message magicMessage = MessageFactoryTestMock.createExecuteRequestMessage(magicCode); + kernelSocketsService.handleMsg(magicMessage); + //then + verifyResult(); + } + + private void verifyResult() throws InterruptedException { + Optional updateMessage = EvaluatorResultTestWatcher.waitForUpdateMessage(kernelSocketsService.getKernelSockets()); + String text = (String) TestWidgetUtils.getState(updateMessage.get()).get("value"); + assertTrue("No jar added", text.contains(DEMO_JAR_NAME)); + } + + @Test + public void shouldSupportList() throws InterruptedException { + //given + String code = "" + + "location1 = \"" + KernelExecutionTest.DEMO_JAR + "\"" + "\n" + + "location2 = \"" + KernelExecutionTest.LOAD_MAGIC_DEMO_JAR + "\"" + "\n"; + runCode(code); + //when + String magicCode = "%classpath add dynamic [location1, location2]" + "\n"; + Message magicMessage = MessageFactoryTestMock.createExecuteRequestMessage(magicCode); + kernelSocketsService.handleMsg(magicMessage); + //then + verifyList(); + } + + private void verifyList() throws InterruptedException { + Optional idleMessage = waitForIdleMessage(kernelSocketsService.getKernelSockets()); + assertThat(idleMessage).isPresent(); + Optional updateMessage = EvaluatorResultTestWatcher.waitForUpdateMessage(kernelSocketsService.getKernelSockets()); + String text = (String) TestWidgetUtils.getState(updateMessage.get()).get("value"); + assertTrue("Should be two added jars", text.contains(DEMO_JAR_NAME) && text.contains(LOAD_MAGIC_JAR_DEMO_JAR_NAME)); + } + + private void runCode(String code) throws InterruptedException { + Message message = MessageFactoryTestMock.createExecuteRequestMessage(code); + kernelSocketsService.handleMsg(message); + Optional idleMessage = waitForIdleMessage(kernelSocketsService.getKernelSockets()); + assertThat(idleMessage).isPresent(); + kernelSocketsService.clear(); + } +} diff --git a/base-test/src/main/java/com/twosigma/beakerx/message/MessageFactoryMock.java b/base-test/src/main/java/com/twosigma/beakerx/message/MessageFactoryMock.java new file mode 100644 index 0000000..623f4d4 --- /dev/null +++ b/base-test/src/main/java/com/twosigma/beakerx/message/MessageFactoryMock.java @@ -0,0 +1,34 @@ +/* + * 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.message; + +import com.twosigma.beakerx.kernel.msg.JupyterMessages; + +import java.util.LinkedHashMap; + +public class MessageFactoryMock { + + public static Message createMessage() { + Header header = new Header(JupyterMessages.COMM_MSG, "session1"); + Message message = new Message(header); + message.getIdentities().add("identityStr".getBytes()); + message.setParentHeader(header); + message.setMetadata(new LinkedHashMap<>()); + message.setContent(new LinkedHashMap<>()); + return message; + } + +} diff --git a/base-test/src/main/java/com/twosigma/beakerx/widget/TestWidgetUtils.java b/base-test/src/main/java/com/twosigma/beakerx/widget/TestWidgetUtils.java new file mode 100644 index 0000000..27fe3a5 --- /dev/null +++ b/base-test/src/main/java/com/twosigma/beakerx/widget/TestWidgetUtils.java @@ -0,0 +1,191 @@ +/* + * Copyright 2017 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.widget; + +import com.twosigma.beakerx.KernelTest; +import com.twosigma.beakerx.jupyter.SearchMessages; +import com.twosigma.beakerx.kernel.comm.Comm; +import com.twosigma.beakerx.kernel.msg.JupyterMessages; +import com.twosigma.beakerx.message.Message; + +import java.io.Serializable; +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.kernel.msg.JupyterMessages.COMM_OPEN; +import static com.twosigma.beakerx.widget.WidgetInfo.DISPLAY; +import static com.twosigma.beakerx.widget.WidgetInfo.METHOD; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.Assert.assertTrue; + +public class TestWidgetUtils { + + public static void verifyOpenCommMsg(List messages, String modelNameValue, + String viewNameValue) { + verifyInternalOpenCommMsgWitLayout(messages, modelNameValue, viewNameValue, + + WidgetInfo.MODEL_MODULE_VALUE, + WidgetInfo.VIEW_MODULE_VALUE); + } + + public static void verifyOpenCommMsgWitoutLayout(List messages, String modelNameValue, + String viewNameValue) { + Message message = SearchMessages.getListWidgetsByViewName(messages, viewNameValue).get(0); + verifyTypeMsg(message, COMM_OPEN); + Map data = getState(message); + assertThat(data.get(WidgetInfo.MODEL_NAME)).isEqualTo(modelNameValue); + assertThat(data.get(WidgetInfo.VIEW_NAME)).isEqualTo(viewNameValue); + } + + public static void verifyInternalOpenCommMsg(Message message, String modelNameValue, + String viewNameValue) { + verifyTypeMsg(message, COMM_OPEN); + Map data = getState(message); + assertThat(data.get(WidgetInfo.MODEL_NAME)).isEqualTo(modelNameValue); + assertThat(data.get(WidgetInfo.VIEW_NAME)).isEqualTo(viewNameValue); + } + + public static void verifyInternalOpenCommMsgWitLayout(List messages, + String modelNameValue, String viewNameValue) { + verifyInternalOpenCommMsgWitLayout(messages, modelNameValue, viewNameValue, + BeakerxWidgetInfo.MODEL_MODULE_VALUE, BeakerxWidgetInfo.VIEW_MODULE_VALUE); + } + + public static void verifyInternalOpenCommMsgWitLayout(List messages, + String modelNameValue, String viewNameValue, String modelModule, String viewModule) { + Message widget = SearchMessages.getListWidgetsByViewName(messages, viewNameValue).get(0); + Message layout = SearchMessages.getLayoutForWidget(messages, widget); + + verifyTypeMsg(widget, COMM_OPEN); + Map data = getState(widget); + assertThat(data.get(LayoutInfo.LAYOUT)) + .isEqualTo(LayoutInfo.IPY_MODEL + layout.getContent().get(Comm.COMM_ID)); + assertThat(data.get(WidgetInfo.MODEL_NAME)).isEqualTo(modelNameValue); + assertThat(data.get(WidgetInfo.VIEW_NAME)).isEqualTo(viewNameValue); + } + + public static void verifyTypeMsg(Message widget, JupyterMessages jupyterMessages) { + assertThat(widget.getHeader().getType()).isEqualTo(jupyterMessages.getName()); + } + + @SuppressWarnings("unchecked") + public static Map getData(Message message) { + Map content = getContent(message); + return (Map) content.get(Comm.DATA); + } + + public static Map getState(Message message) { + Map content = getContent(message); + Serializable data = content.getOrDefault(Comm.DATA, null); + if (null != data) { + return (Map) ((Map) data).getOrDefault(Comm.STATE, null); + } + return new HashMap(); + } + + public static Map getContent(Message message) { + return message.getContent(); + } + + public static void verifyMsgForProperty(KernelTest kernel, String propertyName, T expected) { + Object actual = getValueForProperty(kernel, propertyName, expected.getClass()); + assertThat(actual).isEqualTo(expected); + } + + public static T getValueForProperty(KernelTest kernel, String propertyName, Class clazz) { + Message message = kernel.getPublishedMessages().get(0); + return getValueForProperty(message, propertyName, clazz); + } + + public static T getValueForProperty(Message message, String propertyName, Class clazz) { + Map data = TestWidgetUtils.getState(message); + assertThat(getMethod(message)).isEqualTo(Comm.UPDATE); + Object o = data.get(propertyName); + return clazz.cast(o); + } + + public static void verifyDisplayMsg(Message message) { + assertThat(getMethod(message)).isEqualTo(DISPLAY); + } + + public static void verifyDisplayMsg(List messages) { + List result = SearchMessages.getListByDataAttr(messages, METHOD, DISPLAY); + assertThat(result.size()).isGreaterThan(0); + assertThat(result.get(0)).isNotNull(); + } + + public static T findValueForProperty(KernelTest kernel, String propertyName, Class clazz) { + List messages = SearchMessages + .getListByDataAttr(kernel.getPublishedMessages(), Comm.METHOD, Comm.UPDATE); + messages = messages.stream().filter(x -> getState(x).containsKey(propertyName)).collect(Collectors.toList()); + assertTrue("No update comm message.", messages.size() > 0); + return getValueForProperty(messages.get(0), propertyName, clazz); + } + + public static Optional getMessageUpdate(KernelTest kernel) { + return getMessageUpdate(kernel.getPublishedMessages()); + } + + public static Optional getMessageUpdate(List messages) { + List list = SearchMessages + .getListByDataAttr(messages, Comm.METHOD, Comm.UPDATE); + assertTrue("No update comm message.", list.size() > 0); + return list.stream().filter(x -> x.getHeader().getType().equals(JupyterMessages.COMM_MSG.getName())).findFirst(); + } + + + public static String getMethod(Message message) { + return (String) ((Map) (message.getContent().get(Comm.DATA))).get(Comm.METHOD); + } + + public static List getOpenMessages(List messages) { + return SearchMessages.getListMessagesByType(messages, JupyterMessages.COMM_OPEN); + } + + public static List stateContains(List messages, String attribute, String text) { + List result = messages.stream() + .filter(message -> { + Map state = TestWidgetUtils.getState(message); + if (state != null) { + Object expected = state.get(attribute); + if (expected != null && expected instanceof String) { + return ((String) expected).contains(text); + } + } + return false; + }) + .collect(Collectors.toList()); + return result; + } + + public static List dataContains(List messages, String attribute) { + List result = messages.stream() + .filter(message -> { + Map data = TestWidgetUtils.getData(message); + if (data != null) { + Object expected = data.get(attribute); + return expected != null; + } + return false; + }) + .collect(Collectors.toList()); + return result; + } + +} diff --git a/base-test/src/main/java/com/twosigma/beakerx/widget/strings/TextFieldChecker.java b/base-test/src/main/java/com/twosigma/beakerx/widget/strings/TextFieldChecker.java new file mode 100644 index 0000000..581738f --- /dev/null +++ b/base-test/src/main/java/com/twosigma/beakerx/widget/strings/TextFieldChecker.java @@ -0,0 +1,55 @@ +/* + * 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.widget.strings; + +import com.twosigma.beakerx.jupyter.SearchMessages; +import com.twosigma.beakerx.kernel.comm.Comm; +import com.twosigma.beakerx.message.Message; + +import java.util.List; +import java.util.Map; + +import static com.twosigma.beakerx.kernel.msg.JupyterMessages.COMM_OPEN; +import static com.twosigma.beakerx.widget.LayoutInfo.IPY_MODEL; +import static com.twosigma.beakerx.widget.LayoutInfo.LAYOUT; +import static com.twosigma.beakerx.widget.TestWidgetUtils.getState; +import static com.twosigma.beakerx.widget.TestWidgetUtils.verifyTypeMsg; +import static com.twosigma.beakerx.widget.WidgetInfo.MODEL_MODULE; +import static com.twosigma.beakerx.widget.WidgetInfo.MODEL_NAME; +import static com.twosigma.beakerx.widget.WidgetInfo.VIEW_MODULE; +import static com.twosigma.beakerx.widget.WidgetInfo.VIEW_NAME; +import static org.assertj.core.api.Assertions.assertThat; + +public class TextFieldChecker { + public static void verifyTextField( + List messages, + String modelNameValue, + String modelModuleValue, + String viewNameValue, + String viewModuleValue + ) { + Message widget = SearchMessages.getListWidgetsByViewName(messages, viewNameValue).get(0); + Message layout = SearchMessages.getLayoutForWidget(messages, widget); + + verifyTypeMsg(widget, COMM_OPEN); + Map data = getState(widget); + assertThat(data.get(LAYOUT)).isEqualTo(IPY_MODEL + layout.getContent().get(Comm.COMM_ID)); + assertThat(data.get(MODEL_NAME)).isEqualTo(modelNameValue); + assertThat(data.get(MODEL_MODULE)).isEqualTo(modelModuleValue); + assertThat(data.get(VIEW_NAME)).isEqualTo(viewNameValue); + assertThat(data.get(VIEW_MODULE)).isEqualTo(viewModuleValue); + } +} diff --git a/base/.gitignore b/base/.gitignore new file mode 100644 index 0000000..efe684f --- /dev/null +++ b/base/.gitignore @@ -0,0 +1,4 @@ +/src/main/resources/build_time +/src/main/resources/hash + +beakerx_inspect.json \ No newline at end of file diff --git a/base/build.gradle b/base/build.gradle new file mode 100644 index 0000000..c0941eb --- /dev/null +++ b/base/build.gradle @@ -0,0 +1,114 @@ +/* + * Copyright 2020 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. + */ +version 'unspecified' + +configurations { + provided +} + +sourceSets { + main { + compileClasspath += configurations.provided + } + test { + compileClasspath += configurations.provided + runtimeClasspath += configurations.provided + } +} + +dependencies { + compile project(':base-api') + provided project(':doclet') + compile group: 'com.opencsv', name: 'opencsv', version: '3.10' + compile group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.6.5' + compile group: 'com.github.jupyter', name: 'jvm-repr', version: '0.3.1' + compile group: 'commons-io', name: 'commons-io', version: '2.5' + compile group: 'commons-cli', name: 'commons-cli', version: '1.2' + compile group: 'org.apache.maven.shared', name: 'maven-invoker', version: '3.0.0' + compile group: 'org.slf4j', name: 'slf4j-log4j12', version: '1.7.25' + compile group: 'org.apache.httpcomponents', name: 'fluent-hc', version: '4.5.5' + compile 'io.javalin:javalin:1.7.0' + + compile group: "org.zeromq", name: "jeromq", version: "0.3.5" + compile group: 'org.apache.ivy', name: 'ivy', version: '2.4.0' + + compile group: 'junit', name: 'junit', version: '4.11' + compile group: 'org.assertj', name: 'assertj-core', version: '3.6.1' + + testCompile group: 'org.reflections', name: 'reflections', version: '0.9.10' + testCompile project(':base-test') +} + +publishing { + publications { + maven(MavenPublication) { + groupId 'com.twosigma' + artifactId 'beakerx-kernel-base' + version "$beakerxVersion" + from components.java + } + } +} + +def gitGetHash() { + def name = "git log --pretty=format:%h -n 1".execute().text.trim() + return name +} + +def resourceDir = file("./src/main/resources") + +def gitGetCommitHash() { + return "git rev-list --tags --max-count=1".execute().text.trim() +} + +def gitGetLatestTagVersion() { + def gitLatestTag = "git describe --tags " + gitGetCommitHash() + "" + return gitLatestTag.execute().text.trim() +} + +def mainDir = file("../../") + +task prepareBuildVersion() { + doLast { + new File(resourceDir, 'version').write(gitGetLatestTagVersion()) + new File(resourceDir, 'hash').write(gitGetHash()) + new File(resourceDir, 'build_time').write(new Date().format("yyyy-MM-dd HH:mm z")) + new File(mainDir, 'VERSION').write(gitGetLatestTagVersion()) + } +} + +compileJava.dependsOn prepareBuildVersion + + +task jvmInspectJavaDoc(type: Javadoc) { + source = sourceSets.main.allJava + classpath = configurations.compile + options.doclet = "com.twosigma.beakerx.doclet.BeakerxDoclet" + options.docletpath = [file("../doclet/build/libs/doclet.jar")] + options.addStringOption("subpackages", "com.twosigma.beakerx") + options.addStringOption("sourcepath", "../base/src/main/java") + options.addStringOption("encoding", "UTF-8") +} + + +task moveInspectJson(type: Copy) { + from("beakerx_inspect.json") + into("build/resources/main") +} + +jvmInspectJavaDoc.finalizedBy moveInspectJson +compileJava.finalizedBy jvmInspectJavaDoc + diff --git a/base/src/main/java/com/twosigma/beakerx/AutotranslationServiceImpl.java b/base/src/main/java/com/twosigma/beakerx/AutotranslationServiceImpl.java new file mode 100644 index 0000000..af89114 --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/AutotranslationServiceImpl.java @@ -0,0 +1,147 @@ +/* + * 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; + +import com.google.gson.Gson; +import org.apache.commons.codec.binary.Base64; +import org.apache.http.client.fluent.Request; +import org.apache.http.entity.ContentType; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.Map; + +import static com.twosigma.beakerx.util.Preconditions.checkNotNull; + +public class AutotranslationServiceImpl implements AutotranslationService { + + public static final String AUTHORIZATION = "Authorization"; + public static final String LOCALHOST = "http://localhost:"; + public static final String AUTOTRANSLTION = "/autotransltion/"; + private final String contextAsString; + private final AutotranslationContext context; + + public static AutotranslationService createAsSubkernel(String configuration) { + return new AutotranslationServiceImpl(configuration); + } + + public static AutotranslationService createAsMainKernel(String id) { + Map context = new HashMap<>(); + context.put("contextId", id); + context.put("port", autotranslationPort()); + Gson gson = new Gson(); + String contextAsString = gson.toJson(context); + return new AutotranslationServiceImpl(contextAsString); + } + + private AutotranslationServiceImpl(String configuration) { + Gson gson = new Gson(); + Map map = gson.fromJson(configuration, Map.class); + String c = (String) map.get("contextId"); + String port = (String) map.get("port"); + this.context = new AutotranslationContext(c, port); + this.contextAsString = configuration; + } + + public String getContextAsString() { + return contextAsString; + } + + @Override + public String update(String name, String json) { + checkNotNull(name, "'name' attribute can not be null."); + checkNotNull(json, "'json' attribute can not be null."); + try { + String reply = Request.Post(LOCALHOST + this.context.getPort() + AUTOTRANSLTION) + .addHeader(AUTHORIZATION, auth()) + .bodyString(createBody(name, json), ContentType.APPLICATION_JSON) + .execute().returnContent().asString(); + if (!reply.equals("ok")) { + throw new RuntimeException(reply); + } + } catch (Exception e) { + throw new RuntimeException(e); + } + return json; + } + + @Override + public String get(String name) { + String valueString = ""; + try { + valueString = Request + .Get(LOCALHOST + this.context.getPort() + AUTOTRANSLTION + this.context.getContextId() + "/" + name) + .addHeader(AUTHORIZATION, auth()) + .execute() + .returnContent() + .asString(); + } catch (IOException e) { + throw new RuntimeException(e); + } + return valueString; + } + + private String createBody(String name, String json) { + Map context = new HashMap<>(); + context.put("name", name); + context.put("json", json); + context.put("sessionId", this.context.getContextId()); + Gson gson = new Gson(); + return gson.toJson(context); + } + + private String auth() { + String authString = getBasic_auth_username() + ":" + getBasic_auth_password(); + return "Basic " + Base64.encodeBase64String(authString.getBytes(StandardCharsets.UTF_8)); + } + + private static String getBasic_auth_username() { + return BEAKERX; + } + + private static String getBasic_auth_password() { + return System.getenv("BEAKERX_AUTOTRANSLATION_PASSWORD"); + } + + private static String autotranslationPort() { + return System.getenv("BEAKERX_AUTOTRANSLATION_PORT"); + } + + @Override + public String close() { + return "ok"; + } + + private static class AutotranslationContext { + private String contextId; + private String port; + + AutotranslationContext(String contextId, String port) { + this.contextId = contextId; + this.port = port; + } + + public String getContextId() { + return contextId; + } + + public String getPort() { + return port; + } + } + +} diff --git a/base/src/main/java/com/twosigma/beakerx/BaseBeakerXJsonSerializer.java b/base/src/main/java/com/twosigma/beakerx/BaseBeakerXJsonSerializer.java new file mode 100644 index 0000000..7bd236e --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/BaseBeakerXJsonSerializer.java @@ -0,0 +1,68 @@ +/* + * 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; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.twosigma.beakerx.jvm.serialization.BeakerObjectConverter; +import com.twosigma.beakerx.table.TableDisplayToJson; + +import java.io.IOException; +import java.io.StringWriter; + +import static com.fasterxml.jackson.databind.SerializationFeature.WRITE_ENUMS_USING_TO_STRING; + +public abstract class BaseBeakerXJsonSerializer implements BeakerXJsonSerializer { + + private final ObjectMapper objectMapper; + private final BeakerObjectConverter serializer; + + public BaseBeakerXJsonSerializer() { + this.objectMapper = new ObjectMapper(); + this.objectMapper.enable(WRITE_ENUMS_USING_TO_STRING); + this.objectMapper.registerModule(TableDisplayToJson.tableDisplayModule()); + this.serializer = createSerializer(); + } + + protected abstract BeakerObjectConverter createSerializer(); + + @Override + public String toJson(Object value) { + StringWriter sw = new StringWriter(); + try { + JsonGenerator jgen = objectMapper.getFactory().createGenerator(sw); + boolean success = serializer.writeObject(value, jgen, true); + jgen.flush(); + sw.flush(); + if (success) { + return sw.toString(); + } else { + return value.toString(); + } + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + @Override + public Object fromJson(String json) { + try { + return serializer.deserialize(objectMapper.readTree(json), objectMapper); + } catch (IOException e) { + throw new RuntimeException(e); + } + } +} diff --git a/base/src/main/java/com/twosigma/beakerx/BeakerImplementationInfo.java b/base/src/main/java/com/twosigma/beakerx/BeakerImplementationInfo.java new file mode 100644 index 0000000..8466736 --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/BeakerImplementationInfo.java @@ -0,0 +1,49 @@ +/* + * Copyright 2017 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; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.net.URISyntaxException; +import java.util.stream.Collectors; + +public class BeakerImplementationInfo { + + public final static String IMPLEMENTATION_VERSION = info(); + + private static String info() { + try { + String version = resource("version"); + String hash = resource("hash"); + String build_time = resource("build_time"); + String info = "BeakerX " + version + "\n"; + info += "%s %s\n" ; + info += "hash " + hash + "\n"; + info += "build time " + build_time; + return info; + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + private static String resource(String name) throws IOException, URISyntaxException { + InputStream resourceAsStream = BeakerImplementationInfo.class.getClassLoader().getResourceAsStream(name); + return new BufferedReader(new InputStreamReader(resourceAsStream)).lines().collect(Collectors.joining("\n")); + } + +} diff --git a/base/src/main/java/com/twosigma/beakerx/BeakerXCommRepository.java b/base/src/main/java/com/twosigma/beakerx/BeakerXCommRepository.java new file mode 100644 index 0000000..1f52a65 --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/BeakerXCommRepository.java @@ -0,0 +1,89 @@ +/* + * 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; + +import com.twosigma.beakerx.kernel.comm.BxComm; +import com.twosigma.beakerx.kernel.comm.Comm; +import com.twosigma.beakerx.kernel.comm.TargetNamesEnum; + +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Stream; + +public class BeakerXCommRepository implements CommRepository { + + private Map commMap; + private Comm autotranslationComm; + + public BeakerXCommRepository() { + this.commMap = new ConcurrentHashMap<>(); + } + + @Override + public Comm getOrCreateAutotranslationComm() { + if (autotranslationComm == null) { + autotranslationComm = new BxComm(TargetNamesEnum.BEAKER_AUTOTRANSLATION); + autotranslationComm.open(); + } + return autotranslationComm; + } + + @Override + public Comm getCommByTargetName(String targetName) { + Stream> entryStream = commMap.entrySet().stream().filter(x -> x.getValue().getTargetName().equals(targetName)); + Optional> first = entryStream.findFirst(); + if (first.isPresent()) { + return first.get().getValue(); + } + return null; + } + + @Override + public void closeComms() { + this.commMap.values().forEach(Comm::close); + if (autotranslationComm != null) { + autotranslationComm.close(); + autotranslationComm = null; + } + } + + public synchronized boolean isCommPresent(String hash) { + return commMap.containsKey(hash); + } + + public Set getCommHashSet() { + return commMap.keySet(); + } + + public synchronized void addComm(String hash, Comm commObject) { + if (!isCommPresent(hash)) { + commMap.put(hash, commObject); + } + } + + public synchronized Comm getComm(String hash) { + return commMap.get(hash != null ? hash : ""); + } + + public synchronized void removeComm(String hash) { + if (hash != null && isCommPresent(hash)) { + commMap.remove(hash); + } + } + +} diff --git a/base/src/main/java/com/twosigma/beakerx/BeakerXJsonSerializer.java b/base/src/main/java/com/twosigma/beakerx/BeakerXJsonSerializer.java new file mode 100644 index 0000000..3fcec47 --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/BeakerXJsonSerializer.java @@ -0,0 +1,24 @@ +/* + * 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; + +public interface BeakerXJsonSerializer { + + String toJson(Object value); + + Object fromJson(String json); + +} diff --git a/base/src/main/java/com/twosigma/beakerx/BeakerxDefaultDisplayers.java b/base/src/main/java/com/twosigma/beakerx/BeakerxDefaultDisplayers.java new file mode 100644 index 0000000..820a952 --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/BeakerxDefaultDisplayers.java @@ -0,0 +1,73 @@ +/* + * Copyright 2017 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; + +import com.twosigma.beakerx.mimetype.MIMEContainer; +import com.twosigma.beakerx.util.Images; +import jupyter.Displayer; +import jupyter.Displayers; + +import java.awt.image.RenderedImage; +import java.io.IOException; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.Base64; +import java.util.HashMap; +import java.util.Map; + +public class BeakerxDefaultDisplayers { + + + public static void registerDefaults() { + registerCodeCellDisplayer(); + registerImageDisplayer(); + } + + private static void registerCodeCellDisplayer() { + Displayers.register(CodeCell.class, new Displayer() { + @Override + public Map display(CodeCell value) { + return new HashMap() {{ + StringBuilder sb = new StringBuilder("Cell Type:" + (value).getCellType()).append(System.getProperty("line.separator")); + sb.append("Execution Count:").append((value).getExecutionCount()).append(System.getProperty("line.separator")); + sb.append("Metadata:").append((value).getMetadata()).append(System.getProperty("line.separator")); + sb.append("Source:").append((value).getSource()); + put(MIMEContainer.MIME.TEXT_PLAIN, sb.toString()); + }}; + } + }); + } + + private static void registerImageDisplayer() { + Displayers.register(RenderedImage.class, new Displayer() { + @Override + public Map display(RenderedImage value) { + return new HashMap() {{ + try { + byte[] data = Images.encode(value); + String base64 = Base64.getEncoder().encodeToString(data); + put(MIMEContainer.MIME.IMAGE_PNG, base64); + } + catch (IOException exc) { + StringWriter sw = new StringWriter(); + exc.printStackTrace(new PrintWriter(sw)); + put(MIMEContainer.MIME.TEXT_HTML, "
" + sw.toString() + "
"); + } + }}; + } + }); + } +} diff --git a/base/src/main/java/com/twosigma/beakerx/BeakerxDirvers.java b/base/src/main/java/com/twosigma/beakerx/BeakerxDirvers.java new file mode 100644 index 0000000..510a8fc --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/BeakerxDirvers.java @@ -0,0 +1,34 @@ +/* + * 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; + +import java.sql.Driver; +import java.util.Iterator; +import java.util.ServiceLoader; + +public class BeakerxDirvers { + + public static void loadDrivers() { + ServiceLoader loadedDrivers = ServiceLoader.load(Driver.class); + Iterator driversIterator = loadedDrivers.iterator(); + try { + while (driversIterator.hasNext()) { + driversIterator.next(); + } + } catch (Throwable t) { + } + } +} diff --git a/base/src/main/java/com/twosigma/beakerx/CommRepository.java b/base/src/main/java/com/twosigma/beakerx/CommRepository.java new file mode 100644 index 0000000..2a2ad28 --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/CommRepository.java @@ -0,0 +1,39 @@ +/* + * 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; + +import com.twosigma.beakerx.kernel.comm.Comm; + +import java.util.Set; + +public interface CommRepository { + + Comm getCommByTargetName(String targetName); + + Comm getOrCreateAutotranslationComm(); + + void closeComms(); + + Set getCommHashSet(); + + void addComm(String hash, Comm commObject); + + Comm getComm(String hash); + + void removeComm(String hash); + + boolean isCommPresent(String hash); +} diff --git a/base/src/main/java/com/twosigma/beakerx/DefaultBeakerXJsonSerializer.java b/base/src/main/java/com/twosigma/beakerx/DefaultBeakerXJsonSerializer.java new file mode 100644 index 0000000..f64221f --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/DefaultBeakerXJsonSerializer.java @@ -0,0 +1,32 @@ +/* + * 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; + +import com.twosigma.beakerx.jvm.serialization.BasicObjectSerializer; +import com.twosigma.beakerx.jvm.serialization.BeakerObjectConverter; +import com.twosigma.beakerx.table.serializer.AutotranslationDefaultDeserializer; +import com.twosigma.beakerx.table.serializer.TableDisplayDeSerializer; + +public class DefaultBeakerXJsonSerializer extends BaseBeakerXJsonSerializer { + + @Override + protected BeakerObjectConverter createSerializer() { + BasicObjectSerializer serializer = new BasicObjectSerializer(); + serializer.addTypeDeserializer(new TableDisplayDeSerializer(serializer)); + serializer.addTypeDeserializer(new AutotranslationDefaultDeserializer()); + return serializer; + } +} diff --git a/base/src/main/java/com/twosigma/beakerx/Display.java b/base/src/main/java/com/twosigma/beakerx/Display.java new file mode 100644 index 0000000..cf452eb --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/Display.java @@ -0,0 +1,55 @@ +/* + * 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; + +import com.twosigma.beakerx.mimetype.MIMEContainer; +import com.twosigma.beakerx.widget.MIMEDisplayMethodManager; + +import java.util.List; +import java.util.stream.Collectors; + +public class Display { + + private static Display instance = new Display(MIMEDisplayMethodManager.getInstance()); + + private MIMEDisplayMethodManager mimeDisplayMethodManager; + + private Display(MIMEDisplayMethodManager mimeDisplayMethodManager) { + this.mimeDisplayMethodManager = mimeDisplayMethodManager; + } + + public static void display(Object value) { + instance.displayObject(value); + } + + private void displayObject(Object value) { + List result = getNotHiddenMIMEContainers(value); + if (!result.isEmpty()) { + mimeDisplayMethodManager.display(result); + } + } + + private List getNotHiddenMIMEContainers(Object value) { + List containers = MIMEContainerFactory.createMIMEContainers(value); + return containers.stream() + .filter(x -> !x.getMime().asString().equals(MIMEContainer.MIME.HIDDEN)).collect(Collectors.toList()); + } + + public interface MIMEContainerDisplayMethodStrategy { + void display(List mimeContainers); + } + +} diff --git a/base/src/main/java/com/twosigma/beakerx/DisplayerDataMapper.java b/base/src/main/java/com/twosigma/beakerx/DisplayerDataMapper.java new file mode 100644 index 0000000..3b49a3a --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/DisplayerDataMapper.java @@ -0,0 +1,49 @@ +/* + * Copyright 2017 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; + +public class DisplayerDataMapper { + + private static Converter none = data -> data; + private static DisplayerDataMapper INSTANCE = new DisplayerDataMapper(); + + private Converter converter; + + private DisplayerDataMapper() { + this.converter = none; + } + + public static void register(Converter converter) { + INSTANCE.converter = converter; + } + + static Object convert(Object data) { + try { + return INSTANCE.converter.convert(data); + } catch (Exception e) { + return data; + } + } + + public static void init() { + INSTANCE.converter = none; + } + + @FunctionalInterface + public interface Converter { + Object convert(Object data) throws Exception; + } +} diff --git a/base/src/main/java/com/twosigma/beakerx/KernelInfoHandler.java b/base/src/main/java/com/twosigma/beakerx/KernelInfoHandler.java new file mode 100644 index 0000000..7607280 --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/KernelInfoHandler.java @@ -0,0 +1,107 @@ +/* + * Copyright 2017 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; + +import static com.twosigma.beakerx.kernel.msg.JupyterMessages.KERNEL_INFO_REPLY; +import static com.twosigma.beakerx.handler.KernelHandlerWrapper.wrapBusyIdle; +import static java.util.Arrays.asList; + +import com.twosigma.beakerx.kernel.KernelFunctionality; +import com.twosigma.beakerx.handler.KernelHandler; +import com.twosigma.beakerx.kernel.KernelManager; +import com.twosigma.beakerx.message.Header; +import com.twosigma.beakerx.message.Message; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.HashMap; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public abstract class KernelInfoHandler extends KernelHandler { + + private final static Logger logger = LoggerFactory.getLogger(KernelInfoHandler.class); + public static final String PROTOCOL_VERSION = "protocol_version"; + public static final String PROTOCOL_VERSION_NUMBER = "5.3"; + public static final String INTERRUPT_KERNEL = "interrupt_kernel"; + + public KernelInfoHandler(KernelFunctionality kernel) { + super(kernel); + } + + @Override + public void handle(Message message) { + wrapBusyIdle(kernel, message, () -> handleMsg(message)); + } + + private void handleMsg(Message message) { + logger.debug("Processing kernel info request"); + Message reply = new Message(new Header(KERNEL_INFO_REPLY, message.getHeader().getSession())); + reply.setContent(content()); + reply.setParentHeader(message.getHeader()); + reply.setIdentities(message.getIdentities()); + send(reply); + } + + private HashMap languageInfo() { + HashMap map = new HashMap<>(); + return doLanguageInfo(map); + } + + private HashMap content() { + HashMap map = new HashMap<>(); + map.put("implementation_version", BeakerImplementationInfo.IMPLEMENTATION_VERSION); + map.put(PROTOCOL_VERSION, PROTOCOL_VERSION_NUMBER); + map.put("language_info", languageInfo()); + map.put("help_links", getHelpLinks()); + map.put("beakerx", true); + map.put("status", "ok"); + map.put("url_to_interrupt", KernelManager.get().getBeakerXServer().getURL() + INTERRUPT_KERNEL); + return doContent(map); + } + + private ArrayList getHelpLinks() { + HelpLink beakerXHome = new HelpLink("BeakerX Home", "http://BeakerX.com"); + HelpLink fileAnIssue = new HelpLink("File an Issue", "https://github.com/twosigma/beakerx/issues/new"); + HelpLink twoSigmaOpenSource = new HelpLink("Two Sigma Open Source", "http://opensource.twosigma.com/"); + HelpLink javadoc = new HelpLink("BeakerX JavaDoc", "javadoc/index.html"); + + return new ArrayList<>(asList(beakerXHome, fileAnIssue, twoSigmaOpenSource, javadoc)); + } + + protected abstract HashMap doLanguageInfo(HashMap languageInfo); + + protected abstract HashMap doContent(HashMap content); + + private class HelpLink implements Serializable { + protected String text; + protected String url; + + HelpLink(String text, String url) { + this.text = text; + this.url = url; + } + + public String getText() { + return text; + } + + public String getUrl() { + return url; + } + } +} diff --git a/base/src/main/java/com/twosigma/beakerx/MIMEContainerFactory.java b/base/src/main/java/com/twosigma/beakerx/MIMEContainerFactory.java new file mode 100644 index 0000000..447f866 --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/MIMEContainerFactory.java @@ -0,0 +1,129 @@ +/* + * Copyright 2017 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; + +import com.twosigma.beakerx.chart.xychart.Plot; +import com.twosigma.beakerx.chart.xychart.plotitem.XYGraphics; +import com.twosigma.beakerx.kernel.Kernel; +import com.twosigma.beakerx.mimetype.MIMEContainer; +import com.twosigma.beakerx.table.TableDisplay; +import com.twosigma.beakerx.widget.DisplayableWidget; +import jupyter.Displayers; + +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import static com.twosigma.beakerx.mimetype.MIMEContainer.HIDDEN; +import static com.twosigma.beakerx.mimetype.MIMEContainer.Text; +import static java.util.Collections.singletonList; + + +public class MIMEContainerFactory { + + private static List HIDDEN_MIME = singletonList(HIDDEN); + + public static List createMIMEContainers(final Object input) { + if (input == null) { + return getMimeContainerForNull(); + } + return createMIMEContainersFromObject(input); + } + + public static List getMimeContainerForNull() { + if (Kernel.showNullExecutionResult) { + return singletonList(Text("null")); + } + + return HIDDEN_MIME; + } + + private static List createMIMEContainersFromObject(final Object data) { + + Object input = DisplayerDataMapper.convert(data); + + if (input instanceof DisplayableWidget) { + ((DisplayableWidget) input).display(); + return HIDDEN_MIME; + } + + TableDisplay table = getTableDisplay(input); + if (table != null) { + table.display(); + return HIDDEN_MIME; + } + + if (input instanceof Collection) { + return singletonList(MIMEContainer.Text(collectionToString((Collection) input))); + } + + if (input instanceof XYGraphics) { + new Plot().add((XYGraphics) input).display(); + return HIDDEN_MIME; + } + if (input instanceof MIMEContainer) { + return singletonList((MIMEContainer) input); + } + + return Displayers.display(input).entrySet().stream(). + map(item -> new MIMEContainer(item.getKey(), item.getValue())). + collect(Collectors.toList()); + } + + public static TableDisplay getTableDisplay(final Object input) { + TableDisplay ret = null; + if (input instanceof Map) { + Map map = (Map) input; + ret = new TableDisplay(map); + } else if (input instanceof Collection) { + Collection items = (Collection) input; + if (!items.isEmpty()) { + Object item = items.iterator().next(); + if (item instanceof Map) { + if (((Map) item).keySet().stream().allMatch(o -> o instanceof String)) { + ret = new TableDisplay(items); + } + } + } + } else if (input instanceof Map[]) { + Map[] items = (Map[]) input; + if (items.length > 0) { + ret = new TableDisplay(items); + } + } + return ret; + } + + private static String collectionToString(Collection collection) { + Iterator it = collection.iterator(); + if (!it.hasNext()) + return "[]"; + + StringBuilder sb = new StringBuilder(); + sb.append('['); + for (; ; ) { + E e = it.next(); + sb.append(e); + if (!it.hasNext()) + return sb.append(']').toString(); + sb.append(',').append(' '); + } + } + +} diff --git a/base/src/main/java/com/twosigma/beakerx/NamespaceClient.java b/base/src/main/java/com/twosigma/beakerx/NamespaceClient.java new file mode 100644 index 0000000..278c0a1 --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/NamespaceClient.java @@ -0,0 +1,228 @@ +/* + * Copyright 2017 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; + +import com.twosigma.beakerx.evaluator.InternalVariable; +import com.twosigma.beakerx.jvm.object.EvaluationObject; +import com.twosigma.beakerx.kernel.ConfigurationFile; +import com.twosigma.beakerx.kernel.KernelManager; +import com.twosigma.beakerx.kernel.comm.Buffer; +import com.twosigma.beakerx.kernel.comm.BxComm; +import com.twosigma.beakerx.kernel.comm.Comm; +import com.twosigma.beakerx.kernel.comm.Data; +import com.twosigma.beakerx.kernel.comm.TargetNamesEnum; + +import java.io.Serializable; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.SynchronousQueue; + +import static com.twosigma.beakerx.kernel.msg.JupyterMessages.COMM_MSG; + +public class NamespaceClient implements BeakerXClient { + + public static final String NAMESPACE_CLIENT = NamespaceClient.class.getSimpleName() + ".getBeakerX()"; + + private static Map> messagePool = new HashMap<>(); + private Comm codeCellsComm = null; + private Comm tagRunComm = null; + private AutotranslationService autotranslationService; + private BeakerXJsonSerializer beakerXJsonSerializer; + private CommRepository commRepository; + private Comm urlArgComm; + + public NamespaceClient(AutotranslationService autotranslationService, BeakerXJsonSerializer beakerXJsonSerializer, CommRepository commRepository) { + this.autotranslationService = autotranslationService; + this.beakerXJsonSerializer = beakerXJsonSerializer; + this.commRepository = commRepository; + } + + public static BeakerXClient getBeakerX() { + return BeakerXClientManager.get(); + } + + @Override + public void showProgressUpdate(String message, int progress) { + EvaluationObject seo = InternalVariable.getSimpleEvaluationObject(); + seo.structuredUpdate(message, progress); + } + + @Override + public void delBeaker() { + autotranslationService.close(); + } + + @Override + public Object get(final String name) { + String json = autotranslationService.get(name); + if ("undefined".equals(json)) { + throw new RuntimeException("name '" + name + "' is not defined on the beakerx object"); + } + return beakerXJsonSerializer.fromJson(json); + } + + @Override + public String update(String name, Object value) { + try { + String json = getJson(value); + autotranslationService.update(name, json); + return json; + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @Override + public Object set(String name, Object value) { + String json = update(name, value); + try { + Comm c = commRepository.getOrCreateAutotranslationComm(); + HashMap data = new HashMap<>(); + HashMap state = new HashMap<>(); + state.put("name", name); + state.put("value", json); + state.put("sync", true); + data.put("state", state); + data.put("buffer_paths", new HashMap<>()); + c.send(COMM_MSG, Buffer.EMPTY, new Data(data)); + return value; + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + private String getJson(Object value) { + return beakerXJsonSerializer.toJson(value); + } + + //TODO : Not Implemented + public Object setFast(String name, Object value) { + 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"); + } + + @Override + public SynchronousQueue getMessageQueue(String channel) { + SynchronousQueue result = messagePool.get(channel); + if (result == null) { + result = new SynchronousQueue(); + messagePool.put(channel, result); + } + return result; + } + + private Comm getCodeCellsComm() { + if (codeCellsComm == null) { + codeCellsComm = new BxComm(TargetNamesEnum.BEAKER_GETCODECELLS); + codeCellsComm.open(); + } + return codeCellsComm; + } + + private Comm getTagRunComm() { + if (tagRunComm == null) { + tagRunComm = new BxComm(TargetNamesEnum.BEAKER_TAG_RUN); + tagRunComm.open(); + } + return tagRunComm; + } + + @Override + public List getCodeCells(String tagFilter) { + // first send message to get cells + try { + Comm c = getCodeCellsComm(); + HashMap data = new HashMap<>(); + HashMap state = new HashMap<>(); + state.put("name", "CodeCells"); + state.put("value", getJson(tagFilter)); + data.put("url", KernelManager.get().getBeakerXServer().getURL() + CODE_CELL_PATH); + data.put("state", state); + data.put("buffer_paths", new HashMap<>()); + c.send(COMM_MSG, Buffer.EMPTY, new Data(data)); + // block + Object cells = getMessageQueue("CodeCells").take(); + return (List) cells; + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @Override + public void runByTag(String tag) { + Comm c = getTagRunComm(); + HashMap data = new HashMap<>(); + HashMap state = new HashMap<>(); + state.put("runByTag", tag); + data.put("state", state); + data.put("buffer_paths", new HashMap<>()); + c.send(COMM_MSG, Buffer.EMPTY, new Data(data)); + } + + @Override + public String getContext() { + return this.autotranslationService.getContextAsString(); + } + + public static NamespaceClient create(String id, ConfigurationFile configurationFile, CommRepository commRepository) { + return create(id, configurationFile, new DefaultBeakerXJsonSerializer(), commRepository); + } + + public static NamespaceClient create(String id, + ConfigurationFile configurationFile, + BeakerXJsonSerializer serializer, + CommRepository commRepository) { + if (configurationFile.getContext().isPresent()) { + return new NamespaceClient(AutotranslationServiceImpl.createAsSubkernel(configurationFile.getContext().get()), serializer, commRepository); + } else { + return new NamespaceClient(AutotranslationServiceImpl.createAsMainKernel(id), serializer, commRepository); + } + } + + @Override + public String urlArg(String argName) { + try { + Comm c = getUrlArgComm(); + HashMap data = new HashMap<>(); + HashMap state = new HashMap<>(); + state.put("name", "URL_ARG"); + state.put("arg_name", argName); + data.put("url", KernelManager.get().getBeakerXServer().getURL() + URL_ARG); + data.put("type", "rest"); + data.put("state", state); + data.put("buffer_paths", new HashMap<>()); + c.send(COMM_MSG, Buffer.EMPTY, new Data(data)); + // block + Object argNameValue = getMessageQueue(URL_ARG).take(); + return (String) argNameValue; + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + private Comm getUrlArgComm() { + if (urlArgComm == null) { + urlArgComm = new BxComm(TargetNamesEnum.BEAKER_GET_URL_ARG); + urlArgComm.open(); + } + return urlArgComm; + } +} \ No newline at end of file diff --git a/base/src/main/java/com/twosigma/beakerx/autocomplete/AutocompleteCandidate.java b/base/src/main/java/com/twosigma/beakerx/autocomplete/AutocompleteCandidate.java new file mode 100644 index 0000000..1264693 --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/autocomplete/AutocompleteCandidate.java @@ -0,0 +1,118 @@ +/* + * Copyright 2014 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.autocomplete; + +import java.util.ArrayList; +import java.util.List; + +public class AutocompleteCandidate { + + public static final String EMPTY_NODE = ""; + + private int type; + private String key; + private List children; + + public AutocompleteCandidate(int t, String k) { + type = t; + key = k; + } + + public AutocompleteCandidate(int t, String [] k) { + type = t; + key = k[0]; + AutocompleteCandidate p = this; + for(int i=1; i(); + + for (AutocompleteCandidate c1 : children) { + if(c1.getKey().equals(a.getKey())) { + c1.addChildrens(a.getChildrens()); + return; + } + } + children.add(a); + } + + public int getType() { return type; } + public String getKey() { return key; } + public boolean hasChildren() { return children!=null && children.size()>0; } + + public List getChildrens() { return children; } + + public void addChildrens(List chs) { + if(chs==null) return; + for(AutocompleteCandidate c : chs) { + addChildren(c); + } + } + + public void searchCandidates(List ret, AutocompleteCandidate a) { + if(a.hasChildren()) { + if(!key.equals(a.getKey())) + return; + if(children!=null) { + for (AutocompleteCandidate c1 : children) { + c1.searchCandidates(ret, a.getChildrens().get(0)); + } + } + return; + } + if(key.startsWith(a.key) && !ret.contains(key)) + ret.add(key); + + if(a.getKey()!= EMPTY_NODE && children!=null) { + for (AutocompleteCandidate c1 : children) { + c1.searchCandidates(ret, a); + } + } + } + + public AutocompleteCandidate findLeaf() { + if(children!=null && children.size()>0) + return children.get(0).findLeaf(); + return this; + } +} diff --git a/base/src/main/java/com/twosigma/beakerx/autocomplete/AutocompleteClasspathScanner.java b/base/src/main/java/com/twosigma/beakerx/autocomplete/AutocompleteClasspathScanner.java new file mode 100644 index 0000000..31dd387 --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/autocomplete/AutocompleteClasspathScanner.java @@ -0,0 +1,186 @@ +/* + * Copyright 2014 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.autocomplete; + +import org.apache.commons.lang3.StringUtils; + +import java.io.File; +import java.io.IOException; +import java.io.UncheckedIOException; +import java.lang.module.ModuleReader; +import java.lang.module.ResolvedModule; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; +import java.util.jar.Manifest; + +public class AutocompleteClasspathScanner { + protected Map> packages; + + public AutocompleteClasspathScanner() { + packages = new HashMap>(); + String classpath = System.getProperty("java.class.path"); + scanClassesFromClasspath(classpath); + scanClassesFromModulePath(); + } + + public AutocompleteClasspathScanner(String classpath) { + packages = new HashMap>(); + scanClassesFromClasspath(classpath); + scanClassesFromModulePath(); + } + + private void scanClassesFromModulePath() { + ModuleLayer.boot().configuration().modules().stream() + .map(ResolvedModule::reference) + .forEach(mref -> { + try (ModuleReader reader = mref.open()) { + reader.list().forEach( x -> addClass(x)); + } catch (IOException ioe) { + throw new UncheckedIOException(ioe); + } + }); + } + + public Set getPackages() { return packages.keySet(); } + public List getClasses(String p) { if(packages.containsKey(p)) return packages.get(p); return null; } + + private void scanClassesFromClasspath(String classpath) { + String[] paths = classpath.split(System.getProperty("path.separator")); + + String javaHome = System.getProperty("java.home"); + File file = new File(javaHome + File.separator + "lib"); + if (file.exists()) { + findClasses(file, file, true); + } + + for (String path : paths) { + file = new File(path); + if (file.exists()) { + findClasses(file, file, true); + } + } + } + + private boolean findClasses(File root, File file, boolean includeJars) { + if (file!=null && file.isDirectory()) { + File[] lf = file.listFiles(); + if (lf != null) + for (File child : lf) { + if (!findClasses(root, child, includeJars)) { + return false; + } + } + } else { + if (file.getName().toLowerCase().endsWith(".jar") && includeJars) { + JarFile jar = null; + try { + jar = new JarFile(file); + } catch (Exception ex) { + } + if (jar != null) { + try { + Manifest mf = jar.getManifest(); + if(mf != null){ + String cp = mf.getMainAttributes().getValue("Class-Path"); + if (StringUtils.isNotEmpty(cp)) { + for (String fn : cp.split(" ")) { + if (!fn.equals(".")) { + File child = new File(file.getParent() + System.getProperty("file.separator") + fn); + if (child.getAbsolutePath().equals(jar.getName())) { + continue; //skip bad jars, that contain references to themselves in MANIFEST.MF + } + if (child.exists()) { + if (!findClasses(root, child, includeJars)) { + return false; + } + } + } + } + } + } + }catch (IOException e){ + } + + Enumeration entries = jar.entries(); + while (entries.hasMoreElements()) { + JarEntry entry = entries.nextElement(); + String name = entry.getName(); + addClass(name); + } + } + } + else if (file.getName().toLowerCase().endsWith(".class")) { + String cname = createClassName(root, file); + if(!cname.contains("$")) { + int pIndex = cname.lastIndexOf('.'); + if(pIndex > 0) { + String pname = cname.substring(0, pIndex+1); + cname = cname.substring(pIndex); + if(!packages.containsKey(pname)) + packages.put(pname, new ArrayList()); + packages.get(pname).add(cname); + } + } + } else { + examineFile(root,file); + } + } + + return true; + } + + private void addClass(String name) { + int extIndex = name.lastIndexOf(".class"); + if (extIndex > 0 && !name.contains("$")) { + String cname = name.substring(0, extIndex).replace("/", "."); + int pIndex = cname.lastIndexOf('.'); + if(pIndex > 0) { + String pname = cname.substring(0, pIndex); + cname = cname.substring(pIndex+1); + if(!packages.containsKey(pname)) + packages.put(pname, new ArrayList()); + packages.get(pname).add(cname); + } + } + } + + /* + * extension hook for languages that generate classes on the fly + */ + protected void examineFile(File root, File file) { + + } + + private String createClassName(File root, File file) { + StringBuffer sb = new StringBuffer(); + String fileName = file.getName(); + sb.append(fileName.substring(0, fileName.lastIndexOf(".class"))); + file = file.getParentFile(); + while (file != null && !file.equals(root)) { + sb.insert(0, '.').insert(0, file.getName()); + file = file.getParentFile(); + } + return sb.toString(); + } + +} diff --git a/base/src/main/java/com/twosigma/beakerx/autocomplete/AutocompleteRegistry.java b/base/src/main/java/com/twosigma/beakerx/autocomplete/AutocompleteRegistry.java new file mode 100644 index 0000000..f286b05 --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/autocomplete/AutocompleteRegistry.java @@ -0,0 +1,67 @@ +/* + * Copyright 2014 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.autocomplete; + +import java.util.ArrayList; +import java.util.List; + +public class AutocompleteRegistry { + class AutocompleteRegistryForType { + private List children; + + AutocompleteRegistryForType() { + children = new ArrayList<>(); + } + + void add(AutocompleteCandidate c) { + for (AutocompleteCandidate c1 : children) { + if (c1.getKey().equals(c.getKey())) { + c1.addChildrens(c.getChildrens()); + return; + } + } + children.add(c); + } + + void searchCandidates(List ret, AutocompleteCandidate a) { + for (AutocompleteCandidate c1 : children) { + c1.searchCandidates(ret, a); + } + } + } + + private AutocompleteRegistryForType[] registry; + + public AutocompleteRegistry(int numt) { + registry = new AutocompleteRegistryForType[numt]; + for (int i = 0; i < numt; i++) + registry[i] = new AutocompleteRegistryForType(); + } + + public void addCandidate(AutocompleteCandidate c) { + registry[c.getType()].add(c); + } + + public List searchCandidates(List cands) { + List ret = new ArrayList<>(); + for (AutocompleteCandidate a : cands) { + if (a != null) + registry[a.getType()].searchCandidates(ret, a); + } + return ret; + } +} \ No newline at end of file diff --git a/base/src/main/java/com/twosigma/beakerx/autocomplete/AutocompleteService.java b/base/src/main/java/com/twosigma/beakerx/autocomplete/AutocompleteService.java new file mode 100644 index 0000000..056a3ff --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/autocomplete/AutocompleteService.java @@ -0,0 +1,22 @@ +/* + * 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.autocomplete; + +public interface AutocompleteService { + + AutocompleteResult find(String txt, int cur); + +} diff --git a/base/src/main/java/com/twosigma/beakerx/autocomplete/AutocompleteServiceBeakerx.java b/base/src/main/java/com/twosigma/beakerx/autocomplete/AutocompleteServiceBeakerx.java new file mode 100644 index 0000000..c7f62b9 --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/autocomplete/AutocompleteServiceBeakerx.java @@ -0,0 +1,84 @@ +/* + * 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.autocomplete; + +import com.twosigma.beakerx.kernel.magic.command.functionality.MagicCommandUtils; +import org.jetbrains.annotations.NotNull; + +import java.util.Collection; +import java.util.LinkedList; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +import static com.twosigma.beakerx.util.Preconditions.checkNotNull; +import static java.util.Arrays.asList; + +public abstract class AutocompleteServiceBeakerx implements AutocompleteService { + + private static final String LAST_SPACE = " "; + private MagicCommandAutocompletePatterns magicPatterns; + + public AutocompleteServiceBeakerx(MagicCommandAutocompletePatterns magicCommandAutocompletePatterns) { + this.magicPatterns = checkNotNull(magicCommandAutocompletePatterns); + } + + @Override + public AutocompleteResult find(String txt, int cur) { + String expression = txt.substring(0, cur); + LinkedList parts = new LinkedList<>(asList(MagicCommandUtils.splitPath(expression))); + Optional result; + if (expression.endsWith(LAST_SPACE)) { + result = findNextWord(txt, parts, cur); + } else { + result = matchToTheWord(txt, parts, expression); + } + return result.orElseGet(() -> doAutocomplete(txt, cur)); + } + + private Optional findNextWord(String text, LinkedList parts, int cur) { + String first = parts.removeFirst(); + Optional node = magicPatterns.get(first); + return node.flatMap(x -> x.findNextWord(text, parts)); + } + + private Optional matchToTheWord(String text, LinkedList parts, String txt) { + if (parts.size() == 1) { + List collect = findMatches(magicPatterns.values(), txt); + if (collect.isEmpty()) { + return Optional.empty(); + } + return Optional.of(new AutocompleteResult(collect.stream().map(AutocompleteNode::getName).collect(Collectors.toList()), 0)); + } else if (parts.size() > 1) { + String last = parts.removeLast(); + String first = parts.removeFirst(); + Optional node = magicPatterns.get(first); + return node.flatMap(x -> x.matchToTheWord(text, parts, last)); + } + return Optional.empty(); + } + + @NotNull + private List findMatches(Collection nodes, String txt) { + return nodes.stream() + .filter(x -> x.getName().startsWith(txt)) + .filter(x -> !x.getName().equals(txt)) + .collect(Collectors.toList()); + } + + protected abstract AutocompleteResult doAutocomplete(String txt, int cur); + +} diff --git a/base/src/main/java/com/twosigma/beakerx/autocomplete/ClassUtils.java b/base/src/main/java/com/twosigma/beakerx/autocomplete/ClassUtils.java new file mode 100644 index 0000000..07abb1f --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/autocomplete/ClassUtils.java @@ -0,0 +1,216 @@ +/* + * Copyright 2014 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.autocomplete; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.HashMap; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + + +public class ClassUtils { + + protected ClassLoader loader; + private Map typeMap; + private Map classToTypeMap; + + public final static int DO_STATIC = 0; + public final static int DO_NON_STATIC = 1; + public final static int DO_ALL = 2; + + private final static ModifierValidator classModifierValidator = (type, modifiers) -> (Modifier.isStatic(modifiers) && (type != DO_NON_STATIC)); + private final static ModifierValidator variableModifierValidator = (type, modifiers) -> classModifierValidator.validate(type, modifiers) || (!Modifier.isStatic(modifiers) && (type != DO_STATIC)); + + + public ClassUtils(ClassLoader l) { + loader = l; + typeMap = new HashMap(); + classToTypeMap = new HashMap(); + } + + public ClassUtils() { + loader = null; + typeMap = new HashMap(); + classToTypeMap = new HashMap(); + } + + public void clear() { + typeMap.clear(); + classToTypeMap.clear(); + } + + public void defineVariable(String name, String type) { + typeMap.put(groovyVariableNameGenericParserProblems(name), type); + } + + private String groovyVariableNameGenericParserProblems(String name) { + if (name.contains(">")) { + return name.substring(name.indexOf(">") + 1, name.length()); + } + return name; + } + + public String getVariableType(String name) { + return typeMap.get(name); + } + + public void defineClassShortName(String name, String fqname) { + classToTypeMap.put(name, fqname); + } + + protected Class getClass(String name) throws ClassNotFoundException { + try { + if (loader != null) return loader.loadClass(name); + return Class.forName(name); + } catch (Exception e) { + return null; + } + } + + public AutocompleteCandidate expandExpression(String txt, AutocompleteRegistry registry, int type) { + if (!txt.contains(".")) + return null; + + boolean endsWithDot = txt.endsWith("."); + + Pattern p = Pattern.compile("((?:[a-zA-Z$_][a-zA-Z0-9$_]*(?:\\(.*\\))?\\.\\s*)+)$"); + Matcher m; + if (!endsWithDot) + m = p.matcher(txt.substring(0, txt.lastIndexOf('.') + 1)); + else + m = p.matcher(txt); + + if (m.find()) { + try { + //System.out.println("using "+m.group(0)); + String[] v = m.group(0).split("\\."); + String curtype; + String n = v[0].trim(); + // find starting type + ModifierValidator modifierValidator; + if (typeMap.containsKey(n)) { + curtype = typeMap.get(n); + modifierValidator = variableModifierValidator; + } else { + curtype = n; + modifierValidator = classModifierValidator; + } + + // decode starting type + if (classToTypeMap.containsKey(curtype)) + curtype = classToTypeMap.get(curtype); + + for (int i = 1; i < v.length; i++) { + modifierValidator = variableModifierValidator; + // get next field type + String field = v[i]; + //System.out.println("looking up "+field); + String ntype = null; + Class cl = getClass(curtype); + if (cl == null) { + //System.out.println("not found "+curtype); + return null; + } + if (field.contains("(")) { + field = field.substring(0, field.indexOf('(')); + Method[] mtn = cl.getMethods(); + for (int j = 0; j < mtn.length; j++) { + int modifiers = mtn[j].getModifiers(); + if (mtn[j].getName().equals(field) && + Modifier.isPublic(modifiers) && + modifierValidator.validate(type, modifiers)) { + ntype = mtn[j].getReturnType().getCanonicalName(); + break; + } + } + } else { + Field[] flds = cl.getFields(); + for (Field f : flds) { + int modifiers = f.getModifiers(); + if (f.getName().equals(field) && + Modifier.isPublic(modifiers) && + modifierValidator.validate(type, modifiers)) { + ntype = f.getType().getCanonicalName(); + break; + } + } + } + if (ntype == null) { + //System.out.println("cannot find type for "+field); + return null; + } + curtype = ntype; + } + // now get last field options + AutocompleteCandidate c = new AutocompleteCandidate(GenericCompletionTypes.FIELD, v, v.length); + AutocompleteCandidate l = c; + while (l.hasChildren()) l = l.getChildrens().get(0); + + Class cl = getClass(curtype); + if (cl == null) { + //System.out.println("not found "+curtype); + return null; + } + Field[] fl = cl.getFields(); + Method[] mt = cl.getMethods(); + + if (fl != null) { + for (Field f : fl) { + if (!f.getName().contains("$") && + Modifier.isPublic(f.getModifiers()) && + modifierValidator.validate(type, f.getModifiers())) { + AutocompleteCandidate c2 = new AutocompleteCandidate(GenericCompletionTypes.FIELD, f.getName()); + l.addChildren(c2); + } + } + } + if (mt != null) { + for (Method mm : mt) { + if (!mm.getName().contains("$") && + Modifier.isPublic(mm.getModifiers()) && + modifierValidator.validate(type, mm.getModifiers())) { + AutocompleteCandidate c2 = new AutocompleteCandidate(GenericCompletionTypes.FIELD, mm.getName()); + l.addChildren(c2); + } + } + } + + registry.addCandidate(c); + + // output our query + c = new AutocompleteCandidate(GenericCompletionTypes.FIELD, v); + l = c; + while (l.hasChildren()) l = l.getChildrens().get(0); + if (endsWithDot) + l.addChildren(new AutocompleteCandidate(GenericCompletionTypes.FIELD, "")); + else + l.addChildren(new AutocompleteCandidate(GenericCompletionTypes.FIELD, txt.substring(txt.lastIndexOf('.') + 1))); + return c; + } catch (ClassNotFoundException e) { + e.printStackTrace(); + } + } + return null; + } + + interface ModifierValidator { + boolean validate(int type, int modifiers); + } +} diff --git a/base/src/main/java/com/twosigma/beakerx/autocomplete/GenericCompletionTypes.java b/base/src/main/java/com/twosigma/beakerx/autocomplete/GenericCompletionTypes.java new file mode 100644 index 0000000..2ca7b6a --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/autocomplete/GenericCompletionTypes.java @@ -0,0 +1,26 @@ +/* + * Copyright 2014 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.autocomplete; + +public class GenericCompletionTypes { + public static final int + PACKAGE_NAME=0, + FIELD=1, + NAME=3, + NUM_TYPES=4; + +} diff --git a/base/src/main/java/com/twosigma/beakerx/chart/AbstractChart.java b/base/src/main/java/com/twosigma/beakerx/chart/AbstractChart.java new file mode 100644 index 0000000..dcc3f60 --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/chart/AbstractChart.java @@ -0,0 +1,323 @@ +/* + * Copyright 2014 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.chart; + +import com.twosigma.beakerx.chart.xychart.plotitem.Crosshair; +import com.twosigma.beakerx.chart.xychart.plotitem.YAxis; + +import java.util.ArrayList; +import java.util.List; +import java.util.TimeZone; + +public abstract class AbstractChart extends Chart { + private String xLabel; + protected final YAxis yAxis = new YAxis(); + private final List yAxes = new ArrayList<>(); + private double xLowerMargin = 0.05; + private double xUpperMargin = 0.05; + protected TimeZone timeZone; + private Crosshair crosshair; + private boolean omitCheckboxes = false; + private boolean autoZoom = false; + + protected AbstractChart() { + yAxes.add(yAxis); + } + + public AbstractChart setXLabel(String xLabel) { + this.xLabel = xLabel; + sendModelUpdate(ChartToJson.serializeXLabel(this.xLabel)); + return this; + } + + public AbstractChart setxLabel(String xLabel) { + return setXLabel(xLabel); + } + + public String getXLabel() { + return this.xLabel; + } + + public String getxLabel() { + return getXLabel(); + } + + public AbstractChart setYLabel(String yLabel) { + yAxis.setLabel(yLabel); + sendModelUpdate(ChartToJson.serializeYLabel(this.yAxis.getLabel())); + return this; + } + + public AbstractChart setyLabel(String yLabel) { + setYLabel(yLabel); + return this; + } + + public String getYLabel() { + return yAxis.getLabel(); + } + + public String getyLabel() { + return getYLabel(); + } + + public AbstractChart add(YAxis yAxis) { + this.yAxes.add(yAxis); + sendModelUpdate(ChartToJson.serializeYAxes(this.yAxes)); + return this; + } + + public AbstractChart leftShift(YAxis yAxis) { + return add(yAxis); + } + + public List getYAxes() { + return this.yAxes; + } + + public List getyAxes() { + return getYAxes(); + } + + public AbstractChart add(List items) { + for (Object o : items) { + if (o instanceof YAxis) { + add((YAxis) o); + } + } + return this; + } + + public AbstractChart leftShift(List items) { + return add(items); + } + + public AbstractChart setXLowerMargin(double margin) { + this.xLowerMargin = margin; + sendModelUpdate(ChartToJson.serializeXLowerMargin(this.xLowerMargin)); + return this; + } + + public AbstractChart setxLowerMargin(double margin) { + return setXLowerMargin(margin); + } + + public double getXLowerMargin() { + return this.xLowerMargin; + } + + public double getxLowerMargin() { + return getXLowerMargin(); + } + + public AbstractChart setXUpperMargin(double margin) { + this.xUpperMargin = margin; + sendModelUpdate(ChartToJson.serializeXUpperMargin(this.xUpperMargin)); + return this; + } + + public AbstractChart setxUpperMargin(double margin) { + return setXUpperMargin(margin); + } + + public double getXUpperMargin() { + return this.xUpperMargin; + } + + public double getxUpperMargin() { + return getXUpperMargin(); + } + + public AbstractChart setyAutoRange(boolean yAutoRange) { + this.yAxis.setAutoRange(yAutoRange); + sendModelUpdate(ChartToJson.serializeAutoRange(this.yAxis.getAutoRange())); + return this; + } + + public AbstractChart setYAutoRange(boolean yAutoRange) { + return setyAutoRange(yAutoRange); + } + + public Boolean getyAutoRange() { + return this.yAxis.getAutoRange(); + } + + public Boolean getYAutoRange() { + return getyAutoRange(); + } + + public AbstractChart setYAutoRangeIncludesZero(boolean yAutoRangeIncludesZero) { + this.yAxis.setAutoRangeIncludesZero(yAutoRangeIncludesZero); + sendModelUpdate(ChartToJson.serializeAutoRangeIncludesZero(this.yAxis.getAutoRangeIncludesZero())); + return this; + } + + public AbstractChart setyAutoRangeIncludesZero(boolean yAutoRangeIncludesZero) { + return this.setYAutoRangeIncludesZero(yAutoRangeIncludesZero); + } + + public Boolean getYAutoRangeIncludesZero() { + return this.yAxis.getAutoRangeIncludesZero(); + } + + public Boolean getyAutoRangeIncludesZero() { + return getYAutoRangeIncludesZero(); + } + + public AbstractChart setYLowerMargin(double margin) { + return setyLowerMargin(margin); + } + + public AbstractChart setyLowerMargin(double margin) { + this.yAxis.setLowerMargin(margin); + sendModelUpdate(ChartToJson.serializeYLowerMargin(this.yAxis.getLowerMargin())); + return this; + } + + public double getYLowerMargin() { + return this.yAxis.getLowerMargin(); + } + + public double getyLowerMargin() { + return getYLowerMargin(); + } + + public AbstractChart setYUpperMargin(double margin) { + return setyUpperMargin(margin); + } + + public AbstractChart setyUpperMargin(double margin) { + this.yAxis.setUpperMargin(margin); + sendModelUpdate(ChartToJson.serializeUpperMargin(this.yAxis.getUpperMargin())); + return this; + } + + public double getYUpperMargin() { + return this.yAxis.getUpperMargin(); + } + + public double getyUpperMargin() { + return getYUpperMargin(); + } + + public AbstractChart setYBound(double lower, double upper) { + this.yAxis.setAutoRange(false); + this.yAxis.setBound(lower, upper); + sendModelUpdate(ChartToJson.serializeYBound(this.yAxis)); + return this; + } + + public AbstractChart setYBound(List bound) { + if (bound.size() != 2) { + throw new IllegalArgumentException("to set the y bound, the list needs to be of size=2"); + } + + Number n0 = bound.get(0); + Number n1 = bound.get(1); + setYBound(n0.doubleValue(), n1.doubleValue()); + return this; + } + + public AbstractChart setyBound(List bound) { + return this.setYBound(bound); + } + + public Double getYLowerBound() { + return this.yAxis.getLowerBound(); + } + + public Double getyLowerBound() { + return getYLowerBound(); + } + + public Double getYUpperBound() { + return this.yAxis.getUpperBound(); + } + + public Double getyUpperBound() { + return getYUpperBound(); + } + + public AbstractChart setLogY(boolean logY) { + this.yAxis.setLog(logY); + sendModelUpdate(ChartToJson.serializeLogY(this.yAxis.getLog())); + return this; + } + + public Boolean getLogY() { + return this.yAxis.getLog(); + } + + public AbstractChart setYLogBase(double yLogBase) { + this.yAxis.setLogBase(yLogBase); + sendModel(); + return this; + } + + public AbstractChart setyLogBase(double yLogBase) { + return this.setYLogBase(yLogBase); + } + + public Double getYLogBase() { + return this.yAxis.getLogBase(); + } + + public Double getyLogBase() { + return getYLogBase(); + } + + protected AbstractChart setTimeZone(TimeZone timeZone) { + this.timeZone = timeZone; + sendModelUpdate(ChartToJson.serializeTimeZone(this.timeZone)); + return this; + } + + public TimeZone getTimeZone() { + return this.timeZone; + } + + public AbstractChart setCrosshair(Crosshair crosshair) { + this.crosshair = crosshair; + sendModelUpdate(ChartToJson.serializeCrosshair(this.crosshair)); + return this; + } + + public Crosshair getCrosshair() { + return this.crosshair; + } + + public Boolean getOmitCheckboxes() { + return omitCheckboxes; + } + + public AbstractChart setOmitCheckboxes(boolean omitCheckboxes) { + this.omitCheckboxes = omitCheckboxes; + sendModelUpdate(ChartToJson.serializeOmitCheckboxes(this.omitCheckboxes)); + return this; + } + + public Boolean getAutoZoom() { + return autoZoom; + } + + public AbstractChart setAutoZoom(boolean autoZoom) { + this.autoZoom = autoZoom; + sendModelUpdate(ChartToJson.serializeAutoZoom(this.autoZoom)); + return this; + } + +} diff --git a/base/src/main/java/com/twosigma/beakerx/chart/Chart.java b/base/src/main/java/com/twosigma/beakerx/chart/Chart.java new file mode 100644 index 0000000..8be2895 --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/chart/Chart.java @@ -0,0 +1,193 @@ +/* + * Copyright 2014 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.chart; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import com.twosigma.beakerx.chart.legend.LegendLayout; +import com.twosigma.beakerx.chart.legend.LegendPosition; + +import static com.twosigma.beakerx.widget.BeakerxPlot.MODEL_NAME_VALUE; +import static com.twosigma.beakerx.widget.BeakerxPlot.VIEW_NAME_VALUE; + +public abstract class Chart extends ChartDetails { + + public static final String PLOT_GRIDLINE = ".plot-gridline"; + public static final String PLOT_LABEL_Y = ".plot-label-y"; + public static final String PLOT_LABEL_X = ".plot-label-x"; + public static final String PLOT_LABEL = ".plot-label"; + public static final String PLOT_TITLE = ".plot-title"; + + private int initWidth = 640; + private int initHeight = 480; + private List customStyles = new ArrayList(); + private Map elementStyles = new HashMap<>(); + + private String title; + private Boolean showLegend; + private boolean useToolTip = true; + private LegendPosition legendPosition = new LegendPosition(LegendPosition.Position.TOP_RIGHT); + private LegendLayout legendLayout = LegendLayout.VERTICAL; + + public Chart setInitWidth(int w) { + this.initWidth = w; + sendModelUpdate(ChartToJson.serializeInitWidth(this.initWidth)); + return this; + } + + public Integer getInitWidth() { + return this.initWidth; + } + + public Chart setInitHeight(int h) { + this.initHeight = h; + sendModelUpdate(ChartToJson.serializeInitHeight(this.initHeight)); + return this; + } + + public Integer getInitHeight() { + return this.initHeight; + } + + public Chart setTitle(String title) { + this.title = title; + sendModelUpdate(ChartToJson.serializeTitle(this.title)); + return this; + } + + public String getTitle() { + return this.title; + } + + public Chart setShowLegend(Boolean showLegend) { + this.showLegend = showLegend; + return this; + } + + public Boolean getShowLegend() { + return this.showLegend; + } + + public Chart setUseToolTip(boolean useToolTip) { + this.useToolTip = useToolTip; + return this; + } + + public Boolean getUseToolTip() { + return this.useToolTip; + } + + public LegendPosition getLegendPosition() { + return legendPosition; + } + + public Chart setLegendPosition(LegendPosition legendPosition) { + this.legendPosition = legendPosition; + sendModelUpdate(ChartToJson.serializeLegendPosition(this.legendPosition)); + return this; + } + + public LegendLayout getLegendLayout() { + return legendLayout; + } + + public Chart setLegendLayout(LegendLayout legendLayout) { + this.legendLayout = legendLayout; + sendModelUpdate(ChartToJson.serializeLegendLayout(this.legendLayout)); + return this; + } + + public List getCustomStyles() { + return customStyles; + } + + public void setCustomStyles(List customStyle) { + this.customStyles = customStyle; + sendModelUpdate(ChartToJson.serializeCustomStyles(this.customStyles)); + } + + public String getLabelStyle() { + return this.elementStyles.get(PLOT_LABEL); + } + + public void setLabelStyle(String style) { + this.elementStyles.put(PLOT_LABEL, style); + sendModelUpdate(ChartToJson.serializeElementStyles(this.elementStyles)); + } + + public String getLabelXStyle() { + return this.elementStyles.get(PLOT_LABEL_X); + } + + public void setLabelXStyle(String style) { + this.elementStyles.put(PLOT_LABEL_X, style); + sendModelUpdate(ChartToJson.serializeElementStyles(this.elementStyles)); + } + + public String getLabelYStyle() { + return this.elementStyles.get(PLOT_LABEL_Y); + } + + public void setLabelYStyle(String style) { + this.elementStyles.put(PLOT_LABEL_Y, style); + sendModelUpdate(ChartToJson.serializeElementStyles(this.elementStyles)); + } + + public String getGridLineStyle() { + return this.elementStyles.get(PLOT_GRIDLINE); + } + + public void setGridLineStyle(String style) { + this.elementStyles.put(PLOT_GRIDLINE, style); + sendModelUpdate(ChartToJson.serializeElementStyles(this.elementStyles)); + } + + public String getTitleStyle() { + return this.elementStyles.get(PLOT_TITLE); + } + + public void setTitleStyle(String style) { + this.elementStyles.put(PLOT_TITLE, style); + sendModelUpdate(ChartToJson.serializeElementStyles(this.elementStyles)); + } + + public Map getElementStyles() { + return this.elementStyles; + } + + @Override + public String getModelNameValue() { + return MODEL_NAME_VALUE; + } + + @Override + public String getViewNameValue() { + return VIEW_NAME_VALUE; + } + + @Override + protected Map serializeToJsonObject() { + return ChartToJson.toJson(this); + } + + @Override + protected Map serializeToJsonObject(Object item) { + return ChartToJson.toJson(item); + } +} diff --git a/base/src/main/java/com/twosigma/beakerx/chart/ChartDetails.java b/base/src/main/java/com/twosigma/beakerx/chart/ChartDetails.java new file mode 100644 index 0000000..92a88dc --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/chart/ChartDetails.java @@ -0,0 +1,215 @@ +/* + * Copyright 2014 - 2017 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.chart; + +import com.twosigma.beakerx.BeakerXClientManager; +import com.twosigma.beakerx.widget.CommActions; +import org.apache.commons.lang3.StringUtils; + +import com.twosigma.beakerx.chart.actions.CategoryGraphicsActionObject; +import com.twosigma.beakerx.chart.actions.CombinedPlotActionObject; +import com.twosigma.beakerx.chart.actions.GraphicsActionObject; +import com.twosigma.beakerx.chart.actions.XYGraphicsActionObject; +import com.twosigma.beakerx.chart.categoryplot.CategoryPlot; +import com.twosigma.beakerx.chart.xychart.CombinedPlot; +import com.twosigma.beakerx.chart.xychart.XYChart; +import com.twosigma.beakerx.widget.BeakerxWidget; +import com.twosigma.beakerx.handler.Handler; +import com.twosigma.beakerx.message.Message; + +import java.util.HashMap; +import java.util.List; + +public abstract class ChartDetails extends BeakerxWidget { + + private GraphicsActionObject details; + + public GraphicsActionObject getDetails() { + return details; + } + + public void setDetails(GraphicsActionObject details) { + this.details = details; + } + + protected void openComm() { + super.openComm(); + getComm().addMsgCallbackList((Handler) this::handleSetDetails, (Handler) this::handleClick, (Handler) this::handleKey); + } + + private void handleSetDetails(Message message) { + handleCommEventSync(message, CommActions.ACTIONDETAILS, this::onActionDetails); + } + + private void handleClick(Message message) { + handleCommEventSync(message, CommActions.ONCLICK, this::onClickAction); + } + + private void handleKey(Message message) { + handleCommEventSync(message, CommActions.ONKEY, this::onKeyAction); + } + + private void onKeyAction(HashMap content, Message message) { + GraphicsActionObject info = getDetailsFromMessage(content); + String graphicsId = getGraphicsUid(content); + Graphics g = getGraphicsById(getGraphics(info, this), graphicsId); + if (g != null) { + g.fireOnKey(info.getKey(), info, message); + sendModel(); + } + } + + private void onClickAction(HashMap content, Message message) { + GraphicsActionObject info = getDetailsFromMessage(content); + String graphicsId = getGraphicsUid(content); + Graphics g = getGraphicsById(getGraphics(info, this), graphicsId); + if (g != null) { + g.fireClick(info, message); + sendModel(); + } + } + + protected void onActionDetails(HashMap content, Message message) { + GraphicsActionObject info = getDetailsFromMessage(content); + String graphicsId = getGraphicsUid(content); + Graphics g = getGraphicsById(getGraphics(info, this), graphicsId); + info.setGraphics(g); + updateDetails(info); + if (CommActions.ONCLICK.equals(info.getActionType())) { + BeakerXClientManager.get().runByTag(info.getTag()); + } else if (CommActions.ONKEY.equals(info.getActionType())) { + BeakerXClientManager.get().runByTag(info.getTag()); + } + } + + protected void updateDetails(GraphicsActionObject info) { + setDetails(info); + } + + protected String getGraphicsUid(HashMap content) { + String ret = null; + if (content.containsKey("itemId")) { + ret = (String) content.get("itemId"); + } + return ret; + } + + protected GraphicsActionObject getDetailsFromMessage(HashMap content) { + GraphicsActionObject ret = null; + + if (content.containsKey("params")) { + + HashMap params = (HashMap) content.get("params"); + + if (params.containsKey("type")) { + + String type = (String) params.get("type"); + switch (type) { + + case "CategoryGraphicsActionObject": { + ret = new CategoryGraphicsActionObject(); + CategoryGraphicsActionObject retObject = (CategoryGraphicsActionObject) ret; + if (params.containsKey("category")) { + retObject.setCategory((int) params.get("category")); + } + if (params.containsKey("series")) { + retObject.setSeries((int) params.get("series")); + } + } + break; + + case "CombinedPlotActionObject": { + ret = new CombinedPlotActionObject(); + CombinedPlotActionObject retObject = (CombinedPlotActionObject) ret; + if (params.containsKey("subplotIndex")) { + retObject.setSubplotIndex((int) params.get("subplotIndex")); + } + if (params.containsKey("index")) { + retObject.setIndex((int) params.get("index")); + } + } + break; + + case "XYGraphicsActionObject": { + ret = new XYGraphicsActionObject(); + XYGraphicsActionObject retObject = (XYGraphicsActionObject) ret; + if (params.containsKey("index")) { + retObject.setIndex((int) params.get("index")); + } + } + break; + } + + if (params.containsKey("actionType")) { + CommActions value = CommActions.getByAction((String) params.get("actionType")); + ret.setActionType(value); + } + + if (params.containsKey("tag")) { + ret.setTag((String) params.get("tag")); + } + + if (params.containsKey("key")) { + ret.setKey((String) params.get("key")); + } + + } + } + return ret; + } + + + /** + * Taken from code{@code com.twosigma.beaker.groovy.rest.ChartRest#getGraphics} + * + * @param info GraphicsActionObject + * @param chart ChartDetails + * @return list of Graphics for given plot data + */ + protected List getGraphics(GraphicsActionObject info, ChartDetails chart) { + List graphics = null; + if (chart instanceof XYChart) { + graphics = ((XYChart) chart).getGraphics(); + } else if (chart instanceof CategoryPlot) { + graphics = ((CategoryPlot) chart).getGraphics(); + } else if (chart instanceof CombinedPlot) { + XYChart subplot = ((CombinedPlot) chart).getSubplots().get(((CombinedPlotActionObject) info).getSubplotIndex()); + graphics = subplot.getGraphics(); + } + return graphics; + } + + /** + * code{@code com.twosigma.beaker.groovy.rest.ChartRest#getGraphicsById} + * + * @param graphicsList list of Graphics objects + * @param graphicsId string with id of Graphics object + * @return Graphics with given id or null if it wasn't found + */ + protected Graphics getGraphicsById(List graphicsList, String graphicsId) { + if (graphicsList != null) { + for (Graphics g : graphicsList) { + if (StringUtils.equals(g.getUid(), graphicsId)) { + return g; + } + } + } + return null; + } + + +} \ No newline at end of file diff --git a/base/src/main/java/com/twosigma/beakerx/chart/ChartToJson.java b/base/src/main/java/com/twosigma/beakerx/chart/ChartToJson.java new file mode 100644 index 0000000..1068c2d --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/chart/ChartToJson.java @@ -0,0 +1,543 @@ +/* + * Copyright 2017 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.chart; + +import static com.twosigma.beakerx.chart.serializer.AbstractChartSerializer.CROSSHAIR; +import static com.twosigma.beakerx.chart.serializer.AbstractChartSerializer.DOMAIN_AXIS_LABEL; +import static com.twosigma.beakerx.chart.serializer.AbstractChartSerializer.LOG_Y; +import static com.twosigma.beakerx.chart.serializer.AbstractChartSerializer.OMIT_CHECKBOXES; +import static com.twosigma.beakerx.chart.serializer.AbstractChartSerializer.AUTO_ZOOM; +import static com.twosigma.beakerx.chart.serializer.AbstractChartSerializer.RANGE_AXES; +import static com.twosigma.beakerx.chart.serializer.AbstractChartSerializer.TIMEZONE; +import static com.twosigma.beakerx.chart.serializer.AbstractChartSerializer.X_LOWER_MARGIN; +import static com.twosigma.beakerx.chart.serializer.AbstractChartSerializer.X_UPPER_MARGIN; +import static com.twosigma.beakerx.chart.serializer.AbstractChartSerializer.Y_AUTO_RANGE; +import static com.twosigma.beakerx.chart.serializer.AbstractChartSerializer.Y_AUTO_RANGE_INCLUDES_ZERO; +import static com.twosigma.beakerx.chart.serializer.AbstractChartSerializer.Y_LABEL; +import static com.twosigma.beakerx.chart.serializer.AbstractChartSerializer.Y_LOWER_BOUND; +import static com.twosigma.beakerx.chart.serializer.AbstractChartSerializer.Y_LOWER_MARGIN; +import static com.twosigma.beakerx.chart.serializer.AbstractChartSerializer.Y_UPPER_BOUND; +import static com.twosigma.beakerx.chart.serializer.AbstractChartSerializer.Y_UPPER_MARGIN; +import static com.twosigma.beakerx.chart.serializer.ChartSerializer.CHART_TITLE; +import static com.twosigma.beakerx.chart.serializer.ChartSerializer.CUSTOM_STYLES; +import static com.twosigma.beakerx.chart.serializer.ChartSerializer.ELEMENT_STYLES; +import static com.twosigma.beakerx.chart.serializer.ChartSerializer.INIT_HEIGHT; +import static com.twosigma.beakerx.chart.serializer.ChartSerializer.INIT_WIDTH; +import static com.twosigma.beakerx.chart.serializer.ChartSerializer.LEGEND_LAYOUT; +import static com.twosigma.beakerx.chart.serializer.ChartSerializer.LEGEND_POSITION; +import static com.twosigma.beakerx.chart.serializer.HeatMapSerializer.COLOR; +import static com.twosigma.beakerx.chart.serializer.XYChartSerializer.CONSTANT_LINES; + +import com.fasterxml.jackson.core.Version; +import com.fasterxml.jackson.databind.JsonSerializer; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.module.SimpleModule; +import com.twosigma.beakerx.chart.categoryplot.CategoryPlot; +import com.twosigma.beakerx.chart.categoryplot.plotitem.CategoryArea; +import com.twosigma.beakerx.chart.categoryplot.plotitem.CategoryBars; +import com.twosigma.beakerx.chart.categoryplot.plotitem.CategoryGraphics; +import com.twosigma.beakerx.chart.categoryplot.plotitem.CategoryLines; +import com.twosigma.beakerx.chart.categoryplot.plotitem.CategoryPoints; +import com.twosigma.beakerx.chart.categoryplot.plotitem.CategoryStems; +import com.twosigma.beakerx.chart.heatmap.HeatMap; +import com.twosigma.beakerx.chart.histogram.Histogram; +import com.twosigma.beakerx.chart.legend.LegendLayout; +import com.twosigma.beakerx.chart.legend.LegendPosition; +import com.twosigma.beakerx.chart.serializer.AreaSerializer; +import com.twosigma.beakerx.chart.serializer.BarsSerializer; +import com.twosigma.beakerx.chart.serializer.CategoryAreasSerializer; +import com.twosigma.beakerx.chart.serializer.CategoryBarsSerializer; +import com.twosigma.beakerx.chart.serializer.CategoryLinesSerializer; +import com.twosigma.beakerx.chart.serializer.CategoryPlotSerializer; +import com.twosigma.beakerx.chart.serializer.CategoryPointsSerializer; +import com.twosigma.beakerx.chart.serializer.CategoryStemsSerializer; +import com.twosigma.beakerx.chart.serializer.ColorSerializer; +import com.twosigma.beakerx.chart.serializer.CombinedPlotSerializer; +import com.twosigma.beakerx.chart.serializer.ConstantBandSerializer; +import com.twosigma.beakerx.chart.serializer.ConstantLineSerializer; +import com.twosigma.beakerx.chart.serializer.CrosshairSerializer; +import com.twosigma.beakerx.chart.serializer.GradientColorSerializer; +import com.twosigma.beakerx.chart.serializer.HeatMapSerializer; +import com.twosigma.beakerx.chart.serializer.HistogramSerializer; +import com.twosigma.beakerx.chart.serializer.LegendPositionSerializer; +import com.twosigma.beakerx.chart.serializer.LineSerializer; +import com.twosigma.beakerx.chart.serializer.PointsSerializer; +import com.twosigma.beakerx.chart.serializer.RastersSerializer; +import com.twosigma.beakerx.chart.serializer.StemsSerializer; +import com.twosigma.beakerx.chart.serializer.TextSerializer; +import com.twosigma.beakerx.chart.serializer.TreeMapNodeSerializer; +import com.twosigma.beakerx.chart.serializer.TreeMapSerializer; +import com.twosigma.beakerx.chart.serializer.XYChartSerializer; +import com.twosigma.beakerx.chart.serializer.YAxisSerializer; +import com.twosigma.beakerx.chart.treemap.Mode; +import com.twosigma.beakerx.chart.treemap.TreeMap; +import com.twosigma.beakerx.chart.treemap.ValueAccessor; +import com.twosigma.beakerx.chart.xychart.CombinedPlot; +import com.twosigma.beakerx.chart.xychart.XYChart; +import com.twosigma.beakerx.chart.xychart.plotitem.Area; +import com.twosigma.beakerx.chart.xychart.plotitem.Bars; +import com.twosigma.beakerx.chart.xychart.plotitem.ConstantBand; +import com.twosigma.beakerx.chart.xychart.plotitem.ConstantLine; +import com.twosigma.beakerx.chart.xychart.plotitem.Crosshair; +import com.twosigma.beakerx.chart.xychart.plotitem.Line; +import com.twosigma.beakerx.chart.xychart.plotitem.PlotOrientationType; +import com.twosigma.beakerx.chart.xychart.plotitem.Points; +import com.twosigma.beakerx.chart.xychart.plotitem.Rasters; +import com.twosigma.beakerx.chart.xychart.plotitem.Stems; +import com.twosigma.beakerx.chart.xychart.plotitem.Text; +import com.twosigma.beakerx.chart.xychart.plotitem.XYGraphics; +import com.twosigma.beakerx.chart.xychart.plotitem.YAxis; +import java.util.ArrayList; +import java.util.Hashtable; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.TimeZone; +import net.sf.jtreemap.swing.TreeMapNode; + +public class ChartToJson { + + private static ObjectMapper mapper; + private static Map, JsonSerializer> serializerMap = new Hashtable<>(); + + static { + + serializerMap.put(Color.class, new ColorSerializer()); + serializerMap.put(XYChart.class, new XYChartSerializer()); + serializerMap.put(CombinedPlot.class, new CombinedPlotSerializer()); + serializerMap.put(Line.class, new LineSerializer()); + serializerMap.put(Points.class, new PointsSerializer()); + serializerMap.put(Bars.class, new BarsSerializer()); + serializerMap.put(Stems.class, new StemsSerializer()); + serializerMap.put(Area.class, new AreaSerializer()); + serializerMap.put(YAxis.class, new YAxisSerializer()); + serializerMap.put(Crosshair.class, new CrosshairSerializer()); + serializerMap.put(LegendPosition.class, new LegendPositionSerializer()); + serializerMap.put(Text.class, new TextSerializer()); + serializerMap.put(ConstantLine.class, new ConstantLineSerializer()); + serializerMap.put(ConstantBand.class, new ConstantBandSerializer()); + serializerMap.put(CategoryArea.class, new CategoryAreasSerializer()); + serializerMap.put(CategoryBars.class, new CategoryBarsSerializer()); + serializerMap.put(CategoryStems.class, new CategoryStemsSerializer()); + serializerMap.put(CategoryPoints.class, new CategoryPointsSerializer()); + serializerMap.put(CategoryLines.class, new CategoryLinesSerializer()); + serializerMap.put(CategoryPlot.class, new CategoryPlotSerializer()); + serializerMap.put(GradientColor.class, new GradientColorSerializer()); + serializerMap.put(Histogram.class, new HistogramSerializer()); + serializerMap.put(HeatMap.class, new HeatMapSerializer()); + serializerMap.put(Rasters.class, new RastersSerializer()); + serializerMap.put(TreeMap.class, new TreeMapSerializer()); + serializerMap.put(TreeMapNode.class, new TreeMapNodeSerializer()); + + SimpleModule module = new SimpleModule("ChartSerializer", new Version(1, 0, 0, null)); + serializerMap.forEach(module::addSerializer); + + mapper = new ObjectMapper(); + mapper.registerModule(module); + } + + public static Map toJson(Object result) { + try { + return getMapper().convertValue(result, Map.class); + } catch (Exception e) { + throw new IllegalStateException(e.getMessage()); + } + } + + private static ObjectMapper getMapper() { + return mapper; + } + + static Map serializeLegendPosition(LegendPosition legendPosition) { + Map value = new LinkedHashMap<>(); + value.put(LEGEND_POSITION, toJson(legendPosition)); + return value; + } + + static Map serializeLegendLayout(LegendLayout legendLayout) { + Map value = new LinkedHashMap<>(); + value.put(LEGEND_LAYOUT, legendLayout.toString()); + return value; + } + + static Map serializeCustomStyles(List customStyles) { + Map value = new LinkedHashMap<>(); + value.put(CUSTOM_STYLES, toJsonList(customStyles)); + return value; + } + + static Map serializeElementStyles(Map elementStyles) { + Map value = new LinkedHashMap<>(); + value.put(ELEMENT_STYLES, toJson(elementStyles)); + return value; + } + + static Map serializeInitHeight(int initHeight) { + Map value = new LinkedHashMap<>(); + value.put(INIT_HEIGHT, initHeight); + return value; + } + + static Map serializeInitWidth(int initWidth) { + Map value = new LinkedHashMap<>(); + value.put(INIT_WIDTH, initWidth); + return value; + } + + static Map serializeTitle(String title) { + Map value = new LinkedHashMap<>(); + value.put(CHART_TITLE, title); + return value; + } + + static Map serializeOmitCheckboxes(boolean omitCheckboxes) { + Map value = new LinkedHashMap<>(); + value.put(OMIT_CHECKBOXES, omitCheckboxes); + return value; + } + + static Map serializeAutoZoom(boolean autoZoom) { + Map value = new LinkedHashMap<>(); + value.put(AUTO_ZOOM, autoZoom); + return value; + } + + static Map serializeAutoRangeIncludesZero(boolean autoRangeIncludesZero) { + Map value = new LinkedHashMap<>(); + value.put(Y_AUTO_RANGE_INCLUDES_ZERO, autoRangeIncludesZero); + return value; + } + + static Map serializeYBound(YAxis yAxis) { + Map value = new LinkedHashMap<>(); + value.put(Y_LOWER_BOUND, yAxis.getLowerBound()); + value.put(Y_UPPER_BOUND, yAxis.getUpperBound()); + return value; + } + + static Map serializeXLabel(String title) { + Map value = new LinkedHashMap<>(); + value.put(DOMAIN_AXIS_LABEL, title); + return value; + } + + static Map serializeYLabel(String title) { + Map value = new LinkedHashMap<>(); + value.put(Y_LABEL, title); + return value; + } + + static Map serializeXLowerMargin(double margin) { + Map value = new LinkedHashMap<>(); + value.put(X_LOWER_MARGIN, margin); + return value; + } + + static Map serializeXUpperMargin(double margin) { + Map value = new LinkedHashMap<>(); + value.put(X_UPPER_MARGIN, margin); + return value; + } + + static Map serializeAutoRange(Boolean autoRange) { + Map value = new LinkedHashMap<>(); + value.put(Y_AUTO_RANGE, autoRange); + return value; + } + + static Map serializeYLowerMargin(Double yLowerMargin) { + Map value = new LinkedHashMap<>(); + value.put(Y_LOWER_MARGIN, yLowerMargin); + return value; + } + + static Map serializeUpperMargin(Double upperMargin) { + Map value = new LinkedHashMap<>(); + value.put(Y_UPPER_MARGIN, upperMargin); + return value; + } + + static Map serializeCrosshair(Crosshair crosshair) { + Map value = new LinkedHashMap<>(); + value.put(CROSSHAIR, toJson(crosshair)); + return value; + } + + static Map serializeTimeZone(TimeZone timeZone) { + Map value = new LinkedHashMap<>(); + value.put(TIMEZONE, getMapper().convertValue(timeZone, String.class)); + return value; + } + + static Map serializeLogY(Boolean logY) { + Map value = new LinkedHashMap<>(); + value.put(LOG_Y, logY); + return value; + } + + public static Map serializeHistogramLog(Boolean logY) { + Map value = new LinkedHashMap<>(); + value.put(HistogramSerializer.LOG, logY); + return value; + } + + static Map serializeYAxes(List yAxes) { + List result = new ArrayList(); + for (YAxis item : yAxes) { + result.add(toJson(item)); + } + Map value = new LinkedHashMap<>(); + value.put(RANGE_AXES, toJsonList(result)); + return value; + } + + + public static List toJsonList(Object item) { + return mapper.convertValue(item, List.class); + } + + public static Map serializeHeatmapData(Number[][] data) { + Map value = new LinkedHashMap<>(); + value.put(HeatMapSerializer.GRAPHICS_LIST, toJsonList(data)); + return value; + } + + public static Map serializeHeatmapGradientColor(GradientColor data) { + Map value = new LinkedHashMap<>(); + value.put(COLOR, getMapper().convertValue(data, Object.class)); + return value; + } + + public static Map serializeConstantLines(List constantLines) { + List result = new ArrayList(); + for (ConstantLine item : constantLines) { + result.add(toJson(item)); + } + Map value = new LinkedHashMap<>(); + value.put(CONSTANT_LINES, toJsonList(result)); + return value; + } + + public static Map serializeXYGraphics(List xyGraphics) { + List result = new ArrayList(); + for (XYGraphics item : xyGraphics) { + result.add(toJson(item)); + } + Map value = new LinkedHashMap<>(); + value.put(XYChartSerializer.GRAPHICS_LIST, toJsonList(result)); + return value; + } + + public static Map serializeConstantBands(List constantBands) { + List result = new ArrayList(); + for (ConstantBand item : constantBands) { + result.add(toJson(item)); + } + Map value = new LinkedHashMap<>(); + value.put(XYChartSerializer.CONSTANT_BANDS, toJsonList(result)); + return value; + } + + public static Map serializeTexts(List texts) { + List result = new ArrayList(); + for (Text item : texts) { + result.add(toJson(item)); + } + Map value = new LinkedHashMap<>(); + value.put(XYChartSerializer.TEXTS, toJsonList(result)); + return value; + } + + public static Map serializeRasters(List rasters) { + List result = new ArrayList(); + for (Rasters item : rasters) { + result.add(toJson(item)); + } + Map value = new LinkedHashMap<>(); + value.put(XYChartSerializer.RASTERS, toJsonList(result)); + return value; + } + + public static Map serializeXBound(XYChart xyChart) { + Map value = new LinkedHashMap<>(); + value.put(XYChartSerializer.X_AUTO_RANGE, xyChart.getXAutoRange()); + value.put(XYChartSerializer.X_LOWER_BOUND, xyChart.getXLowerBound()); + value.put(XYChartSerializer.X_UPPER_BOUND, xyChart.getXUpperBound()); + return value; + } + + public static Map serializeXAutoRange(boolean xAutoRange) { + Map value = new LinkedHashMap<>(); + value.put(XYChartSerializer.X_AUTO_RANGE, xAutoRange); + return value; + } + + public static Map serializeLogX(boolean logX) { + Map value = new LinkedHashMap<>(); + value.put(XYChartSerializer.LOG_X, logX); + return value; + } + + public static Map serializeXLogBase(double xLogBase) { + Map value = new LinkedHashMap<>(); + value.put(XYChartSerializer.X_LOG_BASE, xLogBase); + return value; + } + + public static Map serializeLodThreshold(Integer lodThreshold) { + Map value = new LinkedHashMap<>(); + value.put(XYChartSerializer.LOD_THRESHOLD, lodThreshold); + return value; + } + + public static Map serializeXTickLabelsVisible(boolean xtickLabelsVisible) { + Map value = new LinkedHashMap<>(); + value.put(XYChartSerializer.X_TICK_LABELS_VISIBLE, xtickLabelsVisible); + return value; + } + + public static Map serializeYTickLabelsVisible(boolean ytickLabelsVisible) { + Map value = new LinkedHashMap<>(); + value.put(XYChartSerializer.Y_TICK_LABELS_VISIBLE, ytickLabelsVisible); + return value; + } + + public static Map serializeDisplayMode(Histogram.DisplayMode displayMode) { + Map value = new LinkedHashMap<>(); + value.put(HistogramSerializer.DISPLAY_MODE, displayMode.toString()); + return value; + } + + public static Map serializeHistogramNames(List names) { + Map value = new LinkedHashMap<>(); + value.put(HistogramSerializer.NAMES, toJsonList(names)); + return value; + } + + public static Map serializeHistogramListData(List> listData) { + Map value = new LinkedHashMap<>(); + value.put(HistogramSerializer.GRAPHICS_LIST, toJsonList(listData)); + return value; + } + + public static Map serializeHistogramData(List data) { + Map value = new LinkedHashMap<>(); + value.put(HistogramSerializer.GRAPHICS_LIST, toJsonList(data)); + return value; + } + + public static Map serializeColors(List colors) { + List result = new ArrayList(); + for (Color item : colors) { + result.add(getMapper().convertValue(item, String.class)); + } + Map value = new LinkedHashMap<>(); + value.put(HistogramSerializer.COLORS, result); + return value; + } + + public static Map serializeColor(Color color) { + Map value = new LinkedHashMap<>(); + value.put(HistogramSerializer.COLOR, getMapper().convertValue(color, String.class)); + return value; + } + + + public static Map serializeCumulative(boolean cumulative) { + Map value = new LinkedHashMap<>(); + value.put(HistogramSerializer.CUMULATIVE, cumulative); + return value; + } + + public static Map serializeNormed(boolean normed) { + Map value = new LinkedHashMap<>(); + value.put(HistogramSerializer.NORMED, normed); + return value; + } + + public static Map serializeBinCount(int binCount) { + Map value = new LinkedHashMap<>(); + value.put(HistogramSerializer.BIN_COUNT, binCount); + return value; + } + + public static Map serializeCategoryNames(List categoryNames) { + Map value = new LinkedHashMap<>(); + value.put(CategoryPlotSerializer.CATEGORY_NAMES, categoryNames); + return value; + } + + public static Map serializeCategoryGraphics( + List categoryGraphics) { + List result = new ArrayList(); + for (CategoryGraphics item : categoryGraphics) { + result.add(toJson(item)); + } + Map value = new LinkedHashMap<>(); + value.put(CategoryPlotSerializer.GRAPHICS_LIST, result); + return value; + } + + public static Map serializePlotOrientationType(PlotOrientationType orientation) { + Map value = new LinkedHashMap<>(); + value.put(CategoryPlotSerializer.ORIENTATION, orientation.toString()); + return value; + } + + public static Map serializeCategoryNamesLabelAngle( + double categoryNamesLabelAngle) { + Map value = new LinkedHashMap<>(); + value.put(CategoryPlotSerializer.CATEGORY_NAMES_LABEL_ANGLE, categoryNamesLabelAngle); + return value; + } + + public static Map serializeCategoryMargin(double categoryMargin) { + Map value = new LinkedHashMap<>(); + value.put(CategoryPlotSerializer.CATEGORY_MARGIN, categoryMargin); + return value; + } + + public static Map serializeTreeMapRound(Boolean round) { + Map value = new LinkedHashMap<>(); + value.put(TreeMapSerializer.ROUND, round); + return value; + } + + public static Map serializeTreeMapSticky(Boolean sticky) { + Map value = new LinkedHashMap<>(); + value.put(TreeMapSerializer.STICKY, sticky); + return value; + } + + public static Map serializeTreeMapValueAccessor(ValueAccessor valueAccessor) { + Map value = new LinkedHashMap<>(); + value.put(TreeMapSerializer.VALUE_ACCESSOR, valueAccessor.toString()); + return value; + } + + public static Map serializeTreeMapRatio(Double ratio) { + Map value = new LinkedHashMap<>(); + value.put(TreeMapSerializer.RATIO, ratio); + return value; + } + + public static Map serializeTreeMapMode(Mode mode) { + Map value = new LinkedHashMap<>(); + value.put(TreeMapSerializer.MODE, mode.getJsName()); + return value; + } +} \ No newline at end of file diff --git a/base/src/main/java/com/twosigma/beakerx/chart/ChartUtils.java b/base/src/main/java/com/twosigma/beakerx/chart/ChartUtils.java new file mode 100644 index 0000000..faa4439 --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/chart/ChartUtils.java @@ -0,0 +1,41 @@ +/* + * Copyright 2014 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.chart; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Random; + +public class ChartUtils { + + public static List convertColors(List colors, String errorMsg) { + List clist = new ArrayList<>(colors.size()); + for(Object c : colors){ + if (c instanceof Color) { + clist.add(c); + } else if (c instanceof java.awt.Color) { + clist.add(new Color((java.awt.Color) c)); + } else if (c instanceof List) { + clist.add(convertColors((List)c, errorMsg)); + } else { + throw new IllegalArgumentException(errorMsg); + } + } + return clist; + } + +} diff --git a/base/src/main/java/com/twosigma/beakerx/chart/Color.java b/base/src/main/java/com/twosigma/beakerx/chart/Color.java new file mode 100644 index 0000000..b377193 --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/chart/Color.java @@ -0,0 +1,150 @@ +/* + * Copyright 2014 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.chart; + +public class Color implements java.io.Serializable { + public final static Color white = new Color(255, 255, 255); + public final static Color WHITE = white; + public final static Color lightGray = new Color(192, 192, 192); + public final static Color LIGHT_GRAY = lightGray; + public final static Color gray = new Color(128, 128, 128); + public final static Color GRAY = gray; + public final static Color darkGray = new Color(64, 64, 64); + public final static Color DARK_GRAY = darkGray; + public final static Color black = new Color(0, 0, 0); + public final static Color BLACK = black; + public final static Color red = new Color(255, 0, 0); + public final static Color RED = red; + public final static Color pink = new Color(255, 175, 175); + public final static Color PINK = pink; + public final static Color orange = new Color(255, 200, 0); + public final static Color ORANGE = orange; + public final static Color yellow = new Color(255, 255, 0); + public final static Color YELLOW = yellow; + public final static Color green = new Color(0, 255, 0); + public final static Color GREEN = green; + public final static Color lightGreen = new Color(144, 238, 144); + public final static Color LIGHT_GREEN = lightGreen; + public final static Color darkGreen = new Color(0, 100, 0); + public final static Color DARK_GREEN = darkGreen; + public final static Color olive = new Color(128, 128, 0); + public final static Color OLIVE = olive; + public final static Color magenta = new Color(255, 0, 255); + public final static Color MAGENTA = magenta; + public final static Color orangeRed = new Color(255, 69, 0); + public final static Color ORANGE_RED = orangeRed; + public final static Color maroon = new Color(128, 0, 0); + public final static Color MAROON = maroon; + public final static Color cyan = new Color(0, 255, 255); + public final static Color CYAN = cyan; + public final static Color blue = new Color(0, 0, 255); + public final static Color BLUE = blue; + public final static Color lightBlue = new Color(173, 216, 230); + public final static Color LIGHT_BLUE = lightBlue; + public final static Color purple = new Color(128, 0, 128); + public final static Color PURPLE = purple; + public final static Color indigo = new Color(75, 0, 130); + public final static Color INDIGO = indigo; + + private int value; + + private static void testColorValueRange(int r, int g, int b, int a) { + if ( a < 0 || a > 255 || r < 0 || r > 255 || g < 0 || g > 255 || b < 0 || b > 255) { + throw new IllegalArgumentException("Color parameter outside of 0 to 255 range"); + } + } + + private static void testColorValueRange(float r, float g, float b, float a) { + if ( a < 0.0 || a > 1.0 || r < 0.0 || r > 1.0 || g < 0.0 || g > 1.0 || b < 0.0 || b > 1.0) { + throw new IllegalArgumentException("Color parameter outside of 0.0 to 1.0 range"); + } + } + + public Color(int r, int g, int b, int a) { + value = ((a & 0xFF) << 24) | + ((r & 0xFF) << 16) | + ((g & 0xFF) << 8) | + ((b & 0xFF)); + testColorValueRange(r,g,b,a); + } + + public Color(int r, int g, int b) { + this(r, g, b, 255); + } + + public Color(int rgb) { + value = 0xff000000 | rgb; + } + + public Color(int rgba, boolean hasalpha) { + if (hasalpha) { + value = rgba; + } else { + value = 0xff000000 | rgba; + } + } + + public Color(float r, float g, float b) { + this( (int) (r*255+0.5), (int) (g*255+0.5), (int) (b*255+0.5)); + testColorValueRange(r,g,b,1.0f); + } + + public Color(float r, float g, float b, float a) { + this((int)(r*255+0.5), (int)(g*255+0.5), (int)(b*255+0.5), (int)(a*255+0.5)); + } + + public Color(java.awt.Color awtColor) { + this(awtColor.getRed(), awtColor.getGreen(), awtColor.getBlue(), awtColor.getAlpha()); + } + + public int getRed() { + return (getRGB() >> 16) & 0xFF; + } + + public int getGreen() { + return (getRGB() >> 8) & 0xFF; + } + + public int getBlue() { + return (getRGB()) & 0xFF; + } + + public int getRGB() { + return value; + } + + @Override + public int hashCode() { + return value; + } + + @Override + public boolean equals(Object obj) { + return obj instanceof Color && ((Color)obj).getRGB() == this.getRGB(); + } + + @Override + public String toString() { + return getClass().getName() + "[r=" + getRed() + ",g=" + getGreen() + ",b=" + getBlue() + "]"; + } + + public static Color decode(String nm) throws NumberFormatException { + Integer intval = Integer.decode(nm); + int i = intval; + return new Color((i >> 16) & 0xFF, (i >> 8) & 0xFF, i & 0xFF); + } +} diff --git a/base/src/main/java/com/twosigma/beakerx/chart/Filter.java b/base/src/main/java/com/twosigma/beakerx/chart/Filter.java new file mode 100644 index 0000000..b81b912 --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/chart/Filter.java @@ -0,0 +1,41 @@ +/* + * Copyright 2014 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.chart; + +public enum Filter { + + AREA("area"), + LINE("line"), + BAR("bar"), + BOX("box"), + POINT("point"), + STEAM("stem"), + STEAM_PLUS("stem+"), + RIVER("river"); + + private String text; + + Filter(String text) { + this.text = text; + } + + public String getText() { + return text; + } + +} diff --git a/base/src/main/java/com/twosigma/beakerx/chart/GradientColor.java b/base/src/main/java/com/twosigma/beakerx/chart/GradientColor.java new file mode 100644 index 0000000..5a9bff3 --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/chart/GradientColor.java @@ -0,0 +1,70 @@ +/* + * Copyright 2014 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.chart; + + +import java.io.Serializable; +import java.util.List; + +public class GradientColor implements Serializable{ + public final static GradientColor BROWN_RED_YELLOW = new GradientColor(new Color[]{ new Color(120, 0, 4), + new Color(241, 88, 6), + new Color(255, 206, 31)}); + public final static GradientColor GREEN_YELLOW_WHITE = new GradientColor(new Color[]{ new Color(0, 170, 0), + new Color(102, 204, 0), + new Color(238, 238, 0), + new Color(238, 187, 68), + new Color(238, 187, 153), + new Color(255, 255, 255)}); + public final static GradientColor WHITE_BLUE = new GradientColor(new Color[]{ new Color(255, 255, 217), + new Color(237, 248, 177), + new Color(199, 233, 180), + new Color(127, 205, 187), + new Color(65, 182, 196), + new Color(29, 145, 192), + new Color(34, 94, 168), + new Color(37, 52, 148), + new Color(8, 29, 88)}); + + private Color[] colors; + + protected GradientColor(Color[] colors){ + this.colors = colors; + } + + public GradientColor(List colors){ + if (!colors.isEmpty()) { + this.colors = new Color[colors.size()]; + for (int i = 0; i < colors.size(); i++) { + Object c = colors.get(i); + if (c instanceof Color) { + this.colors[i] = (Color) c; + } else if (c instanceof java.awt.Color) { + this.colors[i] = new Color((java.awt.Color) c); + } else { + throw new IllegalArgumentException("GradientColor takes List of Color"); + } + } + } else { + this.colors = GradientColor.BROWN_RED_YELLOW.getColors(); + } + } + + public Color[] getColors() { + return colors; + } + +} diff --git a/base/src/main/java/com/twosigma/beakerx/chart/Graphics.java b/base/src/main/java/com/twosigma/beakerx/chart/Graphics.java new file mode 100644 index 0000000..c475f75 --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/chart/Graphics.java @@ -0,0 +1,163 @@ +/* + * Copyright 2014 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.chart; + +import org.apache.commons.lang3.SerializationUtils; +import org.apache.commons.lang3.StringUtils; + +import com.twosigma.beakerx.chart.actions.GraphicsActionListener; +import com.twosigma.beakerx.chart.actions.GraphicsActionObject; +import com.twosigma.beakerx.message.Message; +import com.twosigma.beakerx.mimetype.MIMEContainer; + +import java.io.Serializable; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +import static com.twosigma.beakerx.widget.CompiledCodeRunner.runCompiledCode; + +public abstract class Graphics implements Serializable, Cloneable { + + private static final long serialVersionUID = -1878979081955090695L; + + private final String uid; + private boolean visible = true; + private String yAxisName = null; + private GraphicsActionListener onClickListener; + private String clickTag; + private Map onKeyListeners = new HashMap(); + private Map keyTags = new HashMap(); + + public Graphics() { + this.uid = UUID.randomUUID().toString(); + } + + public void setVisible(boolean visible) { + this.visible = visible; + } + + public Boolean getVisible() { + return this.visible; + } + + public void setYAxis(String yAxisName) { + this.yAxisName = yAxisName; + } + + public void setyAxis(String yAxisName) { + this.yAxisName = yAxisName; + } + + public String getYAxis() { + return yAxisName; + } + + public String getyAxis() { + return getYAxis(); + } + + public String getUid() { + return uid; + } + + public boolean hasClickAction() { + return onClickListener != null || StringUtils.isNotEmpty(clickTag); + } + + public String getClickTag() { + return clickTag; + } + + public Map getKeyTags() { + return this.keyTags; + } + + public Object[] getKeys() { + return this.onKeyListeners.keySet().toArray(); + } + + public Graphics onClick(GraphicsActionListener onClickListener) { + this.onClickListener = onClickListener; + return this; + } + + public Graphics onClick(String tag) { + this.clickTag = tag; + return this; + } + + public void fireClick(GraphicsActionObject actionObject, Message message) { + if (onClickListener != null) { + runCompiledCode( + message, + params -> { + GraphicsActionObject ao = (GraphicsActionObject) params[0]; + ao.setGraphics(this); + onClickListener.execute(ao); + return MIMEContainer.HIDDEN; + }, + actionObject); + } + } + + public Graphics onKey(String key, GraphicsActionListener listener) { + this.onKeyListeners.put(key, listener); + return this; + } + + public Graphics onKey(KeyboardCodes key, GraphicsActionListener listener) { + this.onKeyListeners.put(key.name(), listener); + return this; + } + + public Graphics onKey(String key, String tag) { + this.keyTags.put(key, tag); + return this; + } + + public Graphics onKey(KeyboardCodes key, String tag) { + this.keyTags.put(key.name(), tag); + return this; + } + + public void fireOnKey(String key, GraphicsActionObject actionObject, Message message) { + GraphicsActionListener listener = onKeyListeners.get(key); + if (listener != null) { + runCompiledCode( + message, + params -> { + GraphicsActionListener listener1 = (GraphicsActionListener) params[0]; + GraphicsActionObject ao = (GraphicsActionObject) params[1]; + ao.setGraphics(this); + listener1.execute(ao); + return MIMEContainer.HIDDEN; + }, + listener, + actionObject); + } + } + + @Override + public Object clone() throws CloneNotSupportedException { + return SerializationUtils.clone(this); + } + + abstract public void setColori(Color color); + + abstract public Color getColor(); +} diff --git a/base/src/main/java/com/twosigma/beakerx/chart/ItemLabelBuilder.java b/base/src/main/java/com/twosigma/beakerx/chart/ItemLabelBuilder.java new file mode 100644 index 0000000..db53e38 --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/chart/ItemLabelBuilder.java @@ -0,0 +1,52 @@ +/* + * Copyright 2014 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.chart; + +public abstract class ItemLabelBuilder { + + public Object call(Object value) { + return null; + } + + public Object call(Object value, Object base) { + return null; + } + + public Object call(Object value, Object base, Object series) { + return null; + } + + public Object call(Object value, Object base, Object series, Object category) { + return null; + } + + public Object call(Object value, Object base, Object series, Object category, Object row) { + return null; + } + + public Object call(Object value, + Object base, + Object series, + Object category, + Object row, + Object column) { + return null; + } + + public abstract int getMaximumNumberOfParameters(); +} + + diff --git a/base/src/main/java/com/twosigma/beakerx/chart/KeyboardCodes.java b/base/src/main/java/com/twosigma/beakerx/chart/KeyboardCodes.java new file mode 100644 index 0000000..0d5d2a0 --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/chart/KeyboardCodes.java @@ -0,0 +1,70 @@ +/* + * Copyright 2014 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.chart; + +public enum KeyboardCodes { + + BACKSPACE, + TAB, + ENTER, + SHIFT, + CTRL, + ALT, + PAUSE_BREAK, + CAPS_LOCK, + ESCAPE, + SPACE, + PAGE_UP, + PAGE_DOWN, + END, + HOME, + LEFT_ARROW, + UP_ARROW, + RIGHT_ARROW, + DOWN_ARROW, + INSERT, + DELETE, + MULTIPLY, + ADD, + SUBTRACT, + DECIMAL_POINT, + DIVIDE, + F1, + F2, + F3, + F4, + F5, + F6, + F7, + F8, + F9, + F10, + F11, + F12, + NUM_LOCK, + SCROLL_LOCK, + EQUAL_SIGN, + COMMA, + DASH, + PERIOD, + FORWARD_SLASH, + GRAVE_ACCENT, + OPEN_BRACKET, + BACK_SLASH, + CLOSE_BRAKET, + SINGLE_QUOTE + +} diff --git a/base/src/main/java/com/twosigma/beakerx/chart/ListColorConverter.java b/base/src/main/java/com/twosigma/beakerx/chart/ListColorConverter.java new file mode 100644 index 0000000..7784f8a --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/chart/ListColorConverter.java @@ -0,0 +1,37 @@ +/* + * Copyright 2017 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.chart; + +import java.util.ArrayList; +import java.util.List; + +public class ListColorConverter { + + public static List convert(List colorList) { + List colors = new ArrayList<>(colorList.size()); + for (Object c : colorList) { + if (c instanceof Color) { + colors.add((Color) c); + } else if (c instanceof java.awt.Color) { + colors.add(new Color((java.awt.Color) c)); + } else { + throw new IllegalArgumentException("setColor takes Color or List of Color"); + } + } + return colors; + } + +} diff --git a/base/src/main/java/com/twosigma/beakerx/chart/ToolTipBuilder.java b/base/src/main/java/com/twosigma/beakerx/chart/ToolTipBuilder.java new file mode 100644 index 0000000..efa3bdd --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/chart/ToolTipBuilder.java @@ -0,0 +1,42 @@ +/* + * Copyright 2014 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.chart; + +public abstract class ToolTipBuilder { + public Object call(Object x) { + return null; + } + + public Object call(Object x, Object y) { + return null; + } + + public Object call(Object x, Object y, Object base) { + return null; + } + + public Object call(Object x, Object y, Object base, Object index) { + return null; + } + + public Object call(Object x, Object y, Object base, Object index, Object displayName) { + return null; + } + + public abstract int getMaximumNumberOfParameters(); +} + + diff --git a/base/src/main/java/com/twosigma/beakerx/chart/actions/CategoryGraphicsActionObject.java b/base/src/main/java/com/twosigma/beakerx/chart/actions/CategoryGraphicsActionObject.java new file mode 100644 index 0000000..9dfe47c --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/chart/actions/CategoryGraphicsActionObject.java @@ -0,0 +1,41 @@ +/* + * Copyright 2014 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.chart.actions; + +public class CategoryGraphicsActionObject extends GraphicsActionObject { + + private static final long serialVersionUID = -5089641975683705334L; + + private int category; + private int series; + + public int getCategory() { + return category; + } + + public void setCategory(int category) { + this.category = category; + } + + public int getSeries() { + return series; + } + + public void setSeries(int series) { + this.series = series; + } +} \ No newline at end of file diff --git a/base/src/main/java/com/twosigma/beakerx/chart/actions/ChartObjectManager.java b/base/src/main/java/com/twosigma/beakerx/chart/actions/ChartObjectManager.java new file mode 100644 index 0000000..9114829 --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/chart/actions/ChartObjectManager.java @@ -0,0 +1,36 @@ +/* + * Copyright 2015 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.chart.actions; + +import com.twosigma.beakerx.chart.ChartDetails; + +import java.util.HashMap; +import java.util.Map; + +public class ChartObjectManager { + /* plot id -> plot object */ + private final Map charts = new HashMap<>(); + + public void registerChart(final String id, final ChartDetails chart) { + charts.put(id, chart); + } + + public ChartDetails getChart(final String id) { + return charts.get(id); + } + +} diff --git a/base/src/main/java/com/twosigma/beakerx/chart/actions/CombinedPlotActionObject.java b/base/src/main/java/com/twosigma/beakerx/chart/actions/CombinedPlotActionObject.java new file mode 100644 index 0000000..d83d472 --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/chart/actions/CombinedPlotActionObject.java @@ -0,0 +1,31 @@ +/* + * Copyright 2014 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.chart.actions; + +public class CombinedPlotActionObject extends XYGraphicsActionObject { + + private static final long serialVersionUID = -7537934020334107816L; + private int subplotIndex; + + public int getSubplotIndex() { + return subplotIndex; + } + + public void setSubplotIndex(int subplotIndex) { + this.subplotIndex = subplotIndex; + } + +} \ No newline at end of file diff --git a/base/src/main/java/com/twosigma/beakerx/chart/actions/GraphicsActionListener.java b/base/src/main/java/com/twosigma/beakerx/chart/actions/GraphicsActionListener.java new file mode 100644 index 0000000..37cfc53 --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/chart/actions/GraphicsActionListener.java @@ -0,0 +1,23 @@ +/* + * Copyright 2014 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.chart.actions; + +/* + * Interface for Chart graphics interactions + */ +public interface GraphicsActionListener { + void execute(GraphicsActionObject actionObject); +} diff --git a/base/src/main/java/com/twosigma/beakerx/chart/actions/GraphicsActionObject.java b/base/src/main/java/com/twosigma/beakerx/chart/actions/GraphicsActionObject.java new file mode 100644 index 0000000..e3491d5 --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/chart/actions/GraphicsActionObject.java @@ -0,0 +1,66 @@ +/* + * Copyright 2014 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.chart.actions; + +import com.twosigma.beakerx.chart.Graphics; +import com.twosigma.beakerx.widget.CommActions; + +import java.io.Serializable; + +public abstract class GraphicsActionObject implements Serializable{ + + private static final long serialVersionUID = -1010209669334228815L; + + private Graphics graphics; + private CommActions actionType; + private String key; + private String tag; + + + public Graphics getGraphics() { + return graphics; + } + + public void setGraphics(Graphics graphics) { + this.graphics = graphics; + } + + public CommActions getActionType() { + return actionType; + } + + public void setActionType(CommActions actionType) { + this.actionType = actionType; + } + + public String getKey() { + return key; + } + + public void setKey(String key) { + this.key = key; + } + + public String getTag() { + return tag; + } + + public void setTag(String tag) { + this.tag = tag; + } + +} \ No newline at end of file diff --git a/base/src/main/java/com/twosigma/beakerx/chart/actions/XYGraphicsActionObject.java b/base/src/main/java/com/twosigma/beakerx/chart/actions/XYGraphicsActionObject.java new file mode 100644 index 0000000..872a588 --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/chart/actions/XYGraphicsActionObject.java @@ -0,0 +1,32 @@ +/* + * Copyright 2014 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.chart.actions; + +public class XYGraphicsActionObject extends GraphicsActionObject { + + private static final long serialVersionUID = -1993185683556266629L; + private int index; + + public int getIndex() { + return index; + } + + public void setIndex(int index) { + this.index = index; + } + +} \ No newline at end of file diff --git a/base/src/main/java/com/twosigma/beakerx/chart/categoryplot/CategoryPlot.java b/base/src/main/java/com/twosigma/beakerx/chart/categoryplot/CategoryPlot.java new file mode 100644 index 0000000..29ff85c --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/chart/categoryplot/CategoryPlot.java @@ -0,0 +1,117 @@ +/* + * Copyright 2014 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.chart.categoryplot; + +import com.twosigma.beakerx.chart.AbstractChart; +import com.twosigma.beakerx.chart.ChartToJson; +import com.twosigma.beakerx.chart.categoryplot.plotitem.CategoryGraphics; +import com.twosigma.beakerx.chart.xychart.plotitem.PlotOrientationType; +import java.util.ArrayList; +import java.util.List; + +import static com.twosigma.beakerx.widget.BeakerxPlot.MODEL_NAME_VALUE; +import static com.twosigma.beakerx.widget.BeakerxPlot.VIEW_NAME_VALUE; + +public class CategoryPlot extends AbstractChart { + private final List categoryGraphics = new ArrayList<>(); + private List categoryNames = new ArrayList<>(); + private PlotOrientationType orientation = PlotOrientationType.VERTICAL; + private double categoryMargin = 0.2; + private double categoryNamesLabelAngle = 0; + + public CategoryPlot() { + super(); + openComm(); + } + + @Override + public String getModelNameValue() { + return MODEL_NAME_VALUE; + } + + @Override + public String getViewNameValue() { + return VIEW_NAME_VALUE; + } + + public CategoryPlot leftShift(CategoryGraphics graphics) { + return add(graphics); + } + + public List getGraphics() { + return this.categoryGraphics; + } + + public CategoryPlot add(CategoryGraphics graphics) { + this.categoryGraphics.add(graphics); + sendModelUpdate(ChartToJson.serializeCategoryGraphics(this.categoryGraphics)); + return this; + } + + @Override + public CategoryPlot add(List items) { + for (Object o : items) { + if (o instanceof CategoryGraphics) { + add((CategoryGraphics) o); + } else { + super.add(items); + } + } + return this; + } + + public List getCategoryNames() { + return categoryNames; + } + + public CategoryPlot setCategoryNames(List categoryNames) { + this.categoryNames = categoryNames; + sendModelUpdate(ChartToJson.serializeCategoryNames(this.categoryNames)); + return this; + } + + public List getCategoryGraphics() { + return categoryGraphics; + } + + public PlotOrientationType getOrientation() { + return orientation; + } + + public void setOrientation(PlotOrientationType orientation) { + this.orientation = orientation; + sendModelUpdate(ChartToJson.serializePlotOrientationType(this.orientation)); + } + + public double getCategoryMargin() { + return categoryMargin; + } + + public void setCategoryMargin(double categoryMargin) { + this.categoryMargin = categoryMargin; + sendModelUpdate(ChartToJson.serializeCategoryMargin(this.categoryMargin)); + } + + public double getCategoryNamesLabelAngle() { + return categoryNamesLabelAngle; + } + + public void setCategoryNamesLabelAngle(double categoryNamesLabelAngle) { + this.categoryNamesLabelAngle = categoryNamesLabelAngle; + sendModelUpdate(ChartToJson.serializeCategoryNamesLabelAngle(this.categoryNamesLabelAngle)); + } +} diff --git a/base/src/main/java/com/twosigma/beakerx/chart/categoryplot/plotitem/BasedCategoryGraphics.java b/base/src/main/java/com/twosigma/beakerx/chart/categoryplot/plotitem/BasedCategoryGraphics.java new file mode 100644 index 0000000..365c6bd --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/chart/categoryplot/plotitem/BasedCategoryGraphics.java @@ -0,0 +1,52 @@ +/* + * Copyright 2017 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.chart.categoryplot.plotitem; + +import java.util.List; +import java.util.function.Predicate; + +public abstract class BasedCategoryGraphics extends CategoryGraphics { + private Number baseBase = 0.0d; + private List bases; + + public void setBase(Number base) { + this.baseBase = base.floatValue(); + } + + public void setBase(List base) { + Predicate number = o -> o instanceof Number; + Predicate listOfNumber = o -> o instanceof List && + ((List)o).stream().allMatch(number); + if (base.stream().allMatch(number.or(listOfNumber))) { + setBases(base); + } else { + throw new IllegalArgumentException("List of bases must consist of Numbers or Lists of Numbers"); + } + } + + private void setBases(List bases) { + this.bases = bases; + } + + public Number getBase() { + return this.baseBase; + } + + public List getBases() { + return this.bases; + } +} diff --git a/base/src/main/java/com/twosigma/beakerx/chart/categoryplot/plotitem/CategoryArea.java b/base/src/main/java/com/twosigma/beakerx/chart/categoryplot/plotitem/CategoryArea.java new file mode 100644 index 0000000..65cc5dc --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/chart/categoryplot/plotitem/CategoryArea.java @@ -0,0 +1,130 @@ +/* + * Copyright 2017 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.chart.categoryplot.plotitem; + +import com.twosigma.beakerx.chart.ChartUtils; +import com.twosigma.beakerx.chart.Color; +import com.twosigma.beakerx.chart.xychart.plotitem.LabelPositionType; +import java.util.List; + +public class CategoryArea extends BasedCategoryGraphics { + + private Number baseWidth; + private List widths; + private Color baseOutlineColor; + private List outlineColors; + private Boolean baseFill; + private List fills; + private Boolean baseOutline = false; + private List outlines; + + private LabelPositionType labelPosition = LabelPositionType.CENTER; + + public void setWidth(Number width) { + this.baseWidth = width.floatValue(); + } + + public void setWidth(List width) { + setWidths(width); + } + + private void setWidths(List widths) { + this.widths = widths; + } + + public Number getWidth() { + return this.baseWidth; + } + + public List getWidths() { + return this.widths; + } + + public void setOutlineColor(Color color) { + this.baseOutlineColor = color; + } + + public void setOutlineColor(java.awt.Color color) { + this.baseOutlineColor = new Color(color); + } + + public void setOutlineColor(List colors) { + setOutlineColors(colors); + } + + private void setOutlineColors(List colors) { + if (colors != null) { + this.outlineColors = ChartUtils + .convertColors(colors, "setOutlineColor takes Color or List of Color"); + } else { + this.outlineColors = null; + } + } + + public Color getOutlineColor() { + return this.baseOutlineColor; + } + + public List getOutlineColors() { + return this.outlineColors; + } + + public void setFill(Boolean fill) { + this.baseFill = fill; + } + + public void setFill(List fill) { + setFills(fill); + } + + private void setFills(List fills) { + this.fills = fills; + } + + public Boolean getFill() { + return this.baseFill; + } + + public List getFills() { + return this.fills; + } + + public void setDrawOutline(Boolean outline) { + this.baseOutline = outline; + } + + public void setDrawOutline(List outline) { + this.outlines = outline; + } + + public List getDrawOutlines() { + return this.outlines; + } + + public Boolean getDrawOutline() { + return this.baseOutline; + } + + public LabelPositionType getLabelPosition() { + return labelPosition; + } + + public void setLabelPosition(LabelPositionType labelPosition) { + this.labelPosition = labelPosition; + } + +} diff --git a/base/src/main/java/com/twosigma/beakerx/chart/categoryplot/plotitem/CategoryBars.java b/base/src/main/java/com/twosigma/beakerx/chart/categoryplot/plotitem/CategoryBars.java new file mode 100644 index 0000000..8a07959 --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/chart/categoryplot/plotitem/CategoryBars.java @@ -0,0 +1,131 @@ +/* + * Copyright 2014 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.chart.categoryplot.plotitem; + +import com.twosigma.beakerx.chart.ChartUtils; +import com.twosigma.beakerx.chart.Color; +import com.twosigma.beakerx.chart.xychart.plotitem.LabelPositionType; + +import java.util.List; + +public class CategoryBars extends BasedCategoryGraphics { + + private Number baseWidth; + private List widths; + private Color baseOutlineColor; + private List outlineColors; + private Boolean baseFill; + private List fills; + private Boolean baseOutline = false; + private List outlines; + + private LabelPositionType labelPosition = LabelPositionType.CENTER; + + public void setWidth(Number width) { + this.baseWidth = width.floatValue(); + } + + public void setWidth(List width) { + setWidths(width); + } + + private void setWidths(List widths) { + this.widths = widths; + } + + public Number getWidth() { + return this.baseWidth; + } + + public List getWidths() { + return this.widths; + } + + private void setOutlineColors(List colors) { + if (colors != null) { + this.outlineColors = ChartUtils.convertColors(colors, "setOutlineColor takes Color or List of Color"); + } else { + this.outlineColors = null; + } + } + + public Color getOutlineColor() { + return this.baseOutlineColor; + } + + public List getOutlineColors() { + return this.outlineColors; + } + + public void setFill(Boolean fill) { + this.baseFill = fill; + } + + public void setFill(List fill) { + setFills(fill); + } + + private void setFills(List fills) { + this.fills = fills; + } + + public Boolean getFill() { + return this.baseFill; + } + + public List getFills() { + return this.fills; + } + + public void setOutlineColor(Color color) { + this.baseOutlineColor = color; + } + + public void setOutlineColor(java.awt.Color color) { + this.baseOutlineColor = new Color(color); + } + + public void setOutlineColor(List colors) { + setOutlineColors(colors); + } + + public void setDrawOutline(Boolean outline) { + this.baseOutline = outline; + } + + public void setDrawOutline(List outline) { + this.outlines = outline; + } + + public List getDrawOutlines() { + return this.outlines; + } + + public Boolean getDrawOutline() { + return this.baseOutline; + } + + public LabelPositionType getLabelPosition() { + return labelPosition; + } + + public void setLabelPosition(LabelPositionType labelPosition) { + this.labelPosition = labelPosition; + } + + +} diff --git a/base/src/main/java/com/twosigma/beakerx/chart/categoryplot/plotitem/CategoryGraphics.java b/base/src/main/java/com/twosigma/beakerx/chart/categoryplot/plotitem/CategoryGraphics.java new file mode 100644 index 0000000..c221699 --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/chart/categoryplot/plotitem/CategoryGraphics.java @@ -0,0 +1,245 @@ +/* + * Copyright 2014 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.chart.categoryplot.plotitem; + +import com.twosigma.beakerx.chart.ChartUtils; +import com.twosigma.beakerx.chart.Color; +import com.twosigma.beakerx.chart.Graphics; +import com.twosigma.beakerx.chart.categoryplot.CategoryPlot; +import org.apache.commons.lang3.ArrayUtils; + +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.List; + +public abstract class CategoryGraphics extends Graphics { + private Number[][] value; + private List seriesNames; + private Color baseColor; + private List colors; + private Object itemLabelBuilder; + private String[][] itemLabels; + + private boolean showItemLabel = false; + private boolean centerSeries = false; + private boolean useToolTip = true; + + protected List getBases() { + return null; + } + + protected Number getBase() { + return null; + } + + public void createItemLabels(CategoryPlot plot) { + if (itemLabelBuilder == null || value == null) { + this.itemLabels = null; + return; + } + + int itemCategoriesNumber = value[0].length; + int itemSeriesNumber = value.length; + + String[][] itemLabels = new String[itemCategoriesNumber][itemSeriesNumber]; + + try { + Class clazz = itemLabelBuilder.getClass(); + Method getMaximumNumberOfParameters = clazz.getMethod("getMaximumNumberOfParameters"); + getMaximumNumberOfParameters.setAccessible(true); + int numberOfParameters = (int) getMaximumNumberOfParameters.invoke(itemLabelBuilder); + + + for (int column = 0; column < itemCategoriesNumber; column++) { + List categoryNames = plot.getCategoryNames(); + String category = categoryNames != null && categoryNames.size() > column ? + categoryNames.get(column) : null; + + for (int row = 0; row < itemSeriesNumber; row++) { + + Number _value = value[row][column]; + String series = seriesNames != null && seriesNames.size() > row ? seriesNames.get(row) : null; + + Method call; + if (numberOfParameters == 1) { + call = clazz.getMethod("call", Object.class); + call.setAccessible(true); + itemLabels[column][row] = String.valueOf(call.invoke(itemLabelBuilder, _value)); + } else { + Object base = getBases() != null ? + getBases().get(row) instanceof List ? + ((List) getBases().get(row)).get(column) : getBases().get(row) : getBase(); + if (numberOfParameters == 2) { + call = clazz.getMethod("call", Object.class, Object.class); + call.setAccessible(true); + itemLabels[column][row] = String.valueOf(call.invoke(itemLabelBuilder, + _value, + base)); + } else if (numberOfParameters == 3) { + call = clazz.getMethod("call", Object.class, Object.class, Object.class); + call.setAccessible(true); + itemLabels[column][row] = String.valueOf(call.invoke(itemLabelBuilder, + _value, + base, + series)); + } else if (numberOfParameters == 4) { + call = clazz.getMethod("call", + Object.class, + Object.class, + Object.class, + Object.class); + call.setAccessible(true); + itemLabels[column][row] = String.valueOf(call.invoke(itemLabelBuilder, + _value, + base, + series, + category)); + } else if (numberOfParameters == 5) { + call = clazz.getMethod("call", + Object.class, + Object.class, + Object.class, + Object.class, + Object.class); + call.setAccessible(true); + itemLabels[column][row] = String.valueOf(call.invoke(itemLabelBuilder, + _value, + base, + series, + category, + row)); + } else if (numberOfParameters == 6) { + call = clazz.getMethod("call", + Object.class, + Object.class, + Object.class, + Object.class, + Object.class, + Object.class); + call.setAccessible(true); + itemLabels[column][row] = String.valueOf(call.invoke(itemLabelBuilder, + _value, + base, + series, + category, + row, + column)); + } + } + + } + } + } catch (Throwable x) { + throw new RuntimeException("Can not create item labels.", x); + } + + this.itemLabels = itemLabels; + } + + public String[][] getItemLabels() { + return itemLabels; + } + + public void setItemLabel(Object itemLabel) { + itemLabelBuilder = itemLabel; + } + + public void setColor(Color color) { + this.baseColor = color; + } + + public void setColor(java.awt.Color color) { + setColor(new Color(color)); + } + + public void setColor(List colorList) { + setColors(colorList); + } + + private void setColors(List colorList) { + if (colorList != null) { + this.colors = ChartUtils.convertColors(colorList, "setColor takes Color or List of Color"); + } else { + this.colors = null; + } + } + + public List getColors() { + return this.colors; + } + + @Override + public void setColori(Color color) { + this.baseColor = color; + } + + @Override + public Color getColor() { + return this.baseColor; + } + + public Number[][] getValue() { + return value; + } + + public void setValue(Object[] value) { + if (value != null && ArrayUtils.isNotEmpty(value)) { + if (value[0] instanceof List) { + this.value = new Number[value.length][]; + for (int i = 0; i < value.length; i++) { + List a = (List) value[i]; + this.value[i] = a.toArray(new Number[a.size()]); + } + } else { + this.value = new Number[][]{Arrays.copyOf(value, value.length, Number[].class)}; + } + } + } + + public List getSeriesNames() { + return seriesNames; + } + + public void setSeriesNames(List seriesNames) { + this.seriesNames = seriesNames; + } + + public boolean getShowItemLabel() { + return showItemLabel; + } + + public void setShowItemLabel(boolean showItemLabel) { + this.showItemLabel = showItemLabel; + } + + public boolean getCenterSeries() { + return centerSeries; + } + + public void setCenterSeries(boolean centerSeries) { + this.centerSeries = centerSeries; + } + + public void setUseToolTip(boolean useToolTip) { + this.useToolTip = useToolTip; + } + + public Boolean getUseToolTip() { + return this.useToolTip; + } +} diff --git a/base/src/main/java/com/twosigma/beakerx/chart/categoryplot/plotitem/CategoryLines.java b/base/src/main/java/com/twosigma/beakerx/chart/categoryplot/plotitem/CategoryLines.java new file mode 100644 index 0000000..30ea78e --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/chart/categoryplot/plotitem/CategoryLines.java @@ -0,0 +1,72 @@ +/* + * Copyright 2014 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.chart.categoryplot.plotitem; + + +import com.twosigma.beakerx.chart.xychart.plotitem.StrokeType; + +import java.util.List; + +public class CategoryLines extends CategoryGraphics { + private Float width = 1.5f; + private Integer interpolation; + + private StrokeType baseStyle = StrokeType.SOLID; + private List styles; + + public void setWidth(Float width) { + this.width = width; + } + + public Float getWidth() { + return this.width; + } + + public void setStyle(StrokeType style) { + this.baseStyle = style; + } + + public void setStyle(List styles) { + setStyles(styles); + } + + private void setStyles(List styles) { + this.styles = styles; + } + + public StrokeType getStyle() { + return this.baseStyle; + } + + public List getStyles() { + return this.styles; + } + + public void setInterpolation(Integer interpolation) { + if (interpolation < 0 || interpolation > 2) { + throw new IllegalArgumentException( + "Line interpolation is limited to 0, 1, 2"); + } + + this.interpolation = interpolation; + } + + public Integer getInterpolation() { + return this.interpolation; + } +} diff --git a/base/src/main/java/com/twosigma/beakerx/chart/categoryplot/plotitem/CategoryPoints.java b/base/src/main/java/com/twosigma/beakerx/chart/categoryplot/plotitem/CategoryPoints.java new file mode 100644 index 0000000..67c6e41 --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/chart/categoryplot/plotitem/CategoryPoints.java @@ -0,0 +1,124 @@ +/* + * Copyright 2014 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.chart.categoryplot.plotitem; + + +import com.twosigma.beakerx.chart.ChartUtils; +import com.twosigma.beakerx.chart.Color; +import com.twosigma.beakerx.chart.xychart.plotitem.ShapeType; + +import java.util.List; + +public class CategoryPoints extends CategoryGraphics { + private float baseSize = 6.0f; + private List sizes; + private ShapeType baseShape = ShapeType.DEFAULT; + private List shapes; + private Boolean baseFill; + private List fills; + private Color baseOutlineColor; + private List outlineColors; + + public void setSize(Number size) { + this.baseSize = size.floatValue(); + } + + public void setSize(List sizes) { + setSizes(sizes); + } + + private void setSizes(List sizes) { + this.sizes = sizes; + } + + public float getSize() { + return this.baseSize; + } + + public List getSizes() { + return this.sizes; + } + + public void setShape(ShapeType shape) { + this.baseShape = shape; + } + + public void setShape(List shapes) { + setShapes(shapes); + } + + private void setShapes(List shapes) { + this.shapes = shapes; + } + + public ShapeType getShape() { + return this.baseShape; + } + + public List getShapes() { + return this.shapes; + } + + public void setFill(Boolean fill) { + this.baseFill = fill; + } + + public void setFill(List fill) { + setFills(fill); + } + + private void setFills(List fills) { + this.fills = fills; + } + + public Boolean getFill() { + return this.baseFill; + } + + public List getFills() { + return this.fills; + } + + public void setOutlineColor(Color color) { + this.baseOutlineColor = color; + } + + public void setOutlineColor(java.awt.Color color) { + this.baseOutlineColor = new Color(color); + } + + public void setOutlineColor(List colors) { + setOutlineColors(colors); + } + + private void setOutlineColors(List colors) { + if (colors != null) { + this.outlineColors = ChartUtils.convertColors(colors, "setOutlineColor takes Color or List of Color"); + } else { + this.outlineColors = null; + } + } + + public Color getOutlineColor() { + return this.baseOutlineColor; + } + + public List getOutlineColors() { + return this.outlineColors; + } +} diff --git a/base/src/main/java/com/twosigma/beakerx/chart/categoryplot/plotitem/CategoryStems.java b/base/src/main/java/com/twosigma/beakerx/chart/categoryplot/plotitem/CategoryStems.java new file mode 100644 index 0000000..fd335e1 --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/chart/categoryplot/plotitem/CategoryStems.java @@ -0,0 +1,57 @@ +/* + * Copyright 2014 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.chart.categoryplot.plotitem; + + +import com.twosigma.beakerx.chart.xychart.plotitem.StrokeType; + +import java.util.List; + +public class CategoryStems extends BasedCategoryGraphics { + private Float width = 1.5f; + private StrokeType baseStyle = StrokeType.SOLID; + private List styles; + + public void setWidth(Float width) { + this.width = width; + } + + public Float getWidth() { + return this.width; + } + + public void setStyle(StrokeType style) { + this.baseStyle = style; + } + + public void setStyle(List styles) { + setStyles(styles); + } + + private void setStyles(List styles) { + this.styles = styles; + } + + public StrokeType getStyle() { + return this.baseStyle; + } + + public List getStyles() { + return this.styles; + } +} diff --git a/base/src/main/java/com/twosigma/beakerx/chart/heatmap/HeatMap.java b/base/src/main/java/com/twosigma/beakerx/chart/heatmap/HeatMap.java new file mode 100644 index 0000000..d107c9b --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/chart/heatmap/HeatMap.java @@ -0,0 +1,77 @@ +/* + * Copyright 2014 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.chart.heatmap; + +import com.twosigma.beakerx.chart.AbstractChart; +import com.twosigma.beakerx.chart.ChartToJson; +import com.twosigma.beakerx.chart.GradientColor; +import com.twosigma.beakerx.chart.legend.LegendLayout; +import com.twosigma.beakerx.chart.legend.LegendPosition; + +import static com.twosigma.beakerx.widget.BeakerxPlot.MODEL_NAME_VALUE; +import static com.twosigma.beakerx.widget.BeakerxPlot.VIEW_NAME_VALUE; + +public class HeatMap extends AbstractChart { + + private Number[][] data; + private GradientColor color = GradientColor.BROWN_RED_YELLOW; + + public static final int ROWS_LIMIT = 100; + public static final int COLUMN_LIMIT = 100; + public static final int NUMBER_OF_NODES_LIMIT = ROWS_LIMIT * COLUMN_LIMIT; + + + public HeatMap() { + super(); + setXLowerMargin(0); + setXUpperMargin(0); + setYLowerMargin(0); + setYUpperMargin(0); + setLegendLayout(LegendLayout.HORIZONTAL); + setLegendPosition(LegendPosition.BOTTOM_RIGHT); + openComm(); + } + + @Override + public String getModelNameValue() { + return MODEL_NAME_VALUE; + } + + @Override + public String getViewNameValue() { + return VIEW_NAME_VALUE; + } + + + public void setColor(GradientColor color) { + this.color = color; + sendModelUpdate(ChartToJson.serializeHeatmapGradientColor(this.color)); + } + + public GradientColor getColor() { + return color; + } + + public Number[][] getData() { + return data; + } + + public void setData(Number[][] data) { + this.data = data; + sendModelUpdate(ChartToJson.serializeHeatmapData(this.data)); + } +} diff --git a/base/src/main/java/com/twosigma/beakerx/chart/histogram/Histogram.java b/base/src/main/java/com/twosigma/beakerx/chart/histogram/Histogram.java new file mode 100644 index 0000000..ca19c04 --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/chart/histogram/Histogram.java @@ -0,0 +1,208 @@ +/* + * Copyright 2014 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.chart.histogram; + +import com.twosigma.beakerx.chart.AbstractChart; +import com.twosigma.beakerx.chart.ChartToJson; +import com.twosigma.beakerx.chart.Color; +import com.twosigma.beakerx.chart.ListColorConverter; + +import java.util.List; + +import static com.twosigma.beakerx.widget.BeakerxPlot.MODEL_NAME_VALUE; +import static com.twosigma.beakerx.widget.BeakerxPlot.VIEW_NAME_VALUE; + +public class Histogram extends AbstractChart { + + public static final int ROWS_LIMIT = 1_000_000; + public static final int NUMBER_OF_POINTS_TO_DISPLAY = 10_000; + + public enum DisplayMode { + OVERLAP, + STACK, + SIDE_BY_SIDE + } + + private Integer rangeMin; + private Integer rangeMax; + private int binCount = 10; + private boolean rightClose; + private boolean cumulative; + private boolean normed; + protected Color baseColor; + private List colors; + private List data; + private List> listData; + private List names; + + private DisplayMode displayMode = DisplayMode.OVERLAP; + + public Histogram() { + super(); + openComm(); + } + + @Override + public String getModelNameValue() { + return MODEL_NAME_VALUE; + } + + @Override + public String getViewNameValue() { + return VIEW_NAME_VALUE; + } + + public Integer getRangeMin() { + return rangeMin; + } + + public void setRangeMin(Integer rangeMin) { + this.rangeMin = rangeMin; + } + + public Integer getRangeMax() { + return rangeMax; + } + + public void setRangeMax(Integer rangeMax) { + this.rangeMax = rangeMax; + } + + public int getBinCount() { + return binCount; + } + + public void setBinCount(int binCount) { + this.binCount = binCount; + sendModelUpdate(ChartToJson.serializeBinCount(this.binCount)); + } + + public boolean getRightClose() { + return rightClose; + } + + public void setRightClose(boolean rightClose) { + this.rightClose = rightClose; + } + + public boolean getCumulative() { + return cumulative; + } + + public void setCumulative(boolean cumulative) { + this.cumulative = cumulative; + sendModelUpdate(ChartToJson.serializeCumulative(this.cumulative)); + } + + public boolean getNormed() { + return normed; + } + + public void setNormed(boolean normed) { + this.normed = normed; + sendModelUpdate(ChartToJson.serializeNormed(this.normed)); + } + + public DisplayMode getDisplayMode() { + return displayMode; + } + + public void setDisplayMode(DisplayMode displayMode) { + this.displayMode = displayMode; + sendModelUpdate(ChartToJson.serializeDisplayMode(this.displayMode)); + } + + public boolean getLog() { + return getLogY(); + } + + public void setLog(boolean log) { + setLogY(log); + } + + @Override + public AbstractChart setLogY(boolean logY) { + this.yAxis.setLog(logY); + sendModelUpdate(ChartToJson.serializeHistogramLog(this.yAxis.getLog())); + return this; + } + + public void setColor(Color color) { + this.baseColor = color; + sendModelUpdate(ChartToJson.serializeColor(this.baseColor)); + } + + public void setColor(java.awt.Color color) { + setColor(new Color(color)); + } + + public void setColor(List colorList) { + setColors(colorList); + } + + private void setColors(List colorList) { + if (colorList != null) { + this.colors = ListColorConverter.convert(colorList); + sendModelUpdate(ChartToJson.serializeColors(this.colors)); + } else { + this.colors = null; + } + } + + public List getColors() { + return this.colors; + } + + public Color getColor() { + return this.baseColor; + } + + @SuppressWarnings("unchecked") + public void setData(List data) { + if (data.size() > 0) { + try { + if (data.get(0) instanceof List) { + this.listData = (List>) data; + sendModelUpdate(ChartToJson.serializeHistogramListData(this.listData)); + } else { + this.data = (List) data; + sendModelUpdate(ChartToJson.serializeHistogramData(this.data)); + } + } catch (Throwable x) { + throw new IllegalArgumentException( + "setData takes List of Number or List of List of Number"); + } + } + } + + public List getData() { + return data; + } + + public List> getListData() { + return listData; + } + + public List getNames() { + return names; + } + + public void setNames(List names) { + this.names = names; + sendModelUpdate(ChartToJson.serializeHistogramNames(this.names)); + } +} diff --git a/base/src/main/java/com/twosigma/beakerx/chart/legend/LegendLayout.java b/base/src/main/java/com/twosigma/beakerx/chart/legend/LegendLayout.java new file mode 100644 index 0000000..fae9c0f --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/chart/legend/LegendLayout.java @@ -0,0 +1,24 @@ +/* + * Copyright 2014 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.chart.legend; + +/** + * LegendLayout + */ +public enum LegendLayout { + HORIZONTAL, + VERTICAL +} diff --git a/base/src/main/java/com/twosigma/beakerx/chart/legend/LegendPosition.java b/base/src/main/java/com/twosigma/beakerx/chart/legend/LegendPosition.java new file mode 100644 index 0000000..15524c3 --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/chart/legend/LegendPosition.java @@ -0,0 +1,86 @@ +/* + * Copyright 2014 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.chart.legend; + +import org.apache.commons.lang3.ArrayUtils; + +public class LegendPosition implements java.io.Serializable { + + public final static LegendPosition TOP = new LegendPosition(Position.TOP); + public final static LegendPosition LEFT = new LegendPosition(Position.LEFT); + public final static LegendPosition BOTTOM = new LegendPosition(Position.BOTTOM); + public final static LegendPosition RIGHT = new LegendPosition(Position.RIGHT); + public final static LegendPosition TOP_LEFT = new LegendPosition(Position.TOP_LEFT); + public final static LegendPosition TOP_RIGHT = new LegendPosition(Position.TOP_RIGHT); + public final static LegendPosition BOTTOM_LEFT = new LegendPosition(Position.BOTTOM_LEFT); + public final static LegendPosition BOTTOM_RIGHT = new LegendPosition(Position.BOTTOM_RIGHT); + + public static enum Position { + TOP, + LEFT, + BOTTOM, + RIGHT, + TOP_LEFT, + TOP_RIGHT, + BOTTOM_LEFT, + BOTTOM_RIGHT + } + + private Position position; + private int x; + private int y; + + public LegendPosition() { + this.position = Position.TOP_RIGHT; + } + + public LegendPosition(Position position) { + this.position = position; + } + + public LegendPosition(int[] coordinates) { + if (!ArrayUtils.isEmpty(coordinates)) { + this.x = coordinates[0]; + if (coordinates.length > 1) { + this.y= coordinates[1]; + } + } + } + + public Position getPosition() { + return position; + } + + public void setPosition(Position position) { + this.position = position; + } + + public int getX() { + return x; + } + + public void setX(int x) { + this.x = x; + } + + public int getY() { + return y; + } + + public void setY(int y) { + this.y = y; + } +} diff --git a/base/src/main/java/com/twosigma/beakerx/chart/serializer/AbstractChartSerializer.java b/base/src/main/java/com/twosigma/beakerx/chart/serializer/AbstractChartSerializer.java new file mode 100644 index 0000000..08924e3 --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/chart/serializer/AbstractChartSerializer.java @@ -0,0 +1,70 @@ +/* + * Copyright 2014 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.chart.serializer; + + +import com.twosigma.beakerx.chart.AbstractChart; +import com.fasterxml.jackson.core.JsonGenerator; + +import java.io.IOException; + +public abstract class AbstractChartSerializer extends ChartSerializer { + + + public static final String DOMAIN_AXIS_LABEL = "domain_axis_label"; + public static final String Y_LABEL = "y_label"; + public static final String RANGE_AXES = "rangeAxes"; + public static final String OMIT_CHECKBOXES = "omit_checkboxes"; + public static final String Y_AUTO_RANGE_INCLUDES_ZERO = "y_auto_range_includes_zero"; + public static final String Y_LOWER_BOUND = "y_lower_bound"; + public static final String Y_UPPER_BOUND = "y_upper_bound"; + public static final String X_LOWER_MARGIN = "x_lower_margin"; + public static final String X_UPPER_MARGIN = "x_upper_margin"; + public static final String Y_AUTO_RANGE = "y_auto_range"; + public static final String Y_LOWER_MARGIN = "y_lower_margin"; + public static final String Y_UPPER_MARGIN = "y_upper_margin"; + public static final String CROSSHAIR = "crosshair"; + public static final String TIMEZONE = "timezone"; + public static final String LOG_Y = "log_y"; + public static final String AUTO_ZOOM = "auto_zoom"; + public static final String TOTAL_NUMBER_OF_POINTS = "totalNumberOfPoints"; + public static final String TOO_MANY_ROWS = "tooManyRows"; + public static final String ROWS_LIMIT_ITEMS = "rowsLimitItems"; + public static final String NUMBER_OF_POINTS_TO_DISPLAY = "numberOfPointsToDisplay"; + + + protected void serialize(T chart, JsonGenerator jgen) throws IOException { + + super.serialize(chart, jgen); + + jgen.writeObjectField(DOMAIN_AXIS_LABEL, chart.getXLabel()); + jgen.writeObjectField(Y_LABEL, chart.getYLabel()); + jgen.writeObjectField(RANGE_AXES, chart.getYAxes()); + jgen.writeObjectField(X_LOWER_MARGIN, chart.getXLowerMargin()); + jgen.writeObjectField(X_UPPER_MARGIN, chart.getXUpperMargin()); + jgen.writeObjectField(Y_AUTO_RANGE, chart.getYAutoRange()); + jgen.writeObjectField(Y_AUTO_RANGE_INCLUDES_ZERO, chart.getYAutoRangeIncludesZero()); + jgen.writeObjectField(Y_LOWER_MARGIN, chart.getYLowerMargin()); + jgen.writeObjectField(Y_UPPER_MARGIN, chart.getYUpperMargin()); + jgen.writeObjectField(Y_LOWER_BOUND, chart.getYLowerBound()); + jgen.writeObjectField(Y_UPPER_BOUND, chart.getYUpperBound()); + jgen.writeObjectField(LOG_Y, chart.getLogY()); + jgen.writeObjectField(TIMEZONE, chart.getTimeZone()); + jgen.writeObjectField(CROSSHAIR, chart.getCrosshair()); + jgen.writeObjectField(OMIT_CHECKBOXES, chart.getOmitCheckboxes()); + jgen.writeObjectField(AUTO_ZOOM, chart.getAutoZoom()); + } +} diff --git a/base/src/main/java/com/twosigma/beakerx/chart/serializer/AreaSerializer.java b/base/src/main/java/com/twosigma/beakerx/chart/serializer/AreaSerializer.java new file mode 100644 index 0000000..30a3125 --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/chart/serializer/AreaSerializer.java @@ -0,0 +1,49 @@ +/* + * Copyright 2014 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.chart.serializer; + +import com.twosigma.beakerx.chart.xychart.plotitem.Area; +import com.twosigma.beakerx.chart.Color; +import java.io.IOException; +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.SerializerProvider; + +/** + * AreaSerializer + * + */ +public class AreaSerializer extends BasedXYGraphicsSerializer { + + @Override + public void serialize(Area area, JsonGenerator jgen, SerializerProvider sp) + throws IOException, JsonProcessingException { + + jgen.writeStartObject(); + + super.serialize(area, jgen, sp); + + if (area.getColor() instanceof Color) { + jgen.writeObjectField("color", area.getColor()); + } + if (area.getInterpolation() != null) { + jgen.writeObjectField("interpolation", area.getInterpolation()); + } + jgen.writeEndObject(); + } + +} diff --git a/base/src/main/java/com/twosigma/beakerx/chart/serializer/BarsSerializer.java b/base/src/main/java/com/twosigma/beakerx/chart/serializer/BarsSerializer.java new file mode 100644 index 0000000..fd96b90 --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/chart/serializer/BarsSerializer.java @@ -0,0 +1,57 @@ +/* + * Copyright 2014 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.chart.serializer; + +import com.twosigma.beakerx.chart.xychart.plotitem.Bars; +import java.io.IOException; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.core.JsonProcessingException; + +/** + * PointsSerializer + * + */ +public class BarsSerializer extends BasedXYGraphicsSerializer { + + @Override + public void serialize(Bars bars, JsonGenerator jgen, SerializerProvider sp) + throws IOException { + + jgen.writeStartObject(); + + super.serialize(bars, jgen, sp); + + if (bars.getWidths() != null) { + jgen.writeObjectField("widths", bars.getWidths()); + } else { + jgen.writeObjectField("width", bars.getWidth()); + } + if (bars.getColors() != null) { + jgen.writeObjectField("colors", bars.getColors()); + } else { + jgen.writeObjectField("color", bars.getColor()); + } + if (bars.getOutlineColors() != null) { + jgen.writeObjectField("outline_colors", bars.getOutlineColors()); + } else { + jgen.writeObjectField("outline_color", bars.getOutlineColor()); + } + jgen.writeEndObject(); + } + +} diff --git a/base/src/main/java/com/twosigma/beakerx/chart/serializer/BasedXYGraphicsSerializer.java b/base/src/main/java/com/twosigma/beakerx/chart/serializer/BasedXYGraphicsSerializer.java new file mode 100644 index 0000000..36483e4 --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/chart/serializer/BasedXYGraphicsSerializer.java @@ -0,0 +1,41 @@ +/* + * Copyright 2014 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.chart.serializer; + +import com.twosigma.beakerx.chart.xychart.plotitem.BasedXYGraphics; +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.SerializerProvider; + +import java.io.IOException; + +public class BasedXYGraphicsSerializer extends XYGraphicsSerializer { + + @Override + public void serialize(T basedXYGraphics, JsonGenerator jgen, SerializerProvider sp) + throws IOException, JsonProcessingException { + + super.serialize(basedXYGraphics, jgen, sp); + + if (basedXYGraphics.getBases() != null) { + jgen.writeObjectField("bases", basedXYGraphics.getBases()); + } else { + jgen.writeObjectField("base", basedXYGraphics.getBase()); + } + + } + +} diff --git a/base/src/main/java/com/twosigma/beakerx/chart/serializer/CategoryAreasSerializer.java b/base/src/main/java/com/twosigma/beakerx/chart/serializer/CategoryAreasSerializer.java new file mode 100644 index 0000000..2901462 --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/chart/serializer/CategoryAreasSerializer.java @@ -0,0 +1,62 @@ +/* + * Copyright 2017 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.chart.serializer; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.twosigma.beakerx.chart.categoryplot.plotitem.CategoryArea; +import java.io.IOException; + +public class CategoryAreasSerializer extends CategoryGraphicsSerializer { + + @Override + public void serialize(CategoryArea categoryArea, JsonGenerator jgen, SerializerProvider provider) + throws IOException { + jgen.writeStartObject(); + + super.serialize(categoryArea, jgen, provider); + + if (categoryArea.getBases() != null) { + jgen.writeObjectField("bases", categoryArea.getBases()); + } else { + jgen.writeObjectField("base", categoryArea.getBase()); + } + if (categoryArea.getWidths() != null) { + jgen.writeObjectField("widths", categoryArea.getWidths()); + } else { + jgen.writeObjectField("width", categoryArea.getWidth()); + } + if (categoryArea.getOutlineColors() != null) { + jgen.writeObjectField("outline_colors", categoryArea.getOutlineColors()); + } else { + jgen.writeObjectField("outline_color", categoryArea.getOutlineColor()); + } + if (categoryArea.getFills() != null) { + jgen.writeObjectField("fills", categoryArea.getFills()); + } else { + jgen.writeObjectField("fill", categoryArea.getFill()); + } + if (categoryArea.getDrawOutlines() != null) { + jgen.writeObjectField("outlines", categoryArea.getDrawOutlines()); + } else { + jgen.writeObjectField("outline", categoryArea.getDrawOutline()); + } + + jgen.writeObjectField("labelPosition", categoryArea.getLabelPosition()); + jgen.writeEndObject(); + } +} diff --git a/base/src/main/java/com/twosigma/beakerx/chart/serializer/CategoryBarsSerializer.java b/base/src/main/java/com/twosigma/beakerx/chart/serializer/CategoryBarsSerializer.java new file mode 100644 index 0000000..f5dabcd --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/chart/serializer/CategoryBarsSerializer.java @@ -0,0 +1,68 @@ +/* + * Copyright 2014 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.chart.serializer; + +import com.twosigma.beakerx.chart.categoryplot.plotitem.CategoryBars; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.core.JsonProcessingException; + +import java.io.IOException; + +public class CategoryBarsSerializer extends CategoryGraphicsSerializer { + + @Override + public void serialize(CategoryBars categoryBars, + JsonGenerator jgen, + SerializerProvider provider) throws + IOException, + JsonProcessingException { + jgen.writeStartObject(); + + super.serialize(categoryBars, jgen, provider); + + if (categoryBars.getBases() != null) { + jgen.writeObjectField("bases", categoryBars.getBases()); + } else { + jgen.writeObjectField("base", categoryBars.getBase()); + } + if (categoryBars.getWidths() != null) { + jgen.writeObjectField("widths", categoryBars.getWidths()); + } else { + jgen.writeObjectField("width", categoryBars.getWidth()); + } + if (categoryBars.getOutlineColors() != null) { + jgen.writeObjectField("outline_colors", categoryBars.getOutlineColors()); + } else { + jgen.writeObjectField("outline_color", categoryBars.getOutlineColor()); + } + if (categoryBars.getFills() != null) { + jgen.writeObjectField("fills", categoryBars.getFills()); + } else { + jgen.writeObjectField("fill", categoryBars.getFill()); + } + if (categoryBars.getDrawOutlines() != null) { + jgen.writeObjectField("outlines", categoryBars.getDrawOutlines()); + } else { + jgen.writeObjectField("outline", categoryBars.getDrawOutline()); + } + + jgen.writeObjectField("labelPosition", categoryBars.getLabelPosition()); + + jgen.writeEndObject(); + } +} diff --git a/base/src/main/java/com/twosigma/beakerx/chart/serializer/CategoryGraphicsSerializer.java b/base/src/main/java/com/twosigma/beakerx/chart/serializer/CategoryGraphicsSerializer.java new file mode 100644 index 0000000..5fcf0cc --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/chart/serializer/CategoryGraphicsSerializer.java @@ -0,0 +1,54 @@ +/* + * Copyright 2014 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.chart.serializer; + +import com.twosigma.beakerx.chart.categoryplot.plotitem.CategoryGraphics; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.core.JsonGenerator; + +import java.io.IOException; +import java.util.List; + +public abstract class CategoryGraphicsSerializer extends GraphicsSerializer { + + public void serialize(T graphics, JsonGenerator jgen, SerializerProvider sp) throws IOException { + + super.serialize(graphics, jgen, sp); + + jgen.writeObjectField("showItemLabel", graphics.getShowItemLabel()); + jgen.writeObjectField("center_series", graphics.getCenterSeries()); + jgen.writeObjectField("use_tool_tip", graphics.getUseToolTip()); + + + if (graphics.getSeriesNames() != null) { + jgen.writeObjectField("seriesNames", graphics.getSeriesNames()); + } + if (graphics.getValue() != null) { + jgen.writeObjectField("value", graphics.getValue()); + + } + if (graphics.getColors() != null) { + jgen.writeObjectField("colors", graphics.getColors()); + } else { + jgen.writeObjectField("color", graphics.getColor()); + } + + String[][] itemLabels = graphics.getItemLabels(); + if (itemLabels != null){ + jgen.writeObjectField("itemLabels", itemLabels); + } + } +} diff --git a/base/src/main/java/com/twosigma/beakerx/chart/serializer/CategoryLinesSerializer.java b/base/src/main/java/com/twosigma/beakerx/chart/serializer/CategoryLinesSerializer.java new file mode 100644 index 0000000..066d577 --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/chart/serializer/CategoryLinesSerializer.java @@ -0,0 +1,51 @@ +/* + * Copyright 2014 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.chart.serializer; + +import com.twosigma.beakerx.chart.categoryplot.plotitem.CategoryLines; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.core.JsonProcessingException; + +import java.io.IOException; + +public class CategoryLinesSerializer extends CategoryGraphicsSerializer { + + @Override + public void serialize(CategoryLines categoryLines, + JsonGenerator jgen, + SerializerProvider provider) throws + IOException, + JsonProcessingException { + jgen.writeStartObject(); + + super.serialize(categoryLines, jgen, provider); + + if (categoryLines.getWidth() != null) { + jgen.writeObjectField("width", categoryLines.getWidth()); + } + if (categoryLines.getStyles() != null) { + jgen.writeObjectField("styles", categoryLines.getStyles()); + } else { + jgen.writeObjectField("style", categoryLines.getStyle().toString()); + } + if (categoryLines.getInterpolation() != null) { + jgen.writeObjectField("interpolation", categoryLines.getInterpolation()); + } + + jgen.writeEndObject(); + } +} diff --git a/base/src/main/java/com/twosigma/beakerx/chart/serializer/CategoryPlotSerializer.java b/base/src/main/java/com/twosigma/beakerx/chart/serializer/CategoryPlotSerializer.java new file mode 100644 index 0000000..af4101a --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/chart/serializer/CategoryPlotSerializer.java @@ -0,0 +1,62 @@ +/* + * Copyright 2014 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.chart.serializer; + +import com.twosigma.beakerx.chart.categoryplot.CategoryPlot; +import com.twosigma.beakerx.chart.categoryplot.plotitem.CategoryGraphics; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.core.JsonProcessingException; + +import java.io.IOException; +import java.util.List; + +public class CategoryPlotSerializer extends AbstractChartSerializer { + + public static final String GRAPHICS_LIST = "graphics_list"; + public static final String CATEGORY_NAMES = "categoryNames"; + public static final String ORIENTATION = "orientation"; + public static final String CATEGORY_MARGIN = "category_margin"; + public static final String CATEGORY_NAMES_LABEL_ANGLE = "categoryNamesLabelAngle"; + + @Override + public void serialize(CategoryPlot categoryPlot, JsonGenerator jgen, SerializerProvider provider) throws + IOException, + JsonProcessingException { + jgen.writeStartObject(); + + serialize(categoryPlot, jgen); + + List categoryNames = categoryPlot.getCategoryNames(); + if (categoryNames != null) { + jgen.writeObjectField(CATEGORY_NAMES, categoryNames); + } + List categoryGraphicsList = categoryPlot.getGraphics(); + if (categoryGraphicsList != null) { + for (CategoryGraphics categoryGraphics : categoryGraphicsList) { + categoryGraphics.createItemLabels(categoryPlot); + } + jgen.writeObjectField(GRAPHICS_LIST, categoryGraphicsList); + } + + jgen.writeObjectField(ORIENTATION, categoryPlot.getOrientation()); + jgen.writeObjectField(CATEGORY_MARGIN, categoryPlot.getCategoryMargin()); + jgen.writeObjectField(CATEGORY_NAMES_LABEL_ANGLE, categoryPlot.getCategoryNamesLabelAngle()); + + + jgen.writeEndObject(); + } +} diff --git a/base/src/main/java/com/twosigma/beakerx/chart/serializer/CategoryPointsSerializer.java b/base/src/main/java/com/twosigma/beakerx/chart/serializer/CategoryPointsSerializer.java new file mode 100644 index 0000000..c04f3d5 --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/chart/serializer/CategoryPointsSerializer.java @@ -0,0 +1,60 @@ +/* + * Copyright 2014 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.chart.serializer; + +import com.twosigma.beakerx.chart.categoryplot.plotitem.CategoryPoints; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.core.JsonProcessingException; + +import java.io.IOException; + +public class CategoryPointsSerializer extends CategoryGraphicsSerializer { + + @Override + public void serialize(CategoryPoints categoryPoints, + JsonGenerator jgen, + SerializerProvider provider) throws + IOException, + JsonProcessingException { + jgen.writeStartObject(); + + super.serialize(categoryPoints, jgen, provider); + + if (categoryPoints.getSizes() != null) { + jgen.writeObjectField("sizes", categoryPoints.getSizes()); + } else { + jgen.writeObjectField("size", categoryPoints.getSize()); + } + if (categoryPoints.getShapes() != null) { + jgen.writeObjectField("shaps", categoryPoints.getShapes()); + } else { + jgen.writeObjectField("shape", categoryPoints.getShape()); + } + if (categoryPoints.getFills() != null) { + jgen.writeObjectField("fills", categoryPoints.getFills()); + } else { + jgen.writeObjectField("fill", categoryPoints.getFill()); + } + if (categoryPoints.getOutlineColors() != null) { + jgen.writeObjectField("outline_colors", categoryPoints.getOutlineColors()); + } else { + jgen.writeObjectField("outline_color", categoryPoints.getOutlineColor()); + } + + jgen.writeEndObject(); + } +} diff --git a/base/src/main/java/com/twosigma/beakerx/chart/serializer/CategoryStemsSerializer.java b/base/src/main/java/com/twosigma/beakerx/chart/serializer/CategoryStemsSerializer.java new file mode 100644 index 0000000..9be1e8d --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/chart/serializer/CategoryStemsSerializer.java @@ -0,0 +1,53 @@ +/* + * Copyright 2014 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.chart.serializer; + +import com.twosigma.beakerx.chart.categoryplot.plotitem.CategoryStems; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.core.JsonProcessingException; + +import java.io.IOException; + +public class CategoryStemsSerializer extends CategoryGraphicsSerializer { + + @Override + public void serialize(CategoryStems categoryStems, + JsonGenerator jgen, + SerializerProvider provider) throws + IOException, + JsonProcessingException { + jgen.writeStartObject(); + + super.serialize(categoryStems, jgen, provider); + + if (categoryStems.getBases() != null) { + jgen.writeObjectField("bases", categoryStems.getBases()); + } else { + jgen.writeObjectField("base", categoryStems.getBase()); + } + if (categoryStems.getWidth() != null) { + jgen.writeObjectField("width", categoryStems.getWidth()); + } + if (categoryStems.getStyles() != null) { + jgen.writeObjectField("styles", categoryStems.getStyles()); + } else { + jgen.writeObjectField("style", categoryStems.getStyle().toString()); + } + + jgen.writeEndObject(); + } +} diff --git a/base/src/main/java/com/twosigma/beakerx/chart/serializer/ChartSerializer.java b/base/src/main/java/com/twosigma/beakerx/chart/serializer/ChartSerializer.java new file mode 100644 index 0000000..5ed7b42 --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/chart/serializer/ChartSerializer.java @@ -0,0 +1,58 @@ +/* + * Copyright 2014 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.chart.serializer; + + +import com.twosigma.beakerx.util.SerializerUtil; +import com.twosigma.beakerx.chart.Chart; +import com.fasterxml.jackson.core.JsonGenerator; + +import java.io.IOException; + +public abstract class ChartSerializer extends ObservableChartSerializer { + + public static final String CHART_TITLE = "chart_title"; + public static final String LEGEND_POSITION = "legend_position"; + public static final String SHOW_LEGEND = "show_legend"; + public static final String USE_TOOL_TIP = "use_tool_tip"; + public static final String INIT_WIDTH = "init_width"; + public static final String INIT_HEIGHT = "init_height"; + public static final String CUSTOM_STYLES = "custom_styles"; + public static final String LEGEND_LAYOUT = "legend_layout"; + public static final String ELEMENT_STYLES = "element_styles"; + + protected void serialize(T chart, JsonGenerator jgen) throws IOException { + + super.serialize(chart, jgen); + + String type = SerializerUtil.getTypeName(chart); + if ("SimpleTimePlot".equals(type)){ + jgen.writeObjectField("type", "TimePlot"); + }else { + jgen.writeObjectField("type", type); + } + + jgen.writeObjectField(INIT_WIDTH, chart.getInitWidth()); + jgen.writeObjectField(INIT_HEIGHT, chart.getInitHeight()); + jgen.writeObjectField(CHART_TITLE, chart.getTitle()); + jgen.writeObjectField(SHOW_LEGEND, chart.getShowLegend()); + jgen.writeObjectField(USE_TOOL_TIP, chart.getUseToolTip()); + jgen.writeObjectField(LEGEND_POSITION, chart.getLegendPosition()); + jgen.writeObjectField(LEGEND_LAYOUT, chart.getLegendLayout()); + jgen.writeObjectField(CUSTOM_STYLES, chart.getCustomStyles()); + jgen.writeObjectField(ELEMENT_STYLES, chart.getElementStyles()); + } +} diff --git a/base/src/main/java/com/twosigma/beakerx/chart/serializer/ColorSerializer.java b/base/src/main/java/com/twosigma/beakerx/chart/serializer/ColorSerializer.java new file mode 100644 index 0000000..ea9a168 --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/chart/serializer/ColorSerializer.java @@ -0,0 +1,36 @@ +/* + * Copyright 2014 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.chart.serializer; + +import com.twosigma.beakerx.chart.Color; +import java.io.IOException; +import com.fasterxml.jackson.databind.JsonSerializer; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.core.JsonProcessingException; + +public class ColorSerializer extends JsonSerializer { + + @Override + public void serialize(Color color, JsonGenerator jgen, SerializerProvider sp) + throws IOException, JsonProcessingException { + synchronized(color) { + jgen.writeString(String.format("#%x", color.getRGB()).toUpperCase()); + } + } + +} diff --git a/base/src/main/java/com/twosigma/beakerx/chart/serializer/CombinedPlotSerializer.java b/base/src/main/java/com/twosigma/beakerx/chart/serializer/CombinedPlotSerializer.java new file mode 100644 index 0000000..cdedbfd --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/chart/serializer/CombinedPlotSerializer.java @@ -0,0 +1,67 @@ +/* + * Copyright 2014 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.chart.serializer; + +import com.twosigma.beakerx.util.SerializerUtil; +import com.twosigma.beakerx.chart.xychart.CombinedPlot; +import com.twosigma.beakerx.chart.xychart.XYChart; +import static com.twosigma.beakerx.chart.serializer.AbstractChartSerializer.AUTO_ZOOM; +import java.io.IOException; +import java.util.List; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.core.JsonProcessingException; + +/** + * XYCombinedChartSerializer + * + */ +public class CombinedPlotSerializer extends ObservableChartSerializer { + + public static final String X_LABEL = "x_label"; + + @Override + public void serialize(CombinedPlot plot, JsonGenerator jgen, SerializerProvider sp) + throws IOException, JsonProcessingException + { + jgen.writeStartObject(); + super.serialize(plot, jgen); + jgen.writeObjectField("type", SerializerUtil.getTypeName(plot)); + jgen.writeObjectField("init_width", plot.getInitWidth()); + jgen.writeObjectField("init_height", plot.getInitHeight()); + jgen.writeObjectField("title", plot.getTitle()); + jgen.writeObjectField(X_LABEL, plot.getXLabel()); + List subplots = plot.getSubplots(); + if (!subplots.isEmpty()) { + + String plot_type = subplots.get(0).getClass().getSimpleName(); + if ("SimpleTimePlot".equals(plot_type)){ + jgen.writeObjectField("plot_type", "TimePlot"); + }else { + jgen.writeObjectField("plot_type", plot_type); + } + } + jgen.writeObjectField("plots", subplots); + jgen.writeObjectField("weights", plot.getWeights()); + jgen.writeObjectField("version", "groovy"); + jgen.writeObjectField("x_tickLabels_visible", plot.isxTickLabelsVisible()); + jgen.writeObjectField("y_tickLabels_visible", plot.isyTickLabelsVisible()); + jgen.writeObjectField(AUTO_ZOOM, plot.getAutoZoom()); + jgen.writeEndObject(); + } + +} diff --git a/base/src/main/java/com/twosigma/beakerx/chart/serializer/ConstantBandSerializer.java b/base/src/main/java/com/twosigma/beakerx/chart/serializer/ConstantBandSerializer.java new file mode 100644 index 0000000..9852682 --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/chart/serializer/ConstantBandSerializer.java @@ -0,0 +1,67 @@ +/* + * Copyright 2014 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.chart.serializer; + +import com.twosigma.beakerx.util.SerializerUtil; +import com.twosigma.beakerx.chart.Color; +import com.twosigma.beakerx.chart.xychart.NanoPlot; +import com.twosigma.beakerx.chart.xychart.plotitem.ConstantBand; +import com.fasterxml.jackson.databind.JsonSerializer; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.core.JsonProcessingException; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +public class ConstantBandSerializer extends JsonSerializer { + + public static final String TYPE = "type"; + + @Override + public void serialize(ConstantBand constantBand, JsonGenerator jgen, SerializerProvider sp) + throws IOException, JsonProcessingException { + + jgen.writeStartObject(); + + boolean isNanoPlot = NanoPlot.isNanoPlotClass(constantBand.getPlotType()); + jgen.writeObjectField(TYPE, SerializerUtil.getTypeName(constantBand)); + jgen.writeObjectField("x", isNanoPlot ? processLargeNumbers(constantBand.getX()) : constantBand.getX()); + jgen.writeObjectField("y", constantBand.getY()); + jgen.writeObjectField("visible", constantBand.getVisible()); + jgen.writeObjectField("yAxis", constantBand.getYAxis()); + if (constantBand.getColor() == null){ + jgen.writeObjectField("color", new Color(0, 127, 255, 127)); + }else{ + jgen.writeObjectField("color", constantBand.getColor()); + } + + jgen.writeEndObject(); + } + + private List processLargeNumbers(List list){ + List stringList = new ArrayList<>(list.size()); + for(Number n : list){ + if(n != null){ + stringList.add(n.toString()); + }else{ + stringList.add(""); + } + } + return stringList; + } +} \ No newline at end of file diff --git a/base/src/main/java/com/twosigma/beakerx/chart/serializer/ConstantLineSerializer.java b/base/src/main/java/com/twosigma/beakerx/chart/serializer/ConstantLineSerializer.java new file mode 100644 index 0000000..32b9b4d --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/chart/serializer/ConstantLineSerializer.java @@ -0,0 +1,64 @@ +/* + * Copyright 2014 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.chart.serializer; + +import com.twosigma.beakerx.util.SerializerUtil; +import com.twosigma.beakerx.chart.Color; +import com.twosigma.beakerx.chart.xychart.NanoPlot; +import com.twosigma.beakerx.chart.xychart.plotitem.ConstantLine; +import com.fasterxml.jackson.databind.JsonSerializer; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.core.JsonProcessingException; + +import java.io.IOException; + +public class ConstantLineSerializer extends JsonSerializer { + + public static final String TYPE = "type"; + + @Override + public void serialize(ConstantLine constantLine, JsonGenerator jgen, SerializerProvider sp) + throws IOException, JsonProcessingException { + + jgen.writeStartObject(); + + boolean isNanoPlot = NanoPlot.isNanoPlotClass(constantLine.getPlotType()); + jgen.writeObjectField(TYPE, SerializerUtil.getTypeName(constantLine)); + jgen.writeObjectField("x", isNanoPlot ? processLargeNumber(constantLine.getX()) : constantLine.getX()); + jgen.writeObjectField("y", constantLine.getY()); + jgen.writeObjectField("visible", constantLine.getVisible()); + jgen.writeObjectField("yAxis", constantLine.getYAxis()); + jgen.writeObjectField("showLabel", constantLine.getShowLabel()); + if (constantLine.getWidth() != null) { + jgen.writeObjectField("width", constantLine.getWidth()); + } + if (constantLine.getStyle() != null) { + jgen.writeObjectField("style", constantLine.getStyle().toString()); + } + if (constantLine.getColor() instanceof Color) { + jgen.writeObjectField("color", constantLine.getColor()); + } + + jgen.writeEndObject(); + } + + private String processLargeNumber(Number largeNumber){ + return largeNumber != null ? largeNumber.toString() : ""; + } + +} \ No newline at end of file diff --git a/base/src/main/java/com/twosigma/beakerx/chart/serializer/CrosshairSerializer.java b/base/src/main/java/com/twosigma/beakerx/chart/serializer/CrosshairSerializer.java new file mode 100644 index 0000000..13aa0de --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/chart/serializer/CrosshairSerializer.java @@ -0,0 +1,54 @@ +/* + * Copyright 2014 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.chart.serializer; + +import com.twosigma.beakerx.util.SerializerUtil; +import com.twosigma.beakerx.chart.xychart.plotitem.Crosshair; +import com.twosigma.beakerx.chart.Color; +import java.io.IOException; +import com.fasterxml.jackson.databind.JsonSerializer; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.core.JsonProcessingException; + +/** + * CrosshairSerializer + * + */ +public class CrosshairSerializer extends JsonSerializer{ + + public static final String TYPE = "type"; + + @Override + public void serialize(Crosshair crosshair, JsonGenerator jgen, SerializerProvider sp) + throws IOException, JsonProcessingException { + + jgen.writeStartObject(); + jgen.writeObjectField(TYPE, SerializerUtil.getTypeName(crosshair)); + if (crosshair.getColor() instanceof Color) { + jgen.writeObjectField("color", crosshair.getColor()); + } + if (crosshair.getStyle() != null) { + jgen.writeObjectField("style", crosshair.getStyle().toString()); + } + if (crosshair.getWidth() != null) { + jgen.writeObjectField("width", crosshair.getWidth()); + } + jgen.writeEndObject(); + } + +} diff --git a/base/src/main/java/com/twosigma/beakerx/chart/serializer/GradientColorSerializer.java b/base/src/main/java/com/twosigma/beakerx/chart/serializer/GradientColorSerializer.java new file mode 100644 index 0000000..df4346b --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/chart/serializer/GradientColorSerializer.java @@ -0,0 +1,35 @@ +/* + * Copyright 2014 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.chart.serializer; + +import com.twosigma.beakerx.chart.GradientColor; +import com.fasterxml.jackson.databind.JsonSerializer; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.core.JsonProcessingException; + +import java.io.IOException; + +public class GradientColorSerializer extends JsonSerializer { + + @Override + public void serialize(GradientColor gradientColor, JsonGenerator jgen, SerializerProvider sp) + throws IOException, JsonProcessingException { + jgen.writeObject(gradientColor.getColors()); + } + +} diff --git a/base/src/main/java/com/twosigma/beakerx/chart/serializer/GraphicsSerializer.java b/base/src/main/java/com/twosigma/beakerx/chart/serializer/GraphicsSerializer.java new file mode 100644 index 0000000..65f6f4f --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/chart/serializer/GraphicsSerializer.java @@ -0,0 +1,57 @@ +/* + * Copyright 2014 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.chart.serializer; + +import com.twosigma.beakerx.util.SerializerUtil; +import com.twosigma.beakerx.chart.Graphics; +import org.apache.commons.lang3.ArrayUtils; +import org.apache.commons.lang3.StringUtils; +import com.fasterxml.jackson.databind.JsonSerializer; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.core.JsonProcessingException; + +import java.io.IOException; +import java.util.Map; + +/** + * GraphicsSerializer + */ +public class GraphicsSerializer extends JsonSerializer { + + public static final String TYPE = "type"; + + @Override + public void serialize(T graphics, JsonGenerator jgen, SerializerProvider sp) + throws IOException, JsonProcessingException { + jgen.writeObjectField(TYPE, SerializerUtil.getTypeName(graphics)); + jgen.writeObjectField("uid", graphics.getUid()); + jgen.writeObjectField("visible", graphics.getVisible()); + jgen.writeObjectField("yAxis", graphics.getYAxis()); + jgen.writeObjectField("hasClickAction", graphics.hasClickAction()); + if(StringUtils.isNotEmpty(graphics.getClickTag())) { + jgen.writeObjectField("clickTag", graphics.getClickTag()); + } + Map keyTags = graphics.getKeyTags(); + if(keyTags != null && !keyTags.isEmpty()) { + jgen.writeObjectField("keyTags", keyTags); + } + Object[] keys = graphics.getKeys(); + if(ArrayUtils.isNotEmpty(keys)) { + jgen.writeObjectField("keys", keys); + } + } +} diff --git a/base/src/main/java/com/twosigma/beakerx/chart/serializer/HeatMapReducer.java b/base/src/main/java/com/twosigma/beakerx/chart/serializer/HeatMapReducer.java new file mode 100644 index 0000000..b44912a --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/chart/serializer/HeatMapReducer.java @@ -0,0 +1,96 @@ +/* + * 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.chart.serializer; + +import org.jetbrains.annotations.NotNull; + +import java.util.Arrays; +import java.util.stream.IntStream; + + +public class HeatMapReducer { + + private final int nodeLimit; + private final int columnLimit; + private final int rowLimit; + + public HeatMapReducer(int columnLimit, int rowLimit) { + this.columnLimit = columnLimit; + this.rowLimit = rowLimit; + this.nodeLimit = this.columnLimit * this.rowLimit; + } + + public Number[][] limitHeatmap(Number[][] data) { + Number[][] limitedElementsInRow = limitElementsInRow(data); + int totalPoints = totalPoints(limitedElementsInRow); + boolean tooManyRows = totalPoints > nodeLimit; + if (tooManyRows) { + return limitRows(limitedElementsInRow); + } + return limitedElementsInRow; + } + + private Number[][] limitRows(Number[][] limitedElementsInRow) { + int stepForRow = findStepForRow(limitedElementsInRow); + Number[][] limitedRows = IntStream.range(0, limitedElementsInRow.length) + .filter(n -> n % stepForRow == 0) + .mapToObj(index -> limitedElementsInRow[index]) + .toArray(Number[][]::new); + return limitedRows; + } + + @NotNull + private Number[][] limitElementsInRow(Number[][] data) { + Number[][] limitedElements = Arrays.stream(data). + map(row -> { + if (row.length > this.columnLimit) { + int step = findStepForColumn(row); + Number[] limitedRow = IntStream.range(0, row.length) + .filter(n -> n % step == 0) + .mapToObj(index -> row[index]) + .toArray(Number[]::new); + return limitedRow; + } else { + return row; + } + }).toArray(Number[][]::new); + + return limitedElements; + } + + private int findStepForRow(Number[][] data) { + int step = 2; + while ((data.length / step) > this.rowLimit) { + step++; + } + return step; + } + + + private int findStepForColumn(Number[] row) { + int step = 2; + while ((row.length / step) > this.columnLimit) { + step++; + } + return step; + } + + public static int totalPoints(Number[][] data) { + return Arrays.stream(data). + mapToInt(x -> x.length).sum(); + } + +} diff --git a/base/src/main/java/com/twosigma/beakerx/chart/serializer/HeatMapSerializer.java b/base/src/main/java/com/twosigma/beakerx/chart/serializer/HeatMapSerializer.java new file mode 100644 index 0000000..c2cd267 --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/chart/serializer/HeatMapSerializer.java @@ -0,0 +1,68 @@ +/* + * Copyright 2014 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.chart.serializer; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.twosigma.beakerx.chart.heatmap.HeatMap; + +import java.io.IOException; + +import static com.twosigma.beakerx.chart.heatmap.HeatMap.COLUMN_LIMIT; +import static com.twosigma.beakerx.chart.heatmap.HeatMap.NUMBER_OF_NODES_LIMIT; +import static com.twosigma.beakerx.chart.heatmap.HeatMap.ROWS_LIMIT; + +public class HeatMapSerializer extends AbstractChartSerializer { + + public static final String GRAPHICS_LIST = "graphics_list"; + public static final String COLOR = "color"; + public static final String ITEMS = " items"; + + private HeatMapReducer heatMapReducer = new HeatMapReducer(COLUMN_LIMIT, ROWS_LIMIT); + + @Override + public void serialize(HeatMap heatmap, JsonGenerator jgen, SerializerProvider sp) + throws IOException { + jgen.writeStartObject(); + serialize(heatmap, jgen); + if (heatmap.getData() == null) { + jgen.writeObjectField(GRAPHICS_LIST, heatmap.getData()); + jgen.writeObjectField(TOTAL_NUMBER_OF_POINTS, 0); + jgen.writeBooleanField(TOO_MANY_ROWS, false); + } else { + serializeData(heatmap.getData(), jgen); + } + jgen.writeObjectField(COLOR, heatmap.getColor()); + jgen.writeEndObject(); + } + + private void serializeData(Number[][] data, JsonGenerator jgen) throws IOException { + int totalPoints = HeatMapReducer.totalPoints(data); + boolean tooManyPoints = totalPoints > NUMBER_OF_NODES_LIMIT; + if (tooManyPoints) { + Number[][] limitedHeatMapData = heatMapReducer.limitHeatmap(data); + jgen.writeObjectField(GRAPHICS_LIST, limitedHeatMapData); + jgen.writeObjectField(ROWS_LIMIT_ITEMS, NUMBER_OF_NODES_LIMIT); + jgen.writeObjectField(NUMBER_OF_POINTS_TO_DISPLAY, HeatMapReducer.totalPoints(limitedHeatMapData) + ITEMS); + } else { + jgen.writeObjectField(GRAPHICS_LIST, data); + } + jgen.writeObjectField(TOTAL_NUMBER_OF_POINTS, totalPoints); + jgen.writeBooleanField(TOO_MANY_ROWS, tooManyPoints); + } + + +} \ No newline at end of file diff --git a/base/src/main/java/com/twosigma/beakerx/chart/serializer/HistogramReducer.java b/base/src/main/java/com/twosigma/beakerx/chart/serializer/HistogramReducer.java new file mode 100644 index 0000000..1966622 --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/chart/serializer/HistogramReducer.java @@ -0,0 +1,51 @@ +/* + * 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.chart.serializer; + +import java.util.List; +import java.util.OptionalInt; +import java.util.stream.Collectors; + +import static java.util.Collections.singletonList; + +public class HistogramReducer { + + private int rowLimit; + private int numberOfRowsToDisplay; + + + public HistogramReducer(int rowLimit, int numberOfRowsToDisplay) { + this.rowLimit = rowLimit; + this.numberOfRowsToDisplay = numberOfRowsToDisplay; + } + + public List> limitData(List list) { + return singletonList(list.subList(0, numberOfRowsToDisplay)); + } + + public List> limitListData(List> listData) { + return listData.stream(). + map(x -> x.subList(0, (x.size() >= rowLimit) ? numberOfRowsToDisplay : x.size())). + collect(Collectors.toList()); + } + + public OptionalInt totalPoints(List> listData) { + return listData.stream(). + mapToInt(List::size). + max(); + } + +} diff --git a/base/src/main/java/com/twosigma/beakerx/chart/serializer/HistogramSerializer.java b/base/src/main/java/com/twosigma/beakerx/chart/serializer/HistogramSerializer.java new file mode 100644 index 0000000..e047654 --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/chart/serializer/HistogramSerializer.java @@ -0,0 +1,100 @@ +/* + * Copyright 2014 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.chart.serializer; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.twosigma.beakerx.chart.histogram.Histogram; + +import java.io.IOException; +import java.util.List; +import java.util.OptionalInt; + +import static java.util.Collections.emptyList; +import static java.util.Collections.singletonList; + +public class HistogramSerializer extends AbstractChartSerializer { + + public static final String GRAPHICS_LIST = "graphics_list"; + public static final String BIN_COUNT = "bin_count"; + public static final String COLOR = "color"; + public static final String COLORS = "colors"; + public static final String NAMES = "names"; + public static final String DISPLAY_MODE = "displayMode"; + public static final String CUMULATIVE = "cumulative"; + public static final String NORMED = "normed"; + public static final String LOG = "log"; + public static final String ITEMS = " items"; + + private HistogramReducer histogramReducer = new HistogramReducer(Histogram.ROWS_LIMIT, Histogram.NUMBER_OF_POINTS_TO_DISPLAY); + + @Override + public void serialize(Histogram histogram, JsonGenerator jgen, SerializerProvider provider) throws + IOException { + jgen.writeStartObject(); + + serialize(histogram, jgen); + + if (histogram.getColors() != null) { + jgen.writeObjectField(COLORS, histogram.getColors()); + } else { + jgen.writeObjectField(COLOR, histogram.getColor()); + } + + if (histogram.getListData() != null) { + serializeListData(jgen, histogram.getListData()); + } else { + serializeData(jgen, (histogram.getData() != null) ? histogram.getData() : emptyList()); + } + + jgen.writeObjectField("right_close", histogram.getRightClose()); + if (histogram.getRangeMin() != null) + jgen.writeObjectField("range_min", histogram.getRangeMin()); + if (histogram.getRangeMax() != null) + jgen.writeObjectField("range_max", histogram.getRangeMax()); + jgen.writeObjectField(BIN_COUNT, histogram.getBinCount()); + jgen.writeObjectField(CUMULATIVE, histogram.getCumulative()); + jgen.writeObjectField(NORMED, histogram.getNormed()); + jgen.writeObjectField(LOG, histogram.getLog()); + jgen.writeObjectField(DISPLAY_MODE, histogram.getDisplayMode()); + jgen.writeObjectField(NAMES, histogram.getNames()); + jgen.writeEndObject(); + } + + private void serializeData(JsonGenerator jgen, List list) throws IOException { + if (Histogram.ROWS_LIMIT < list.size()) { + jgen.writeObjectField(GRAPHICS_LIST, histogramReducer.limitData(list)); + jgen.writeBooleanField(TOO_MANY_ROWS, true); + jgen.writeObjectField(ROWS_LIMIT_ITEMS, Histogram.ROWS_LIMIT); + jgen.writeObjectField(NUMBER_OF_POINTS_TO_DISPLAY, Histogram.NUMBER_OF_POINTS_TO_DISPLAY + ITEMS); + } else { + jgen.writeObjectField(GRAPHICS_LIST, singletonList(list)); + jgen.writeBooleanField(TOO_MANY_ROWS, false); + } + jgen.writeObjectField(TOTAL_NUMBER_OF_POINTS, list.size()); + } + + private void serializeListData(JsonGenerator jgen, List> listData) throws IOException { + OptionalInt max = histogramReducer.totalPoints(listData); + List> limited = histogramReducer.limitListData(listData); + jgen.writeObjectField(GRAPHICS_LIST, limited); + jgen.writeObjectField(TOTAL_NUMBER_OF_POINTS, max.orElse(0)); + jgen.writeBooleanField(TOO_MANY_ROWS, max.isPresent() && Histogram.ROWS_LIMIT <= max.getAsInt()); + jgen.writeObjectField(ROWS_LIMIT_ITEMS, Histogram.ROWS_LIMIT); + jgen.writeObjectField(NUMBER_OF_POINTS_TO_DISPLAY, Histogram.NUMBER_OF_POINTS_TO_DISPLAY + ITEMS); + } + +} diff --git a/base/src/main/java/com/twosigma/beakerx/chart/serializer/LegendPositionSerializer.java b/base/src/main/java/com/twosigma/beakerx/chart/serializer/LegendPositionSerializer.java new file mode 100644 index 0000000..4e35840 --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/chart/serializer/LegendPositionSerializer.java @@ -0,0 +1,51 @@ +/* + * Copyright 2014 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.chart.serializer; + +import com.twosigma.beakerx.util.SerializerUtil; +import com.twosigma.beakerx.chart.legend.LegendPosition; +import com.fasterxml.jackson.databind.JsonSerializer; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.core.JsonProcessingException; + +import java.io.IOException; + +/** + * LegendPositionSerializer + * + */ +public class LegendPositionSerializer extends JsonSerializer { + + public static final String TYPE = "type"; + public static final String POSITION = "position"; + + @Override + public void serialize(LegendPosition legendPosition, JsonGenerator jgen, SerializerProvider sp) + throws IOException, JsonProcessingException { + + jgen.writeStartObject(); + jgen.writeObjectField(TYPE, SerializerUtil.getTypeName(legendPosition)); + if (legendPosition.getPosition() != null) { + jgen.writeObjectField(POSITION, legendPosition.getPosition().name()); + }else{ + jgen.writeObjectField("x", legendPosition.getX()); + jgen.writeObjectField("y", legendPosition.getY()); + } + jgen.writeEndObject(); + } + +} \ No newline at end of file diff --git a/base/src/main/java/com/twosigma/beakerx/chart/serializer/LineSerializer.java b/base/src/main/java/com/twosigma/beakerx/chart/serializer/LineSerializer.java new file mode 100644 index 0000000..952ed42 --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/chart/serializer/LineSerializer.java @@ -0,0 +1,52 @@ +/* + * Copyright 2014 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.chart.serializer; + +import com.twosigma.beakerx.chart.xychart.plotitem.Line; +import com.twosigma.beakerx.chart.Color; +import java.io.IOException; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.core.JsonProcessingException; + +public class LineSerializer extends XYGraphicsSerializer { + + @Override + public void serialize(Line line, JsonGenerator jgen, SerializerProvider sp) + throws IOException, JsonProcessingException { + + jgen.writeStartObject(); + + super.serialize(line, jgen, sp); + + if (line.getLodFilter() != null) + jgen.writeObjectField("lod_filter", line.getLodFilter().getText()); + if (line.getColor() instanceof Color) { + jgen.writeObjectField("color", line.getColor()); + } + if (line.getWidth() != null) { + jgen.writeObjectField("width", line.getWidth()); + } + if (line.getStyle() != null) { + jgen.writeObjectField("style", line.getStyle().toString()); + } + if (line.getInterpolation() != null) { + jgen.writeObjectField("interpolation", line.getInterpolation()); + } + jgen.writeEndObject(); + } + +} diff --git a/base/src/main/java/com/twosigma/beakerx/chart/serializer/Messages.java b/base/src/main/java/com/twosigma/beakerx/chart/serializer/Messages.java new file mode 100644 index 0000000..e7f0173 --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/chart/serializer/Messages.java @@ -0,0 +1,25 @@ +/* + * Copyright 2017 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.chart.serializer; + +public interface Messages { + + String PROVIDE_X_COORDINATE = "Please provide X coordinate"; + String PROVIDE_Y_COORDINATE = "Please provide Y coordinate"; + String PROVIDE_HEIGHT = "Please provide height size."; + String PROVIDE_WIDTH = "Please provide width size."; + +} diff --git a/base/src/main/java/com/twosigma/beakerx/chart/serializer/ObservableChartSerializer.java b/base/src/main/java/com/twosigma/beakerx/chart/serializer/ObservableChartSerializer.java new file mode 100644 index 0000000..33df322 --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/chart/serializer/ObservableChartSerializer.java @@ -0,0 +1,32 @@ +/* + * Copyright 2014 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.chart.serializer; + +import com.twosigma.beakerx.chart.ChartDetails; +import com.fasterxml.jackson.databind.JsonSerializer; +import com.fasterxml.jackson.core.JsonGenerator; + +import java.io.IOException; + +public abstract class ObservableChartSerializer extends JsonSerializer { + + protected void serialize(T chart, JsonGenerator jgen) throws IOException { +// String id = updateManagerProvider.get().register(chart); +// chartObjectManagerProvider.get().registerChart(id, chart); +// jgen.writeStringField("update_id", id); + } + +} diff --git a/base/src/main/java/com/twosigma/beakerx/chart/serializer/PointsSerializer.java b/base/src/main/java/com/twosigma/beakerx/chart/serializer/PointsSerializer.java new file mode 100644 index 0000000..069e735 --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/chart/serializer/PointsSerializer.java @@ -0,0 +1,70 @@ +/* + * Copyright 2014 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.chart.serializer; + +import com.twosigma.beakerx.chart.xychart.plotitem.Points; +import java.io.IOException; +import java.util.stream.Collectors; + +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.twosigma.beakerx.chart.xychart.plotitem.ShapeType; + +/** + * PointsSerializer + * + */ +public class PointsSerializer extends XYGraphicsSerializer { + + @Override + public void serialize(Points points, JsonGenerator jgen, SerializerProvider sp) + throws IOException, JsonProcessingException { + + jgen.writeStartObject(); + + super.serialize(points, jgen, sp); + + if (points.getSizes() != null) { + jgen.writeObjectField("sizes", points.getSizes()); + } else { + jgen.writeObjectField("size", points.getSize()); + } + if (points.getShapes() != null) { + jgen.writeObjectField("shaps", points.getShapes().stream().map(ShapeType::getText).collect(Collectors.toList())); + } else { + jgen.writeObjectField("shape", points.getShape().getText()); + } + if (points.getFills() != null) { + jgen.writeObjectField("fills", points.getFills()); + } else { + jgen.writeObjectField("fill", points.getFill()); + } + if (points.getColors() != null) { + jgen.writeObjectField("colors", points.getColors()); + } else { + jgen.writeObjectField("color", points.getColor()); + } + if (points.getOutlineColors() != null) { + jgen.writeObjectField("outline_colors", points.getOutlineColors()); + } else { + jgen.writeObjectField("outline_color", points.getOutlineColor()); + } + jgen.writeEndObject(); + } + +} diff --git a/base/src/main/java/com/twosigma/beakerx/chart/serializer/RastersSerializer.java b/base/src/main/java/com/twosigma/beakerx/chart/serializer/RastersSerializer.java new file mode 100644 index 0000000..56f7002 --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/chart/serializer/RastersSerializer.java @@ -0,0 +1,103 @@ +/* + * Copyright 2017 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.chart.serializer; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.JsonSerializer; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.twosigma.beakerx.util.SerializerUtil; +import com.twosigma.beakerx.chart.xychart.plotitem.Rasters; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.nio.file.Files; +import org.apache.commons.codec.binary.Base64; +import org.apache.commons.codec.binary.StringUtils; + +public class RastersSerializer extends JsonSerializer { + + public static final String TYPE = "type"; + + @Override + public void serialize(Rasters rasters, JsonGenerator jgen, SerializerProvider sp) + throws IOException { + validate(rasters); + + jgen.writeStartObject(); + + jgen.writeObjectField(TYPE, SerializerUtil.getTypeName(rasters)); + jgen.writeObjectField("x", rasters.getX()); + jgen.writeObjectField("y", rasters.getY()); + jgen.writeObjectField("opacity", rasters.getOpacity()); + jgen.writeObjectField("visible", rasters.getVisible()); + jgen.writeObjectField("yAxis", rasters.getYAxis()); + jgen.writeObjectField("position", rasters.getPosition()); + jgen.writeObjectField("width", rasters.getWidth()); + jgen.writeObjectField("height", rasters.getHeight()); + + // datastring will override file path/url + if (rasters.getDataString() != null) { + jgen.writeObjectField("value", Bytes2Base64(rasters.getDataString(), null)); + } else if (!rasters.getFilePath().isEmpty()) { + String path = rasters.getFilePath(); + File file = new File(path); + + if (!file.exists()) { + throw new FileNotFoundException("Cannot find file " + path); + } + + byte[] picture = Files.readAllBytes(new File(path).toPath()); + String extension = ""; + int i = path.lastIndexOf('.'); + if (i > 0) { + extension = path.substring(i + 1); + } + + jgen.writeObjectField("value", Bytes2Base64(picture, extension)); + } else if (!rasters.getFileUrl().isEmpty()) { + jgen.writeObjectField("value", rasters.getFileUrl()); + } + + jgen.writeEndObject(); + } + + private void validate(Rasters raster) { + if (raster.getY() == null || raster.getY().isEmpty()) { + throw new IllegalStateException(Messages.PROVIDE_Y_COORDINATE); + } + + if (raster.getHeight() == null || raster.getHeight().isEmpty()) { + throw new IllegalStateException(Messages.PROVIDE_HEIGHT); + } + + if (raster.getWidth() == null || raster.getWidth().isEmpty()) { + throw new IllegalStateException(Messages.PROVIDE_WIDTH); + } + } + + private String Bytes2Base64(byte[] bytes, String format) { + StringBuilder sb = new StringBuilder(); + if (format != null) { + sb.append("data:image/").append(format).append(";base64,"); + } else { + sb.append("data:image/png;base64,"); + } + sb.append(StringUtils.newStringUtf8(Base64.encodeBase64(bytes, false))); + return sb.toString(); + } +} diff --git a/base/src/main/java/com/twosigma/beakerx/chart/serializer/StemsSerializer.java b/base/src/main/java/com/twosigma/beakerx/chart/serializer/StemsSerializer.java new file mode 100644 index 0000000..7eade09 --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/chart/serializer/StemsSerializer.java @@ -0,0 +1,54 @@ +/* + * Copyright 2014 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.chart.serializer; + +import com.twosigma.beakerx.chart.xychart.plotitem.Stems; +import java.io.IOException; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.core.JsonProcessingException; + +/** + * PointsSerializer + * + */ +public class StemsSerializer extends BasedXYGraphicsSerializer { + + @Override + public void serialize(Stems stems, JsonGenerator jgen, SerializerProvider sp) + throws IOException, JsonProcessingException { + + jgen.writeStartObject(); + + super.serialize(stems, jgen, sp); + + if (stems.getColors() != null) { + jgen.writeObjectField("colors", stems.getColors()); + } else { + jgen.writeObjectField("color", stems.getColor()); + } + if (stems.getWidth() != null) { + jgen.writeObjectField("width", stems.getWidth()); + } + if (stems.getStyles() != null) { + jgen.writeObjectField("styles", stems.getStyles()); + } else { + jgen.writeObjectField("style", stems.getStyle().toString()); + } + jgen.writeEndObject(); + } + +} diff --git a/base/src/main/java/com/twosigma/beakerx/chart/serializer/TextSerializer.java b/base/src/main/java/com/twosigma/beakerx/chart/serializer/TextSerializer.java new file mode 100644 index 0000000..7756bb6 --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/chart/serializer/TextSerializer.java @@ -0,0 +1,56 @@ +/* + * Copyright 2014 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.chart.serializer; + +import com.twosigma.beakerx.util.SerializerUtil; +import com.twosigma.beakerx.chart.xychart.NanoPlot; +import com.twosigma.beakerx.chart.xychart.plotitem.Text; +import com.fasterxml.jackson.databind.JsonSerializer; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.core.JsonProcessingException; + +import java.io.IOException; + +/** + * TextSerializer + */ +public class TextSerializer extends JsonSerializer { + + public static final String TYPE = "type"; + + @Override + public void serialize(Text text, JsonGenerator jgen, SerializerProvider sp) + throws IOException, JsonProcessingException { + + boolean isNanoPlot = NanoPlot.isNanoPlotClass(text.getPlotType()); + jgen.writeStartObject(); + jgen.writeObjectField(TYPE, SerializerUtil.getTypeName(text)); + jgen.writeObjectField("x", isNanoPlot ? processLargeNumber(text.getX()) : text.getX()); + jgen.writeObjectField("y", text.getY()); + jgen.writeObjectField("show_pointer", text.getShowPointer()); + jgen.writeObjectField("text", text.getText()); + jgen.writeObjectField("pointer_angle", text.getPointerAngle()); + jgen.writeObjectField("color", text.getColor()); + jgen.writeObjectField("size", text.getSize()); + jgen.writeEndObject(); + } + + private String processLargeNumber(Number largeNumber){ + return largeNumber != null ? largeNumber.toString() : ""; + } + +} diff --git a/base/src/main/java/com/twosigma/beakerx/chart/serializer/TreeMapNodeCounter.java b/base/src/main/java/com/twosigma/beakerx/chart/serializer/TreeMapNodeCounter.java new file mode 100644 index 0000000..ead473c --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/chart/serializer/TreeMapNodeCounter.java @@ -0,0 +1,55 @@ +/* + * 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.chart.serializer; + +import net.sf.jtreemap.swing.TreeMapNode; + +import java.util.Map; + +public class TreeMapNodeCounter { + + public static final String IS_LEAF = "isLeaf"; + + public static int countAllNodes(TreeMapNode node) { + return count(node, 0, (object, count1) -> count1 + 1); + } + + public static int countReducedLeaves(TreeMapNode node) { + return count(node, 0, (object, count) -> { + Map userObject = (Map)object.getUserObject(); + Boolean isLeaf = (Boolean)userObject.get(IS_LEAF); + if (isLeaf) { + return count + 1; + } + return count; + }); + } + + private static int count(TreeMapNode node, int count, Visitor visitor) { + count = visitor.visit(node, count); + Iterable children = node.getChildren(); + if (children != null) { + for (TreeMapNode child : children) { + count = count(child, count, visitor); + } + } + return count; + } + + interface Visitor { + int visit(TreeMapNode object, int count); + } +} diff --git a/base/src/main/java/com/twosigma/beakerx/chart/serializer/TreeMapNodeSerializer.java b/base/src/main/java/com/twosigma/beakerx/chart/serializer/TreeMapNodeSerializer.java new file mode 100644 index 0000000..868b3bb --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/chart/serializer/TreeMapNodeSerializer.java @@ -0,0 +1,58 @@ +/* + * Copyright 2014 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.chart.serializer; + +import com.twosigma.beakerx.util.SerializerUtil; +import net.sf.jtreemap.swing.TreeMapNode; +import com.fasterxml.jackson.databind.JsonSerializer; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.core.JsonProcessingException; +import java.io.IOException; +import java.util.Map; + + +public class TreeMapNodeSerializer extends JsonSerializer { + @Override + @SuppressWarnings("unchecked") + public void serialize(TreeMapNode treeMapNode, + JsonGenerator jgen, + SerializerProvider provider) throws + IOException, + JsonProcessingException { + jgen.writeStartObject(); + + jgen.writeObjectField("type", SerializerUtil.getTypeName(treeMapNode)); + jgen.writeObjectField("weight", treeMapNode.getWeight()); + + if (treeMapNode.getValue() != null) { + jgen.writeObjectField("doubleValue", treeMapNode.getDoubleValue()); + jgen.writeObjectField("labelValue", treeMapNode.getLabelValue()); + + Object userObject = treeMapNode.getUserObject(); + Map values = (Map) userObject; + jgen.writeObjectField("label", values.get("label")); + jgen.writeObjectField("color", values.get("color")); + jgen.writeObjectField("tooltip", values.get("tooltip")); + } + + if (treeMapNode.getChildren() != null) + jgen.writeObjectField("children", treeMapNode.getChildren()); + + jgen.writeEndObject(); + } +} diff --git a/base/src/main/java/com/twosigma/beakerx/chart/serializer/TreeMapReducer.java b/base/src/main/java/com/twosigma/beakerx/chart/serializer/TreeMapReducer.java new file mode 100644 index 0000000..a26ca60 --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/chart/serializer/TreeMapReducer.java @@ -0,0 +1,163 @@ +/* + * 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.chart.serializer; + +import net.sf.jtreemap.swing.TreeMapNode; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Queue; + +public class TreeMapReducer { + + private int limit; + + public TreeMapReducer(int limit) { + this.limit = limit; + } + + public TreeMapNode limitTreeMap(TreeMapNode root) { + Queue treeLayers = createTreeLayers(root); + Map mapper = reduceTreeMapChildren(treeLayers); + return mapper.get(root); + } + + private Queue createTreeLayers(TreeMapNode root) { + Queue treeLayers = new LinkedList<>(); + TreeLayer treeLayer = new TreeLayer(); + treeLayer.addNodeLayer(new NodeLayer(root, root.getChildren())); + treeLayers.add(treeLayer); + createNextTreeLayer(treeLayer, treeLayers); + return treeLayers; + } + + private void createNextTreeLayer(TreeLayer treeLayer, Queue treeLayers) { + TreeLayer newTreeLayer = createTreeLayer(treeLayer.getNodeLayers()); + if (!newTreeLayer.getNodeLayers().isEmpty()) { + treeLayers.add(newTreeLayer); + createNextTreeLayer(newTreeLayer, treeLayers); + } + } + + private TreeLayer createTreeLayer(List nodeLayers) { + TreeLayer newTreeLayer = new TreeLayer(); + for (NodeLayer rtl : nodeLayers) { + List children = rtl.getChildren(); + if (children != null) { + for (TreeMapNode child : children) { + NodeLayer nodeLayer = new NodeLayer(child, child.getChildren()); + newTreeLayer.addNodeLayer(nodeLayer); + } + } + } + return newTreeLayer; + } + + private Map reduceTreeMapChildren(Queue treeLayers) { + Map mapper = new HashMap<>(); + TreeCounter treeCounter = new TreeCounter(); + for (TreeLayer tl : treeLayers) { + boolean numberOfNodesChanged = true; + while (numberOfNodesChanged && treeCounter.getCount() <= limit) { + numberOfNodesChanged = tl.addChildToNodeLayers(treeCounter, mapper); + } + } + return mapper; + } + + private class TreeCounter { + private int count = 1; + + public void increase() { + this.count++; + } + + public int getCount() { + return count; + } + } + + + private class TreeLayer { + private List nodeLayers; + + TreeLayer() { + this.nodeLayers = new LinkedList<>(); + } + + List getNodeLayers() { + return nodeLayers; + } + + boolean addChildToNodeLayers(TreeCounter treeCounter, Map mapper) { + boolean atLeastOneChildAdded = false; + for (NodeLayer nl : getNodeLayers()) { + if (treeCounter.getCount() <= limit) { + atLeastOneChildAdded = nl.addChild(treeCounter, mapper) || atLeastOneChildAdded; + } + } + return atLeastOneChildAdded; + } + + void addNodeLayer(NodeLayer nodeLayer) { + this.nodeLayers.add(nodeLayer); + } + } + + private class NodeLayer { + + private final Iterator iter; + private TreeMapNode node; + private List children; + + NodeLayer(TreeMapNode node, List children) { + this.node = node; + this.children = children; + this.iter = (this.children == null) ? Collections.emptyIterator() : children.iterator(); + } + + public TreeMapNode getNode() { + return node; + } + + public List getChildren() { + return children; + } + + boolean addChild(TreeCounter treeCounter, Map mapper) { + if (iter.hasNext()) { + if (!mapper.containsKey(node)) { + TreeMapNode clonedNode = (TreeMapNode) node.clone(); + mapper.put(node, clonedNode); + } + TreeMapNode child = iter.next(); + TreeMapNode clone = (TreeMapNode) child.clone(); + mapper.get(node).add(clone); + mapper.put(child, clone); + if (child.isLeaf()){ + treeCounter.increase(); + } + return true; + } + return false; + } + } + +} diff --git a/base/src/main/java/com/twosigma/beakerx/chart/serializer/TreeMapSerializer.java b/base/src/main/java/com/twosigma/beakerx/chart/serializer/TreeMapSerializer.java new file mode 100644 index 0000000..70195cc --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/chart/serializer/TreeMapSerializer.java @@ -0,0 +1,139 @@ +/* + * Copyright 2014 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.chart.serializer; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.twosigma.beakerx.chart.Color; +import com.twosigma.beakerx.chart.treemap.TreeMap; +import com.twosigma.beakerx.chart.treemap.util.IToolTipBuilder; +import net.sf.jtreemap.swing.TreeMapNode; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +import static com.twosigma.beakerx.chart.serializer.AbstractChartSerializer.NUMBER_OF_POINTS_TO_DISPLAY; +import static com.twosigma.beakerx.chart.serializer.AbstractChartSerializer.ROWS_LIMIT_ITEMS; +import static com.twosigma.beakerx.chart.serializer.AbstractChartSerializer.TOO_MANY_ROWS; +import static com.twosigma.beakerx.chart.serializer.AbstractChartSerializer.TOTAL_NUMBER_OF_POINTS; +import static com.twosigma.beakerx.chart.treemap.TreeMap.ROWS_LIMIT; + +public class TreeMapSerializer extends ChartSerializer { + + public static final String TOOLTIP = "tooltip"; + public static final String GRAPHICS_LIST = "graphics_list"; + public static final String MODE = "mode"; + public static final String STICKY = "sticky"; + public static final String RATIO = "ratio"; + public static final String ROUND = "round"; + public static final String VALUE_ACCESSOR = "valueAccessor"; + public static final String LEAVES = " leaves"; + + private final TreeMapReducer treeMapReducer = new TreeMapReducer(ROWS_LIMIT); + + protected String toHex(Color col) { + return "#" + Integer.toHexString(col.getRGB()).substring(2); + } + + @Override + public void serialize(final TreeMap treeMap, + JsonGenerator jgen, + SerializerProvider provider) throws IOException { + + TreeMapNode root = treeMap.getRoot(); + process(root, node -> setUserObject(treeMap, node)); + + jgen.writeStartObject(); + int numberOfNodes = TreeMapNodeCounter.countAllNodes(root); + jgen.writeObjectField(TOTAL_NUMBER_OF_POINTS, numberOfNodes); + boolean tooManyRows = numberOfNodes > ROWS_LIMIT; + jgen.writeBooleanField(TOO_MANY_ROWS, tooManyRows); + if (tooManyRows) { + root = treeMapReducer.limitTreeMap(root); + jgen.writeObjectField(ROWS_LIMIT_ITEMS, ROWS_LIMIT); + jgen.writeObjectField(NUMBER_OF_POINTS_TO_DISPLAY, TreeMapNodeCounter.countReducedLeaves(root) + LEAVES); + } + + serialize(treeMap, jgen); + + if (root != null) + jgen.writeObjectField(GRAPHICS_LIST, root); + + if (treeMap.getMode() != null) + jgen.writeObjectField(MODE, treeMap.getMode().getJsName()); + if (treeMap.getSticky() != null) + jgen.writeObjectField(STICKY, treeMap.getSticky()); + if (treeMap.getRatio() != null) + jgen.writeObjectField(RATIO, treeMap.getRatio()); + if (treeMap.getRound() != null) + jgen.writeObjectField(ROUND, treeMap.getRound()); + + jgen.writeObjectField(VALUE_ACCESSOR, treeMap.getValueAccessor()); + + jgen.writeEndObject(); + } + + private void setUserObject(TreeMap treeMap, TreeMapNode node) { + Object userObject = node.getUserObject(); + Map values; + if (userObject instanceof Map) { + values = (Map) userObject; + if (node.isLeaf()) { + Color color = treeMap.getColorProvider().getColor(node); + values.put("color", toHex(color)); + IToolTipBuilder toolTipBuilder = treeMap.getToolTipBuilder(); + if (toolTipBuilder != null) { + values.put(TOOLTIP, toolTipBuilder.getToolTip(node)); + } else { + values.put(TOOLTIP, values.get("label")); + } + } + node.setUserObject(values); + } else { + values = new HashMap<>(); + values.put("label", userObject); + IToolTipBuilder toolTipBuilder = treeMap.getToolTipBuilder(); + if (toolTipBuilder != null) { + values.put(TOOLTIP, toolTipBuilder.getToolTip(node)); + } else { + values.put(TOOLTIP, userObject); + } + } + if (node.isLeaf()) { + Color color = treeMap.getColorProvider().getColor(node); + values.put("color", toHex(color)); + } + values.put(TreeMapNodeCounter.IS_LEAF,node.isLeaf()); + + node.setUserObject(values); + } + + private void process(TreeMapNode node, Visitor visitor) { + visitor.visit(node); + Iterable children = node.getChildren(); + if (children != null) { + for (TreeMapNode child : children) { + process(child, visitor); + } + } + } + + interface Visitor { + void visit(T object); + } +} diff --git a/base/src/main/java/com/twosigma/beakerx/chart/serializer/XYChartSerializer.java b/base/src/main/java/com/twosigma/beakerx/chart/serializer/XYChartSerializer.java new file mode 100644 index 0000000..be4284f --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/chart/serializer/XYChartSerializer.java @@ -0,0 +1,70 @@ +/* + * Copyright 2014 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.chart.serializer; + +import com.twosigma.beakerx.chart.xychart.XYChart; +import java.io.IOException; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.core.JsonProcessingException; + +/** + * XYChartSerializer + * + */ +public class XYChartSerializer extends AbstractChartSerializer { + + public static final String GRAPHICS_LIST = "graphics_list"; + public static final String LOD_THRESHOLD = "lodThreshold"; + public static final String X_AUTO_RANGE = "x_auto_range"; + public static final String X_LOWER_BOUND = "x_lower_bound"; + public static final String X_UPPER_BOUND = "x_upper_bound"; + public static final String LOG_X = "log_x"; + public static final String X_LOG_BASE = "x_log_base"; + public static final String X_TICK_LABELS_VISIBLE = "x_tickLabels_visible"; + public static final String Y_TICK_LABELS_VISIBLE = "y_tickLabels_visible"; + public static final String TEXTS = "texts"; + public static final String CONSTANT_BANDS = "constant_bands"; + public static final String CONSTANT_LINES = "constant_lines"; + public static final String RASTERS = "rasters"; + + @Override + public void serialize(XYChart xychart, JsonGenerator jgen, SerializerProvider sp) + throws IOException, JsonProcessingException { + + jgen.writeStartObject(); + + serialize(xychart, jgen); + + jgen.writeObjectField(GRAPHICS_LIST, xychart.getGraphics()); + jgen.writeObjectField(CONSTANT_LINES, xychart.getConstantLines()); + jgen.writeObjectField(CONSTANT_BANDS, xychart.getConstantBands()); + jgen.writeObjectField(RASTERS, xychart.getRasters()); + jgen.writeObjectField(TEXTS, xychart.getTexts()); + jgen.writeObjectField(X_AUTO_RANGE, xychart.getXAutoRange()); + jgen.writeObjectField(X_LOWER_BOUND, xychart.getXLowerBound()); + jgen.writeObjectField(X_UPPER_BOUND, xychart.getXUpperBound()); + jgen.writeObjectField(LOG_X, xychart.getLogX()); + jgen.writeObjectField(X_LOG_BASE, xychart.getXLogBase()); + if (xychart.getLodThreshold() != null) { + jgen.writeObjectField(LOD_THRESHOLD, xychart.getLodThreshold()); + } + jgen.writeObjectField(X_TICK_LABELS_VISIBLE, xychart.isxTickLabelsVisible()); + jgen.writeObjectField(Y_TICK_LABELS_VISIBLE, xychart.isyTickLabelsVisible()); + jgen.writeEndObject(); + } + +} diff --git a/base/src/main/java/com/twosigma/beakerx/chart/serializer/XYGraphicsSerializer.java b/base/src/main/java/com/twosigma/beakerx/chart/serializer/XYGraphicsSerializer.java new file mode 100644 index 0000000..9c9e2c8 --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/chart/serializer/XYGraphicsSerializer.java @@ -0,0 +1,79 @@ +/* + * Copyright 2014 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.chart.serializer; + +import com.twosigma.beakerx.chart.xychart.NanoPlot; +import com.twosigma.beakerx.chart.xychart.plotitem.XYGraphics; +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonSerializer; +import com.fasterxml.jackson.databind.SerializerProvider; + + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +/** + * XYGraphicsSerializer + */ +public class XYGraphicsSerializer extends GraphicsSerializer { + + public static final String DISPLAY_NAME = "display_name"; + + @Override + public void serialize(T xyGraphics, JsonGenerator jgen, SerializerProvider sp) + throws IOException { + + validate(xyGraphics); + + super.serialize(xyGraphics, jgen, sp); + + boolean isNanoPlot = NanoPlot.isNanoPlotClass(xyGraphics.getPlotType()); + jgen.writeObjectField("x", isNanoPlot ? processLargeNumbers(xyGraphics.getX()) : xyGraphics.getX()); + jgen.writeObjectField("y", xyGraphics.getY()); + jgen.writeObjectField(DISPLAY_NAME, xyGraphics.getDisplayName()); + if (xyGraphics.getLodFilter() != null){ + jgen.writeObjectField("lod_filter", xyGraphics.getLodFilter().getText()); + } + List toolTips = xyGraphics.getToolTips(); + if (toolTips != null) { + jgen.writeObjectField("tooltips", toolTips); + } + } + + private void validate(T xyGraphics) { + if (xyGraphics.getX() == null || xyGraphics.getX().isEmpty()) { + throw new IllegalStateException(Messages.PROVIDE_X_COORDINATE); + } + if (xyGraphics.getY() == null || xyGraphics.getY().isEmpty()) { + throw new IllegalStateException(Messages.PROVIDE_Y_COORDINATE); + } + } + + private List processLargeNumbers(List list) { + List stringList = new ArrayList<>(list.size()); + for(Number n : list) { + if (n != null){ + stringList.add(n.toString()); + } else { + stringList.add(""); + } + } + return stringList; + } + +} diff --git a/base/src/main/java/com/twosigma/beakerx/chart/serializer/YAxisSerializer.java b/base/src/main/java/com/twosigma/beakerx/chart/serializer/YAxisSerializer.java new file mode 100644 index 0000000..f4394aa --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/chart/serializer/YAxisSerializer.java @@ -0,0 +1,50 @@ +/* + * Copyright 2014 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.chart.serializer; + +import com.twosigma.beakerx.util.SerializerUtil; +import com.twosigma.beakerx.chart.xychart.plotitem.YAxis; +import java.io.IOException; +import com.fasterxml.jackson.databind.JsonSerializer; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.core.JsonProcessingException; + +public class YAxisSerializer extends JsonSerializer { + + public static final String TYPE = "type"; + public static final String AUTO_RANGE_INCLUDES_ZERO = "auto_range_includes_zero"; + + @Override + public void serialize(YAxis yAxis, JsonGenerator jgen, SerializerProvider sp) + throws IOException, JsonProcessingException { + + jgen.writeStartObject(); + jgen.writeObjectField(TYPE, SerializerUtil.getTypeName(yAxis)); + jgen.writeObjectField("label", yAxis.getLabel()); + jgen.writeObjectField("auto_range", yAxis.getAutoRange()); + jgen.writeObjectField(AUTO_RANGE_INCLUDES_ZERO, yAxis.getAutoRangeIncludesZero()); + jgen.writeObjectField("lower_margin", yAxis.getLowerMargin()); + jgen.writeObjectField("upper_margin", yAxis.getUpperMargin()); + jgen.writeObjectField("lower_bound", yAxis.getLowerBound()); + jgen.writeObjectField("upper_bound", yAxis.getUpperBound()); + jgen.writeObjectField("use_log", yAxis.getLog()); + jgen.writeObjectField("log_base", yAxis.getLogBase()); + jgen.writeEndObject(); + } + +} diff --git a/base/src/main/java/com/twosigma/beakerx/chart/treemap/Mode.java b/base/src/main/java/com/twosigma/beakerx/chart/treemap/Mode.java new file mode 100644 index 0000000..41291d4 --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/chart/treemap/Mode.java @@ -0,0 +1,37 @@ +/* + * Copyright 2014 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.chart.treemap; + +public enum Mode { + SQUARIFY("squarify"),//rectangular subdivision; squareness controlled via the target ratio. + SLICE("slice"),// horizontal subdivision. + DICE("dice"),// vertical subdivision. + SLICE_DIC("slice-dic");// alternating between horizontal and vertical subdivision. + + private String jsName; + + Mode() { + } + + Mode(String jsName) { + this.jsName = jsName; + } + + public String getJsName() { + return jsName; + } +} diff --git a/base/src/main/java/com/twosigma/beakerx/chart/treemap/TreeMap.java b/base/src/main/java/com/twosigma/beakerx/chart/treemap/TreeMap.java new file mode 100644 index 0000000..2205e75 --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/chart/treemap/TreeMap.java @@ -0,0 +1,189 @@ +/* + * Copyright 2014 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.chart.treemap; + +import com.twosigma.beakerx.chart.Chart; +import com.twosigma.beakerx.chart.ChartToJson; +import com.twosigma.beakerx.chart.treemap.util.ColorProvider; +import com.twosigma.beakerx.chart.treemap.util.IToolTipBuilder; +import com.twosigma.beakerx.chart.treemap.util.RandomColorProvider; +import net.sf.jtreemap.swing.TreeMapNode; + +import static com.twosigma.beakerx.widget.BeakerxPlot.MODEL_NAME_VALUE; +import static com.twosigma.beakerx.widget.BeakerxPlot.VIEW_NAME_VALUE; + +public class TreeMap extends Chart { + + public static final int ROWS_LIMIT = 1_000; + + // root of the tree + private TreeMapNode root = null; + + // color provider + private ColorProvider colorProvider = null; + + private IToolTipBuilder toolTipBuilder = null; + + /** + * If mode is specified, sets the layout algorithm. If mode is not specified, returns the current layout + * algorithm, which defaults to "squarify". The following modes are supported: + *

+ * squarify - rectangular subdivision; squareness controlled via the target ratio. + * slice - horizontal subdivision. + * dice - vertical subdivision. + * slice-dice - alternating between horizontal and vertical subdivision. + */ + private Mode mode; + + + /** + * If ratio is specified, sets the layout ratio. If ratio is not specified, returns the current layout + * ratio, which defaults to .5 * (1 + Math.sqrt(5)) + */ + private Double ratio; + + /** + * If sticky is specified, sets whether or not the treemap layout is "sticky": a sticky treemap + * layout will preserve the relative arrangement of nodes across transitions. The allocation of nodes + * into squarified horizontal and vertical rows is persisted across updates by storing a z attribute + * on the last element in each row; this allows nodes to be resized smoothly, without shuffling or + * occlusion that would impede perception of changing values. Note, however, that this results in a + * suboptimal layout for one of the two states. If sticky is not specified, returns whether the + * treemap layout is sticky. + * Implementation note: sticky treemaps cache the array of nodes internally; therefore, + * it is not possible to reuse the same layout instance on multiple datasets. To reset the + * cached state when switching datasets with a sticky layout, call sticky(true) again. Since + * version 1.25.0, hierarchy layouts no longer copy the input data by default on each invocation, + * so it may be possible to eliminate caching and make the layout fully stateless. + */ + private Boolean sticky; + + /** + * If round is specified, sets whether or not the treemap layout will round to exact pixel boundaries. + * This can be nice to avoid antialiasing artifacts in SVG. If round is not specified, returns whether + * the treemap will be rounded. + */ + private Boolean round; + + + //determine value accessor for chart + private ValueAccessor valueAccessor = ValueAccessor.VALUE; + + + public TreeMap(final TreeMapNode root) { + this(); + setRoot(root); + } + + public TreeMap() { + super(); + openComm(); + setColorProvider(new RandomColorProvider()); + setShowLegend(false); + } + + /** + * get the root. + * + * @return the root + */ + public TreeMapNode getRoot() { + return root; + } + + + /** + * set the new root. + * + * @param newRoot the new root to set + */ + public void setRoot(final TreeMapNode newRoot) { + root = newRoot; + } + + public Mode getMode() { + return mode; + } + + public void setMode(Mode mode) { + this.mode = mode; + sendModelUpdate(ChartToJson.serializeTreeMapMode(this.mode)); + } + + public Double getRatio() { + return ratio; + } + + public void setRatio(Double ratio) { + this.ratio = ratio; + sendModelUpdate(ChartToJson.serializeTreeMapRatio(this.ratio)); + } + + public Boolean getSticky() { + return sticky; + } + + public void setSticky(Boolean sticky) { + this.sticky = sticky; + sendModelUpdate(ChartToJson.serializeTreeMapSticky(this.sticky)); + } + + public Boolean getRound() { + return round; + } + + public void setRound(Boolean round) { + this.round = round; + sendModelUpdate(ChartToJson.serializeTreeMapRound(this.round)); + } + + public ValueAccessor getValueAccessor() { + return valueAccessor; + } + + public void setValueAccessor(ValueAccessor valueAccessor) { + this.valueAccessor = valueAccessor; + sendModelUpdate(ChartToJson.serializeTreeMapValueAccessor(this.valueAccessor)); + } + + public void setColorProvider(final ColorProvider newColorProvider) { + colorProvider = newColorProvider; + } + + public ColorProvider getColorProvider() { + return colorProvider; + } + + public IToolTipBuilder getToolTipBuilder() { + return toolTipBuilder; + } + + public void setToolTipBuilder(IToolTipBuilder toolTipBuilder) { + this.toolTipBuilder = toolTipBuilder; + sendModelUpdate(); + } + + @Override + public String getModelNameValue() { + return MODEL_NAME_VALUE; + } + + @Override + public String getViewNameValue() { + return VIEW_NAME_VALUE; + } +} diff --git a/base/src/main/java/com/twosigma/beakerx/chart/treemap/ValueAccessor.java b/base/src/main/java/com/twosigma/beakerx/chart/treemap/ValueAccessor.java new file mode 100644 index 0000000..add33df --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/chart/treemap/ValueAccessor.java @@ -0,0 +1,22 @@ +/* + * Copyright 2014 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.chart.treemap; + + +public enum ValueAccessor { + VALUE, + WEIGHT +} diff --git a/base/src/main/java/com/twosigma/beakerx/chart/treemap/util/ColorProvider.java b/base/src/main/java/com/twosigma/beakerx/chart/treemap/util/ColorProvider.java new file mode 100644 index 0000000..e1c5899 --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/chart/treemap/util/ColorProvider.java @@ -0,0 +1,65 @@ +/* + * Copyright 2014 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.chart.treemap.util; + +import com.twosigma.beakerx.chart.Color; +import com.twosigma.beakerx.chart.treemap.ValueAccessor; +import net.sf.jtreemap.swing.TreeMapNode; + +import java.io.Serializable; +import java.util.Enumeration; + +public abstract class ColorProvider implements Serializable { + + protected ValueAccessor valueAccessor = ValueAccessor.VALUE; + + public abstract Color getColor(TreeMapNode value); + + protected void setValues(final TreeMapNode root) { + if (root.isLeaf()) { + double value; + if (valueAccessor == ValueAccessor.VALUE) { + if (root.getValue() == null) { + return; + } + value = root.getValue().getValue(); + } else { + value = root.getWeight(); + } + + if (maxValue == null || value >= maxValue) { + maxValue = value; + } + if (minValue == null || value <= minValue) { + minValue = value; + } + } else { + for (final Enumeration e = root.children(); e.hasMoreElements(); ) { + final TreeMapNode node = (TreeMapNode) e.nextElement(); + setValues(node); + } + } + } + + protected double getValue(TreeMapNode node) { + return (node != null ? ((valueAccessor == ValueAccessor.VALUE) ? + node.getValue().getValue() : node.getWeight()) : 0.00); + } + + protected Double maxValue; + + protected Double minValue; +} diff --git a/base/src/main/java/com/twosigma/beakerx/chart/treemap/util/ColorUtils.java b/base/src/main/java/com/twosigma/beakerx/chart/treemap/util/ColorUtils.java new file mode 100644 index 0000000..32a8544 --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/chart/treemap/util/ColorUtils.java @@ -0,0 +1,63 @@ +/* + * Copyright 2014 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.chart.treemap.util; + + +import com.twosigma.beakerx.chart.Color; + +public class ColorUtils { + + public static Color interpolateColor(final java.awt.Color COLOR1, + final java.awt.Color COLOR2, + float fraction) { + final float INT_TO_FLOAT_CONST = 1f / 255f; + fraction = Math.min(fraction, 1f); + fraction = Math.max(fraction, 0f); + + final float RED1 = COLOR1.getRed() * INT_TO_FLOAT_CONST; + final float GREEN1 = COLOR1.getGreen() * INT_TO_FLOAT_CONST; + final float BLUE1 = COLOR1.getBlue() * INT_TO_FLOAT_CONST; + final float ALPHA1 = COLOR1.getAlpha() * INT_TO_FLOAT_CONST; + + final float RED2 = COLOR2.getRed() * INT_TO_FLOAT_CONST; + final float GREEN2 = COLOR2.getGreen() * INT_TO_FLOAT_CONST; + final float BLUE2 = COLOR2.getBlue() * INT_TO_FLOAT_CONST; + final float ALPHA2 = COLOR2.getAlpha() * INT_TO_FLOAT_CONST; + + final float DELTA_RED = RED2 - RED1; + final float DELTA_GREEN = GREEN2 - GREEN1; + final float DELTA_BLUE = BLUE2 - BLUE1; + final float DELTA_ALPHA = ALPHA2 - ALPHA1; + + float red = RED1 + (DELTA_RED * fraction); + float green = GREEN1 + (DELTA_GREEN * fraction); + float blue = BLUE1 + (DELTA_BLUE * fraction); + float alpha = ALPHA1 + (DELTA_ALPHA * fraction); + + red = Math.min(red, 1f); + red = Math.max(red, 0f); + green = Math.min(green, 1f); + green = Math.max(green, 0f); + blue = Math.min(blue, 1f); + blue = Math.max(blue, 0f); + alpha = Math.min(alpha, 1f); + alpha = Math.max(alpha, 0f); + + return new Color((new java.awt.Color(red, green, blue, alpha)).getRGB()); + } + +} diff --git a/base/src/main/java/com/twosigma/beakerx/chart/treemap/util/GradientColorProvider.java b/base/src/main/java/com/twosigma/beakerx/chart/treemap/util/GradientColorProvider.java new file mode 100644 index 0000000..dd685bf --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/chart/treemap/util/GradientColorProvider.java @@ -0,0 +1,53 @@ +/* + * Copyright 2014 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.chart.treemap.util; + +import com.twosigma.beakerx.chart.Color; +import com.twosigma.beakerx.chart.treemap.TreeMap; +import net.sf.jtreemap.swing.TreeMapNode; + + +public class GradientColorProvider extends ColorProvider { + + private java.awt.Color start; + private java.awt.Color end; + + public GradientColorProvider(TreeMap treeMap, Color start, Color end) { + valueAccessor = treeMap.getValueAccessor(); + + this.start = new java.awt.Color(start.getRGB()); + this.end = new java.awt.Color(end.getRGB());; + + setValues(treeMap.getRoot()); + } + + public GradientColorProvider(TreeMap treeMap) { + this(treeMap, Color.RED, Color.GREEN); + } + + + @Override + public Color getColor(TreeMapNode node) { + double value = getValue(node); + float result = (float) ((value - minValue) / (maxValue - minValue)); + return ColorUtils.interpolateColor(start, + end, + result); + } + + +} diff --git a/base/src/main/java/com/twosigma/beakerx/chart/treemap/util/IToolTipBuilder.java b/base/src/main/java/com/twosigma/beakerx/chart/treemap/util/IToolTipBuilder.java new file mode 100644 index 0000000..08959fa --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/chart/treemap/util/IToolTipBuilder.java @@ -0,0 +1,23 @@ +/* + * Copyright 2014 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.chart.treemap.util; + +import net.sf.jtreemap.swing.TreeMapNode; + +public interface IToolTipBuilder { + String getToolTip(TreeMapNode node); +} diff --git a/base/src/main/java/com/twosigma/beakerx/chart/treemap/util/RandomColorProvider.java b/base/src/main/java/com/twosigma/beakerx/chart/treemap/util/RandomColorProvider.java new file mode 100644 index 0000000..7322e95 --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/chart/treemap/util/RandomColorProvider.java @@ -0,0 +1,117 @@ +/* + * Copyright 2014 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.chart.treemap.util; + +import com.twosigma.beakerx.chart.Color; +import net.sf.jtreemap.swing.TreeMapNode; + +import java.lang.reflect.Field; +import java.util.List; + + +public class RandomColorProvider extends ColorProvider { + + private static final Color[] COLOURS = new Color[]{new Color(33, 87, 141), // blue + new Color(140, 29, 23), // red + new Color(150, 130, 54),// yellow + new Color(20, 30, 120), // violet + new Color(54, 100, 54), // green + new Color(0, 30, 50), // dark + new Color(102, 102, 51), + new Color(255, 51, 153), + new Color(255, 153, 51), + new Color(204, 204, 51), + new Color(205, 102, 204), + new Color(51, 153, 255), + new Color(153, 102, 0)}; + + private int cursor = 0; + private final Color[] colours; + private boolean groupByParent = false; + + private final java.util.TreeMap mapping = new java.util.TreeMap<>(); + + public RandomColorProvider() { + this.colours = COLOURS; + } + + public RandomColorProvider(final Color[] colours) { + this.colours = colours; + } + + public RandomColorProvider(List colors) { + this.colours = new Color[colors.size()]; + for (int i = 0; i < colors.size(); i++) { + this.colours[i] = createChartColor(colors.get(i)); + } + } + + @Override + public Color getColor(TreeMapNode node) { + Object value; + if (groupByParent && node.getParent() instanceof TreeMapNode){ + value = ((TreeMapNode) node.getParent()).getLabel(); + }else{ + value = getValue(node); + } + + if (!this.mapping.containsKey(value)) { + mapping.put(value, colours[this.cursor]); + cursor++; + if (this.cursor == colours.length) { + cursor = 0; + } + } + return mapping.get(value); + } + + private Color createChartColor(Object color) { + if (color instanceof List) { + try { + return new Color((int) ((List) color).get(0), + (int) ((List) color).get(1), + (int) ((List) color).get(2)); + } catch (IndexOutOfBoundsException x) { + throw new RuntimeException("Color list too short"); + } + + } + String colorAsStr = (String) color; + if (colorAsStr.indexOf("#") == 0) { + return Color.decode(colorAsStr); + } + return colorFromName(colorAsStr); + } + + private Color colorFromName(String color) { + try { + Field field = Class.forName("com.twosigma.beakerx.chart.Color").getField(color); + return (Color) field.get(null); + } catch (ClassNotFoundException | IllegalAccessException | NoSuchFieldException x) { + throw new RuntimeException(String.format("Can not parse color '%s'", color), x); + } + } + + public boolean isGroupByParent() { + return groupByParent; + } + + public void setGroupByParent(boolean groupByParent) { + this.groupByParent = groupByParent; + } +} + diff --git a/base/src/main/java/com/twosigma/beakerx/chart/xychart/CombinedPlot.java b/base/src/main/java/com/twosigma/beakerx/chart/xychart/CombinedPlot.java new file mode 100644 index 0000000..21c347b --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/chart/xychart/CombinedPlot.java @@ -0,0 +1,198 @@ +/* + * Copyright 2014 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.chart.xychart; + +import com.twosigma.beakerx.chart.ChartDetails; +import com.twosigma.beakerx.chart.ChartToJson; +import com.twosigma.beakerx.chart.actions.CombinedPlotActionObject; +import com.twosigma.beakerx.chart.actions.GraphicsActionObject; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import static com.twosigma.beakerx.widget.BeakerxPlot.MODEL_NAME_VALUE; +import static com.twosigma.beakerx.widget.BeakerxPlot.VIEW_NAME_VALUE; + +/** + * CombinedPlot + */ +public class CombinedPlot extends ChartDetails { + private int initWidth = 640; + private int initHeight = 480; + private String title; + private String xLabel; + private List subplots = new ArrayList<>(); + private List weights = new ArrayList<>(); + private boolean xTickLabelsVisible = true; + private boolean yTickLabelsVisible = true; + private boolean autoZoom = false; + + public CombinedPlot() { + super(); + openComm(); + } + + @Override + public String getModelNameValue() { + return MODEL_NAME_VALUE; + } + + @Override + public String getViewNameValue() { + return VIEW_NAME_VALUE; + } + + public CombinedPlot setInitWidth(int w) { + this.initWidth = w; + return this; + } + + public Integer getInitWidth() { + return this.initWidth; + } + + public CombinedPlot setInitHeight(int h) { + this.initHeight = h; + return this; + } + + public Integer getInitHeight() { + return this.initHeight; + } + + public CombinedPlot setTitle(String title) { + this.title = title; + return this; + } + + public String getTitle() { + return this.title; + } + + public CombinedPlot setXLabel(String xLabel) { + this.xLabel = xLabel; + return this; + } + + public CombinedPlot setxLabel(String xLabel) { + this.xLabel = xLabel; + return this; + } + + public String getXLabel() { + return this.xLabel; + } + + public String getxLabel() { + return getXLabel(); + } + + public CombinedPlot add(XYChart plot, int weight) { + this.subplots.add(plot); + this.weights.add(weight); + sendModel(); + return this; + } + + public CombinedPlot add(XYChart plot) { + this.subplots.add(plot); + this.weights.add(1); + return this; + } + + public CombinedPlot leftShift(Object obj) { + if (obj instanceof XYChart) { + this.add((XYChart) obj, 1); + } else if (obj instanceof List && ((List) obj).size() == 2) { + List list = (List) obj; + XYChart plot = (XYChart) list.get(0); + int weight = ((Number) list.get(1)).intValue(); + this.add(plot, weight); + } else { + throw new IllegalArgumentException( + "leftShift takes XYChart or List that hold a XYChart and weight"); + } + return this; + } + + public List getSubplots() { + return this.subplots; + } + + public List getWeights() { + return this.weights; + } + + public boolean isyTickLabelsVisible() { + return yTickLabelsVisible; + } + + public boolean isYTickLabelsVisible() { + return isyTickLabelsVisible(); + } + + public void setyTickLabelsVisible(boolean yTickLabelsVisible) { + this.yTickLabelsVisible = yTickLabelsVisible; + } + + public void setYTickLabelsVisible(boolean yTickLabelsVisible) { + setyTickLabelsVisible(yTickLabelsVisible); + } + + public boolean isxTickLabelsVisible() { + return xTickLabelsVisible; + } + + public boolean isXTickLabelsVisible() { + return isxTickLabelsVisible(); + } + + public void setxTickLabelsVisible(boolean xTickLabelsVisible) { + this.xTickLabelsVisible = xTickLabelsVisible; + } + + public void setXTickLabelsVisible(boolean xTickLabelsVisible) { + setxTickLabelsVisible(xTickLabelsVisible); + } + + public boolean getAutoZoom() { + return this.autoZoom; + } + + public CombinedPlot setAutoZoom(boolean autoZoom) { + this.autoZoom = autoZoom; + return this; + } + + @Override + protected void updateDetails(GraphicsActionObject info) { + CombinedPlotActionObject combinedPlotActionObject = (CombinedPlotActionObject) info; + XYChart xyChart = getSubplots().get(combinedPlotActionObject.getSubplotIndex()); + xyChart.setDetails(info); + } + + @Override + protected Map serializeToJsonObject() { + return ChartToJson.toJson(this); + } + + @Override + protected Map serializeToJsonObject(Object item) { + return ChartToJson.toJson(item); + } +} \ No newline at end of file diff --git a/base/src/main/java/com/twosigma/beakerx/chart/xychart/NanoPlot.java b/base/src/main/java/com/twosigma/beakerx/chart/xychart/NanoPlot.java new file mode 100644 index 0000000..566f24e --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/chart/xychart/NanoPlot.java @@ -0,0 +1,24 @@ +/* + * Copyright 2014 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.chart.xychart; + + +public class NanoPlot extends TimePlot { + static public boolean isNanoPlotClass(Class plotClass) { + return plotClass != null && NanoPlot.class.isAssignableFrom(plotClass); + } +} diff --git a/base/src/main/java/com/twosigma/beakerx/chart/xychart/Plot.java b/base/src/main/java/com/twosigma/beakerx/chart/xychart/Plot.java new file mode 100644 index 0000000..2efc6f9 --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/chart/xychart/Plot.java @@ -0,0 +1,39 @@ +/* + * Copyright 2014 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.chart.xychart; + +import static com.twosigma.beakerx.widget.BeakerxPlot.MODEL_NAME_VALUE; +import static com.twosigma.beakerx.widget.BeakerxPlot.VIEW_NAME_VALUE; + +public class Plot extends XYChart { + + public Plot(){ + super(); + openComm(); + } + + @Override + public String getModelNameValue() { + return MODEL_NAME_VALUE; + } + + @Override + public String getViewNameValue() { + return VIEW_NAME_VALUE; + } + +} diff --git a/base/src/main/java/com/twosigma/beakerx/chart/xychart/SimpleTimePlot.java b/base/src/main/java/com/twosigma/beakerx/chart/xychart/SimpleTimePlot.java new file mode 100644 index 0000000..05ad9b4 --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/chart/xychart/SimpleTimePlot.java @@ -0,0 +1,358 @@ +/* + * Copyright 2014 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.chart.xychart; + +import com.twosigma.beakerx.chart.Color; +import com.twosigma.beakerx.chart.xychart.plotitem.Line; +import com.twosigma.beakerx.chart.xychart.plotitem.Points; +import com.twosigma.beakerx.chart.xychart.plotitem.XYGraphics; +import com.twosigma.beakerx.util.DateUtil; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.*; + +public class SimpleTimePlot extends TimePlot{ + + private List> data; + private String timeColumn = "time"; + private List columns; + private List displayNames; + private List colors; + private boolean displayLines = true; + private boolean displayPoints = false; + + public SimpleTimePlot(List> data, List columns) { + this(null, data, columns); + } + + public SimpleTimePlot(Map parameters, + List> data, + List columns) { + this.data = data; + this.columns = columns; + + //default values + setUseToolTip(true); + setShowLegend(true); + setXLabel("Time"); + + if (parameters != null) { + for (Map.Entry entry : parameters.entrySet()) { + String fieldName = entry.getKey(); + Object fieldValue = entry.getValue(); + + ReflectionUtils.set(this, fieldName, fieldValue); + } + } + + //default the names for the lines and points to the same as the column + if (displayNames == null || displayNames.size() == 0) { + displayNames = columns; + } + + reinitialize(); + } + + private List getChartColors() { + List chartColors = new ArrayList<>(); + if (colors != null) { + for (int i = 0; i < columns.size(); i++) { + if (i < colors.size()) { + chartColors.add(createChartColor(colors.get(i))); + } + } + } + return chartColors; + } + + private Color createChartColor(Object color) { + if (color instanceof Color) { + return (Color) color; + } + if (color instanceof java.awt.Color) { + return new Color((java.awt.Color) color); + } + if (color instanceof List) { + try { + return new Color((int) ((List) color).get(0), + (int) ((List) color).get(1), + (int) ((List) color).get(2)); + } catch (IndexOutOfBoundsException x) { + throw new RuntimeException("Color list too short"); + } + + } + String colorAsStr = (String) color; + if (colorAsStr.indexOf("#") == 0) { + return Color.decode(colorAsStr); + } + return colorFromName(colorAsStr); + } + + private Color colorFromName(String color) { + try { + Field field = Class.forName("com.twosigma.beakerx.chart.Color").getField(color); + return (Color) field.get(null); + } catch (ClassNotFoundException | IllegalAccessException | NoSuchFieldException x) { + throw new RuntimeException(String.format("Can not parse color '%s'", color), x); + } + } + + private void reinitialize() { + List graphics = getGraphics(); + filter(graphics, new Predicate() { + public boolean test(XYGraphics graphic) { + return !(graphic instanceof Line || graphic instanceof Points); + } + }); + + List xs = new ArrayList<>(); + List> yss = new ArrayList<>(); + Set dataColumnsNames = new HashSet<>(); + + if (data != null && columns != null) { + for (Map row : data) { + dataColumnsNames.addAll(row.keySet()); + + xs.add(getNumberForTimeColumn(row.get(timeColumn))); + + for (int i = 0; i < columns.size(); i++) { + String column = columns.get(i); + + if (i >= yss.size()) { + yss.add(new ArrayList()); + } + yss.get(i).add(getNumberForTimeColumn(row.get(column))); + } + } + + final HashSet columnsWithoutData = getColumnsWithoutData(dataColumnsNames); + if (!columnsWithoutData.isEmpty()) { + throw new IllegalArgumentException(String.format("Chart data not found for columns: %s", columnsWithoutData)); + } + + List colors = getChartColors(); + + for (int i = 0; i < yss.size(); i++) { + List ys = yss.get(i); + + if (displayLines) { + Line line = new Line(); + line.setX(xs); + line.setY(ys); + + if (displayNames != null && i < displayNames.size()) { + line.setDisplayName(displayNames.get(i)); + } else { + line.setDisplayName(columns.get(i)); + } + if(i < colors.size()){ + line.setColor(colors.get(i)); + } + + add(line); + } + + if (displayPoints) { + Points points = new Points(); + points.setX(xs); + points.setY(ys); + + if (displayNames != null && i < displayNames.size()) { + points.setDisplayName(displayNames.get(i)); + } else { + points.setDisplayName(columns.get(i)); + } + if(i < colors.size()){ + points.setColor(colors.get(i)); + } + + add(points); + } + } + } + } + + private Number getNumberForTimeColumn(Object o) { + if(o instanceof Number) { + return (Number) o; + } + return DateUtil.dateToLong(o); + } + + public List> getData() { + return data; + } + + public void setData(List> data) { + this.data = data; + reinitialize(); + } + + public List getColumns() { + return columns; + } + + public void setColumns(List columns) { + this.columns = columns; + reinitialize(); + } + + public void setDisplayNames(List displayNames) { + this.displayNames = displayNames; + if (displayNames != null) { + List graphics = getGraphics(); + int i = 0; + for (XYGraphics graphic : graphics) { + if (graphic instanceof Line) { + graphic.setDisplayName(displayNames.get(++i)); + } + } + } + } + + public List getDisplayNames() { + return displayNames; + } + + + public void setColors(List colors) { + this.colors = colors; + } + + public List getColors() { + return colors; + } + + public String getTimeColumn() { + return timeColumn; + } + + public void setTimeColumn(String timeColumn) { + this.timeColumn = timeColumn; + reinitialize(); + } + + public boolean isDisplayLines() { + return displayLines; + } + + public void setDisplayLines(boolean displayLines) { + this.displayLines = displayLines; + reinitialize(); + } + + public boolean isDisplayPoints() { + return displayPoints; + } + + public void setDisplayPoints(boolean displayPoints) { + this.displayPoints = displayPoints; + reinitialize(); + } + + private HashSet getColumnsWithoutData(Set dataColumnsNames) { + final HashSet columnsCopy = new HashSet<>(columns); + columnsCopy.removeAll(dataColumnsNames); + return columnsCopy; + } + + private interface Predicate { + boolean test(T o); + } + + private static void filter(Collection collection, Predicate predicate) { + if ((collection != null) && (predicate != null)) { + Iterator itr = collection.iterator(); + while (itr.hasNext()) { + T obj = itr.next(); + if (!predicate.test(obj)) { + itr.remove(); + } + } + } + } + + private static class ReflectionUtils { + private static Map SETTERS_MAP = new HashMap(); + + static boolean set(Object object, String fieldName, Object fieldValue) { + Class clazz = object.getClass(); + while (clazz != null) { + try { + Field field = clazz.getDeclaredField(fieldName); + field.setAccessible(true); + field.set(object, fieldValue); + return true; + } catch (NoSuchFieldException e) { + clazz = clazz.getSuperclass(); + } catch (Exception expected) { + //nothing to do + } + } + return callSetter(object, fieldName, fieldValue); + } + + private static boolean callSetter(Object obj, String fieldName, Object fieldValue) { + + String key = String.format("%s.%s(%s)", obj.getClass().getName(), + fieldName, fieldValue.getClass().getName()); + Method m = null; + if (!SETTERS_MAP.containsKey(key)) { + m = findMethod(obj, fieldName, fieldValue); + SETTERS_MAP.put(key, m); + } else { + m = SETTERS_MAP.get(key); + } + if (m != null) { + try { + m.invoke(obj, fieldValue); + return true; + } catch (Throwable ignored) { + //expected + } + } + return false; + } + + private static Method findMethod(Object obj, String fieldName, Object fieldValue) { + Method m = null; + Class theClass = obj.getClass(); + String setter = String.format("set%C%s", + fieldName.charAt(0), fieldName.substring(1)); + Class paramType = fieldValue.getClass(); + while (paramType != null) { + try { + m = theClass.getMethod(setter, paramType); + return m; + } catch (NoSuchMethodException ex) { + // try on the interfaces of this class + for (Class iface : paramType.getInterfaces()) { + try { + m = theClass.getMethod(setter, iface); + return m; + } catch (NoSuchMethodException ignored) { + } + } + paramType = paramType.getSuperclass(); + } + } + return m; + } + } +} diff --git a/base/src/main/java/com/twosigma/beakerx/chart/xychart/TimePlot.java b/base/src/main/java/com/twosigma/beakerx/chart/xychart/TimePlot.java new file mode 100644 index 0000000..142c054 --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/chart/xychart/TimePlot.java @@ -0,0 +1,63 @@ +/* + * Copyright 2014 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.chart.xychart; + +import java.util.Date; +import java.util.List; + +import static com.twosigma.beakerx.widget.BeakerxPlot.MODEL_NAME_VALUE; +import static com.twosigma.beakerx.widget.BeakerxPlot.VIEW_NAME_VALUE; + +public class TimePlot extends XYChart { + + public TimePlot(){ + super(); + openComm(); + } + + @Override + public String getModelNameValue() { + return MODEL_NAME_VALUE; + } + + @Override + public String getViewNameValue() { + return VIEW_NAME_VALUE; + } + + public XYChart setXBound(Date lower, Date upper) { + setXBound((double) lower.getTime(), (double) upper.getTime()); + return this; + } + + public XYChart setxBound(Date lower, Date upper) { + return setXBound(lower, upper); + } + + @Override + public XYChart setXBound(List bound) { + if (bound.size() != 2) { + throw new IllegalArgumentException("to set the x bound, the list needs to be of size=2"); + } + if (bound.get(0) instanceof Date && bound.get(1) instanceof Date) { + setXBound((Date) bound.get(0), (Date) bound.get(1)); + } else { + super.setXBound(bound); + } + return this; + } +} diff --git a/base/src/main/java/com/twosigma/beakerx/chart/xychart/XYChart.java b/base/src/main/java/com/twosigma/beakerx/chart/xychart/XYChart.java new file mode 100644 index 0000000..26adf83 --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/chart/xychart/XYChart.java @@ -0,0 +1,269 @@ +/* + * Copyright 2014 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.chart.xychart; + +import com.twosigma.beakerx.chart.AbstractChart; +import com.twosigma.beakerx.chart.ChartToJson; +import com.twosigma.beakerx.chart.xychart.plotitem.ConstantBand; +import com.twosigma.beakerx.chart.xychart.plotitem.ConstantLine; +import com.twosigma.beakerx.chart.xychart.plotitem.Rasters; +import com.twosigma.beakerx.chart.xychart.plotitem.Text; +import com.twosigma.beakerx.chart.xychart.plotitem.XYGraphics; + +import java.util.ArrayList; +import java.util.List; + +abstract public class XYChart extends AbstractChart { + + private final List xyGraphics = new ArrayList<>(); + private final List constantLines = new ArrayList<>(); + private final List constantBands = new ArrayList<>(); + private final List rasters = new ArrayList<>(); + private final List texts = new ArrayList<>(); + private boolean xAutoRange = true; + private double xLowerBound; + private double xUpperBound; + private boolean logX = false; + private double xLogBase = 10; + private Integer lodThreshold = null; + private boolean xTickLabelsVisible = true; + private boolean yTickLabelsVisible = true; + + public XYChart add(XYGraphics graphics) { + graphics.setPlotType(this.getClass()); + this.xyGraphics.add(graphics); + sendModelUpdate(ChartToJson.serializeXYGraphics(this.xyGraphics)); + return this; + } + + public XYChart leftShift(XYGraphics graphics) { + return add(graphics); + } + + public List getGraphics() { + return this.xyGraphics; + } + + public XYChart add(ConstantLine constantLine) { + constantLine.setPlotType(this.getClass()); + this.constantLines.add(constantLine); + sendModelUpdate(ChartToJson.serializeConstantLines(this.constantLines)); + return this; + } + + public XYChart leftShift(ConstantLine constantLine) { + return add(constantLine); + } + + public List getConstantLines() { + return constantLines; + } + + public XYChart add(ConstantBand constantBand) { + this.constantBands.add(constantBand); + sendModelUpdate(ChartToJson.serializeConstantBands(this.constantBands)); + return this; + } + + public XYChart leftShift(ConstantBand constantBand) { + return add(constantBand); + } + + public List getConstantBands() { + return constantBands; + } + + public XYChart add(Text text) { + text.setPlotType(this.getClass()); + this.texts.add(text); + sendModelUpdate(ChartToJson.serializeTexts(this.texts)); + return this; + } + + public XYChart leftShift(Text text) { + return add(text); + } + + public List getTexts() { + return this.texts; + } + + public XYChart add(Rasters raster) { + this.rasters.add(raster); + sendModelUpdate(ChartToJson.serializeRasters(this.rasters)); + return this; + } + + public XYChart leftShift(Rasters raster) { + return add(raster); + } + + public List getRasters() { + return this.rasters; + } + + public XYChart add(List items) { + for (Object o : items) { + if (o instanceof Rasters) { + add((Rasters) o); + } else if (o instanceof XYGraphics) { + add((XYGraphics) o); + } else if (o instanceof ConstantLine) { + add((ConstantLine) o); + } else if (o instanceof ConstantBand) { + add((ConstantBand) o); + } else if (o instanceof Text) { + add((Text) o); + } else { + super.add(items); + } + } + return this; + } + + public XYChart setXAutoRange(boolean xAutoRange) { + this.xAutoRange = xAutoRange; + sendModelUpdate(ChartToJson.serializeXAutoRange(this.xAutoRange)); + return this; + } + + public XYChart setxAutoRange(boolean xAutoRange) { + return this.setXAutoRange(xAutoRange); + } + + public Boolean getXAutoRange() { + return this.xAutoRange; + } + + public Boolean getxAutoRange() { + return getXAutoRange(); + } + + public XYChart setXBound(double lower, double upper) { + this.xAutoRange = false; + this.xLowerBound = lower; + this.xUpperBound = upper; + sendModelUpdate(ChartToJson.serializeXBound(this)); + return this; + } + + public XYChart setxBound(double lower, double upper) { + return setXBound(lower, upper); + } + + public XYChart setXBound(List bound) { + if (bound.size() != 2) { + throw new IllegalArgumentException("to set the x bound, the list needs to be of size=2"); + } + + Number n0 = bound.get(0); + Number n1 = bound.get(1); + setXBound(n0.doubleValue(), n1.doubleValue()); + return this; + } + + public XYChart setxBound(List bound) { + return this.setXBound(bound); + } + + public Double getXLowerBound() { + return this.xLowerBound; + } + + public Double getxLowerBound() { + return getXLowerBound(); + } + + public Double getXUpperBound() { + return this.xUpperBound; + } + + public Double getxUpperBound() { + return getXUpperBound(); + } + + public XYChart setLogX(boolean logX) { + this.logX = logX; + sendModelUpdate(ChartToJson.serializeLogX(this.logX)); + return this; + } + + public Boolean getLogX() { + return this.logX; + } + + public Double getXLogBase() { + return xLogBase; + } + + public Double getxLogBase() { + return getXLogBase(); + } + + public XYChart setXLogBase(double xLogBase) { + this.xLogBase = xLogBase; + sendModelUpdate(ChartToJson.serializeXLogBase(this.xLogBase)); + return this; + } + + public XYChart setxLogBase(double xLogBase) { + return this.setXLogBase(xLogBase); + } + + public Integer getLodThreshold() { + return lodThreshold; + } + + public void setLodThreshold(Integer lodThreshold) { + this.lodThreshold = lodThreshold; + sendModelUpdate(ChartToJson.serializeLodThreshold(this.lodThreshold)); + } + + public boolean isxTickLabelsVisible() { + return xTickLabelsVisible; + } + + public boolean isXTickLabelsVisible() { + return isxTickLabelsVisible(); + } + + public void setxTickLabelsVisible(boolean xTickLabelsVisible) { + this.xTickLabelsVisible = xTickLabelsVisible; + sendModelUpdate(ChartToJson.serializeXTickLabelsVisible(this.xTickLabelsVisible)); + } + + public void setXTickLabelsVisible(boolean xTickLabelsVisible) { + setxTickLabelsVisible(xTickLabelsVisible); + } + + public boolean isyTickLabelsVisible() { + return yTickLabelsVisible; + } + + public boolean isYTickLabelsVisible() { + return isyTickLabelsVisible(); + } + + public void setyTickLabelsVisible(boolean yTickLabelsVisible) { + this.yTickLabelsVisible = yTickLabelsVisible; + sendModelUpdate(ChartToJson.serializeYTickLabelsVisible(this.yTickLabelsVisible)); + } + + public void setYTickLabelsVisible(boolean yTickLabelsVisible) { + setyTickLabelsVisible(yTickLabelsVisible); + } +} diff --git a/base/src/main/java/com/twosigma/beakerx/chart/xychart/plotitem/Area.java b/base/src/main/java/com/twosigma/beakerx/chart/xychart/plotitem/Area.java new file mode 100644 index 0000000..dfee72b --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/chart/xychart/plotitem/Area.java @@ -0,0 +1,47 @@ +/* + * Copyright 2014 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.chart.xychart.plotitem; + +import com.twosigma.beakerx.chart.Filter; + +import java.util.EnumSet; + + +public class Area extends BasedXYGraphics { + + private final static EnumSet POSSIBLE_LOD_FILTERS = EnumSet.of(Filter.AREA, Filter.RIVER); + + private Integer interpolation; + + public void setInterpolation(Integer interpolation) { + if (interpolation < 0 || interpolation > 1) { + throw new IllegalArgumentException( + "Area interpolation is limited to 0, 1"); + } + + this.interpolation = interpolation; + } + + public Integer getInterpolation() { + return this.interpolation; + } + + @Override + protected EnumSet getPossibleFilters() { + return POSSIBLE_LOD_FILTERS; + } +} diff --git a/base/src/main/java/com/twosigma/beakerx/chart/xychart/plotitem/Bars.java b/base/src/main/java/com/twosigma/beakerx/chart/xychart/plotitem/Bars.java new file mode 100644 index 0000000..0411a1f --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/chart/xychart/plotitem/Bars.java @@ -0,0 +1,98 @@ +/* + * Copyright 2014 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.chart.xychart.plotitem; + +import com.twosigma.beakerx.chart.Color; +import com.twosigma.beakerx.chart.Filter; + +import java.util.ArrayList; +import java.util.EnumSet; +import java.util.List; + + +public class Bars extends BasedXYGraphics { + + private final static EnumSet POSSIBLE_LOD_FILTERS = EnumSet.of(Filter.BAR, Filter.BOX); + + private Number baseWidth; + private List widths; + private Color baseOutlineColor; + private List outlineColors; + + public void setWidth(Number width) { + this.baseWidth = width.floatValue(); + } + + public void setWidth(List width) { + setWidths(width); + } + + private void setWidths(List widths) { + this.widths = widths; + } + + public Number getWidth() { + return this.baseWidth; + } + + public List getWidths() { + return this.widths; + } + + public void setOutlineColor(Color color) { + this.baseOutlineColor = color; + } + + public void setOutlineColor(java.awt.Color color) { + this.baseOutlineColor = new Color(color); + } + + public void setOutlineColor(List colors) { + setOutlineColors(colors); + } + + private void setOutlineColors(List colors) { + if (colors != null) { + this.outlineColors = new ArrayList<>(colors.size()); + for (Object c : colors) { + if (c instanceof Color) { + this.outlineColors.add((Color)c); + } else if (c instanceof java.awt.Color) { + this.outlineColors.add(new Color((java.awt.Color) c)); + } else { + throw new IllegalArgumentException("setColor takes Color or List of Color"); + } + } + } else { + this.outlineColors = null; + } + } + + public Color getOutlineColor() { + return this.baseOutlineColor; + } + + public List getOutlineColors() { + return this.outlineColors; + } + + + @Override + protected EnumSet getPossibleFilters() { + return POSSIBLE_LOD_FILTERS; + } +} diff --git a/base/src/main/java/com/twosigma/beakerx/chart/xychart/plotitem/BasedXYGraphics.java b/base/src/main/java/com/twosigma/beakerx/chart/xychart/plotitem/BasedXYGraphics.java new file mode 100644 index 0000000..f49e59b --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/chart/xychart/plotitem/BasedXYGraphics.java @@ -0,0 +1,45 @@ +/* + * Copyright 2014 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.chart.xychart.plotitem; + +import java.util.List; + +public abstract class BasedXYGraphics extends XYGraphics { + private Number baseBase = 0.0d; + private List bases; + + public void setBase(Number base) { + this.baseBase = base.floatValue(); + super.setBase(base); + } + + public void setBase(List base) { + setBases(base); + super.setBase(base); + } + + private void setBases(List bases) { + this.bases = bases; + } + + public Number getBase() { + return this.baseBase; + } + + public List getBases() { + return this.bases; + } +} diff --git a/base/src/main/java/com/twosigma/beakerx/chart/xychart/plotitem/ConstantBand.java b/base/src/main/java/com/twosigma/beakerx/chart/xychart/plotitem/ConstantBand.java new file mode 100644 index 0000000..0c932be --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/chart/xychart/plotitem/ConstantBand.java @@ -0,0 +1,86 @@ +/* + * Copyright 2014 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.chart.xychart.plotitem; + +import com.twosigma.beakerx.chart.Color; +import com.twosigma.beakerx.chart.Graphics; +import com.twosigma.beakerx.util.DateUtil; + +import java.util.ArrayList; +import java.util.List; + +/** + * ConstantBand + */ +public class ConstantBand extends Graphics { + private List xs; + private List ys; + private Color baseColor; + private Class plotType; + + public List getX() { + return xs; + } + + public void setX(List xs) { + this.xs = new ArrayList<>(); + if (xs != null) { + for (Object x : xs) { + if (x instanceof Number) { + this.xs.add((Number) x); + } else { + this.xs.add(DateUtil.dateToLong(x)); + } + } + } + } + + public List getY() { + return ys; + } + + public void setY(List y) { + this.ys = y; + } + + public void setColor(Color color) { + this.baseColor = color; + } + + public void setColor(java.awt.Color color) { + setColor(new Color(color)); + } + + @Override + public void setColori(Color color) { + this.baseColor = color; + } + + @Override + public Color getColor() { + return baseColor; + } + + public Class getPlotType() { + return plotType; + } + + public void setPlotType(Class plotType) { + this.plotType = plotType; + } + +} diff --git a/base/src/main/java/com/twosigma/beakerx/chart/xychart/plotitem/ConstantLine.java b/base/src/main/java/com/twosigma/beakerx/chart/xychart/plotitem/ConstantLine.java new file mode 100644 index 0000000..e13c5f3 --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/chart/xychart/plotitem/ConstantLine.java @@ -0,0 +1,126 @@ +/* + * Copyright 2014 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.chart.xychart.plotitem; + +import com.twosigma.beakerx.chart.Color; +import com.twosigma.beakerx.chart.Graphics; +import com.twosigma.beakerx.util.DateUtil; + +import java.time.Instant; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.util.Calendar; +import java.util.Date; + +/** + * ConstantLine + */ +public class ConstantLine extends Graphics { + private Number x; + private Number y; + private Color baseColor; + private Float width = 1.5f; + private StrokeType style; + private Class plotType; + private boolean showLabel; + + public Number getX() { + return x; + } + + public void setX(Number x) { + this.x = x; + } + + public void setX(Date x) { + this.x = DateUtil.dateToLong(x); + } + + public void setX(Calendar x) { + this.x = DateUtil.dateToLong(x); + } + + public void setX(Instant x) { + this.x = DateUtil.dateToLong(x); + } + + public void setX(LocalDateTime x) { + this.x = DateUtil.dateToLong(x); + } + + public void setX(LocalDate x) { + this.x = DateUtil.dateToLong(x); + } + + public Number getY() { + return y; + } + + public void setY(Number y) { + this.y = y; + } + + public void setColor(Color color) { + this.baseColor = color; + } + + public void setColor(java.awt.Color color) { + setColor(new Color(color)); + } + + @Override + public void setColori(Color color) { + this.baseColor = color; + } + + @Override + public Color getColor() { + return baseColor; + } + + public Float getWidth() { + return width; + } + + public void setWidth(Float width) { + this.width = width; + } + + public StrokeType getStyle() { + return style; + } + + public void setStyle(StrokeType style) { + this.style = style; + } + + public Class getPlotType() { + return plotType; + } + + public void setPlotType(Class plotType) { + this.plotType = plotType; + } + + public Boolean getShowLabel() { + return showLabel; + } + + public void setShowLabel(boolean showLabel) { + this.showLabel = showLabel; + } +} diff --git a/base/src/main/java/com/twosigma/beakerx/chart/xychart/plotitem/Crosshair.java b/base/src/main/java/com/twosigma/beakerx/chart/xychart/plotitem/Crosshair.java new file mode 100644 index 0000000..0909337 --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/chart/xychart/plotitem/Crosshair.java @@ -0,0 +1,68 @@ +/* + * Copyright 2014 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.chart.xychart.plotitem; + +import com.twosigma.beakerx.chart.Color; +import org.apache.commons.lang3.SerializationUtils; + +import java.io.Serializable; + +/** + * Crosshair + * + */ +public class Crosshair implements Serializable{ + private StrokeType style; + private Float width; + private Color color; + + public Crosshair setStyle(StrokeType style) { + this.style = style; + return this; + } + + public StrokeType getStyle() { + return this.style; + } + + public Crosshair setWidth(float width) { + this.width = width; + return this; + } + + public Float getWidth() { + return this.width; + } + + public Crosshair setColor(Color color) { + this.color = color; + return this; + } + + public Crosshair setColor(java.awt.Color color) { + return setColor(new Color(color)); + } + + public Color getColor() { + return this.color; + } + + @Override + public Object clone() throws CloneNotSupportedException { + return SerializationUtils.clone(this); + } +} diff --git a/base/src/main/java/com/twosigma/beakerx/chart/xychart/plotitem/LabelPositionType.java b/base/src/main/java/com/twosigma/beakerx/chart/xychart/plotitem/LabelPositionType.java new file mode 100644 index 0000000..d1793c2 --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/chart/xychart/plotitem/LabelPositionType.java @@ -0,0 +1,25 @@ +/* + * Copyright 2014 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.chart.xychart.plotitem; + +public enum LabelPositionType { + VALUE_OUTSIDE, + VALUE_INSIDE, + CENTER, + BASE_OUTSIDE, + BASE_INSIDE +} diff --git a/base/src/main/java/com/twosigma/beakerx/chart/xychart/plotitem/Line.java b/base/src/main/java/com/twosigma/beakerx/chart/xychart/plotitem/Line.java new file mode 100644 index 0000000..f29e551 --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/chart/xychart/plotitem/Line.java @@ -0,0 +1,81 @@ +/* + * Copyright 2014 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.chart.xychart.plotitem; + +import com.twosigma.beakerx.chart.Filter; +import java.util.EnumSet; +import java.util.List; + + +public class Line extends XYGraphics { + + private final static EnumSet POSSIBLE_LOD_FILTERS = EnumSet.of(Filter.LINE, + Filter.BOX, + Filter.RIVER); + + + private Float width = 1.5f; + private StrokeType style; + private Integer interpolation; + + public Line() { + + } + + public Line(List ys) { + super.setY(ys); + } + + public Line(List xs, List ys) { + super.setX(xs); + super.setY(ys); + } + + public void setWidth(Float width) { + this.width = width; + } + + public Float getWidth() { + return this.width; + } + + public void setStyle(StrokeType style) { + this.style = style; + } + + public StrokeType getStyle() { + return this.style; + } + + public void setInterpolation(Integer interpolation) { + if (interpolation.intValue() < 0 || interpolation.intValue() > 2) { + throw new IllegalArgumentException( + "Line interpolation is limited to 0, 1, 2"); + } + + this.interpolation = interpolation; + } + + public Integer getInterpolation() { + return this.interpolation; + } + + @Override + protected EnumSet getPossibleFilters() { + return POSSIBLE_LOD_FILTERS; + } +} diff --git a/base/src/main/java/com/twosigma/beakerx/chart/xychart/plotitem/PlotOrientationType.java b/base/src/main/java/com/twosigma/beakerx/chart/xychart/plotitem/PlotOrientationType.java new file mode 100644 index 0000000..af8710c --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/chart/xychart/plotitem/PlotOrientationType.java @@ -0,0 +1,24 @@ +/* + * Copyright 2014 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.chart.xychart.plotitem; + + +public enum PlotOrientationType { + VERTICAL, + HORIZONTAL +} diff --git a/base/src/main/java/com/twosigma/beakerx/chart/xychart/plotitem/Points.java b/base/src/main/java/com/twosigma/beakerx/chart/xychart/plotitem/Points.java new file mode 100644 index 0000000..0c6e49d --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/chart/xychart/plotitem/Points.java @@ -0,0 +1,143 @@ +/* + * Copyright 2014 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.chart.xychart.plotitem; + +import com.twosigma.beakerx.chart.Color; +import com.twosigma.beakerx.chart.Filter; + +import java.util.ArrayList; +import java.util.EnumSet; +import java.util.List; + + +public class Points extends XYGraphics { + + private final static EnumSet POSSIBLE_LOD_FILTERS = EnumSet.of(Filter.POINT, + Filter.BOX); + + private float baseSize = 6.0f; + private List sizes; + private ShapeType baseShape = ShapeType.DEFAULT; + private List shapes; + private Boolean baseFill; + private List fills; + private Color baseOutlineColor; + private List outlineColors; + + public void setSize(Number size) { + this.baseSize = size.floatValue(); + } + + public void setSize(List sizes) { + setSizes(sizes); + } + + private void setSizes(List sizes) { + this.sizes = sizes; + } + + public float getSize() { + return this.baseSize; + } + + public List getSizes() { + return this.sizes; + } + + public void setShape(ShapeType shape) { + this.baseShape = shape; + } + + public void setShape(List shapes) { + setShapes(shapes); + } + + private void setShapes(List shapes) { + this.shapes = shapes; + } + + public ShapeType getShape() { + return this.baseShape; + } + + public List getShapes() { + return this.shapes; + } + + public void setFill(Boolean fill) { + this.baseFill = fill; + } + + public void setFill(List fill) { + setFills(fill); + } + + private void setFills(List fills) { + this.fills = fills; + } + + public Boolean getFill() { + return this.baseFill; + } + + public List getFills() { + return this.fills; + } + + public void setOutlineColor(Color color) { + this.baseOutlineColor = color; + } + + public void setOutlineColor(java.awt.Color color) { + this.baseOutlineColor = new Color(color); + } + + public void setOutlineColor(List colors) { + setOutlineColors(colors); + } + + private void setOutlineColors(List colors) { + if (colors != null) { + this.outlineColors = new ArrayList<>(colors.size()); + for (Object c : colors) { + if (c instanceof Color) { + this.outlineColors.add((Color)c); + } else if (c instanceof java.awt.Color) { + this.outlineColors.add(new Color((java.awt.Color) c)); + } else { + throw new IllegalArgumentException("setColor takes Color or List of Color"); + } + } + } else { + this.outlineColors = null; + } + } + + public Color getOutlineColor() { + return this.baseOutlineColor; + } + + public List getOutlineColors() { + return this.outlineColors; + } + + @Override + protected EnumSet getPossibleFilters() { + return POSSIBLE_LOD_FILTERS; + } + +} diff --git a/base/src/main/java/com/twosigma/beakerx/chart/xychart/plotitem/Rasters.java b/base/src/main/java/com/twosigma/beakerx/chart/xychart/plotitem/Rasters.java new file mode 100644 index 0000000..066608e --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/chart/xychart/plotitem/Rasters.java @@ -0,0 +1,104 @@ +/* + * Copyright 2017 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.chart.xychart.plotitem; + +import com.twosigma.beakerx.chart.Color; +import com.twosigma.beakerx.chart.Graphics; +import com.twosigma.beakerx.chart.Filter; + +import java.util.ArrayList; +import java.util.EnumSet; +import java.util.List; + +public class Rasters extends XYGraphics { + private List width; + private List height; + private List opacity; + private String filePath = ""; + private String fileUrl = ""; + private byte[] dataString; + private Color baseColor; + private String position = "zoomable"; + + public List getOpacity() { + // generate a list of opacity 1, if not given + if (this.opacity == null){ + this.opacity = new ArrayList<>(this.width.size()); + for (int i = 0; i < this.width.size(); ++i) { + this.opacity.add(1); + } + } + return this.opacity; + } + + public void setOpacity(List opacity) { + this.opacity = new ArrayList(opacity); + } + + public List getWidth() { + return this.width; + } + + public void setWidth(List width) { + this.width = new ArrayList(width); + } + + public List getHeight() { + return this.height; + } + + public void setHeight(List height) { + this.height = new ArrayList(height); + } + + public String getFilePath() { + return filePath; + } + + public void setFilePath(String filePath) { + this.filePath = filePath; + } + + public String getFileUrl() { + return fileUrl; + } + + public void setFileUrl(String fileUrl) { + this.fileUrl = fileUrl; + } + + public String getPosition() { + return position; + } + + public void setPosition(String position) { + this.position = position; + } + + public byte[] getDataString() { + return dataString; + } + + public void setDataString(byte[] dataString) { + this.dataString = dataString; + } + + @Override + protected EnumSet getPossibleFilters() { + return null; + } +} \ No newline at end of file diff --git a/base/src/main/java/com/twosigma/beakerx/chart/xychart/plotitem/ShapeType.java b/base/src/main/java/com/twosigma/beakerx/chart/xychart/plotitem/ShapeType.java new file mode 100644 index 0000000..43403aa --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/chart/xychart/plotitem/ShapeType.java @@ -0,0 +1,42 @@ +/* + * Copyright 2014 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.chart.xychart.plotitem; + +public enum ShapeType { + SQUARE("rect"), + CIRCLE("circle"), + TRIANGLE("triangle"), + DIAMOND("diamond"), + DCROSS("dcross"), + DOWNTRIANGLE("downtriangle"), + CROSS("cross"), + DEFAULT("DEFAULT"), + LEVEL("level"), + VLEVEL("vlevel"), + LINECROSS("linecross"); + + private String shape; + + ShapeType(String shape) { + this.shape = shape; + } + + public String getText() { + return shape; + } + +} diff --git a/base/src/main/java/com/twosigma/beakerx/chart/xychart/plotitem/Stems.java b/base/src/main/java/com/twosigma/beakerx/chart/xychart/plotitem/Stems.java new file mode 100644 index 0000000..82d42c2 --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/chart/xychart/plotitem/Stems.java @@ -0,0 +1,68 @@ +/* + * Copyright 2014 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.chart.xychart.plotitem; + +import com.twosigma.beakerx.chart.Filter; + +import java.util.EnumSet; +import java.util.List; + + +public class Stems extends BasedXYGraphics { + + private final static EnumSet POSSIBLE_LOD_FILTERS = EnumSet.of(Filter.STEAM, + Filter.STEAM_PLUS, + Filter.BOX); + + + private Float width = 1.5f; + private StrokeType baseStyle = StrokeType.SOLID; + private List styles; + + public void setWidth(Float width) { + this.width = width; + } + + public Float getWidth() { + return this.width; + } + + public void setStyle(StrokeType style) { + this.baseStyle = style; + } + + public void setStyle(List styles) { + setStyles(styles); + } + + private void setStyles(List styles) { + this.styles = styles; + } + + public StrokeType getStyle() { + return this.baseStyle; + } + + public List getStyles() { + return this.styles; + } + + @Override + protected EnumSet getPossibleFilters() { + return POSSIBLE_LOD_FILTERS; + } +} diff --git a/base/src/main/java/com/twosigma/beakerx/chart/xychart/plotitem/StrokeType.java b/base/src/main/java/com/twosigma/beakerx/chart/xychart/plotitem/StrokeType.java new file mode 100644 index 0000000..2c77750 --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/chart/xychart/plotitem/StrokeType.java @@ -0,0 +1,26 @@ +/* + * Copyright 2014 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.chart.xychart.plotitem; + +public enum StrokeType { + NONE, + SOLID, + DASH, + DOT, + DASHDOT, + LONGDASH; +} diff --git a/base/src/main/java/com/twosigma/beakerx/chart/xychart/plotitem/Text.java b/base/src/main/java/com/twosigma/beakerx/chart/xychart/plotitem/Text.java new file mode 100644 index 0000000..8406352 --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/chart/xychart/plotitem/Text.java @@ -0,0 +1,134 @@ +/* + * Copyright 2014 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.chart.xychart.plotitem; + +import com.twosigma.beakerx.chart.Color; +import com.twosigma.beakerx.util.DateUtil; +import org.apache.commons.lang3.SerializationUtils; + +import java.io.Serializable; +import java.time.Instant; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.util.Calendar; +import java.util.Date; + + +/** + * Text + */ +public class Text implements Serializable, Cloneable { + + private Number x = 0.0d; + private Number y = 0.0d; + private boolean showPointer = true; + private String text = ""; + private Double pointerAngle = (-0.25f) * Math.PI; + private Color color; + private int size = 13; + private Class plotType; + + public Number getX() { + return x; + } + + public void setX(Number x) { + this.x = x; + } + + public void setX(Date x) { + this.x = DateUtil.dateToLong(x); + } + + public void setX(Calendar x) { + this.x = DateUtil.dateToLong(x); + } + + public void setX(Instant x) { + this.x = DateUtil.dateToLong(x); + } + + public void setX(LocalDateTime x) { + this.x = DateUtil.dateToLong(x); + } + + public void setX(LocalDate x) { + this.x = DateUtil.dateToLong(x); + } + + public Number getY() { + return y; + } + + public void setY(Number y) { + this.y = y; + } + + public Boolean getShowPointer() { + return showPointer; + } + + public void setShowPointer(boolean showPointer) { + this.showPointer = showPointer; + } + + public String getText() { + return text; + } + + public void setText(String text) { + this.text = text; + } + + + public Double getPointerAngle() { + return pointerAngle; + } + + public void setPointerAngle(Double pointerAngle) { + this.pointerAngle = pointerAngle; + } + + public Color getColor() { + return color; + } + + public void setColor(Color color) { + this.color = color; + } + + public int getSize() { + return size; + } + + public void setSize(int size) { + this.size = size; + } + + public Class getPlotType() { + return plotType; + } + + public void setPlotType(Class plotType) { + this.plotType = plotType; + } + + @Override + public Object clone() throws CloneNotSupportedException { + return SerializationUtils.clone(this); + } +} diff --git a/base/src/main/java/com/twosigma/beakerx/chart/xychart/plotitem/XYGraphics.java b/base/src/main/java/com/twosigma/beakerx/chart/xychart/plotitem/XYGraphics.java new file mode 100644 index 0000000..598a740 --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/chart/xychart/plotitem/XYGraphics.java @@ -0,0 +1,198 @@ +/* + * Copyright 2014 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.chart.xychart.plotitem; + +import com.twosigma.beakerx.chart.Color; +import com.twosigma.beakerx.chart.Filter; +import com.twosigma.beakerx.chart.Graphics; +import com.twosigma.beakerx.chart.ListColorConverter; +import com.twosigma.beakerx.util.DateUtil; +import com.twosigma.beakerx.widget.RunWidgetClosure; + +import java.util.ArrayList; +import java.util.EnumSet; +import java.util.List; + +abstract public class XYGraphics extends Graphics { + private List xs; + private List ys = new ArrayList<>(); + private String displayName = ""; + protected Color baseColor; + private List colors; + private Class plotType; + private Filter lodFilter; + private Object toolTipBuilder; + private List toolTips; + + protected List getBases() { + return null; + } + + protected Number getBase() { + return null; + } + + protected void setBase(Object base) { + reinit(); + } + + public List getToolTips() { + return toolTips; + } + + public void setToolTip(Object toolTip) { + toolTipBuilder = toolTip; + reinit(); + } + + public void setToolTip(List toolTips) { + toolTipBuilder = null; + for (Object tooltip : toolTips) { + if (!(tooltip == null || tooltip instanceof String)) { + throw new IllegalArgumentException("Tooltips should be the list of strings"); + } + } + this.toolTips = toolTips; + } + + public void setX(List xs) { + this.xs = new ArrayList<>(); + if (xs != null) { + for (Object x : xs) { + if (x instanceof Number) { + this.xs.add((Number) x); + } else { + this.xs.add(DateUtil.dateToLong(x)); + } + } + } + reinit(); + } + + public List getX() { + if (xs == null || xs.isEmpty()) { + generateXs(); + } + return this.xs; + } + + public void setY(List ys) { + this.ys = new ArrayList<>(ys);//to make it serializable + reinit(); + } + + public List getY() { + return this.ys; + } + + public void setDisplayName(String displayName) { + this.displayName = displayName; + reinit(); + } + + public String getDisplayName() { + return this.displayName; + } + + + private void generateXs() { + this.xs = new ArrayList<>(this.ys.size()); + for (int i = 0; i < ys.size(); ++i) { + this.xs.add(i); + } + } + + public Filter getLodFilter() { + return lodFilter; + } + + public void setLodFilter(Filter lodFilter) { + if (getPossibleFilters().contains(lodFilter)) { + this.lodFilter = lodFilter; + } else { + throw new RuntimeException(String.format("%s doesn't not support '%s' filter.", + getClass().getSimpleName(), + lodFilter.getText())); + } + + } + + public void setColor(Color color) { + this.baseColor = color; + } + + public void setColor(java.awt.Color color) { + setColor(new Color(color)); + } + + public void setColor(List colorList) { + if (colorList != null) { + this.colors = ListColorConverter.convert(colorList); + } else { + this.colors = null; + } + } + + public List getColors() { + return this.colors; + } + + @Override + public void setColori(Color color) { + this.baseColor = color; + } + + @Override + public Color getColor() { + return this.baseColor; + } + + abstract protected EnumSet getPossibleFilters(); + + public Class getPlotType() { + return plotType; + } + + public void setPlotType(Class plotType) { + this.plotType = plotType; + } + + private void reinit() { + if (toolTipBuilder == null) return; + + List toolTip = new ArrayList<>(); + + try { + for (int i = 0; i < xs.size(); i++) { + toolTip.add((String) runClosure(toolTipBuilder, new Object[]{ + xs.get(i), + ys.get(i), + i, + getBases() != null ? getBases().get(i) : getBase(), + displayName})); + } + } catch (Throwable x) { + throw new RuntimeException("Can not create tooltips.", x); + } + + this.toolTips = toolTip; + } + + private Object runClosure(Object closure, Object... params) throws Exception { + return RunWidgetClosure.runClosure(closure, params); + } +} diff --git a/base/src/main/java/com/twosigma/beakerx/chart/xychart/plotitem/XYStacker.java b/base/src/main/java/com/twosigma/beakerx/chart/xychart/plotitem/XYStacker.java new file mode 100644 index 0000000..b5e0722 --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/chart/xychart/plotitem/XYStacker.java @@ -0,0 +1,79 @@ +/* + * Copyright 2014 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.chart.xychart.plotitem; + + +import java.util.*; + +public class XYStacker { + + public static List stack(List graphicsList) { + return transformGraphicsList(graphicsList); + } + + private static List transformGraphicsList(List graphicsList) { + if (graphicsList.isEmpty() || graphicsList.size() == 1){ + return graphicsList; + } else { + BasedXYGraphics graphicsWithMaxElements = Collections.max(graphicsList, new Comparator() { + @Override + public int compare(BasedXYGraphics o1, BasedXYGraphics o2) { + return o1.getY().size() - o2.getY().size(); + } + }); + List stackedList = new ArrayList(graphicsList.size()); + padYs(graphicsList.get(0), graphicsWithMaxElements); + stackedList.add(graphicsList.get(0)); + for (int gIndex = 1; gIndex < graphicsList.size(); gIndex++) { + BasedXYGraphics current = graphicsList.get(gIndex); + padYs(current, graphicsWithMaxElements); + BasedXYGraphics previous = graphicsList.get(gIndex - 1); + List currentYs = current.getY(); + List previousYs = previous.getY(); + + for (int yIndex = 0; yIndex < currentYs.size(); yIndex++) { + currentYs.set(yIndex, currentYs.get(yIndex).doubleValue() + previousYs.get(yIndex).doubleValue()); + } + current.setBase(previousYs); + stackedList.add(current); + } + return stackedList; + } + } + + private static void padYs(BasedXYGraphics graphics, BasedXYGraphics graphicsWithMaxElements) { + int maxSize = graphicsWithMaxElements.getY().size(); + int currentSize = graphics.getY().size(); + int diff = maxSize - currentSize; + if (diff > 0) { + Number[] ys = new Number[diff]; + Arrays.fill(ys, graphics.getY().get(currentSize - 1)); + graphics.getY().addAll(Arrays.asList(ys)); + List xs = graphics.getX(); + if (xs != null && xs.size() != maxSize) { + if (graphicsWithMaxElements.getX() != null) { + xs.addAll(graphicsWithMaxElements.getX().subList(currentSize, maxSize)); + } else { + Number lastX = xs.get(currentSize - 1); + for (int i = 0; i < diff; ++i) { + xs.add(lastX.doubleValue() + i); + } + } + } + } + } + +} diff --git a/base/src/main/java/com/twosigma/beakerx/chart/xychart/plotitem/YAxis.java b/base/src/main/java/com/twosigma/beakerx/chart/xychart/plotitem/YAxis.java new file mode 100644 index 0000000..7c6c54e --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/chart/xychart/plotitem/YAxis.java @@ -0,0 +1,135 @@ +/* + * Copyright 2014 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.chart.xychart.plotitem; + +import org.apache.commons.lang3.SerializationUtils; + +import java.io.Serializable; + +/** + * YAxis + * + */ +public class YAxis implements Serializable, Cloneable{ + + private String label; + private boolean autoRange; + private boolean autoRangeIncludesZero; + private double lowerMargin; + private double upperMargin; + private double lowerBound; + private double upperBound; + private boolean log; + private double logBase; + + public YAxis() { + this(""); + } + + public YAxis(String label) { + this(label, 0, 0); + } + + public YAxis(double lowerMargin, double upperMargin) { + this("", lowerMargin, upperMargin); + } + + public YAxis(String label, double lowerMargin, double upperMargin) { + this.label = label; + this.autoRange = true; + this.autoRangeIncludesZero = false; + this.lowerMargin = lowerMargin; + this.upperMargin = upperMargin; + this.log = false; + this.logBase = 10d; + } + + public void setLabel(String label) { + this.label = label; + } + + public String getLabel() { + return this.label; + } + + public void setAutoRange(boolean autoRange) { + this.autoRange = autoRange; + } + + public Boolean getAutoRange() { + return this.autoRange; + } + + public void setAutoRangeIncludesZero(boolean autoRangeIncludesZero) { + this.autoRangeIncludesZero = autoRangeIncludesZero; + } + + public Boolean getAutoRangeIncludesZero() { + return this.autoRangeIncludesZero; + } + + public void setUpperMargin(double margin) { + this.upperMargin = margin; + } + + public Double getUpperMargin() { + return this.upperMargin; + } + + public void setLowerMargin(double margin) { + this.lowerMargin = margin; + } + + public Double getLowerMargin() { + return this.lowerMargin; + } + + public void setBound(double lower, double upper) { + this.autoRange = false; + this.lowerBound = lower; + this.upperBound = upper; + } + + public Double getLowerBound() { + return this.lowerBound; + } + + public Double getUpperBound() { + return this.upperBound; + } + + public void setLog(boolean log) { + this.log = log; + } + + public Boolean getLog() { + return this.log; + } + + public void setLogBase(double logBase) { + this.logBase = logBase; + } + + public Double getLogBase() { + return this.logBase; + } + + @Override + public Object clone() throws CloneNotSupportedException { + return SerializationUtils.clone(this); + } +} diff --git a/base/src/main/java/com/twosigma/beakerx/easyform/EasyForm.java b/base/src/main/java/com/twosigma/beakerx/easyform/EasyForm.java new file mode 100644 index 0000000..5f5c732 --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/easyform/EasyForm.java @@ -0,0 +1,395 @@ +/* + * Copyright 2015 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.easyform; + +import com.twosigma.beakerx.easyform.formitem.ListComponent; +import com.twosigma.beakerx.easyform.formitem.LoadValuesButton; +import com.twosigma.beakerx.easyform.formitem.SaveValuesButton; +import com.twosigma.beakerx.easyform.formitem.widgets.ButtonComponentWidget; +import com.twosigma.beakerx.easyform.formitem.widgets.CheckBoxGroupWidget; +import com.twosigma.beakerx.easyform.formitem.widgets.CheckBoxWidget; +import com.twosigma.beakerx.easyform.formitem.widgets.ComboBoxWidget; +import com.twosigma.beakerx.easyform.formitem.widgets.DatePickerComponentWidget; +import com.twosigma.beakerx.easyform.formitem.widgets.PasswordWidget; +import com.twosigma.beakerx.easyform.formitem.widgets.RadioButtonComponentWidget; +import com.twosigma.beakerx.easyform.formitem.widgets.SelectMultipleSingleWidget; +import com.twosigma.beakerx.easyform.formitem.widgets.SelectMultipleWidget; +import com.twosigma.beakerx.easyform.formitem.widgets.TextAreaWidget; +import com.twosigma.beakerx.easyform.formitem.widgets.TextFieldWidget; +import com.twosigma.beakerx.widget.DOMWidget; +import com.twosigma.beakerx.widget.DisplayableWidget; +import com.twosigma.beakerx.widget.ValueWidget; +import com.twosigma.beakerx.widget.Widget; +import com.twosigma.beakerx.widget.WidgetItem; +import org.apache.commons.lang3.StringUtils; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +@SuppressWarnings("unchecked") +public class EasyForm extends ObservableMap implements DisplayableWidget, WidgetItem { + + public static final Integer HORIZONTAL = 1; + public static final Integer VERTICAL = 2; + private static final Integer AUTO_SIZE = 20; + + private final String caption; + private Boolean ready = Boolean.FALSE; + private Map>> componentMap = new LinkedHashMap<>(); + private SaveValuesButton saveValuesButton; + private LoadValuesButton loadValuesButton; + + public EasyForm(final String caption) { + this.caption = caption; + } + + public void addSaveValuesButton(final String path) { + SaveValuesButton button = new SaveValuesButton(); + button.setPath(path); + this.saveValuesButton = button; + } + + public void addLoadValuesButton(final String path) { + LoadValuesButton button = new LoadValuesButton(); + button.setPath(path); + this.loadValuesButton = button; + } + + public EasyFormComponent addTextField(final String label) throws Exception { + return addTextField(label, -1); + } + + public EasyFormComponent addTextField(final String label, final Integer size) throws Exception { + TextFieldWidget textField = new TextFieldWidget(); + textField.registerUpdateValueCallback(textField::fireChanged); + textField.setLabel(label); + textField.setSize(size); + return addComponentOrThrow(label, textField); + } + + public EasyFormComponent addPasswordField(final String label) throws Exception { + return addPasswordField(label, -1); + } + + public EasyFormComponent addPasswordField(String label, int size) throws Exception { + PasswordWidget passwordWidget = new PasswordWidget(); + passwordWidget.registerUpdateValueCallback(passwordWidget::fireChanged); + passwordWidget.setLabel(label); + passwordWidget.setSize(size); + return addComponentOrThrow(label, passwordWidget); + } + + public EasyFormComponent addTextArea(final String label) throws Exception { + return addTextArea(label, null, TextAreaWidget.AUTO_WIDTH, TextAreaWidget.AUTO_HEIGHT); + } + + public EasyFormComponent addTextArea(final String label, final Integer cols, final Integer rows) + throws Exception { + return addTextArea(label, null, cols, rows); + } + + public EasyFormComponent addTextArea(final String label, final String initialValue) throws Exception { + return addTextArea(label, initialValue, TextAreaWidget.AUTO_WIDTH, TextAreaWidget.AUTO_HEIGHT); + } + + public EasyFormComponent addTextArea(final String label, + final String initialValue, + final Integer cols, + final Integer rows) throws Exception { + TextAreaWidget textArea = new TextAreaWidget(); + textArea.registerUpdateValueCallback(textArea::fireChanged); + textArea.setLabel(label); + textArea.setCols(cols); + textArea.setRows(rows); + textArea.setValue(initialValue); + return addComponentOrThrow(label, textArea); + } + + public EasyFormComponent addCheckBox(final String label) throws Exception { + return addCheckBox(label, Boolean.FALSE); + } + + public EasyFormComponent addCheckBox(final String label, final Boolean value) throws Exception { + CheckBoxWidget checkBox = new CheckBoxWidget(); + checkBox.registerUpdateValueCallback(checkBox::fireChanged); + checkBox.setLabel(label); + checkBox.setValue(String.valueOf(value)); + return addComponentOrThrow(label, checkBox); + } + + public EasyFormComponent addComboBox(final String label, + final Collection values) throws Exception { + return addComboBox(label, values, Boolean.FALSE); + } + + public EasyFormComponent addComboBox(final String label, + final Collection values, + final Boolean editable) throws Exception { + return addComboBox(label, values, editable, EasyForm.AUTO_SIZE); + } + + public EasyFormComponent addComboBox(final String label, + final Collection values, + final Boolean editable, + final Integer size) throws Exception { + ComboBoxWidget comboBox = new ComboBoxWidget(); + comboBox.registerUpdateValueCallback(comboBox::fireChanged); + comboBox.setLabel(label); + comboBox.setEditable(editable); + comboBox.setValues(values); + comboBox.setSize(size); + if (values != null && values.size() > 0) { + comboBox.setValue(values.iterator().next()); + } + return addComponentOrThrow(label, comboBox); + } + + public EasyFormComponent addList(final String label, + final Collection values) throws Exception { + return addList(label, values, Boolean.TRUE, values.size()); + } + + public EasyFormComponent addList(final String label, + final Collection values, + final Boolean multipleSelection) throws Exception { + return addList(label, values, multipleSelection, values.size()); + } + + public EasyFormComponent addList(final String label, + final Collection values, + final Integer size) throws Exception { + return addList(label, values, Boolean.TRUE, size); + } + + public EasyFormComponent addList(final String label, + final Collection values, + final Boolean multipleSelection, + final Integer size) throws Exception { + + ListComponent list = (multipleSelection) ? createSelectMultipleWidget() : createSelectMultipleSingleWidget(); + list.setLabel(label); + list.setSize(size); + list.setMultipleSelection(multipleSelection); + list.setValues(values); + list.setValue(Collections.EMPTY_LIST); + return addComponentOrThrow(label, list); + } + + private ListComponent createSelectMultipleSingleWidget() { + SelectMultipleSingleWidget list = new SelectMultipleSingleWidget(); + list.registerUpdateValueCallback(list::fireChanged); + return list; + } + + private ListComponent createSelectMultipleWidget() { + SelectMultipleWidget list = new SelectMultipleWidget(); + list.registerUpdateValueCallback(list::fireChanged); + return list; + } + + public EasyFormComponent addRadioButtons(final String label, + final Collection values) throws Exception { + return addRadioButtons(label, values, EasyForm.VERTICAL); + } + + public EasyFormComponent addRadioButtons(final String label, + final Collection values, + final Integer orientation) throws Exception { + RadioButtonComponentWidget radioButtonComponent = new RadioButtonComponentWidget(values, EasyForm.HORIZONTAL.equals(orientation)); + radioButtonComponent.setLabel(label); + radioButtonComponent.registerUpdateValueCallback(radioButtonComponent::fireChanged); + return addComponentOrThrow(label, radioButtonComponent); + } + + public EasyFormComponent addCheckBoxes(final String label, + final Collection values) throws Exception { + return addCheckBoxes(label, values, EasyForm.VERTICAL); + } + + public EasyFormComponent addCheckBoxes(final String label, + final Collection values, + final Integer orientation) throws Exception { + CheckBoxGroupWidget checkBoxGroup = new CheckBoxGroupWidget(values, EasyForm.HORIZONTAL.equals(orientation)); + checkBoxGroup.setLabel(label); + checkBoxGroup.registerUpdateValueCallback(checkBoxGroup::fireChanged); + return addComponentOrThrow(label, checkBoxGroup); + } + + public DatePickerComponentWidget addDatePicker(final String label) throws Exception { + DatePickerComponentWidget datePickerComponent = new DatePickerComponentWidget(); + datePickerComponent.registerUpdateValueCallback(datePickerComponent::fireChanged); + datePickerComponent.setLabel(label); + addComponentOrThrow(label, datePickerComponent); + + return datePickerComponent; + } + + public ButtonComponentWidget addButton(final String label) throws Exception { + return addButton(label, null); + } + + public ButtonComponentWidget addButton(final String label, final String actionCellTag) throws Exception { + ButtonComponentWidget buttonComponent = new ButtonComponentWidget(); + buttonComponent.registerUpdateValueCallback(buttonComponent::fireChanged); + buttonComponent.setLabel(label); + buttonComponent.setTag(actionCellTag); + addComponentOrThrow(label, buttonComponent); + return buttonComponent; + } + + public EasyFormComponent> addWidget(final String label, final ValueWidget widget) throws Exception { + EasyFormComponent> ret = new EasyFormComponent<>(widget); + addComponentOrThrow(label, ret); + return ret; + } + + private EasyFormComponent> addComponentOrThrow(final String label, + final EasyFormComponent component) throws Exception { + if (getComponentMap().containsKey(label)) { + throw new Exception( + String.format("EasyForm already contains component with such label: %s.", label)); + } else { + getComponentMap().put(label, component); + } + return component; + } + + public Map>> getComponentMap() { + return componentMap; + } + + public DOMWidget getWidget(String key) { + return getComponentMap().get(key).getWidget(); + } + + public List getCommFunctionalities() { + return componentMap.values().stream().map(EasyFormComponent::getWidget).collect(Collectors.toList()); + } + + public boolean hasComponents() { + return getComponentMap().size() > 0; + } + + + public boolean hasSaveValuesButton() { + return this.saveValuesButton != null; + } + + public boolean hasLoadValuesButton() { + return this.loadValuesButton != null; + } + + public SaveValuesButton getSaveValuesButton() { + return saveValuesButton; + } + + public LoadValuesButton getLoadValuesButton() { + return loadValuesButton; + } + + public String getCaption() { + return caption; + } + + private HashMap getValuesMap() { + return this.mapInstance; + } + + @Override + public Object get(final Object key) { + checkComponentExists((String) key); + return getComponentMap().get(key).getValue(); + } + + @Override + public String put(final String key, final Object value) { + checkComponentExists(key); + final EasyFormComponent> component = getComponentMap().get(key); + if (!component.checkValue(value)) { + throw new IllegalArgumentException( + String.format("\"%s\" is not a valid option for %s \"%s\".", + value, component.getClass().getSimpleName(), key)); + } + final Object currentValue = component.formatValue(value); + final String previousValue = (component.getValue() == null) ? "" : component.getValue().toString(); + component.setValue(currentValue); + getValuesMap().put(key, currentValue); + setChanged(); + notifyObservers(); + component.fireChanged(); + return previousValue; + } + + private void checkComponentExists(final String key) { + if (!componentExists(key)) { + throw new IllegalArgumentException( + String.format("The requested component \"%s\" does not exist.", key)); + } + } + + private boolean componentExists(final String key) { + return getComponentMap().containsKey(key); + } + + public void setEnabled(final String label, final Boolean enabled) { + if (StringUtils.isNotEmpty(label) && componentMap.containsKey(label)) { + componentMap.get(label).setEnabled(enabled); + setChanged(); + notifyObservers(); + } + } + + public Boolean isReady() { + return ready; + } + + public void setReady() { + this.ready = Boolean.TRUE; + for (EasyFormComponent> component : getComponentMap().values()) { + if (!component.isButton()) { + getValuesMap().put(component.getLabel(), component.getValue()); + } + component.fireInit(); + } + } + + public void setNotReady() { + this.ready = Boolean.FALSE; + } + + public EasyFormView getView(){ + EasyFormView easyFormView = new EasyFormView(this.getCommFunctionalities()); + easyFormView.setEasyFormName(this.getCaption()); + return easyFormView; + } + + @Override + public void display() { + this.setReady(); + this.getView().display(); + } + + @Override + public Widget asWidget() { + return getView(); + } +} diff --git a/base/src/main/java/com/twosigma/beakerx/easyform/EasyFormComponent.java b/base/src/main/java/com/twosigma/beakerx/easyform/EasyFormComponent.java new file mode 100644 index 0000000..ff85bbb --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/easyform/EasyFormComponent.java @@ -0,0 +1,187 @@ +/* + * Copyright 2015 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.easyform; + +import static com.twosigma.beakerx.kernel.comm.Comm.DATA; +import static com.twosigma.beakerx.kernel.comm.Comm.STATE; + +import com.twosigma.beakerx.easyform.formitem.EasyFormListener; +import com.twosigma.beakerx.kernel.comm.Comm; +import com.twosigma.beakerx.message.Message; +import com.twosigma.beakerx.widget.CommFunctionality; +import com.twosigma.beakerx.widget.UpdateValueCallback; +import com.twosigma.beakerx.widget.ValueWidget; + +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +public class EasyFormComponent> implements CommFunctionality { + + protected T widget; + private boolean enabled = true; + private List onChangeListeners = new LinkedList<>(); + private List onInitListeners = new LinkedList<>(); + + public EasyFormComponent(T widget) { + this.widget = widget; + widget.getComm().addMsgCallbackList(this::setupNewValue); + } + + public EasyFormComponent() { + } + + //Acts like ID + public String getLabel() { + return this.widget.getDescription(); + } + + //Acts like ID + public void setLabel(String label) { + this.widget.setDescription(label); + } + + public Object getValue() { + return this.widget.getValue(); + } + + public void setValue(Object value) { + this.widget.setValue(value); + } + + public T getWidget() { + return widget; + } + + public void fireInit() { + for (EasyFormListener listener : onInitListeners) { + listener.execute((getValue() != null) ? getValue().toString() : null); + } + } + + public EasyFormComponent onInit(final EasyFormListener listener) { + addOnInitListener(listener); + return this; + } + + public void addOnInitListener(final EasyFormListener listener) { + if (listener != null) { + onInitListeners.add(listener); + } + } + + public void removeOnInitListener(final EasyFormListener listener) { + if (onInitListeners.contains(listener)) { + onInitListeners.remove(listener); + } + } + + public EasyFormComponent onChange(final EasyFormListener listener) { + addOnChangeListener(listener); + return this; + } + + public void fireChanged() { + for (EasyFormListener listener : onChangeListeners) { + listener.execute((this.getValue() != null) ? this.getValue().toString() : null); + } + } + + public void addOnChangeListener(final EasyFormListener listener) { + if (listener != null) { + onChangeListeners.add(listener); + } + } + + public void removeOnChangeListener(final EasyFormListener listener) { + if (onChangeListeners.contains(listener)) { + onChangeListeners.remove(listener); + } + } + + public void clearListeners() { + onChangeListeners.clear(); + onInitListeners.clear(); + } + + public boolean isEnabled() { + return enabled; + } + + public void setEnabled(final boolean enabled) { + this.enabled = enabled; + } + + public Object formatValue(final Object value) { + return String.class.cast(value); + } + + /** + * Throw IllegalArgumentException if such value can't be set to this component + * + * @param value + * object with data to be set + * @return true if value can be set to given component + */ + protected boolean checkValue(Object value) { + return true; + } + + public void registerUpdateValueCallback(final UpdateValueCallback updateValueCallback) { + getWidget().register(updateValueCallback); + } + + public boolean isButton() { + return false; + } + + @Override + public Comm getComm() { + return getWidget().getComm(); + } + + @Override + public void close() { + getComm().close(); + } + + private void setupNewValue(Message message) { + if (message.getContent() == null) { + return; + } + Map> dataMap = ((Map>) message.getContent().get(DATA)); + + if (dataMap != null && !dataMap.isEmpty()) { + Map stateMap = dataMap.get(STATE); + if (stateMap != null && !stateMap.isEmpty()) { + getNewValue(stateMap).ifPresent(newValue -> widget.setValue(newValue)); + } + } + } + + private Optional getNewValue(Map stateMap) { + if (stateMap.containsKey("value")) { + return Optional.of(stateMap.get("value")); + } else if (stateMap.containsKey("index")) { + return Optional.of(stateMap.get("index")); + } + + return Optional.empty(); + } + +} \ No newline at end of file diff --git a/base/src/main/java/com/twosigma/beakerx/easyform/EasyFormObjectManager.java b/base/src/main/java/com/twosigma/beakerx/easyform/EasyFormObjectManager.java new file mode 100644 index 0000000..8099116 --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/easyform/EasyFormObjectManager.java @@ -0,0 +1,52 @@ +/* + * Copyright 2015 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.easyform; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class EasyFormObjectManager { + private final Map _forms = new HashMap<>(); + private final Map _shellToId = new HashMap<>(); + + public void registerForm(final String id, final EasyForm form) { + _forms.put(id, form); + } + + public EasyForm getForm(final String id) { + return _forms.get(id); + } + + public void unregisterForm(final String id) { + _forms.remove(id); + } + + public void associate(final String id, final String shellId) { + _shellToId.put(id, shellId); + } + + public void dropAll(final String shellId) { + List keys = new ArrayList(_shellToId.keySet()); + for (String s : keys) { + if (_shellToId.get(s).equals(shellId)) { + _shellToId.remove(s); + _forms.remove(s); + } + } + } +} diff --git a/base/src/main/java/com/twosigma/beakerx/easyform/EasyFormView.java b/base/src/main/java/com/twosigma/beakerx/easyform/EasyFormView.java new file mode 100644 index 0000000..45db3db --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/easyform/EasyFormView.java @@ -0,0 +1,71 @@ +/* + * Copyright 2017 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.easyform; + +import com.twosigma.beakerx.widget.BeakerxWidget; +import com.twosigma.beakerx.widget.BeakerxWidgetInfo; +import com.twosigma.beakerx.widget.Widget; +import com.twosigma.beakerx.widget.Box; + +import java.util.List; + +public class EasyFormView extends Box { + + public static final String VIEW_NAME_VALUE = "EasyFormView"; + public static final String MODEL_NAME_VALUE = "EasyFormModel"; + public static final String EASY_FORM_NAME = "easyFormName"; + + private String easyFormName; + + public EasyFormView(List children) { + super(children); + openComm(); + } + + @Override + public String getModelModuleValue() { + return BeakerxWidgetInfo.MODEL_MODULE_VALUE; + } + + @Override + public String getViewModuleValue() { + return BeakerxWidgetInfo.VIEW_MODULE_VALUE; + } + + @Override + public String getModelNameValue() { + return MODEL_NAME_VALUE; + } + + @Override + public String getViewNameValue() { + return VIEW_NAME_VALUE; + } + + @Override + public void updateValue(Object value) { + + } + public String getEasyFormName() { + return easyFormName; + } + + public void setEasyFormName(String easyFormName) { + this.easyFormName = easyFormName; + sendUpdate(EASY_FORM_NAME, easyFormName); + } + +} \ No newline at end of file diff --git a/base/src/main/java/com/twosigma/beakerx/easyform/ObservableMap.java b/base/src/main/java/com/twosigma/beakerx/easyform/ObservableMap.java new file mode 100644 index 0000000..2cf2dde --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/easyform/ObservableMap.java @@ -0,0 +1,87 @@ +/* + * Copyright 2015 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.easyform; + +import java.util.Collection; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Observable; +import java.util.Set; + +public abstract class ObservableMap extends Observable implements Map { + + protected LinkedHashMap mapInstance = new LinkedHashMap<>(); + + @Override + public int size() { + return mapInstance.size(); + } + + @Override + public boolean isEmpty() { + return mapInstance.isEmpty(); + } + + @Override + public boolean containsKey(Object key) { + return mapInstance.containsKey(key); + } + + @Override + public boolean containsValue(Object value) { + return mapInstance.containsValue(value); + } + + @Override + public V get(Object key) { + return mapInstance.get(key); + } + + @Override + public V put(K key, V value) { + return mapInstance.put(key, value); + } + + @Override + public V remove(Object key) { + return mapInstance.remove(key); + } + + @Override + public void putAll(Map m) { + mapInstance.putAll(m); + } + + @Override + public void clear() { + mapInstance.clear(); + } + + @Override + public Set keySet() { + return mapInstance.keySet(); + } + + @Override + public Collection values() { + return mapInstance.values(); + } + + @Override + public Set> entrySet() { + return mapInstance.entrySet(); + } +} diff --git a/base/src/main/java/com/twosigma/beakerx/easyform/formitem/EasyFormListener.java b/base/src/main/java/com/twosigma/beakerx/easyform/formitem/EasyFormListener.java new file mode 100644 index 0000000..5dc9848 --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/easyform/formitem/EasyFormListener.java @@ -0,0 +1,22 @@ +/* + * Copyright 2015 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.easyform.formitem; + +@FunctionalInterface +public interface EasyFormListener { + void execute(String value); +} diff --git a/base/src/main/java/com/twosigma/beakerx/easyform/formitem/ListComponent.java b/base/src/main/java/com/twosigma/beakerx/easyform/formitem/ListComponent.java new file mode 100644 index 0000000..28d303c --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/easyform/formitem/ListComponent.java @@ -0,0 +1,52 @@ +/* + * Copyright 2015 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.easyform.formitem; + +import com.twosigma.beakerx.easyform.EasyFormComponent; +import com.twosigma.beakerx.widget.SelectionWidget; + +import java.util.Collection; + +public abstract class ListComponent> extends EasyFormComponent { + + private Boolean multipleSelection; + private Collection values; + + public ListComponent(T widget){ + this.widget = widget; + } + + public abstract void setSize(final Integer size); + + public abstract Integer getSize(); + + public void setMultipleSelection(final Boolean multipleSelection) { + this.multipleSelection = multipleSelection; + } + + public Boolean getMultipleSelection() { + return multipleSelection; + } + + public void setValues(final Collection values) { + this.values = values; + } + + public Collection getValues() { + return values; + } +} diff --git a/base/src/main/java/com/twosigma/beakerx/easyform/formitem/LoadValuesButton.java b/base/src/main/java/com/twosigma/beakerx/easyform/formitem/LoadValuesButton.java new file mode 100644 index 0000000..a420ec4 --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/easyform/formitem/LoadValuesButton.java @@ -0,0 +1,58 @@ +/* + * Copyright 2015 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.easyform.formitem; + +import com.twosigma.beakerx.easyform.EasyFormComponent; +import com.twosigma.beakerx.widget.ValueWidget; + +public class LoadValuesButton extends EasyFormComponent { + + private String path; + + public void setPath(final String path) { + this.path = path; + } + + public String getPath() { + return path; + } + + @Override + public ValueWidget getWidget() { + return null; + } + + @Override + public String getLabel() { + throw new RuntimeException("Not implemented yet."); + } + + @Override + public void setLabel(String label) { + throw new RuntimeException("Not implemented yet."); + } + + @Override + public String getValue() { + throw new RuntimeException("Not implemented yet."); + } + + @Override + public void setValue(Object value) { + throw new RuntimeException("Not implemented yet."); + } +} diff --git a/base/src/main/java/com/twosigma/beakerx/easyform/formitem/SaveValuesButton.java b/base/src/main/java/com/twosigma/beakerx/easyform/formitem/SaveValuesButton.java new file mode 100644 index 0000000..16e3c05 --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/easyform/formitem/SaveValuesButton.java @@ -0,0 +1,62 @@ +/* + * Copyright 2015 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.easyform.formitem; + +import com.twosigma.beakerx.easyform.EasyFormComponent; +import com.twosigma.beakerx.widget.ValueWidget; + +public class SaveValuesButton extends EasyFormComponent> { + + private String path; + + public void setPath(final String path) { + this.path = path; + } + + public String getPath() { + return path; + } + + public boolean isButton() { + return true; + } + + @Override + public ValueWidget getWidget() { + return null; + } + + @Override + public String getLabel() { + throw new RuntimeException("Not implemented yet."); + } + + @Override + public void setLabel(String label) { + throw new RuntimeException("Not implemented yet."); + } + + @Override + public String getValue() { + throw new RuntimeException("Not implemented yet."); + } + + @Override + public void setValue(Object value) { + throw new RuntimeException("Not implemented yet."); + } +} \ No newline at end of file diff --git a/base/src/main/java/com/twosigma/beakerx/easyform/formitem/widgets/ButtonComponentWidget.java b/base/src/main/java/com/twosigma/beakerx/easyform/formitem/widgets/ButtonComponentWidget.java new file mode 100644 index 0000000..21acb84 --- /dev/null +++ b/base/src/main/java/com/twosigma/beakerx/easyform/formitem/widgets/ButtonComponentWidget.java @@ -0,0 +1,80 @@ +/* + * Copyright 2017 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.easyform.formitem.widgets; + +import com.twosigma.beakerx.easyform.EasyFormComponent; +import com.twosigma.beakerx.easyform.formitem.EasyFormListener; +import com.twosigma.beakerx.widget.Button; +import com.twosigma.beakerx.message.Message; + +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; + +public class ButtonComponentWidget extends EasyFormComponent