You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@zeppelin.apache.org by ah...@apache.org on 2017/04/04 05:59:45 UTC
zeppelin git commit: Groovy Interpreter for Apazhe Zeppelin
[ZEPPELIN-2176]
Repository: zeppelin
Updated Branches:
refs/heads/master e7d41c349 -> 53a28a3a9
Groovy Interpreter for Apazhe Zeppelin [ZEPPELIN-2176]
### What is this PR for?
Groovy Interpreter
### What type of PR is it?
Feature
### Todos
* [ Tests ] - Task
* [ Documentation ] - Task
### What is the Jira issue?
[ZEPPELIN-2176]
### How should this be tested?
Follow the groovy interpreter documentation samples
### Questions:
* Does the licenses files need update? YES
* Is there breaking changes for older versions? NO
* Does this needs documentation? YES
Author: dlukyanov <dl...@ukr.net>
Author: dm <dm>
Closes #2135 from dlukyanov/master and squashes the following commits:
faf213f [dlukyanov] ZEPPELIN-2176 comments from @AhyoungRyu - remove @author - remove commented code
89c3ed5 [dlukyanov] retry
ca65947 [dlukyanov] deprecated
3dd53e2 [dlukyanov] ZEPPELIN-2176 comments from @AhyoungRyu - Zeppelin follows Google Java code - interpreter alphabetical order in _navigation.html - direct link to MarkupBuilder in groovy help
fe08159 [dlukyanov] retry
ca8bea6 [dlukyanov] Update groovy.md
a5b37a1 [dlukyanov] ZEPPELIN-2176 https://github.com/apache/zeppelin/pull/2135#issuecomment-289308850 - Inside of docs directory, groovy.md will need some header to be compiled with Jekyll - Menu in docs also need link to groovy - .travis.yml we need add !groovy
4abf649 [dm] Merge branch 'master' of https://github.com/apache/zeppelin
41a1702 [dlukyanov] ZEPPELIN-2176 https://github.com/apache/zeppelin/pull/2135#issuecomment-288829494 - implement shared script variables - move docs - implement run methods
dd388b3 [dlukyanov] retry
b34b42a [dlukyanov] retry
0d7732a [dlukyanov] retry
2646fa8 [dlukyanov] ZEPPELIN-2176 groovy interpreter, fix unchecked, add to configs, move HTTP.groovy to resources to simplify build, add default z-properties
5fa26e0 [dlukyanov] ZEPPELIN-2176 groovy interpreter, fix unchecked, add to configs, move HTTP.groovy to resources to simplify build, add default z-properties
aa427cd [dlukyanov] retry
addf167 [dlukyanov] retry
db4c35b [dlukyanov] Update README.md
fa779ea [dlukyanov] groovy interpreter
Project: http://git-wip-us.apache.org/repos/asf/zeppelin/repo
Commit: http://git-wip-us.apache.org/repos/asf/zeppelin/commit/53a28a3a
Tree: http://git-wip-us.apache.org/repos/asf/zeppelin/tree/53a28a3a
Diff: http://git-wip-us.apache.org/repos/asf/zeppelin/diff/53a28a3a
Branch: refs/heads/master
Commit: 53a28a3a915310f87990e705c78637d29c17683e
Parents: e7d41c3
Author: dlukyanov <dl...@ukr.net>
Authored: Thu Mar 30 20:29:00 2017 +0300
Committer: ahyoungryu <ah...@apache.org>
Committed: Tue Apr 4 14:59:35 2017 +0900
----------------------------------------------------------------------
.travis.yml | 2 +-
conf/zeppelin-site.xml.template | 4 +-
docs/_includes/themes/zeppelin/_navigation.html | 1 +
docs/interpreter/groovy.md | 116 ++++++
groovy/README.md | 4 +
groovy/pom-groovy-only.xml | 166 +++++++++
groovy/pom.xml | 149 ++++++++
groovy/src/assembly/dep.xml | 66 ++++
groovy/src/assembly/readme.txt | 1 +
.../org/apache/zeppelin/groovy/GObject.java | 369 +++++++++++++++++++
.../zeppelin/groovy/GroovyInterpreter.java | 215 +++++++++++
groovy/src/main/resources/HTTP.groovy | 154 ++++++++
.../src/main/resources/interpreter-setting.json | 15 +
pom.xml | 1 +
.../zeppelin/conf/ZeppelinConfiguration.java | 6 +-
15 files changed, 1264 insertions(+), 5 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/zeppelin/blob/53a28a3a/.travis.yml
----------------------------------------------------------------------
diff --git a/.travis.yml b/.travis.yml
index ee51c75..9424a91 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -37,7 +37,7 @@ addons:
env:
global:
# Interpreters does not required by zeppelin-server integration tests
- - INTERPRETERS='!hbase,!pig,!jdbc,!file,!flink,!ignite,!kylin,!python,!lens,!cassandra,!elasticsearch,!bigquery,!alluxio,!scio,!livy'
+ - INTERPRETERS='!hbase,!pig,!jdbc,!file,!flink,!ignite,!kylin,!python,!lens,!cassandra,!elasticsearch,!bigquery,!alluxio,!scio,!livy,!groovy'
matrix:
include:
http://git-wip-us.apache.org/repos/asf/zeppelin/blob/53a28a3a/conf/zeppelin-site.xml.template
----------------------------------------------------------------------
diff --git a/conf/zeppelin-site.xml.template b/conf/zeppelin-site.xml.template
index 6ce764b..5efe620 100755
--- a/conf/zeppelin-site.xml.template
+++ b/conf/zeppelin-site.xml.template
@@ -259,13 +259,13 @@
<property>
<name>zeppelin.interpreters</name>
- <value>org.apache.zeppelin.spark.SparkInterpreter,org.apache.zeppelin.spark.PySparkInterpreter,org.apache.zeppelin.rinterpreter.RRepl,org.apache.zeppelin.rinterpreter.KnitR,org.apache.zeppelin.spark.SparkRInterpreter,org.apache.zeppelin.spark.SparkSqlInterpreter,org.apache.zeppelin.spark.DepInterpreter,org.apache.zeppelin.markdown.Markdown,org.apache.zeppelin.angular.AngularInterpreter,org.apache.zeppelin.shell.ShellInterpreter,org.apache.zeppelin.file.HDFSFileInterpreter,org.apache.zeppelin.flink.FlinkInterpreter,,org.apache.zeppelin.python.PythonInterpreter,org.apache.zeppelin.python.PythonInterpreterPandasSql,org.apache.zeppelin.python.PythonCondaInterpreter,org.apache.zeppelin.python.PythonDockerInterpreter,org.apache.zeppelin.lens.LensInterpreter,org.apache.zeppelin.ignite.IgniteInterpreter,org.apache.zeppelin.ignite.IgniteSqlInterpreter,org.apache.zeppelin.cassandra.CassandraInterpreter,org.apache.zeppelin.geode.GeodeOqlInterpreter,org.apache.zeppelin.jdbc.JDBCInterpreter,or
g.apache.zeppelin.kylin.KylinInterpreter,org.apache.zeppelin.elasticsearch.ElasticsearchInterpreter,org.apache.zeppelin.scalding.ScaldingInterpreter,org.apache.zeppelin.alluxio.AlluxioInterpreter,org.apache.zeppelin.hbase.HbaseInterpreter,org.apache.zeppelin.livy.LivySparkInterpreter,org.apache.zeppelin.livy.LivyPySparkInterpreter,org.apache.zeppelin.livy.LivyPySpark3Interpreter,org.apache.zeppelin.livy.LivySparkRInterpreter,org.apache.zeppelin.livy.LivySparkSQLInterpreter,org.apache.zeppelin.bigquery.BigQueryInterpreter,org.apache.zeppelin.beam.BeamInterpreter,org.apache.zeppelin.pig.PigInterpreter,org.apache.zeppelin.pig.PigQueryInterpreter,org.apache.zeppelin.scio.ScioInterpreter</value>
+ <value>org.apache.zeppelin.spark.SparkInterpreter,org.apache.zeppelin.spark.PySparkInterpreter,org.apache.zeppelin.rinterpreter.RRepl,org.apache.zeppelin.rinterpreter.KnitR,org.apache.zeppelin.spark.SparkRInterpreter,org.apache.zeppelin.spark.SparkSqlInterpreter,org.apache.zeppelin.spark.DepInterpreter,org.apache.zeppelin.markdown.Markdown,org.apache.zeppelin.angular.AngularInterpreter,org.apache.zeppelin.shell.ShellInterpreter,org.apache.zeppelin.file.HDFSFileInterpreter,org.apache.zeppelin.flink.FlinkInterpreter,,org.apache.zeppelin.python.PythonInterpreter,org.apache.zeppelin.python.PythonInterpreterPandasSql,org.apache.zeppelin.python.PythonCondaInterpreter,org.apache.zeppelin.python.PythonDockerInterpreter,org.apache.zeppelin.lens.LensInterpreter,org.apache.zeppelin.ignite.IgniteInterpreter,org.apache.zeppelin.ignite.IgniteSqlInterpreter,org.apache.zeppelin.cassandra.CassandraInterpreter,org.apache.zeppelin.geode.GeodeOqlInterpreter,org.apache.zeppelin.jdbc.JDBCInterpreter,or
g.apache.zeppelin.kylin.KylinInterpreter,org.apache.zeppelin.elasticsearch.ElasticsearchInterpreter,org.apache.zeppelin.scalding.ScaldingInterpreter,org.apache.zeppelin.alluxio.AlluxioInterpreter,org.apache.zeppelin.hbase.HbaseInterpreter,org.apache.zeppelin.livy.LivySparkInterpreter,org.apache.zeppelin.livy.LivyPySparkInterpreter,org.apache.zeppelin.livy.LivyPySpark3Interpreter,org.apache.zeppelin.livy.LivySparkRInterpreter,org.apache.zeppelin.livy.LivySparkSQLInterpreter,org.apache.zeppelin.bigquery.BigQueryInterpreter,org.apache.zeppelin.beam.BeamInterpreter,org.apache.zeppelin.pig.PigInterpreter,org.apache.zeppelin.pig.PigQueryInterpreter,org.apache.zeppelin.scio.ScioInterpreter,org.apache.zeppelin.groovy.GroovyInterpreter</value>
<description>Comma separated interpreter configurations. First interpreter become a default</description>
</property>
<property>
<name>zeppelin.interpreter.group.order</name>
- <value>spark,md,angular,sh,livy,alluxio,file,psql,flink,python,ignite,lens,cassandra,geode,kylin,elasticsearch,scalding,jdbc,hbase,bigquery,beam</value>
+ <value>spark,md,angular,sh,livy,alluxio,file,psql,flink,python,ignite,lens,cassandra,geode,kylin,elasticsearch,scalding,jdbc,hbase,bigquery,beam,groovy</value>
<description></description>
</property>
http://git-wip-us.apache.org/repos/asf/zeppelin/blob/53a28a3a/docs/_includes/themes/zeppelin/_navigation.html
----------------------------------------------------------------------
diff --git a/docs/_includes/themes/zeppelin/_navigation.html b/docs/_includes/themes/zeppelin/_navigation.html
index 797455c..623fac3 100644
--- a/docs/_includes/themes/zeppelin/_navigation.html
+++ b/docs/_includes/themes/zeppelin/_navigation.html
@@ -61,6 +61,7 @@
<li><a href="{{BASE_PATH}}/interpreter/elasticsearch.html">Elasticsearch</a></li>
<li><a href="{{BASE_PATH}}/interpreter/flink.html">Flink</a></li>
<li><a href="{{BASE_PATH}}/interpreter/geode.html">Geode</a></li>
+ <li><a href="{{BASE_PATH}}/interpreter/groovy.html">Groovy</a></li>
<li><a href="{{BASE_PATH}}/interpreter/hbase.html">HBase</a></li>
<li><a href="{{BASE_PATH}}/interpreter/hdfs.html">HDFS</a></li>
<li><a href="{{BASE_PATH}}/interpreter/hive.html">Hive</a></li>
http://git-wip-us.apache.org/repos/asf/zeppelin/blob/53a28a3a/docs/interpreter/groovy.md
----------------------------------------------------------------------
diff --git a/docs/interpreter/groovy.md b/docs/interpreter/groovy.md
new file mode 100644
index 0000000..01074a3
--- /dev/null
+++ b/docs/interpreter/groovy.md
@@ -0,0 +1,116 @@
+---
+layout: page
+title: "Apache Groovy Interpreter for Apache Zeppelin"
+description: "Apache Groovy is a powerful, optionally typed and dynamic language, with static-typing and static compilation capabilities, for the Java platform aimed at improving developer productivity thanks to a concise, familiar and easy to learn syntax."
+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 %}
+
+# Groovy Interpreter for Apache Zeppelin
+
+
+### Samples
+
+```groovy
+%groovy
+//get a parameter defined as z.angularBind('ngSearchParam', value, 'paragraph_id')
+//g is a context object for groovy to avoid mix with z object
+def param = g.angular('ngSearchParam')
+//send request https://www.googleapis.com/customsearch/v1?q=ngSearchParam_value
+def r = HTTP.get(
+ //assume you defined the groovy interpreter property
+ // `search_baseurl`='https://www.googleapis.com/customsearch/v1'
+ //in groovy object o.getProperty('A') == o.'A' == o.A == o['A']
+ url : g.search_baseurl,
+ query: [ q: param ],
+ headers: [
+ 'Accept':'application/json',
+ //'Authorization:' : g.getProperty('search_auth'),
+ ]
+)
+//check response code
+if( r.response.code==200 ) {
+ g.html().with{
+ //g.html() renders %angular to output and returns groovy.xml.MarkupBuilder
+ h2("the response ${r.response.code}")
+ span( r.response.body )
+ h2("headers")
+ pre( r.response.headers.join('\n') )
+ }
+} else {
+ //just to show that it's possible to use println with multiline groovy string to render output
+ println("""%angular
+ <script> alert ("code=${r.response.code} \n msg=${r.response.message}") </script>
+ """)
+}
+```
+
+
+```groovy
+%groovy
+
+//renders a table with headers a, b, c and two rows
+g.table(
+ [
+ ['a','b','c'],
+ ['a1','b1','c1'],
+ ['a2','b2','c2'],
+ ]
+)
+```
+
+### the `g` object
+
+* `g.angular(String name)`
+
+Returns angular object by name. Look up notebook scope first and then global scope.
+
+
+* `g.angularBind(String name, Object value)`
+
+Assign a new `value` into angular object `name`
+
+
+* `java.util.Properties g.getProperties()`
+
+returns all properties defined for this interpreter
+
+
+* `String g.getProperty('PROPERTY_NAME')`
+```groovy
+g.PROPERTY_NAME
+g.'PROPERTY_NAME'
+g['PROPERTY_NAME']
+g.getProperties().getProperty('PROPERTY_NAME')
+```
+
+All above the accessor to named property defined in groovy interpreter.
+In this case with name `PROPERTY_NAME`
+
+
+* `groovy.xml.MarkupBuilder g.html()`
+
+Starts or continues rendering of `%angular` to output and returns [groovy.xml.MarkupBuilder](http://groovy-lang.org/processing-xml.html#_markupbuilder)
+MarkupBuilder is usefull to generate html (xml)
+
+* `void g.table(obj)`
+
+starts or continues rendering table rows.
+
+obj: List(rows) of List(columns) where first line is a header
+
+
+
http://git-wip-us.apache.org/repos/asf/zeppelin/blob/53a28a3a/groovy/README.md
----------------------------------------------------------------------
diff --git a/groovy/README.md b/groovy/README.md
new file mode 100644
index 0000000..4f2e986
--- /dev/null
+++ b/groovy/README.md
@@ -0,0 +1,4 @@
+## Groovy Interpreter
+
+
+[see groovy documentation](../docs/interpreter/groovy.md)
http://git-wip-us.apache.org/repos/asf/zeppelin/blob/53a28a3a/groovy/pom-groovy-only.xml
----------------------------------------------------------------------
diff --git a/groovy/pom-groovy-only.xml b/groovy/pom-groovy-only.xml
new file mode 100644
index 0000000..971c674
--- /dev/null
+++ b/groovy/pom-groovy-only.xml
@@ -0,0 +1,166 @@
+<?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/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <artifactId>zeppelin</artifactId>
+ <groupId>org.apache.zeppelin</groupId>
+ <!--version>0.6.2</version-->
+ <version>0.8.0-SNAPSHOT</version>
+ <relativePath>..</relativePath>
+ </parent>
+
+ <groupId>org.apache.zeppelin</groupId>
+ <artifactId>zeppelin-groovy</artifactId>
+ <packaging>jar</packaging>
+ <version>0.8.0-SNAPSHOT</version>
+ <name>Zeppelin: Groovy interpreter</name>
+
+ <dependencies>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>zeppelin-interpreter</artifactId>
+ <version>${project.version}</version>
+ <scope>provided</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-log4j12</artifactId>
+ </dependency>
+
+ <!-- https://mvnrepository.com/artifact/org.codehaus.groovy/groovy-all -->
+ <dependency>
+ <groupId>org.codehaus.groovy</groupId>
+ <artifactId>groovy-all</artifactId>
+ <version>2.4.7</version>
+ </dependency>
+
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>3.1</version>
+ <configuration>
+ <showDeprecation>true</showDeprecation>
+ <compilerArgs>
+ <!--arg>-verbose</arg-->
+ <arg>-Xlint:unchecked</arg>
+ </compilerArgs>
+ </configuration>
+ </plugin>
+
+ <!--TODO: comment local `maven-checkstyle-plugin` and use zeppelin common check style-->
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-checkstyle-plugin</artifactId>
+ <configuration>
+ <skip>true</skip>
+ </configuration>
+ <executions>
+ </executions>
+ </plugin>
+ <plugin>
+ <artifactId>maven-enforcer-plugin</artifactId>
+ <version>1.3.1</version>
+ <executions>
+ <execution>
+ <id>enforce</id>
+ <phase>none</phase>
+ </execution>
+ </executions>
+ </plugin>
+
+ <plugin>
+ <artifactId>maven-dependency-plugin</artifactId>
+ <version>2.8</version>
+ <executions>
+ <execution>
+ <id>copy-dependencies</id>
+ <phase>package</phase>
+ <goals>
+ <goal>copy-dependencies</goal>
+ </goals>
+ <configuration>
+ <outputDirectory>${project.build.directory}/../../interpreter/groovy</outputDirectory>
+ <overWriteReleases>false</overWriteReleases>
+ <overWriteSnapshots>false</overWriteSnapshots>
+ <overWriteIfNewer>true</overWriteIfNewer>
+ <includeScope>runtime</includeScope>
+ </configuration>
+ </execution>
+ <execution>
+ <id>copy-artifact</id>
+ <phase>package</phase>
+ <goals>
+ <goal>copy</goal>
+ </goals>
+ <configuration>
+ <outputDirectory>${project.build.directory}/../../interpreter/groovy</outputDirectory>
+ <overWriteReleases>false</overWriteReleases>
+ <overWriteSnapshots>false</overWriteSnapshots>
+ <overWriteIfNewer>true</overWriteIfNewer>
+ <includeScope>runtime</includeScope>
+ <artifactItems>
+ <artifactItem>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>${project.artifactId}</artifactId>
+ <version>${project.version}</version>
+ <type>${project.packaging}</type>
+ </artifactItem>
+ </artifactItems>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <!--this one only for independent groovy interpreter assembly-->
+ <plugin>
+ <artifactId>maven-assembly-plugin</artifactId>
+ <version>2.5.3</version>
+ <configuration>
+ <descriptor>src/assembly/dep.xml</descriptor>
+ </configuration>
+ <executions>
+ <execution>
+ <id>create-archive</id>
+ <phase>package</phase>
+ <goals>
+ <goal>single</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+
+</project>
http://git-wip-us.apache.org/repos/asf/zeppelin/blob/53a28a3a/groovy/pom.xml
----------------------------------------------------------------------
diff --git a/groovy/pom.xml b/groovy/pom.xml
new file mode 100644
index 0000000..bee50bd
--- /dev/null
+++ b/groovy/pom.xml
@@ -0,0 +1,149 @@
+<?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/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <artifactId>zeppelin</artifactId>
+ <groupId>org.apache.zeppelin</groupId>
+ <!--version>0.6.2</version-->
+ <version>0.8.0-SNAPSHOT</version>
+ <relativePath>..</relativePath>
+ </parent>
+
+ <groupId>org.apache.zeppelin</groupId>
+ <artifactId>zeppelin-groovy</artifactId>
+ <packaging>jar</packaging>
+ <version>0.8.0-SNAPSHOT</version>
+ <name>Zeppelin: Groovy interpreter</name>
+
+ <dependencies>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>zeppelin-interpreter</artifactId>
+ <version>${project.version}</version>
+ <scope>provided</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-log4j12</artifactId>
+ </dependency>
+
+ <!-- https://mvnrepository.com/artifact/org.codehaus.groovy/groovy-all -->
+ <dependency>
+ <groupId>org.codehaus.groovy</groupId>
+ <artifactId>groovy-all</artifactId>
+ <version>2.4.7</version>
+ </dependency>
+
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>3.1</version>
+ <configuration>
+ <showDeprecation>true</showDeprecation>
+ <compilerArgs>
+ <!--arg>-verbose</arg-->
+ <arg>-Xlint:unchecked</arg>
+ </compilerArgs>
+ </configuration>
+ </plugin>
+
+ <!--TODO: comment local `maven-checkstyle-plugin` and use zeppelin common check style-->
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-checkstyle-plugin</artifactId>
+ <configuration>
+ <skip>true</skip>
+ </configuration>
+ <executions>
+ </executions>
+ </plugin>
+ <plugin>
+ <artifactId>maven-enforcer-plugin</artifactId>
+ <version>1.3.1</version>
+ <executions>
+ <execution>
+ <id>enforce</id>
+ <phase>none</phase>
+ </execution>
+ </executions>
+ </plugin>
+
+ <plugin>
+ <artifactId>maven-dependency-plugin</artifactId>
+ <version>2.8</version>
+ <executions>
+ <execution>
+ <id>copy-dependencies</id>
+ <phase>package</phase>
+ <goals>
+ <goal>copy-dependencies</goal>
+ </goals>
+ <configuration>
+ <outputDirectory>${project.build.directory}/../../interpreter/groovy</outputDirectory>
+ <overWriteReleases>false</overWriteReleases>
+ <overWriteSnapshots>false</overWriteSnapshots>
+ <overWriteIfNewer>true</overWriteIfNewer>
+ <includeScope>runtime</includeScope>
+ </configuration>
+ </execution>
+ <execution>
+ <id>copy-artifact</id>
+ <phase>package</phase>
+ <goals>
+ <goal>copy</goal>
+ </goals>
+ <configuration>
+ <outputDirectory>${project.build.directory}/../../interpreter/groovy</outputDirectory>
+ <overWriteReleases>false</overWriteReleases>
+ <overWriteSnapshots>false</overWriteSnapshots>
+ <overWriteIfNewer>true</overWriteIfNewer>
+ <includeScope>runtime</includeScope>
+ <artifactItems>
+ <artifactItem>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>${project.artifactId}</artifactId>
+ <version>${project.version}</version>
+ <type>${project.packaging}</type>
+ </artifactItem>
+ </artifactItems>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+
+</project>
http://git-wip-us.apache.org/repos/asf/zeppelin/blob/53a28a3a/groovy/src/assembly/dep.xml
----------------------------------------------------------------------
diff --git a/groovy/src/assembly/dep.xml b/groovy/src/assembly/dep.xml
new file mode 100644
index 0000000..a391075
--- /dev/null
+++ b/groovy/src/assembly/dep.xml
@@ -0,0 +1,66 @@
+<!--
+ ~ 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.
+ -->
+
+<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
+ <id>bin</id>
+ <baseDirectory>groovy</baseDirectory>
+ <formats>
+ <format>zip</format>
+ </formats>
+ <fileSets>
+ <fileSet>
+ <directory>${project.basedir}</directory>
+ <outputDirectory>/</outputDirectory>
+ <filtered>true</filtered>
+ <includes>
+ <include>README*</include>
+ </includes>
+ </fileSet>
+ <fileSet>
+ <directory>${project.build.directory}</directory>
+ <outputDirectory>/</outputDirectory>
+ <includes>
+ <include>*.jar</include>
+ <include>revision.txt</include>
+ </includes>
+ </fileSet>
+ <!--fileSet>
+ <directory>${project.basedir}/src/main/groovy/classes/</directory>
+ <outputDirectory>/classes/</outputDirectory>
+ <includes>
+ <include>*.groovy</include>
+ </includes>
+ </fileSet-->
+
+ <!--fileSet>
+ <directory>${project.build.directory}/site</directory>
+ <outputDirectory>docs</outputDirectory>
+ </fileSet-->
+ </fileSets>
+ <dependencySets>
+ <dependencySet>
+ <outputDirectory>/</outputDirectory>
+ <unpack>false</unpack>
+ <scope>runtime</scope>
+ <!--excludes>
+ <exclude>junit:junit</exclude>
+ </excludes-->
+ </dependencySet>
+ </dependencySets>
+</assembly>
http://git-wip-us.apache.org/repos/asf/zeppelin/blob/53a28a3a/groovy/src/assembly/readme.txt
----------------------------------------------------------------------
diff --git a/groovy/src/assembly/readme.txt b/groovy/src/assembly/readme.txt
new file mode 100644
index 0000000..dbc8369
--- /dev/null
+++ b/groovy/src/assembly/readme.txt
@@ -0,0 +1 @@
+to assemble groovy interpreter separately
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/zeppelin/blob/53a28a3a/groovy/src/main/java/org/apache/zeppelin/groovy/GObject.java
----------------------------------------------------------------------
diff --git a/groovy/src/main/java/org/apache/zeppelin/groovy/GObject.java b/groovy/src/main/java/org/apache/zeppelin/groovy/GObject.java
new file mode 100644
index 0000000..e460651
--- /dev/null
+++ b/groovy/src/main/java/org/apache/zeppelin/groovy/GObject.java
@@ -0,0 +1,369 @@
+/*
+ * 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.groovy;
+
+
+import java.io.StringWriter;
+
+import org.slf4j.Logger;
+
+import java.util.Properties;
+import java.util.Collection;
+import java.util.Map;
+import java.util.List;
+import java.util.LinkedList;
+
+import groovy.xml.MarkupBuilder;
+import groovy.lang.Closure;
+
+import org.apache.zeppelin.interpreter.InterpreterContext;
+import org.apache.zeppelin.interpreter.InterpreterContextRunner;
+
+import org.apache.zeppelin.display.AngularObjectRegistry;
+import org.apache.zeppelin.display.AngularObject;
+import org.apache.zeppelin.display.GUI;
+import org.apache.zeppelin.display.Input.ParamOption;
+import org.apache.zeppelin.annotation.ZeppelinApi;
+import org.apache.zeppelin.interpreter.RemoteWorksController;
+import org.apache.zeppelin.interpreter.InterpreterException;
+
+/**
+ * Groovy interpreter for Zeppelin.
+ */
+public class GObject extends groovy.lang.GroovyObjectSupport {
+
+ Logger log;
+ StringWriter out;
+ Properties props;
+ InterpreterContext interpreterContext;
+ Map<String, Object> bindings;
+
+
+ public GObject(Logger log, StringWriter out, Properties p, InterpreterContext ctx,
+ Map<String, Object> bindings) {
+ this.log = log;
+ this.out = out;
+ this.interpreterContext = ctx;
+ this.props = p;
+ this.bindings = bindings;
+ }
+
+ public Object getProperty(String key) {
+ if ("log".equals(key)) {
+ return log;
+ }
+ return props.getProperty(key);
+ }
+
+ public void setProperty(String key, Object value) {
+ throw new RuntimeException("Set properties not supported: " + key + "=" + value);
+ }
+
+ public Properties getProperties() {
+ return props;
+ }
+
+ private void startOutputType(String type) {
+ StringBuffer sb = out.getBuffer();
+ if (sb.length() > 0) {
+ if (sb.length() < type.length() || !type.equals(sb.substring(0, type.length()))) {
+ log.error("try to start output `" + type + "` after non-" + type + " started");
+ }
+ } else {
+ out.append(type);
+ out.append('\n');
+ }
+ }
+
+ /**
+ * returns gui object
+ */
+ public GUI getGui() {
+ return interpreterContext.getGui();
+ }
+
+ @ZeppelinApi
+ public Object input(String name) {
+ return input(name, "");
+ }
+
+ @ZeppelinApi
+ public Object input(String name, Object defaultValue) {
+ return getGui().input(name, defaultValue);
+ }
+
+ private ParamOption[] toParamOptions(Map<Object, String> options) {
+ ParamOption[] paramOptions = new ParamOption[options.size()];
+ int i = 0;
+ for (Map.Entry<Object, String> e : options.entrySet()) {
+ paramOptions[i++] = new ParamOption(e.getKey(), e.getValue());
+ }
+ return paramOptions;
+ }
+
+ @ZeppelinApi
+ public Object select(String name, Map<Object, String> options) {
+ return select(name, "", options);
+ }
+
+ @ZeppelinApi
+ public Object select(String name, Object defaultValue, Map<Object, String> options) {
+ return getGui().select(name, defaultValue, toParamOptions(options));
+ }
+
+ @ZeppelinApi
+ public Collection<Object> checkbox(String name, Map<Object, String> options) {
+ return checkbox(name, options.keySet(), options);
+ }
+
+ @ZeppelinApi
+ public Collection<Object> checkbox(String name, Collection<Object> defaultChecked,
+ Map<Object, String> options) {
+ return getGui().checkbox(name, defaultChecked, toParamOptions(options));
+ }
+
+
+ /**
+ * Returns shared variable if it was previously set. The same as getting groovy script variables
+ * but this method will return null if script variable not assigned. To understand groovy script
+ * variables see groovy.transform.Field annotation for more information.
+ *
+ * @see #put
+ */
+ public Object get(String varName) {
+ return bindings.get(varName);
+ }
+
+ /**
+ * Returns script (shared) variable value but if value was not set returns default value. The same
+ * as getting groovy script variables but this method will return default value if script variable
+ * not assigned. To understand groovy script variables see groovy.transform.Field annotation for
+ * more information.
+ *
+ * @see #put
+ */
+ public Object get(String varName, Object defValue) {
+ return bindings.containsKey(varName) ? bindings.get(varName) : defValue;
+ }
+
+ /**
+ * Sets a new value to interpreter's shared variables.
+ * Could be set by <code>put('varName', newValue )</code>
+ * or by just assigning <code>varName = value</code> without declaring a variable.
+ */
+ public Object put(String varName, Object newValue) {
+ return bindings.put(varName, newValue);
+ }
+
+ /**
+ * starts or continues rendering html/angular and returns MarkupBuilder to build html.
+ * <pre> g.html().with{
+ * h1("hello")
+ * h2("world")
+ * }</pre>
+ */
+ public MarkupBuilder html() {
+ startOutputType("%angular");
+ return new MarkupBuilder(out);
+ }
+
+ /**
+ * starts or continues rendering table rows
+ *
+ * @param obj: 1. List(rows) of List(columns) where first line is a header
+ */
+ public void table(Object obj) {
+ if (obj == null) {
+ return;
+ }
+ StringBuffer sb = out.getBuffer();
+ startOutputType("%table");
+ if (obj instanceof groovy.lang.Closure) {
+ //if closure run and get result collection
+ obj = ((Closure) obj).call();
+ }
+ if (obj instanceof Collection) {
+ int count = 0;
+ for (Object row : ((Collection) obj)) {
+ count++;
+ boolean rowStarted = false;
+ if (row instanceof Collection) {
+ for (Object field : ((Collection) row)) {
+ if (rowStarted) {
+ sb.append('\t');
+ }
+ sb.append(field);
+ rowStarted = true;
+ }
+ } else {
+ sb.append(row);
+ }
+ sb.append('\n');
+ }
+ } else {
+ throw new RuntimeException("Not supported table value :" + obj.getClass());
+ }
+ }
+
+ private AngularObject getAngularObject(String name) {
+ AngularObjectRegistry registry = interpreterContext.getAngularObjectRegistry();
+ String noteId = interpreterContext.getNoteId();
+ // try get local object
+ AngularObject paragraphAo = registry.get(name, noteId, interpreterContext.getParagraphId());
+ AngularObject noteAo = registry.get(name, noteId, null);
+
+ AngularObject ao = paragraphAo != null ? paragraphAo : noteAo;
+
+ if (ao == null) {
+ // then global object
+ ao = registry.get(name, null, null);
+ }
+ return ao;
+ }
+
+ /**
+ * Get angular object. Look up notebook scope first and then global scope
+ *
+ * @param name variable name
+ * @return value
+ */
+ public Object angular(String name) {
+ AngularObject ao = getAngularObject(name);
+ if (ao == null) {
+ return null;
+ } else {
+ return ao.get();
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ public void angularBind(String name, Object o, String noteId) {
+ AngularObjectRegistry registry = interpreterContext.getAngularObjectRegistry();
+
+ if (registry.get(name, noteId, null) == null) {
+ registry.add(name, o, noteId, null);
+ } else {
+ registry.get(name, noteId, null).set(o);
+ }
+ }
+
+ /**
+ * Create angular variable in notebook scope and bind with front end Angular display system.
+ * If variable exists, it'll be overwritten.
+ *
+ * @param name name of the variable
+ * @param o value
+ */
+ public void angularBind(String name, Object o) {
+ angularBind(name, o, interpreterContext.getNoteId());
+ }
+
+ /*------------------------------------------RUN----------------------------------------*/
+ @ZeppelinApi
+ public List<InterpreterContextRunner> getInterpreterContextRunner(String noteId,
+ String paragraphId, InterpreterContext interpreterContext) {
+ RemoteWorksController remoteWorksController = interpreterContext.getRemoteWorksController();
+ if (remoteWorksController != null) {
+ return remoteWorksController.getRemoteContextRunner(noteId, paragraphId);
+ }
+ return new LinkedList<InterpreterContextRunner>();
+ }
+
+ @ZeppelinApi
+ public List<InterpreterContextRunner> getInterpreterContextRunner(String noteId,
+ InterpreterContext interpreterContext) {
+ RemoteWorksController remoteWorksController = interpreterContext.getRemoteWorksController();
+ if (remoteWorksController != null) {
+ return remoteWorksController.getRemoteContextRunner(noteId);
+ }
+ return new LinkedList<InterpreterContextRunner>();
+ }
+
+ /**
+ * Run paragraph by id
+ */
+ @ZeppelinApi
+ public void run(String noteId, String paragraphId) {
+ run(noteId, paragraphId, interpreterContext);
+ }
+
+ /**
+ * Run paragraph by id
+ */
+ @ZeppelinApi
+ public void run(String paragraphId) {
+ String noteId = interpreterContext.getNoteId();
+ run(noteId, paragraphId, interpreterContext);
+ }
+
+ /**
+ * Run paragraph by id
+ */
+ @ZeppelinApi
+ public void run(String noteId, String paragraphId, InterpreterContext context) {
+ if (paragraphId.equals(context.getParagraphId())) {
+ throw new InterpreterException("Can not run current Paragraph");
+ }
+ List<InterpreterContextRunner> runners = getInterpreterContextRunner(noteId, paragraphId,
+ context);
+ if (runners.size() <= 0) {
+ throw new InterpreterException("Paragraph " + paragraphId + " not found " + runners.size());
+ }
+ for (InterpreterContextRunner r : runners) {
+ r.run();
+ }
+ }
+
+ public void runNote(String noteId) {
+ runNote(noteId, interpreterContext);
+ }
+
+ public void runNote(String noteId, InterpreterContext context) {
+ String runningNoteId = context.getNoteId();
+ String runningParagraphId = context.getParagraphId();
+ List<InterpreterContextRunner> runners = getInterpreterContextRunner(noteId, context);
+
+ if (runners.size() <= 0) {
+ throw new InterpreterException("Note " + noteId + " not found " + runners.size());
+ }
+
+ for (InterpreterContextRunner r : runners) {
+ if (r.getNoteId().equals(runningNoteId) && r.getParagraphId().equals(runningParagraphId)) {
+ continue;
+ }
+ r.run();
+ }
+ }
+
+ /**
+ * Run all paragraphs. except this.
+ */
+ @ZeppelinApi
+ public void runAll() {
+ runAll(interpreterContext);
+ }
+
+ /**
+ * Run all paragraphs. except this.
+ */
+ @ZeppelinApi
+ public void runAll(InterpreterContext context) {
+ runNote(context.getNoteId());
+ }
+
+
+}
http://git-wip-us.apache.org/repos/asf/zeppelin/blob/53a28a3a/groovy/src/main/java/org/apache/zeppelin/groovy/GroovyInterpreter.java
----------------------------------------------------------------------
diff --git a/groovy/src/main/java/org/apache/zeppelin/groovy/GroovyInterpreter.java b/groovy/src/main/java/org/apache/zeppelin/groovy/GroovyInterpreter.java
new file mode 100644
index 0000000..8951a62
--- /dev/null
+++ b/groovy/src/main/java/org/apache/zeppelin/groovy/GroovyInterpreter.java
@@ -0,0 +1,215 @@
+/*
+ * 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.groovy;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.StringWriter;
+import java.io.PrintWriter;
+import java.io.File;
+import java.util.*;
+
+import org.apache.zeppelin.interpreter.Interpreter;
+import org.apache.zeppelin.interpreter.InterpreterContext;
+import org.apache.zeppelin.interpreter.InterpreterPropertyBuilder;
+import org.apache.zeppelin.interpreter.InterpreterResult;
+import org.apache.zeppelin.interpreter.InterpreterResult.Code;
+import org.apache.zeppelin.interpreter.InterpreterResult.Type;
+import org.apache.zeppelin.interpreter.thrift.InterpreterCompletion;
+import org.apache.zeppelin.scheduler.Job;
+import org.apache.zeppelin.scheduler.Scheduler;
+import org.apache.zeppelin.scheduler.SchedulerFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import groovy.lang.GroovyShell;
+import groovy.lang.Script;
+import org.codehaus.groovy.control.CompilerConfiguration;
+import org.codehaus.groovy.runtime.ResourceGroovyMethods;
+import org.codehaus.groovy.runtime.StackTraceUtils;
+
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * Groovy interpreter for Zeppelin.
+ */
+public class GroovyInterpreter extends Interpreter {
+
+ Logger log = LoggerFactory.getLogger(GroovyInterpreter.class);
+ GroovyShell shell = null; //new GroovyShell();
+ //here we will store Interpreters shared variables. concurrent just in case.
+ Map<String, Object> sharedBindings = new ConcurrentHashMap<String, Object>();
+ //cache for groovy compiled scripts
+ Map<String, Class<Script>> scriptCache = Collections
+ .synchronizedMap(new WeakHashMap<String, Class<Script>>(100));
+
+
+ public GroovyInterpreter(Properties property) {
+ super(property);
+ }
+
+ @Override
+ public void open() {
+ CompilerConfiguration conf = new CompilerConfiguration();
+ conf.setDebug(true);
+ shell = new GroovyShell(conf);
+ String classes = getProperty("GROOVY_CLASSES");
+ if (classes == null || classes.length() == 0) {
+ try {
+ File jar = new File(
+ GroovyInterpreter.class.getProtectionDomain().getCodeSource().getLocation().toURI()
+ .getPath());
+ classes = new File(jar.getParentFile(), "classes").toString();
+ } catch (Exception e) {
+ }
+ }
+ log.info("groovy classes classpath: " + classes);
+ if (classes != null && classes.length() > 0) {
+ File fClasses = new File(classes);
+ if (!fClasses.exists()) {
+ fClasses.mkdirs();
+ }
+ shell.getClassLoader().addClasspath(classes);
+ }
+ }
+
+ @Override
+ public void close() {
+ shell = null;
+ }
+
+ @Override
+ public FormType getFormType() {
+ return FormType.NATIVE;
+ }
+
+ @Override
+ public int getProgress(InterpreterContext context) {
+ return 0;
+ }
+
+ @Override
+ public Scheduler getScheduler() {
+ return SchedulerFactory.singleton()
+ .createOrGetParallelScheduler(GroovyInterpreter.class.getName() + this.hashCode(), 10);
+ }
+
+ private Job getRunningJob(String paragraphId) {
+ Job foundJob = null;
+ Collection<Job> jobsRunning = getScheduler().getJobsRunning();
+ for (Job job : jobsRunning) {
+ if (job.getId().equals(paragraphId)) {
+ foundJob = job;
+ }
+ }
+ return foundJob;
+ }
+
+ @Override
+ public List<InterpreterCompletion> completion(String buf, int cursor) {
+ return null;
+ }
+
+ @SuppressWarnings("unchecked")
+ Script getGroovyScript(String id, String scriptText) /*throws SQLException*/ {
+ if (shell == null) {
+ throw new RuntimeException("Groovy Shell is not initialized: null");
+ }
+ try {
+ Class<Script> clazz = scriptCache.get(scriptText);
+ if (clazz == null) {
+ String scriptName = id + "_" + Long.toHexString(scriptText.hashCode()) + ".groovy";
+ clazz = (Class<Script>) shell.parse(scriptText, scriptName).getClass();
+ scriptCache.put(scriptText, clazz);
+ }
+
+ Script script = (Script) clazz.newInstance();
+ return script;
+ } catch (Throwable t) {
+ throw new RuntimeException("Failed to parse groovy script: " + t, t);
+ }
+ }
+
+ private static Set<String> predefinedBindings = new HashSet<String>();
+
+ static {
+ predefinedBindings.add("g");
+ predefinedBindings.add("out");
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public InterpreterResult interpret(String cmd, InterpreterContext contextInterpreter) {
+ try {
+ Script script = getGroovyScript(contextInterpreter.getParagraphId(), cmd);
+ Job runningJob = getRunningJob(contextInterpreter.getParagraphId());
+ runningJob.info()
+ .put("CURRENT_THREAD", Thread.currentThread()); //to be able to terminate thread
+ Map<String, Object> bindings = script.getBinding().getVariables();
+ bindings.clear();
+ StringWriter out = new StringWriter((int) (cmd.length() * 1.75));
+ //put shared bindings evaluated in this interpreter
+ bindings.putAll(sharedBindings);
+ //put predefined bindings
+ bindings.put("g", new GObject(log, out, this.getProperty(), contextInterpreter, bindings));
+ bindings.put("out", new PrintWriter(out, true));
+
+ script.run();
+ //let's get shared variables defined in current script and store them in shared map
+ for (Map.Entry<String, Object> e : bindings.entrySet()) {
+ if (!predefinedBindings.contains(e.getKey())) {
+ if (log.isTraceEnabled()) {
+ log.trace("groovy script variable " + e); //let's see what we have...
+ }
+ sharedBindings.put(e.getKey(), e.getValue());
+ }
+ }
+
+ bindings.clear();
+ InterpreterResult result = new InterpreterResult(Code.SUCCESS, out.toString());
+ return result;
+ } catch (Throwable t) {
+ t = StackTraceUtils.deepSanitize(t);
+ String msg = t.toString() + "\n at " + t.getStackTrace()[0];
+ log.error("Failed to run script: " + t + "\n" + cmd + "\n", t);
+ return new InterpreterResult(Code.ERROR, msg);
+ }
+ }
+
+
+ @Override
+ public void cancel(InterpreterContext context) {
+ 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.dumpStack();
+ t.interrupt();
+ //t.stop(); //TODO: need some way to terminate maybe through GObject..
+ } catch (Throwable t) {
+ log.error("Failed to cancel script: " + t, t);
+ }
+ }
+ }
+ }
+
+
+}
http://git-wip-us.apache.org/repos/asf/zeppelin/blob/53a28a3a/groovy/src/main/resources/HTTP.groovy
----------------------------------------------------------------------
diff --git a/groovy/src/main/resources/HTTP.groovy b/groovy/src/main/resources/HTTP.groovy
new file mode 100644
index 0000000..fe4eb36
--- /dev/null
+++ b/groovy/src/main/resources/HTTP.groovy
@@ -0,0 +1,154 @@
+/*
+ * 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.
+ */
+
+import groovy.json.JsonOutput
+
+/**
+ * simple http rest client for groovy
+ * by dlukyanov@ukr.net
+ */
+@groovy.transform.CompileStatic
+public class HTTP{
+ //default response handler
+ public static Closure TEXT_RECEIVER = {InputStream instr,Map ctx->
+ return instr.getText( (String)ctx.encoding );
+ }
+
+ public static Closure JSON_RECEIVER = { InputStream instr, Map ctx->
+ return new groovy.json.JsonSlurper().parse(instr,(String)ctx.encoding);
+ }
+
+ public static Closure FILE_RECEIVER(File f){
+ return { InputStream instr, Map ctx->
+ f<<instr;
+ return f;
+ }
+ }
+
+ public static Map<String,Object> get(Map<String,Object> ctx)throws IOException{
+ ctx.put('method','GET');
+ return send(ctx);
+ }
+
+ public static Map<String,Object> post(Map<String,Object> ctx)throws IOException{
+ ctx.put('method','POST');
+ return send(ctx);
+ }
+
+ public static Map<String,Object> put(Map<String,Object> ctx)throws IOException{
+ ctx.put('method','PUT');
+ return send(ctx);
+ }
+
+ public static Map<String,Object> delete(Map<String,Object> ctx)throws IOException{
+ ctx.put('method','DELETE');
+ return send(ctx);
+ }
+
+ public static Map<String,Object> send(Map<String,Object> ctx)throws IOException{
+ String url = ctx.url;
+ Map<String,String> headers = (Map<String,String>)ctx.headers;
+ String method = ctx.method;
+ Object body = ctx.body;
+ String encoding = ctx.encoding?:"UTF-8";
+ Closure receiver = (Closure)ctx.receiver;
+ Map<String,String> query = (Map<String,String>)ctx.query;
+
+ //copy context and set default values
+ ctx = [:] + ctx;
+ ctx.encoding = encoding;
+ String contentType="";
+
+ if(query){
+ url+="?"+query.collect{k,v-> k+"="+URLEncoder.encode(v,'UTF-8') }.join('&')
+ }
+
+ HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
+
+ connection.setDoOutput(true);
+ connection.setRequestMethod(method);
+ if ( headers!=null && !headers.isEmpty() ) {
+ //add headers
+ for (Map.Entry<String, String> entry : headers.entrySet()) {
+ connection.addRequestProperty(entry.getKey(), entry.getValue());
+ if("content-type".equals(entry.getKey().toLowerCase()))contentType=entry.getValue();
+ }
+ }
+
+ if(body!=null){
+ //write body
+ OutputStream out = connection.getOutputStream();
+ if( body instanceof Closure ){
+ ((Closure)body).call(out, ctx);
+ }else if(body instanceof InputStream){
+ out << (InputStream)body;
+ }else if(body instanceof Map){
+ if( contentType.matches("(?i)[^/]+/json") ){
+ out.withWriter((String)ctx.encoding){
+ it.append( JsonOutput.toJson((Map)body) );
+ it.flush();
+ }
+ }else{
+ throw new IOException("Map body type supported only for */json content-type");
+ }
+ }else if(body instanceof CharSequence){
+ out.withWriter((String)ctx.encoding){
+ it.append((CharSequence)body);
+ it.flush();
+ }
+ }else{
+ throw new IOException("Unsupported body type: "+body.getClass());
+ }
+ out.flush();
+ out.close();
+ out=null;
+ }
+
+ Map response = [:];
+ ctx.response = response;
+ response.code = connection.getResponseCode();
+ response.message = connection.getResponseMessage();
+ response.headers = connection.getHeaderFields();
+
+ InputStream instr = null;
+
+ if( ((int)response.code)>=400 ){
+ try{
+ instr = connection.getErrorStream();
+ }catch(Exception ei){}
+ }else{
+ try{
+ instr = connection.getInputStream();
+ }catch(java.io.IOException ei){
+ throw new IOException("fail to open InputStream for http code "+response.code+":"+ei);
+ }
+ }
+
+ if(instr!=null) {
+ instr = new BufferedInputStream(instr);
+ if(receiver==null){
+ if( response.headers['Content-Type']?.toString()?.indexOf('/json')>0 ){
+ receiver=JSON_RECEIVER;
+ } else receiver=TEXT_RECEIVER;
+ }
+ response.body = receiver(instr,ctx);
+ instr.close();
+ instr=null;
+ }
+ return ctx;
+ }
+}
http://git-wip-us.apache.org/repos/asf/zeppelin/blob/53a28a3a/groovy/src/main/resources/interpreter-setting.json
----------------------------------------------------------------------
diff --git a/groovy/src/main/resources/interpreter-setting.json b/groovy/src/main/resources/interpreter-setting.json
new file mode 100644
index 0000000..552f600
--- /dev/null
+++ b/groovy/src/main/resources/interpreter-setting.json
@@ -0,0 +1,15 @@
+[
+ {
+ "group": "groovy",
+ "name": "groovy",
+ "className": "org.apache.zeppelin.groovy.GroovyInterpreter",
+ "properties": {
+ "GROOVY_CLASSES": {
+ "envName": null,
+ "propertyName": "GROOVY_CLASSES",
+ "defaultValue": "",
+ "description": "The path for custom groovy classes location. If empty `./interpreter/groovy/classes`"
+ }
+ }
+ }
+]
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/zeppelin/blob/53a28a3a/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index af2bdf7..5a15221 100644
--- a/pom.xml
+++ b/pom.xml
@@ -56,6 +56,7 @@
<module>zeppelin-zengine</module>
<module>zeppelin-display</module>
<module>spark-dependencies</module>
+ <module>groovy</module>
<module>spark</module>
<module>markdown</module>
<module>angular</module>
http://git-wip-us.apache.org/repos/asf/zeppelin/blob/53a28a3a/zeppelin-zengine/src/main/java/org/apache/zeppelin/conf/ZeppelinConfiguration.java
----------------------------------------------------------------------
diff --git a/zeppelin-zengine/src/main/java/org/apache/zeppelin/conf/ZeppelinConfiguration.java b/zeppelin-zengine/src/main/java/org/apache/zeppelin/conf/ZeppelinConfiguration.java
index 55f502c..4331b72 100644
--- a/zeppelin-zengine/src/main/java/org/apache/zeppelin/conf/ZeppelinConfiguration.java
+++ b/zeppelin-zengine/src/main/java/org/apache/zeppelin/conf/ZeppelinConfiguration.java
@@ -593,7 +593,9 @@ public class ZeppelinConfiguration extends XMLConfiguration {
+ "org.apache.zeppelin.hbase.HbaseInterpreter,"
+ "org.apache.zeppelin.bigquery.BigQueryInterpreter,"
+ "org.apache.zeppelin.beam.BeamInterpreter,"
- + "org.apache.zeppelin.scio.ScioInterpreter"),
+ + "org.apache.zeppelin.scio.ScioInterpreter,"
+ + "org.apache.zeppelin.groovy.GroovyInterpreter"
+ ),
ZEPPELIN_INTERPRETER_JSON("zeppelin.interpreter.setting", "interpreter-setting.json"),
ZEPPELIN_INTERPRETER_DIR("zeppelin.interpreter.dir", "interpreter"),
ZEPPELIN_INTERPRETER_LOCALREPO("zeppelin.interpreter.localRepo", "local-repo"),
@@ -603,7 +605,7 @@ public class ZeppelinConfiguration extends XMLConfiguration {
ZEPPELIN_INTERPRETER_MAX_POOL_SIZE("zeppelin.interpreter.max.poolsize", 10),
ZEPPELIN_INTERPRETER_GROUP_ORDER("zeppelin.interpreter.group.order", "spark,md,angular,sh,"
+ "livy,alluxio,file,psql,flink,python,ignite,lens,cassandra,geode,kylin,elasticsearch,"
- + "scalding,jdbc,hbase,bigquery,beam,pig,scio"),
+ + "scalding,jdbc,hbase,bigquery,beam,pig,scio,groovy"),
ZEPPELIN_INTERPRETER_OUTPUT_LIMIT("zeppelin.interpreter.output.limit", 1024 * 100),
ZEPPELIN_ENCODING("zeppelin.encoding", "UTF-8"),
ZEPPELIN_NOTEBOOK_DIR("zeppelin.notebook.dir", "notebook"),