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"),