This is an automated email from the ASF dual-hosted git repository. jongyoul pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/zeppelin.git
The following commit(s) were added to refs/heads/master by this push: new c86bfadaa5 [ZEPPELIN-5965] Remove Kotlin Interpreter (#4659) c86bfadaa5 is described below commit c86bfadaa5ef5e08f41e689d4aae9d78624729d7 Author: Cheng Pan <cheng...@apache.org> AuthorDate: Mon Sep 18 09:24:34 2023 +0800 [ZEPPELIN-5965] Remove Kotlin Interpreter (#4659) * [ZEPPELIN-5965] Remove Kotlin Interpreter * fix * fix * fix --- LICENSE | 1 - conf/interpreter-list | 1 - docs/_includes/themes/zeppelin/_navigation.html | 1 - docs/index.md | 1 - docs/interpreter/kotlin.md | 84 ------ docs/interpreter/spark.md | 7 +- docs/usage/interpreter/installation.md | 5 - kotlin/README.md | 83 ------ kotlin/pom.xml | 117 -------- .../apache/zeppelin/kotlin/KotlinInterpreter.java | 189 ------------ .../kotlin/completion/KotlinCompleter.java | 68 ----- .../zeppelin/kotlin/completion/KotlinKeywords.java | 104 ------- .../zeppelin/kotlin/context/KotlinReceiver.java | 37 --- .../zeppelin/kotlin/reflect/ContextUpdater.java | 160 ---------- .../kotlin/reflect/KotlinFunctionInfo.java | 69 ----- .../zeppelin/kotlin/reflect/KotlinReflectUtil.java | 37 --- .../kotlin/reflect/KotlinVariableInfo.java | 60 ---- .../apache/zeppelin/kotlin/repl/ClassWriter.java | 91 ------ .../apache/zeppelin/kotlin/repl/KotlinRepl.java | 272 ----------------- .../kotlin/repl/building/KotlinReplProperties.java | 129 -------- .../kotlin/repl/building/ReplBuilding.java | 108 ------- kotlin/src/main/resources/interpreter-setting.json | 28 -- .../zeppelin/kotlin/KotlinInterpreterTest.java | 329 --------------------- pom.xml | 1 - spark/interpreter/pom.xml | 6 - .../spark/AbstractSparkScalaInterpreter.java | 5 - .../zeppelin/spark/KotlinSparkInterpreter.java | 191 ------------ .../apache/zeppelin/spark/SparkInterpreter.java | 7 - .../spark/kotlin/KotlinZeppelinBindings.java | 52 ---- .../zeppelin/spark/kotlin/SparkKotlinReceiver.java | 43 --- .../src/main/resources/interpreter-setting.json | 34 --- .../zeppelin/spark/KotlinSparkInterpreterTest.java | 232 --------------- .../zeppelin/spark/SparkScala212Interpreter.scala | 14 +- .../zeppelin/spark/SparkZeppelinContext.scala | 3 +- .../org/apache/zeppelin/spark/SparkILoop.scala | 2 +- .../zeppelin/spark/SparkScala213Interpreter.scala | 14 +- .../zeppelin/spark/SparkZeppelinContext.scala | 3 +- zeppelin-web/bower.json | 1 - zeppelin-web/karma.conf.js | 1 - zeppelin-web/src/index.html | 1 - 40 files changed, 6 insertions(+), 2585 deletions(-) diff --git a/LICENSE b/LICENSE index 7f759130ca..2efdc5dbb0 100644 --- a/LICENSE +++ b/LICENSE @@ -265,7 +265,6 @@ The text of each license is also included at licenses/LICENSE-[project]-[version (Apache 2.0) Google Cloud Client Library for Java (https://github.com/GoogleCloudPlatform/google-cloud-java) (Apache 2.0) concurrentunit (https://github.com/jhalterman/concurrentunit) (Apache 2.0) Embedded MongoDB (https://github.com/flapdoodle-oss/de.flapdoodle.embed.mongo) - (Apache 2.0) Kotlin (https://github.com/JetBrains/kotlin) (Apache 2.0) s3proxy (https://github.com/gaul/s3proxy) (Apache 2.0) kubernetes-client (https://github.com/fabric8io/kubernetes-client) diff --git a/conf/interpreter-list b/conf/interpreter-list index 4e7bef2448..0c27153953 100644 --- a/conf/interpreter-list +++ b/conf/interpreter-list @@ -28,7 +28,6 @@ groovy org.apache.zeppelin:zeppelin-groovy:0.10.0 Groovy hbase org.apache.zeppelin:zeppelin-hbase:0.10.0 Hbase interpreter java org.apache.zeppelin:zeppelin-java:0.10.0 Java interpreter jdbc org.apache.zeppelin:zeppelin-jdbc:0.10.0 Jdbc interpreter -kotlin org.apache.zeppelin:zeppelin-kotlin:0.10.0 Kotlin interpreter livy org.apache.zeppelin:zeppelin-livy:0.10.0 Livy interpreter md org.apache.zeppelin:zeppelin-markdown:0.10.0 Markdown support neo4j org.apache.zeppelin:zeppelin-neo4j:0.10.0 Neo4j interpreter diff --git a/docs/_includes/themes/zeppelin/_navigation.html b/docs/_includes/themes/zeppelin/_navigation.html index d7f3ee4db7..d2d1b3edb2 100644 --- a/docs/_includes/themes/zeppelin/_navigation.html +++ b/docs/_includes/themes/zeppelin/_navigation.html @@ -150,7 +150,6 @@ <li><a href="{{BASE_PATH}}/interpreter/influxdb.html">influxDB</a></li> <li><a href="{{BASE_PATH}}/interpreter/java.html">Java</a></li> <li><a href="{{BASE_PATH}}/interpreter/jupyter.html">Jupyter</a></li> - <li><a href="{{BASE_PATH}}/interpreter/kotlin.html">Kotlin</a></li> <li><a href="{{BASE_PATH}}/interpreter/livy.html">Livy</a></li> <li><a href="{{BASE_PATH}}/interpreter/mahout.html">Mahout</a></li> <li><a href="{{BASE_PATH}}/interpreter/markdown.html">Markdown</a></li> diff --git a/docs/index.md b/docs/index.md index f0cd7355ed..b0fc32bb55 100644 --- a/docs/index.md +++ b/docs/index.md @@ -147,7 +147,6 @@ limitations under the License. * [Java](./interpreter/java.html) * [JDBC](./interpreter/jdbc.html) * [Jupyter](./interpreter/jupyter.html) - * [Kotlin](./interpreter/kotlin.html) * [Livy](./interpreter/livy.html) * [Mahout](./interpreter/mahout.html) * [Markdown](./interpreter/markdown.html) diff --git a/docs/interpreter/kotlin.md b/docs/interpreter/kotlin.md deleted file mode 100644 index f994dbb9d7..0000000000 --- a/docs/interpreter/kotlin.md +++ /dev/null @@ -1,84 +0,0 @@ ---- -layout: page -title: "Kotlin interpreter in Apache Zeppelin" -description: "Kotlin is a cross-platform, statically typed, general-purpose programming language with type inference." -group: interpreter ---- -<!-- -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - -http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. ---> - -{% include JB/setup %} - -# Kotlin interpreter for Apache Zeppelin - -<div id="toc"></div> - -## Overview -Kotlin is a cross-platform, statically typed, general-purpose programming language with type inference. -It is designed to interoperate fully with Java, and the JVM version of its standard library depends on the Java Class Library, but type inference allows its syntax to be more concise. - -## Configuration -<table class="table-configuration"> - <thead> - <tr> - <th>Name</th> - <th>Default</th> - <th>Description</th> - </tr> - </thead> - <tbody> - <tr> - <td>zeppelin.kotlin.maxResult</td> - <td>1000</td> - <td>Max n</td> - </tr> - <tr> - <td>zeppelin.kotlin.shortenTypes</td> - <td>true</td> - <td>Display shortened types instead of full, e.g. Int vs kotlin.Int</td> - </tr> - </tbody> -</table> - -## Example - -```kotlin -%kotlin - -fun square(n: Int): Int = n * n -``` - -## Kotlin Context -Kotlin context is accessible via `kc` object bound to the interpreter. -It holds `vars` and `functions` fields that return all user-defined variables and functions present in the interpreter. -You can also print variables or functions by calling `kc.showVars()` or `kc.showFunctions()`. - -### Example - - -```kotlin -fun square(n: Int): Int = n * n - -val greeter = { s: String -> println("Hello $s!") } -val l = listOf("Drive", "to", "develop") - -kc.showVars() -kc.showFunctions() -``` -Output: -``` -l: List<String> = [Drive, to, develop] -greeter: (String) -> Unit = (kotlin.String) -> kotlin.Unit -fun square(Int): Int -``` diff --git a/docs/interpreter/spark.md b/docs/interpreter/spark.md index 561f76d3c7..1fa02b5b2f 100644 --- a/docs/interpreter/spark.md +++ b/docs/interpreter/spark.md @@ -69,11 +69,6 @@ Apache Spark is supported in Zeppelin with Spark interpreter group which consist <td>SparkSQLInterpreter</td> <td>Provides a SQL environment</td> </tr> - <tr> - <td>%spark.kotlin</td> - <td>KotlinSparkInterpreter</td> - <td>Provides a Kotlin environment</td> - </tr> </table> ## Main Features @@ -390,7 +385,7 @@ You can also choose `scoped` mode. For `scoped` per note mode, Zeppelin creates ## SparkContext, SQLContext, SparkSession, ZeppelinContext -SparkContext, SQLContext, SparkSession (for spark 2.x, 3.x) and ZeppelinContext are automatically created and exposed as variable names `sc`, `sqlContext`, `spark` and `z` respectively, in Scala, Kotlin, Python and R environments. +SparkContext, SQLContext, SparkSession (for spark 2.x, 3.x) and ZeppelinContext are automatically created and exposed as variable names `sc`, `sqlContext`, `spark` and `z` respectively, in Scala, Python and R environments. > Note that Scala/Python/R environment shares the same SparkContext, > SQLContext, SparkSession and ZeppelinContext instance. diff --git a/docs/usage/interpreter/installation.md b/docs/usage/interpreter/installation.md index 3050fac6c1..abaa9624d8 100644 --- a/docs/usage/interpreter/installation.md +++ b/docs/usage/interpreter/installation.md @@ -162,11 +162,6 @@ You can also find the below community managed interpreter list in `conf/interpre <td>org.apache.zeppelin:zeppelin-jdbc:0.10.0</td> <td>Jdbc interpreter</td> </tr> - <tr> - <td>kotlin</td> - <td>org.apache.zeppelin:zeppelin-kotlin:0.7.0</td> - <td>Kotlin interpreter</td> - </tr> <tr> <td>livy</td> <td>org.apache.zeppelin:zeppelin-livy:0.10.0</td> diff --git a/kotlin/README.md b/kotlin/README.md deleted file mode 100644 index 765df6aa47..0000000000 --- a/kotlin/README.md +++ /dev/null @@ -1,83 +0,0 @@ -# Developer guide to Kotlin interpreter - -The following module adds Kotlin language support to Apache Zeppelin. -Here is the guide to its implementation and how it can be improved and tested. - -## Implementation details -### Kotlin REPL -For interactive Kotlin execution, an instance of `KotlinRepl` is created. -To set REPL properties (such as classpath, generated classes output directory, max result, etc.), -pass `KotlinReplProperties` to its constructor. For example: -```java -KotlinReplProperties replProperties = new KotlinReplProperties() - .maxResult(1000) - .shortenTypes(true); -KotlinRepl repl = new KotlinRepl(replProperties); -``` - -### Variable/function binding -You can also bind variables and functions on REPL creation using implicit receiver language feature. -This means that all code run in REPL will be executed in Kotlin's `with` block with the receiver, -making the receiver's fields and methods accessible. - -To add your variables/functions, extend `KotlinReceiver` class (in separate file), declare your fields and methods, and pass an instance of it to -`KotlinReplProperties`. Example: -```java -// In separate file: -class CustomReceiver extends KotlinReceiver { - public int myValue = 1 // will be converted to Kotlin "var myValue: Int" - public final String messageTemplate = "Value = %VALUE%" // "val messageTemplate: String" - - public String getMessage() { - return messageTemplate.replace("%VALUE%", String.valueOf(myValue)); - } -} - -// In intepreter creation: -replProperties.receiver(new CustomReceiver); -KotlinRepl repl = new KotlinRepl(replProperties); -repl.eval("getMessage()"); // will return interpreterResult with "Value = 1" string -``` - -In `KotlinInterpreter` REPL properties are created on construction, are accessible via `getKotlinReplProperties` method, -and are used in REPL creation on `open()`. - -### Generated class files -Each code snippet run in REPL is registered as a separate class and saved in location -specified by `outputDir` REPL property. Anonymous classes and lambdas also get saved there under specific names. - -This is needed for Spark to send classes to remote executors, and in Spark Kotlin interpreter this directory is the same -as in `sparkContext` option `spark.repl.class.outputDir`. - -### Kotlin Spark Interpreter -Kotlin interpreter in Spark intepreter group takes `SparkSession`, `JavaSparkContext`, `SQLContext` -and `ZeppelinContext` from `SparkInterpreter` in the same session and binds them in its scope. - -## Testing -Kotlin Interpreter and Spark Kotlin Interpreter come with unit tests. -They can be run with \ -`./mvnw clean test` \ -in `$ZEPPELIN_HOME/kotlin` for base Kotlin Interpreter and \ -`./mvnw -Dtest=KotlinSparkInterpreterTest test` \ -in `$ZEPPELIN_HOME/spark/interpreter` for Spark Kotlin Interpreter. - -To test manually, build Zeppelin with \ -`./mvnw clean package -DskipTests` \ -and create a note with `kotlin` interpreter for base or `spark` for Spark. -In Spark interpreter, add `%spark.kotlin` in the start of paragraph to use Kotlin Spark Interpreter. - -Example: -```$kotlin -%spark.kotlin -val df = spark.range(10) -df.show() -``` -## Possible Improvements -* It would be great to bind `ZeppelinContext` to base Kotlin interpreter, but for now I had trouble instantiating it -inside KotlinInterpreter. -* When Kotlin has its own Spark API, it will be good to move to it. Currently in Java Spark API Kotlin -can not use things like `forEach` because of ambiguity between `Iterable<?>.forEach` and `Map<?, ?>.forEach` -(`foreach` from Spark's API does work, though). -* The scoped mode for Kotlin Spark Interpreter currently has issues with having the same class output directory -for different intepreters, leading to overwriting classes. Adding prefixes to generated classes or putting them - in separate directories leads to `ClassNotFoundException` on Spark executors. diff --git a/kotlin/pom.xml b/kotlin/pom.xml deleted file mode 100644 index 81c5f33ca2..0000000000 --- a/kotlin/pom.xml +++ /dev/null @@ -1,117 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - ~ Licensed to the Apache Software Foundation (ASF) under one or more - ~ contributor license agreements. See the NOTICE file distributed with - ~ this work for additional information regarding copyright ownership. - ~ The ASF licenses this file to You under the Apache License, Version 2.0 - ~ (the "License"); you may not use this file except in compliance with - ~ the License. You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> - <modelVersion>4.0.0</modelVersion> - - <parent> - <artifactId>zeppelin-interpreter-parent</artifactId> - <groupId>org.apache.zeppelin</groupId> - <version>0.11.0-SNAPSHOT</version> - <relativePath>../zeppelin-interpreter-parent/pom.xml</relativePath> - </parent> - - <artifactId>zeppelin-kotlin</artifactId> - <packaging>jar</packaging> - <name>Zeppelin: Kotlin interpreter</name> - - <properties> - <interpreter.name>kotlin</interpreter.name> - <kotlin.version>1.3.50</kotlin.version> - </properties> - - <dependencies> - <dependency> - <groupId>org.jetbrains.kotlin</groupId> - <artifactId>kotlin-scripting-jvm-host-embeddable</artifactId> - <version>${kotlin.version}</version> - <exclusions> - <exclusion> - <groupId>org.jetbrains.kotlin</groupId> - <artifactId>kotlin-stdlib</artifactId> - </exclusion> - <exclusion> - <groupId>org.jetbrains.kotlin</groupId> - <artifactId>kotlin-stdlib-common</artifactId> - </exclusion> - </exclusions> - </dependency> - <dependency> - <groupId>org.jetbrains.kotlin</groupId> - <artifactId>kotlin-compiler-embeddable</artifactId> - <version>${kotlin.version}</version> - <exclusions> - <exclusion> - <groupId>org.jetbrains.kotlin</groupId> - <artifactId>kotlin-stdlib</artifactId> - </exclusion> - </exclusions> - </dependency> - <dependency> - <groupId>org.jetbrains.kotlin</groupId> - <artifactId>kotlin-scripting-jvm</artifactId> - <version>${kotlin.version}</version> - <exclusions> - <exclusion> - <groupId>org.jetbrains.kotlin</groupId> - <artifactId>kotlin-stdlib</artifactId> - </exclusion> - </exclusions> - </dependency> - <dependency> - <groupId>org.jetbrains.kotlin</groupId> - <artifactId>kotlin-scripting-compiler-embeddable</artifactId> - <version>${kotlin.version}</version> - <exclusions> - <exclusion> - <groupId>org.jetbrains.kotlin</groupId> - <artifactId>kotlin-stdlib</artifactId> - </exclusion> - </exclusions> - </dependency> - <dependency> - <groupId>org.jetbrains.kotlin</groupId> - <artifactId>kotlin-stdlib</artifactId> - <version>${kotlin.version}</version> - </dependency> - - <dependency> - <groupId>org.jetbrains.kotlin</groupId> - <artifactId>kotlin-reflect</artifactId> - <version>${kotlin.version}</version> - </dependency> - </dependencies> - - <build> - <plugins> - <plugin> - <artifactId>maven-enforcer-plugin</artifactId> - </plugin> - <plugin> - <artifactId>maven-resources-plugin</artifactId> - </plugin> - <plugin> - <artifactId>maven-shade-plugin</artifactId> - </plugin> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-checkstyle-plugin</artifactId> - </plugin> - </plugins> - </build> -</project> diff --git a/kotlin/src/main/java/org/apache/zeppelin/kotlin/KotlinInterpreter.java b/kotlin/src/main/java/org/apache/zeppelin/kotlin/KotlinInterpreter.java deleted file mode 100644 index 26af7eef6c..0000000000 --- a/kotlin/src/main/java/org/apache/zeppelin/kotlin/KotlinInterpreter.java +++ /dev/null @@ -1,189 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.zeppelin.kotlin; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import java.io.File; -import java.io.PrintStream; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Map; -import java.util.Properties; -import org.apache.zeppelin.interpreter.Interpreter; -import org.apache.zeppelin.interpreter.InterpreterContext; -import org.apache.zeppelin.interpreter.InterpreterException; -import org.apache.zeppelin.interpreter.InterpreterOutput; -import org.apache.zeppelin.interpreter.InterpreterResult; -import org.apache.zeppelin.interpreter.thrift.InterpreterCompletion; -import org.apache.zeppelin.interpreter.util.InterpreterOutputStream; -import org.apache.zeppelin.kotlin.completion.KotlinCompleter; -import org.apache.zeppelin.kotlin.context.KotlinReceiver; -import org.apache.zeppelin.kotlin.reflect.KotlinFunctionInfo; -import org.apache.zeppelin.kotlin.reflect.KotlinVariableInfo; -import org.apache.zeppelin.kotlin.repl.KotlinRepl; -import org.apache.zeppelin.kotlin.repl.building.KotlinReplProperties; -import org.apache.zeppelin.scheduler.Job; - -public class KotlinInterpreter extends Interpreter { - - private static Logger logger = LoggerFactory.getLogger(KotlinInterpreter.class); - - private InterpreterOutputStream out; - private KotlinRepl interpreter; - private KotlinReplProperties replProperties; - private KotlinCompleter completer; - - public KotlinInterpreter(Properties properties) { - super(properties); - replProperties = new KotlinReplProperties(); - - int maxResult = Integer.parseInt( - properties.getProperty("zeppelin.kotlin.maxResult", "1000")); - - boolean shortenTypes = Boolean.parseBoolean( - properties.getProperty("zeppelin.kotlin.shortenTypes", "true")); - String imports = properties.getProperty("zeppelin.interpreter.localRepo", ""); - - completer = new KotlinCompleter(); - replProperties - .receiver(new KotlinReceiver()) - .maxResult(maxResult) - .codeOnLoad("") - .classPath(getImportClasspath(imports)) - .shortenTypes(shortenTypes); - } - - public KotlinReplProperties getKotlinReplProperties() { - return replProperties; - } - - @Override - public void open() throws InterpreterException { - interpreter = new KotlinRepl(replProperties); - - completer.setCtx(interpreter.getKotlinContext()); - out = new InterpreterOutputStream(logger); - } - - @Override - public void close() { - - } - - @Override - public InterpreterResult interpret(String code, - InterpreterContext context) throws InterpreterException{ - // saving job's running thread for cancelling - Job<?> runningJob = getRunningJob(context.getParagraphId()); - if (runningJob != null) { - runningJob.info().put("CURRENT_THREAD", Thread.currentThread()); - } - - return runWithOutput(code, context.out); - } - - @Override - public void cancel(InterpreterContext context) throws InterpreterException { - Job<?> runningJob = getRunningJob(context.getParagraphId()); - if (runningJob != null) { - Map<String, Object> info = runningJob.info(); - Object object = info.get("CURRENT_THREAD"); - if (object instanceof Thread) { - try { - Thread t = (Thread) object; - t.interrupt(); - } catch (Throwable t) { - logger.error("Failed to cancel script: " + t, t); - } - } - } - } - - @Override - public FormType getFormType() throws InterpreterException { - return FormType.NATIVE; - } - - @Override - public int getProgress(InterpreterContext context) throws InterpreterException { - return 0; - } - - @Override - public List<InterpreterCompletion> completion(String buf, int cursor, - InterpreterContext interpreterContext) throws InterpreterException { - return completer.completion(buf, cursor, interpreterContext); - } - - public List<KotlinVariableInfo> getVariables() { - return interpreter.getVariables(); - } - - public List<KotlinFunctionInfo> getFunctions() { - return interpreter.getFunctions(); - } - - private Job<?> getRunningJob(String paragraphId) { - Job<?> foundJob = null; - Collection<Job<?>> jobsRunning = getScheduler().getAllJobs(); - for (Job<?> job : jobsRunning) { - if (job.getId().equals(paragraphId)) { - foundJob = job; - } - } - return foundJob; - } - - /** - * Kotlin interpreter uses System.out for printing, so it is redirected to InterpreterOutput. - * Note that Scala's Console class needs separate output redirection - */ - private InterpreterResult runWithOutput(String code, InterpreterOutput out) { - this.out.setInterpreterOutput(out); - - PrintStream oldOut = System.out; - PrintStream newOut = (out != null) ? new PrintStream(out) : null; - try { - System.setOut(newOut); - return interpreter.eval(code); - } finally { - System.setOut(oldOut); - } - } - - private List<String> getImportClasspath(String localRepo) { - List<String> classpath = new ArrayList<>(); - if (localRepo.equals("")) { - return classpath; - } - - File repo = new File(localRepo); - File[] files = repo.listFiles(); - if (files == null) { - return classpath; - } - for (File file : files) { - if (file.isFile()) { - classpath.add(file.getAbsolutePath()); - } - } - return classpath; - } -} diff --git a/kotlin/src/main/java/org/apache/zeppelin/kotlin/completion/KotlinCompleter.java b/kotlin/src/main/java/org/apache/zeppelin/kotlin/completion/KotlinCompleter.java deleted file mode 100644 index 4b3789f412..0000000000 --- a/kotlin/src/main/java/org/apache/zeppelin/kotlin/completion/KotlinCompleter.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.zeppelin.kotlin.completion; - -import static org.apache.zeppelin.kotlin.reflect.KotlinReflectUtil.shorten; -import java.util.ArrayList; -import java.util.List; -import java.util.stream.Collectors; -import org.apache.zeppelin.interpreter.InterpreterContext; -import org.apache.zeppelin.interpreter.thrift.InterpreterCompletion; -import org.apache.zeppelin.kotlin.reflect.KotlinFunctionInfo; -import org.apache.zeppelin.kotlin.reflect.KotlinVariableInfo; -import org.apache.zeppelin.kotlin.repl.KotlinRepl; - -public class KotlinCompleter { - private static final List<InterpreterCompletion> keywords = KotlinKeywords.KEYWORDS.stream() - .map(keyword -> new InterpreterCompletion(keyword, keyword, null)) - .collect(Collectors.toList()); - - private KotlinRepl.KotlinContext ctx; - - public void setCtx(KotlinRepl.KotlinContext ctx) { - this.ctx = ctx; - } - - public List<InterpreterCompletion> completion(String buf, int cursor, - InterpreterContext interpreterContext) { - if (ctx == null) { - return new ArrayList<>(keywords); - } - - List<InterpreterCompletion> result = new ArrayList<>(); - - for (KotlinVariableInfo var : ctx.getVars()) { - result.add(new InterpreterCompletion( - var.getName(), - var.getName(), - shorten(var.getType()) - )); - } - - for (KotlinFunctionInfo fun : ctx.getFunctions()) { - result.add(new InterpreterCompletion( - fun.getName(), - fun.getName(), - fun.toString(true) - )); - } - - result.addAll(keywords); - return result; - } -} diff --git a/kotlin/src/main/java/org/apache/zeppelin/kotlin/completion/KotlinKeywords.java b/kotlin/src/main/java/org/apache/zeppelin/kotlin/completion/KotlinKeywords.java deleted file mode 100644 index 2c75d8cd8f..0000000000 --- a/kotlin/src/main/java/org/apache/zeppelin/kotlin/completion/KotlinKeywords.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.zeppelin.kotlin.completion; - -import java.util.Arrays; -import java.util.List; - -public class KotlinKeywords { - /** - * List of Kotlin keywords for completion. - */ - public static final List<String> KEYWORDS = Arrays.asList( - "as", - "as?", - "break", - "class", - "continue", - "do", - "else", - "false", - "for", - "fun", - "if", - "in", - "interface", - "is", - "null", - "object", - "package", - "return", - "super", - "this", - "throw", - "true", - "try", - "typealias", - "typeof", - "val", - "var", - "when", - "while", - "by", - "catch", - "constructor", - "delegate", - "dynamic", - "field", - "file", - "finally", - "get", - "import", - "init", - "param", - "property", - "receiver", - "set", - "setparam", - "where", - "actual", - "abstract", - "annotation", - "companion", - "const", - "crossinline", - "data", - "enum", - "expect", - "external", - "final", - "infix", - "inline", - "inner", - "internal", - "lateinit", - "noinline", - "open", - "operator", - "out", - "override", - "private", - "protected", - "public", - "reified", - "sealed", - "suspend", - "tailrec", - "vararg" - ); -} diff --git a/kotlin/src/main/java/org/apache/zeppelin/kotlin/context/KotlinReceiver.java b/kotlin/src/main/java/org/apache/zeppelin/kotlin/context/KotlinReceiver.java deleted file mode 100644 index 2b5ac8fccd..0000000000 --- a/kotlin/src/main/java/org/apache/zeppelin/kotlin/context/KotlinReceiver.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.zeppelin.kotlin.context; - -import org.apache.zeppelin.kotlin.repl.KotlinRepl; - -/** - * The implicit receiver for lines in Kotlin REPL. - * It is passed to the script as an implicit receiver, identical to: - * with (context) { - * ... - * } - * - * KotlinReceiver can be inherited from and passed to REPL building properties, - * so other variables and functions can be accessed inside REPL. - * By default, it only has KotlinContext. - * Inherited KotlinReceivers should be in separate java file, they can't be inner or nested. - */ -public class KotlinReceiver { - public KotlinRepl.KotlinContext kc; -} - diff --git a/kotlin/src/main/java/org/apache/zeppelin/kotlin/reflect/ContextUpdater.java b/kotlin/src/main/java/org/apache/zeppelin/kotlin/reflect/ContextUpdater.java deleted file mode 100644 index 33c81d61ca..0000000000 --- a/kotlin/src/main/java/org/apache/zeppelin/kotlin/reflect/ContextUpdater.java +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.zeppelin.kotlin.reflect; - -import org.jetbrains.kotlin.cli.common.repl.AggregatedReplStageState; -import org.jetbrains.kotlin.cli.common.repl.ReplHistoryRecord; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.stream.Collectors; -import kotlin.Pair; -import kotlin.reflect.KFunction; -import kotlin.reflect.KProperty; -import kotlin.reflect.jvm.ReflectJvmMapping; - -/** - * ContextUpdater updates current user-defined functions and variables - * to use in completion and KotlinContext. - */ -public class ContextUpdater { - private static final Logger logger = LoggerFactory.getLogger(ContextUpdater.class); - private static final Set<Method> objectMethods = - new HashSet<>(Arrays.asList(Object.class.getMethods())); - - private AggregatedReplStageState<?, ?> state; - private Map<String, KotlinVariableInfo> vars; - private Set<KotlinFunctionInfo> functions; - - public ContextUpdater(AggregatedReplStageState<?, ?> state, - Map<String, KotlinVariableInfo> vars, - Set<KotlinFunctionInfo> functions) { - this.state = state; - this.vars = vars; - this.functions = functions; - } - - public void update() { - try { - List<Object> lines = getLines(); - refreshVariables(lines); - refreshMethods(lines); - } catch (ReflectiveOperationException | NullPointerException e) { - logger.error("Exception updating current variables", e); - } - } - - private void refreshMethods(List<Object> lines) { - functions.clear(); - for (Object line : lines) { - Method[] methods = line.getClass().getMethods(); - for (Method method : methods) { - if (objectMethods.contains(method) || method.getName().equals("main")) { - continue; - } - KFunction<?> function = ReflectJvmMapping.getKotlinFunction(method); - if (function == null) { - continue; - } - functions.add(new KotlinFunctionInfo(function)); - } - } - } - - private List<Object> getLines() { - List<Object> lines = state.getHistory().stream() - .map(this::getLineFromRecord) - .collect(Collectors.toList()); - - Collections.reverse(lines); - return lines; - } - - /* - ReplHistoryRecord class holds a pair of line ID and a compiled Line_N class. - This Line class is generated by Kotlin REPL compiler, its base class is Object - and it contains the functions and variables declared in the paragraph as its - methods and fields. For example, line "val i = 1" can be compiled to Line_0.class - with field "public final int i" set to 1. - Note that when a new value is reassigned to variable in a separate paragraph, - REPL compiler does not change the value in a previously created field, - instead it creates a field with the same name in the new Line_(N+1) class. - */ - private Object getLineFromRecord(ReplHistoryRecord<? extends Pair<?, ?>> record) { - Object statePair = record.getItem().getSecond(); - return ((Pair<?, ?>) statePair).getSecond(); - } - - private Object getImplicitReceiver(Object script) - throws ReflectiveOperationException { - Field receiverField = script.getClass().getDeclaredField("$$implicitReceiver0"); - return receiverField.get(script); - } - - private void refreshVariables(List<Object> lines) throws ReflectiveOperationException { - vars.clear(); - if (!lines.isEmpty()) { - Object receiver = getImplicitReceiver(lines.get(0)); - findReceiverVariables(receiver); - } - for (Object line : lines) { - findLineVariables(line); - } - } - - // For lines, we only want fields from top level class - private void findLineVariables(Object line) throws IllegalAccessException { - Field[] fields = line.getClass().getDeclaredFields(); - findVariables(fields, line); - } - - // For implicit receiver, we want to also get fields in parent classes - private void findReceiverVariables(Object receiver) throws IllegalAccessException { - List<Field> fieldsList = new ArrayList<>(); - for (Class<?> cl = receiver.getClass(); cl != null; cl = cl.getSuperclass()) { - fieldsList.addAll(Arrays.asList(cl.getDeclaredFields())); - } - findVariables(fieldsList.toArray(new Field[0]), receiver); - } - - private void findVariables(Field[] fields, Object o) throws IllegalAccessException { - for (Field field : fields) { - String fieldName = field.getName(); - if (fieldName.contains("$$implicitReceiver")) { - continue; - } - - field.setAccessible(true); - Object value = field.get(o); - if (!fieldName.contains("script$")) { - KProperty<?> descriptor = ReflectJvmMapping.getKotlinProperty(field); - if (descriptor != null) { - vars.putIfAbsent(fieldName, new KotlinVariableInfo(value, descriptor)); - } - } - } - } -} diff --git a/kotlin/src/main/java/org/apache/zeppelin/kotlin/reflect/KotlinFunctionInfo.java b/kotlin/src/main/java/org/apache/zeppelin/kotlin/reflect/KotlinFunctionInfo.java deleted file mode 100644 index c4c4579728..0000000000 --- a/kotlin/src/main/java/org/apache/zeppelin/kotlin/reflect/KotlinFunctionInfo.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.zeppelin.kotlin.reflect; - -import static org.apache.zeppelin.kotlin.reflect.KotlinReflectUtil.functionSignature; -import static org.apache.zeppelin.kotlin.reflect.KotlinReflectUtil.shorten; -import org.jetbrains.annotations.NotNull; -import kotlin.reflect.KFunction; - -public class KotlinFunctionInfo implements Comparable<KotlinFunctionInfo> { - private final KFunction<?> function; - - public KotlinFunctionInfo(KFunction<?> function) { - this.function = function; - } - - public KFunction<?> getFunction() { - return function; - } - - public String getName() { - return function.getName(); - } - - public String toString(boolean shortenTypes) { - if (shortenTypes) { - return shorten(toString()); - } - return toString(); - } - - @Override - public String toString() { - return functionSignature(function); - } - - @Override - public int compareTo(@NotNull KotlinFunctionInfo f) { - return this.toString().compareTo(f.toString()); - } - - @Override - public int hashCode() { - return this.toString().hashCode(); - } - - @Override - public boolean equals(Object obj) { - if (obj instanceof KotlinFunctionInfo) { - return this.toString().equals(obj.toString()); - } - return false; - } -} diff --git a/kotlin/src/main/java/org/apache/zeppelin/kotlin/reflect/KotlinReflectUtil.java b/kotlin/src/main/java/org/apache/zeppelin/kotlin/reflect/KotlinReflectUtil.java deleted file mode 100644 index 9a3d283770..0000000000 --- a/kotlin/src/main/java/org/apache/zeppelin/kotlin/reflect/KotlinReflectUtil.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.zeppelin.kotlin.reflect; - -import kotlin.reflect.KFunction; - -/** - * Util class for pretty-printing Kotlin variables and functions. - */ -public class KotlinReflectUtil { - public static String functionSignature(KFunction<?> function) { - return function.toString().replaceAll("Line_\\d+\\.", ""); - } - - public static String shorten(String name) { - if (name == null) { - return null; - } - // kotlin.collections.List<kotlin.Int> -> List<Int> - return name.replaceAll("(\\b[_a-zA-Z$][_a-zA-Z0-9$]*\\b\\.)+", ""); - } -} diff --git a/kotlin/src/main/java/org/apache/zeppelin/kotlin/reflect/KotlinVariableInfo.java b/kotlin/src/main/java/org/apache/zeppelin/kotlin/reflect/KotlinVariableInfo.java deleted file mode 100644 index a90dacc664..0000000000 --- a/kotlin/src/main/java/org/apache/zeppelin/kotlin/reflect/KotlinVariableInfo.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.zeppelin.kotlin.reflect; - -import static org.apache.zeppelin.kotlin.reflect.KotlinReflectUtil.shorten; -import kotlin.reflect.KProperty; - -public class KotlinVariableInfo { - private final Object value; - private final KProperty<?> descriptor; - - public KotlinVariableInfo(Object value, KProperty<?> descriptor) { - this.value = value; - this.descriptor = descriptor; - } - - public Object getValue() { - return value; - } - - public KProperty<?> getDescriptor() { - return descriptor; - } - - public String getName() { - return descriptor.getName(); - } - - public String getType() { - return descriptor.getReturnType().toString(); - } - - public String toString(boolean shortenTypes) { - String type = getType(); - if (shortenTypes) { - type = shorten(type); - } - return getName() + ": " + type + " = " + getValue(); - } - - @Override - public String toString() { - return toString(false); - } -} diff --git a/kotlin/src/main/java/org/apache/zeppelin/kotlin/repl/ClassWriter.java b/kotlin/src/main/java/org/apache/zeppelin/kotlin/repl/ClassWriter.java deleted file mode 100644 index e7de34c7fb..0000000000 --- a/kotlin/src/main/java/org/apache/zeppelin/kotlin/repl/ClassWriter.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.zeppelin.kotlin.repl; - -import org.jetbrains.kotlin.cli.common.repl.CompiledClassData; -import org.jetbrains.kotlin.cli.common.repl.ReplCompileResult; -import org.jetbrains.kotlin.scripting.compiler.plugin.impl.KJvmCompiledModuleInMemory; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import java.io.BufferedOutputStream; -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.util.Objects; -import kotlin.script.experimental.jvm.impl.KJvmCompiledScript; - -/** - * Kotlin REPL compiler generates compiled classes consisting of - * compiled in-memory module and some other classes. - * Spark may need saving them somewhere to send them to the executors, - * so this class provides writing classes on disk. - */ -public class ClassWriter { - private static Logger logger = LoggerFactory.getLogger(ClassWriter.class); - - private String outputDir; - - public ClassWriter(String outputDir) { - this.outputDir = outputDir; - } - - public void writeClasses(ReplCompileResult.CompiledClasses classes) { - if (outputDir == null) { - return; - } - - for (CompiledClassData compiledClass: classes.getClasses()) { - String filePath = compiledClass.getPath(); - if (!filePath.contains(File.separator)) { - String classWritePath = outputDir + File.separator + filePath; - writeClass(compiledClass.getBytes(), classWritePath); - } - } - - writeModuleInMemory(classes); - } - - private void writeModuleInMemory(ReplCompileResult.CompiledClasses classes) { - try { - KJvmCompiledScript<?> compiledScript = Objects.requireNonNull( - (KJvmCompiledScript<?>) classes.getData()); - - KJvmCompiledModuleInMemory moduleInMemory = Objects.requireNonNull( - (KJvmCompiledModuleInMemory) compiledScript.getCompiledModule()); - - moduleInMemory.getCompilerOutputFiles().forEach((name, bytes) -> { - if (name.contains("class")) { - writeClass(bytes, outputDir + File.separator + name); - } - }); - } catch (ClassCastException | NullPointerException e) { - logger.info("Compiled line #" + classes.getLineId().getNo() + "has no in-memory modules"); - } - } - - private void writeClass(byte[] classBytes, String path) { - try (FileOutputStream fos = new FileOutputStream(path); - OutputStream out = new BufferedOutputStream(fos)) { - out.write(classBytes); - out.flush(); - } catch (IOException e) { - logger.error(e.getMessage()); - } - } -} diff --git a/kotlin/src/main/java/org/apache/zeppelin/kotlin/repl/KotlinRepl.java b/kotlin/src/main/java/org/apache/zeppelin/kotlin/repl/KotlinRepl.java deleted file mode 100644 index 38fdba39b8..0000000000 --- a/kotlin/src/main/java/org/apache/zeppelin/kotlin/repl/KotlinRepl.java +++ /dev/null @@ -1,272 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.zeppelin.kotlin.repl; - -import static org.apache.zeppelin.kotlin.reflect.KotlinReflectUtil.shorten; -import org.jetbrains.kotlin.cli.common.repl.AggregatedReplStageState; -import org.jetbrains.kotlin.cli.common.repl.InvokeWrapper; -import org.jetbrains.kotlin.cli.common.repl.ReplCodeLine; -import org.jetbrains.kotlin.cli.common.repl.ReplCompileResult; -import org.jetbrains.kotlin.cli.common.repl.ReplEvalResult; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Set; -import java.util.TreeSet; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.locks.ReentrantReadWriteLock; -import java.util.stream.Collectors; -import kotlin.jvm.functions.Function0; -import kotlin.script.experimental.jvmhost.repl.JvmReplCompiler; -import kotlin.script.experimental.jvmhost.repl.JvmReplEvaluator; -import org.apache.zeppelin.interpreter.InterpreterResult; -import org.apache.zeppelin.kotlin.reflect.ContextUpdater; -import org.apache.zeppelin.kotlin.reflect.KotlinFunctionInfo; -import org.apache.zeppelin.kotlin.reflect.KotlinVariableInfo; -import org.apache.zeppelin.kotlin.repl.building.KotlinReplProperties; -import org.apache.zeppelin.kotlin.repl.building.ReplBuilding; - -/** - * Read-evaluate-print loop for Kotlin code. - * Each code snippet is compiled into Line_N class and evaluated. - * - * Outside variables and functions can be bound to REPL - * by inheriting KotlinReceiver class and passing it to REPL properties on creation. - * After that, all fields and methods of receiver are seen inside the snippet scope - * as if the code was run in Kotlin's `with` block. - * - * By default, KotlinReceiver has KotlinContext bound by the name `kc`. - * It can be used to show user-defined variables and functions - * and setting invokeWrapper to add effects to snippet evaluation. - */ -public class KotlinRepl { - private static Logger logger = LoggerFactory.getLogger(KotlinRepl.class); - - private JvmReplCompiler compiler; - private JvmReplEvaluator evaluator; - private AggregatedReplStageState<?, ?> state; - private AtomicInteger counter; - private ClassWriter writer; - private KotlinContext ctx; - private InvokeWrapper wrapper; - private int maxResult; - private ContextUpdater contextUpdater; - boolean shortenTypes; - - private KotlinRepl() { } - - @SuppressWarnings("unchecked") - public KotlinRepl(KotlinReplProperties properties) { - compiler = ReplBuilding.buildCompiler(properties); - evaluator = ReplBuilding.buildEvaluator(properties); - ReentrantReadWriteLock stateLock = new ReentrantReadWriteLock(); - state = new AggregatedReplStageState( - compiler.createState(stateLock), - evaluator.createState(stateLock), - stateLock); - counter = new AtomicInteger(0); - - writer = new ClassWriter(properties.getOutputDir()); - maxResult = properties.getMaxResult(); - shortenTypes = properties.getShortenTypes(); - - ctx = new KotlinContext(); - properties.getReceiver().kc = ctx; - - contextUpdater = new ContextUpdater( - state, ctx.vars, ctx.functions); - - for (String line: properties.getCodeOnLoad()) { - eval(line); - } - } - - public List<KotlinVariableInfo> getVariables() { - return ctx.getVars(); - } - - public List<KotlinFunctionInfo> getFunctions() { - return ctx.getFunctions(); - } - - public KotlinContext getKotlinContext() { - return ctx; - } - - /** - * Evaluates code snippet and returns interpreter result. - * REPL evaluation consists of: - * - Compiling code in JvmReplCompiler - * - Writing compiled classes to disk - * - Evaluating compiled classes inside InvokeWrapper - * - Updating list of user-defined functions and variables - * - Formatting result - * @param code Kotlin code to execute - * @return result of interpretation - */ - public InterpreterResult eval(String code) { - ReplCompileResult compileResult = compiler.compile(state, - new ReplCodeLine(counter.getAndIncrement(), 0, code)); - - Optional<InterpreterResult> compileError = checkCompileError(compileResult); - if (compileError.isPresent()) { - return compileError.get(); - } - - ReplCompileResult.CompiledClasses classes = - (ReplCompileResult.CompiledClasses) compileResult; - writer.writeClasses(classes); - - ReplEvalResult evalResult = evalInWrapper(classes); - - Optional<InterpreterResult> evalError = checkEvalError(evalResult); - if (evalError.isPresent()) { - return evalError.get(); - } - - contextUpdater.update(); - - if (evalResult instanceof ReplEvalResult.UnitResult) { - return new InterpreterResult(InterpreterResult.Code.SUCCESS); - } - if (evalResult instanceof ReplEvalResult.ValueResult) { - ReplEvalResult.ValueResult v = (ReplEvalResult.ValueResult) evalResult; - String typeString = shortenTypes ? shorten(v.getType()) : v.getType(); - String valueString = prepareValueString(v.getValue()); - - return new InterpreterResult( - InterpreterResult.Code.SUCCESS, - v.getName() + ": " + typeString + " = " + valueString); - } - return new InterpreterResult(InterpreterResult.Code.ERROR, - "unknown evaluation result: " + evalResult.toString()); - } - - private ReplEvalResult evalInWrapper(ReplCompileResult.CompiledClasses classes) { - ReplEvalResult evalResult; - // For now, invokeWrapper parameter in evaluator.eval does not work, so wrapping happens here - Function0<ReplEvalResult> runEvaluator = () -> evaluator.eval(state, classes, null, null); - if (wrapper != null) { - evalResult = wrapper.invoke(runEvaluator); - } else { - evalResult = runEvaluator.invoke(); - } - return evalResult; - } - - private Optional<InterpreterResult> checkCompileError(ReplCompileResult compileResult) { - if (compileResult instanceof ReplCompileResult.Incomplete) { - return Optional.of(new InterpreterResult(InterpreterResult.Code.INCOMPLETE)); - } - - if (compileResult instanceof ReplCompileResult.Error) { - ReplCompileResult.Error e = (ReplCompileResult.Error) compileResult; - return Optional.of(new InterpreterResult(InterpreterResult.Code.ERROR, e.getMessage())); - } - - if (!(compileResult instanceof ReplCompileResult.CompiledClasses)) { - return Optional.of(new InterpreterResult(InterpreterResult.Code.ERROR, - "unknown compilation result:" + compileResult.toString())); - } - - return Optional.empty(); - } - - private Optional<InterpreterResult> checkEvalError(ReplEvalResult evalResult) { - if (evalResult instanceof ReplEvalResult.Error) { - ReplEvalResult.Error e = (ReplEvalResult.Error) evalResult; - return Optional.of(new InterpreterResult(InterpreterResult.Code.ERROR, e.getMessage())); - } - - if (evalResult instanceof ReplEvalResult.Incomplete) { - return Optional.of(new InterpreterResult(InterpreterResult.Code.INCOMPLETE)); - } - - if (evalResult instanceof ReplEvalResult.HistoryMismatch) { - ReplEvalResult.HistoryMismatch e = (ReplEvalResult.HistoryMismatch) evalResult; - return Optional.of(new InterpreterResult( - InterpreterResult.Code.ERROR, "history mismatch at " + e.getLineNo())); - } - - return Optional.empty(); - } - - private String prepareValueString(Object value) { - if (value == null) { - return "null"; - } - if (!(value instanceof Collection<?>)) { - return value.toString(); - } - - Collection<?> collection = (Collection<?>) value; - - if (collection.size() <= maxResult) { - return value.toString(); - } - - return "[" + collection.stream() - .limit(maxResult) - .map(Object::toString) - .collect(Collectors.joining(",")) - + " ... " + (collection.size() - maxResult) + " more]"; - } - - /** - * Kotlin REPL has built-in context for getting user-declared functions and variables - * and setting invokeWrapper for additional side effects in evaluation. - * It can be accessed inside REPL by name `kc`, e.g. kc.showVars() - */ - public class KotlinContext { - private Map<String, KotlinVariableInfo> vars = new HashMap<>(); - private Set<KotlinFunctionInfo> functions = new TreeSet<>(); - - public List<KotlinVariableInfo> getVars() { - return new ArrayList<>(vars.values()); - } - - public void setWrapper(InvokeWrapper wrapper) { - KotlinRepl.this.wrapper = wrapper; - } - - public InvokeWrapper getWrapper() { - return KotlinRepl.this.wrapper; - } - - public List<KotlinFunctionInfo> getFunctions() { - return new ArrayList<>(functions); - } - - public void showVars() { - for (KotlinVariableInfo var : vars.values()) { - System.out.println(var.toString(shortenTypes)); - } - } - - public void showFunctions() { - for (KotlinFunctionInfo fun : functions) { - System.out.println(fun.toString(shortenTypes)); - } - } - } -} diff --git a/kotlin/src/main/java/org/apache/zeppelin/kotlin/repl/building/KotlinReplProperties.java b/kotlin/src/main/java/org/apache/zeppelin/kotlin/repl/building/KotlinReplProperties.java deleted file mode 100644 index a3e1b74189..0000000000 --- a/kotlin/src/main/java/org/apache/zeppelin/kotlin/repl/building/KotlinReplProperties.java +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.zeppelin.kotlin.repl.building; - -import static kotlin.script.experimental.jvm.JvmScriptingHostConfigurationKt.getDefaultJvmScriptingHostConfiguration; -import java.io.File; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import kotlin.script.experimental.host.ScriptingHostConfiguration; -import org.apache.zeppelin.kotlin.context.KotlinReceiver; - -/** - * Class that holds properties for Kotlin REPL creation, - * namely implicit receiver, classpath, preloaded code, directory for class bytecode output, - * max result limit and shortening types flag. - * - * Set its parameters by chaining corresponding methods, e.g. - * properties.outputDir(dir).shortenTypes(false) - * - * Get its parameters via getters. - */ -public class KotlinReplProperties { - - private ScriptingHostConfiguration hostConf = getDefaultJvmScriptingHostConfiguration(); - - private KotlinReceiver receiver; - private Set<String> classpath; - private List<String> codeOnLoad; - private String outputDir; - private int maxResult = 1000; - private boolean shortenTypes = true; - - public KotlinReplProperties() { - this.receiver = new KotlinReceiver(); - - this.classpath = new HashSet<>(); - String[] javaClasspath = System.getProperty("java.class.path").split(File.pathSeparator); - Collections.addAll(classpath, javaClasspath); - - this.codeOnLoad = new ArrayList<>(); - } - - public KotlinReplProperties receiver(KotlinReceiver receiver) { - this.receiver = receiver; - return this; - } - - public KotlinReplProperties classPath(String path) { - this.classpath.add(path); - return this; - } - - public KotlinReplProperties classPath(Collection<String> paths) { - this.classpath.addAll(paths); - return this; - } - - public KotlinReplProperties codeOnLoad(String code) { - this.codeOnLoad.add(code); - return this; - } - - public KotlinReplProperties codeOnLoad(Collection<String> code) { - this.codeOnLoad.addAll(code); - return this; - } - - public KotlinReplProperties outputDir(String outputDir) { - this.outputDir = outputDir; - return this; - } - - public KotlinReplProperties maxResult(int maxResult) { - this.maxResult = maxResult; - return this; - } - - public KotlinReplProperties shortenTypes(boolean shortenTypes) { - this.shortenTypes = shortenTypes; - return this; - } - - public ScriptingHostConfiguration getHostConf() { - return hostConf; - } - - public KotlinReceiver getReceiver() { - return receiver; - } - - public Set<String> getClasspath() { - return classpath; - } - - public List<String> getCodeOnLoad() { - return codeOnLoad; - } - - public String getOutputDir() { - return outputDir; - } - - public int getMaxResult() { - return maxResult; - } - - public boolean getShortenTypes() { - return shortenTypes; - } -} diff --git a/kotlin/src/main/java/org/apache/zeppelin/kotlin/repl/building/ReplBuilding.java b/kotlin/src/main/java/org/apache/zeppelin/kotlin/repl/building/ReplBuilding.java deleted file mode 100644 index af50a7dcd7..0000000000 --- a/kotlin/src/main/java/org/apache/zeppelin/kotlin/repl/building/ReplBuilding.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.zeppelin.kotlin.repl.building; - -import org.jetbrains.kotlin.scripting.compiler.plugin.impl.KJvmReplCompilerImpl; -import java.io.File; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.StringJoiner; -import kotlin.Unit; -import kotlin.script.experimental.api.KotlinType; -import kotlin.script.experimental.api.ScriptCompilationConfiguration; -import kotlin.script.experimental.api.ScriptCompilationKt; -import kotlin.script.experimental.api.ScriptEvaluationConfiguration; -import kotlin.script.experimental.api.ScriptEvaluationKt; -import kotlin.script.experimental.jvm.BasicJvmScriptEvaluator; -import kotlin.script.experimental.jvm.JvmScriptCompilationConfigurationBuilder; -import kotlin.script.experimental.jvm.JvmScriptCompilationKt; -import kotlin.script.experimental.jvmhost.impl.JvmHostUtilKt; -import kotlin.script.experimental.jvmhost.repl.JvmReplCompiler; -import kotlin.script.experimental.jvmhost.repl.JvmReplEvaluator; - -/** - * Util class for building REPL components. - */ -public class ReplBuilding { - public static JvmReplCompiler buildCompiler(KotlinReplProperties properties) { - String receiverClassPath = properties.getReceiver().getClass() - .getProtectionDomain().getCodeSource().getLocation().getPath(); - properties.classPath(receiverClassPath); - - KJvmReplCompilerImpl compilerImpl = - new KJvmReplCompilerImpl(JvmHostUtilKt.withDefaults(properties.getHostConf())); - - return new JvmReplCompiler( - buildCompilationConfiguration(properties), - properties.getHostConf(), - compilerImpl); - } - - public static JvmReplEvaluator buildEvaluator(KotlinReplProperties properties) { - return new JvmReplEvaluator( - buildEvaluationConfiguration(properties), - new BasicJvmScriptEvaluator()); - } - - private static String buildClassPath(KotlinReplProperties p) { - StringJoiner joiner = new StringJoiner(File.pathSeparator); - for (String path : p.getClasspath()) { - if (path != null && !path.equals("")) { - joiner.add(path); - } - } - return joiner.toString(); - } - - private static ScriptCompilationConfiguration buildCompilationConfiguration( - KotlinReplProperties p) { - return new ScriptCompilationConfiguration((b) -> { - b.invoke(ScriptCompilationKt.getHostConfiguration(b), p.getHostConf()); - - JvmScriptCompilationConfigurationBuilder jvmBuilder = - JvmScriptCompilationKt.getJvm(b); - JvmScriptCompilationKt.dependenciesFromCurrentContext( - jvmBuilder, new String[0], true, false); - - List<String> compilerOptions = Arrays.asList("-classpath", buildClassPath(p)); - - b.invoke(ScriptCompilationKt.getCompilerOptions(b), compilerOptions); - - KotlinType kt = new KotlinType(p.getReceiver().getClass().getCanonicalName()); - List<KotlinType> receivers = - Collections.singletonList(kt); - b.invoke(ScriptCompilationKt.getImplicitReceivers(b), receivers); - - return Unit.INSTANCE; - }); - } - - private static ScriptEvaluationConfiguration buildEvaluationConfiguration( - KotlinReplProperties p) { - return new ScriptEvaluationConfiguration((b) -> { - b.invoke(ScriptEvaluationKt.getHostConfiguration(b), p.getHostConf()); - - List<Object> receivers = - Collections.singletonList(p.getReceiver()); - b.invoke(ScriptEvaluationKt.getImplicitReceivers(b), receivers); - - return Unit.INSTANCE; - }); - } -} diff --git a/kotlin/src/main/resources/interpreter-setting.json b/kotlin/src/main/resources/interpreter-setting.json deleted file mode 100644 index 1277b597f7..0000000000 --- a/kotlin/src/main/resources/interpreter-setting.json +++ /dev/null @@ -1,28 +0,0 @@ -[ - { - "group": "kotlin", - "name": "kotlin", - "className": "org.apache.zeppelin.kotlin.KotlinInterpreter", - "defaultInterpreter": true, - "properties": { - "zeppelin.kotlin.maxResult": { - "envName": null, - "propertyName": "zeppelin.kotlin.maxResult", - "defaultValue": "1000", - "description": "Max number of dataframe rows to display.", - "type": "number" - }, - "zeppelin.kotlin.shortenTypes": { - "envName": null, - "propertyName": "zeppelin.kotlin.shortenTypes", - "defaultValue": true, - "description": "Show short types instead of full, e.g. List<String> or kotlin.collections.List<kotlin.String>", - "type": "checkbox" - } - }, - "editor": { - "language": "kotlin", - "editOnDblClick": false - } - } -] diff --git a/kotlin/src/test/java/org/apache/zeppelin/kotlin/KotlinInterpreterTest.java b/kotlin/src/test/java/org/apache/zeppelin/kotlin/KotlinInterpreterTest.java deleted file mode 100644 index 69a0d32199..0000000000 --- a/kotlin/src/test/java/org/apache/zeppelin/kotlin/KotlinInterpreterTest.java +++ /dev/null @@ -1,329 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.zeppelin.kotlin; - -import static org.apache.zeppelin.interpreter.InterpreterResult.Code.ERROR; -import static org.apache.zeppelin.interpreter.InterpreterResult.Code.SUCCESS; -import static org.apache.zeppelin.kotlin.reflect.KotlinReflectUtil.shorten; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.jupiter.api.Assertions.fail; - -import java.io.File; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.Arrays; -import java.util.List; -import java.util.Properties; -import java.util.stream.Collectors; -import org.apache.zeppelin.interpreter.InterpreterContext; -import org.apache.zeppelin.interpreter.InterpreterException; -import org.apache.zeppelin.interpreter.InterpreterOutput; -import org.apache.zeppelin.interpreter.InterpreterOutputListener; -import org.apache.zeppelin.interpreter.InterpreterResult; -import org.apache.zeppelin.interpreter.InterpreterResultMessageOutput; -import org.apache.zeppelin.interpreter.thrift.InterpreterCompletion; -import org.apache.zeppelin.kotlin.reflect.KotlinFunctionInfo; -import org.apache.zeppelin.kotlin.reflect.KotlinVariableInfo; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - - -class KotlinInterpreterTest { - - private static KotlinInterpreter interpreter; - private static InterpreterContext context; - - private static volatile String output = ""; - - public void prepareInterpreter() { - prepareInterpreter(new Properties()); - } - - public void prepareInterpreter(Properties properties) { - context = getInterpreterContext(); - interpreter = new KotlinInterpreter(properties); - output = ""; - } - - @BeforeEach - public void setUp() throws InterpreterException { - prepareInterpreter(); - interpreter.open(); - } - - @AfterEach - public void tearDown() { - interpreter.close(); - } - - private static void testCodeForResult(String code, String expected) throws Exception { - InterpreterResult result = interpreter.interpret(code, context); - - String value; - if (result.message().isEmpty()) { - value = ""; - } else { - String message = result.message().get(0).getData().trim(); - // "res0 : kotlin.Int = 1" -> "kotlin.Int = 1" - value = message.substring(message.indexOf(':') + 2); - } - - assertEquals(SUCCESS, result.code()); - assertEquals(expected, value); - } - - @Test - void testLiteral() throws Exception { - testCodeForResult("1", "Int = 1"); - } - - @Test - void testOperation() throws Exception { - testCodeForResult("\"foo\" + \"bar\"", "String = foobar"); - } - - @Test - void testFunction() throws Exception { - testCodeForResult( - "fun square(x: Int): Int = x * x\nsquare(10)", - "Int = 100"); - } - - @Test - void testIncomplete() throws Exception { - InterpreterResult result = interpreter.interpret("val x =", context); - assertEquals(ERROR, result.code()); - } - - @Test - void testCompileError() throws Exception { - InterpreterResult result = interpreter.interpret("prinln(1)", context); - assertEquals(ERROR, result.code()); - assertEquals("Unresolved reference: prinln", result.message().get(0).getData().trim()); - } - - @Test - void testOutput() throws Exception { - testCodeForResult("println(\"Hello Kotlin\")", ""); - assertEquals("Hello Kotlin\n", output); - } - - @Test - void testRuntimeError() throws Exception { - InterpreterResult result = interpreter.interpret( - "throw RuntimeException(\"Error Message\")", context); - assertEquals(ERROR, result.code()); - assertEquals("Error Message", result.message().get(0).getData().trim()); - } - - @Test - void testCancel() throws Exception { - Thread t = new Thread(() -> { - try { - InterpreterResult result = interpreter.interpret( - "repeat(10000000) { Thread.sleep(100) }", context); - assertEquals(ERROR, result.code()); - assertEquals("sleep interrupted", result.message().get(0).getData().trim()); - } catch (InterpreterException e) { - fail(e.getMessage()); - } - }); - t.start(); - Thread.sleep(200); - interpreter.cancel(context); - } - - @Test - void testVariables() throws Exception { - interpreter.interpret("val x = 1", context); - interpreter.interpret("val x = 2", context); - List<KotlinVariableInfo> vars = interpreter.getVariables(); - assertEquals(2, vars.size()); - - KotlinVariableInfo varX = vars.stream() - .filter(info -> info.getName().equals("x")) - .findFirst() - .orElseGet( () -> { - fail(); - return null; - }); - - assertEquals(2, varX.getValue()); - assertEquals("kotlin.Int", varX.getType()); - } - - @Test - void testGetVariablesFromCode() throws Exception { - interpreter.interpret("val x = 1", context); - interpreter.interpret("val y = 2", context); - interpreter.interpret("val x = 3", context); - interpreter.interpret("val l = listOf(1,2,3)", context); - interpreter.interpret("kc.showVars()", context); - assertTrue(output.contains("x: Int = 3"), output); - assertTrue(output.contains("y: Int = 2"), output); - assertTrue(output.contains("l: List<Int> = [1, 2, 3]"), output); - InterpreterResult res = interpreter.interpret("kc.vars = null", context); - assertTrue(res.message().get(0).getData().contains("Val cannot be reassigned")); - } - - @Test - void testFunctionsAsValues() throws Exception { - InterpreterResult res = interpreter.interpret("val f = { x: Int -> x + 1 }", context); - assertEquals(SUCCESS, res.code()); - assertNotNull(interpreter.getVariables()); - } - - @Test - void testMethods() throws Exception { - interpreter.interpret("fun sq(x: Int): Int = x * x", context); - interpreter.interpret("fun sq(x: Int): Int = x * x", context); - assertEquals(1, interpreter.getFunctions().size()); - - interpreter.interpret("fun <T> singletonListOf(elem: T): List<T> = listOf(elem)", context); - List<String> signatures = interpreter.getFunctions().stream() - .map(KotlinFunctionInfo::toString).collect(Collectors.toList()); - assertTrue( - signatures.stream() - .anyMatch(signature -> signature.equals("fun sq(kotlin.Int): kotlin.Int")), - signatures.toString()); - assertTrue( - signatures.stream() - .anyMatch(signature -> signature - .equals("fun singletonListOf(T): kotlin.collections.List<T>")), - signatures.toString()); - } - - @Test - void testCompletion() throws Exception { - interpreter.interpret("val x = 1", context); - interpreter.interpret("fun inc(n: Int): Int = n + 1", context); - List<InterpreterCompletion> completions = interpreter.completion("", 0, context); - assertTrue(completions.stream().anyMatch(c -> c.name.equals("x"))); - assertTrue(completions.stream().anyMatch(c -> c.name.equals("inc"))); - } - - @Test - void testOutputClasses() throws Exception { - prepareInterpreter(); - Path tempPath = Files.createTempDirectory("tempKotlinClasses"); - interpreter.getKotlinReplProperties().outputDir(tempPath.toAbsolutePath().toString()); - interpreter.open(); - interpreter.interpret("val x = 1\nx", context); - File[] dir = tempPath.toFile().listFiles(); - assertNotNull(dir); - assertTrue(dir.length > 0); - assertTrue(Arrays.stream(dir) - .anyMatch(file -> file.getName().matches("Line_\\d+\\.class")), tempPath.toString()); - int oldLength = dir.length; - interpreter.interpret("x + 1", context); - dir = tempPath.toFile().listFiles(); - assertNotNull(dir); - assertTrue(dir.length > oldLength); - } - - @Test - void testWrapper() throws Exception { - String code = "import org.jetbrains.kotlin.cli.common.repl.InvokeWrapper\n" + - "var k = 0\n" + - "val wrapper = object : InvokeWrapper {\n" + - " override operator fun <T> invoke(body: () -> T): T {\n" + - " println(\"START\")\n" + - " val result = body()\n" + - " println(\"END\")\n" + - " k = k + 1\n" + - " return result\n" + - " }\n" + - "}\n" + - "kc.setWrapper(wrapper)\n"; - interpreter.interpret(code, context); - interpreter.interpret("println(\"hello!\")", context); - List<KotlinVariableInfo> vars = interpreter.getVariables(); - for (KotlinVariableInfo v: vars) { - if (v.getName().equals("k")) { - assertEquals(1, v.getValue()); - } - } - - InterpreterResult result = interpreter.interpret("kc.vars", context); - assertTrue(result.message().get(0).getData().contains("k: kotlin.Int = 1")); - } - - @Test - void testReflectUtil() throws Exception { - String message = interpreter.interpret("1", context) - .message().get(0).getData(); - assertTrue(shorten(message).contains("Int = 1")); - - interpreter.interpret("val f = { l: List<Int> -> l[0] }", context); - message = interpreter.interpret("f", context) - .message().get(0).getData(); - assertTrue(shorten(message).contains("(List<Int>) -> Int")); - - interpreter.interpret("fun first(s: String): Char = s[0]", context); - KotlinFunctionInfo first = interpreter.getFunctions().get(0); - assertEquals("fun first(String): Char", first.toString(true)); - } - - @Test - void fullTypeNamesTest() throws Exception { - prepareInterpreter(); - interpreter.getKotlinReplProperties().shortenTypes(false); - interpreter.open(); - - interpreter.interpret("val s = \"abc\"", context); - interpreter.interpret("fun f(l: List<String>) { }", context); - interpreter.interpret("kc.showFunctions()", context); - assertEquals("fun f(kotlin.collections.List<kotlin.String>): kotlin.Unit\n", output); - output = ""; - interpreter.interpret("kc.showVars()", context); - assertTrue(output.contains("s: kotlin.String = abc"), output); - } - - private static InterpreterContext getInterpreterContext() { - output = ""; - InterpreterContext context = InterpreterContext.builder() - .setInterpreterOut(new InterpreterOutput()) - .build(); - context.out = new InterpreterOutput( - new InterpreterOutputListener() { - @Override - public void onUpdateAll(InterpreterOutput out) { - - } - - @Override - public void onAppend(int index, InterpreterResultMessageOutput out, byte[] line) { - try { - output = out.toInterpreterResultMessage().getData(); - } catch (IOException e) { - e.printStackTrace(); - } - } - - @Override - public void onUpdate(int index, InterpreterResultMessageOutput out) { - - } - }); - return context; - } -} diff --git a/pom.xml b/pom.xml index d7262b4054..84a190c372 100644 --- a/pom.xml +++ b/pom.xml @@ -61,7 +61,6 @@ <module>rlang</module> <module>zeppelin-jupyter-interpreter</module> <module>zeppelin-jupyter-interpreter-shaded</module> - <module>kotlin</module> <module>groovy</module> <module>spark</module> <module>spark-submit</module> diff --git a/spark/interpreter/pom.xml b/spark/interpreter/pom.xml index 1f7dd99f32..ee8d6a5afa 100644 --- a/spark/interpreter/pom.xml +++ b/spark/interpreter/pom.xml @@ -85,12 +85,6 @@ <version>${project.version}</version> </dependency> - <dependency> - <groupId>org.apache.zeppelin</groupId> - <artifactId>zeppelin-kotlin</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> <groupId>org.apache.zeppelin</groupId> <artifactId>zeppelin-python</artifactId> diff --git a/spark/interpreter/src/main/java/org/apache/zeppelin/spark/AbstractSparkScalaInterpreter.java b/spark/interpreter/src/main/java/org/apache/zeppelin/spark/AbstractSparkScalaInterpreter.java index 4e83c74ceb..78c07c9a9d 100644 --- a/spark/interpreter/src/main/java/org/apache/zeppelin/spark/AbstractSparkScalaInterpreter.java +++ b/spark/interpreter/src/main/java/org/apache/zeppelin/spark/AbstractSparkScalaInterpreter.java @@ -35,7 +35,6 @@ import org.apache.spark.sql.SQLContext; import org.apache.spark.sql.SparkSession; import org.apache.zeppelin.interpreter.*; import org.apache.zeppelin.interpreter.thrift.InterpreterCompletion; -import org.apache.zeppelin.kotlin.KotlinInterpreter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -162,10 +161,6 @@ public abstract class AbstractSparkScalaInterpreter { public abstract InterpreterResult interpret(String st, InterpreterContext context) throws InterpreterException; - public abstract InterpreterResult delegateInterpret(KotlinInterpreter kotlinInterpreter, - String st, - InterpreterContext context) throws InterpreterException; - public abstract List<InterpreterCompletion> completion(String buf, int cursor, InterpreterContext interpreterContext) throws InterpreterException; diff --git a/spark/interpreter/src/main/java/org/apache/zeppelin/spark/KotlinSparkInterpreter.java b/spark/interpreter/src/main/java/org/apache/zeppelin/spark/KotlinSparkInterpreter.java deleted file mode 100644 index 299f70bc3e..0000000000 --- a/spark/interpreter/src/main/java/org/apache/zeppelin/spark/KotlinSparkInterpreter.java +++ /dev/null @@ -1,191 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.zeppelin.spark; - -import org.apache.spark.SparkConf; -import org.apache.spark.api.java.JavaSparkContext; -import org.apache.spark.sql.SQLContext; -import org.apache.spark.util.Utils; -import org.apache.zeppelin.interpreter.Interpreter; -import org.apache.zeppelin.interpreter.InterpreterContext; -import org.apache.zeppelin.interpreter.InterpreterException; -import org.apache.zeppelin.interpreter.InterpreterResult; -import org.apache.zeppelin.interpreter.ZeppelinContext; -import org.apache.zeppelin.interpreter.thrift.InterpreterCompletion; -import org.apache.zeppelin.kotlin.KotlinInterpreter; -import org.apache.zeppelin.spark.kotlin.KotlinZeppelinBindings; -import org.apache.zeppelin.spark.kotlin.SparkKotlinReceiver; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.File; -import java.io.IOException; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.Properties; -import java.util.regex.Pattern; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -import static org.apache.zeppelin.spark.Utils.buildJobDesc; -import static org.apache.zeppelin.spark.Utils.buildJobGroupId; - -public class KotlinSparkInterpreter extends Interpreter { - private static Logger logger = LoggerFactory.getLogger(KotlinSparkInterpreter.class); - private static final SparkVersion KOTLIN_SPARK_SUPPORTED_VERSION = SparkVersion.SPARK_2_4_0; - - private InterpreterResult unsupportedMessage; - private KotlinInterpreter interpreter; - private SparkInterpreter sparkInterpreter; - private ZeppelinContext z; - private JavaSparkContext jsc; - - public KotlinSparkInterpreter(Properties properties) { - super(properties); - logger.debug("Creating KotlinSparkInterpreter"); - interpreter = new KotlinInterpreter(properties); - } - - @Override - public void open() throws InterpreterException { - sparkInterpreter = - getInterpreterInTheSameSessionByClassName(SparkInterpreter.class); - jsc = sparkInterpreter.getJavaSparkContext(); - - SparkVersion sparkVersion = SparkVersion.fromVersionString(jsc.version()); - if (sparkVersion.olderThan(KOTLIN_SPARK_SUPPORTED_VERSION)) { - unsupportedMessage = new InterpreterResult( - InterpreterResult.Code.ERROR, - "Spark version is " + sparkVersion + ", only " + - KOTLIN_SPARK_SUPPORTED_VERSION + " and newer are supported"); - } - - z = sparkInterpreter.getZeppelinContext(); - - // convert Object to SQLContext explicitly, that means Kotlin Spark may not work with Spark 1.x - SparkKotlinReceiver ctx = new SparkKotlinReceiver( - sparkInterpreter.getSparkSession(), - jsc, - (SQLContext) sparkInterpreter.getSQLContext(), - z); - - List<String> classpath = sparkClasspath(); - - String outputDir = null; - SparkConf conf = jsc.getConf(); - if (conf != null) { - outputDir = conf.getOption("spark.repl.class.outputDir").getOrElse(null); - } - - interpreter.getKotlinReplProperties() - .receiver(ctx) - .classPath(classpath) - .outputDir(outputDir) - .codeOnLoad(KotlinZeppelinBindings.Z_SELECT_KOTLIN_SYNTAX) - .codeOnLoad(KotlinZeppelinBindings.SPARK_UDF_IMPORTS) - .codeOnLoad(KotlinZeppelinBindings.CAST_SPARK_SESSION); - interpreter.open(); - } - - @Override - public void close() throws InterpreterException { - interpreter.close(); - } - - @Override - public InterpreterResult interpret(String st, InterpreterContext context) - throws InterpreterException { - - if (isSparkVersionUnsupported()) { - return unsupportedMessage; - } - - z.setInterpreterContext(context); - z.setGui(context.getGui()); - z.setNoteGui(context.getNoteGui()); - InterpreterContext.set(context); - - jsc.setJobGroup(buildJobGroupId(context), buildJobDesc(context), false); - jsc.setLocalProperty("spark.scheduler.pool", context.getLocalProperties().get("pool")); - - return sparkInterpreter.delegateInterpret(interpreter, st, context); - } - - @Override - public void cancel(InterpreterContext context) throws InterpreterException { - if (isSparkVersionUnsupported()) { - return; - } - jsc.cancelJobGroup(buildJobGroupId(context)); - interpreter.cancel(context); - } - - @Override - public FormType getFormType() throws InterpreterException { - return interpreter.getFormType(); - } - - @Override - public int getProgress(InterpreterContext context) throws InterpreterException { - if (isSparkVersionUnsupported()) { - return 0; - } - return sparkInterpreter.getProgress(context); - } - - @Override - public List<InterpreterCompletion> completion(String buf, int cursor, - InterpreterContext interpreterContext) throws InterpreterException { - if (isSparkVersionUnsupported()) { - return Collections.emptyList(); - } - return interpreter.completion(buf, cursor, interpreterContext); - } - - boolean isSparkVersionUnsupported() { - return unsupportedMessage != null; - } - - private static List<String> sparkClasspath() { - String sparkJars = System.getProperty("spark.jars"); - Pattern isKotlinJar = Pattern.compile("/kotlin-[a-z]*(-.*)?\\.jar"); - - Stream<File> addedJars = Arrays.stream(Utils.resolveURIs(sparkJars).split(",")) - .filter(s -> !s.trim().equals("")) - .filter(s -> !isKotlinJar.matcher(s).find()) - .map(s -> { - int p = s.indexOf(':'); - return new File(s.substring(p + 1)); - }); - - Stream<File> systemJars = Arrays.stream( - System.getProperty("java.class.path").split(File.pathSeparator)) - .map(File::new); - - return Stream.concat(addedJars, systemJars) - .map(file -> { - try { - return file.getCanonicalPath(); - } catch (IOException e) { - return ""; - } - }) - .collect(Collectors.toList()); - } -} diff --git a/spark/interpreter/src/main/java/org/apache/zeppelin/spark/SparkInterpreter.java b/spark/interpreter/src/main/java/org/apache/zeppelin/spark/SparkInterpreter.java index 62dfb1dd1a..65ab6f5966 100644 --- a/spark/interpreter/src/main/java/org/apache/zeppelin/spark/SparkInterpreter.java +++ b/spark/interpreter/src/main/java/org/apache/zeppelin/spark/SparkInterpreter.java @@ -30,7 +30,6 @@ import org.apache.zeppelin.interpreter.InterpreterException; import org.apache.zeppelin.interpreter.InterpreterGroup; import org.apache.zeppelin.interpreter.InterpreterResult; import org.apache.zeppelin.interpreter.thrift.InterpreterCompletion; -import org.apache.zeppelin.kotlin.KotlinInterpreter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -240,12 +239,6 @@ public class SparkInterpreter extends AbstractInterpreter { return this.innerInterpreter.getZeppelinContext(); } - public InterpreterResult delegateInterpret(KotlinInterpreter kotlinInterpreter, - String code, - InterpreterContext context) throws InterpreterException{ - return innerInterpreter.delegateInterpret(kotlinInterpreter, code, context); - } - public SparkContext getSparkContext() { return this.sc; } diff --git a/spark/interpreter/src/main/java/org/apache/zeppelin/spark/kotlin/KotlinZeppelinBindings.java b/spark/interpreter/src/main/java/org/apache/zeppelin/spark/kotlin/KotlinZeppelinBindings.java deleted file mode 100644 index f315838d8b..0000000000 --- a/spark/interpreter/src/main/java/org/apache/zeppelin/spark/kotlin/KotlinZeppelinBindings.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.zeppelin.spark.kotlin; - -/** - * Pre-executed code on KotlinSparkInterpreter opening. - */ -public class KotlinZeppelinBindings { - - //Simpler Kotlin syntax for z.select - public static final String Z_SELECT_KOTLIN_SYNTAX = - "import org.apache.zeppelin.display.ui.OptionInput.ParamOption\n" + - "import org.apache.zeppelin.interpreter.ZeppelinContext\n" + - "\n" + - "fun ZeppelinContext.select(name: String, defaultValue: Any?, " + - "options: List<Pair<Any?, String>>): Any? {\n" + - " return select(name, defaultValue, " + - "options.map{ ParamOption(it.first, it.second) }.toTypedArray())\n" + - "}\n" + - "\n" + - "fun ZeppelinContext.select(name: String, options: List<Pair<Any?, String>>): Any? {\n" + - " return select(name, \"\", options)\n" + - "}"; - - /** - * Automatic imports for Spark SQL UDFs. - */ - public static final String SPARK_UDF_IMPORTS = - "import org.apache.spark.sql.types.DataTypes\n" + - "import org.apache.spark.sql.functions.*\n" + - "import org.apache.spark.sql.expressions.UserDefinedFunction\n" + - "import org.apache.spark.sql.api.java.*"; - - public static final String CAST_SPARK_SESSION = "" + - "import org.apache.spark.sql.SparkSession\n" + - "val spark = _sparkObject as SparkSession"; -} diff --git a/spark/interpreter/src/main/java/org/apache/zeppelin/spark/kotlin/SparkKotlinReceiver.java b/spark/interpreter/src/main/java/org/apache/zeppelin/spark/kotlin/SparkKotlinReceiver.java deleted file mode 100644 index 1579891182..0000000000 --- a/spark/interpreter/src/main/java/org/apache/zeppelin/spark/kotlin/SparkKotlinReceiver.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.zeppelin.spark.kotlin; - -import org.apache.spark.api.java.JavaSparkContext; -import org.apache.spark.sql.SQLContext; -import org.apache.zeppelin.interpreter.ZeppelinContext; -import org.apache.zeppelin.kotlin.context.KotlinReceiver; - -/** - * Implicit receiver for Kotlin REPL with Spark's context (see KotlinReceiver for more details) - */ -public class SparkKotlinReceiver extends KotlinReceiver { - public final Object _sparkObject; - public final JavaSparkContext sc; - public final SQLContext sqlContext; - public final ZeppelinContext z; - - public SparkKotlinReceiver(Object spark, - JavaSparkContext sc, - SQLContext sqlContext, - ZeppelinContext z) { - this._sparkObject = spark; - this.sc = sc; - this.sqlContext = sqlContext; - this.z = z; - } -} diff --git a/spark/interpreter/src/main/resources/interpreter-setting.json b/spark/interpreter/src/main/resources/interpreter-setting.json index 5ba5f23bf5..eb3a4ef65f 100644 --- a/spark/interpreter/src/main/resources/interpreter-setting.json +++ b/spark/interpreter/src/main/resources/interpreter-setting.json @@ -330,39 +330,5 @@ "completionSupport": true, "completionKey": "TAB" } - }, - { - "group": "spark", - "name": "kotlin", - "className": "org.apache.zeppelin.spark.KotlinSparkInterpreter", - "properties": { - "zeppelin.spark.printREPLOutput": { - "envName": null, - "propertyName": "zeppelin.spark.printREPLOutput", - "defaultValue": true, - "description": "Print REPL output", - "type": "checkbox" - }, - "zeppelin.spark.maxResult": { - "envName": null, - "propertyName": "zeppelin.kotlin.maxResult", - "defaultValue": "1000", - "description": "Max number of result to display.", - "type": "number" - }, - "zeppelin.kotlin.shortenTypes": { - "envName": null, - "propertyName": "zeppelin.kotlin.shortenTypes", - "defaultValue": true, - "description": "Show short types instead of full, e.g. List<String> or kotlin.collections.List<kotlin.String>", - "type": "checkbox" - } - }, - "editor": { - "language": "kotlin", - "editOnDblClick": false, - "completionKey": "TAB", - "completionSupport": false - } } ] diff --git a/spark/interpreter/src/test/java/org/apache/zeppelin/spark/KotlinSparkInterpreterTest.java b/spark/interpreter/src/test/java/org/apache/zeppelin/spark/KotlinSparkInterpreterTest.java deleted file mode 100644 index 7ff63933ab..0000000000 --- a/spark/interpreter/src/test/java/org/apache/zeppelin/spark/KotlinSparkInterpreterTest.java +++ /dev/null @@ -1,232 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.zeppelin.spark; - -import static org.apache.zeppelin.interpreter.InterpreterResult.Code.ERROR; -import static org.apache.zeppelin.interpreter.InterpreterResult.Code.SUCCESS; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.jupiter.api.Assertions.fail; -import static org.mockito.Mockito.mock; - -import java.io.File; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.LinkedList; -import java.util.Properties; -import org.apache.zeppelin.display.AngularObjectRegistry; -import org.apache.zeppelin.display.ui.TextBox; -import org.apache.zeppelin.interpreter.Interpreter; -import org.apache.zeppelin.interpreter.InterpreterContext; -import org.apache.zeppelin.interpreter.InterpreterException; -import org.apache.zeppelin.interpreter.InterpreterGroup; -import org.apache.zeppelin.interpreter.InterpreterOutput; -import org.apache.zeppelin.interpreter.InterpreterOutputListener; -import org.apache.zeppelin.interpreter.InterpreterResult; -import org.apache.zeppelin.interpreter.InterpreterResultMessageOutput; -import org.apache.zeppelin.interpreter.remote.RemoteInterpreterEventClient; -import org.apache.zeppelin.resource.LocalResourcePool; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.io.TempDir; - -public class KotlinSparkInterpreterTest { - - @TempDir - static File tmpDir; - - private static SparkInterpreter repl; - private static InterpreterGroup intpGroup; - private static InterpreterContext context; - private static KotlinSparkInterpreter interpreter; - private static String output; - private static boolean sparkSupported; - - public static Properties getSparkTestProperties() throws IOException { - Properties p = new Properties(); - p.setProperty(SparkStringConstants.MASTER_PROP_NAME, "local[*]"); - p.setProperty(SparkStringConstants.APP_NAME_PROP_NAME, "Zeppelin Test"); - p.setProperty("zeppelin.spark.useHiveContext", "true"); - p.setProperty("zeppelin.spark.maxResult", "1000"); - p.setProperty("zeppelin.spark.importImplicit", "true"); - p.setProperty("zeppelin.dep.localrepo", tmpDir.getAbsolutePath()); - p.setProperty("zeppelin.spark.property_1", "value_1"); - return p; - } - - private static void testCodeForResult(String code, String expected) throws Exception { - InterpreterResult result = interpreter.interpret(code, context); - - String value; - if (result.message().isEmpty()) { - value = ""; - } else { - String message = result.message().get(0).getData().trim(); - // "res0 : kotlin.Int = 1" -> "kotlin.Int = 1" - value = message.substring(message.indexOf(':') + 2); - } - - assertEquals(SUCCESS, result.code()); - assertEquals(expected, value); - } - - @BeforeAll - public static void setUp() throws Exception { - intpGroup = new InterpreterGroup(); - context = InterpreterContext.builder() - .setNoteId("noteId") - .setParagraphId("paragraphId") - .setParagraphTitle("title") - .setAngularObjectRegistry(new AngularObjectRegistry(intpGroup.getId(), null)) - .setResourcePool(new LocalResourcePool("id")) - .setInterpreterOut(new InterpreterOutput()) - .setIntpEventClient(mock(RemoteInterpreterEventClient.class)) - .build(); - context.out = new InterpreterOutput( - new InterpreterOutputListener() { - @Override - public void onUpdateAll(InterpreterOutput out) { - - } - - @Override - public void onAppend(int index, InterpreterResultMessageOutput out, byte[] line) { - try { - output = out.toInterpreterResultMessage().getData(); - } catch (IOException e) { - e.printStackTrace(); - } - } - - @Override - public void onUpdate(int index, InterpreterResultMessageOutput out) { - - } - }); - - InterpreterContext.set(context); - - intpGroup.put("note", new LinkedList<Interpreter>()); - - Properties properties = getSparkTestProperties(); - repl = new SparkInterpreter(properties); - repl.setInterpreterGroup(intpGroup); - intpGroup.get("note").add(repl); - repl.open(); - repl.interpret("sc", context); - - interpreter = new KotlinSparkInterpreter(properties); - interpreter.setInterpreterGroup(intpGroup); - intpGroup.get("note").add(interpreter); - try { - interpreter.open(); - sparkSupported = true; - } catch (UnsupportedClassVersionError e) { - sparkSupported = false; - } - } - - @AfterAll - public static void tearDown() throws InterpreterException { - repl.close(); - } - - @Test - void simpleKotlinTest() throws Exception { - testCodeForResult("1 + 1", "Int = 2"); - } - - @Test - void dataFrameTest() throws Exception { - interpreter.interpret("spark.range(100, 0, -1).sort(\"id\").show(2)", context); - assertTrue(output.contains( - "+---+\n" + - "| id|\n" + - "+---+\n" + - "| 1|\n" + - "| 2|\n" + - "+---+")); - } - - @Test - void testCancel() throws Exception { - Thread t = new Thread(() -> { - try { - InterpreterResult result = interpreter.interpret( - "spark.range(10).foreach { Thread.sleep(1000) }", context); - assertEquals(ERROR, result.code()); - assertTrue(result.message().get(0).getData().trim().contains("cancelled")); - } catch (UnsupportedClassVersionError e) { - if (sparkSupported) { - fail(e.getMessage()); - } - } catch (InterpreterException e) { - fail(e.getMessage()); - } - }); - t.start(); - Thread.sleep(1000); - interpreter.cancel(context); - } - - @Test - void sparkPropertiesTest() throws Exception { - InterpreterResult result = interpreter.interpret( - "sc.conf.all.map{ it.toString() }", context); - String message = result.message().get(0).getData().trim(); - System.out.println("PROPS_1 = " + message); - assertTrue(message.contains("(zeppelin.spark.property_1,value_1)")); - } - - @Test - void classWriteTest() throws Exception { - interpreter.interpret("val f = { x: Any -> println(x) }", context); - output = ""; - InterpreterResult result = interpreter.interpret("spark.range(5).foreach(f)", context); - assertEquals(SUCCESS, result.code()); - assertTrue(output.contains("0")); - assertTrue(output.contains("1")); - assertTrue(output.contains("2")); - assertTrue(output.contains("3")); - assertTrue(output.contains("4")); - - String classOutputDir = repl.getSparkContext().getConf().get("spark.repl.class.outputDir"); - System.out.println(classOutputDir); - - Path outPath = Paths.get(classOutputDir); - Files.walk(outPath).forEach(System.out::println); - assertTrue(Files.walk(outPath).anyMatch(path -> path.toString().matches( - ".*Line_\\d+\\$f\\$1\\.class"))); - assertTrue(Files.walk(outPath).anyMatch(path -> path.toString().matches( - ".*Line_\\d+\\$sam\\$org_apache_spark_api_java_function_ForeachFunction\\$0\\.class"))); - } - - @Test - void zeppelinContextTest() throws Exception { - InterpreterResult result = interpreter.interpret("z.input(\"name\", \"default_name\")", context); - assertEquals(InterpreterResult.Code.SUCCESS, result.code()); - assertEquals(1, context.getGui().getForms().size()); - assertTrue(context.getGui().getForms().get("name") instanceof TextBox); - TextBox textBox = (TextBox) context.getGui().getForms().get("name"); - assertEquals("name", textBox.getName()); - assertEquals("default_name", textBox.getDefaultValue()); - } -} diff --git a/spark/scala-2.12/src/main/scala/org/apache/zeppelin/spark/SparkScala212Interpreter.scala b/spark/scala-2.12/src/main/scala/org/apache/zeppelin/spark/SparkScala212Interpreter.scala index 764dda93b0..4e9cece8e8 100644 --- a/spark/scala-2.12/src/main/scala/org/apache/zeppelin/spark/SparkScala212Interpreter.scala +++ b/spark/scala-2.12/src/main/scala/org/apache/zeppelin/spark/SparkScala212Interpreter.scala @@ -22,10 +22,9 @@ import org.apache.spark.repl.SparkILoop import org.apache.zeppelin.interpreter.thrift.InterpreterCompletion import org.apache.zeppelin.interpreter.util.InterpreterOutputStream import org.apache.zeppelin.interpreter.{InterpreterContext, InterpreterException, InterpreterGroup, InterpreterResult} -import org.apache.zeppelin.kotlin.KotlinInterpreter import org.slf4j.{Logger, LoggerFactory} -import java.io.{BufferedReader, File, PrintStream} +import java.io.{BufferedReader, File} import java.net.URLClassLoader import java.nio.file.Paths import java.util.Properties @@ -153,17 +152,6 @@ class SparkScala212Interpreter(conf: SparkConf, sparkILoop.classLoader } - // Used by KotlinSparkInterpreter - override def delegateInterpret(interpreter: KotlinInterpreter, - code: String, - context: InterpreterContext): InterpreterResult = { - val out = context.out - val newOut = if (out != null) new PrintStream(out) else null - Console.withOut(newOut) { - interpreter.interpret(code, context) - } - } - def interpret(code: String): InterpreterResult = interpret(code, InterpreterContext.get()) diff --git a/spark/scala-2.12/src/main/scala/org/apache/zeppelin/spark/SparkZeppelinContext.scala b/spark/scala-2.12/src/main/scala/org/apache/zeppelin/spark/SparkZeppelinContext.scala index 410ed4cf54..ff6186e8a4 100644 --- a/spark/scala-2.12/src/main/scala/org/apache/zeppelin/spark/SparkZeppelinContext.scala +++ b/spark/scala-2.12/src/main/scala/org/apache/zeppelin/spark/SparkZeppelinContext.scala @@ -42,8 +42,7 @@ class SparkZeppelinContext(val sc: SparkContext, "sql" -> "org.apache.zeppelin.spark.SparkSqlInterpreter", "pyspark" -> "org.apache.zeppelin.spark.PySparkInterpreter", "ipyspark" -> "org.apache.zeppelin.spark.IPySparkInterpreter", - "r" -> "org.apache.zeppelin.spark.SparkRInterpreter", - "kotlin" -> "org.apache.zeppelin.spark.KotlinSparkInterpreter" + "r" -> "org.apache.zeppelin.spark.SparkRInterpreter" ) private val supportedClasses = scala.collection.mutable.ArrayBuffer[Class[_]]() diff --git a/spark/scala-2.13/src/main/scala/org/apache/zeppelin/spark/SparkILoop.scala b/spark/scala-2.13/src/main/scala/org/apache/zeppelin/spark/SparkILoop.scala index 71f93a9661..2e91ea1c2d 100644 --- a/spark/scala-2.13/src/main/scala/org/apache/zeppelin/spark/SparkILoop.scala +++ b/spark/scala-2.13/src/main/scala/org/apache/zeppelin/spark/SparkILoop.scala @@ -22,8 +22,8 @@ import java.io.{BufferedReader, PrintWriter} import scala.Predef.{println => _, _} import scala.tools.nsc.GenericRunnerSettings import scala.tools.nsc.Settings -import scala.tools.nsc.interpreter.shell.{ILoop, ShellConfig} import scala.tools.nsc.util.stringFromStream +import scala.tools.nsc.interpreter.shell.{ILoop, ShellConfig} import scala.util.Properties.{javaVersion, javaVmName, versionString} /** diff --git a/spark/scala-2.13/src/main/scala/org/apache/zeppelin/spark/SparkScala213Interpreter.scala b/spark/scala-2.13/src/main/scala/org/apache/zeppelin/spark/SparkScala213Interpreter.scala index 91afc8545c..9b966e46ba 100644 --- a/spark/scala-2.13/src/main/scala/org/apache/zeppelin/spark/SparkScala213Interpreter.scala +++ b/spark/scala-2.13/src/main/scala/org/apache/zeppelin/spark/SparkScala213Interpreter.scala @@ -22,10 +22,9 @@ import org.apache.spark.SparkConf import org.apache.zeppelin.interpreter.thrift.InterpreterCompletion import org.apache.zeppelin.interpreter.util.InterpreterOutputStream import org.apache.zeppelin.interpreter.{InterpreterContext, InterpreterException, InterpreterGroup, InterpreterResult} -import org.apache.zeppelin.kotlin.KotlinInterpreter import org.slf4j.{Logger, LoggerFactory} -import java.io.{File, PrintStream, PrintWriter} +import java.io.{File, PrintWriter} import java.net.URLClassLoader import java.nio.file.Paths import java.util.Properties @@ -152,17 +151,6 @@ class SparkScala213Interpreter(conf: SparkConf, sparkILoop.classLoader } - // Used by KotlinSparkInterpreter - def delegateInterpret(interpreter: KotlinInterpreter, - code: String, - context: InterpreterContext): InterpreterResult = { - val out = context.out - val newOut = if (out != null) new PrintStream(out) else null - Console.withOut(newOut) { - interpreter.interpret(code, context) - } - } - override def close(): Unit = { super.close() if (sparkILoop != null) { diff --git a/spark/scala-2.13/src/main/scala/org/apache/zeppelin/spark/SparkZeppelinContext.scala b/spark/scala-2.13/src/main/scala/org/apache/zeppelin/spark/SparkZeppelinContext.scala index 410ed4cf54..ff6186e8a4 100644 --- a/spark/scala-2.13/src/main/scala/org/apache/zeppelin/spark/SparkZeppelinContext.scala +++ b/spark/scala-2.13/src/main/scala/org/apache/zeppelin/spark/SparkZeppelinContext.scala @@ -42,8 +42,7 @@ class SparkZeppelinContext(val sc: SparkContext, "sql" -> "org.apache.zeppelin.spark.SparkSqlInterpreter", "pyspark" -> "org.apache.zeppelin.spark.PySparkInterpreter", "ipyspark" -> "org.apache.zeppelin.spark.IPySparkInterpreter", - "r" -> "org.apache.zeppelin.spark.SparkRInterpreter", - "kotlin" -> "org.apache.zeppelin.spark.KotlinSparkInterpreter" + "r" -> "org.apache.zeppelin.spark.SparkRInterpreter" ) private val supportedClasses = scala.collection.mutable.ArrayBuffer[Class[_]]() diff --git a/zeppelin-web/bower.json b/zeppelin-web/bower.json index 90c212e7c8..4c7c11fe0c 100644 --- a/zeppelin-web/bower.json +++ b/zeppelin-web/bower.json @@ -47,7 +47,6 @@ "main": [ "src-noconflict/ace.js", "src-noconflict/mode-scala.js", - "src-noconflict/mode-kotlin.js", "src-noconflict/mode-python.js", "src-noconflict/mode-sql.js", "src-noconflict/mode-markdown.js", diff --git a/zeppelin-web/karma.conf.js b/zeppelin-web/karma.conf.js index 9e16589fba..bfddf8f8cc 100644 --- a/zeppelin-web/karma.conf.js +++ b/zeppelin-web/karma.conf.js @@ -56,7 +56,6 @@ module.exports = function(config) { 'bower_components/angular-websocket/angular-websocket.min.js', 'bower_components/ace-builds/src-noconflict/ace.js', 'bower_components/ace-builds/src-noconflict/mode-scala.js', - 'bower_components/ace-builds/src-noconflict/mode-kotlin.js', 'bower_components/ace-builds/src-noconflict/mode-python.js', 'bower_components/ace-builds/src-noconflict/mode-sql.js', 'bower_components/ace-builds/src-noconflict/mode-markdown.js', diff --git a/zeppelin-web/src/index.html b/zeppelin-web/src/index.html index 4f577adeff..11566b150a 100644 --- a/zeppelin-web/src/index.html +++ b/zeppelin-web/src/index.html @@ -180,7 +180,6 @@ limitations under the License. <script src="bower_components/angular-websocket/angular-websocket.min.js"></script> <script src="bower_components/ace-builds/src-noconflict/ace.js"></script> <script src="bower_components/ace-builds/src-noconflict/mode-scala.js"></script> - <script src="bower_components/ace-builds/src-noconflict/mode-kotlin.js"></script> <script src="bower_components/ace-builds/src-noconflict/mode-python.js"></script> <script src="bower_components/ace-builds/src-noconflict/mode-sql.js"></script> <script src="bower_components/ace-builds/src-noconflict/mode-markdown.js"></script>