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 <dlukya...@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 <dlukya...@ukr.net> Authored: Thu Mar 30 20:29:00 2017 +0300 Committer: ahyoungryu <ahyoung...@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 dlukya...@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"),