Merge branch 'master' into ZEPPELIN-732-up

This commit is contained in:
Lee moon soo 2016-06-28 19:19:10 -07:00
commit c714a1950c
38 changed files with 923 additions and 578 deletions

45
bin/install-interpreter.sh Executable file
View file

@ -0,0 +1,45 @@
#!/bin/bash
#
# 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.
#
# Run Zeppelin
#
bin=$(dirname "${BASH_SOURCE-$0}")
bin=$(cd "${bin}">/dev/null; pwd)
. "${bin}/common.sh"
ZEPPELIN_INSTALL_INTERPRETER_MAIN=org.apache.zeppelin.interpreter.install.InstallInterpreter
ZEPPELIN_LOGFILE="${ZEPPELIN_LOG_DIR}/install-interpreter.log"
JAVA_OPTS+=" -Dzeppelin.log.file=${ZEPPELIN_LOGFILE}"
if [[ -d "${ZEPPELIN_HOME}/zeppelin-zengine/target/classes" ]]; then
ZEPPELIN_CLASSPATH+=":${ZEPPELIN_HOME}/zeppelin-zengine/target/classes"
fi
addJarInDir "${ZEPPELIN_HOME}/zeppelin-server/target/lib"
if [[ -d "${ZEPPELIN_HOME}/zeppelin-interpreter/target/classes" ]]; then
ZEPPELIN_CLASSPATH+=":${ZEPPELIN_HOME}/zeppelin-interpreter/target/classes"
fi
addJarInDir "${ZEPPELIN_HOME}/zeppelin-interpreter/target/lib"
addJarInDir "${ZEPPELIN_HOME}/lib"
CLASSPATH+=":${ZEPPELIN_CLASSPATH}"
$ZEPPELIN_RUNNER $JAVA_OPTS -cp $CLASSPATH $ZEPPELIN_INSTALL_INTERPRETER_MAIN ${@}

35
conf/interpreter-list Normal file
View file

@ -0,0 +1,35 @@
# 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.
#
#
# [name] [maven artifact] [description]
alluxio org.apache.zeppelin:zeppelin-alluxio:0.6.0 Alluxio interpreter
angular org.apache.zeppelin:zeppelin-angular:0.6.0 HTML and AngularJS view rendering
cassandra org.apache.zeppelin:zeppelin-cassandra:0.6.0 Cassandra interpreter
elasticsearch org.apache.zeppelin:zeppelin-elasticsearch:0.6.0 Elasticsearch interpreter
file org.apache.zeppelin:zeppelin-file:0.6.0 HDFS file interpreter
flink org.apache.zeppelin:zeppelin-flink:0.6.0 Flink interpreter
hbase org.apache.zeppelin:zeppelin-hbase:0.6.0 Hbase interpreter
ignite org.apache.zeppelin:zeppelin-ignite:0.6.0 Ignite interpreter
jdbc org.apache.zeppelin:zeppelin-jdbc:0.6.0 Jdbc interpreter
kylin org.apache.zeppelin:zeppelin-kylin:0.6.0 Kylin interpreter
lens org.apache.zeppelin:zeppelin-lens:0.6.0 Lens interpreter
livy org.apache.zeppelin:zeppelin-livy:0.6.0 Livy interpreter
md org.apache.zeppelin:zeppelin-markdown:0.6.0 Markdown support
postgresql org.apache.zeppelin:zeppelin-postgresql:0.6.0 Postgresql interpreter
python org.apache.zeppelin:zeppelin-python:0.6.0 Python interpreter
shell org.apache.zeppelin:zeppelin-shell:0.6.0 Shell command

View file

@ -55,12 +55,13 @@ REM set HADOOP_CONF_DIR REM yarn-site.xml is located in configuration
REM Pyspark (supported with Spark 1.2.1 and above)
REM To configure pyspark, you need to set spark distribution's path to 'spark.home' property in Interpreter setting screen in Zeppelin GUI
REM set PYSPARK_PYTHON REM path to the python command. must be the same path on the driver(Zeppelin) and all workers.
REM set PYTHONPATH
REM set PYTHONPATH
REM Spark interpreter options
REM
REM set ZEPPELIN_SPARK_USEHIVECONTEXT REM Use HiveContext instead of SQLContext if set true. true by default.
REM set ZEPPELIN_SPARK_CONCURRENTSQL REM Execute multiple SQL concurrently if set true. false by default.
REM set ZEPPELIN_SPARK_IMPORTIMPLICIT REM Import implicits, UDF collection, and sql if set true. true by default.
REM set ZEPPELIN_SPARK_MAXRESULT REM Max number of SparkSQL result to display. 1000 by default.
REM ZeppelinHub connection configuration

View file

@ -55,15 +55,17 @@
# Pyspark (supported with Spark 1.2.1 and above)
# To configure pyspark, you need to set spark distribution's path to 'spark.home' property in Interpreter setting screen in Zeppelin GUI
# export PYSPARK_PYTHON # path to the python command. must be the same path on the driver(Zeppelin) and all workers.
# export PYTHONPATH
# export PYTHONPATH
## Spark interpreter options ##
##
# export ZEPPELIN_SPARK_USEHIVECONTEXT # Use HiveContext instead of SQLContext if set true. true by default.
# export ZEPPELIN_SPARK_CONCURRENTSQL # Execute multiple SQL concurrently if set true. false by default.
# export ZEPPELIN_SPARK_IMPORTIMPLICIT # Import implicits, UDF collection, and sql if set true. true by default.
# export ZEPPELIN_SPARK_MAXRESULT # Max number of SparkSQL result to display. 1000 by default.
# export ZEPPELIN_WEBSOCKET_MAX_TEXT_MESSAGE_SIZE # Size in characters of the maximum text message to be received by websocket. Defaults to 1024000
#### HBase interpreter configuration ####
## To connect to HBase running on a cluster, either HBASE_HOME or HBASE_CONF_DIR must be set
@ -75,4 +77,3 @@
# export ZEPPELINHUB_API_ADDRESS # Refers to the address of the ZeppelinHub service in use
# export ZEPPELINHUB_API_TOKEN # Refers to the Zeppelin instance token of the user
# export ZEPPELINHUB_USER_KEY # Optional, when using Zeppelin with authentication.

View file

@ -103,6 +103,7 @@ function make_binary_release() {
git_clone
make_source_package
make_binary_release all "-Pspark-1.6 -Phadoop-2.4 -Pyarn -Ppyspark -Psparkr -Pr"
make_binary_release netinst "-Pspark-1.6 -Phadoop-2.4 -Pyarn -Ppyspark -pl !alluxio,!angular,!cassandra,!elasticsearch,!file,!flink,!hbase,!ignite,!jdbc,!kylin,!lens,!livy,!markdown,!postgresql,!python,!shell"
# remove non release files and dirs
rm -rf "${WORKING_DIR}/zeppelin"

View file

@ -21,8 +21,8 @@
<li><a href="{{BASE_PATH}}/index.html">What is Apache Zeppelin ?</a></li>
<li role="separator" class="divider"></li>
<li class="title"><span><b>Getting Started</b><span></li>
<li><a href="{{BASE_PATH}}/install/install.html">Quick Start</a></li>
<li><a href="{{BASE_PATH}}/install/install.html#zeppelin-configuration">Configuration</a></li>
<li><a href="{{BASE_PATH}}/install/install.html">Install</a></li>
<li><a href="{{BASE_PATH}}/install/install.html#apache-zeppelin-configuration">Configuration</a></li>
<li><a href="{{BASE_PATH}}/quickstart/explorezeppelinui.html">Explore Zeppelin UI</a></li>
<li><a href="{{BASE_PATH}}/quickstart/tutorial.html">Tutorial</a></li>
<li role="separator" class="divider"></li>
@ -42,6 +42,7 @@
<li><a href="{{BASE_PATH}}/manual/interpreters.html">Overview</a></li>
<li role="separator" class="divider"></li>
<li class="title"><span><b>Usage</b><span></li>
<li><a href="{{BASE_PATH}}/manual/interpreterinstallation.html">Interpreter Installation</a></li>
<li><a href="{{BASE_PATH}}/manual/dynamicinterpreterload.html">Dynamic Interpreter Loading</a></li>
<li><a href="{{BASE_PATH}}/manual/dependencymanagement.html">Interpreter Dependency Management</a></li>
<li role="separator" class="divider"></li>
@ -111,3 +112,4 @@
</nav><!--/.navbar-collapse -->
</div>
</div>

View file

@ -60,6 +60,9 @@ Although it can be unstable somehow since it is on development status, you can e
### Downloading Binary Package
If you want to install Apache Zeppelin with a stable binary package, please visit [Apache Zeppelin download Page](http://zeppelin.apache.org/download.html).
If you have downloaded `netinst` binary, [install additional interpreters](../manual/interpreterinstallation.html) before you start Zeppelin. Or simply run `./bin/install-interpreter.sh --all`.
After unpacking, jump to [Starting Apache Zeppelin with Command Line](#starting-apache-zeppelin-with-command-line) section.
### Building from Source
@ -388,4 +391,4 @@ You can configure Apache Zeppelin with both **environment variables** in `conf/z
<td>1024000</td>
<td>Size in characters of the maximum text message to be received by websocket.</td>
</tr>
</table>
</table>

View file

@ -83,7 +83,7 @@ plt.figure()
z.show(plt)
plt.close()
```
zeppelin_show function can take optional parameters to adapt graph width and height
z.show function can take optional parameters to adapt graph width and height
```python
%python

View file

@ -45,7 +45,7 @@ Spark Interpreter group, which consists of five interpreters.
</table>
## Configuration
The Spark interpreter can be configured with properties provided by Zeppelin.
The Spark interpreter can be configured with properties provided by Zeppelin.
You can also set other Spark properties which are not listed in the table. For a list of additional properties, refer to [Spark Available Properties](http://spark.apache.org/docs/latest/configuration.html#available-properties).
<table class="table-configuration">
<tr>
@ -111,6 +111,11 @@ You can also set other Spark properties which are not listed in the table. For a
<td>true</td>
<td>Use HiveContext instead of SQLContext if it is true.</td>
</tr>
<tr>
<td>zeppelin.spark.importImplicit</td>
<td>true</td>
<td>Import implicits, UDF collection, and sql if set true.</td>
</tr>
</table>
Without any configuration, Spark interpreter works out of box in local mode. But if you want to connect to your Spark cluster, you'll need to follow below two simple steps.

View file

@ -0,0 +1,164 @@
---
layout: page
title: "Interpreter Installation"
description: ""
group: manual
---
<!--
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 %}
# Interpreter Installation
Apache Zeppelin provides **Interpreter Installation** mechanism for whom downloaded Zeppelin `netinst` binary package, or just want to install another 3rd party interpreters.
## Community managed interpreters
Apache Zeppelin provides several interpreters as [community managed interpreters](#available-community-managed-interpreters).
If you downloaded `netinst` binary package, you need to install by using below commands.
#### Install all community managed interpreters
```
./bin/install-interpreter.sh --all
```
#### Install specific interpreters
```
./bin/install-interpreter.sh --name md,shell,jdbc,python
```
You can get full list of community managed interpreters by running
```
./bin/install-interpreter.sh --list
```
Once you have installed interpreters, you need to restart Zeppelin. And then [create interpreter setting](../manual/interpreters.html#what-is-zeppelin-interpreter) and [bind it with your notebook](../manual/interpreters.html#what-is-zeppelin-interpreter-setting).
## 3rd party interpreters
You can also install 3rd party interpreters located in the maven repository by using below commands.
#### Install 3rd party interpreters
```
./bin/install-interpreter.sh --name interpreter1 --artifact groupId1:artifact1:version1
```
The above command will download maven artifact `groupId1:artifact1:version1` and all of it's transitive dependencies into `interpreter/interpreter1` directory.
Once you have installed interpreters, you'll need to add interpreter class name into `zeppelin.interpreters` property in [configuration](../install/install.html#apache-zeppelin-configuration).
And then restart Zeppelin, [create interpreter setting](../manual/interpreters.html#what-is-zeppelin-interpreter) and [bind it with your notebook](../manual/interpreters.html#what-is-zeppelin-interpreter-setting).
#### Install multiple 3rd party interpreters at once
```
./bin/install-interpreter.sh --name interpreter1,interpreter2 --artifact groupId1:artifact1:version1,groupId2:artifact2:version2
```
`--name` and `--artifact` arguments will recieve comma separated list.
## Available community managed interpreters
You can also find the below community managed interpreter list in `conf/interpreter-list` file.
<table class="table-configuration">
<tr>
<th>Name</th>
<th>Maven Artifact</th>
<th>Description</th>
</tr>
<tr>
<td>alluxio</td>
<td>org.apache.zeppelin:zeppelin-alluxio:0.6.0</td>
<td>Alluxio interpreter</td>
</tr>
<tr>
<td>angular</td>
<td>org.apache.zeppelin:zeppelin-angular:0.6.0</td>
<td>HTML and AngularJS view rendering</td>
</tr>
<tr>
<td>cassandra</td>
<td>org.apache.zeppelin:zeppelin-cassandra:0.6.0</td>
<td>Cassandra interpreter</td>
</tr>
<tr>
<td>elasticsearch</td>
<td>org.apache.zeppelin:zeppelin-elasticsearch:0.6.0</td>
<td>Elasticsearch interpreter</td>
</tr>
<tr>
<td>file</td>
<td>org.apache.zeppelin:zeppelin-file:0.6.0</td>
<td>HDFS file interpreter</td>
</tr>
<tr>
<td>flink</td>
<td>org.apache.zeppelin:zeppelin-flink:0.6.0</td>
<td>Flink interpreter</td>
</tr>
<tr>
<td>hbase</td>
<td>org.apache.zeppelin:zeppelin-hbase:0.6.0</td>
<td>Hbase interpreter</td>
</tr>
<tr>
<td>ignite</td>
<td>org.apache.zeppelin:zeppelin-ignite:0.6.0</td>
<td>Ignite interpreter</td>
</tr>
<tr>
<td>jdbc</td>
<td>org.apache.zeppelin:zeppelin-jdbc:0.6.0</td>
<td>Jdbc interpreter</td>
</tr>
<tr>
<td>kylin</td>
<td>org.apache.zeppelin:zeppelin-kylin:0.6.0</td>
<td>Kylin interpreter</td>
</tr>
<tr>
<td>lens</td>
<td>org.apache.zeppelin:zeppelin-lens:0.6.0</td>
<td>Lens interpreter</td>
</tr>
<tr>
<td>livy</td>
<td>org.apache.zeppelin:zeppelin-livy:0.6.0</td>
<td>Livy interpreter</td>
</tr>
<tr>
<td>md</td>
<td>org.apache.zeppelin:zeppelin-markdown:0.6.0</td>
<td>Markdown support</td>
</tr>
<tr>
<td>postgresql</td>
<td>org.apache.zeppelin:zeppelin-postgresql:0.6.0</td>
<td>Postgresql interpreter</td>
</tr>
<tr>
<td>python</td>
<td>org.apache.zeppelin:zeppelin-python:0.6.0</td>
<td>Python interpreter</td>
</tr>
<tr>
<td>shell</td>
<td>org.apache.zeppelin:zeppelin-shell:0.6.0</td>
<td>Shell command</td>
</tr>
</table>

View file

@ -0,0 +1,14 @@
# 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.

View file

@ -116,7 +116,7 @@ public class PythonInterpreterTest {
assertTrue(cmdHistory.contains("def help()"));
assertTrue(cmdHistory.contains("class PyZeppelinContext(object):"));
assertTrue(cmdHistory.contains("z = PyZeppelinContext"));
assertTrue(cmdHistory.contains("z.show"));
assertTrue(cmdHistory.contains("def show"));
assertFalse(cmdHistory.contains("GatewayClient"));
}
@ -141,8 +141,8 @@ public class PythonInterpreterTest {
assertTrue(cmdHistory.contains("def help()"));
assertTrue(cmdHistory.contains("class PyZeppelinContext(object):"));
assertTrue(cmdHistory.contains("z = PyZeppelinContext"));
assertTrue(cmdHistory.contains("z.show"));
assertTrue(cmdHistory.contains("z = Py4jZeppelinContext"));
assertTrue(cmdHistory.contains("def show"));
assertTrue(cmdHistory.contains("GatewayClient(port=" + py4jPort + ")"));
assertTrue(cmdHistory.contains("org.apache.zeppelin.display.Input"));

View file

@ -178,6 +178,10 @@ public class SparkInterpreter extends Interpreter {
return java.lang.Boolean.parseBoolean(getProperty("zeppelin.spark.useHiveContext"));
}
private boolean importImplicit() {
return java.lang.Boolean.parseBoolean(getProperty("zeppelin.spark.importImplicit"));
}
public SQLContext getSQLContext() {
synchronized (sharedInterpreterLock) {
if (sqlc == null) {
@ -252,7 +256,7 @@ public class SparkInterpreter extends Interpreter {
| IllegalArgumentException | InvocationTargetException e) {
// continue instead of: throw new InterpreterException(e);
// Newer Spark versions (like the patched CDH5.7.0 one) don't contain this method
logger.warn(String.format("Spark method classServerUri not available due to: [%s]",
logger.warn(String.format("Spark method classServerUri not available due to: [%s]",
e.getMessage()));
}
}
@ -544,12 +548,14 @@ public class SparkInterpreter extends Interpreter {
+ "_binder.get(\"sqlc\").asInstanceOf[org.apache.spark.sql.SQLContext]");
intp.interpret("import org.apache.spark.SparkContext._");
if (sparkVersion.oldSqlContextImplicits()) {
intp.interpret("import sqlContext._");
} else {
intp.interpret("import sqlContext.implicits._");
intp.interpret("import sqlContext.sql");
intp.interpret("import org.apache.spark.sql.functions._");
if (importImplicit()) {
if (sparkVersion.oldSqlContextImplicits()) {
intp.interpret("import sqlContext._");
} else {
intp.interpret("import sqlContext.implicits._");
intp.interpret("import sqlContext.sql");
intp.interpret("import org.apache.spark.sql.functions._");
}
}
}

View file

@ -77,6 +77,12 @@
"propertyName": "zeppelin.spark.maxResult",
"defaultValue": "1000",
"description": "Max number of SparkSQL result to display."
},
"zeppelin.spark.importImplicit": {
"envName": "ZEPPELIN_SPARK_IMPORTIMPLICIT",
"propertyName": "zeppelin.spark.importImplicit",
"defaultValue": "true",
"description": "Import implicits, UDF collection, and sql if set true. true by default."
}
}
},

View file

@ -70,6 +70,7 @@ public class SparkInterpreterTest {
p.setProperty("spark.app.name", "Zeppelin Test");
p.setProperty("zeppelin.spark.useHiveContext", "true");
p.setProperty("zeppelin.spark.maxResult", "1000");
p.setProperty("zeppelin.spark.importImplicit", "true");
return p;
}
@ -229,4 +230,35 @@ public class SparkInterpreterTest {
repl2.close();
}
@Test
public void testEnableImplicitImport() {
// Set option of importing implicits to "true", and initialize new Spark repl
Properties p = getSparkTestProperties();
p.setProperty("zeppelin.spark.importImplicit", "true");
SparkInterpreter repl2 = new SparkInterpreter(p);
repl2.setInterpreterGroup(intpGroup);
intpGroup.get("note").add(repl2);
repl2.open();
String ddl = "val df = Seq((1, true), (2, false)).toDF(\"num\", \"bool\")";
assertEquals(Code.SUCCESS, repl2.interpret(ddl, context).code());
repl2.close();
}
@Test
public void testDisableImplicitImport() {
// Set option of importing implicits to "false", and initialize new Spark repl
// this test should return error status when creating DataFrame from sequence
Properties p = getSparkTestProperties();
p.setProperty("zeppelin.spark.importImplicit", "false");
SparkInterpreter repl2 = new SparkInterpreter(p);
repl2.setInterpreterGroup(intpGroup);
intpGroup.get("note").add(repl2);
repl2.open();
String ddl = "val df = Seq((1, true), (2, false)).toDF(\"num\", \"bool\")";
assertEquals(Code.ERROR, repl2.interpret(ddl, context).code());
repl2.close();
}
}

View file

@ -17,6 +17,7 @@
package org.apache.zeppelin.dep;
import java.net.URL;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedList;
@ -25,6 +26,7 @@ import java.util.List;
import org.sonatype.aether.RepositorySystem;
import org.sonatype.aether.RepositorySystemSession;
import org.sonatype.aether.repository.Authentication;
import org.sonatype.aether.repository.Proxy;
import org.sonatype.aether.repository.RemoteRepository;
import org.sonatype.aether.repository.RepositoryPolicy;
import org.sonatype.aether.resolution.ArtifactResult;
@ -44,6 +46,16 @@ public abstract class AbstractDependencyResolver {
repos.add(Booter.newLocalRepository());
}
public void setProxy(URL proxyUrl, String proxyUser, String proxyPassword) {
Authentication auth = new Authentication(proxyUser, proxyPassword);
Proxy proxy = new Proxy(proxyUrl.getProtocol(), proxyUrl.getHost(), proxyUrl.getPort(), auth);
synchronized (repos) {
for (RemoteRepository repo : repos) {
repo.setProxy(proxy);
}
}
}
public List<RemoteRepository> getRepos() {
return this.repos;
}

View file

@ -19,6 +19,7 @@ package org.apache.zeppelin.dep;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
@ -63,11 +64,6 @@ public class DependencyResolver extends AbstractDependencyResolver {
return load(artifact, new LinkedList<String>());
}
public List<File> load(String artifact, String destPath)
throws RepositoryException, IOException {
return load(artifact, new LinkedList<String>(), destPath);
}
public synchronized List<File> load(String artifact, Collection<String> excludes)
throws RepositoryException, IOException {
if (StringUtils.isBlank(artifact)) {
@ -86,24 +82,11 @@ public class DependencyResolver extends AbstractDependencyResolver {
}
}
private String getPath(String path) {
if (path.startsWith("/")) {
return path;
} else {
// find home dir
String home = System.getenv("ZEPPELIN_HOME");
if (home == null) {
home = System.getProperty("zeppelin.home");
}
if (home == null) {
home = "..";
}
return home + "/" + path;
}
public List<File> load(String artifact, File destPath) throws IOException, RepositoryException {
return load(artifact, new LinkedList<String>(), destPath);
}
public List<File> load(String artifact, Collection<String> excludes, String destPath)
public List<File> load(String artifact, Collection<String> excludes, File destPath)
throws RepositoryException, IOException {
List<File> libs = new LinkedList<File>();
@ -111,7 +94,7 @@ public class DependencyResolver extends AbstractDependencyResolver {
libs = load(artifact, excludes);
for (File srcFile : libs) {
File destFile = new File(getPath(destPath), srcFile.getName());
File destFile = new File(destPath, srcFile.getName());
if (!destFile.exists() || !FileUtils.contentEquals(srcFile, destFile)) {
FileUtils.copyFile(srcFile, destFile);
logger.info("copy {} to {}", srcFile.getAbsolutePath(), getPath(destPath));

View file

@ -33,27 +33,20 @@ import org.sonatype.aether.RepositoryException;
public class DependencyResolverTest {
private static DependencyResolver resolver;
private static String testPath;
private static String testCopyPath;
private static String home;
private static File testCopyPath;
private static File tmpDir;
@BeforeClass
public static void setUp() throws Exception {
testPath = "test-repo";
testCopyPath = "test-copy-repo";
tmpDir = new File(System.getProperty("java.io.tmpdir")+"/ZeppelinLTest_"+System.currentTimeMillis());
testPath = tmpDir.getAbsolutePath() + "/test-repo";
testCopyPath = new File(tmpDir, "test-copy-repo");
resolver = new DependencyResolver(testPath);
home = System.getenv("ZEPPELIN_HOME");
if (home == null) {
home = System.getProperty("zeppelin.home");
}
if (home == null) {
home = "..";
}
}
@AfterClass
public static void tearDown() throws Exception {
FileUtils.deleteDirectory(new File(home + "/" + testPath));
FileUtils.deleteDirectory(new File(home + "/" + testCopyPath));
FileUtils.deleteDirectory(tmpDir);
}
@Rule
@ -78,19 +71,19 @@ public class DependencyResolverTest {
public void testLoad() throws Exception {
// basic load
resolver.load("com.databricks:spark-csv_2.10:1.3.0", testCopyPath);
assertEquals(new File(home + "/" + testCopyPath).list().length, 4);
FileUtils.cleanDirectory(new File(home + "/" + testCopyPath));
assertEquals(testCopyPath.list().length, 4);
FileUtils.cleanDirectory(testCopyPath);
// load with exclusions parameter
resolver.load("com.databricks:spark-csv_2.10:1.3.0",
Collections.singletonList("org.scala-lang:scala-library"), testCopyPath);
assertEquals(new File(home + "/" + testCopyPath).list().length, 3);
FileUtils.cleanDirectory(new File(home + "/" + testCopyPath));
assertEquals(testCopyPath.list().length, 3);
FileUtils.cleanDirectory(testCopyPath);
// load from added repository
resolver.addRepo("sonatype", "https://oss.sonatype.org/content/repositories/agimatec-releases/", false);
resolver.load("com.agimatec:agimatec-validation:0.9.3", testCopyPath);
assertEquals(new File(home + "/" + testCopyPath).list().length, 8);
assertEquals(testCopyPath.list().length, 8);
// load invalid artifact
resolver.delRepo("sonatype");

View file

@ -256,13 +256,6 @@
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.3.6</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.scalatest</groupId>
<artifactId>scalatest_2.10</artifactId>

View file

@ -79,8 +79,7 @@ public class NotebookServer extends WebSocketServlet implements
}
private static final Logger LOG = LoggerFactory.getLogger(NotebookServer.class);
Gson gson = new GsonBuilder()
.setDateFormat("yyyy-MM-dd'T'HH:mm:ssZ").create();
Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd'T'HH:mm:ssZ").create();
final Map<String, List<NotebookSocket>> noteSocketMap = new HashMap<>();
final Queue<NotebookSocket> connectedSockets = new ConcurrentLinkedQueue<>();

View file

@ -125,8 +125,7 @@ public class WebDriverManager {
(new WebDriverWait(driver, 5)).until(new ExpectedCondition<Boolean>() {
@Override
public Boolean apply(WebDriver d) {
return d.findElement(By.xpath(
"//div[contains(@class, 'navbar-collapse')]//li//a[contains(.,'Connected')]"))
return d.findElement(By.xpath("//i[@tooltip='WebSocket Connected']"))
.isDisplayed();
}
});

View file

@ -158,8 +158,8 @@ public class AuthenticationIT extends AbstractZeppelinIT {
String noteId = driver.getCurrentUrl().substring(driver.getCurrentUrl().lastIndexOf("/") + 1);
pollingWait(By.xpath("//button[@tooltip='Note permissions']"),
MAX_BROWSER_TIMEOUT_SEC).sendKeys(Keys.ENTER);
pollingWait(By.xpath("//span[@tooltip='Note permissions']"),
MAX_BROWSER_TIMEOUT_SEC).click();
pollingWait(By.xpath("//input[@ng-model='permissions.owners']"), MAX_BROWSER_TIMEOUT_SEC)
.sendKeys("finance");
pollingWait(By.xpath("//input[@ng-model='permissions.readers']"), MAX_BROWSER_TIMEOUT_SEC)

View file

@ -196,7 +196,9 @@ public class ZeppelinIT extends AbstractZeppelinIT {
}
try {
// navigate to interpreter page
WebElement interpreterLink = driver.findElement(By.xpath("//a[contains(.,'Interpreter')]"));
WebElement settingButton = driver.findElement(By.xpath("//button[@class='nav-btn dropdown-toggle ng-scope']"));
settingButton.click();
WebElement interpreterLink = driver.findElement(By.xpath("//a[@href='#/interpreter']"));
interpreterLink.click();
// add new dependency to spark interpreter
@ -235,6 +237,7 @@ public class ZeppelinIT extends AbstractZeppelinIT {
sleep(1000, false);
// reset dependency
settingButton.click();
interpreterLink.click();
driver.findElement(By.xpath("//div[@id='spark']//button[contains(.,'edit')]")).sendKeys(Keys.ENTER);
WebElement testDepRemoveBtn = pollingWait(By.xpath("//tr[descendant::text()[contains(.,'" +

View file

@ -127,8 +127,9 @@ public abstract class AbstractTestRestApi {
}
}
// set spark master
// set spark master and other properties
sparkIntpSetting.getProperties().setProperty("master", "spark://" + getHostname() + ":7071");
sparkIntpSetting.getProperties().setProperty("spark.cores.max", "2");
// set spark home for pyspark
sparkIntpSetting.getProperties().setProperty("spark.home", getSparkHome());

View file

@ -242,10 +242,6 @@ a.navbar-brand:hover {
background: #080808;
}
.server-status {
float: right;
}
.navbar-inverse .navbar-nav .open .dropdown-menu .divider {
background: #3071A9;
}
@ -272,20 +268,43 @@ a.navbar-brand:hover {
}
}
i.server-status {
font-size: 12px;
top: -2px;
position: relative;
.nav-component {
margin-top: 8px;
}
.nav-btn {
color: #fff;
background-color: transparent;
border-color: transparent;
font-size: 14px;
}
.nav-login-btn,
.nav-login-btn:hover,
.nav-login-btn:focus {
color: #fff;
background-color: #428bca;
border-color: #357ebd;
}
.username {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
max-width: 120px;
display: inline-block;
}
.server-connected {
padding-top: 12px;
color: #00CC00;
font-size: 12px !important;
}
.server-disconnected {
padding-top: 12px;
color: rgba(240, 48, 0, 1);
font-size: 12px !important;
font-weight: bold !important;
}
.box {

View file

@ -153,26 +153,24 @@ limitations under the License.
</span>
<div class="pull-right" style="margin-top:15px; margin-right:15px; font-size:15px;">
<span>
<button type="button"
class="btn btn-default btn-xs"
<span class="setting-btn"
type="button"
data-toggle="modal"
data-target="#shortcutModal"
tooltip-placement="bottom" tooltip="List of shortcut">
<i class="fa fa-keyboard-o"></i>
</button>
<button type="button"
class="btn btn-default btn-xs"
<i class="fa fa-keyboard-o"></i>
</span>
<span class="setting-btn"
type="button"
ng-click="toggleSetting()"
tooltip-placement="bottom" tooltip="Interpreter binding">
<i class="fa fa-cog" ng-style="{color: showSetting ? '#3071A9' : 'black' }"></i>
</button>
<button type="button"
class="btn btn-default btn-xs"
<i class="fa fa-cog" ng-style="{color: showSetting ? '#3071A9' : 'black' }"></i>
</span>
<span class="setting-btn"
type="button"
ng-click="togglePermissions()"
tooltip-placement="bottom" tooltip="Note permissions">
<i class="fa fa-lock" ng-style="{color: showPermissions ? '#3071A9' : 'black' }"></i>
</button>
<i class="fa fa-lock" ng-style="{color: showPermissions ? '#3071A9' : 'black' }"></i>
</span>
<span class="btn-group">

View file

@ -223,6 +223,13 @@
padding-left: 5px;
}
.setting-btn {
position: relative;
top: 2px;
margin-right: 4px;
cursor: pointer;
}
.cron-preset-container {
padding: 10px 20px 0 20px;
font-weight: normal;

View file

@ -30,7 +30,7 @@ angular.module('zeppelinWebApp')
return notebook;
}
if (notebook.children) {
if (notebook.children) {
filteringNote(notebook.children, filteredNotes);
}
});
@ -63,7 +63,6 @@ angular.module('zeppelinWebApp')
}, 500);
};
var vm = this;
vm.notes = notebookListDataFactory;
vm.connected = websocketMsgSrv.isConnected();
@ -71,13 +70,6 @@ angular.module('zeppelinWebApp')
vm.arrayOrderingSrv = arrayOrderingSrv;
$scope.searchForm = searchService;
if ($rootScope.ticket) {
$rootScope.fullUsername = $rootScope.ticket.principal;
$rootScope.truncatedUsername = $rootScope.ticket.principal;
}
var MAX_USERNAME_LENGTH=16;
angular.element('#notebook-list').perfectScrollbar({suppressScrollX: true});
$scope.$on('setNoteMenu', function(event, notes) {
@ -88,43 +80,36 @@ angular.module('zeppelinWebApp')
vm.connected = param;
});
$scope.checkUsername = function () {
if ($rootScope.ticket) {
if ($rootScope.ticket.principal.length <= MAX_USERNAME_LENGTH) {
$rootScope.truncatedUsername = $rootScope.ticket.principal;
}
else {
$rootScope.truncatedUsername = $rootScope.ticket.principal.substr(0, MAX_USERNAME_LENGTH) + '..';
}
}
if (_.isEmpty($rootScope.truncatedUsername)) {
$rootScope.truncatedUsername = 'Connected';
}
};
$scope.$on('loginSuccess', function(event, param) {
$scope.checkUsername();
loadNotes();
});
$scope.logout = function() {
$http.post(baseUrlSrv.getRestApiBase()+'/login/logout')
.success(function(data, status, headers, config) {
$rootScope.userName = '';
$rootScope.ticket.principal = '';
$rootScope.ticket.ticket = '';
$rootScope.ticket.roles = '';
BootstrapDialog.show({
message: 'Logout Success'
});
setTimeout(function() {
window.location = '#';
window.location.reload();
}, 1000);
}).
error(function(data, status, headers, config) {
console.log('Error %o %o', status, data.message);
});
var logoutURL = baseUrlSrv.getRestApiBase() + '/login/logout';
var request = new XMLHttpRequest();
//force authcBasic (if configured) to logout by setting credentials as false:false
request.open('post', logoutURL, true, 'false', 'false');
request.onreadystatechange = function() {
if (request.readyState === 4) {
if (request.status === 401 || request.status === 405) {
$rootScope.userName = '';
$rootScope.ticket.principal = '';
$rootScope.ticket.ticket = '';
$rootScope.ticket.roles = '';
BootstrapDialog.show({
message: 'Logout Success'
});
setTimeout(function() {
window.location.replace('/');
}, 1000);
} else {
request.open('post', logoutURL, true, 'false', 'false');
request.send();
}
}
};
request.send();
};
$scope.search = function(searchTerm) {
@ -146,7 +131,6 @@ angular.module('zeppelinWebApp')
};
function getZeppelinVersion() {
console.log('version');
$http.get(baseUrlSrv.getRestApiBase() + '/version').success(
function(data, status, headers, config) {
$rootScope.zeppelinVersion = data.body;
@ -161,6 +145,5 @@ angular.module('zeppelinWebApp')
getZeppelinVersion();
vm.loadNotes();
$scope.checkUsername();
});

View file

@ -44,24 +44,15 @@ limitations under the License.
<li class="divider"></li>
<div id="notebook-list" class="scrollbar-container">
<li class="filter-names" ng-include="'components/filterNoteNames/filter-note-names.html'"></li>
<li ng-repeat="note in navbar.notes.root.children |notebookFilter:query track by $index" ng-class="{'active' : navbar.isActive(note.id)}" ng-include="'notebook_list_renderer.html'"></li>
<li ng-repeat="note in navbar.notes.root.children |notebookFilter:query track by $index"
ng-class="{'active' : navbar.isActive(note.id)}" ng-include="'notebook_list_renderer.html'"></li>
</div>
</ul>
</li>
<li>
<a href="#/interpreter">Interpreter</a>
</li>
<li>
<a href="#/credential">Credential</a>
</li>
<li>
<a href="#/configuration">Configuration</a>
</li>
</ul>
<ul class="nav navbar-nav navbar-right" style="margin-right:5px;">
<li ng-if="ticket" style="margin-top:10px;">
<li class="nav-component" ng-if="ticket">
<!--TODO(bzz): move to Typeahead https://angular-ui.github.io/bootstrap -->
<form role="search" data-ng-model="searchForm"
@ -89,43 +80,35 @@ limitations under the License.
</span>
</div>
</form>
<li class="nav-component">
<i ng-if="navbar.connected" class="fa fa-circle server-connected"
tooltip="WebSocket Connected" tooltip-placement="bottom"></i>
<i ng-if="!navbar.connected" class="fa fa-circle server-disconnected"
tooltip="WebSocket Disconnected" tooltip-placement="bottom"></i>
</li>
<li class="dropdown " dropdown="">
<a class="dropdown-toggle" type="button" data-toggle="dropdown" href="#"
ng-show="navbar.connected" ng-if="ticket.principal == 'anonymous' ">
<i class="fa fa-circle server-status"
ng-class="{'server-connected':navbar.connected, 'server-disconnected':!navbar.connected}"></i>
Connected
<span class="caret"></span>
</a>
<a class="dropdown-toggle" type="button" data-toggle="dropdown" href="#"
ng-show="navbar.connected" ng-if="ticket.principal != 'anonymous' "
tooltip-placement="bottom" tooltip="{{fullUsername}}">
<i class="fa fa-circle server-status"
ng-class="{'server-connected':navbar.connected, 'server-disconnected':!navbar.connected}"></i>
{{truncatedUsername}}
<span class="caret"></span></a>
<a class="dropdown-toggle" type="button" data-toggle="dropdown" href="#"
ng-show="!navbar.connected">
<i class="fa fa-circle server-status"
ng-class="{'server-connected':navbar.connected, 'server-disconnected':!navbar.connected}"></i>
Disconnected
<span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a href="" data-toggle="modal" data-target="#aboutModal">
<i style="font-size: 15px;" class="fa fa-info"></i> About</a></li>
<li ng-show="ticket.principal && ticket.principal!='anonymous'" style="left: 5px;">
<a ng-click="logout()">Logout</a>
</li>
</ul>
<li>
<div class="dropdown">
<button ng-if="ticket" class="nav-btn dropdown-toggle" type="button" data-toggle="dropdown" style="margin:11px 5px 0 0;">
<span class="username">{{ticket.principal}}</span>
<span class="caret" style="margin-bottom: 8px"></span>
</button>
<span ng-if="!ticket" style="margin: 5px;"></span>
<ul class="dropdown-menu">
<li><a href="" data-toggle="modal" data-target="#aboutModal">About Zeppelin</a>
<li role="separator" style="margin: 5px 0;" class="divider"></li>
<li><a href="#/interpreter">Interpreter</a></li>
<li><a href="#/credential">Credential</a></li>
<li><a href="#/configuration">Configuration</a></li>
<li ng-if="ticket.principal && ticket.principal !== 'anonymous'" role="separator" style="margin: 5px 0;" class="divider"></li>
<li ng-if="ticket.principal && ticket.principal !== 'anonymous'"><a ng-click="logout()">Logout</a></li>
</ul>
</div>
</li>
<li ng-if="!ticket">
<button class="btn btn-default" data-toggle="modal" data-target="#loginModal"
ng-click="showLoginWindow()" style="margin-top: 8px">Login
<li class="nav-component" ng-if="!ticket">
<button class="btn nav-login-btn" data-toggle="modal" data-target="#loginModal"
ng-click="showLoginWindow()">Login
</button>
</li>
</ul>
</div>
</div>

View file

@ -346,6 +346,10 @@ public class ZeppelinConfiguration extends XMLConfiguration {
return getString(ConfVars.ZEPPELIN_NOTEBOOK_S3_EMP);
}
public String getInterpreterListPath() {
return getRelativeDir(String.format("%s/interpreter-list", getConfDir()));
}
public String getInterpreterDir() {
return getRelativeDir(ConfVars.ZEPPELIN_INTERPRETER_DIR);
}

View file

@ -361,15 +361,17 @@ public class InterpreterFactory implements InterpreterGroupFactory {
List<Dependency> deps = intSetting.getDependencies();
if (deps != null) {
for (Dependency d: deps) {
File destDir = new File(conf.getRelativeDir(ConfVars.ZEPPELIN_DEP_LOCALREPO));
if (d.getExclusions() != null) {
depResolver.load(
d.getGroupArtifactVersion(),
d.getExclusions(),
conf.getString(ConfVars.ZEPPELIN_DEP_LOCALREPO) + "/" + intSetting.id());
new File(destDir, intSetting.id()));
} else {
depResolver.load(
d.getGroupArtifactVersion(),
conf.getString(ConfVars.ZEPPELIN_DEP_LOCALREPO) + "/" + intSetting.id());
new File(destDir, intSetting.id()));
}
}
}

View file

@ -0,0 +1,301 @@
/*
* 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.interpreter.install;
import org.apache.commons.io.FileUtils;
import org.apache.log4j.ConsoleAppender;
import org.apache.log4j.Logger;
import org.apache.zeppelin.conf.ZeppelinConfiguration;
import org.apache.zeppelin.dep.DependencyResolver;
import org.apache.zeppelin.util.Util;
import org.sonatype.aether.RepositoryException;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Commandline utility to install interpreter from maven repository
*/
public class InstallInterpreter {
private final File interpreterListFile;
private final File interpreterBaseDir;
private final List<AvailableInterpreterInfo> availableInterpreters;
private final String localRepoDir;
private URL proxyUrl;
private String proxyUser;
private String proxyPassword;
/**
*
* @param interpreterListFile
* @param interpreterBaseDir interpreter directory for installing binaries
* @throws IOException
*/
public InstallInterpreter(File interpreterListFile, File interpreterBaseDir, String localRepoDir)
throws IOException {
this.interpreterListFile = interpreterListFile;
this.interpreterBaseDir = interpreterBaseDir;
this.localRepoDir = localRepoDir;
availableInterpreters = new LinkedList<AvailableInterpreterInfo>();
readAvailableInterpreters();
}
/**
* Information for available informations
*/
private static class AvailableInterpreterInfo {
public final String name;
public final String artifact;
public final String description;
public AvailableInterpreterInfo(String name, String artifact, String description) {
this.name = name;
this.artifact = artifact;
this.description = description;
}
}
private void readAvailableInterpreters() throws IOException {
if (!interpreterListFile.isFile()) {
System.err.println("Can't find interpreter list " + interpreterListFile.getAbsolutePath());
return;
}
String text = FileUtils.readFileToString(interpreterListFile);
String[] lines = text.split("\n");
Pattern pattern = Pattern.compile("(\\S+)\\s+(\\S+)\\s+(.*)");
int lineNo = 0;
for (String line : lines) {
lineNo++;
if (line == null || line.length() == 0 || line.startsWith("#")) {
continue;
}
Matcher match = pattern.matcher(line);
if (match.groupCount() != 3) {
System.err.println("Error on line " + lineNo + ", " + line);
continue;
}
match.find();
String name = match.group(1);
String artifact = match.group(2);
String description = match.group(3);
availableInterpreters.add(new AvailableInterpreterInfo(name, artifact, description));
}
}
public List<AvailableInterpreterInfo> list() {
for (AvailableInterpreterInfo info : availableInterpreters) {
System.out.println(info.name + "\t\t\t" + info.description);
}
return availableInterpreters;
}
public void installAll() {
for (AvailableInterpreterInfo info : availableInterpreters) {
install(info.name, info.artifact);
}
}
public void install(String [] names) {
for (String name : names) {
install(name);
}
}
public void install(String name) {
// find artifact name
for (AvailableInterpreterInfo info : availableInterpreters) {
if (name.equals(info.name)) {
install(name, info.artifact);
return;
}
}
throw new RuntimeException("Can't find interpreter '" + name + "'");
}
public void install(String [] names, String [] artifacts) {
if (names.length != artifacts.length) {
throw new RuntimeException("Length of given names and artifacts are different");
}
for (int i = 0; i < names.length; i++) {
install(names[i], artifacts[i]);
}
}
public void install(String name, String artifact) {
DependencyResolver depResolver = new DependencyResolver(localRepoDir);
if (proxyUrl != null) {
depResolver.setProxy(proxyUrl, proxyUser, proxyPassword);
}
File installDir = new File(interpreterBaseDir, name);
if (installDir.exists()) {
System.err.println("Directory " + installDir.getAbsolutePath() + " already exists. Skipping");
return;
}
System.out.println("Install " + name + "(" + artifact + ") to "
+ installDir.getAbsolutePath() + " ... ");
try {
depResolver.load(artifact, installDir);
System.out.println("Interpreter " + name + " installed under " +
installDir.getAbsolutePath() + ".");
} catch (RepositoryException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public void setProxy(URL proxyUrl, String proxyUser, String proxyPassword) {
this.proxyUrl = proxyUrl;
this.proxyUser = proxyUser;
this.proxyPassword = proxyPassword;
}
public static void usage() {
System.out.println("Options");
System.out.println(" -l, --list List available interpreters");
System.out.println(" -a, --all Install all available interpreters");
System.out.println(" -n, --name [NAMES] Install interpreters (comma separated " +
"list)" +
"e.g. md,shell,jdbc,python,angular");
System.out.println(" -t, --artifact [ARTIFACTS] (Optional with -n) custom artifact names" +
". " +
"(comma separated list correspond to --name) " +
"e.g. customGroup:customArtifact:customVersion");
System.out.println(" --proxy-url [url] (Optional) proxy url. http(s)://host:port");
System.out.println(" --proxy-user [user] (Optional) proxy user");
System.out.println(" --proxy-password [password] (Optional) proxy password");
}
public static void main(String [] args) throws IOException {
if (args.length == 0) {
usage();
return;
}
ZeppelinConfiguration conf = ZeppelinConfiguration.create();
InstallInterpreter installer = new InstallInterpreter(
new File(conf.getInterpreterListPath()),
new File(conf.getInterpreterDir()),
conf.getInterpreterLocalRepoPath());
String names = null;
String artifacts = null;
URL proxyUrl = null;
String proxyUser = null;
String proxyPassword = null;
boolean all = false;
for (int i = 0; i < args.length; i++) {
String arg = args[i].toLowerCase(Locale.US);
switch (arg) {
case "--list":
case "-l":
installer.list();
System.exit(0);
break;
case "--all":
case "-a":
all = true;
break;
case "--name":
case "-n":
names = args[++i];
break;
case "--artifact":
case "-t":
artifacts = args[++i];
break;
case "--version":
case "-v":
Util.getVersion();
break;
case "--proxy-url":
proxyUrl = new URL(args[++i]);
break;
case "--proxy-user":
proxyUser = args[++i];
break;
case "--proxy-password":
proxyPassword = args[++i];
break;
case "--help":
case "-h":
usage();
System.exit(0);
break;
default:
System.out.println("Unknown option " + arg);
}
}
if (proxyUrl != null) {
installer.setProxy(proxyUrl, proxyUser, proxyPassword);
}
if (all) {
installer.installAll();
System.exit(0);
}
if (names != null) {
if (artifacts != null) {
installer.install(names.split(","), artifacts.split(","));
startTip();
configurationTip();
interpreterSettingTip();
} else {
installer.install(names.split(","));
startTip();
interpreterSettingTip();
}
}
}
private static void startTip() {
System.out.println("");
}
private static void configurationTip() {
System.out.println("Add interpreter class name to '"
+ ZeppelinConfiguration.ConfVars.ZEPPELIN_INTERPRETERS.getVarName() + "' property "
+ "in your conf/zeppelin-site.xml file");
}
private static void interpreterSettingTip() {
System.out.println("Create interpreter setting in 'Interpreter' menu on GUI."
+ " And then you can bind interpreter on your notebook");
}
}

View file

@ -205,7 +205,9 @@ public class Notebook implements NoteEventListener {
throws IOException {
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.setPrettyPrinting();
Gson gson = gsonBuilder.create();
Gson gson = gsonBuilder.registerTypeAdapter(Date.class, new NotebookImportDeserializer())
.create();
JsonReader reader = new JsonReader(new StringReader(sourceJson));
reader.setLenient(true);
Note newNote;

View file

@ -0,0 +1,53 @@
/*
* 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.notebook;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonParseException;
import java.lang.reflect.Type;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.Locale;
/**
* importNote date format deserializer
*/
public class NotebookImportDeserializer implements JsonDeserializer<Date> {
private static final String[] DATE_FORMATS = new String[] {
"yyyy-MM-dd'T'HH:mm:ssZ",
"MMM dd, yyyy HH:mm:ss"
};
@Override
public Date deserialize(JsonElement jsonElement, Type typeOF,
JsonDeserializationContext context) throws JsonParseException {
for (String format : DATE_FORMATS) {
try {
return new SimpleDateFormat(format, Locale.US).parse(jsonElement.getAsString());
} catch (ParseException e) {
}
}
throw new JsonParseException("Unparsable date: \"" + jsonElement.getAsString()
+ "\". Supported formats: " + Arrays.toString(DATE_FORMATS));
}
}

View file

@ -18,13 +18,8 @@
package org.apache.zeppelin.util;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Properties;
/**
@ -44,162 +39,6 @@ public class Util {
}
}
public static String[] split(String str, char split) {
return split(str, new String[] {String.valueOf(split)}, false);
}
public static String[] split(String str, String[] splitters, boolean includeSplitter) {
String escapeSeq = "\"',;<%>";
char escapeChar = '\\';
String[] blockStart = new String[] {"\"", "'", "<%", "N_<"};
String[] blockEnd = new String[] {"\"", "'", "%>", "N_>"};
return split(str, escapeSeq, escapeChar, blockStart, blockEnd, splitters, includeSplitter);
}
public static String[] split(String str, String escapeSeq, char escapeChar, String[] blockStart,
String[] blockEnd, String[] splitters, boolean includeSplitter) {
List<String> splits = new ArrayList<String>();
String curString = "";
boolean escape = false; // true when escape char is found
int lastEscapeOffset = -1;
int blockStartPos = -1;
List<Integer> blockStack = new LinkedList<Integer>();
for (int i = 0; i < str.length(); i++) {
char c = str.charAt(i);
// escape char detected
if (c == escapeChar && escape == false) {
escape = true;
continue;
}
// escaped char comes
if (escape == true) {
if (escapeSeq.indexOf(c) < 0) {
curString += escapeChar;
}
curString += c;
escape = false;
lastEscapeOffset = curString.length();
continue;
}
if (blockStack.size() > 0) { // inside of block
curString += c;
// check multichar block
boolean multicharBlockDetected = false;
for (int b = 0; b < blockStart.length; b++) {
if (blockStartPos >= 0
&& getBlockStr(blockStart[b]).compareTo(str.substring(blockStartPos, i)) == 0) {
blockStack.remove(0);
blockStack.add(0, b);
multicharBlockDetected = true;
break;
}
}
if (multicharBlockDetected == true) {
continue;
}
// check if current block is nestable
if (isNestedBlock(blockStart[blockStack.get(0)]) == true) {
// try to find nested block start
if (curString.substring(lastEscapeOffset + 1).endsWith(
getBlockStr(blockStart[blockStack.get(0)])) == true) {
blockStack.add(0, blockStack.get(0)); // block is started
blockStartPos = i;
continue;
}
}
// check if block is finishing
if (curString.substring(lastEscapeOffset + 1).endsWith(
getBlockStr(blockEnd[blockStack.get(0)]))) {
// the block closer is one of the splitters (and not nested block)
if (isNestedBlock(blockEnd[blockStack.get(0)]) == false) {
for (String splitter : splitters) {
if (splitter.compareTo(getBlockStr(blockEnd[blockStack.get(0)])) == 0) {
splits.add(curString);
if (includeSplitter == true) {
splits.add(splitter);
}
curString = "";
lastEscapeOffset = -1;
break;
}
}
}
blockStartPos = -1;
blockStack.remove(0);
continue;
}
} else { // not in the block
boolean splitted = false;
for (String splitter : splitters) {
// forward check for splitter
if (splitter.compareTo(
str.substring(i, Math.min(i + splitter.length(), str.length()))) == 0) {
splits.add(curString);
if (includeSplitter == true) {
splits.add(splitter);
}
curString = "";
lastEscapeOffset = -1;
i += splitter.length() - 1;
splitted = true;
break;
}
}
if (splitted == true) {
continue;
}
// add char to current string
curString += c;
// check if block is started
for (int b = 0; b < blockStart.length; b++) {
if (curString.substring(lastEscapeOffset + 1)
.endsWith(getBlockStr(blockStart[b])) == true) {
blockStack.add(0, b); // block is started
blockStartPos = i;
break;
}
}
}
}
if (curString.length() > 0) {
splits.add(curString.trim());
}
return splits.toArray(new String[] {});
}
private static String getBlockStr(String blockDef) {
if (blockDef.startsWith("N_")) {
return blockDef.substring("N_".length());
} else {
return blockDef;
}
}
private static boolean isNestedBlock(String blockDef) {
if (blockDef.startsWith("N_")) {
return true;
} else {
return false;
}
}
/**
* Get Zeppelin version
*

View file

@ -0,0 +1,86 @@
package org.apache.zeppelin.interpreter.install;
import org.apache.commons.io.FileUtils;
import org.apache.zeppelin.conf.ZeppelinConfiguration;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.io.File;
import java.io.IOException;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
/*
* 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.
*/
public class InstallInterpreterTest {
private File tmpDir;
private InstallInterpreter installer;
private File interpreterBaseDir;
@Before
public void setUp() throws IOException {
tmpDir = new File(System.getProperty("java.io.tmpdir")+"/ZeppelinLTest_"+System.currentTimeMillis());
new File(tmpDir, "conf").mkdirs();
interpreterBaseDir = new File(tmpDir, "interpreter");
File localRepoDir = new File(tmpDir, "local-repo");
interpreterBaseDir.mkdir();
localRepoDir.mkdir();
File interpreterListFile = new File(tmpDir, "conf/interpreter-list");
// create interpreter list file
System.setProperty(ZeppelinConfiguration.ConfVars.ZEPPELIN_HOME.getVarName(), tmpDir.getAbsolutePath());
String interpreterList = "";
interpreterList += "intp1 org.apache.commons:commons-csv:1.1 test interpreter 1\n";
interpreterList += "intp2 org.apache.commons:commons-math3:3.6.1 test interpreter 2\n";
FileUtils.writeStringToFile(new File(tmpDir, "conf/interpreter-list"), interpreterList);
installer = new InstallInterpreter(interpreterListFile, interpreterBaseDir, localRepoDir
.getAbsolutePath());
}
@After
public void tearDown() throws IOException {
FileUtils.deleteDirectory(tmpDir);
}
@Test
public void testList() {
assertEquals(2, installer.list().size());
}
@Test
public void install() {
assertEquals(0, interpreterBaseDir.listFiles().length);
installer.install("intp1");
assertTrue(new File(interpreterBaseDir, "intp1").isDirectory());
}
@Test
public void installAll() {
installer.installAll();
assertTrue(new File(interpreterBaseDir, "intp1").isDirectory());
assertTrue(new File(interpreterBaseDir, "intp2").isDirectory());
}
}

View file

@ -1,106 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.zeppelin.util;
import org.apache.zeppelin.util.Util;
import junit.framework.TestCase;
public class UtilTest extends TestCase {
@Override
protected void setUp() throws Exception {
super.setUp();
}
@Override
protected void tearDown() throws Exception {
super.tearDown();
}
public void testSplitIncludingToken() {
String[] token = Util.split("hello | \"world '>|hehe\" > next >> sink", new String[]{"|", ">>", ">"}, true);
assertEquals(7, token.length);
assertEquals(" \"world '>|hehe\" ", token[2]);
}
public void testSplitExcludingToken() {
String[] token = Util.split("hello | \"world '>|hehe\" > next >> sink", new String[]{"|", ">>", ">"}, false);
assertEquals(4, token.length);
assertEquals(" \"world '>|hehe\" ", token[1]);
}
public void testSplitWithSemicolonEnd(){
String[] token = Util.split("show tables;", ';');
assertEquals(1, token.length);
assertEquals("show tables", token[0]);
}
public void testEscapeTemplate(){
String[] token = Util.split("select * from <%=table%> limit 1 > output", '>');
assertEquals(2, token.length);
assertEquals("output", token[1]);
}
public void testSplit(){
String [] op = new String[]{";", "|", ">>", ">"};
String str = "CREATE external table news20b_train (\n"+
" rowid int,\n"+
" label int,\n"+
" features ARRAY<STRING>\n"+
")\n"+
"ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t' \n"+
"COLLECTION ITEMS TERMINATED BY \",\" \n"+
"STORED AS TEXTFILE;\n";
Util.split(str, op, true);
}
public void testSplitDifferentBlockStartEnd(){
String [] op = new String[]{";", "|", ">>", ">"};
String escapeSeq = "\"',;<%>!";
char escapeChar = '\\';
String [] blockStart = new String[]{ "\"", "'", "<%", "<", "!"};
String [] blockEnd = new String[]{ "\"", "'", "%>", ">", ";" };
String [] t = Util.split("!echo a;!echo b;", escapeSeq, escapeChar, blockStart, blockEnd, op, true);
assertEquals(4, t.length);
assertEquals("!echo a;", t[0]);
assertEquals(";", t[1]);
assertEquals("!echo b;", t[2]);
assertEquals(";", t[3]);
}
public void testNestedBlock(){
String [] op = new String[]{";", "|", ">>", ">"};
String escapeSeq = "\"',;<%>!";
char escapeChar = '\\';
String [] blockStart = new String[]{ "\"", "'", "<%", "N_<", "<", "!"};
String [] blockEnd = new String[]{ "\"", "'", "%>", "N_>", ";", ";" };
String [] t = Util.split("array <STRUCT<STRING>> tags|aa", escapeSeq, escapeChar, blockStart, blockEnd, op, true);
assertEquals(3, t.length);
assertEquals("array <STRUCT<STRING>> tags", t[0]);
assertEquals("aa", t[2]);
}
public void testGetVersion(){
String version = Util.getVersion();
assertNotNull(version);
System.out.println(version);
}
}

View file

@ -1,124 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.zeppelin.util;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
public class UtilsForTests {
static Logger LOGGER = LoggerFactory.getLogger(UtilsForTests.class);
public static File createTmpDir() throws Exception {
File tmpDir = new File(System.getProperty("java.io.tmpdir") + "/ZeppelinLTest_" + System.currentTimeMillis());
tmpDir.mkdir();
return tmpDir;
}
/*
private static final String HADOOP_DIST="http://apache.mirror.cdnetworks.com/hadoop/common/hadoop-1.2.1/hadoop-1.2.1-bin.tar.gz";
//private static final String HADOOP_DIST="http://www.us.apache.org/dist/hadoop/common/hadoop-1.2.1/hadoop-1.2.1-bin.tar.gz";
public static void getHadoop() throws MalformedURLException, IOException{
setEnv("HADOOP_HOME", new File("./target/hadoop-1.2.1").getAbsolutePath());
if(new File("./target/hadoop-1.2.1").isDirectory()) return;
//System.out.println("Downloading a hadoop distribution ... it will take a while");
//FileUtils.copyURLToFile(new URL(HADOOP_DIST), new File("/tmp/zp_test_hadoop-bin.tar.gz"));
System.out.println("Unarchive hadoop distribution ... ");
new File("./target").mkdir();
Runtime.getRuntime().exec("tar -xzf /tmp/zp_test_hadoop-bin.tar.gz -C ./target");
}
*/
public static void delete(File file) {
if (file.isFile()) file.delete();
else if (file.isDirectory()) {
File[] files = file.listFiles();
if (files != null && files.length > 0) {
for (File f : files) {
delete(f);
}
}
file.delete();
}
}
/**
* Utility method to create a file (if does not exist) and populate it the the given content
*
* @param path to file
* @param content of the file
* @throws IOException
*/
public static void createFileWithContent(String path, String content) throws IOException {
File f = new File(path);
if (!f.exists()) {
stringToFile(content, f);
}
}
public static void stringToFile(String string, File file) throws IOException {
FileOutputStream out = new FileOutputStream(file);
out.write(string.getBytes());
out.close();
}
@SuppressWarnings({"unchecked", "rawtypes"})
public static void setEnv(String k, String v) {
Map<String, String> newenv = new HashMap<String, String>();
newenv.put(k, v);
try {
Class<?> processEnvironmentClass = Class.forName("java.lang.ProcessEnvironment");
Field theEnvironmentField = processEnvironmentClass.getDeclaredField("theEnvironment");
theEnvironmentField.setAccessible(true);
Map<String, String> env = (Map<String, String>) theEnvironmentField.get(null);
env.putAll(newenv);
Field theCaseInsensitiveEnvironmentField = processEnvironmentClass.getDeclaredField("theCaseInsensitiveEnvironment");
theCaseInsensitiveEnvironmentField.setAccessible(true);
Map<String, String> cienv = (Map<String, String>) theCaseInsensitiveEnvironmentField.get(null);
cienv.putAll(newenv);
} catch (NoSuchFieldException e) {
try {
Class[] classes = Collections.class.getDeclaredClasses();
Map<String, String> env = System.getenv();
for (Class cl : classes) {
if ("java.util.Collections$UnmodifiableMap".equals(cl.getName())) {
Field field = cl.getDeclaredField("m");
field.setAccessible(true);
Object obj = field.get(env);
Map<String, String> map = (Map<String, String>) obj;
map.clear();
map.putAll(newenv);
}
}
} catch (Exception e2) {
LOGGER.error(e2.toString(), e2);
}
} catch (Exception e1) {
LOGGER.error(e1.toString(), e1);
}
}
}