diff --git a/kernel/scala/src/main/java/com/twosigma/beakerx/scala/comm/ScalaCommOpenHandler.java b/kernel/scala/src/main/java/com/twosigma/beakerx/scala/comm/ScalaCommOpenHandler.java index 29a10a07e8..dd55eebdd4 100644 --- a/kernel/scala/src/main/java/com/twosigma/beakerx/scala/comm/ScalaCommOpenHandler.java +++ b/kernel/scala/src/main/java/com/twosigma/beakerx/scala/comm/ScalaCommOpenHandler.java @@ -17,6 +17,7 @@ import com.twosigma.beakerx.kernel.KernelFunctionality; import com.twosigma.beakerx.handler.Handler; +import com.twosigma.beakerx.kernel.comm.AutotranslationHandler; import com.twosigma.beakerx.message.Message; import com.twosigma.beakerx.kernel.comm.KernelControlCommandListHandler; import com.twosigma.beakerx.kernel.comm.KernelControlInterrupt; @@ -29,6 +30,9 @@ public class ScalaCommOpenHandler extends CommOpenHandler{ new KernelControlInterrupt(kernel), new KernelControlCommandListHandler(kernel)}; + private Handler[] AUTOTRANSLATION_HANDLER = { + new AutotranslationHandler(kernel)}; + public ScalaCommOpenHandler(KernelFunctionality kernel) { super(kernel); } @@ -36,6 +40,8 @@ public ScalaCommOpenHandler(KernelFunctionality kernel) { public Handler[] getKernelControlChanelHandlers(String targetName){ if(TargetNamesEnum.KERNEL_CONTROL_CHANNEL.getTargetName().equalsIgnoreCase(targetName)){ return (Handler[]) KERNEL_CONTROL_CHANNEL_HANDLERS; + }else if (TargetNamesEnum.BEAKER_AUTOTRANSLATION.getTargetName().equalsIgnoreCase(targetName)) { + return (Handler[]) AUTOTRANSLATION_HANDLER; }else{ return (Handler[]) new Handler[0]; } diff --git a/kernel/scala/src/main/java/com/twosigma/beakerx/scala/evaluator/BeakerxObjectFactoryImpl.java b/kernel/scala/src/main/java/com/twosigma/beakerx/scala/evaluator/BeakerxObjectFactoryImpl.java index ecd7db0cb9..f33d7c422f 100644 --- a/kernel/scala/src/main/java/com/twosigma/beakerx/scala/evaluator/BeakerxObjectFactoryImpl.java +++ b/kernel/scala/src/main/java/com/twosigma/beakerx/scala/evaluator/BeakerxObjectFactoryImpl.java @@ -24,6 +24,7 @@ public class BeakerxObjectFactoryImpl implements BeakerxObjectFactory { public String create() { return "import " + BEAKER_X_CLIENT_MANAGER_PATH + "\n" + "import language.dynamics\n" + + "implicit class ObjectEnhancement(obj: Any) { def as[T] = obj.asInstanceOf[T]}\n" + "var _beakerx = " + BEAKER_X_CLIENT_MANAGER_GET + "\n" + "object beakerx extends Dynamic {\n" + " def selectDynamic( field : String ) = _beakerx.get(field)\n" + diff --git a/kernel/scala/src/test/java/com/twosigma/beakerx/scala/ScalaAutotranslationTest.java b/kernel/scala/src/test/java/com/twosigma/beakerx/scala/ScalaAutotranslationTest.java new file mode 100644 index 0000000000..119cf3595f --- /dev/null +++ b/kernel/scala/src/test/java/com/twosigma/beakerx/scala/ScalaAutotranslationTest.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.scala; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.twosigma.beakerx.BeakerXCommRepositoryMock; +import com.twosigma.beakerx.KernelSetUpFixtureTest; +import com.twosigma.beakerx.NamespaceClient; +import com.twosigma.beakerx.NamespaceClientTest; +import com.twosigma.beakerx.evaluator.EvaluatorTest; +import com.twosigma.beakerx.kernel.CloseKernelAction; +import com.twosigma.beakerx.kernel.CustomMagicCommandsEmptyImpl; +import com.twosigma.beakerx.kernel.Kernel; +import com.twosigma.beakerx.kernel.KernelSocketsFactory; +import com.twosigma.beakerx.kernel.comm.Comm; +import com.twosigma.beakerx.message.Message; +import com.twosigma.beakerx.scala.evaluator.BeakerxObjectFactoryImpl; +import com.twosigma.beakerx.scala.evaluator.ScalaEvaluator; +import com.twosigma.beakerx.scala.kernel.Scala; +import com.twosigma.beakerx.scala.kernel.ScalaBeakerXJsonSerializer; +import org.junit.Test; + +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +import static com.twosigma.beakerx.MessageFactoryTest.getExecuteRequestMessage; +import static com.twosigma.beakerx.evaluator.EvaluatorResultTestWatcher.waitForIdleMessage; +import static com.twosigma.beakerx.evaluator.EvaluatorResultTestWatcher.waitForResult; +import static com.twosigma.beakerx.evaluator.EvaluatorTest.getCacheFolderFactory; +import static com.twosigma.beakerx.evaluator.EvaluatorTest.getTestTempFolderFactory; +import static com.twosigma.beakerx.evaluator.TestBeakerCellExecutor.cellExecutor; +import static org.assertj.core.api.Assertions.assertThat; + +public class ScalaAutotranslationTest extends KernelSetUpFixtureTest { + + private NamespaceClientTest.AutotranslationServiceTestImpl autotranslationService; + + @Override + protected Kernel createKernel(String sessionId, KernelSocketsFactory kernelSocketsFactory, CloseKernelAction closeKernelAction) { + autotranslationService = new NamespaceClientTest.AutotranslationServiceTestImpl(); + NamespaceClient nc = new NamespaceClient(autotranslationService, new ScalaBeakerXJsonSerializer(), new BeakerXCommRepositoryMock()); + + ScalaEvaluator evaluator = new ScalaEvaluator( + sessionId, + sessionId, + cellExecutor(), + new BeakerxObjectFactoryImpl(), + getTestTempFolderFactory(), + EvaluatorTest.KERNEL_PARAMETERS, + nc); + return new Scala(sessionId, evaluator, kernelSocketsFactory, closeKernelAction, getCacheFolderFactory(), new CustomMagicCommandsEmptyImpl(), new BeakerXCommRepositoryMock()); + } + + + @Test + public void transformFromJsonToScalaObject() throws Exception { + //given + autotranslationService.update("bar", list()); + //when + String code = "beakerx.bar"; + Message message = getExecuteRequestMessage(code); + kernelSocketsService.handleMsg(message); + //then + Optional idleMessage = waitForIdleMessage(kernelSocketsService.getKernelSockets()); + assertThat(idleMessage).isPresent(); + Optional result = waitForResult(kernelSocketsService.getKernelSockets()); + verifyScalaObject(result.get()); + } + + private void verifyScalaObject(Message message) { + Map actual = ((Map) message.getContent().get(Comm.DATA)); + String value = (String) actual.get("text/plain"); + assertThat(value).isNotEmpty(); + assertThat(value).contains("2"); + } + + @Test + public void transformFromJsonToScalaListHead() throws Exception { + //given + autotranslationService.update("bar", list()); + //when + String code = "beakerx.bar.as[List[Any]].head"; + Message message = getExecuteRequestMessage(code); + kernelSocketsService.handleMsg(message); + //then + Optional idleMessage = waitForIdleMessage(kernelSocketsService.getKernelSockets()); + assertThat(idleMessage).isPresent(); + Optional result = waitForResult(kernelSocketsService.getKernelSockets()); + verifyScalaListHead(result.get()); + } + + private void verifyScalaListHead(Message message) { + Map actual = ((Map) message.getContent().get(Comm.DATA)); + String value = (String) actual.get("text/plain"); + assertThat(value).isNotEmpty(); + assertThat(value).isEqualTo("1"); + } + + + private String list() { + List maps = new LinkedList<>(); + maps.add(1); + maps.add(2); + maps.add(3); + ObjectMapper objectMapper = new ObjectMapper(); + try { + return objectMapper.writeValueAsString(maps); + } catch (JsonProcessingException e) { + throw new RuntimeException(); + } + + } + + +} diff --git a/test/ipynb/scala/SupportScalaObjectInAutotranslation.ipynb b/test/ipynb/scala/SupportScalaObjectInAutotranslation.ipynb new file mode 100644 index 0000000000..cc7daa9013 --- /dev/null +++ b/test/ipynb/scala/SupportScalaObjectInAutotranslation.ipynb @@ -0,0 +1,145 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "%%javascript\n", + "beakerx.bar = [23, 48, 55, 100];" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "%%scala\n", + "beakerx.bar.as[List[Int]].head" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "%%scala\n", + "val list = beakerx.bar.as[List[Any]]\n", + "list.head" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "%%scala\n", + "beakerx.bar.as[List[Any]](1)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "%%scala\n", + "beakerx.bar.as[List[Any]].isEmpty" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "%%scala\n", + "1 :: beakerx.bar.as[List[Any]]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "%%scala\n", + "beakerx.bar.asInstanceOf[List[Any]].head" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "%%javascript\n", + "beakerx.foo = 11;" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "%%scala\n", + "beakerx.foo.as[Int] + 1" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "%%scala\n", + "val cc = beakerx.foo.as[Int] \n", + "cc + 1" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Groovy", + "language": "groovy", + "name": "groovy" + }, + "language_info": { + "codemirror_mode": "groovy", + "file_extension": ".groovy", + "mimetype": "", + "name": "Groovy", + "nbconverter_exporter": "", + "version": "2.4.3" + }, + "toc": { + "base_numbering": 1, + "nav_menu": {}, + "number_sections": false, + "sideBar": false, + "skip_h1_title": false, + "title_cell": "Table of Contents", + "title_sidebar": "Contents", + "toc_cell": false, + "toc_position": {}, + "toc_section_display": false, + "toc_window_display": false + } + }, + "nbformat": 4, + "nbformat_minor": 2 +}