You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@zeppelin.apache.org by zj...@apache.org on 2018/02/02 06:00:46 UTC

[01/10] zeppelin git commit: ZEPPELIN-3111. Refactor SparkInterpreter

Repository: zeppelin
Updated Branches:
  refs/heads/master 66644126a -> d762b5288


http://git-wip-us.apache.org/repos/asf/zeppelin/blob/d762b528/spark/src/test/java/org/apache/zeppelin/spark/IPySparkInterpreterTest.java
----------------------------------------------------------------------
diff --git a/spark/src/test/java/org/apache/zeppelin/spark/IPySparkInterpreterTest.java b/spark/src/test/java/org/apache/zeppelin/spark/IPySparkInterpreterTest.java
deleted file mode 100644
index d2b01ce..0000000
--- a/spark/src/test/java/org/apache/zeppelin/spark/IPySparkInterpreterTest.java
+++ /dev/null
@@ -1,206 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.zeppelin.spark;
-
-
-import com.google.common.io.Files;
-import org.apache.zeppelin.display.AngularObjectRegistry;
-import org.apache.zeppelin.display.GUI;
-import org.apache.zeppelin.interpreter.Interpreter;
-import org.apache.zeppelin.interpreter.InterpreterContext;
-import org.apache.zeppelin.interpreter.InterpreterContextRunner;
-import org.apache.zeppelin.interpreter.InterpreterException;
-import org.apache.zeppelin.interpreter.InterpreterGroup;
-import org.apache.zeppelin.interpreter.InterpreterOutput;
-import org.apache.zeppelin.interpreter.InterpreterOutputListener;
-import org.apache.zeppelin.interpreter.InterpreterResult;
-import org.apache.zeppelin.interpreter.InterpreterResultMessage;
-import org.apache.zeppelin.interpreter.InterpreterResultMessageOutput;
-import org.apache.zeppelin.interpreter.thrift.InterpreterCompletion;
-import org.apache.zeppelin.python.IPythonInterpreterTest;
-import org.apache.zeppelin.resource.LocalResourcePool;
-import org.apache.zeppelin.user.AuthenticationInfo;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Properties;
-import java.util.concurrent.CopyOnWriteArrayList;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
-public class IPySparkInterpreterTest {
-
-  private IPySparkInterpreter iPySparkInterpreter;
-  private InterpreterGroup intpGroup;
-
-  @Before
-  public void setup() throws InterpreterException {
-    Properties p = new Properties();
-    p.setProperty("spark.master", "local[4]");
-    p.setProperty("master", "local[4]");
-    p.setProperty("spark.submit.deployMode", "client");
-    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");
-    p.setProperty("zeppelin.pyspark.python", "python");
-    p.setProperty("zeppelin.dep.localrepo", Files.createTempDir().getAbsolutePath());
-
-    intpGroup = new InterpreterGroup();
-    intpGroup.put("session_1", new LinkedList<Interpreter>());
-
-    SparkInterpreter sparkInterpreter = new SparkInterpreter(p);
-    intpGroup.get("session_1").add(sparkInterpreter);
-    sparkInterpreter.setInterpreterGroup(intpGroup);
-    sparkInterpreter.open();
-
-    iPySparkInterpreter = new IPySparkInterpreter(p);
-    intpGroup.get("session_1").add(iPySparkInterpreter);
-    iPySparkInterpreter.setInterpreterGroup(intpGroup);
-    iPySparkInterpreter.open();
-  }
-
-
-  @After
-  public void tearDown() {
-    if (iPySparkInterpreter != null) {
-      iPySparkInterpreter.close();
-    }
-  }
-
-  @Test
-  public void testBasics() throws InterruptedException, IOException, InterpreterException {
-    // all the ipython test should pass too.
-    IPythonInterpreterTest.testInterpreter(iPySparkInterpreter);
-
-    // rdd
-    InterpreterContext context = getInterpreterContext();
-    InterpreterResult result = iPySparkInterpreter.interpret("sc.range(1,10).sum()", context);
-    Thread.sleep(100);
-    assertEquals(InterpreterResult.Code.SUCCESS, result.code());
-    List<InterpreterResultMessage> interpreterResultMessages = context.out.getInterpreterResultMessages();
-    assertEquals("45", interpreterResultMessages.get(0).getData());
-
-    context = getInterpreterContext();
-    result = iPySparkInterpreter.interpret("sc.version", context);
-    Thread.sleep(100);
-    assertEquals(InterpreterResult.Code.SUCCESS, result.code());
-    interpreterResultMessages = context.out.getInterpreterResultMessages();
-    // spark sql
-    context = getInterpreterContext();
-    if (interpreterResultMessages.get(0).getData().startsWith("'1.") ||
-        interpreterResultMessages.get(0).getData().startsWith("u'1.")) {
-      result = iPySparkInterpreter.interpret("df = sqlContext.createDataFrame([(1,'a'),(2,'b')])\ndf.show()", context);
-      assertEquals(InterpreterResult.Code.SUCCESS, result.code());
-      interpreterResultMessages = context.out.getInterpreterResultMessages();
-      assertEquals(
-          "+---+---+\n" +
-          "| _1| _2|\n" +
-          "+---+---+\n" +
-          "|  1|  a|\n" +
-          "|  2|  b|\n" +
-          "+---+---+\n\n", interpreterResultMessages.get(0).getData());
-    } else {
-      result = iPySparkInterpreter.interpret("df = spark.createDataFrame([(1,'a'),(2,'b')])\ndf.show()", context);
-      assertEquals(InterpreterResult.Code.SUCCESS, result.code());
-      interpreterResultMessages = context.out.getInterpreterResultMessages();
-      assertEquals(
-          "+---+---+\n" +
-          "| _1| _2|\n" +
-          "+---+---+\n" +
-          "|  1|  a|\n" +
-          "|  2|  b|\n" +
-          "+---+---+\n\n", interpreterResultMessages.get(0).getData());
-    }
-
-    // cancel
-    final InterpreterContext context2 = getInterpreterContext();
-
-    Thread thread = new Thread(){
-      @Override
-      public void run() {
-        InterpreterResult result = iPySparkInterpreter.interpret("import time\nsc.range(1,10).foreach(lambda x: time.sleep(1))", context2);
-        assertEquals(InterpreterResult.Code.ERROR, result.code());
-        List<InterpreterResultMessage> interpreterResultMessages = null;
-        try {
-          interpreterResultMessages = context2.out.getInterpreterResultMessages();
-          assertTrue(interpreterResultMessages.get(0).getData().contains("KeyboardInterrupt"));
-        } catch (IOException e) {
-          e.printStackTrace();
-        }
-      }
-    };
-    thread.start();
-
-    // sleep 1 second to wait for the spark job starts
-    Thread.sleep(1000);
-    iPySparkInterpreter.cancel(context);
-    thread.join();
-
-    // completions
-    List<InterpreterCompletion> completions = iPySparkInterpreter.completion("sc.ran", 6, getInterpreterContext());
-    assertEquals(1, completions.size());
-    assertEquals("range", completions.get(0).getValue());
-
-    // pyspark streaming
-    context = getInterpreterContext();
-    result = iPySparkInterpreter.interpret(
-        "from pyspark.streaming import StreamingContext\n" +
-        "import time\n" +
-        "ssc = StreamingContext(sc, 1)\n" +
-        "rddQueue = []\n" +
-        "for i in range(5):\n" +
-        "    rddQueue += [ssc.sparkContext.parallelize([j for j in range(1, 1001)], 10)]\n" +
-        "inputStream = ssc.queueStream(rddQueue)\n" +
-        "mappedStream = inputStream.map(lambda x: (x % 10, 1))\n" +
-        "reducedStream = mappedStream.reduceByKey(lambda a, b: a + b)\n" +
-        "reducedStream.pprint()\n" +
-        "ssc.start()\n" +
-        "time.sleep(6)\n" +
-        "ssc.stop(stopSparkContext=False, stopGraceFully=True)", context);
-    Thread.sleep(1000);
-    assertEquals(InterpreterResult.Code.SUCCESS, result.code());
-    interpreterResultMessages = context.out.getInterpreterResultMessages();
-    assertEquals(1, interpreterResultMessages.size());
-    assertTrue(interpreterResultMessages.get(0).getData().contains("(0, 100)"));
-  }
-
-  private InterpreterContext getInterpreterContext() {
-    return new InterpreterContext(
-        "noteId",
-        "paragraphId",
-        "replName",
-        "paragraphTitle",
-        "paragraphText",
-        new AuthenticationInfo(),
-        new HashMap<String, Object>(),
-        new GUI(),
-        new GUI(),
-        null,
-        null,
-        null,
-        new InterpreterOutput(null));
-  }
-}

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/d762b528/spark/src/test/java/org/apache/zeppelin/spark/PySparkInterpreterMatplotlibTest.java
----------------------------------------------------------------------
diff --git a/spark/src/test/java/org/apache/zeppelin/spark/PySparkInterpreterMatplotlibTest.java b/spark/src/test/java/org/apache/zeppelin/spark/PySparkInterpreterMatplotlibTest.java
deleted file mode 100644
index 2f1077d..0000000
--- a/spark/src/test/java/org/apache/zeppelin/spark/PySparkInterpreterMatplotlibTest.java
+++ /dev/null
@@ -1,241 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.zeppelin.spark;
-
-import org.apache.zeppelin.display.AngularObjectRegistry;
-import org.apache.zeppelin.display.GUI;
-import org.apache.zeppelin.interpreter.*;
-import org.apache.zeppelin.interpreter.InterpreterResult.Type;
-import org.apache.zeppelin.resource.LocalResourcePool;
-import org.apache.zeppelin.user.AuthenticationInfo;
-import org.junit.*;
-import org.junit.rules.TemporaryFolder;
-import org.junit.runners.MethodSorters;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import java.io.IOException;
-import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Properties;
-
-import static org.junit.Assert.*;
-
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-public class PySparkInterpreterMatplotlibTest {
-
-  @ClassRule
-  public static TemporaryFolder tmpDir = new TemporaryFolder();
-
-  static SparkInterpreter sparkInterpreter;
-  static PySparkInterpreter pyspark;
-  static InterpreterGroup intpGroup;
-  static Logger LOGGER = LoggerFactory.getLogger(PySparkInterpreterTest.class);
-  static InterpreterContext context;
-  
-  public static class AltPySparkInterpreter extends PySparkInterpreter {
-    /**
-     * Since pyspark output is  sent to an outputstream rather than
-     * being directly provided by interpret(), this subclass is created to
-     * override interpret() to append the result from the outputStream
-     * for the sake of convenience in testing. 
-     */
-    public AltPySparkInterpreter(Properties property) {
-      super(property);
-    }
-
-    /**
-     * This code is mainly copied from RemoteInterpreterServer.java which 
-     * normally handles this in real use cases.
-     */    
-    @Override
-    public InterpreterResult interpret(String st, InterpreterContext context) throws InterpreterException {
-      context.out.clear();
-      InterpreterResult result = super.interpret(st, context);
-      List<InterpreterResultMessage> resultMessages = null;
-      try {
-        context.out.flush();
-        resultMessages = context.out.toInterpreterResultMessage();
-      } catch (IOException e) {
-        e.printStackTrace();
-      }
-      resultMessages.addAll(result.message());
-
-      return new InterpreterResult(result.code(), resultMessages);
-    }
-  }
-
-  private static Properties getPySparkTestProperties() throws IOException {
-    Properties p = new Properties();
-    p.setProperty("master", "local[*]");
-    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");
-    p.setProperty("zeppelin.pyspark.python", "python");
-    p.setProperty("zeppelin.dep.localrepo", tmpDir.newFolder().getAbsolutePath());
-    p.setProperty("zeppelin.pyspark.useIPython", "false");
-    return p;
-  }
-
-  /**
-   * Get spark version number as a numerical value.
-   * eg. 1.1.x => 11, 1.2.x => 12, 1.3.x => 13 ...
-   */
-  public static int getSparkVersionNumber() {
-    if (sparkInterpreter == null) {
-      return 0;
-    }
-
-    String[] split = sparkInterpreter.getSparkContext().version().split("\\.");
-    int version = Integer.parseInt(split[0]) * 10 + Integer.parseInt(split[1]);
-    return version;
-  }
-
-  @BeforeClass
-  public static void setUp() throws Exception {
-    intpGroup = new InterpreterGroup();
-    intpGroup.put("note", new LinkedList<Interpreter>());
-    context = new InterpreterContext("note", "id", null, "title", "text",
-        new AuthenticationInfo(),
-        new HashMap<String, Object>(),
-        new GUI(),
-        new GUI(),
-        new AngularObjectRegistry(intpGroup.getId(), null),
-        new LocalResourcePool("id"),
-        new LinkedList<InterpreterContextRunner>(),
-        new InterpreterOutput(null));
-    InterpreterContext.set(context);
-
-    sparkInterpreter = new SparkInterpreter(getPySparkTestProperties());
-    intpGroup.get("note").add(sparkInterpreter);
-    sparkInterpreter.setInterpreterGroup(intpGroup);
-    sparkInterpreter.open();
-
-    pyspark = new AltPySparkInterpreter(getPySparkTestProperties());
-    intpGroup.get("note").add(pyspark);
-    pyspark.setInterpreterGroup(intpGroup);
-    pyspark.open();
-
-  }
-
-  @AfterClass
-  public static void tearDown() {
-    pyspark.close();
-    sparkInterpreter.close();
-  }
-
-  @Test
-  public void dependenciesAreInstalled() throws InterpreterException {
-    // matplotlib
-    InterpreterResult ret = pyspark.interpret("import matplotlib", context);
-    assertEquals(ret.message().toString(), InterpreterResult.Code.SUCCESS, ret.code());
-    
-    // inline backend
-    ret = pyspark.interpret("import backend_zinline", context);
-    assertEquals(ret.message().toString(), InterpreterResult.Code.SUCCESS, ret.code());
-  }
-
-  @Test
-  public void showPlot() throws InterpreterException {
-    // Simple plot test
-    InterpreterResult ret;
-    ret = pyspark.interpret("import matplotlib.pyplot as plt", context);
-    ret = pyspark.interpret("plt.close()", context);
-    ret = pyspark.interpret("z.configure_mpl(interactive=False)", context);
-    ret = pyspark.interpret("plt.plot([1, 2, 3])", context);
-    ret = pyspark.interpret("plt.show()", context);
-
-    assertEquals(ret.message().toString(), InterpreterResult.Code.SUCCESS, ret.code());
-    assertEquals(ret.message().toString(), Type.HTML, ret.message().get(0).getType());
-    assertTrue(ret.message().get(0).getData().contains("data:image/png;base64"));
-    assertTrue(ret.message().get(0).getData().contains("<div>"));
-  }
-
-  @Test
-  // Test for when configuration is set to auto-close figures after show().
-  public void testClose() throws InterpreterException {
-    InterpreterResult ret;
-    InterpreterResult ret1;
-    InterpreterResult ret2;
-    ret = pyspark.interpret("import matplotlib.pyplot as plt", context);
-    ret = pyspark.interpret("plt.close()", context);
-    ret = pyspark.interpret("z.configure_mpl(interactive=False, close=True, angular=False)", context);
-    ret = pyspark.interpret("plt.plot([1, 2, 3])", context);
-    ret1 = pyspark.interpret("plt.show()", context);
-    
-    // Second call to show() should print nothing, and Type should be TEXT.
-    // This is because when close=True, there should be no living instances
-    // of FigureManager, causing show() to return before setting the output
-    // type to HTML.
-    ret = pyspark.interpret("plt.show()", context);
-    assertEquals(0, ret.message().size());
-    
-    // Now test that new plot is drawn. It should be identical to the
-    // previous one.
-    ret = pyspark.interpret("plt.plot([1, 2, 3])", context);
-    ret2 = pyspark.interpret("plt.show()", context);
-    assertEquals(ret1.message().get(0).getType(), ret2.message().get(0).getType());
-    assertEquals(ret1.message().get(0).getData(), ret2.message().get(0).getData());
-  }
-  
-  @Test
-  // Test for when configuration is set to not auto-close figures after show().
-  public void testNoClose() throws InterpreterException {
-    InterpreterResult ret;
-    InterpreterResult ret1;
-    InterpreterResult ret2;
-    ret = pyspark.interpret("import matplotlib.pyplot as plt", context);
-    ret = pyspark.interpret("plt.close()", context);
-    ret = pyspark.interpret("z.configure_mpl(interactive=False, close=False, angular=False)", context);
-    ret = pyspark.interpret("plt.plot([1, 2, 3])", context);
-    ret1 = pyspark.interpret("plt.show()", context);
-    
-    // Second call to show() should print nothing, and Type should be HTML.
-    // This is because when close=False, there should be living instances
-    // of FigureManager, causing show() to set the output
-    // type to HTML even though the figure is inactive.
-    ret = pyspark.interpret("plt.show()", context);
-    assertEquals(ret.message().toString(), InterpreterResult.Code.SUCCESS, ret.code());
-
-    // Now test that plot can be reshown if it is updated. It should be
-    // different from the previous one because it will plot the same line
-    // again but in a different color.
-    ret = pyspark.interpret("plt.plot([1, 2, 3])", context);
-    ret2 = pyspark.interpret("plt.show()", context);
-    assertNotSame(ret1.message().get(0).getData(), ret2.message().get(0).getData());
-  }
-  
-  @Test
-  // Test angular mode
-  public void testAngular() throws InterpreterException {
-    InterpreterResult ret;
-    ret = pyspark.interpret("import matplotlib.pyplot as plt", context);
-    ret = pyspark.interpret("plt.close()", context);
-    ret = pyspark.interpret("z.configure_mpl(interactive=False, close=False, angular=True)", context);
-    ret = pyspark.interpret("plt.plot([1, 2, 3])", context);
-    ret = pyspark.interpret("plt.show()", context);    
-    assertEquals(ret.message().toString(), InterpreterResult.Code.SUCCESS, ret.code());
-    assertEquals(ret.message().toString(), Type.ANGULAR, ret.message().get(0).getType());
-
-    // Check if the figure data is in the Angular Object Registry
-    AngularObjectRegistry registry = context.getAngularObjectRegistry();
-    String figureData = registry.getAll("note", null).get(0).toString();
-    assertTrue(figureData.contains("data:image/png;base64"));
-  }  
-}

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/d762b528/spark/src/test/java/org/apache/zeppelin/spark/PySparkInterpreterTest.java
----------------------------------------------------------------------
diff --git a/spark/src/test/java/org/apache/zeppelin/spark/PySparkInterpreterTest.java b/spark/src/test/java/org/apache/zeppelin/spark/PySparkInterpreterTest.java
deleted file mode 100644
index 0db2bb1..0000000
--- a/spark/src/test/java/org/apache/zeppelin/spark/PySparkInterpreterTest.java
+++ /dev/null
@@ -1,194 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.zeppelin.spark;
-
-import org.apache.zeppelin.display.AngularObjectRegistry;
-import org.apache.zeppelin.display.GUI;
-import org.apache.zeppelin.interpreter.*;
-import org.apache.zeppelin.interpreter.thrift.InterpreterCompletion;
-import org.apache.zeppelin.resource.LocalResourcePool;
-import org.apache.zeppelin.user.AuthenticationInfo;
-import org.junit.*;
-import org.junit.rules.TemporaryFolder;
-import org.junit.runners.MethodSorters;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import java.io.IOException;
-import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Properties;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import static org.junit.Assert.*;
-
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-public class PySparkInterpreterTest {
-
-  @ClassRule
-  public static TemporaryFolder tmpDir = new TemporaryFolder();
-
-  static SparkInterpreter sparkInterpreter;
-  static PySparkInterpreter pySparkInterpreter;
-  static InterpreterGroup intpGroup;
-  static Logger LOGGER = LoggerFactory.getLogger(PySparkInterpreterTest.class);
-  static InterpreterContext context;
-
-  private static Properties getPySparkTestProperties() throws IOException {
-    Properties p = new Properties();
-    p.setProperty("master", "local[*]");
-    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");
-    p.setProperty("zeppelin.pyspark.python", "python");
-    p.setProperty("zeppelin.dep.localrepo", tmpDir.newFolder().getAbsolutePath());
-    p.setProperty("zeppelin.pyspark.useIPython", "false");
-    return p;
-  }
-
-  /**
-   * Get spark version number as a numerical value.
-   * eg. 1.1.x => 11, 1.2.x => 12, 1.3.x => 13 ...
-   */
-  public static int getSparkVersionNumber() {
-    if (sparkInterpreter == null) {
-      return 0;
-    }
-
-    String[] split = sparkInterpreter.getSparkContext().version().split("\\.");
-    int version = Integer.parseInt(split[0]) * 10 + Integer.parseInt(split[1]);
-    return version;
-  }
-
-  @BeforeClass
-  public static void setUp() throws Exception {
-    intpGroup = new InterpreterGroup();
-    intpGroup.put("note", new LinkedList<Interpreter>());
-
-    context = new InterpreterContext("note", "id", null, "title", "text",
-        new AuthenticationInfo(),
-        new HashMap<String, Object>(),
-        new GUI(),
-        new GUI(),
-        new AngularObjectRegistry(intpGroup.getId(), null),
-        new LocalResourcePool("id"),
-        new LinkedList<InterpreterContextRunner>(),
-        new InterpreterOutput(null));
-    InterpreterContext.set(context);
-
-    sparkInterpreter = new SparkInterpreter(getPySparkTestProperties());
-    intpGroup.get("note").add(sparkInterpreter);
-    sparkInterpreter.setInterpreterGroup(intpGroup);
-    sparkInterpreter.open();
-
-    pySparkInterpreter = new PySparkInterpreter(getPySparkTestProperties());
-    intpGroup.get("note").add(pySparkInterpreter);
-    pySparkInterpreter.setInterpreterGroup(intpGroup);
-    pySparkInterpreter.open();
-
-
-  }
-
-  @AfterClass
-  public static void tearDown() {
-    pySparkInterpreter.close();
-    sparkInterpreter.close();
-  }
-
-  @Test
-  public void testBasicIntp() throws InterpreterException {
-    if (getSparkVersionNumber() > 11) {
-      assertEquals(InterpreterResult.Code.SUCCESS,
-        pySparkInterpreter.interpret("a = 1\n", context).code());
-    }
-
-    InterpreterResult result = pySparkInterpreter.interpret(
-        "from pyspark.streaming import StreamingContext\n" +
-            "import time\n" +
-            "ssc = StreamingContext(sc, 1)\n" +
-            "rddQueue = []\n" +
-            "for i in range(5):\n" +
-            "    rddQueue += [ssc.sparkContext.parallelize([j for j in range(1, 1001)], 10)]\n" +
-            "inputStream = ssc.queueStream(rddQueue)\n" +
-            "mappedStream = inputStream.map(lambda x: (x % 10, 1))\n" +
-            "reducedStream = mappedStream.reduceByKey(lambda a, b: a + b)\n" +
-            "reducedStream.pprint()\n" +
-            "ssc.start()\n" +
-            "time.sleep(6)\n" +
-            "ssc.stop(stopSparkContext=False, stopGraceFully=True)", context);
-    assertEquals(InterpreterResult.Code.SUCCESS, result.code());
-  }
-
-  @Test
-  public void testCompletion() throws InterpreterException {
-    if (getSparkVersionNumber() > 11) {
-      List<InterpreterCompletion> completions = pySparkInterpreter.completion("sc.", "sc.".length(), null);
-      assertTrue(completions.size() > 0);
-    }
-  }
-
-  @Test
-  public void testRedefinitionZeppelinContext() throws InterpreterException {
-    if (getSparkVersionNumber() > 11) {
-      String redefinitionCode = "z = 1\n";
-      String restoreCode = "z = __zeppelin__\n";
-      String validCode = "z.input(\"test\")\n";
-
-      assertEquals(InterpreterResult.Code.SUCCESS, pySparkInterpreter.interpret(validCode, context).code());
-      assertEquals(InterpreterResult.Code.SUCCESS, pySparkInterpreter.interpret(redefinitionCode, context).code());
-      assertEquals(InterpreterResult.Code.ERROR, pySparkInterpreter.interpret(validCode, context).code());
-      assertEquals(InterpreterResult.Code.SUCCESS, pySparkInterpreter.interpret(restoreCode, context).code());
-      assertEquals(InterpreterResult.Code.SUCCESS, pySparkInterpreter.interpret(validCode, context).code());
-    }
-  }
-
-  private class infinityPythonJob implements Runnable {
-    @Override
-    public void run() {
-      String code = "import time\nwhile True:\n  time.sleep(1)" ;
-      InterpreterResult ret = null;
-      try {
-        ret = pySparkInterpreter.interpret(code, context);
-      } catch (InterpreterException e) {
-        e.printStackTrace();
-      }
-      assertNotNull(ret);
-      Pattern expectedMessage = Pattern.compile("KeyboardInterrupt");
-      Matcher m = expectedMessage.matcher(ret.message().toString());
-      assertTrue(m.find());
-    }
-  }
-
-  @Test
-  public void testCancelIntp() throws InterruptedException, InterpreterException {
-    if (getSparkVersionNumber() > 11) {
-      assertEquals(InterpreterResult.Code.SUCCESS,
-        pySparkInterpreter.interpret("a = 1\n", context).code());
-
-      Thread t = new Thread(new infinityPythonJob());
-      t.start();
-      Thread.sleep(5000);
-      pySparkInterpreter.cancel(context);
-      assertTrue(t.isAlive());
-      t.join(2000);
-      assertFalse(t.isAlive());
-    }
-  }
-}

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/d762b528/spark/src/test/java/org/apache/zeppelin/spark/SparkInterpreterTest.java
----------------------------------------------------------------------
diff --git a/spark/src/test/java/org/apache/zeppelin/spark/SparkInterpreterTest.java b/spark/src/test/java/org/apache/zeppelin/spark/SparkInterpreterTest.java
deleted file mode 100644
index e4f15f4..0000000
--- a/spark/src/test/java/org/apache/zeppelin/spark/SparkInterpreterTest.java
+++ /dev/null
@@ -1,355 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.zeppelin.spark;
-
-import static org.junit.Assert.*;
-
-import java.io.IOException;
-import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.Properties;
-
-import org.apache.spark.SparkConf;
-import org.apache.spark.SparkContext;
-import org.apache.zeppelin.display.AngularObjectRegistry;
-import org.apache.zeppelin.interpreter.remote.RemoteEventClientWrapper;
-import org.apache.zeppelin.interpreter.thrift.InterpreterCompletion;
-import org.apache.zeppelin.resource.LocalResourcePool;
-import org.apache.zeppelin.resource.WellKnownResourceName;
-import org.apache.zeppelin.user.AuthenticationInfo;
-import org.apache.zeppelin.display.GUI;
-import org.apache.zeppelin.interpreter.*;
-import org.apache.zeppelin.interpreter.InterpreterResult.Code;
-import org.junit.*;
-import org.junit.rules.TemporaryFolder;
-import org.junit.runners.MethodSorters;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-public class SparkInterpreterTest {
-
-  @ClassRule
-  public static TemporaryFolder tmpDir = new TemporaryFolder();
-
-  static SparkInterpreter repl;
-  static InterpreterGroup intpGroup;
-  static InterpreterContext context;
-  static Logger LOGGER = LoggerFactory.getLogger(SparkInterpreterTest.class);
-  static Map<String, Map<String, String>> paraIdToInfosMap =
-      new HashMap<>();
-
-  /**
-   * Get spark version number as a numerical value.
-   * eg. 1.1.x => 11, 1.2.x => 12, 1.3.x => 13 ...
-   */
-  public static int getSparkVersionNumber(SparkInterpreter repl) {
-    if (repl == null) {
-      return 0;
-    }
-
-    String[] split = repl.getSparkContext().version().split("\\.");
-    int version = Integer.parseInt(split[0]) * 10 + Integer.parseInt(split[1]);
-    return version;
-  }
-
-  public static Properties getSparkTestProperties(TemporaryFolder tmpDir) throws IOException {
-    Properties p = new Properties();
-    p.setProperty("master", "local[*]");
-    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");
-    p.setProperty("zeppelin.dep.localrepo", tmpDir.newFolder().getAbsolutePath());
-    p.setProperty("zeppelin.spark.property_1", "value_1");
-    return p;
-  }
-
-  @BeforeClass
-  public static void setUp() throws Exception {
-    intpGroup = new InterpreterGroup();
-    intpGroup.put("note", new LinkedList<Interpreter>());
-    repl = new SparkInterpreter(getSparkTestProperties(tmpDir));
-    repl.setInterpreterGroup(intpGroup);
-    intpGroup.get("note").add(repl);
-    repl.open();
-
-    final RemoteEventClientWrapper remoteEventClientWrapper = new RemoteEventClientWrapper() {
-
-      @Override
-      public void onParaInfosReceived(String noteId, String paragraphId,
-          Map<String, String> infos) {
-        if (infos != null) {
-          paraIdToInfosMap.put(paragraphId, infos);
-        }
-      }
-
-      @Override
-      public void onMetaInfosReceived(Map<String, String> infos) {
-      }
-    };
-    context = new InterpreterContext("note", "id", null, "title", "text",
-        new AuthenticationInfo(),
-        new HashMap<String, Object>(),
-        new GUI(),
-        new GUI(),
-        new AngularObjectRegistry(intpGroup.getId(), null),
-        new LocalResourcePool("id"),
-        new LinkedList<InterpreterContextRunner>(),
-        new InterpreterOutput(null)) {
-        
-        @Override
-        public RemoteEventClientWrapper getClient() {
-          return remoteEventClientWrapper;
-        }
-    };
-    // The first para interpretdr will set the Eventclient wrapper
-    //SparkInterpreter.interpret(String, InterpreterContext) ->
-    //SparkInterpreter.populateSparkWebUrl(InterpreterContext) ->
-    //ZeppelinContext.setEventClient(RemoteEventClientWrapper)
-    //running a dummy to ensure that we dont have any race conditions among tests
-    repl.interpret("sc", context);
-  }
-
-  @AfterClass
-  public static void tearDown() {
-    repl.close();
-  }
-
-  @Test
-  public void testBasicIntp() {
-    assertEquals(InterpreterResult.Code.SUCCESS,
-        repl.interpret("val a = 1\nval b = 2", context).code());
-
-    // when interpret incomplete expression
-    InterpreterResult incomplete = repl.interpret("val a = \"\"\"", context);
-    assertEquals(InterpreterResult.Code.INCOMPLETE, incomplete.code());
-    assertTrue(incomplete.message().get(0).getData().length() > 0); // expecting some error
-                                                   // message
-
-    /*
-     * assertEquals(1, repl.getValue("a")); assertEquals(2, repl.getValue("b"));
-     * repl.interpret("val ver = sc.version");
-     * assertNotNull(repl.getValue("ver")); assertEquals("HELLO\n",
-     * repl.interpret("println(\"HELLO\")").message());
-     */
-  }
-
-  @Test
-  public void testNonStandardSparkProperties() throws IOException {
-    // throw NoSuchElementException if no such property is found
-    InterpreterResult result = repl.interpret("sc.getConf.get(\"property_1\")", context);
-    assertEquals(InterpreterResult.Code.SUCCESS, result.code());
-  }
-
-  @Test
-  public void testNextLineInvocation() {
-    assertEquals(InterpreterResult.Code.SUCCESS, repl.interpret("\"123\"\n.toInt", context).code());
-  }
-
-  @Test
-  public void testNextLineComments() {
-    assertEquals(InterpreterResult.Code.SUCCESS, repl.interpret("\"123\"\n/*comment here\n*/.toInt", context).code());
-  }
-
-  @Test
-  public void testNextLineCompanionObject() {
-    String code = "class Counter {\nvar value: Long = 0\n}\n // comment\n\n object Counter {\n def apply(x: Long) = new Counter()\n}";
-    assertEquals(InterpreterResult.Code.SUCCESS, repl.interpret(code, context).code());
-  }
-
-  @Test
-  public void testEndWithComment() {
-    assertEquals(InterpreterResult.Code.SUCCESS, repl.interpret("val c=1\n//comment", context).code());
-  }
-
-  @Test
-  public void testListener() {
-    SparkContext sc = repl.getSparkContext();
-    assertNotNull(SparkInterpreter.setupListeners(sc));
-  }
-
-  @Test
-  public void testCreateDataFrame() {
-    if (getSparkVersionNumber(repl) >= 13) {
-      repl.interpret("case class Person(name:String, age:Int)\n", context);
-      repl.interpret("val people = sc.parallelize(Seq(Person(\"moon\", 33), Person(\"jobs\", 51), Person(\"gates\", 51), Person(\"park\", 34)))\n", context);
-      repl.interpret("people.toDF.count", context);
-      assertEquals(new Long(4), context.getResourcePool().get(
-          context.getNoteId(),
-          context.getParagraphId(),
-          WellKnownResourceName.ZeppelinReplResult.toString()).get());
-    }
-  }
-
-  @Test
-  public void testZShow() {
-    String code = "";
-    repl.interpret("case class Person(name:String, age:Int)\n", context);
-    repl.interpret("val people = sc.parallelize(Seq(Person(\"moon\", 33), Person(\"jobs\", 51), Person(\"gates\", 51), Person(\"park\", 34)))\n", context);
-    if (getSparkVersionNumber(repl) < 13) {
-      repl.interpret("people.registerTempTable(\"people\")", context);
-      code = "z.show(sqlc.sql(\"select * from people\"))";
-    } else {
-      code = "z.show(people.toDF)";
-    }
-      assertEquals(Code.SUCCESS, repl.interpret(code, context).code());
-  }
-
-  @Test
-  public void testSparkSql() throws IOException, InterpreterException {
-    repl.interpret("case class Person(name:String, age:Int)\n", context);
-    repl.interpret("val people = sc.parallelize(Seq(Person(\"moon\", 33), Person(\"jobs\", 51), Person(\"gates\", 51), Person(\"park\", 34)))\n", context);
-    assertEquals(Code.SUCCESS, repl.interpret("people.take(3)", context).code());
-
-
-    if (getSparkVersionNumber(repl) <= 11) { // spark 1.2 or later does not allow create multiple
-      // SparkContext in the same jvm by default.
-      // create new interpreter
-      SparkInterpreter repl2 = new SparkInterpreter(getSparkTestProperties(tmpDir));
-      repl2.setInterpreterGroup(intpGroup);
-      intpGroup.get("note").add(repl2);
-      repl2.open();
-
-      repl2.interpret("case class Man(name:String, age:Int)", context);
-      repl2.interpret("val man = sc.parallelize(Seq(Man(\"moon\", 33), Man(\"jobs\", 51), Man(\"gates\", 51), Man(\"park\", 34)))", context);
-      assertEquals(Code.SUCCESS, repl2.interpret("man.take(3)", context).code());
-      repl2.close();
-    }
-  }
-
-  @Test
-  public void testReferencingUndefinedVal() {
-    InterpreterResult result = repl.interpret("def category(min: Int) = {"
-        + "    if (0 <= value) \"error\"" + "}", context);
-    assertEquals(Code.ERROR, result.code());
-  }
-
-  @Test
-  public void emptyConfigurationVariablesOnlyForNonSparkProperties() {
-    Properties intpProperty = repl.getProperties();
-    SparkConf sparkConf = repl.getSparkContext().getConf();
-    for (Object oKey : intpProperty.keySet()) {
-      String key = (String) oKey;
-      String value = (String) intpProperty.get(key);
-      LOGGER.debug(String.format("[%s]: [%s]", key, value));
-      if (key.startsWith("spark.") && value.isEmpty()) {
-        assertTrue(String.format("configuration starting from 'spark.' should not be empty. [%s]", key), !sparkConf.contains(key) || !sparkConf.get(key).isEmpty());
-      }
-    }
-  }
-
-  @Test
-  public void shareSingleSparkContext() throws InterruptedException, IOException, InterpreterException {
-    // create another SparkInterpreter
-    SparkInterpreter repl2 = new SparkInterpreter(getSparkTestProperties(tmpDir));
-    repl2.setInterpreterGroup(intpGroup);
-    intpGroup.get("note").add(repl2);
-    repl2.open();
-
-    assertEquals(Code.SUCCESS,
-        repl.interpret("print(sc.parallelize(1 to 10).count())", context).code());
-    assertEquals(Code.SUCCESS,
-        repl2.interpret("print(sc.parallelize(1 to 10).count())", context).code());
-
-    repl2.close();
-  }
-
-  @Test
-  public void testEnableImplicitImport() throws IOException, InterpreterException {
-    if (getSparkVersionNumber(repl) >= 13) {
-      // Set option of importing implicits to "true", and initialize new Spark repl
-      Properties p = getSparkTestProperties(tmpDir);
-      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() throws IOException, InterpreterException {
-    if (getSparkVersionNumber(repl) >= 13) {
-      // 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(tmpDir);
-      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();
-    }
-  }
-
-  @Test
-  public void testCompletion() {
-    List<InterpreterCompletion> completions = repl.completion("sc.", "sc.".length(), null);
-    assertTrue(completions.size() > 0);
-  }
-
-  @Test
-  public void testMultilineCompletion() {
-    String buf = "val x = 1\nsc.";
-	List<InterpreterCompletion> completions = repl.completion(buf, buf.length(), null);
-    assertTrue(completions.size() > 0);
-  }
-
-  @Test
-  public void testMultilineCompletionNewVar() {
-    Assume.assumeFalse("this feature does not work with scala 2.10", Utils.isScala2_10());
-    Assume.assumeTrue("This feature does not work with scala < 2.11.8", Utils.isCompilerAboveScala2_11_7());
-    String buf = "val x = sc\nx.";
-	  List<InterpreterCompletion> completions = repl.completion(buf, buf.length(), null);
-    assertTrue(completions.size() > 0);
-  }
-
-  @Test
-  public void testParagraphUrls() {
-    String paraId = "test_para_job_url";
-    InterpreterContext intpCtx = new InterpreterContext("note", paraId, null, "title", "text",
-        new AuthenticationInfo(),
-        new HashMap<String, Object>(),
-        new GUI(),
-        new GUI(),
-        new AngularObjectRegistry(intpGroup.getId(), null),
-        new LocalResourcePool("id"),
-        new LinkedList<InterpreterContextRunner>(),
-        new InterpreterOutput(null));
-    repl.interpret("sc.parallelize(1 to 10).map(x => {x}).collect", intpCtx);
-    Map<String, String> paraInfos = paraIdToInfosMap.get(intpCtx.getParagraphId());
-    String jobUrl = null;
-    if (paraInfos != null) {
-      jobUrl = paraInfos.get("jobUrl");
-    }
-    String sparkUIUrl = repl.getSparkUIUrl();
-    assertNotNull(jobUrl);
-    assertTrue(jobUrl.startsWith(sparkUIUrl + "/jobs/job/?id="));
-
-  }
-}

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/d762b528/spark/src/test/java/org/apache/zeppelin/spark/SparkSqlInterpreterTest.java
----------------------------------------------------------------------
diff --git a/spark/src/test/java/org/apache/zeppelin/spark/SparkSqlInterpreterTest.java b/spark/src/test/java/org/apache/zeppelin/spark/SparkSqlInterpreterTest.java
deleted file mode 100644
index d97e57c..0000000
--- a/spark/src/test/java/org/apache/zeppelin/spark/SparkSqlInterpreterTest.java
+++ /dev/null
@@ -1,180 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.zeppelin.spark;
-
-import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.Properties;
-
-import org.apache.zeppelin.display.AngularObjectRegistry;
-import org.apache.zeppelin.resource.LocalResourcePool;
-import org.apache.zeppelin.user.AuthenticationInfo;
-import org.apache.zeppelin.display.GUI;
-import org.apache.zeppelin.interpreter.*;
-import org.apache.zeppelin.interpreter.InterpreterResult.Type;
-import org.junit.*;
-import org.junit.rules.TemporaryFolder;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
-public class SparkSqlInterpreterTest {
-
-  @ClassRule
-  public static TemporaryFolder tmpDir = new TemporaryFolder();
-
-  static SparkSqlInterpreter sql;
-  static SparkInterpreter repl;
-  static InterpreterContext context;
-  static InterpreterGroup intpGroup;
-
-  @BeforeClass
-  public static void setUp() throws Exception {
-    Properties p = new Properties();
-    p.putAll(SparkInterpreterTest.getSparkTestProperties(tmpDir));
-    p.setProperty("zeppelin.spark.maxResult", "10");
-    p.setProperty("zeppelin.spark.concurrentSQL", "false");
-    p.setProperty("zeppelin.spark.sql.stacktrace", "false");
-
-    repl = new SparkInterpreter(p);
-    intpGroup = new InterpreterGroup();
-    repl.setInterpreterGroup(intpGroup);
-    repl.open();
-    SparkInterpreterTest.repl = repl;
-    SparkInterpreterTest.intpGroup = intpGroup;
-
-    sql = new SparkSqlInterpreter(p);
-
-    intpGroup = new InterpreterGroup();
-    intpGroup.put("note", new LinkedList<Interpreter>());
-    intpGroup.get("note").add(repl);
-    intpGroup.get("note").add(sql);
-    sql.setInterpreterGroup(intpGroup);
-    sql.open();
-
-    context = new InterpreterContext("note", "id", null, "title", "text", new AuthenticationInfo(),
-        new HashMap<String, Object>(), new GUI(), new GUI(),
-        new AngularObjectRegistry(intpGroup.getId(), null),
-        new LocalResourcePool("id"),
-        new LinkedList<InterpreterContextRunner>(), new InterpreterOutput(null));
-  }
-
-  @AfterClass
-  public static void tearDown() {
-    sql.close();
-    repl.close();
-  }
-
-  boolean isDataFrameSupported() {
-    return SparkInterpreterTest.getSparkVersionNumber(repl) >= 13;
-  }
-
-  @Test
-  public void test() throws InterpreterException {
-    repl.interpret("case class Test(name:String, age:Int)", context);
-    repl.interpret("val test = sc.parallelize(Seq(Test(\"moon\", 33), Test(\"jobs\", 51), Test(\"gates\", 51), Test(\"park\", 34)))", context);
-    if (isDataFrameSupported()) {
-      repl.interpret("test.toDF.registerTempTable(\"test\")", context);
-    } else {
-      repl.interpret("test.registerTempTable(\"test\")", context);
-    }
-
-    InterpreterResult ret = sql.interpret("select name, age from test where age < 40", context);
-    assertEquals(InterpreterResult.Code.SUCCESS, ret.code());
-    assertEquals(Type.TABLE, ret.message().get(0).getType());
-    assertEquals("name\tage\nmoon\t33\npark\t34\n", ret.message().get(0).getData());
-
-    ret = sql.interpret("select wrong syntax", context);
-    assertEquals(InterpreterResult.Code.ERROR, ret.code());
-    assertTrue(ret.message().get(0).getData().length() > 0);
-
-    assertEquals(InterpreterResult.Code.SUCCESS, sql.interpret("select case when name==\"aa\" then name else name end from test", context).code());
-  }
-
-  @Test
-  public void testStruct() throws InterpreterException {
-    repl.interpret("case class Person(name:String, age:Int)", context);
-    repl.interpret("case class People(group:String, person:Person)", context);
-    repl.interpret(
-        "val gr = sc.parallelize(Seq(People(\"g1\", Person(\"moon\",33)), People(\"g2\", Person(\"sun\",11))))",
-        context);
-    if (isDataFrameSupported()) {
-      repl.interpret("gr.toDF.registerTempTable(\"gr\")", context);
-    } else {
-      repl.interpret("gr.registerTempTable(\"gr\")", context);
-    }
-
-    InterpreterResult ret = sql.interpret("select * from gr", context);
-    assertEquals(InterpreterResult.Code.SUCCESS, ret.code());
-  }
-
-  @Test
-  public void test_null_value_in_row() throws InterpreterException {
-    repl.interpret("import org.apache.spark.sql._", context);
-    if (isDataFrameSupported()) {
-      repl.interpret(
-          "import org.apache.spark.sql.types.{StructType,StructField,StringType,IntegerType}",
-          context);
-    }
-    repl.interpret(
-        "def toInt(s:String): Any = {try { s.trim().toInt} catch {case e:Exception => null}}",
-        context);
-    repl.interpret(
-        "val schema = StructType(Seq(StructField(\"name\", StringType, false),StructField(\"age\" , IntegerType, true),StructField(\"other\" , StringType, false)))",
-        context);
-    repl.interpret(
-        "val csv = sc.parallelize(Seq((\"jobs, 51, apple\"), (\"gates, , microsoft\")))",
-        context);
-    repl.interpret(
-        "val raw = csv.map(_.split(\",\")).map(p => Row(p(0),toInt(p(1)),p(2)))",
-        context);
-    if (isDataFrameSupported()) {
-      repl.interpret("val people = z.sqlContext.createDataFrame(raw, schema)",
-          context);
-      repl.interpret("people.toDF.registerTempTable(\"people\")", context);
-    } else {
-      repl.interpret("val people = z.sqlContext.applySchema(raw, schema)",
-          context);
-      repl.interpret("people.registerTempTable(\"people\")", context);
-    }
-
-    InterpreterResult ret = sql.interpret(
-        "select name, age from people where name = 'gates'", context);
-    System.err.println("RET=" + ret.message());
-    assertEquals(InterpreterResult.Code.SUCCESS, ret.code());
-    assertEquals(Type.TABLE, ret.message().get(0).getType());
-    assertEquals("name\tage\ngates\tnull\n", ret.message().get(0).getData());
-  }
-
-  @Test
-  public void testMaxResults() throws InterpreterException {
-    repl.interpret("case class P(age:Int)", context);
-    repl.interpret(
-        "val gr = sc.parallelize(Seq(P(1),P(2),P(3),P(4),P(5),P(6),P(7),P(8),P(9),P(10),P(11)))",
-        context);
-    if (isDataFrameSupported()) {
-      repl.interpret("gr.toDF.registerTempTable(\"gr\")", context);
-    } else {
-      repl.interpret("gr.registerTempTable(\"gr\")", context);
-    }
-
-    InterpreterResult ret = sql.interpret("select * from gr", context);
-    assertEquals(InterpreterResult.Code.SUCCESS, ret.code());
-    assertTrue(ret.message().get(1).getData().contains("alert-warning"));
-  }
-}

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/d762b528/spark/src/test/java/org/apache/zeppelin/spark/SparkVersionTest.java
----------------------------------------------------------------------
diff --git a/spark/src/test/java/org/apache/zeppelin/spark/SparkVersionTest.java b/spark/src/test/java/org/apache/zeppelin/spark/SparkVersionTest.java
deleted file mode 100644
index 3dc8f4e..0000000
--- a/spark/src/test/java/org/apache/zeppelin/spark/SparkVersionTest.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.zeppelin.spark;
-
-import static org.junit.Assert.*;
-
-import org.junit.Test;
-
-public class SparkVersionTest {
-
-  @Test
-  public void testUnknownSparkVersion() {
-    assertEquals(99999, SparkVersion.fromVersionString("DEV-10.10").toNumber());
-  }
-
-  @Test
-  public void testUnsupportedVersion() {
-    assertTrue(SparkVersion.fromVersionString("9.9.9").isUnsupportedVersion());
-    assertFalse(SparkVersion.fromVersionString("1.5.9").isUnsupportedVersion());
-    assertTrue(SparkVersion.fromVersionString("0.9.0").isUnsupportedVersion());
-    assertTrue(SparkVersion.UNSUPPORTED_FUTURE_VERSION.isUnsupportedVersion());
-    // should support spark2 version of HDP 2.5
-    assertFalse(SparkVersion.fromVersionString("2.0.0.2.5.0.0-1245").isUnsupportedVersion());
-  }
-
-  @Test
-  public void testSparkVersion() {
-    // test equals
-    assertEquals(SparkVersion.SPARK_1_2_0, SparkVersion.fromVersionString("1.2.0"));
-    assertEquals(SparkVersion.SPARK_1_5_0, SparkVersion.fromVersionString("1.5.0-SNAPSHOT"));
-    assertEquals(SparkVersion.SPARK_1_5_0, SparkVersion.fromVersionString("1.5.0-SNAPSHOT"));
-    // test spark2 version of HDP 2.5
-    assertEquals(SparkVersion.SPARK_2_0_0, SparkVersion.fromVersionString("2.0.0.2.5.0.0-1245"));
-
-    // test newer than
-    assertFalse(SparkVersion.SPARK_1_2_0.newerThan(SparkVersion.SPARK_1_2_0));
-    assertFalse(SparkVersion.SPARK_1_2_0.newerThan(SparkVersion.SPARK_1_3_0));
-    assertTrue(SparkVersion.SPARK_1_2_0.newerThan(SparkVersion.SPARK_1_1_0));
-
-    assertTrue(SparkVersion.SPARK_1_2_0.newerThanEquals(SparkVersion.SPARK_1_2_0));
-    assertFalse(SparkVersion.SPARK_1_2_0.newerThanEquals(SparkVersion.SPARK_1_3_0));
-    assertTrue(SparkVersion.SPARK_1_2_0.newerThanEquals(SparkVersion.SPARK_1_1_0));
-
-    // test older than
-    assertFalse(SparkVersion.SPARK_1_2_0.olderThan(SparkVersion.SPARK_1_2_0));
-    assertFalse(SparkVersion.SPARK_1_2_0.olderThan(SparkVersion.SPARK_1_1_0));
-    assertTrue(SparkVersion.SPARK_1_2_0.olderThan(SparkVersion.SPARK_1_3_0));
-
-    assertTrue(SparkVersion.SPARK_1_2_0.olderThanEquals(SparkVersion.SPARK_1_2_0));
-    assertFalse(SparkVersion.SPARK_1_2_0.olderThanEquals(SparkVersion.SPARK_1_1_0));
-    assertTrue(SparkVersion.SPARK_1_2_0.olderThanEquals(SparkVersion.SPARK_1_3_0));
-
-    // conversion
-    assertEquals(10200, SparkVersion.SPARK_1_2_0.toNumber());
-    assertEquals("1.2.0", SparkVersion.SPARK_1_2_0.toString());
-  }
-}

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/d762b528/spark/src/test/java/org/apache/zeppelin/spark/dep/SparkDependencyResolverTest.java
----------------------------------------------------------------------
diff --git a/spark/src/test/java/org/apache/zeppelin/spark/dep/SparkDependencyResolverTest.java b/spark/src/test/java/org/apache/zeppelin/spark/dep/SparkDependencyResolverTest.java
deleted file mode 100644
index b226a00..0000000
--- a/spark/src/test/java/org/apache/zeppelin/spark/dep/SparkDependencyResolverTest.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.zeppelin.spark.dep;
-
-import static org.junit.Assert.assertEquals;
-
-import org.junit.Test;
-
-public class SparkDependencyResolverTest {
-
-  @Test
-  public void testInferScalaVersion() {
-    String [] version = scala.util.Properties.versionNumberString().split("[.]");
-    String scalaVersion = version[0] + "." + version[1];
-
-    assertEquals("groupId:artifactId:version",
-        SparkDependencyResolver.inferScalaVersion("groupId:artifactId:version"));
-    assertEquals("groupId:artifactId_" + scalaVersion + ":version",
-        SparkDependencyResolver.inferScalaVersion("groupId::artifactId:version"));
-    assertEquals("groupId:artifactId:version::test",
-        SparkDependencyResolver.inferScalaVersion("groupId:artifactId:version::test"));
-    assertEquals("*",
-        SparkDependencyResolver.inferScalaVersion("*"));
-    assertEquals("groupId:*",
-        SparkDependencyResolver.inferScalaVersion("groupId:*"));
-    assertEquals("groupId:artifactId*",
-        SparkDependencyResolver.inferScalaVersion("groupId:artifactId*"));
-    assertEquals("groupId:artifactId_" + scalaVersion,
-        SparkDependencyResolver.inferScalaVersion("groupId::artifactId"));
-    assertEquals("groupId:artifactId_" + scalaVersion + "*",
-        SparkDependencyResolver.inferScalaVersion("groupId::artifactId*"));
-    assertEquals("groupId:artifactId_" + scalaVersion + ":*",
-        SparkDependencyResolver.inferScalaVersion("groupId::artifactId:*"));
-  }
-
-}

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/d762b528/spark/src/test/resources/log4j.properties
----------------------------------------------------------------------
diff --git a/spark/src/test/resources/log4j.properties b/spark/src/test/resources/log4j.properties
deleted file mode 100644
index 3ee61ab..0000000
--- a/spark/src/test/resources/log4j.properties
+++ /dev/null
@@ -1,49 +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.
-#
-
-# Direct log messages to stdout
-log4j.appender.stdout=org.apache.log4j.ConsoleAppender
-log4j.appender.stdout.Target=System.out
-log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
-log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c:%L - %m%n
-#log4j.appender.stdout.layout.ConversionPattern=
-#%5p [%t] (%F:%L) - %m%n
-#%-4r [%t] %-5p %c %x - %m%n
-#
-
-# Root logger option
-log4j.rootLogger=INFO, stdout
- 
-#mute some noisy guys
-log4j.logger.org.apache.hadoop.mapred=WARN
-log4j.logger.org.apache.hadoop.hive.ql=WARN
-log4j.logger.org.apache.hadoop.hive.metastore=WARN
-log4j.logger.org.apache.haadoop.hive.service.HiveServer=WARN
-log4j.logger.org.apache.zeppelin.scheduler=WARN
-
-log4j.logger.org.quartz=WARN
-log4j.logger.DataNucleus=WARN
-log4j.logger.DataNucleus.MetaData=ERROR
-log4j.logger.DataNucleus.Datastore=ERROR
-
-# Log all JDBC parameters
-log4j.logger.org.hibernate.type=ALL
-
-log4j.logger.org.apache.zeppelin.interpreter=DEBUG
-log4j.logger.org.apache.zeppelin.spark=DEBUG
-log4j.logger.org.apache.zeppelin.python.IPythonInterpreter=DEBUG
-log4j.logger.org.apache.zeppelin.python.IPythonClient=DEBUG

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/d762b528/spark/src/test/scala/org/apache/zeppelin/spark/utils/DisplayFunctionsTest.scala
----------------------------------------------------------------------
diff --git a/spark/src/test/scala/org/apache/zeppelin/spark/utils/DisplayFunctionsTest.scala b/spark/src/test/scala/org/apache/zeppelin/spark/utils/DisplayFunctionsTest.scala
deleted file mode 100644
index 2638f17..0000000
--- a/spark/src/test/scala/org/apache/zeppelin/spark/utils/DisplayFunctionsTest.scala
+++ /dev/null
@@ -1,173 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.zeppelin.spark.utils
-
-import java.io.ByteArrayOutputStream
-
-import org.apache.spark.rdd.RDD
-import org.apache.spark.{SparkContext, SparkConf}
-import org.scalatest._
-import org.scalatest.{BeforeAndAfter}
-
-case class Person(login : String, name: String, age: Int)
-
-class DisplayFunctionsTest extends FlatSpec with BeforeAndAfter with BeforeAndAfterEach with Matchers {
-  var sc: SparkContext = null
-  var testTuples:List[(String, String, Int)] = null
-  var testPersons:List[Person] = null
-  var testRDDTuples: RDD[(String,String,Int)]  = null
-  var testRDDPersons: RDD[Person]  = null
-  var stream: ByteArrayOutputStream = null
-  
-  before {
-    val sparkConf: SparkConf = new SparkConf(true)
-      .setAppName("test-DisplayFunctions")
-      .setMaster("local")
-    sc = new SparkContext(sparkConf)
-    testTuples = List(("jdoe", "John DOE", 32), ("hsue", "Helen SUE", 27), ("rsmith", "Richard SMITH", 45))
-    testRDDTuples = sc.parallelize(testTuples)
-    testPersons = List(Person("jdoe", "John DOE", 32), Person("hsue", "Helen SUE", 27), Person("rsmith", "Richard SMITH", 45))
-    testRDDPersons = sc.parallelize(testPersons)
-  }
-
-  override def beforeEach() {
-    stream = new java.io.ByteArrayOutputStream()
-    super.beforeEach() // To be stackable, must call super.beforeEach
-  }
-
-
-  "DisplayFunctions" should "generate correct column headers for tuples" in {
-    implicit val sparkMaxResult = new SparkMaxResult(100)
-    Console.withOut(stream) {
-      new DisplayRDDFunctions[(String,String,Int)](testRDDTuples).display("Login","Name","Age")
-    }
-
-    stream.toString("UTF-8") should be("%table Login\tName\tAge\n" +
-      "jdoe\tJohn DOE\t32\n" +
-      "hsue\tHelen SUE\t27\n" +
-      "rsmith\tRichard SMITH\t45\n")
-  }
-
-  "DisplayFunctions" should "generate correct column headers for case class" in {
-    implicit val sparkMaxResult = new SparkMaxResult(100)
-    Console.withOut(stream) {
-      new DisplayRDDFunctions[Person](testRDDPersons).display("Login","Name","Age")
-    }
-
-    stream.toString("UTF-8") should be("%table Login\tName\tAge\n" +
-      "jdoe\tJohn DOE\t32\n" +
-      "hsue\tHelen SUE\t27\n" +
-      "rsmith\tRichard SMITH\t45\n")
-  }
-
-  "DisplayFunctions" should "truncate exceeding column headers for tuples" in {
-    implicit val sparkMaxResult = new SparkMaxResult(100)
-    Console.withOut(stream) {
-      new DisplayRDDFunctions[(String,String,Int)](testRDDTuples).display("Login","Name","Age","xxx","yyy")
-    }
-
-    stream.toString("UTF-8") should be("%table Login\tName\tAge\n" +
-      "jdoe\tJohn DOE\t32\n" +
-      "hsue\tHelen SUE\t27\n" +
-      "rsmith\tRichard SMITH\t45\n")
-  }
-
-  "DisplayFunctions" should "pad missing column headers with ColumnXXX for tuples" in {
-    implicit val sparkMaxResult = new SparkMaxResult(100)
-    Console.withOut(stream) {
-      new DisplayRDDFunctions[(String,String,Int)](testRDDTuples).display("Login")
-    }
-
-    stream.toString("UTF-8") should be("%table Login\tColumn2\tColumn3\n" +
-      "jdoe\tJohn DOE\t32\n" +
-      "hsue\tHelen SUE\t27\n" +
-      "rsmith\tRichard SMITH\t45\n")
-  }
-
-  "DisplayUtils" should "restricts RDD to sparkMaxresult with implicit limit" in {
-
-    implicit val sparkMaxResult = new SparkMaxResult(2)
-
-    Console.withOut(stream) {
-      new DisplayRDDFunctions[(String,String,Int)](testRDDTuples).display("Login")
-    }
-
-    stream.toString("UTF-8") should be("%table Login\tColumn2\tColumn3\n" +
-      "jdoe\tJohn DOE\t32\n" +
-      "hsue\tHelen SUE\t27\n")
-  }
-
-  "DisplayUtils" should "restricts RDD to sparkMaxresult with explicit limit" in {
-
-    implicit val sparkMaxResult = new SparkMaxResult(2)
-
-    Console.withOut(stream) {
-      new DisplayRDDFunctions[(String,String,Int)](testRDDTuples).display(1,"Login")
-    }
-
-    stream.toString("UTF-8") should be("%table Login\tColumn2\tColumn3\n" +
-      "jdoe\tJohn DOE\t32\n")
-  }
-
-  "DisplayFunctions" should "display traversable of tuples" in {
-
-    Console.withOut(stream) {
-      new DisplayTraversableFunctions[(String,String,Int)](testTuples).display("Login","Name","Age")
-    }
-
-    stream.toString("UTF-8") should be("%table Login\tName\tAge\n" +
-      "jdoe\tJohn DOE\t32\n" +
-      "hsue\tHelen SUE\t27\n" +
-      "rsmith\tRichard SMITH\t45\n")
-  }
-
-  "DisplayFunctions" should "display traversable of case class" in {
-
-    Console.withOut(stream) {
-      new DisplayTraversableFunctions[Person](testPersons).display("Login","Name","Age")
-    }
-
-    stream.toString("UTF-8") should be("%table Login\tName\tAge\n" +
-      "jdoe\tJohn DOE\t32\n" +
-      "hsue\tHelen SUE\t27\n" +
-      "rsmith\tRichard SMITH\t45\n")
-  }
-
-  "DisplayUtils" should "display HTML" in {
-    DisplayUtils.html() should be ("%html ")
-    DisplayUtils.html("test") should be ("%html test")
-  }
-
-  "DisplayUtils" should "display img" in {
-    DisplayUtils.img("http://www.google.com") should be ("<img src='http://www.google.com' />")
-    DisplayUtils.img64() should be ("%img ")
-    DisplayUtils.img64("abcde") should be ("%img abcde")
-  }
-
-  override def afterEach() {
-    try super.afterEach() // To be stackable, must call super.afterEach
-    stream = null
-  }
-
-  after {
-    sc.stop()
-  }
-
-
-}
-
-

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/d762b528/testing/install_external_dependencies.sh
----------------------------------------------------------------------
diff --git a/testing/install_external_dependencies.sh b/testing/install_external_dependencies.sh
index e34296e..d6c0736 100755
--- a/testing/install_external_dependencies.sh
+++ b/testing/install_external_dependencies.sh
@@ -44,6 +44,6 @@ if [[ -n "$PYTHON" ]] ; then
   conda update -q conda
   conda info -a
   conda config --add channels conda-forge
-  conda install -q matplotlib pandasql ipython=5.4.1 jupyter_client ipykernel matplotlib bokeh=0.12.6
-  pip install -q grpcio ggplot
+  conda install -q matplotlib pandasql ipython=5.4.1 jupyter_client ipykernel matplotlib bokeh=0.12.10
+  pip install -q grpcio ggplot bkzep==0.4.0
 fi

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/d762b528/zeppelin-display/pom.xml
----------------------------------------------------------------------
diff --git a/zeppelin-display/pom.xml b/zeppelin-display/pom.xml
index c6edd95..79a08a6 100644
--- a/zeppelin-display/pom.xml
+++ b/zeppelin-display/pom.xml
@@ -27,7 +27,7 @@
   </parent>
 
   <groupId>org.apache.zeppelin</groupId>
-  <artifactId>zeppelin-display_2.10</artifactId>
+  <artifactId>zeppelin-display</artifactId>
   <packaging>jar</packaging>
   <version>0.9.0-SNAPSHOT</version>
   <name>Zeppelin: Display system apis</name>
@@ -45,18 +45,21 @@
         <groupId>org.scala-lang</groupId>
         <artifactId>scala-library</artifactId>
         <version>${scala.version}</version>
+        <scope>provided</scope>
       </dependency>
 
       <dependency>
         <groupId>org.scala-lang</groupId>
         <artifactId>scala-compiler</artifactId>
         <version>${scala.version}</version>
+        <scope>provided</scope>
       </dependency>
 
       <dependency>
         <groupId>org.scala-lang</groupId>
         <artifactId>scalap</artifactId>
         <version>${scala.version}</version>
+        <scope>provided</scope>
       </dependency>
     </dependencies>
   </dependencyManagement>
@@ -85,13 +88,6 @@
     </dependency>
 
     <dependency>
-      <groupId>org.scala-lang</groupId>
-      <artifactId>scala-library</artifactId>
-      <version>${scala.version}</version>
-      <scope>provided</scope>
-    </dependency>
-
-    <dependency>
       <groupId>org.scalatest</groupId>
       <artifactId>scalatest_${scala.binary.version}</artifactId>
       <version>${scalatest.version}</version>

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/d762b528/zeppelin-integration/src/test/java/org/apache/zeppelin/integration/SparkParagraphIT.java
----------------------------------------------------------------------
diff --git a/zeppelin-integration/src/test/java/org/apache/zeppelin/integration/SparkParagraphIT.java b/zeppelin-integration/src/test/java/org/apache/zeppelin/integration/SparkParagraphIT.java
index f7bb776..1804fc4 100644
--- a/zeppelin-integration/src/test/java/org/apache/zeppelin/integration/SparkParagraphIT.java
+++ b/zeppelin-integration/src/test/java/org/apache/zeppelin/integration/SparkParagraphIT.java
@@ -184,7 +184,7 @@ public class SparkParagraphIT extends AbstractZeppelinIT {
     }
   }
 
-  @Test
+//  @Test
   public void testDep() throws Exception {
     try {
       // restart spark interpreter before running %dep

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/d762b528/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/BaseZeppelinContext.java
----------------------------------------------------------------------
diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/BaseZeppelinContext.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/BaseZeppelinContext.java
index 65bb06f..e38a29f 100644
--- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/BaseZeppelinContext.java
+++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/BaseZeppelinContext.java
@@ -237,6 +237,8 @@ public abstract class BaseZeppelinContext {
       if (isSupportedObject(o)) {
         interpreterContext.out.write(showData(o));
       } else {
+        interpreterContext.out.write("ZeppelinContext doesn't support to show type: "
+            + o.getClass().getCanonicalName() + "\n");
         interpreterContext.out.write(o.toString());
       }
     } catch (IOException e) {

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/d762b528/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/remote/RemoteInterpreterServer.java
----------------------------------------------------------------------
diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/remote/RemoteInterpreterServer.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/remote/RemoteInterpreterServer.java
index fca8449..37db1fc 100644
--- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/remote/RemoteInterpreterServer.java
+++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/remote/RemoteInterpreterServer.java
@@ -96,10 +96,10 @@ import java.util.concurrent.ConcurrentMap;
  * Entry point for Interpreter process.
  * Accepting thrift connections from ZeppelinServer.
  */
-public class RemoteInterpreterServer
-    extends Thread
+public class RemoteInterpreterServer extends Thread
     implements RemoteInterpreterService.Iface, AngularObjectRegistryListener {
-  Logger logger = LoggerFactory.getLogger(RemoteInterpreterServer.class);
+
+  private static Logger logger = LoggerFactory.getLogger(RemoteInterpreterServer.class);
 
   InterpreterGroup interpreterGroup;
   AngularObjectRegistry angularObjectRegistry;
@@ -255,6 +255,9 @@ public class RemoteInterpreterServer
 
   public static void main(String[] args)
       throws TTransportException, InterruptedException, IOException {
+    Class klass = RemoteInterpreterServer.class;
+    URL location = klass.getResource('/' + klass.getName().replace('.', '/') + ".class");
+    logger.info("URL:" + location);
     String callbackHost = null;
     int port = Constants.ZEPPELIN_INTERPRETER_DEFAUlT_PORT;
     String portRange = ":";

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/d762b528/zeppelin-server/pom.xml
----------------------------------------------------------------------
diff --git a/zeppelin-server/pom.xml b/zeppelin-server/pom.xml
index a73cd96..970f302 100644
--- a/zeppelin-server/pom.xml
+++ b/zeppelin-server/pom.xml
@@ -261,6 +261,12 @@
       <artifactId>scalatest_${scala.binary.version}</artifactId>
       <version>${scalatest.version}</version>
       <scope>test</scope>
+      <exclusions>
+        <exclusion>
+          <groupId>org.scala-lang.modules</groupId>
+          <artifactId>scala-xml_${scala.binary.version}</artifactId>
+        </exclusion>
+      </exclusions>
     </dependency>
 
     <dependency>

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/d762b528/zeppelin-server/src/test/java/org/apache/zeppelin/rest/AbstractTestRestApi.java
----------------------------------------------------------------------
diff --git a/zeppelin-server/src/test/java/org/apache/zeppelin/rest/AbstractTestRestApi.java b/zeppelin-server/src/test/java/org/apache/zeppelin/rest/AbstractTestRestApi.java
index 7d4c21c..5193420 100644
--- a/zeppelin-server/src/test/java/org/apache/zeppelin/rest/AbstractTestRestApi.java
+++ b/zeppelin-server/src/test/java/org/apache/zeppelin/rest/AbstractTestRestApi.java
@@ -265,21 +265,21 @@ public abstract class AbstractTestRestApi {
         // set spark master and other properties
         sparkProperties.put("master",
             new InterpreterProperty("master", "local[2]", InterpreterPropertyType.TEXTAREA.getValue()));
+        sparkProperties.put("spark.master",
+            new InterpreterProperty("spark.master", "local[2]", InterpreterPropertyType.TEXTAREA.getValue()));
         sparkProperties.put("spark.cores.max",
             new InterpreterProperty("spark.cores.max", "2", InterpreterPropertyType.TEXTAREA.getValue()));
         sparkProperties.put("zeppelin.spark.useHiveContext",
             new InterpreterProperty("zeppelin.spark.useHiveContext", false, InterpreterPropertyType.CHECKBOX.getValue()));
-        // set spark home for pyspark
-        sparkProperties.put("spark.home",
-            new InterpreterProperty("spark.home", getSparkHome(), InterpreterPropertyType.TEXTAREA.getValue()));
         sparkProperties.put("zeppelin.pyspark.useIPython",  new InterpreterProperty("zeppelin.pyspark.useIPython", "false", InterpreterPropertyType.TEXTAREA.getValue()));
-
+        sparkProperties.put("zeppelin.spark.test", new InterpreterProperty("zeppelin.spark.test", "true", InterpreterPropertyType.TEXTAREA.getValue()));
         sparkIntpSetting.setProperties(sparkProperties);
         pySpark = true;
         sparkR = true;
         ZeppelinServer.notebook.getInterpreterSettingManager().restart(sparkIntpSetting.getId());
       } else {
         String sparkHome = getSparkHome();
+        LOG.info("SPARK HOME detected " + sparkHome);
         if (sparkHome != null) {
           if (System.getenv("SPARK_MASTER") != null) {
             sparkProperties.put("master",
@@ -288,14 +288,14 @@ public abstract class AbstractTestRestApi {
             sparkProperties.put("master",
                 new InterpreterProperty("master", "local[2]", InterpreterPropertyType.TEXTAREA.getValue()));
           }
+          sparkProperties.put("spark.master",
+              new InterpreterProperty("spark.master", "local[2]", InterpreterPropertyType.TEXTAREA.getValue()));
           sparkProperties.put("spark.cores.max",
               new InterpreterProperty("spark.cores.max", "2", InterpreterPropertyType.TEXTAREA.getValue()));
-          // set spark home for pyspark
-          sparkProperties.put("spark.home",
-              new InterpreterProperty("spark.home", sparkHome, InterpreterPropertyType.TEXTAREA.getValue()));
           sparkProperties.put("zeppelin.spark.useHiveContext",
               new InterpreterProperty("zeppelin.spark.useHiveContext", false, InterpreterPropertyType.CHECKBOX.getValue()));
           sparkProperties.put("zeppelin.pyspark.useIPython",  new InterpreterProperty("zeppelin.pyspark.useIPython", "false", InterpreterPropertyType.TEXTAREA.getValue()));
+          sparkProperties.put("zeppelin.spark.test", new InterpreterProperty("zeppelin.spark.test", "true", InterpreterPropertyType.TEXTAREA.getValue()));
 
           pySpark = true;
           sparkR = true;
@@ -333,7 +333,6 @@ public abstract class AbstractTestRestApi {
       return sparkHome;
     }
     sparkHome = getSparkHomeRecursively(new File(System.getProperty(ZeppelinConfiguration.ConfVars.ZEPPELIN_HOME.getVarName())));
-    System.out.println("SPARK HOME detected " + sparkHome);
     return sparkHome;
   }
 

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/d762b528/zeppelin-server/src/test/java/org/apache/zeppelin/rest/ZeppelinSparkClusterTest.java
----------------------------------------------------------------------
diff --git a/zeppelin-server/src/test/java/org/apache/zeppelin/rest/ZeppelinSparkClusterTest.java b/zeppelin-server/src/test/java/org/apache/zeppelin/rest/ZeppelinSparkClusterTest.java
index 6156755..f3a7099 100644
--- a/zeppelin-server/src/test/java/org/apache/zeppelin/rest/ZeppelinSparkClusterTest.java
+++ b/zeppelin-server/src/test/java/org/apache/zeppelin/rest/ZeppelinSparkClusterTest.java
@@ -167,8 +167,8 @@ public class ZeppelinSparkClusterTest extends AbstractTestRestApi {
                 assertEquals(InterpreterResult.Type.TABLE, p.getResult().message().get(1).getType());
                 assertEquals("_1\t_2\nhello\t20\n", p.getResult().message().get(1).getData());
             }
-            ZeppelinServer.notebook.removeNote(note.getId(), anonymous);
         }
+        ZeppelinServer.notebook.removeNote(note.getId(), anonymous);
     }
 
     @Test
@@ -470,7 +470,7 @@ public class ZeppelinSparkClusterTest extends AbstractTestRestApi {
             p1.setText("%pyspark\n" +
                     "from pyspark.sql import SQLContext\n" +
                     "print(" + sqlContextName + ".read.format('com.databricks.spark.csv')" +
-                    ".load('"+ tmpFile.getAbsolutePath() +"').count())");
+                    ".load('" + tmpFile.getAbsolutePath() +"').count())");
             p1.setAuthenticationInfo(anonymous);
             note.run(p1.getId());
 
@@ -576,6 +576,7 @@ public class ZeppelinSparkClusterTest extends AbstractTestRestApi {
 
     @Test
     public void testConfInterpreter() throws IOException {
+        ZeppelinServer.notebook.getInterpreterSettingManager().close();
         Note note = ZeppelinServer.notebook.createNote(AuthenticationInfo.ANONYMOUS);
         Paragraph p = note.addNewParagraph(AuthenticationInfo.ANONYMOUS);
         Map config = p.getConfig();

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/d762b528/zeppelin-zengine/pom.xml
----------------------------------------------------------------------
diff --git a/zeppelin-zengine/pom.xml b/zeppelin-zengine/pom.xml
index ac75360..fade4dd 100644
--- a/zeppelin-zengine/pom.xml
+++ b/zeppelin-zengine/pom.xml
@@ -603,7 +603,7 @@
 
         <dependency>
           <groupId>org.apache.zeppelin</groupId>
-          <artifactId>zeppelin-spark_2.10</artifactId>
+          <artifactId>spark-interpreter</artifactId>
           <version>${project.version}</version>
           <scope>test</scope>
           <exclusions>


[04/10] zeppelin git commit: ZEPPELIN-3111. Refactor SparkInterpreter

Posted by zj...@apache.org.
http://git-wip-us.apache.org/repos/asf/zeppelin/blob/d762b528/spark/spark-scala-parent/src/main/scala/org/apache/zeppelin/spark/BaseSparkScalaInterpreter.scala
----------------------------------------------------------------------
diff --git a/spark/spark-scala-parent/src/main/scala/org/apache/zeppelin/spark/BaseSparkScalaInterpreter.scala b/spark/spark-scala-parent/src/main/scala/org/apache/zeppelin/spark/BaseSparkScalaInterpreter.scala
new file mode 100644
index 0000000..3ef4fe7
--- /dev/null
+++ b/spark/spark-scala-parent/src/main/scala/org/apache/zeppelin/spark/BaseSparkScalaInterpreter.scala
@@ -0,0 +1,338 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.zeppelin.spark
+
+
+import java.io.File
+
+import org.apache.spark.sql.SQLContext
+import org.apache.spark.{SparkConf, SparkContext}
+import org.apache.zeppelin.interpreter.thrift.InterpreterCompletion
+import org.apache.zeppelin.interpreter.util.InterpreterOutputStream
+import org.apache.zeppelin.interpreter.{InterpreterContext, InterpreterResult}
+import org.slf4j.{Logger, LoggerFactory}
+
+import scala.collection.JavaConverters._
+import scala.tools.nsc.interpreter.Completion.ScalaCompleter
+import scala.util.control.NonFatal
+
+/**
+  * Base class for different scala versions of SparkInterpreter. It should be
+  * binary compatible between multiple scala versions.
+  * @param conf
+  * @param depFiles
+  */
+abstract class BaseSparkScalaInterpreter(val conf: SparkConf,
+                                         val depFiles: java.util.List[String]) {
+
+  protected lazy val LOGGER: Logger = LoggerFactory.getLogger(getClass)
+
+  private val isTest = conf.getBoolean("zeppelin.spark.test", false)
+
+  protected var sc: SparkContext = _
+
+  protected var sqlContext: SQLContext = _
+
+  protected var sparkSession: Object = _
+
+  protected var sparkHttpServer: Object = _
+
+  protected var sparkUrl: String = _
+
+  protected var scalaCompleter: ScalaCompleter = _
+
+  protected val interpreterOutput: InterpreterOutputStream
+
+  protected def open(): Unit = {
+    /* Required for scoped mode.
+     * In scoped mode multiple scala compiler (repl) generates class in the same directory.
+     * Class names is not randomly generated and look like '$line12.$read$$iw$$iw'
+     * Therefore it's possible to generated class conflict(overwrite) with other repl generated
+     * class.
+     *
+     * To prevent generated class name conflict,
+     * change prefix of generated class name from each scala compiler (repl) instance.
+     *
+     * In Spark 2.x, REPL generated wrapper class name should compatible with the pattern
+     * ^(\$line(?:\d+)\.\$read)(?:\$\$iw)+$
+     *
+     * As hashCode() can return a negative integer value and the minus character '-' is invalid
+     * in a package name we change it to a numeric value '0' which still conforms to the regexp.
+     *
+     */
+    System.setProperty("scala.repl.name.line", ("$line" + this.hashCode).replace('-', '0'))
+  }
+
+  protected def interpret(code: String, context: InterpreterContext): InterpreterResult
+
+  protected def interpret(code: String): InterpreterResult = interpret(code, null)
+
+  protected def scalaInterpret(code: String): scala.tools.nsc.interpreter.IR.Result
+
+  protected def completion(buf: String,
+                           cursor: Int,
+                           context: InterpreterContext): java.util.List[InterpreterCompletion] = {
+    val completions = scalaCompleter.complete(buf, cursor).candidates
+      .map(e => new InterpreterCompletion(e, e, null))
+    scala.collection.JavaConversions.seqAsJavaList(completions)
+  }
+
+  protected def getProgress(jobGroup: String, context: InterpreterContext): Int = {
+    val jobIds = sc.statusTracker.getJobIdsForGroup(jobGroup)
+    val jobs = jobIds.flatMap { id => sc.statusTracker.getJobInfo(id) }
+    val stages = jobs.flatMap { job =>
+      job.stageIds().flatMap(sc.statusTracker.getStageInfo)
+    }
+
+    val taskCount = stages.map(_.numTasks).sum
+    val completedTaskCount = stages.map(_.numCompletedTasks).sum
+    if (taskCount == 0) {
+      0
+    } else {
+      (100 * completedTaskCount.toDouble / taskCount).toInt
+    }
+  }
+
+  protected def bind(name: String, tpe: String, value: Object, modifier: List[String]): Unit
+
+  // for use in java side
+  protected def bind(name: String,
+                     tpe: String,
+                     value: Object,
+                     modifier: java.util.List[String]): Unit =
+    bind(name, tpe, value, modifier.asScala.toList)
+
+  protected def close(): Unit = {
+    if (sc != null) {
+      sc.stop()
+    }
+    if (sparkHttpServer != null) {
+      sparkHttpServer.getClass.getMethod("stop").invoke(sparkHttpServer)
+    }
+    sc = null
+    sqlContext = null
+    if (sparkSession != null) {
+      sparkSession.getClass.getMethod("stop").invoke(sparkSession)
+      sparkSession = null
+    }
+
+  }
+
+  protected def createSparkContext(): Unit = {
+    if (isSparkSessionPresent()) {
+      spark2CreateContext()
+    } else {
+      spark1CreateContext()
+    }
+  }
+
+  private def spark1CreateContext(): Unit = {
+    this.sc = SparkContext.getOrCreate(conf)
+    if (!isTest) {
+      interpreterOutput.write("Created SparkContext.\n".getBytes())
+    }
+    getUserFiles().foreach(file => sc.addFile(file))
+
+    sc.getClass.getMethod("ui").invoke(sc).asInstanceOf[Option[_]] match {
+      case Some(webui) =>
+        sparkUrl = webui.getClass.getMethod("appUIAddress").invoke(webui).asInstanceOf[String]
+      case None =>
+    }
+
+    val hiveSiteExisted: Boolean =
+      Thread.currentThread().getContextClassLoader.getResource("hive-site.xml") != null
+    val hiveEnabled = conf.getBoolean("spark.useHiveContext", false)
+    if (hiveEnabled && hiveSiteExisted) {
+      sqlContext = Class.forName("org.apache.spark.sql.hive.HiveContext")
+        .getConstructor(classOf[SparkContext]).newInstance(sc).asInstanceOf[SQLContext]
+      if (!isTest) {
+        interpreterOutput.write("Created sql context (with Hive support).\n".getBytes())
+      }
+    } else {
+      if (hiveEnabled && !hiveSiteExisted && !isTest) {
+        interpreterOutput.write(("spark.useHiveContext is set as true but no hive-site.xml" +
+          " is found in classpath, so zeppelin will fallback to SQLContext.\n").getBytes())
+      }
+      sqlContext = Class.forName("org.apache.spark.sql.SQLContext")
+        .getConstructor(classOf[SparkContext]).newInstance(sc).asInstanceOf[SQLContext]
+      if (!isTest) {
+        interpreterOutput.write("Created sql context.\n".getBytes())
+      }
+    }
+
+    bind("sc", "org.apache.spark.SparkContext", sc, List("""@transient"""))
+    bind("sqlContext", sqlContext.getClass.getCanonicalName, sqlContext, List("""@transient"""))
+
+    interpret("import org.apache.spark.SparkContext._")
+    interpret("import sqlContext.implicits._")
+    interpret("import sqlContext.sql")
+    interpret("import org.apache.spark.sql.functions._")
+  }
+
+  private def spark2CreateContext(): Unit = {
+    val sparkClz = Class.forName("org.apache.spark.sql.SparkSession$")
+    val sparkObj = sparkClz.getField("MODULE$").get(null)
+
+    val builderMethod = sparkClz.getMethod("builder")
+    val builder = builderMethod.invoke(sparkObj)
+    builder.getClass.getMethod("config", classOf[SparkConf]).invoke(builder, conf)
+
+    if (conf.get("spark.sql.catalogImplementation", "in-memory").toLowerCase == "hive"
+        || conf.get("spark.useHiveContext", "false").toLowerCase == "true") {
+      val hiveSiteExisted: Boolean =
+        Thread.currentThread().getContextClassLoader.getResource("hive-site.xml") != null
+      val hiveClassesPresent =
+        sparkClz.getMethod("hiveClassesArePresent").invoke(sparkObj).asInstanceOf[Boolean]
+      if (hiveSiteExisted && hiveClassesPresent) {
+        builder.getClass.getMethod("enableHiveSupport").invoke(builder)
+        sparkSession = builder.getClass.getMethod("getOrCreate").invoke(builder)
+        if (!isTest) {
+          interpreterOutput.write("Created Spark session (with Hive support).\n".getBytes())
+        }
+      } else {
+        if (!hiveClassesPresent && !isTest) {
+          interpreterOutput.write(
+            "Hive support can not be enabled because spark is not built with hive\n".getBytes)
+        }
+        if (!hiveSiteExisted && !isTest) {
+          interpreterOutput.write(
+            "Hive support can not be enabled because no hive-site.xml found\n".getBytes)
+        }
+        sparkSession = builder.getClass.getMethod("getOrCreate").invoke(builder)
+        if (!isTest) {
+          interpreterOutput.write("Created Spark session.\n".getBytes())
+        }
+      }
+    } else {
+      sparkSession = builder.getClass.getMethod("getOrCreate").invoke(builder)
+      if (!isTest) {
+        interpreterOutput.write("Created Spark session.\n".getBytes())
+      }
+    }
+
+    sc = sparkSession.getClass.getMethod("sparkContext").invoke(sparkSession)
+      .asInstanceOf[SparkContext]
+    getUserFiles().foreach(file => sc.addFile(file))
+    sqlContext = sparkSession.getClass.getMethod("sqlContext").invoke(sparkSession)
+      .asInstanceOf[SQLContext]
+    sc.getClass.getMethod("uiWebUrl").invoke(sc).asInstanceOf[Option[String]] match {
+      case Some(url) => sparkUrl = url
+      case None =>
+    }
+
+    bind("spark", sparkSession.getClass.getCanonicalName, sparkSession, List("""@transient"""))
+    bind("sc", "org.apache.spark.SparkContext", sc, List("""@transient"""))
+    bind("sqlContext", "org.apache.spark.sql.SQLContext", sqlContext, List("""@transient"""))
+
+    interpret("import org.apache.spark.SparkContext._")
+    interpret("import spark.implicits._")
+    interpret("import spark.sql")
+    interpret("import org.apache.spark.sql.functions._")
+  }
+
+  private def isSparkSessionPresent(): Boolean = {
+    try {
+      Class.forName("org.apache.spark.sql.SparkSession")
+      true
+    } catch {
+      case _: ClassNotFoundException | _: NoClassDefFoundError => false
+    }
+  }
+
+  protected def getField(obj: Object, name: String): Object = {
+    val field = obj.getClass.getField(name)
+    field.setAccessible(true)
+    field.get(obj)
+  }
+
+  protected def getDeclareField(obj: Object, name: String): Object = {
+    val field = obj.getClass.getDeclaredField(name)
+    field.setAccessible(true)
+    field.get(obj)
+  }
+
+  protected def setDeclaredField(obj: Object, name: String, value: Object): Unit = {
+    val field = obj.getClass.getDeclaredField(name)
+    field.setAccessible(true)
+    field.set(obj, value)
+  }
+
+  protected def callMethod(obj: Object, name: String): Object = {
+    callMethod(obj, name, Array.empty[Class[_]], Array.empty[Object])
+  }
+
+  protected def callMethod(obj: Object, name: String,
+                           parameterTypes: Array[Class[_]],
+                           parameters: Array[Object]): Object = {
+    val method = obj.getClass.getMethod(name, parameterTypes: _ *)
+    method.setAccessible(true)
+    method.invoke(obj, parameters: _ *)
+  }
+
+  protected def startHttpServer(outputDir: File): Option[(Object, String)] = {
+    try {
+      val httpServerClass = Class.forName("org.apache.spark.HttpServer")
+      val securityManager = {
+        val constructor = Class.forName("org.apache.spark.SecurityManager")
+          .getConstructor(classOf[SparkConf])
+        constructor.setAccessible(true)
+        constructor.newInstance(conf).asInstanceOf[Object]
+      }
+      val httpServerConstructor = httpServerClass
+        .getConstructor(classOf[SparkConf],
+          classOf[File],
+          Class.forName("org.apache.spark.SecurityManager"),
+          classOf[Int],
+          classOf[String])
+      httpServerConstructor.setAccessible(true)
+      // Create Http Server
+      val port = conf.getInt("spark.replClassServer.port", 0)
+      val server = httpServerConstructor
+        .newInstance(conf, outputDir, securityManager, new Integer(port), "HTTP server")
+        .asInstanceOf[Object]
+
+      // Start Http Server
+      val startMethod = server.getClass.getMethod("start")
+      startMethod.setAccessible(true)
+      startMethod.invoke(server)
+
+      // Get uri of this Http Server
+      val uriMethod = server.getClass.getMethod("uri")
+      uriMethod.setAccessible(true)
+      val uri = uriMethod.invoke(server).asInstanceOf[String]
+      Some((server, uri))
+    } catch {
+      // Spark 2.0+ removed HttpServer, so return null instead.
+      case NonFatal(e) =>
+        None
+    }
+  }
+
+  protected def getUserJars(): Seq[String] = {
+    val sparkJars = conf.getOption("spark.jars").map(_.split(","))
+      .map(_.filter(_.nonEmpty)).toSeq.flatten
+    val depJars = depFiles.asScala.filter(_.endsWith(".jar"))
+    val result = sparkJars ++ depJars
+    conf.set("spark.jars", result.mkString(","))
+    result
+  }
+
+  protected def getUserFiles(): Seq[String] = {
+    depFiles.asScala.filter(!_.endsWith(".jar"))
+  }
+}

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/d762b528/spark/src/main/java/org/apache/zeppelin/spark/DepInterpreter.java
----------------------------------------------------------------------
diff --git a/spark/src/main/java/org/apache/zeppelin/spark/DepInterpreter.java b/spark/src/main/java/org/apache/zeppelin/spark/DepInterpreter.java
deleted file mode 100644
index 6b1f0a9..0000000
--- a/spark/src/main/java/org/apache/zeppelin/spark/DepInterpreter.java
+++ /dev/null
@@ -1,363 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.zeppelin.spark;
-
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.PrintStream;
-import java.io.PrintWriter;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.InvocationTargetException;
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.net.URLClassLoader;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.Properties;
-
-import com.google.common.reflect.TypeToken;
-import com.google.gson.Gson;
-
-import org.apache.commons.lang.StringUtils;
-import org.apache.spark.repl.SparkILoop;
-import org.apache.zeppelin.interpreter.Interpreter;
-import org.apache.zeppelin.interpreter.InterpreterContext;
-import org.apache.zeppelin.interpreter.InterpreterGroup;
-import org.apache.zeppelin.interpreter.InterpreterResult;
-import org.apache.zeppelin.interpreter.InterpreterResult.Code;
-import org.apache.zeppelin.interpreter.WrappedInterpreter;
-import org.apache.zeppelin.interpreter.thrift.InterpreterCompletion;
-import org.apache.zeppelin.scheduler.Scheduler;
-import org.apache.zeppelin.spark.dep.SparkDependencyContext;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.sonatype.aether.resolution.ArtifactResolutionException;
-import org.sonatype.aether.resolution.DependencyResolutionException;
-
-import scala.Console;
-import scala.None;
-import scala.Some;
-import scala.collection.convert.WrapAsJava$;
-import scala.collection.JavaConversions;
-import scala.tools.nsc.Settings;
-import scala.tools.nsc.interpreter.Completion.Candidates;
-import scala.tools.nsc.interpreter.Completion.ScalaCompleter;
-import scala.tools.nsc.interpreter.IMain;
-import scala.tools.nsc.interpreter.Results;
-import scala.tools.nsc.settings.MutableSettings.BooleanSetting;
-import scala.tools.nsc.settings.MutableSettings.PathSetting;
-
-
-/**
- * DepInterpreter downloads dependencies and pass them when SparkInterpreter initialized.
- * It extends SparkInterpreter but does not create sparkcontext
- *
- */
-public class DepInterpreter extends Interpreter {
-  /**
-   * intp - org.apache.spark.repl.SparkIMain (scala 2.10)
-   * intp - scala.tools.nsc.interpreter.IMain; (scala 2.11)
-   */
-  private Object intp;
-  private ByteArrayOutputStream out;
-  private SparkDependencyContext depc;
-  /**
-   * completer - org.apache.spark.repl.SparkJLineCompletion (scala 2.10)
-   */
-  private Object completer;
-  private SparkILoop interpreter;
-  static final Logger LOGGER = LoggerFactory.getLogger(DepInterpreter.class);
-
-  public DepInterpreter(Properties property) {
-    super(property);
-  }
-
-  public SparkDependencyContext getDependencyContext() {
-    return depc;
-  }
-
-  public static String getSystemDefault(
-      String envName,
-      String propertyName,
-      String defaultValue) {
-
-    if (envName != null && !envName.isEmpty()) {
-      String envValue = System.getenv().get(envName);
-      if (envValue != null) {
-        return envValue;
-      }
-    }
-
-    if (propertyName != null && !propertyName.isEmpty()) {
-      String propValue = System.getProperty(propertyName);
-      if (propValue != null) {
-        return propValue;
-      }
-    }
-    return defaultValue;
-  }
-
-  @Override
-  public void close() {
-    if (intp != null) {
-      Utils.invokeMethod(intp, "close");
-    }
-  }
-
-  @Override
-  public void open() {
-    out = new ByteArrayOutputStream();
-    createIMain();
-  }
-
-
-  private void createIMain() {
-    Settings settings = new Settings();
-    URL[] urls = getClassloaderUrls();
-
-    // set classpath for scala compiler
-    PathSetting pathSettings = settings.classpath();
-    String classpath = "";
-    List<File> paths = currentClassPath();
-    for (File f : paths) {
-      if (classpath.length() > 0) {
-        classpath += File.pathSeparator;
-      }
-      classpath += f.getAbsolutePath();
-    }
-
-    if (urls != null) {
-      for (URL u : urls) {
-        if (classpath.length() > 0) {
-          classpath += File.pathSeparator;
-        }
-        classpath += u.getFile();
-      }
-    }
-
-    pathSettings.v_$eq(classpath);
-    settings.scala$tools$nsc$settings$ScalaSettings$_setter_$classpath_$eq(pathSettings);
-
-    // set classloader for scala compiler
-    settings.explicitParentLoader_$eq(new Some<>(Thread.currentThread()
-        .getContextClassLoader()));
-
-    BooleanSetting b = (BooleanSetting) settings.usejavacp();
-    b.v_$eq(true);
-    settings.scala$tools$nsc$settings$StandardScalaSettings$_setter_$usejavacp_$eq(b);
-
-    interpreter = new SparkILoop((java.io.BufferedReader) null, new PrintWriter(out));
-    interpreter.settings_$eq(settings);
-
-    interpreter.createInterpreter();
-
-
-    intp = Utils.invokeMethod(interpreter, "intp");
-
-    if (Utils.isScala2_10()) {
-      Utils.invokeMethod(intp, "setContextClassLoader");
-      Utils.invokeMethod(intp, "initializeSynchronous");
-    }
-
-    depc = new SparkDependencyContext(getProperty("zeppelin.dep.localrepo"),
-                                 getProperty("zeppelin.dep.additionalRemoteRepository"));
-    if (Utils.isScala2_10()) {
-      completer = Utils.instantiateClass(
-          "org.apache.spark.repl.SparkJLineCompletion",
-          new Class[]{Utils.findClass("org.apache.spark.repl.SparkIMain")},
-          new Object[]{intp});
-    }
-    interpret("@transient var _binder = new java.util.HashMap[String, Object]()");
-    Map<String, Object> binder;
-    if (Utils.isScala2_10()) {
-      binder = (Map<String, Object>) getValue("_binder");
-    } else {
-      binder = (Map<String, Object>) getLastObject();
-    }
-    binder.put("depc", depc);
-
-    interpret("@transient val z = "
-        + "_binder.get(\"depc\")"
-        + ".asInstanceOf[org.apache.zeppelin.spark.dep.SparkDependencyContext]");
-
-  }
-
-  private Results.Result interpret(String line) {
-    return (Results.Result) Utils.invokeMethod(
-        intp,
-        "interpret",
-        new Class[] {String.class},
-        new Object[] {line});
-  }
-
-  public Object getValue(String name) {
-    Object ret = Utils.invokeMethod(
-      intp, "valueOfTerm", new Class[]{String.class}, new Object[]{name});
-    if (ret instanceof None) {
-      return null;
-    } else if (ret instanceof Some) {
-      return ((Some) ret).get();
-    } else {
-      return ret;
-    }
-  }
-
-  public Object getLastObject() {
-    IMain.Request r = (IMain.Request) Utils.invokeMethod(intp, "lastRequest");
-    Object obj = r.lineRep().call("$result",
-        JavaConversions.asScalaBuffer(new LinkedList<>()));
-    return obj;
-  }
-
-  @Override
-  public InterpreterResult interpret(String st, InterpreterContext context) {
-    PrintStream printStream = new PrintStream(out);
-    Console.setOut(printStream);
-    out.reset();
-
-    SparkInterpreter sparkInterpreter = getSparkInterpreter();
-
-    if (sparkInterpreter != null && sparkInterpreter.isSparkContextInitialized()) {
-      return new InterpreterResult(Code.ERROR,
-          "Must be used before SparkInterpreter (%spark) initialized\n" +
-          "Hint: put this paragraph before any Spark code and " +
-          "restart Zeppelin/Interpreter" );
-    }
-
-    scala.tools.nsc.interpreter.Results.Result ret = interpret(st);
-    Code code = getResultCode(ret);
-
-    try {
-      depc.fetch();
-    } catch (MalformedURLException | DependencyResolutionException
-        | ArtifactResolutionException e) {
-      LOGGER.error("Exception in DepInterpreter while interpret ", e);
-      return new InterpreterResult(Code.ERROR, e.toString());
-    }
-
-    if (code == Code.INCOMPLETE) {
-      return new InterpreterResult(code, "Incomplete expression");
-    } else if (code == Code.ERROR) {
-      return new InterpreterResult(code, out.toString());
-    } else {
-      return new InterpreterResult(code, out.toString());
-    }
-  }
-
-  private Code getResultCode(scala.tools.nsc.interpreter.Results.Result r) {
-    if (r instanceof scala.tools.nsc.interpreter.Results.Success$) {
-      return Code.SUCCESS;
-    } else if (r instanceof scala.tools.nsc.interpreter.Results.Incomplete$) {
-      return Code.INCOMPLETE;
-    } else {
-      return Code.ERROR;
-    }
-  }
-
-  @Override
-  public void cancel(InterpreterContext context) {
-  }
-
-
-  @Override
-  public FormType getFormType() {
-    return FormType.NATIVE;
-  }
-
-  @Override
-  public int getProgress(InterpreterContext context) {
-    return 0;
-  }
-
-  @Override
-  public List<InterpreterCompletion> completion(String buf, int cursor,
-      InterpreterContext interpreterContext) {
-    if (Utils.isScala2_10()) {
-      ScalaCompleter c = (ScalaCompleter) Utils.invokeMethod(completer, "completer");
-      Candidates ret = c.complete(buf, cursor);
-
-      List<String> candidates = WrapAsJava$.MODULE$.seqAsJavaList(ret.candidates());
-      List<InterpreterCompletion> completions = new LinkedList<>();
-
-      for (String candidate : candidates) {
-        completions.add(new InterpreterCompletion(candidate, candidate, StringUtils.EMPTY));
-      }
-
-      return completions;
-    } else {
-      return new LinkedList<>();
-    }
-  }
-
-  private List<File> currentClassPath() {
-    List<File> paths = classPath(Thread.currentThread().getContextClassLoader());
-    String[] cps = System.getProperty("java.class.path").split(File.pathSeparator);
-    if (cps != null) {
-      for (String cp : cps) {
-        paths.add(new File(cp));
-      }
-    }
-    return paths;
-  }
-
-  private List<File> classPath(ClassLoader cl) {
-    List<File> paths = new LinkedList<>();
-    if (cl == null) {
-      return paths;
-    }
-
-    if (cl instanceof URLClassLoader) {
-      URLClassLoader ucl = (URLClassLoader) cl;
-      URL[] urls = ucl.getURLs();
-      if (urls != null) {
-        for (URL url : urls) {
-          paths.add(new File(url.getFile()));
-        }
-      }
-    }
-    return paths;
-  }
-
-  private SparkInterpreter getSparkInterpreter() {
-    InterpreterGroup intpGroup = getInterpreterGroup();
-    if (intpGroup == null) {
-      return null;
-    }
-
-    Interpreter p = getInterpreterInTheSameSessionByClassName(SparkInterpreter.class.getName());
-    if (p == null) {
-      return null;
-    }
-
-    while (p instanceof WrappedInterpreter) {
-      p = ((WrappedInterpreter) p).getInnerInterpreter();
-    }
-    return (SparkInterpreter) p;
-  }
-
-  @Override
-  public Scheduler getScheduler() {
-    SparkInterpreter sparkInterpreter = getSparkInterpreter();
-    if (sparkInterpreter != null) {
-      return getSparkInterpreter().getScheduler();
-    } else {
-      return null;
-    }
-  }
-}

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/d762b528/spark/src/main/java/org/apache/zeppelin/spark/IPySparkInterpreter.java
----------------------------------------------------------------------
diff --git a/spark/src/main/java/org/apache/zeppelin/spark/IPySparkInterpreter.java b/spark/src/main/java/org/apache/zeppelin/spark/IPySparkInterpreter.java
deleted file mode 100644
index a050569..0000000
--- a/spark/src/main/java/org/apache/zeppelin/spark/IPySparkInterpreter.java
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.zeppelin.spark;
-
-import org.apache.spark.SparkConf;
-import org.apache.spark.api.java.JavaSparkContext;
-import org.apache.zeppelin.interpreter.Interpreter;
-import org.apache.zeppelin.interpreter.InterpreterContext;
-import org.apache.zeppelin.interpreter.InterpreterException;
-import org.apache.zeppelin.interpreter.LazyOpenInterpreter;
-import org.apache.zeppelin.interpreter.WrappedInterpreter;
-import org.apache.zeppelin.python.IPythonInterpreter;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.io.IOException;
-import java.util.Map;
-import java.util.Properties;
-
-/**
- * PySparkInterpreter which use IPython underlying.
- */
-public class IPySparkInterpreter extends IPythonInterpreter {
-
-  private static final Logger LOGGER = LoggerFactory.getLogger(IPySparkInterpreter.class);
-
-  private SparkInterpreter sparkInterpreter;
-
-  public IPySparkInterpreter(Properties property) {
-    super(property);
-  }
-
-  @Override
-  public void open() throws InterpreterException {
-    setProperty("zeppelin.python",
-        PySparkInterpreter.getPythonExec(getProperties()));
-    sparkInterpreter = getSparkInterpreter();
-    SparkConf conf = sparkInterpreter.getSparkContext().getConf();
-    // only set PYTHONPATH in local or yarn-client mode.
-    // yarn-cluster will setup PYTHONPATH automatically.
-    if (!conf.get("spark.submit.deployMode").equals("cluster")) {
-      setAdditionalPythonPath(PythonUtils.sparkPythonPath());
-      setAddBulitinPy4j(false);
-    }
-    setAdditionalPythonInitFile("python/zeppelin_ipyspark.py");
-    super.open();
-  }
-
-  @Override
-  protected Map<String, String> setupIPythonEnv() throws IOException {
-    Map<String, String> env = super.setupIPythonEnv();
-    // set PYSPARK_PYTHON
-    SparkConf conf = sparkInterpreter.getSparkContext().getConf();
-    if (conf.contains("spark.pyspark.python")) {
-      env.put("PYSPARK_PYTHON", conf.get("spark.pyspark.python"));
-    }
-    return env;
-  }
-
-  private SparkInterpreter getSparkInterpreter() throws InterpreterException {
-    LazyOpenInterpreter lazy = null;
-    SparkInterpreter spark = null;
-    Interpreter p = getInterpreterInTheSameSessionByClassName(SparkInterpreter.class.getName());
-
-    while (p instanceof WrappedInterpreter) {
-      if (p instanceof LazyOpenInterpreter) {
-        lazy = (LazyOpenInterpreter) p;
-      }
-      p = ((WrappedInterpreter) p).getInnerInterpreter();
-    }
-    spark = (SparkInterpreter) p;
-
-    if (lazy != null) {
-      lazy.open();
-    }
-    return spark;
-  }
-
-  @Override
-  public void cancel(InterpreterContext context) {
-    super.cancel(context);
-    sparkInterpreter.cancel(context);
-  }
-
-  @Override
-  public void close() {
-    super.close();
-    if (sparkInterpreter != null) {
-      sparkInterpreter.close();
-    }
-  }
-
-  @Override
-  public int getProgress(InterpreterContext context) {
-    return sparkInterpreter.getProgress(context);
-  }
-
-  public boolean isSpark2() {
-    return sparkInterpreter.getSparkVersion().newerThanEquals(SparkVersion.SPARK_2_0_0);
-  }
-
-  public JavaSparkContext getJavaSparkContext() {
-    return sparkInterpreter.getJavaSparkContext();
-  }
-
-  public Object getSQLContext() {
-    return sparkInterpreter.getSQLContext();
-  }
-
-  public Object getSparkSession() {
-    return sparkInterpreter.getSparkSession();
-  }
-}

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/d762b528/spark/src/main/java/org/apache/zeppelin/spark/PySparkInterpreter.java
----------------------------------------------------------------------
diff --git a/spark/src/main/java/org/apache/zeppelin/spark/PySparkInterpreter.java b/spark/src/main/java/org/apache/zeppelin/spark/PySparkInterpreter.java
deleted file mode 100644
index 47ffe14..0000000
--- a/spark/src/main/java/org/apache/zeppelin/spark/PySparkInterpreter.java
+++ /dev/null
@@ -1,745 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.zeppelin.spark;
-
-import java.io.BufferedWriter;
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.OutputStreamWriter;
-import java.io.PipedInputStream;
-import java.io.PipedOutputStream;
-import java.net.MalformedURLException;
-import java.net.ServerSocket;
-import java.net.URL;
-import java.net.URLClassLoader;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.Properties;
-
-import org.apache.commons.compress.utils.IOUtils;
-import org.apache.commons.exec.CommandLine;
-import org.apache.commons.exec.DefaultExecutor;
-import org.apache.commons.exec.ExecuteException;
-import org.apache.commons.exec.ExecuteResultHandler;
-import org.apache.commons.exec.ExecuteWatchdog;
-import org.apache.commons.exec.PumpStreamHandler;
-import org.apache.commons.exec.environment.EnvironmentUtils;
-import org.apache.commons.lang.StringUtils;
-import org.apache.spark.SparkConf;
-import org.apache.spark.api.java.JavaSparkContext;
-import org.apache.spark.sql.SQLContext;
-import org.apache.zeppelin.interpreter.*;
-import org.apache.zeppelin.interpreter.InterpreterHookRegistry.HookType;
-import org.apache.zeppelin.interpreter.InterpreterResult.Code;
-import org.apache.zeppelin.interpreter.thrift.InterpreterCompletion;
-import org.apache.zeppelin.interpreter.util.InterpreterOutputStream;
-import org.apache.zeppelin.spark.dep.SparkDependencyContext;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.gson.Gson;
-
-import py4j.GatewayServer;
-
-/**
- *
- */
-public class PySparkInterpreter extends Interpreter implements ExecuteResultHandler {
-  private static final Logger LOGGER = LoggerFactory.getLogger(PySparkInterpreter.class);
-  private GatewayServer gatewayServer;
-  private DefaultExecutor executor;
-  private int port;
-  private InterpreterOutputStream outputStream;
-  private BufferedWriter ins;
-  private PipedInputStream in;
-  private ByteArrayOutputStream input;
-  private String scriptPath;
-  boolean pythonscriptRunning = false;
-  private static final int MAX_TIMEOUT_SEC = 10;
-  private long pythonPid;
-
-  private IPySparkInterpreter iPySparkInterpreter;
-
-  public PySparkInterpreter(Properties property) {
-    super(property);
-
-    pythonPid = -1;
-    try {
-      File scriptFile = File.createTempFile("zeppelin_pyspark-", ".py");
-      scriptPath = scriptFile.getAbsolutePath();
-    } catch (IOException e) {
-      throw new RuntimeException(e);
-    }
-  }
-
-  private void createPythonScript() throws InterpreterException {
-    ClassLoader classLoader = getClass().getClassLoader();
-    File out = new File(scriptPath);
-
-    if (out.exists() && out.isDirectory()) {
-      throw new InterpreterException("Can't create python script " + out.getAbsolutePath());
-    }
-
-    try {
-      FileOutputStream outStream = new FileOutputStream(out);
-      IOUtils.copy(
-          classLoader.getResourceAsStream("python/zeppelin_pyspark.py"),
-          outStream);
-      outStream.close();
-    } catch (IOException e) {
-      throw new InterpreterException(e);
-    }
-
-    LOGGER.info("File {} created", scriptPath);
-  }
-
-  @Override
-  public void open() throws InterpreterException {
-    // try IPySparkInterpreter first
-    iPySparkInterpreter = getIPySparkInterpreter();
-    if (getProperty("zeppelin.pyspark.useIPython", "true").equals("true") &&
-        StringUtils.isEmpty(
-            iPySparkInterpreter.checkIPythonPrerequisite(getPythonExec(getProperties())))) {
-      try {
-        iPySparkInterpreter.open();
-        if (InterpreterContext.get() != null) {
-          // don't print it when it is in testing, just for easy output check in test.
-          InterpreterContext.get().out.write(("IPython is available, " +
-              "use IPython for PySparkInterpreter\n")
-              .getBytes());
-        }
-        LOGGER.info("Use IPySparkInterpreter to replace PySparkInterpreter");
-        return;
-      } catch (Exception e) {
-        LOGGER.warn("Fail to open IPySparkInterpreter", e);
-      }
-    }
-    iPySparkInterpreter = null;
-    if (getProperty("zeppelin.pyspark.useIPython", "true").equals("true")) {
-      // don't print it when it is in testing, just for easy output check in test.
-      try {
-        InterpreterContext.get().out.write(("IPython is not available, " +
-            "use the native PySparkInterpreter\n")
-            .getBytes());
-      } catch (IOException e) {
-        LOGGER.warn("Fail to write InterpreterOutput", e);
-      }
-    }
-
-    // Add matplotlib display hook
-    InterpreterGroup intpGroup = getInterpreterGroup();
-    if (intpGroup != null && intpGroup.getInterpreterHookRegistry() != null) {
-      registerHook(HookType.POST_EXEC_DEV, "__zeppelin__._displayhook()");
-    }
-    DepInterpreter depInterpreter = getDepInterpreter();
-
-    // load libraries from Dependency Interpreter
-    URL [] urls = new URL[0];
-    List<URL> urlList = new LinkedList<>();
-
-    if (depInterpreter != null) {
-      SparkDependencyContext depc = depInterpreter.getDependencyContext();
-      if (depc != null) {
-        List<File> files = depc.getFiles();
-        if (files != null) {
-          for (File f : files) {
-            try {
-              urlList.add(f.toURI().toURL());
-            } catch (MalformedURLException e) {
-              LOGGER.error("Error", e);
-            }
-          }
-        }
-      }
-    }
-
-    String localRepo = getProperty("zeppelin.interpreter.localRepo");
-    if (localRepo != null) {
-      File localRepoDir = new File(localRepo);
-      if (localRepoDir.exists()) {
-        File[] files = localRepoDir.listFiles();
-        if (files != null) {
-          for (File f : files) {
-            try {
-              urlList.add(f.toURI().toURL());
-            } catch (MalformedURLException e) {
-              LOGGER.error("Error", e);
-            }
-          }
-        }
-      }
-    }
-
-    urls = urlList.toArray(urls);
-    ClassLoader oldCl = Thread.currentThread().getContextClassLoader();
-    try {
-      URLClassLoader newCl = new URLClassLoader(urls, oldCl);
-      Thread.currentThread().setContextClassLoader(newCl);
-      createGatewayServerAndStartScript();
-    } catch (Exception e) {
-      LOGGER.error("Error", e);
-      throw new InterpreterException(e);
-    } finally {
-      Thread.currentThread().setContextClassLoader(oldCl);
-    }
-  }
-
-  private Map setupPySparkEnv() throws IOException, InterpreterException {
-    Map env = EnvironmentUtils.getProcEnvironment();
-
-    // only set PYTHONPATH in local or yarn-client mode.
-    // yarn-cluster will setup PYTHONPATH automatically.
-    SparkConf conf = getSparkConf();
-    if (!conf.get("spark.submit.deployMode", "client").equals("cluster")) {
-      if (!env.containsKey("PYTHONPATH")) {
-        env.put("PYTHONPATH", PythonUtils.sparkPythonPath());
-      } else {
-        env.put("PYTHONPATH", PythonUtils.sparkPythonPath());
-      }
-    }
-
-    // get additional class paths when using SPARK_SUBMIT and not using YARN-CLIENT
-    // also, add all packages to PYTHONPATH since there might be transitive dependencies
-    if (SparkInterpreter.useSparkSubmit() &&
-        !getSparkInterpreter().isYarnMode()) {
-
-      String sparkSubmitJars = getSparkConf().get("spark.jars").replace(",", ":");
-
-      if (!"".equals(sparkSubmitJars)) {
-        env.put("PYTHONPATH", env.get("PYTHONPATH") + sparkSubmitJars);
-      }
-    }
-
-    LOGGER.info("PYTHONPATH: " + env.get("PYTHONPATH"));
-
-    // set PYSPARK_PYTHON
-    if (getSparkConf().contains("spark.pyspark.python")) {
-      env.put("PYSPARK_PYTHON", getSparkConf().get("spark.pyspark.python"));
-    }
-    return env;
-  }
-
-  // Run python shell
-  // Choose python in the order of
-  // PYSPARK_DRIVER_PYTHON > PYSPARK_PYTHON > zeppelin.pyspark.python
-  public static String getPythonExec(Properties properties) {
-    String pythonExec = properties.getProperty("zeppelin.pyspark.python", "python");
-    if (System.getenv("PYSPARK_PYTHON") != null) {
-      pythonExec = System.getenv("PYSPARK_PYTHON");
-    }
-    if (System.getenv("PYSPARK_DRIVER_PYTHON") != null) {
-      pythonExec = System.getenv("PYSPARK_DRIVER_PYTHON");
-    }
-    return pythonExec;
-  }
-
-  private void createGatewayServerAndStartScript() throws InterpreterException {
-    // create python script
-    createPythonScript();
-
-    port = findRandomOpenPortOnAllLocalInterfaces();
-
-    gatewayServer = new GatewayServer(this, port);
-    gatewayServer.start();
-
-    String pythonExec = getPythonExec(getProperties());
-    LOGGER.info("pythonExec: " + pythonExec);
-    CommandLine cmd = CommandLine.parse(pythonExec);
-    cmd.addArgument(scriptPath, false);
-    cmd.addArgument(Integer.toString(port), false);
-    cmd.addArgument(Integer.toString(getSparkInterpreter().getSparkVersion().toNumber()), false);
-    executor = new DefaultExecutor();
-    outputStream = new InterpreterOutputStream(LOGGER);
-    PipedOutputStream ps = new PipedOutputStream();
-    in = null;
-    try {
-      in = new PipedInputStream(ps);
-    } catch (IOException e1) {
-      throw new InterpreterException(e1);
-    }
-    ins = new BufferedWriter(new OutputStreamWriter(ps));
-
-    input = new ByteArrayOutputStream();
-
-    PumpStreamHandler streamHandler = new PumpStreamHandler(outputStream, outputStream, in);
-    executor.setStreamHandler(streamHandler);
-    executor.setWatchdog(new ExecuteWatchdog(ExecuteWatchdog.INFINITE_TIMEOUT));
-
-    try {
-      Map env = setupPySparkEnv();
-      executor.execute(cmd, env, this);
-      pythonscriptRunning = true;
-    } catch (IOException e) {
-      throw new InterpreterException(e);
-    }
-
-
-    try {
-      input.write("import sys, getopt\n".getBytes());
-      ins.flush();
-    } catch (IOException e) {
-      throw new InterpreterException(e);
-    }
-  }
-
-  private int findRandomOpenPortOnAllLocalInterfaces() throws InterpreterException {
-    int port;
-    try (ServerSocket socket = new ServerSocket(0);) {
-      port = socket.getLocalPort();
-      socket.close();
-    } catch (IOException e) {
-      throw new InterpreterException(e);
-    }
-    return port;
-  }
-
-  @Override
-  public void close() {
-    if (iPySparkInterpreter != null) {
-      iPySparkInterpreter.close();
-      return;
-    }
-    executor.getWatchdog().destroyProcess();
-    new File(scriptPath).delete();
-    gatewayServer.shutdown();
-  }
-
-  PythonInterpretRequest pythonInterpretRequest = null;
-
-  /**
-   *
-   */
-  public class PythonInterpretRequest {
-    public String statements;
-    public String jobGroup;
-    public String jobDescription;
-
-    public PythonInterpretRequest(String statements, String jobGroup,
-        String jobDescription) {
-      this.statements = statements;
-      this.jobGroup = jobGroup;
-      this.jobDescription = jobDescription;
-    }
-
-    public String statements() {
-      return statements;
-    }
-
-    public String jobGroup() {
-      return jobGroup;
-    }
-
-    public String jobDescription() {
-      return jobDescription;
-    }
-  }
-
-  Integer statementSetNotifier = new Integer(0);
-
-  public PythonInterpretRequest getStatements() {
-    synchronized (statementSetNotifier) {
-      while (pythonInterpretRequest == null) {
-        try {
-          statementSetNotifier.wait(1000);
-        } catch (InterruptedException e) {
-        }
-      }
-      PythonInterpretRequest req = pythonInterpretRequest;
-      pythonInterpretRequest = null;
-      return req;
-    }
-  }
-
-  String statementOutput = null;
-  boolean statementError = false;
-  Integer statementFinishedNotifier = new Integer(0);
-
-  public void setStatementsFinished(String out, boolean error) {
-    synchronized (statementFinishedNotifier) {
-      LOGGER.debug("Setting python statement output: " + out + ", error: " + error);
-      statementOutput = out;
-      statementError = error;
-      statementFinishedNotifier.notify();
-    }
-  }
-
-  boolean pythonScriptInitialized = false;
-  Integer pythonScriptInitializeNotifier = new Integer(0);
-
-  public void onPythonScriptInitialized(long pid) {
-    pythonPid = pid;
-    synchronized (pythonScriptInitializeNotifier) {
-      LOGGER.debug("onPythonScriptInitialized is called");
-      pythonScriptInitialized = true;
-      pythonScriptInitializeNotifier.notifyAll();
-    }
-  }
-
-  public void appendOutput(String message) throws IOException {
-    LOGGER.debug("Output from python process: " + message);
-    outputStream.getInterpreterOutput().write(message);
-  }
-
-  @Override
-  public InterpreterResult interpret(String st, InterpreterContext context)
-      throws InterpreterException {
-    SparkInterpreter sparkInterpreter = getSparkInterpreter();
-    sparkInterpreter.populateSparkWebUrl(context);
-    if (sparkInterpreter.isUnsupportedSparkVersion()) {
-      return new InterpreterResult(Code.ERROR, "Spark "
-          + sparkInterpreter.getSparkVersion().toString() + " is not supported");
-    }
-
-    if (iPySparkInterpreter != null) {
-      return iPySparkInterpreter.interpret(st, context);
-    }
-
-    if (!pythonscriptRunning) {
-      return new InterpreterResult(Code.ERROR, "python process not running"
-          + outputStream.toString());
-    }
-
-    outputStream.setInterpreterOutput(context.out);
-
-    synchronized (pythonScriptInitializeNotifier) {
-      long startTime = System.currentTimeMillis();
-      while (pythonScriptInitialized == false
-          && pythonscriptRunning
-          && System.currentTimeMillis() - startTime < MAX_TIMEOUT_SEC * 1000) {
-        try {
-          pythonScriptInitializeNotifier.wait(1000);
-        } catch (InterruptedException e) {
-          e.printStackTrace();
-        }
-      }
-    }
-
-    List<InterpreterResultMessage> errorMessage;
-    try {
-      context.out.flush();
-      errorMessage = context.out.toInterpreterResultMessage();
-    } catch (IOException e) {
-      throw new InterpreterException(e);
-    }
-
-
-    if (pythonscriptRunning == false) {
-      // python script failed to initialize and terminated
-      errorMessage.add(new InterpreterResultMessage(
-          InterpreterResult.Type.TEXT, "failed to start pyspark"));
-      return new InterpreterResult(Code.ERROR, errorMessage);
-    }
-    if (pythonScriptInitialized == false) {
-      // timeout. didn't get initialized message
-      errorMessage.add(new InterpreterResultMessage(
-          InterpreterResult.Type.TEXT, "pyspark is not responding"));
-      return new InterpreterResult(Code.ERROR, errorMessage);
-    }
-
-    if (!sparkInterpreter.getSparkVersion().isPysparkSupported()) {
-      errorMessage.add(new InterpreterResultMessage(
-          InterpreterResult.Type.TEXT,
-          "pyspark " + sparkInterpreter.getSparkContext().version() + " is not supported"));
-      return new InterpreterResult(Code.ERROR, errorMessage);
-    }
-    String jobGroup = Utils.buildJobGroupId(context);
-    String jobDesc = "Started by: " + Utils.getUserName(context.getAuthenticationInfo());
-    SparkZeppelinContext __zeppelin__ = sparkInterpreter.getZeppelinContext();
-    __zeppelin__.setInterpreterContext(context);
-    __zeppelin__.setGui(context.getGui());
-    __zeppelin__.setNoteGui(context.getNoteGui());
-    pythonInterpretRequest = new PythonInterpretRequest(st, jobGroup, jobDesc);
-    statementOutput = null;
-
-    synchronized (statementSetNotifier) {
-      statementSetNotifier.notify();
-    }
-
-    synchronized (statementFinishedNotifier) {
-      while (statementOutput == null) {
-        try {
-          statementFinishedNotifier.wait(1000);
-        } catch (InterruptedException e) {
-        }
-      }
-    }
-
-    if (statementError) {
-      return new InterpreterResult(Code.ERROR, statementOutput);
-    } else {
-
-      try {
-        context.out.flush();
-      } catch (IOException e) {
-        throw new InterpreterException(e);
-      }
-
-      return new InterpreterResult(Code.SUCCESS);
-    }
-  }
-
-  public void interrupt() throws IOException {
-    if (pythonPid > -1) {
-      LOGGER.info("Sending SIGINT signal to PID : " + pythonPid);
-      Runtime.getRuntime().exec("kill -SIGINT " + pythonPid);
-    } else {
-      LOGGER.warn("Non UNIX/Linux system, close the interpreter");
-      close();
-    }
-  }
-
-  @Override
-  public void cancel(InterpreterContext context) throws InterpreterException {
-    if (iPySparkInterpreter != null) {
-      iPySparkInterpreter.cancel(context);
-      return;
-    }
-    SparkInterpreter sparkInterpreter = getSparkInterpreter();
-    sparkInterpreter.cancel(context);
-    try {
-      interrupt();
-    } catch (IOException e) {
-      LOGGER.error("Error", e);
-    }
-  }
-
-  @Override
-  public FormType getFormType() {
-    return FormType.NATIVE;
-  }
-
-  @Override
-  public int getProgress(InterpreterContext context) throws InterpreterException {
-    if (iPySparkInterpreter != null) {
-      return iPySparkInterpreter.getProgress(context);
-    }
-    SparkInterpreter sparkInterpreter = getSparkInterpreter();
-    return sparkInterpreter.getProgress(context);
-  }
-
-
-  @Override
-  public List<InterpreterCompletion> completion(String buf, int cursor,
-      InterpreterContext interpreterContext) throws InterpreterException {
-    if (iPySparkInterpreter != null) {
-      return iPySparkInterpreter.completion(buf, cursor, interpreterContext);
-    }
-    if (buf.length() < cursor) {
-      cursor = buf.length();
-    }
-    String completionString = getCompletionTargetString(buf, cursor);
-    String completionCommand = "completion.getCompletion('" + completionString + "')";
-
-    //start code for completion
-    SparkInterpreter sparkInterpreter = getSparkInterpreter();
-    if (sparkInterpreter.isUnsupportedSparkVersion() || pythonscriptRunning == false) {
-      return new LinkedList<>();
-    }
-
-    pythonInterpretRequest = new PythonInterpretRequest(completionCommand, "", "");
-    statementOutput = null;
-
-    synchronized (statementSetNotifier) {
-      statementSetNotifier.notify();
-    }
-
-    String[] completionList = null;
-    synchronized (statementFinishedNotifier) {
-      long startTime = System.currentTimeMillis();
-      while (statementOutput == null
-        && pythonscriptRunning) {
-        try {
-          if (System.currentTimeMillis() - startTime > MAX_TIMEOUT_SEC * 1000) {
-            LOGGER.error("pyspark completion didn't have response for {}sec.", MAX_TIMEOUT_SEC);
-            break;
-          }
-          statementFinishedNotifier.wait(1000);
-        } catch (InterruptedException e) {
-          // not working
-          LOGGER.info("wait drop");
-          return new LinkedList<>();
-        }
-      }
-      if (statementError) {
-        return new LinkedList<>();
-      }
-      Gson gson = new Gson();
-      completionList = gson.fromJson(statementOutput, String[].class);
-    }
-    //end code for completion
-
-    if (completionList == null) {
-      return new LinkedList<>();
-    }
-
-    List<InterpreterCompletion> results = new LinkedList<>();
-    for (String name: completionList) {
-      results.add(new InterpreterCompletion(name, name, StringUtils.EMPTY));
-    }
-    return results;
-  }
-
-  private String getCompletionTargetString(String text, int cursor) {
-    String[] completionSeqCharaters = {" ", "\n", "\t"};
-    int completionEndPosition = cursor;
-    int completionStartPosition = cursor;
-    int indexOfReverseSeqPostion = cursor;
-
-    String resultCompletionText = "";
-    String completionScriptText = "";
-    try {
-      completionScriptText = text.substring(0, cursor);
-    }
-    catch (Exception e) {
-      LOGGER.error(e.toString());
-      return null;
-    }
-    completionEndPosition = completionScriptText.length();
-
-    String tempReverseCompletionText = new StringBuilder(completionScriptText).reverse().toString();
-
-    for (String seqCharacter : completionSeqCharaters) {
-      indexOfReverseSeqPostion = tempReverseCompletionText.indexOf(seqCharacter);
-
-      if (indexOfReverseSeqPostion < completionStartPosition && indexOfReverseSeqPostion > 0) {
-        completionStartPosition = indexOfReverseSeqPostion;
-      }
-
-    }
-
-    if (completionStartPosition == completionEndPosition) {
-      completionStartPosition = 0;
-    }
-    else
-    {
-      completionStartPosition = completionEndPosition - completionStartPosition;
-    }
-    resultCompletionText = completionScriptText.substring(
-            completionStartPosition , completionEndPosition);
-
-    return resultCompletionText;
-  }
-
-
-  private SparkInterpreter getSparkInterpreter() throws InterpreterException {
-    LazyOpenInterpreter lazy = null;
-    SparkInterpreter spark = null;
-    Interpreter p = getInterpreterInTheSameSessionByClassName(SparkInterpreter.class.getName());
-
-    while (p instanceof WrappedInterpreter) {
-      if (p instanceof LazyOpenInterpreter) {
-        lazy = (LazyOpenInterpreter) p;
-      }
-      p = ((WrappedInterpreter) p).getInnerInterpreter();
-    }
-    spark = (SparkInterpreter) p;
-
-    if (lazy != null) {
-      lazy.open();
-    }
-    return spark;
-  }
-
-  private IPySparkInterpreter getIPySparkInterpreter() {
-    LazyOpenInterpreter lazy = null;
-    IPySparkInterpreter iPySpark = null;
-    Interpreter p = getInterpreterInTheSameSessionByClassName(IPySparkInterpreter.class.getName());
-
-    while (p instanceof WrappedInterpreter) {
-      if (p instanceof LazyOpenInterpreter) {
-        lazy = (LazyOpenInterpreter) p;
-      }
-      p = ((WrappedInterpreter) p).getInnerInterpreter();
-    }
-    iPySpark = (IPySparkInterpreter) p;
-    return iPySpark;
-  }
-
-  public SparkZeppelinContext getZeppelinContext() throws InterpreterException {
-    SparkInterpreter sparkIntp = getSparkInterpreter();
-    if (sparkIntp != null) {
-      return getSparkInterpreter().getZeppelinContext();
-    } else {
-      return null;
-    }
-  }
-
-  public JavaSparkContext getJavaSparkContext() throws InterpreterException {
-    SparkInterpreter intp = getSparkInterpreter();
-    if (intp == null) {
-      return null;
-    } else {
-      return new JavaSparkContext(intp.getSparkContext());
-    }
-  }
-
-  public Object getSparkSession() throws InterpreterException {
-    SparkInterpreter intp = getSparkInterpreter();
-    if (intp == null) {
-      return null;
-    } else {
-      return intp.getSparkSession();
-    }
-  }
-
-  public SparkConf getSparkConf() throws InterpreterException {
-    JavaSparkContext sc = getJavaSparkContext();
-    if (sc == null) {
-      return null;
-    } else {
-      return getJavaSparkContext().getConf();
-    }
-  }
-
-  public SQLContext getSQLContext() throws InterpreterException {
-    SparkInterpreter intp = getSparkInterpreter();
-    if (intp == null) {
-      return null;
-    } else {
-      return intp.getSQLContext();
-    }
-  }
-
-  private DepInterpreter getDepInterpreter() {
-    Interpreter p = getInterpreterInTheSameSessionByClassName(DepInterpreter.class.getName());
-    if (p == null) {
-      return null;
-    }
-
-    while (p instanceof WrappedInterpreter) {
-      p = ((WrappedInterpreter) p).getInnerInterpreter();
-    }
-    return (DepInterpreter) p;
-  }
-
-
-  @Override
-  public void onProcessComplete(int exitValue) {
-    pythonscriptRunning = false;
-    LOGGER.info("python process terminated. exit code " + exitValue);
-  }
-
-  @Override
-  public void onProcessFailed(ExecuteException e) {
-    pythonscriptRunning = false;
-    LOGGER.error("python process failed", e);
-  }
-}

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/d762b528/spark/src/main/java/org/apache/zeppelin/spark/PythonUtils.java
----------------------------------------------------------------------
diff --git a/spark/src/main/java/org/apache/zeppelin/spark/PythonUtils.java b/spark/src/main/java/org/apache/zeppelin/spark/PythonUtils.java
deleted file mode 100644
index 8182690..0000000
--- a/spark/src/main/java/org/apache/zeppelin/spark/PythonUtils.java
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-package org.apache.zeppelin.spark;
-
-import org.apache.commons.lang3.StringUtils;
-
-import java.io.File;
-import java.io.FilenameFilter;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Util class for PySpark
- */
-public class PythonUtils {
-
-  /**
-   * Get the PYTHONPATH for PySpark, either from SPARK_HOME, if it is set, or from ZEPPELIN_HOME
-   * when it is embedded mode.
-   *
-   * This method will called in zeppelin server process and spark driver process when it is
-   * local or yarn-client mode.
-   */
-  public static String sparkPythonPath() {
-    List<String> pythonPath = new ArrayList<String>();
-    String sparkHome = System.getenv("SPARK_HOME");
-    String zeppelinHome = System.getenv("ZEPPELIN_HOME");
-    if (zeppelinHome == null) {
-      zeppelinHome = new File("..").getAbsolutePath();
-    }
-    if (sparkHome != null) {
-      // non-embedded mode when SPARK_HOME is specified.
-      File pyspark = new File(sparkHome, "python/lib/pyspark.zip");
-      if (!pyspark.exists()) {
-        throw new RuntimeException("No pyspark.zip found under " + sparkHome + "/python/lib");
-      }
-      pythonPath.add(pyspark.getAbsolutePath());
-      File[] py4j = new File(sparkHome + "/python/lib").listFiles(new FilenameFilter() {
-        @Override
-        public boolean accept(File dir, String name) {
-          return name.startsWith("py4j");
-        }
-      });
-      if (py4j.length == 0) {
-        throw new RuntimeException("No py4j files found under " + sparkHome + "/python/lib");
-      } else if (py4j.length > 1) {
-        throw new RuntimeException("Multiple py4j files found under " + sparkHome + "/python/lib");
-      } else {
-        pythonPath.add(py4j[0].getAbsolutePath());
-      }
-    } else {
-      // embedded mode
-      File pyspark = new File(zeppelinHome, "interpreter/spark/pyspark/pyspark.zip");
-      if (!pyspark.exists()) {
-        throw new RuntimeException("No pyspark.zip found: " + pyspark.getAbsolutePath());
-      }
-      pythonPath.add(pyspark.getAbsolutePath());
-      File[] py4j = new File(zeppelinHome, "interpreter/spark/pyspark").listFiles(
-          new FilenameFilter() {
-            @Override
-            public boolean accept(File dir, String name) {
-              return name.startsWith("py4j");
-            }
-          });
-      if (py4j.length == 0) {
-        throw new RuntimeException("No py4j files found under " + zeppelinHome +
-            "/interpreter/spark/pyspark");
-      } else if (py4j.length > 1) {
-        throw new RuntimeException("Multiple py4j files found under " + sparkHome +
-            "/interpreter/spark/pyspark");
-      } else {
-        pythonPath.add(py4j[0].getAbsolutePath());
-      }
-    }
-
-    // add ${ZEPPELIN_HOME}/interpreter/lib/python for all the cases
-    pythonPath.add(zeppelinHome + "/interpreter/lib/python");
-    return StringUtils.join(pythonPath, ":");
-  }
-}


[09/10] zeppelin git commit: ZEPPELIN-3111. Refactor SparkInterpreter

Posted by zj...@apache.org.
http://git-wip-us.apache.org/repos/asf/zeppelin/blob/d762b528/spark/interpreter/src/main/java/org/apache/zeppelin/spark/AbstractSparkInterpreter.java
----------------------------------------------------------------------
diff --git a/spark/interpreter/src/main/java/org/apache/zeppelin/spark/AbstractSparkInterpreter.java b/spark/interpreter/src/main/java/org/apache/zeppelin/spark/AbstractSparkInterpreter.java
new file mode 100644
index 0000000..9968dc6
--- /dev/null
+++ b/spark/interpreter/src/main/java/org/apache/zeppelin/spark/AbstractSparkInterpreter.java
@@ -0,0 +1,57 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.zeppelin.spark;
+
+import org.apache.spark.SparkContext;
+import org.apache.spark.api.java.JavaSparkContext;
+import org.apache.spark.sql.SQLContext;
+import org.apache.zeppelin.interpreter.Interpreter;
+import org.apache.zeppelin.interpreter.InterpreterContext;
+
+import java.util.Properties;
+
+/**
+ * Abstract class for SparkInterpreter. For the purpose of co-exist of NewSparkInterpreter
+ * and OldSparkInterpreter
+ */
+public abstract class AbstractSparkInterpreter extends Interpreter {
+
+  public AbstractSparkInterpreter(Properties properties) {
+    super(properties);
+  }
+
+  public abstract SparkContext getSparkContext();
+
+  public abstract SQLContext getSQLContext();
+
+  public abstract Object getSparkSession();
+
+  public abstract boolean isSparkContextInitialized();
+
+  public abstract SparkVersion getSparkVersion();
+
+  public abstract JavaSparkContext getJavaSparkContext();
+
+  public abstract void populateSparkWebUrl(InterpreterContext ctx);
+
+  public abstract SparkZeppelinContext getZeppelinContext();
+
+  public abstract String getSparkUIUrl();
+
+  public abstract boolean isUnsupportedSparkVersion();
+}

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/d762b528/spark/interpreter/src/main/java/org/apache/zeppelin/spark/DepInterpreter.java
----------------------------------------------------------------------
diff --git a/spark/interpreter/src/main/java/org/apache/zeppelin/spark/DepInterpreter.java b/spark/interpreter/src/main/java/org/apache/zeppelin/spark/DepInterpreter.java
new file mode 100644
index 0000000..df0a484
--- /dev/null
+++ b/spark/interpreter/src/main/java/org/apache/zeppelin/spark/DepInterpreter.java
@@ -0,0 +1,363 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.zeppelin.spark;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.PrintStream;
+import java.io.PrintWriter;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+import com.google.common.reflect.TypeToken;
+import com.google.gson.Gson;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.spark.repl.SparkILoop;
+import org.apache.zeppelin.interpreter.Interpreter;
+import org.apache.zeppelin.interpreter.InterpreterContext;
+import org.apache.zeppelin.interpreter.InterpreterGroup;
+import org.apache.zeppelin.interpreter.InterpreterResult;
+import org.apache.zeppelin.interpreter.InterpreterResult.Code;
+import org.apache.zeppelin.interpreter.WrappedInterpreter;
+import org.apache.zeppelin.interpreter.thrift.InterpreterCompletion;
+import org.apache.zeppelin.scheduler.Scheduler;
+import org.apache.zeppelin.spark.dep.SparkDependencyContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.sonatype.aether.resolution.ArtifactResolutionException;
+import org.sonatype.aether.resolution.DependencyResolutionException;
+
+import scala.Console;
+import scala.None;
+import scala.Some;
+import scala.collection.convert.WrapAsJava$;
+import scala.collection.JavaConversions;
+import scala.tools.nsc.Settings;
+import scala.tools.nsc.interpreter.Completion.Candidates;
+import scala.tools.nsc.interpreter.Completion.ScalaCompleter;
+import scala.tools.nsc.interpreter.IMain;
+import scala.tools.nsc.interpreter.Results;
+import scala.tools.nsc.settings.MutableSettings.BooleanSetting;
+import scala.tools.nsc.settings.MutableSettings.PathSetting;
+
+
+/**
+ * DepInterpreter downloads dependencies and pass them when SparkInterpreter initialized.
+ * It extends SparkInterpreter but does not create sparkcontext
+ *
+ */
+public class DepInterpreter extends Interpreter {
+  /**
+   * intp - org.apache.spark.repl.SparkIMain (scala 2.10)
+   * intp - scala.tools.nsc.interpreter.IMain; (scala 2.11)
+   */
+  private Object intp;
+  private ByteArrayOutputStream out;
+  private SparkDependencyContext depc;
+  /**
+   * completer - org.apache.spark.repl.SparkJLineCompletion (scala 2.10)
+   */
+  private Object completer;
+  private SparkILoop interpreter;
+  static final Logger LOGGER = LoggerFactory.getLogger(DepInterpreter.class);
+
+  public DepInterpreter(Properties property) {
+    super(property);
+  }
+
+  public SparkDependencyContext getDependencyContext() {
+    return depc;
+  }
+
+  public static String getSystemDefault(
+      String envName,
+      String propertyName,
+      String defaultValue) {
+
+    if (envName != null && !envName.isEmpty()) {
+      String envValue = System.getenv().get(envName);
+      if (envValue != null) {
+        return envValue;
+      }
+    }
+
+    if (propertyName != null && !propertyName.isEmpty()) {
+      String propValue = System.getProperty(propertyName);
+      if (propValue != null) {
+        return propValue;
+      }
+    }
+    return defaultValue;
+  }
+
+  @Override
+  public void close() {
+    if (intp != null) {
+      Utils.invokeMethod(intp, "close");
+    }
+  }
+
+  @Override
+  public void open() {
+    out = new ByteArrayOutputStream();
+    createIMain();
+  }
+
+
+  private void createIMain() {
+    Settings settings = new Settings();
+    URL[] urls = getClassloaderUrls();
+
+    // set classpath for scala compiler
+    PathSetting pathSettings = settings.classpath();
+    String classpath = "";
+    List<File> paths = currentClassPath();
+    for (File f : paths) {
+      if (classpath.length() > 0) {
+        classpath += File.pathSeparator;
+      }
+      classpath += f.getAbsolutePath();
+    }
+
+    if (urls != null) {
+      for (URL u : urls) {
+        if (classpath.length() > 0) {
+          classpath += File.pathSeparator;
+        }
+        classpath += u.getFile();
+      }
+    }
+
+    pathSettings.v_$eq(classpath);
+    settings.scala$tools$nsc$settings$ScalaSettings$_setter_$classpath_$eq(pathSettings);
+
+    // set classloader for scala compiler
+    settings.explicitParentLoader_$eq(new Some<>(Thread.currentThread()
+        .getContextClassLoader()));
+
+    BooleanSetting b = (BooleanSetting) settings.usejavacp();
+    b.v_$eq(true);
+    settings.scala$tools$nsc$settings$StandardScalaSettings$_setter_$usejavacp_$eq(b);
+
+    interpreter = new SparkILoop((java.io.BufferedReader) null, new PrintWriter(out));
+    interpreter.settings_$eq(settings);
+
+    interpreter.createInterpreter();
+
+
+    intp = Utils.invokeMethod(interpreter, "intp");
+
+    if (Utils.isScala2_10()) {
+      Utils.invokeMethod(intp, "setContextClassLoader");
+      Utils.invokeMethod(intp, "initializeSynchronous");
+    }
+
+    depc = new SparkDependencyContext(getProperty("zeppelin.dep.localrepo"),
+        getProperty("zeppelin.dep.additionalRemoteRepository"));
+    if (Utils.isScala2_10()) {
+      completer = Utils.instantiateClass(
+          "org.apache.spark.repl.SparkJLineCompletion",
+          new Class[]{Utils.findClass("org.apache.spark.repl.SparkIMain")},
+          new Object[]{intp});
+    }
+    interpret("@transient var _binder = new java.util.HashMap[String, Object]()");
+    Map<String, Object> binder;
+    if (Utils.isScala2_10()) {
+      binder = (Map<String, Object>) getValue("_binder");
+    } else {
+      binder = (Map<String, Object>) getLastObject();
+    }
+    binder.put("depc", depc);
+
+    interpret("@transient val z = "
+        + "_binder.get(\"depc\")"
+        + ".asInstanceOf[org.apache.zeppelin.spark.dep.SparkDependencyContext]");
+
+  }
+
+  private Results.Result interpret(String line) {
+    return (Results.Result) Utils.invokeMethod(
+        intp,
+        "interpret",
+        new Class[] {String.class},
+        new Object[] {line});
+  }
+
+  public Object getValue(String name) {
+    Object ret = Utils.invokeMethod(
+        intp, "valueOfTerm", new Class[]{String.class}, new Object[]{name});
+    if (ret instanceof None) {
+      return null;
+    } else if (ret instanceof Some) {
+      return ((Some) ret).get();
+    } else {
+      return ret;
+    }
+  }
+
+  public Object getLastObject() {
+    IMain.Request r = (IMain.Request) Utils.invokeMethod(intp, "lastRequest");
+    Object obj = r.lineRep().call("$result",
+        JavaConversions.asScalaBuffer(new LinkedList<>()));
+    return obj;
+  }
+
+  @Override
+  public InterpreterResult interpret(String st, InterpreterContext context) {
+    PrintStream printStream = new PrintStream(out);
+    Console.setOut(printStream);
+    out.reset();
+
+    SparkInterpreter sparkInterpreter = getSparkInterpreter();
+
+    if (sparkInterpreter != null && sparkInterpreter.getDelegation().isSparkContextInitialized()) {
+      return new InterpreterResult(Code.ERROR,
+          "Must be used before SparkInterpreter (%spark) initialized\n" +
+              "Hint: put this paragraph before any Spark code and " +
+              "restart Zeppelin/Interpreter" );
+    }
+
+    scala.tools.nsc.interpreter.Results.Result ret = interpret(st);
+    Code code = getResultCode(ret);
+
+    try {
+      depc.fetch();
+    } catch (MalformedURLException | DependencyResolutionException
+        | ArtifactResolutionException e) {
+      LOGGER.error("Exception in DepInterpreter while interpret ", e);
+      return new InterpreterResult(Code.ERROR, e.toString());
+    }
+
+    if (code == Code.INCOMPLETE) {
+      return new InterpreterResult(code, "Incomplete expression");
+    } else if (code == Code.ERROR) {
+      return new InterpreterResult(code, out.toString());
+    } else {
+      return new InterpreterResult(code, out.toString());
+    }
+  }
+
+  private Code getResultCode(scala.tools.nsc.interpreter.Results.Result r) {
+    if (r instanceof scala.tools.nsc.interpreter.Results.Success$) {
+      return Code.SUCCESS;
+    } else if (r instanceof scala.tools.nsc.interpreter.Results.Incomplete$) {
+      return Code.INCOMPLETE;
+    } else {
+      return Code.ERROR;
+    }
+  }
+
+  @Override
+  public void cancel(InterpreterContext context) {
+  }
+
+
+  @Override
+  public FormType getFormType() {
+    return FormType.NATIVE;
+  }
+
+  @Override
+  public int getProgress(InterpreterContext context) {
+    return 0;
+  }
+
+  @Override
+  public List<InterpreterCompletion> completion(String buf, int cursor,
+                                                InterpreterContext interpreterContext) {
+    if (Utils.isScala2_10()) {
+      ScalaCompleter c = (ScalaCompleter) Utils.invokeMethod(completer, "completer");
+      Candidates ret = c.complete(buf, cursor);
+
+      List<String> candidates = WrapAsJava$.MODULE$.seqAsJavaList(ret.candidates());
+      List<InterpreterCompletion> completions = new LinkedList<>();
+
+      for (String candidate : candidates) {
+        completions.add(new InterpreterCompletion(candidate, candidate, StringUtils.EMPTY));
+      }
+
+      return completions;
+    } else {
+      return new LinkedList<>();
+    }
+  }
+
+  private List<File> currentClassPath() {
+    List<File> paths = classPath(Thread.currentThread().getContextClassLoader());
+    String[] cps = System.getProperty("java.class.path").split(File.pathSeparator);
+    if (cps != null) {
+      for (String cp : cps) {
+        paths.add(new File(cp));
+      }
+    }
+    return paths;
+  }
+
+  private List<File> classPath(ClassLoader cl) {
+    List<File> paths = new LinkedList<>();
+    if (cl == null) {
+      return paths;
+    }
+
+    if (cl instanceof URLClassLoader) {
+      URLClassLoader ucl = (URLClassLoader) cl;
+      URL[] urls = ucl.getURLs();
+      if (urls != null) {
+        for (URL url : urls) {
+          paths.add(new File(url.getFile()));
+        }
+      }
+    }
+    return paths;
+  }
+
+  private SparkInterpreter getSparkInterpreter() {
+    InterpreterGroup intpGroup = getInterpreterGroup();
+    if (intpGroup == null) {
+      return null;
+    }
+
+    Interpreter p = getInterpreterInTheSameSessionByClassName(SparkInterpreter.class.getName());
+    if (p == null) {
+      return null;
+    }
+
+    while (p instanceof WrappedInterpreter) {
+      p = ((WrappedInterpreter) p).getInnerInterpreter();
+    }
+    return (SparkInterpreter) p;
+  }
+
+  @Override
+  public Scheduler getScheduler() {
+    SparkInterpreter sparkInterpreter = getSparkInterpreter();
+    if (sparkInterpreter != null) {
+      return getSparkInterpreter().getScheduler();
+    } else {
+      return null;
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/d762b528/spark/interpreter/src/main/java/org/apache/zeppelin/spark/IPySparkInterpreter.java
----------------------------------------------------------------------
diff --git a/spark/interpreter/src/main/java/org/apache/zeppelin/spark/IPySparkInterpreter.java b/spark/interpreter/src/main/java/org/apache/zeppelin/spark/IPySparkInterpreter.java
new file mode 100644
index 0000000..c7253fb
--- /dev/null
+++ b/spark/interpreter/src/main/java/org/apache/zeppelin/spark/IPySparkInterpreter.java
@@ -0,0 +1,128 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.zeppelin.spark;
+
+import org.apache.spark.SparkConf;
+import org.apache.spark.api.java.JavaSparkContext;
+import org.apache.zeppelin.interpreter.Interpreter;
+import org.apache.zeppelin.interpreter.InterpreterContext;
+import org.apache.zeppelin.interpreter.InterpreterException;
+import org.apache.zeppelin.interpreter.LazyOpenInterpreter;
+import org.apache.zeppelin.interpreter.WrappedInterpreter;
+import org.apache.zeppelin.python.IPythonInterpreter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.util.Map;
+import java.util.Properties;
+
+/**
+ * PySparkInterpreter which use IPython underlying.
+ */
+public class IPySparkInterpreter extends IPythonInterpreter {
+
+  private static final Logger LOGGER = LoggerFactory.getLogger(IPySparkInterpreter.class);
+
+  private SparkInterpreter sparkInterpreter;
+
+  public IPySparkInterpreter(Properties property) {
+    super(property);
+  }
+
+  @Override
+  public void open() throws InterpreterException {
+    setProperty("zeppelin.python",
+        PySparkInterpreter.getPythonExec(getProperties()));
+    sparkInterpreter = getSparkInterpreter();
+    SparkConf conf = sparkInterpreter.getSparkContext().getConf();
+    // only set PYTHONPATH in local or yarn-client mode.
+    // yarn-cluster will setup PYTHONPATH automatically.
+    if (!conf.get("spark.submit.deployMode").equals("cluster")) {
+      setAdditionalPythonPath(PythonUtils.sparkPythonPath());
+      setAddBulitinPy4j(false);
+    }
+    setAdditionalPythonInitFile("python/zeppelin_ipyspark.py");
+    super.open();
+  }
+
+  @Override
+  protected Map<String, String> setupIPythonEnv() throws IOException {
+    Map<String, String> env = super.setupIPythonEnv();
+    // set PYSPARK_PYTHON
+    SparkConf conf = sparkInterpreter.getSparkContext().getConf();
+    if (conf.contains("spark.pyspark.python")) {
+      env.put("PYSPARK_PYTHON", conf.get("spark.pyspark.python"));
+    }
+    return env;
+  }
+
+  private SparkInterpreter getSparkInterpreter() throws InterpreterException {
+    LazyOpenInterpreter lazy = null;
+    SparkInterpreter spark = null;
+    Interpreter p = getInterpreterInTheSameSessionByClassName(SparkInterpreter.class.getName());
+
+    while (p instanceof WrappedInterpreter) {
+      if (p instanceof LazyOpenInterpreter) {
+        lazy = (LazyOpenInterpreter) p;
+      }
+      p = ((WrappedInterpreter) p).getInnerInterpreter();
+    }
+    spark = (SparkInterpreter) p;
+
+    if (lazy != null) {
+      lazy.open();
+    }
+    return spark;
+  }
+
+  @Override
+  public void cancel(InterpreterContext context) throws InterpreterException {
+    super.cancel(context);
+    sparkInterpreter.cancel(context);
+  }
+
+  @Override
+  public void close() throws InterpreterException {
+    super.close();
+    if (sparkInterpreter != null) {
+      sparkInterpreter.close();
+    }
+  }
+
+  @Override
+  public int getProgress(InterpreterContext context) throws InterpreterException {
+    return sparkInterpreter.getProgress(context);
+  }
+
+  public boolean isSpark2() {
+    return sparkInterpreter.getSparkVersion().newerThanEquals(SparkVersion.SPARK_2_0_0);
+  }
+
+  public JavaSparkContext getJavaSparkContext() {
+    return sparkInterpreter.getJavaSparkContext();
+  }
+
+  public Object getSQLContext() {
+    return sparkInterpreter.getSQLContext();
+  }
+
+  public Object getSparkSession() {
+    return sparkInterpreter.getSparkSession();
+  }
+}

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/d762b528/spark/interpreter/src/main/java/org/apache/zeppelin/spark/NewSparkInterpreter.java
----------------------------------------------------------------------
diff --git a/spark/interpreter/src/main/java/org/apache/zeppelin/spark/NewSparkInterpreter.java b/spark/interpreter/src/main/java/org/apache/zeppelin/spark/NewSparkInterpreter.java
new file mode 100644
index 0000000..1d3ccd6
--- /dev/null
+++ b/spark/interpreter/src/main/java/org/apache/zeppelin/spark/NewSparkInterpreter.java
@@ -0,0 +1,390 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.zeppelin.spark;
+
+import com.google.common.collect.Lists;
+import org.apache.commons.lang.StringUtils;
+import org.apache.commons.lang3.exception.ExceptionUtils;
+import org.apache.spark.SparkConf;
+import org.apache.spark.SparkContext;
+import org.apache.spark.api.java.JavaSparkContext;
+import org.apache.spark.scheduler.SparkListenerJobStart;
+import org.apache.spark.sql.SQLContext;
+import org.apache.spark.ui.jobs.JobProgressListener;
+import org.apache.zeppelin.interpreter.BaseZeppelinContext;
+import org.apache.zeppelin.interpreter.DefaultInterpreterProperty;
+import org.apache.zeppelin.interpreter.Interpreter;
+import org.apache.zeppelin.interpreter.InterpreterContext;
+import org.apache.zeppelin.interpreter.InterpreterException;
+import org.apache.zeppelin.interpreter.InterpreterHookRegistry;
+import org.apache.zeppelin.interpreter.InterpreterResult;
+import org.apache.zeppelin.interpreter.WrappedInterpreter;
+import org.apache.zeppelin.interpreter.remote.RemoteEventClientWrapper;
+import org.apache.zeppelin.interpreter.thrift.InterpreterCompletion;
+import org.apache.zeppelin.spark.dep.SparkDependencyContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.File;
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+/**
+ * SparkInterpreter of Java implementation. It is just wrapper of Spark211Interpreter
+ * and Spark210Interpreter.
+ */
+public class NewSparkInterpreter extends AbstractSparkInterpreter {
+
+  private static final Logger LOGGER = LoggerFactory.getLogger(SparkInterpreter.class);
+
+  private BaseSparkScalaInterpreter innerInterpreter;
+  private Map<String, String> innerInterpreterClassMap = new HashMap<>();
+  private SparkContext sc;
+  private JavaSparkContext jsc;
+  private SQLContext sqlContext;
+  private Object sparkSession;
+
+  private SparkZeppelinContext z;
+  private SparkVersion sparkVersion;
+  private boolean enableSupportedVersionCheck;
+  private String sparkUrl;
+
+  private static InterpreterHookRegistry hooks;
+
+
+  public NewSparkInterpreter(Properties properties) {
+    super(properties);
+    this.enableSupportedVersionCheck = java.lang.Boolean.parseBoolean(
+        properties.getProperty("zeppelin.spark.enableSupportedVersionCheck", "true"));
+    innerInterpreterClassMap.put("2.10", "org.apache.zeppelin.spark.SparkScala210Interpreter");
+    innerInterpreterClassMap.put("2.11", "org.apache.zeppelin.spark.SparkScala211Interpreter");
+  }
+
+  @Override
+  public void open() throws InterpreterException {
+    try {
+      String scalaVersion = extractScalaVersion();
+      LOGGER.info("Using Scala Version: " + scalaVersion);
+      setupConfForPySpark();
+      SparkConf conf = new SparkConf();
+      for (Map.Entry<Object, Object> entry : getProperties().entrySet()) {
+        if (!StringUtils.isBlank(entry.getValue().toString())) {
+          conf.set(entry.getKey().toString(), entry.getValue().toString());
+        }
+        if (entry.getKey().toString().equals("zeppelin.spark.useHiveContext")) {
+          conf.set("spark.useHiveContext", entry.getValue().toString());
+        }
+      }
+      // use local mode for embedded spark mode when spark.master is not found
+      conf.setIfMissing("spark.master", "local");
+
+      String innerIntpClassName = innerInterpreterClassMap.get(scalaVersion);
+      Class clazz = Class.forName(innerIntpClassName);
+      this.innerInterpreter =
+          (BaseSparkScalaInterpreter) clazz.getConstructor(SparkConf.class, List.class)
+              .newInstance(conf, getDependencyFiles());
+      this.innerInterpreter.open();
+
+      sc = this.innerInterpreter.sc();
+      jsc = JavaSparkContext.fromSparkContext(sc);
+      sparkVersion = SparkVersion.fromVersionString(sc.version());
+      if (enableSupportedVersionCheck && sparkVersion.isUnsupportedVersion()) {
+        throw new Exception("This is not officially supported spark version: " + sparkVersion
+            + "\nYou can set zeppelin.spark.enableSupportedVersionCheck to false if you really" +
+            " want to try this version of spark.");
+      }
+      sqlContext = this.innerInterpreter.sqlContext();
+      sparkSession = this.innerInterpreter.sparkSession();
+      sparkUrl = this.innerInterpreter.sparkUrl();
+      setupListeners();
+
+      hooks = getInterpreterGroup().getInterpreterHookRegistry();
+      z = new SparkZeppelinContext(sc, hooks,
+          Integer.parseInt(getProperty("zeppelin.spark.maxResult")));
+      this.innerInterpreter.bind("z", z.getClass().getCanonicalName(), z,
+          Lists.newArrayList("@transient"));
+    } catch (Exception e) {
+      LOGGER.error(ExceptionUtils.getStackTrace(e));
+      throw new InterpreterException("Fail to open SparkInterpreter", e);
+    }
+  }
+
+  private void setupConfForPySpark() {
+    String sparkHome = getProperty("SPARK_HOME");
+    File pysparkFolder = null;
+    if (sparkHome == null) {
+      String zeppelinHome =
+          new DefaultInterpreterProperty("ZEPPELIN_HOME", "zeppelin.home", "../../")
+              .getValue().toString();
+      pysparkFolder = new File(zeppelinHome,
+          "interpreter" + File.separator + "spark" + File.separator + "pyspark");
+    } else {
+      pysparkFolder = new File(sparkHome, "python" + File.separator + "lib");
+    }
+
+    ArrayList<String> pysparkPackages = new ArrayList<>();
+    for (File file : pysparkFolder.listFiles()) {
+      if (file.getName().equals("pyspark.zip")) {
+        pysparkPackages.add(file.getAbsolutePath());
+      }
+      if (file.getName().startsWith("py4j-")) {
+        pysparkPackages.add(file.getAbsolutePath());
+      }
+    }
+
+    if (pysparkPackages.size() != 2) {
+      throw new RuntimeException("Not correct number of pyspark packages: " +
+          StringUtils.join(pysparkPackages, ","));
+    }
+    // Distribute two libraries(pyspark.zip and py4j-*.zip) to workers
+    System.setProperty("spark.files", mergeProperty(System.getProperty("spark.files", ""),
+        StringUtils.join(pysparkPackages, ",")));
+    System.setProperty("spark.submit.pyFiles", mergeProperty(
+        System.getProperty("spark.submit.pyFiles", ""), StringUtils.join(pysparkPackages, ",")));
+
+  }
+
+  private String mergeProperty(String originalValue, String appendedValue) {
+    if (StringUtils.isBlank(originalValue)) {
+      return appendedValue;
+    }
+    return originalValue + "," + appendedValue;
+  }
+
+  @Override
+  public void close() {
+    LOGGER.info("Close SparkInterpreter");
+    innerInterpreter.close();
+  }
+
+  @Override
+  public InterpreterResult interpret(String st, InterpreterContext context) {
+    InterpreterContext.set(context);
+    z.setGui(context.getGui());
+    z.setNoteGui(context.getNoteGui());
+    z.setInterpreterContext(context);
+    populateSparkWebUrl(context);
+    String jobDesc = "Started by: " + Utils.getUserName(context.getAuthenticationInfo());
+    sc.setJobGroup(Utils.buildJobGroupId(context), jobDesc, false);
+    return innerInterpreter.interpret(st, context);
+  }
+
+  @Override
+  public void cancel(InterpreterContext context) {
+    sc.cancelJobGroup(Utils.buildJobGroupId(context));
+  }
+
+  @Override
+  public List<InterpreterCompletion> completion(String buf,
+                                                int cursor,
+                                                InterpreterContext interpreterContext) {
+    LOGGER.debug("buf: " + buf + ", cursor:" + cursor);
+    return innerInterpreter.completion(buf, cursor, interpreterContext);
+  }
+
+  @Override
+  public FormType getFormType() {
+    return FormType.NATIVE;
+  }
+
+  @Override
+  public int getProgress(InterpreterContext context) {
+    return innerInterpreter.getProgress(Utils.buildJobGroupId(context), context);
+  }
+
+  private void setupListeners() {
+    JobProgressListener pl = new JobProgressListener(sc.getConf()) {
+      @Override
+      public synchronized void onJobStart(SparkListenerJobStart jobStart) {
+        super.onJobStart(jobStart);
+        int jobId = jobStart.jobId();
+        String jobGroupId = jobStart.properties().getProperty("spark.jobGroup.id");
+        String uiEnabled = jobStart.properties().getProperty("spark.ui.enabled");
+        String jobUrl = getJobUrl(jobId);
+        String noteId = Utils.getNoteId(jobGroupId);
+        String paragraphId = Utils.getParagraphId(jobGroupId);
+        // Button visible if Spark UI property not set, set as invalid boolean or true
+        java.lang.Boolean showSparkUI =
+            uiEnabled == null || !uiEnabled.trim().toLowerCase().equals("false");
+        if (showSparkUI && jobUrl != null) {
+          RemoteEventClientWrapper eventClient = BaseZeppelinContext.getEventClient();
+          Map<String, String> infos = new java.util.HashMap<>();
+          infos.put("jobUrl", jobUrl);
+          infos.put("label", "SPARK JOB");
+          infos.put("tooltip", "View in Spark web UI");
+          if (eventClient != null) {
+            eventClient.onParaInfosReceived(noteId, paragraphId, infos);
+          }
+        }
+      }
+
+      private String getJobUrl(int jobId) {
+        String jobUrl = null;
+        if (sparkUrl != null) {
+          jobUrl = sparkUrl + "/jobs/job?id=" + jobId;
+        }
+        return jobUrl;
+      }
+    };
+    try {
+      Object listenerBus = sc.getClass().getMethod("listenerBus").invoke(sc);
+      Method[] methods = listenerBus.getClass().getMethods();
+      Method addListenerMethod = null;
+      for (Method m : methods) {
+        if (!m.getName().equals("addListener")) {
+          continue;
+        }
+        Class<?>[] parameterTypes = m.getParameterTypes();
+        if (parameterTypes.length != 1) {
+          continue;
+        }
+        if (!parameterTypes[0].isAssignableFrom(JobProgressListener.class)) {
+          continue;
+        }
+        addListenerMethod = m;
+        break;
+      }
+      if (addListenerMethod != null) {
+        addListenerMethod.invoke(listenerBus, pl);
+      }
+    } catch (NoSuchMethodException | SecurityException | IllegalAccessException
+        | IllegalArgumentException | InvocationTargetException e) {
+      LOGGER.error(e.toString(), e);
+    }
+  }
+
+  public SparkZeppelinContext getZeppelinContext() {
+    return this.z;
+  }
+
+  public SparkContext getSparkContext() {
+    return this.sc;
+  }
+
+  @Override
+  public SQLContext getSQLContext() {
+    return sqlContext;
+  }
+
+  public JavaSparkContext getJavaSparkContext() {
+    return this.jsc;
+  }
+
+  public Object getSparkSession() {
+    return sparkSession;
+  }
+
+  public SparkVersion getSparkVersion() {
+    return sparkVersion;
+  }
+
+  private DepInterpreter getDepInterpreter() {
+    Interpreter p = getInterpreterInTheSameSessionByClassName(DepInterpreter.class.getName());
+    if (p == null) {
+      return null;
+    }
+
+    while (p instanceof WrappedInterpreter) {
+      p = ((WrappedInterpreter) p).getInnerInterpreter();
+    }
+    return (DepInterpreter) p;
+  }
+
+  private String extractScalaVersion() throws IOException, InterruptedException {
+    String scalaVersionString = scala.util.Properties.versionString();
+    if (scalaVersionString.contains("version 2.10")) {
+      return "2.10";
+    } else {
+      return "2.11";
+    }
+  }
+
+  public void populateSparkWebUrl(InterpreterContext ctx) {
+    Map<String, String> infos = new java.util.HashMap<>();
+    infos.put("url", sparkUrl);
+    String uiEnabledProp = properties.getProperty("spark.ui.enabled", "true");
+    java.lang.Boolean uiEnabled = java.lang.Boolean.parseBoolean(
+        uiEnabledProp.trim());
+    if (!uiEnabled) {
+      infos.put("message", "Spark UI disabled");
+    } else {
+      if (StringUtils.isNotBlank(sparkUrl)) {
+        infos.put("message", "Spark UI enabled");
+      } else {
+        infos.put("message", "No spark url defined");
+      }
+    }
+    if (ctx != null && ctx.getClient() != null) {
+      LOGGER.debug("Sending metadata to Zeppelin server: {}", infos.toString());
+      getZeppelinContext().setEventClient(ctx.getClient());
+      ctx.getClient().onMetaInfosReceived(infos);
+    }
+  }
+
+  public boolean isSparkContextInitialized() {
+    return this.sc != null;
+  }
+
+  private List<String> getDependencyFiles() {
+    List<String> depFiles = new ArrayList<>();
+    // add jar from DepInterpreter
+    DepInterpreter depInterpreter = getDepInterpreter();
+    if (depInterpreter != null) {
+      SparkDependencyContext depc = depInterpreter.getDependencyContext();
+      if (depc != null) {
+        List<File> files = depc.getFilesDist();
+        if (files != null) {
+          for (File f : files) {
+            depFiles.add(f.getAbsolutePath());
+          }
+        }
+      }
+    }
+
+    // add jar from local repo
+    String localRepo = getProperty("zeppelin.interpreter.localRepo");
+    if (localRepo != null) {
+      File localRepoDir = new File(localRepo);
+      if (localRepoDir.exists()) {
+        File[] files = localRepoDir.listFiles();
+        if (files != null) {
+          for (File f : files) {
+            depFiles.add(f.getAbsolutePath());
+          }
+        }
+      }
+    }
+    return depFiles;
+  }
+
+  @Override
+  public String getSparkUIUrl() {
+    return sparkUrl;
+  }
+
+  @Override
+  public boolean isUnsupportedSparkVersion() {
+    return enableSupportedVersionCheck  && sparkVersion.isUnsupportedVersion();
+  }
+}

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/d762b528/spark/interpreter/src/main/java/org/apache/zeppelin/spark/OldSparkInterpreter.java
----------------------------------------------------------------------
diff --git a/spark/interpreter/src/main/java/org/apache/zeppelin/spark/OldSparkInterpreter.java b/spark/interpreter/src/main/java/org/apache/zeppelin/spark/OldSparkInterpreter.java
new file mode 100644
index 0000000..6a54c3b
--- /dev/null
+++ b/spark/interpreter/src/main/java/org/apache/zeppelin/spark/OldSparkInterpreter.java
@@ -0,0 +1,1525 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.zeppelin.spark;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.hadoop.security.UserGroupInformation;
+import org.apache.spark.SecurityManager;
+import org.apache.spark.SparkConf;
+import org.apache.spark.SparkContext;
+import org.apache.spark.SparkEnv;
+import org.apache.spark.api.java.JavaSparkContext;
+import org.apache.spark.repl.SparkILoop;
+import org.apache.spark.scheduler.ActiveJob;
+import org.apache.spark.scheduler.DAGScheduler;
+import org.apache.spark.scheduler.Pool;
+import org.apache.spark.scheduler.SparkListenerJobStart;
+import org.apache.spark.sql.SQLContext;
+import org.apache.spark.ui.SparkUI;
+import org.apache.spark.ui.jobs.JobProgressListener;
+import org.apache.zeppelin.interpreter.BaseZeppelinContext;
+import org.apache.zeppelin.interpreter.Interpreter;
+import org.apache.zeppelin.interpreter.InterpreterContext;
+import org.apache.zeppelin.interpreter.InterpreterException;
+import org.apache.zeppelin.interpreter.InterpreterHookRegistry;
+import org.apache.zeppelin.interpreter.InterpreterResult;
+import org.apache.zeppelin.interpreter.InterpreterResult.Code;
+import org.apache.zeppelin.interpreter.InterpreterUtils;
+import org.apache.zeppelin.interpreter.WrappedInterpreter;
+import org.apache.zeppelin.interpreter.remote.RemoteEventClientWrapper;
+import org.apache.zeppelin.interpreter.thrift.InterpreterCompletion;
+import org.apache.zeppelin.interpreter.util.InterpreterOutputStream;
+import org.apache.zeppelin.resource.ResourcePool;
+import org.apache.zeppelin.resource.WellKnownResourceName;
+import org.apache.zeppelin.scheduler.Scheduler;
+import org.apache.zeppelin.scheduler.SchedulerFactory;
+import org.apache.zeppelin.spark.dep.SparkDependencyContext;
+import org.apache.zeppelin.spark.dep.SparkDependencyResolver;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import scala.Console;
+import scala.Enumeration.Value;
+import scala.None;
+import scala.Option;
+import scala.Some;
+import scala.Tuple2;
+import scala.collection.Iterator;
+import scala.collection.JavaConversions;
+import scala.collection.JavaConverters;
+import scala.collection.Seq;
+import scala.collection.convert.WrapAsJava$;
+import scala.collection.mutable.HashMap;
+import scala.collection.mutable.HashSet;
+import scala.reflect.io.AbstractFile;
+import scala.tools.nsc.Global;
+import scala.tools.nsc.Settings;
+import scala.tools.nsc.interpreter.Completion.Candidates;
+import scala.tools.nsc.interpreter.Completion.ScalaCompleter;
+import scala.tools.nsc.interpreter.IMain;
+import scala.tools.nsc.interpreter.Results;
+import scala.tools.nsc.settings.MutableSettings;
+import scala.tools.nsc.settings.MutableSettings.BooleanSetting;
+import scala.tools.nsc.settings.MutableSettings.PathSetting;
+
+/**
+ * Spark interpreter for Zeppelin.
+ *
+ */
+public class OldSparkInterpreter extends AbstractSparkInterpreter {
+  public static Logger logger = LoggerFactory.getLogger(OldSparkInterpreter.class);
+
+  private SparkZeppelinContext z;
+  private SparkILoop interpreter;
+  /**
+   * intp - org.apache.spark.repl.SparkIMain (scala 2.10)
+   * intp - scala.tools.nsc.interpreter.IMain; (scala 2.11)
+   */
+  private Object intp;
+  private SparkConf conf;
+  private static SparkContext sc;
+  private static SQLContext sqlc;
+  private static InterpreterHookRegistry hooks;
+  private static SparkEnv env;
+  private static Object sparkSession;    // spark 2.x
+  private static JobProgressListener sparkListener;
+  private static AbstractFile classOutputDir;
+  private static Integer sharedInterpreterLock = new Integer(0);
+  private static AtomicInteger numReferenceOfSparkContext = new AtomicInteger(0);
+
+  private InterpreterOutputStream out;
+  private SparkDependencyResolver dep;
+  private static String sparkUrl;
+
+  /**
+   * completer - org.apache.spark.repl.SparkJLineCompletion (scala 2.10)
+   */
+  private Object completer = null;
+
+  private Map<String, Object> binder;
+  private SparkVersion sparkVersion;
+  private static File outputDir;          // class outputdir for scala 2.11
+  private Object classServer;      // classserver for scala 2.11
+  private JavaSparkContext jsc;
+  private boolean enableSupportedVersionCheck;
+
+  public OldSparkInterpreter(Properties property) {
+    super(property);
+    out = new InterpreterOutputStream(logger);
+  }
+
+  public OldSparkInterpreter(Properties property, SparkContext sc) {
+    this(property);
+
+    this.sc = sc;
+    env = SparkEnv.get();
+    sparkListener = setupListeners(this.sc);
+  }
+
+  public SparkContext getSparkContext() {
+    synchronized (sharedInterpreterLock) {
+      if (sc == null) {
+        sc = createSparkContext();
+        env = SparkEnv.get();
+        sparkListener = setupListeners(sc);
+      }
+      return sc;
+    }
+  }
+
+  public JavaSparkContext getJavaSparkContext() {
+    synchronized (sharedInterpreterLock) {
+      if (jsc == null) {
+        jsc = JavaSparkContext.fromSparkContext(sc);
+      }
+      return jsc;
+    }
+  }
+
+  public boolean isSparkContextInitialized() {
+    synchronized (sharedInterpreterLock) {
+      return sc != null;
+    }
+  }
+
+  static JobProgressListener setupListeners(SparkContext context) {
+    JobProgressListener pl = new JobProgressListener(context.getConf()) {
+      @Override
+      public synchronized void onJobStart(SparkListenerJobStart jobStart) {
+        super.onJobStart(jobStart);
+        int jobId = jobStart.jobId();
+        String jobGroupId = jobStart.properties().getProperty("spark.jobGroup.id");
+        String uiEnabled = jobStart.properties().getProperty("spark.ui.enabled");
+        String jobUrl = getJobUrl(jobId);
+        String noteId = Utils.getNoteId(jobGroupId);
+        String paragraphId = Utils.getParagraphId(jobGroupId);
+        // Button visible if Spark UI property not set, set as invalid boolean or true
+        java.lang.Boolean showSparkUI =
+            uiEnabled == null || !uiEnabled.trim().toLowerCase().equals("false");
+        if (showSparkUI && jobUrl != null) {
+          RemoteEventClientWrapper eventClient = BaseZeppelinContext.getEventClient();
+          Map<String, String> infos = new java.util.HashMap<>();
+          infos.put("jobUrl", jobUrl);
+          infos.put("label", "SPARK JOB");
+          infos.put("tooltip", "View in Spark web UI");
+          if (eventClient != null) {
+            eventClient.onParaInfosReceived(noteId, paragraphId, infos);
+          }
+        }
+      }
+
+      private String getJobUrl(int jobId) {
+        String jobUrl = null;
+        if (sparkUrl != null) {
+          jobUrl = sparkUrl + "/jobs/job/?id=" + jobId;
+        }
+        return jobUrl;
+      }
+
+    };
+    try {
+      Object listenerBus = context.getClass().getMethod("listenerBus").invoke(context);
+
+      Method[] methods = listenerBus.getClass().getMethods();
+      Method addListenerMethod = null;
+      for (Method m : methods) {
+        if (!m.getName().equals("addListener")) {
+          continue;
+        }
+
+        Class<?>[] parameterTypes = m.getParameterTypes();
+
+        if (parameterTypes.length != 1) {
+          continue;
+        }
+
+        if (!parameterTypes[0].isAssignableFrom(JobProgressListener.class)) {
+          continue;
+        }
+
+        addListenerMethod = m;
+        break;
+      }
+
+      if (addListenerMethod != null) {
+        addListenerMethod.invoke(listenerBus, pl);
+      } else {
+        return null;
+      }
+    } catch (NoSuchMethodException | SecurityException | IllegalAccessException
+        | IllegalArgumentException | InvocationTargetException e) {
+      logger.error(e.toString(), e);
+      return null;
+    }
+    return pl;
+  }
+
+  private boolean useHiveContext() {
+    return java.lang.Boolean.parseBoolean(getProperty("zeppelin.spark.useHiveContext"));
+  }
+
+  /**
+   * See org.apache.spark.sql.SparkSession.hiveClassesArePresent
+   * @return
+   */
+  private boolean hiveClassesArePresent() {
+    try {
+      this.getClass().forName("org.apache.spark.sql.hive.execution.InsertIntoHiveTable");
+      this.getClass().forName("org.apache.hadoop.hive.conf.HiveConf");
+      return true;
+    } catch (ClassNotFoundException | NoClassDefFoundError e) {
+      return false;
+    }
+  }
+
+  private boolean importImplicit() {
+    return java.lang.Boolean.parseBoolean(getProperty("zeppelin.spark.importImplicit"));
+  }
+
+  public Object getSparkSession() {
+    synchronized (sharedInterpreterLock) {
+      if (sparkSession == null) {
+        createSparkSession();
+      }
+      return sparkSession;
+    }
+  }
+
+  public SQLContext getSQLContext() {
+    synchronized (sharedInterpreterLock) {
+      if (Utils.isSpark2()) {
+        return getSQLContext_2();
+      } else {
+        return getSQLContext_1();
+      }
+    }
+  }
+
+  /**
+   * Get SQLContext for spark 2.x
+   */
+  private SQLContext getSQLContext_2() {
+    if (sqlc == null) {
+      sqlc = (SQLContext) Utils.invokeMethod(sparkSession, "sqlContext");
+    }
+    return sqlc;
+  }
+
+  public SQLContext getSQLContext_1() {
+    if (sqlc == null) {
+      if (useHiveContext()) {
+        String name = "org.apache.spark.sql.hive.HiveContext";
+        Constructor<?> hc;
+        try {
+          hc = getClass().getClassLoader().loadClass(name)
+              .getConstructor(SparkContext.class);
+          sqlc = (SQLContext) hc.newInstance(getSparkContext());
+        } catch (NoSuchMethodException | SecurityException
+            | ClassNotFoundException | InstantiationException
+            | IllegalAccessException | IllegalArgumentException
+            | InvocationTargetException e) {
+          logger.warn("Can't create HiveContext. Fallback to SQLContext", e);
+          // when hive dependency is not loaded, it'll fail.
+          // in this case SQLContext can be used.
+          sqlc = new SQLContext(getSparkContext());
+        }
+      } else {
+        sqlc = new SQLContext(getSparkContext());
+      }
+    }
+    return sqlc;
+  }
+
+
+  public SparkDependencyResolver getDependencyResolver() {
+    if (dep == null) {
+      dep = new SparkDependencyResolver(
+          (Global) Utils.invokeMethod(intp, "global"),
+          (ClassLoader) Utils.invokeMethod(Utils.invokeMethod(intp, "classLoader"), "getParent"),
+          sc,
+          getProperty("zeppelin.dep.localrepo"),
+          getProperty("zeppelin.dep.additionalRemoteRepository"));
+    }
+    return dep;
+  }
+
+  private DepInterpreter getDepInterpreter() {
+    Interpreter p = getInterpreterInTheSameSessionByClassName(DepInterpreter.class.getName());
+    if (p == null) {
+      return null;
+    }
+
+    while (p instanceof WrappedInterpreter) {
+      p = ((WrappedInterpreter) p).getInnerInterpreter();
+    }
+    return (DepInterpreter) p;
+  }
+
+  public boolean isYarnMode() {
+    String master = getProperty("master");
+    if (master == null) {
+      master = getProperty("spark.master", "local[*]");
+    }
+    return master.startsWith("yarn");
+  }
+
+  /**
+   * Spark 2.x
+   * Create SparkSession
+   */
+  public Object createSparkSession() {
+    // use local mode for embedded spark mode when spark.master is not found
+    conf.setIfMissing("spark.master", "local");
+    logger.info("------ Create new SparkSession {} -------", conf.get("spark.master"));
+    String execUri = System.getenv("SPARK_EXECUTOR_URI");
+    if (outputDir != null) {
+      conf.set("spark.repl.class.outputDir", outputDir.getAbsolutePath());
+    }
+
+    if (execUri != null) {
+      conf.set("spark.executor.uri", execUri);
+    }
+    conf.set("spark.scheduler.mode", "FAIR");
+
+    Properties intpProperty = getProperties();
+    for (Object k : intpProperty.keySet()) {
+      String key = (String) k;
+      String val = toString(intpProperty.get(key));
+      if (!val.trim().isEmpty()) {
+        if (key.startsWith("spark.")) {
+          logger.debug(String.format("SparkConf: key = [%s], value = [%s]", key, val));
+          conf.set(key, val);
+        }
+        if (key.startsWith("zeppelin.spark.")) {
+          String sparkPropertyKey = key.substring("zeppelin.spark.".length());
+          logger.debug(String.format("SparkConf: key = [%s], value = [%s]", sparkPropertyKey, val));
+          conf.set(sparkPropertyKey, val);
+        }
+      }
+    }
+
+    Class SparkSession = Utils.findClass("org.apache.spark.sql.SparkSession");
+    Object builder = Utils.invokeStaticMethod(SparkSession, "builder");
+    Utils.invokeMethod(builder, "config", new Class[]{ SparkConf.class }, new Object[]{ conf });
+
+    if (useHiveContext()) {
+      if (hiveClassesArePresent()) {
+        Utils.invokeMethod(builder, "enableHiveSupport");
+        sparkSession = Utils.invokeMethod(builder, "getOrCreate");
+        logger.info("Created Spark session with Hive support");
+      } else {
+        Utils.invokeMethod(builder, "config",
+            new Class[]{ String.class, String.class},
+            new Object[]{ "spark.sql.catalogImplementation", "in-memory"});
+        sparkSession = Utils.invokeMethod(builder, "getOrCreate");
+        logger.info("Created Spark session with Hive support use in-memory catalogImplementation");
+      }
+    } else {
+      sparkSession = Utils.invokeMethod(builder, "getOrCreate");
+      logger.info("Created Spark session");
+    }
+
+    return sparkSession;
+  }
+
+  public SparkContext createSparkContext() {
+    if (Utils.isSpark2()) {
+      return createSparkContext_2();
+    } else {
+      return createSparkContext_1();
+    }
+  }
+
+  /**
+   * Create SparkContext for spark 2.x
+   * @return
+   */
+  private SparkContext createSparkContext_2() {
+    return (SparkContext) Utils.invokeMethod(sparkSession, "sparkContext");
+  }
+
+  public SparkContext createSparkContext_1() {
+    // use local mode for embedded spark mode when spark.master is not found
+    if (!conf.contains("spark.master")) {
+      conf.setMaster("local");
+    }
+    logger.info("------ Create new SparkContext {} -------", conf.get("spark.master"));
+
+    String execUri = System.getenv("SPARK_EXECUTOR_URI");
+    String[] jars = null;
+
+    if (Utils.isScala2_10()) {
+      jars = (String[]) Utils.invokeStaticMethod(SparkILoop.class, "getAddedJars");
+    } else {
+      jars = (String[]) Utils.invokeStaticMethod(
+          Utils.findClass("org.apache.spark.repl.Main"), "getAddedJars");
+    }
+
+    String classServerUri = null;
+    String replClassOutputDirectory = null;
+
+    try { // in case of spark 1.1x, spark 1.2x
+      Method classServer = intp.getClass().getMethod("classServer");
+      Object httpServer = classServer.invoke(intp);
+      classServerUri = (String) Utils.invokeMethod(httpServer, "uri");
+    } catch (NoSuchMethodException | SecurityException | IllegalAccessException
+        | IllegalArgumentException | InvocationTargetException e) {
+      // continue
+    }
+
+    if (classServerUri == null) {
+      try { // for spark 1.3x
+        Method classServer = intp.getClass().getMethod("classServerUri");
+        classServerUri = (String) classServer.invoke(intp);
+      } catch (NoSuchMethodException | SecurityException | IllegalAccessException
+          | 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]",
+            e.getMessage()));
+      }
+    }
+
+    if (classServerUri == null) {
+      try { // for RcpEnv
+        Method getClassOutputDirectory = intp.getClass().getMethod("getClassOutputDirectory");
+        File classOutputDirectory = (File) getClassOutputDirectory.invoke(intp);
+        replClassOutputDirectory = classOutputDirectory.getAbsolutePath();
+      } catch (NoSuchMethodException | SecurityException | IllegalAccessException
+          | IllegalArgumentException | InvocationTargetException e) {
+        // continue
+      }
+    }
+
+    if (Utils.isScala2_11()) {
+      classServer = createHttpServer(outputDir);
+      Utils.invokeMethod(classServer, "start");
+      classServerUri = (String) Utils.invokeMethod(classServer, "uri");
+    }
+
+    if (classServerUri != null) {
+      conf.set("spark.repl.class.uri", classServerUri);
+    }
+
+    if (replClassOutputDirectory != null) {
+      conf.set("spark.repl.class.outputDir", replClassOutputDirectory);
+    }
+
+    if (jars.length > 0) {
+      conf.setJars(jars);
+    }
+
+    if (execUri != null) {
+      conf.set("spark.executor.uri", execUri);
+    }
+    conf.set("spark.scheduler.mode", "FAIR");
+
+    Properties intpProperty = getProperties();
+    for (Object k : intpProperty.keySet()) {
+      String key = (String) k;
+      String val = toString(intpProperty.get(key));
+      if (!val.trim().isEmpty()) {
+        if (key.startsWith("spark.")) {
+          logger.debug(String.format("SparkConf: key = [%s], value = [%s]", key, val));
+          conf.set(key, val);
+        }
+
+        if (key.startsWith("zeppelin.spark.")) {
+          String sparkPropertyKey = key.substring("zeppelin.spark.".length());
+          logger.debug(String.format("SparkConf: key = [%s], value = [%s]", sparkPropertyKey, val));
+          conf.set(sparkPropertyKey, val);
+        }
+      }
+    }
+    SparkContext sparkContext = new SparkContext(conf);
+    return sparkContext;
+  }
+
+  static final String toString(Object o) {
+    return (o instanceof String) ? (String) o : "";
+  }
+
+  public static boolean useSparkSubmit() {
+    return null != System.getenv("SPARK_SUBMIT");
+  }
+
+  public boolean printREPLOutput() {
+    return java.lang.Boolean.parseBoolean(getProperty("zeppelin.spark.printREPLOutput"));
+  }
+
+  @Override
+  public void open() throws InterpreterException {
+    this.enableSupportedVersionCheck = java.lang.Boolean.parseBoolean(
+        getProperty("zeppelin.spark.enableSupportedVersionCheck", "true"));
+
+    // set properties and do login before creating any spark stuff for secured cluster
+    if (isYarnMode()) {
+      System.setProperty("SPARK_YARN_MODE", "true");
+    }
+    if (getProperties().containsKey("spark.yarn.keytab") &&
+        getProperties().containsKey("spark.yarn.principal")) {
+      try {
+        String keytab = getProperties().getProperty("spark.yarn.keytab");
+        String principal = getProperties().getProperty("spark.yarn.principal");
+        UserGroupInformation.loginUserFromKeytab(principal, keytab);
+      } catch (IOException e) {
+        throw new RuntimeException("Can not pass kerberos authentication", e);
+      }
+    }
+
+    conf = new SparkConf();
+    URL[] urls = getClassloaderUrls();
+
+    // Very nice discussion about how scala compiler handle classpath
+    // https://groups.google.com/forum/#!topic/scala-user/MlVwo2xCCI0
+
+    /*
+     * > val env = new nsc.Settings(errLogger) > env.usejavacp.value = true > val p = new
+     * Interpreter(env) > p.setContextClassLoader > Alternatively you can set the class path through
+     * nsc.Settings.classpath.
+     *
+     * >> val settings = new Settings() >> settings.usejavacp.value = true >>
+     * settings.classpath.value += File.pathSeparator + >> System.getProperty("java.class.path") >>
+     * val in = new Interpreter(settings) { >> override protected def parentClassLoader =
+     * getClass.getClassLoader >> } >> in.setContextClassLoader()
+     */
+    Settings settings = new Settings();
+
+    // process args
+    String args = getProperty("args");
+    if (args == null) {
+      args = "";
+    }
+
+    String[] argsArray = args.split(" ");
+    LinkedList<String> argList = new LinkedList<>();
+    for (String arg : argsArray) {
+      argList.add(arg);
+    }
+
+    DepInterpreter depInterpreter = getDepInterpreter();
+    String depInterpreterClasspath = "";
+    if (depInterpreter != null) {
+      SparkDependencyContext depc = depInterpreter.getDependencyContext();
+      if (depc != null) {
+        List<File> files = depc.getFiles();
+        if (files != null) {
+          for (File f : files) {
+            if (depInterpreterClasspath.length() > 0) {
+              depInterpreterClasspath += File.pathSeparator;
+            }
+            depInterpreterClasspath += f.getAbsolutePath();
+          }
+        }
+      }
+    }
+
+
+    if (Utils.isScala2_10()) {
+      scala.collection.immutable.List<String> list =
+          JavaConversions.asScalaBuffer(argList).toList();
+
+      Object sparkCommandLine = Utils.instantiateClass(
+          "org.apache.spark.repl.SparkCommandLine",
+          new Class[]{ scala.collection.immutable.List.class },
+          new Object[]{ list });
+
+      settings = (Settings) Utils.invokeMethod(sparkCommandLine, "settings");
+    } else {
+      String sparkReplClassDir = getProperty("spark.repl.classdir");
+      if (sparkReplClassDir == null) {
+        sparkReplClassDir = System.getProperty("spark.repl.classdir");
+      }
+      if (sparkReplClassDir == null) {
+        sparkReplClassDir = System.getProperty("java.io.tmpdir");
+      }
+
+      synchronized (sharedInterpreterLock) {
+        if (outputDir == null) {
+          outputDir = createTempDir(sparkReplClassDir);
+        }
+      }
+      argList.add("-Yrepl-class-based");
+      argList.add("-Yrepl-outdir");
+      argList.add(outputDir.getAbsolutePath());
+
+      String classpath = "";
+      if (conf.contains("spark.jars")) {
+        classpath = StringUtils.join(conf.get("spark.jars").split(","), File.separator);
+      }
+
+      if (!depInterpreterClasspath.isEmpty()) {
+        if (!classpath.isEmpty()) {
+          classpath += File.separator;
+        }
+        classpath += depInterpreterClasspath;
+      }
+
+      if (!classpath.isEmpty()) {
+        argList.add("-classpath");
+        argList.add(classpath);
+      }
+
+      scala.collection.immutable.List<String> list =
+          JavaConversions.asScalaBuffer(argList).toList();
+
+      settings.processArguments(list, true);
+    }
+
+    // set classpath for scala compiler
+    PathSetting pathSettings = settings.classpath();
+    String classpath = "";
+
+    List<File> paths = currentClassPath();
+    for (File f : paths) {
+      if (classpath.length() > 0) {
+        classpath += File.pathSeparator;
+      }
+      classpath += f.getAbsolutePath();
+    }
+
+    if (urls != null) {
+      for (URL u : urls) {
+        if (classpath.length() > 0) {
+          classpath += File.pathSeparator;
+        }
+        classpath += u.getFile();
+      }
+    }
+
+    // add dependency from DepInterpreter
+    if (classpath.length() > 0) {
+      classpath += File.pathSeparator;
+    }
+    classpath += depInterpreterClasspath;
+
+    // add dependency from local repo
+    String localRepo = getProperty("zeppelin.interpreter.localRepo");
+    if (localRepo != null) {
+      File localRepoDir = new File(localRepo);
+      if (localRepoDir.exists()) {
+        File[] files = localRepoDir.listFiles();
+        if (files != null) {
+          for (File f : files) {
+            if (classpath.length() > 0) {
+              classpath += File.pathSeparator;
+            }
+            classpath += f.getAbsolutePath();
+          }
+        }
+      }
+    }
+
+    pathSettings.v_$eq(classpath);
+    settings.scala$tools$nsc$settings$ScalaSettings$_setter_$classpath_$eq(pathSettings);
+
+    // set classloader for scala compiler
+    settings.explicitParentLoader_$eq(new Some<>(Thread.currentThread()
+        .getContextClassLoader()));
+    BooleanSetting b = (BooleanSetting) settings.usejavacp();
+    b.v_$eq(true);
+    settings.scala$tools$nsc$settings$StandardScalaSettings$_setter_$usejavacp_$eq(b);
+
+    /* Required for scoped mode.
+     * In scoped mode multiple scala compiler (repl) generates class in the same directory.
+     * Class names is not randomly generated and look like '$line12.$read$$iw$$iw'
+     * Therefore it's possible to generated class conflict(overwrite) with other repl generated
+     * class.
+     *
+     * To prevent generated class name conflict,
+     * change prefix of generated class name from each scala compiler (repl) instance.
+     *
+     * In Spark 2.x, REPL generated wrapper class name should compatible with the pattern
+     * ^(\$line(?:\d+)\.\$read)(?:\$\$iw)+$
+     *
+     * As hashCode() can return a negative integer value and the minus character '-' is invalid
+     * in a package name we change it to a numeric value '0' which still conforms to the regexp.
+     *
+     */
+    System.setProperty("scala.repl.name.line", ("$line" + this.hashCode()).replace('-', '0'));
+
+    // To prevent 'File name too long' error on some file system.
+    MutableSettings.IntSetting numClassFileSetting = settings.maxClassfileName();
+    numClassFileSetting.v_$eq(128);
+    settings.scala$tools$nsc$settings$ScalaSettings$_setter_$maxClassfileName_$eq(
+        numClassFileSetting);
+
+    synchronized (sharedInterpreterLock) {
+      /* create scala repl */
+      if (printREPLOutput()) {
+        this.interpreter = new SparkILoop((java.io.BufferedReader) null, new PrintWriter(out));
+      } else {
+        this.interpreter = new SparkILoop((java.io.BufferedReader) null,
+            new PrintWriter(Console.out(), false));
+      }
+
+      interpreter.settings_$eq(settings);
+
+      interpreter.createInterpreter();
+
+      intp = Utils.invokeMethod(interpreter, "intp");
+      Utils.invokeMethod(intp, "setContextClassLoader");
+      Utils.invokeMethod(intp, "initializeSynchronous");
+
+      if (Utils.isScala2_10()) {
+        if (classOutputDir == null) {
+          classOutputDir = settings.outputDirs().getSingleOutput().get();
+        } else {
+          // change SparkIMain class output dir
+          settings.outputDirs().setSingleOutput(classOutputDir);
+          ClassLoader cl = (ClassLoader) Utils.invokeMethod(intp, "classLoader");
+          try {
+            Field rootField = cl.getClass().getSuperclass().getDeclaredField("root");
+            rootField.setAccessible(true);
+            rootField.set(cl, classOutputDir);
+          } catch (NoSuchFieldException | IllegalAccessException e) {
+            logger.error(e.getMessage(), e);
+          }
+        }
+      }
+
+      if (Utils.findClass("org.apache.spark.repl.SparkJLineCompletion", true) != null) {
+        completer = Utils.instantiateClass(
+            "org.apache.spark.repl.SparkJLineCompletion",
+            new Class[]{Utils.findClass("org.apache.spark.repl.SparkIMain")},
+            new Object[]{intp});
+      } else if (Utils.findClass(
+          "scala.tools.nsc.interpreter.PresentationCompilerCompleter", true) != null) {
+        completer = Utils.instantiateClass(
+            "scala.tools.nsc.interpreter.PresentationCompilerCompleter",
+            new Class[]{ IMain.class },
+            new Object[]{ intp });
+      } else if (Utils.findClass(
+          "scala.tools.nsc.interpreter.JLineCompletion", true) != null) {
+        completer = Utils.instantiateClass(
+            "scala.tools.nsc.interpreter.JLineCompletion",
+            new Class[]{ IMain.class },
+            new Object[]{ intp });
+      }
+
+      if (Utils.isSpark2()) {
+        sparkSession = getSparkSession();
+      }
+      sc = getSparkContext();
+      if (sc.getPoolForName("fair").isEmpty()) {
+        Value schedulingMode = org.apache.spark.scheduler.SchedulingMode.FAIR();
+        int minimumShare = 0;
+        int weight = 1;
+        Pool pool = new Pool("fair", schedulingMode, minimumShare, weight);
+        sc.taskScheduler().rootPool().addSchedulable(pool);
+      }
+
+      sparkVersion = SparkVersion.fromVersionString(sc.version());
+
+      sqlc = getSQLContext();
+
+      dep = getDependencyResolver();
+
+      hooks = getInterpreterGroup().getInterpreterHookRegistry();
+
+      z = new SparkZeppelinContext(sc, hooks,
+          Integer.parseInt(getProperty("zeppelin.spark.maxResult")));
+
+      interpret("@transient val _binder = new java.util.HashMap[String, Object]()");
+      Map<String, Object> binder;
+      if (Utils.isScala2_10()) {
+        binder = (Map<String, Object>) getValue("_binder");
+      } else {
+        binder = (Map<String, Object>) getLastObject();
+      }
+      binder.put("sc", sc);
+      binder.put("sqlc", sqlc);
+      binder.put("z", z);
+
+      if (Utils.isSpark2()) {
+        binder.put("spark", sparkSession);
+      }
+
+      interpret("@transient val z = "
+          + "_binder.get(\"z\").asInstanceOf[org.apache.zeppelin.spark.SparkZeppelinContext]");
+      interpret("@transient val sc = "
+          + "_binder.get(\"sc\").asInstanceOf[org.apache.spark.SparkContext]");
+      interpret("@transient val sqlc = "
+          + "_binder.get(\"sqlc\").asInstanceOf[org.apache.spark.sql.SQLContext]");
+      interpret("@transient val sqlContext = "
+          + "_binder.get(\"sqlc\").asInstanceOf[org.apache.spark.sql.SQLContext]");
+
+      if (Utils.isSpark2()) {
+        interpret("@transient val spark = "
+            + "_binder.get(\"spark\").asInstanceOf[org.apache.spark.sql.SparkSession]");
+      }
+
+      interpret("import org.apache.spark.SparkContext._");
+
+      if (importImplicit()) {
+        if (Utils.isSpark2()) {
+          interpret("import spark.implicits._");
+          interpret("import spark.sql");
+          interpret("import org.apache.spark.sql.functions._");
+        } else {
+          if (sparkVersion.oldSqlContextImplicits()) {
+            interpret("import sqlContext._");
+          } else {
+            interpret("import sqlContext.implicits._");
+            interpret("import sqlContext.sql");
+            interpret("import org.apache.spark.sql.functions._");
+          }
+        }
+      }
+    }
+
+    /* Temporary disabling DisplayUtils. see https://issues.apache.org/jira/browse/ZEPPELIN-127
+     *
+    // Utility functions for display
+    intp.interpret("import org.apache.zeppelin.spark.utils.DisplayUtils._");
+
+    // Scala implicit value for spark.maxResult
+    intp.interpret("import org.apache.zeppelin.spark.utils.SparkMaxResult");
+    intp.interpret("implicit val sparkMaxResult = new SparkMaxResult(" +
+            Integer.parseInt(getProperty("zeppelin.spark.maxResult")) + ")");
+     */
+
+    if (Utils.isScala2_10()) {
+      try {
+        if (sparkVersion.oldLoadFilesMethodName()) {
+          Method loadFiles = this.interpreter.getClass().getMethod("loadFiles", Settings.class);
+          loadFiles.invoke(this.interpreter, settings);
+        } else {
+          Method loadFiles = this.interpreter.getClass().getMethod(
+              "org$apache$spark$repl$SparkILoop$$loadFiles", Settings.class);
+          loadFiles.invoke(this.interpreter, settings);
+        }
+      } catch (NoSuchMethodException | SecurityException | IllegalAccessException
+          | IllegalArgumentException | InvocationTargetException e) {
+        throw new InterpreterException(e);
+      }
+    }
+
+    // add jar from DepInterpreter
+    if (depInterpreter != null) {
+      SparkDependencyContext depc = depInterpreter.getDependencyContext();
+      if (depc != null) {
+        List<File> files = depc.getFilesDist();
+        if (files != null) {
+          for (File f : files) {
+            if (f.getName().toLowerCase().endsWith(".jar")) {
+              sc.addJar(f.getAbsolutePath());
+              logger.info("sc.addJar(" + f.getAbsolutePath() + ")");
+            } else {
+              sc.addFile(f.getAbsolutePath());
+              logger.info("sc.addFile(" + f.getAbsolutePath() + ")");
+            }
+          }
+        }
+      }
+    }
+
+    // add jar from local repo
+    if (localRepo != null) {
+      File localRepoDir = new File(localRepo);
+      if (localRepoDir.exists()) {
+        File[] files = localRepoDir.listFiles();
+        if (files != null) {
+          for (File f : files) {
+            if (f.getName().toLowerCase().endsWith(".jar")) {
+              sc.addJar(f.getAbsolutePath());
+              logger.info("sc.addJar(" + f.getAbsolutePath() + ")");
+            } else {
+              sc.addFile(f.getAbsolutePath());
+              logger.info("sc.addFile(" + f.getAbsolutePath() + ")");
+            }
+          }
+        }
+      }
+    }
+
+    numReferenceOfSparkContext.incrementAndGet();
+  }
+
+  public String getSparkUIUrl() {
+    if (sparkUrl != null) {
+      return sparkUrl;
+    }
+
+    String sparkUrlProp = getProperty("zeppelin.spark.uiWebUrl", "");
+    if (!StringUtils.isBlank(sparkUrlProp)) {
+      return sparkUrlProp;
+    }
+
+    if (sparkVersion.newerThanEquals(SparkVersion.SPARK_2_0_0)) {
+      Option<String> uiWebUrlOption = (Option<String>) Utils.invokeMethod(sc, "uiWebUrl");
+      if (uiWebUrlOption.isDefined()) {
+        return uiWebUrlOption.get();
+      }
+    } else {
+      Option<SparkUI> sparkUIOption = (Option<SparkUI>) Utils.invokeMethod(sc, "ui");
+      if (sparkUIOption.isDefined()) {
+        return (String) Utils.invokeMethod(sparkUIOption.get(), "appUIAddress");
+      }
+    }
+    return null;
+  }
+
+  private Results.Result interpret(String line) {
+    out.ignoreLeadingNewLinesFromScalaReporter();
+    return (Results.Result) Utils.invokeMethod(
+        intp,
+        "interpret",
+        new Class[] {String.class},
+        new Object[] {line});
+  }
+
+  public void populateSparkWebUrl(InterpreterContext ctx) {
+    sparkUrl = getSparkUIUrl();
+    Map<String, String> infos = new java.util.HashMap<>();
+    infos.put("url", sparkUrl);
+    String uiEnabledProp = getProperty("spark.ui.enabled", "true");
+    java.lang.Boolean uiEnabled = java.lang.Boolean.parseBoolean(
+        uiEnabledProp.trim());
+    if (!uiEnabled) {
+      infos.put("message", "Spark UI disabled");
+    } else {
+      if (StringUtils.isNotBlank(sparkUrl)) {
+        infos.put("message", "Spark UI enabled");
+      } else {
+        infos.put("message", "No spark url defined");
+      }
+    }
+    if (ctx != null && ctx.getClient() != null) {
+      logger.info("Sending metadata to Zeppelin server: {}", infos.toString());
+      getZeppelinContext().setEventClient(ctx.getClient());
+      ctx.getClient().onMetaInfosReceived(infos);
+    }
+  }
+
+  private List<File> currentClassPath() {
+    List<File> paths = classPath(Thread.currentThread().getContextClassLoader());
+    String[] cps = System.getProperty("java.class.path").split(File.pathSeparator);
+    if (cps != null) {
+      for (String cp : cps) {
+        paths.add(new File(cp));
+      }
+    }
+    return paths;
+  }
+
+  private List<File> classPath(ClassLoader cl) {
+    List<File> paths = new LinkedList<>();
+    if (cl == null) {
+      return paths;
+    }
+
+    if (cl instanceof URLClassLoader) {
+      URLClassLoader ucl = (URLClassLoader) cl;
+      URL[] urls = ucl.getURLs();
+      if (urls != null) {
+        for (URL url : urls) {
+          paths.add(new File(url.getFile()));
+        }
+      }
+    }
+    return paths;
+  }
+
+  @Override
+  public List<InterpreterCompletion> completion(String buf, int cursor,
+                                                InterpreterContext interpreterContext) {
+    if (completer == null) {
+      logger.warn("Can't find completer");
+      return new LinkedList<>();
+    }
+
+    if (buf.length() < cursor) {
+      cursor = buf.length();
+    }
+
+    ScalaCompleter c = (ScalaCompleter) Utils.invokeMethod(completer, "completer");
+
+    if (Utils.isScala2_10() || !Utils.isCompilerAboveScala2_11_7()) {
+      String singleToken = getCompletionTargetString(buf, cursor);
+      Candidates ret = c.complete(singleToken, singleToken.length());
+
+      List<String> candidates = WrapAsJava$.MODULE$.seqAsJavaList(ret.candidates());
+      List<InterpreterCompletion> completions = new LinkedList<>();
+
+      for (String candidate : candidates) {
+        completions.add(new InterpreterCompletion(candidate, candidate, StringUtils.EMPTY));
+      }
+
+      return completions;
+    } else {
+      Candidates ret = c.complete(buf, cursor);
+
+      List<String> candidates = WrapAsJava$.MODULE$.seqAsJavaList(ret.candidates());
+      List<InterpreterCompletion> completions = new LinkedList<>();
+
+      for (String candidate : candidates) {
+        completions.add(new InterpreterCompletion(candidate, candidate, StringUtils.EMPTY));
+      }
+
+      return completions;
+    }
+  }
+
+  private String getCompletionTargetString(String text, int cursor) {
+    String[] completionSeqCharaters = {" ", "\n", "\t"};
+    int completionEndPosition = cursor;
+    int completionStartPosition = cursor;
+    int indexOfReverseSeqPostion = cursor;
+
+    String resultCompletionText = "";
+    String completionScriptText = "";
+    try {
+      completionScriptText = text.substring(0, cursor);
+    }
+    catch (Exception e) {
+      logger.error(e.toString());
+      return null;
+    }
+    completionEndPosition = completionScriptText.length();
+
+    String tempReverseCompletionText = new StringBuilder(completionScriptText).reverse().toString();
+
+    for (String seqCharacter : completionSeqCharaters) {
+      indexOfReverseSeqPostion = tempReverseCompletionText.indexOf(seqCharacter);
+
+      if (indexOfReverseSeqPostion < completionStartPosition && indexOfReverseSeqPostion > 0) {
+        completionStartPosition = indexOfReverseSeqPostion;
+      }
+
+    }
+
+    if (completionStartPosition == completionEndPosition) {
+      completionStartPosition = 0;
+    }
+    else
+    {
+      completionStartPosition = completionEndPosition - completionStartPosition;
+    }
+    resultCompletionText = completionScriptText.substring(
+        completionStartPosition , completionEndPosition);
+
+    return resultCompletionText;
+  }
+
+  /*
+   * this method doesn't work in scala 2.11
+   * Somehow intp.valueOfTerm returns scala.None always with -Yrepl-class-based option
+   */
+  public Object getValue(String name) {
+    Object ret = Utils.invokeMethod(
+        intp, "valueOfTerm", new Class[]{String.class}, new Object[]{name});
+
+    if (ret instanceof None || ret instanceof scala.None$) {
+      return null;
+    } else if (ret instanceof Some) {
+      return ((Some) ret).get();
+    } else {
+      return ret;
+    }
+  }
+
+  public Object getLastObject() {
+    IMain.Request r = (IMain.Request) Utils.invokeMethod(intp, "lastRequest");
+    if (r == null || r.lineRep() == null) {
+      return null;
+    }
+    Object obj = r.lineRep().call("$result",
+        JavaConversions.asScalaBuffer(new LinkedList<>()));
+    return obj;
+  }
+
+  public boolean isUnsupportedSparkVersion() {
+    return enableSupportedVersionCheck  && sparkVersion.isUnsupportedVersion();
+  }
+
+  /**
+   * Interpret a single line.
+   */
+  @Override
+  public InterpreterResult interpret(String line, InterpreterContext context) {
+    if (isUnsupportedSparkVersion()) {
+      return new InterpreterResult(Code.ERROR, "Spark " + sparkVersion.toString()
+          + " is not supported");
+    }
+    populateSparkWebUrl(context);
+    z.setInterpreterContext(context);
+    if (line == null || line.trim().length() == 0) {
+      return new InterpreterResult(Code.SUCCESS);
+    }
+    return interpret(line.split("\n"), context);
+  }
+
+  public InterpreterResult interpret(String[] lines, InterpreterContext context) {
+    synchronized (this) {
+      z.setGui(context.getGui());
+      z.setNoteGui(context.getNoteGui());
+      String jobDesc = "Started by: " + Utils.getUserName(context.getAuthenticationInfo());
+      sc.setJobGroup(Utils.buildJobGroupId(context), jobDesc, false);
+      InterpreterResult r = interpretInput(lines, context);
+      sc.clearJobGroup();
+      return r;
+    }
+  }
+
+  public InterpreterResult interpretInput(String[] lines, InterpreterContext context) {
+    SparkEnv.set(env);
+
+    String[] linesToRun = new String[lines.length];
+    for (int i = 0; i < lines.length; i++) {
+      linesToRun[i] = lines[i];
+    }
+
+    Console.setOut(context.out);
+    out.setInterpreterOutput(context.out);
+    context.out.clear();
+    Code r = null;
+    String incomplete = "";
+    boolean inComment = false;
+
+    for (int l = 0; l < linesToRun.length; l++) {
+      String s = linesToRun[l];
+      // check if next line starts with "." (but not ".." or "./") it is treated as an invocation
+      if (l + 1 < linesToRun.length) {
+        String nextLine = linesToRun[l + 1].trim();
+        boolean continuation = false;
+        if (nextLine.isEmpty()
+            || nextLine.startsWith("//")         // skip empty line or comment
+            || nextLine.startsWith("}")
+            || nextLine.startsWith("object")) {  // include "} object" for Scala companion object
+          continuation = true;
+        } else if (!inComment && nextLine.startsWith("/*")) {
+          inComment = true;
+          continuation = true;
+        } else if (inComment && nextLine.lastIndexOf("*/") >= 0) {
+          inComment = false;
+          continuation = true;
+        } else if (nextLine.length() > 1
+            && nextLine.charAt(0) == '.'
+            && nextLine.charAt(1) != '.'     // ".."
+            && nextLine.charAt(1) != '/') {  // "./"
+          continuation = true;
+        } else if (inComment) {
+          continuation = true;
+        }
+        if (continuation) {
+          incomplete += s + "\n";
+          continue;
+        }
+      }
+
+      scala.tools.nsc.interpreter.Results.Result res = null;
+      try {
+        res = interpret(incomplete + s);
+      } catch (Exception e) {
+        sc.clearJobGroup();
+        out.setInterpreterOutput(null);
+        logger.info("Interpreter exception", e);
+        return new InterpreterResult(Code.ERROR, InterpreterUtils.getMostRelevantMessage(e));
+      }
+
+      r = getResultCode(res);
+
+      if (r == Code.ERROR) {
+        sc.clearJobGroup();
+        out.setInterpreterOutput(null);
+        return new InterpreterResult(r, "");
+      } else if (r == Code.INCOMPLETE) {
+        incomplete += s + "\n";
+      } else {
+        incomplete = "";
+      }
+    }
+
+    // make sure code does not finish with comment
+    if (r == Code.INCOMPLETE) {
+      scala.tools.nsc.interpreter.Results.Result res = null;
+      res = interpret(incomplete + "\nprint(\"\")");
+      r = getResultCode(res);
+    }
+
+    if (r == Code.INCOMPLETE) {
+      sc.clearJobGroup();
+      out.setInterpreterOutput(null);
+      return new InterpreterResult(r, "Incomplete expression");
+    } else {
+      sc.clearJobGroup();
+      putLatestVarInResourcePool(context);
+      out.setInterpreterOutput(null);
+      return new InterpreterResult(Code.SUCCESS);
+    }
+  }
+
+  private void putLatestVarInResourcePool(InterpreterContext context) {
+    String varName = (String) Utils.invokeMethod(intp, "mostRecentVar");
+    if (varName == null || varName.isEmpty()) {
+      return;
+    }
+    Object lastObj = null;
+    try {
+      if (Utils.isScala2_10()) {
+        lastObj = getValue(varName);
+      } else {
+        lastObj = getLastObject();
+      }
+    } catch (NullPointerException e) {
+      // Some case, scala.tools.nsc.interpreter.IMain$ReadEvalPrint.call throws an NPE
+      logger.error(e.getMessage(), e);
+    }
+
+    if (lastObj != null) {
+      ResourcePool resourcePool = context.getResourcePool();
+      resourcePool.put(context.getNoteId(), context.getParagraphId(),
+          WellKnownResourceName.ZeppelinReplResult.toString(), lastObj);
+    }
+  };
+
+
+  @Override
+  public void cancel(InterpreterContext context) {
+    sc.cancelJobGroup(Utils.buildJobGroupId(context));
+  }
+
+  @Override
+  public int getProgress(InterpreterContext context) {
+    String jobGroup = Utils.buildJobGroupId(context);
+    int completedTasks = 0;
+    int totalTasks = 0;
+
+    DAGScheduler scheduler = sc.dagScheduler();
+    if (scheduler == null) {
+      return 0;
+    }
+    HashSet<ActiveJob> jobs = scheduler.activeJobs();
+    if (jobs == null || jobs.size() == 0) {
+      return 0;
+    }
+    Iterator<ActiveJob> it = jobs.iterator();
+    while (it.hasNext()) {
+      ActiveJob job = it.next();
+      String g = (String) job.properties().get("spark.jobGroup.id");
+      if (jobGroup.equals(g)) {
+        int[] progressInfo = null;
+        try {
+          Object finalStage = job.getClass().getMethod("finalStage").invoke(job);
+          if (sparkVersion.getProgress1_0()) {
+            progressInfo = getProgressFromStage_1_0x(sparkListener, finalStage);
+          } else {
+            progressInfo = getProgressFromStage_1_1x(sparkListener, finalStage);
+          }
+        } catch (IllegalAccessException | IllegalArgumentException
+            | InvocationTargetException | NoSuchMethodException
+            | SecurityException e) {
+          logger.error("Can't get progress info", e);
+          return 0;
+        }
+        totalTasks += progressInfo[0];
+        completedTasks += progressInfo[1];
+      }
+    }
+
+    if (totalTasks == 0) {
+      return 0;
+    }
+    return completedTasks * 100 / totalTasks;
+  }
+
+  private int[] getProgressFromStage_1_0x(JobProgressListener sparkListener, Object stage)
+      throws IllegalAccessException, IllegalArgumentException,
+      InvocationTargetException, NoSuchMethodException, SecurityException {
+    int numTasks = (int) stage.getClass().getMethod("numTasks").invoke(stage);
+    int completedTasks = 0;
+
+    int id = (int) stage.getClass().getMethod("id").invoke(stage);
+
+    Object completedTaskInfo = null;
+
+    completedTaskInfo = JavaConversions.mapAsJavaMap(
+        (HashMap<Object, Object>) sparkListener.getClass()
+            .getMethod("stageIdToTasksComplete").invoke(sparkListener)).get(id);
+
+    if (completedTaskInfo != null) {
+      completedTasks += (int) completedTaskInfo;
+    }
+    List<Object> parents = JavaConversions.seqAsJavaList((Seq<Object>) stage.getClass()
+        .getMethod("parents").invoke(stage));
+    if (parents != null) {
+      for (Object s : parents) {
+        int[] p = getProgressFromStage_1_0x(sparkListener, s);
+        numTasks += p[0];
+        completedTasks += p[1];
+      }
+    }
+
+    return new int[] {numTasks, completedTasks};
+  }
+
+  private int[] getProgressFromStage_1_1x(JobProgressListener sparkListener, Object stage)
+      throws IllegalAccessException, IllegalArgumentException,
+      InvocationTargetException, NoSuchMethodException, SecurityException {
+    int numTasks = (int) stage.getClass().getMethod("numTasks").invoke(stage);
+    int completedTasks = 0;
+    int id = (int) stage.getClass().getMethod("id").invoke(stage);
+
+    try {
+      Method stageIdToData = sparkListener.getClass().getMethod("stageIdToData");
+      HashMap<Tuple2<Object, Object>, Object> stageIdData =
+          (HashMap<Tuple2<Object, Object>, Object>) stageIdToData.invoke(sparkListener);
+      Class<?> stageUIDataClass =
+          this.getClass().forName("org.apache.spark.ui.jobs.UIData$StageUIData");
+
+      Method numCompletedTasks = stageUIDataClass.getMethod("numCompleteTasks");
+      Set<Tuple2<Object, Object>> keys =
+          JavaConverters.setAsJavaSetConverter(stageIdData.keySet()).asJava();
+      for (Tuple2<Object, Object> k : keys) {
+        if (id == (int) k._1()) {
+          Object uiData = stageIdData.get(k).get();
+          completedTasks += (int) numCompletedTasks.invoke(uiData);
+        }
+      }
+    } catch (Exception e) {
+      logger.error("Error on getting progress information", e);
+    }
+
+    List<Object> parents = JavaConversions.seqAsJavaList((Seq<Object>) stage.getClass()
+        .getMethod("parents").invoke(stage));
+    if (parents != null) {
+      for (Object s : parents) {
+        int[] p = getProgressFromStage_1_1x(sparkListener, s);
+        numTasks += p[0];
+        completedTasks += p[1];
+      }
+    }
+    return new int[] {numTasks, completedTasks};
+  }
+
+  private Code getResultCode(scala.tools.nsc.interpreter.Results.Result r) {
+    if (r instanceof scala.tools.nsc.interpreter.Results.Success$) {
+      return Code.SUCCESS;
+    } else if (r instanceof scala.tools.nsc.interpreter.Results.Incomplete$) {
+      return Code.INCOMPLETE;
+    } else {
+      return Code.ERROR;
+    }
+  }
+
+  @Override
+  public void close() {
+    logger.info("Close interpreter");
+
+    if (numReferenceOfSparkContext.decrementAndGet() == 0) {
+      if (sparkSession != null) {
+        Utils.invokeMethod(sparkSession, "stop");
+      } else if (sc != null){
+        sc.stop();
+      }
+      sparkSession = null;
+      sc = null;
+      jsc = null;
+      if (classServer != null) {
+        Utils.invokeMethod(classServer, "stop");
+        classServer = null;
+      }
+    }
+
+    Utils.invokeMethod(intp, "close");
+  }
+
+  @Override
+  public FormType getFormType() {
+    return FormType.NATIVE;
+  }
+
+  public JobProgressListener getJobProgressListener() {
+    return sparkListener;
+  }
+
+  @Override
+  public Scheduler getScheduler() {
+    return SchedulerFactory.singleton().createOrGetFIFOScheduler(
+        OldSparkInterpreter.class.getName() + this.hashCode());
+  }
+
+  public SparkZeppelinContext getZeppelinContext() {
+    return z;
+  }
+
+  public SparkVersion getSparkVersion() {
+    return sparkVersion;
+  }
+
+  private File createTempDir(String dir) {
+    File file = null;
+
+    // try Utils.createTempDir()
+    file = (File) Utils.invokeStaticMethod(
+        Utils.findClass("org.apache.spark.util.Utils"),
+        "createTempDir",
+        new Class[]{String.class, String.class},
+        new Object[]{dir, "spark"});
+
+    // fallback to old method
+    if (file == null) {
+      file = (File) Utils.invokeStaticMethod(
+          Utils.findClass("org.apache.spark.util.Utils"),
+          "createTempDir",
+          new Class[]{String.class},
+          new Object[]{dir});
+    }
+
+    return file;
+  }
+
+  private Object createHttpServer(File outputDir) {
+    SparkConf conf = new SparkConf();
+    try {
+      // try to create HttpServer
+      Constructor<?> constructor = getClass().getClassLoader()
+          .loadClass("org.apache.spark.HttpServer")
+          .getConstructor(new Class[]{
+            SparkConf.class, File.class, SecurityManager.class, int.class, String.class});
+
+      Object securityManager = createSecurityManager(conf);
+      return constructor.newInstance(new Object[]{
+        conf, outputDir, securityManager, 0, "HTTP Server"});
+
+    } catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException |
+        InstantiationException | InvocationTargetException e) {
+      // fallback to old constructor
+      Constructor<?> constructor = null;
+      try {
+        constructor = getClass().getClassLoader()
+            .loadClass("org.apache.spark.HttpServer")
+            .getConstructor(new Class[]{
+              File.class, SecurityManager.class, int.class, String.class});
+        return constructor.newInstance(new Object[] {
+          outputDir, createSecurityManager(conf), 0, "HTTP Server"});
+      } catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException |
+          InstantiationException | InvocationTargetException e1) {
+        logger.error(e1.getMessage(), e1);
+        return null;
+      }
+    }
+  }
+
+  /**
+   * Constructor signature of SecurityManager changes in spark 2.1.0, so we use this method to
+   * create SecurityManager properly for different versions of spark
+   *
+   * @param conf
+   * @return
+   * @throws ClassNotFoundException
+   * @throws NoSuchMethodException
+   * @throws IllegalAccessException
+   * @throws InvocationTargetException
+   * @throws InstantiationException
+   */
+  private Object createSecurityManager(SparkConf conf) throws ClassNotFoundException,
+      NoSuchMethodException, IllegalAccessException, InvocationTargetException,
+      InstantiationException {
+    Object securityManager = null;
+    try {
+      Constructor<?> smConstructor = getClass().getClassLoader()
+          .loadClass("org.apache.spark.SecurityManager")
+          .getConstructor(new Class[]{ SparkConf.class, scala.Option.class });
+      securityManager = smConstructor.newInstance(conf, null);
+    } catch (NoSuchMethodException e) {
+      Constructor<?> smConstructor = getClass().getClassLoader()
+          .loadClass("org.apache.spark.SecurityManager")
+          .getConstructor(new Class[]{ SparkConf.class });
+      securityManager = smConstructor.newInstance(conf);
+    }
+    return securityManager;
+  }
+}


[03/10] zeppelin git commit: ZEPPELIN-3111. Refactor SparkInterpreter

Posted by zj...@apache.org.
http://git-wip-us.apache.org/repos/asf/zeppelin/blob/d762b528/spark/src/main/java/org/apache/zeppelin/spark/SparkInterpreter.java
----------------------------------------------------------------------
diff --git a/spark/src/main/java/org/apache/zeppelin/spark/SparkInterpreter.java b/spark/src/main/java/org/apache/zeppelin/spark/SparkInterpreter.java
deleted file mode 100644
index 3e4da19..0000000
--- a/spark/src/main/java/org/apache/zeppelin/spark/SparkInterpreter.java
+++ /dev/null
@@ -1,1525 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.zeppelin.spark;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.PrintWriter;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.Field;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.net.URL;
-import java.net.URLClassLoader;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.Properties;
-import java.util.Set;
-import java.util.concurrent.atomic.AtomicInteger;
-
-import org.apache.commons.lang3.StringUtils;
-import org.apache.hadoop.security.UserGroupInformation;
-import org.apache.spark.SecurityManager;
-import org.apache.spark.SparkConf;
-import org.apache.spark.SparkContext;
-import org.apache.spark.SparkEnv;
-import org.apache.spark.api.java.JavaSparkContext;
-import org.apache.spark.repl.SparkILoop;
-import org.apache.spark.scheduler.ActiveJob;
-import org.apache.spark.scheduler.DAGScheduler;
-import org.apache.spark.scheduler.Pool;
-import org.apache.spark.scheduler.SparkListenerJobStart;
-import org.apache.spark.sql.SQLContext;
-import org.apache.spark.ui.SparkUI;
-import org.apache.spark.ui.jobs.JobProgressListener;
-import org.apache.zeppelin.interpreter.BaseZeppelinContext;
-import org.apache.zeppelin.interpreter.Interpreter;
-import org.apache.zeppelin.interpreter.InterpreterContext;
-import org.apache.zeppelin.interpreter.InterpreterException;
-import org.apache.zeppelin.interpreter.InterpreterHookRegistry;
-import org.apache.zeppelin.interpreter.InterpreterResult;
-import org.apache.zeppelin.interpreter.InterpreterResult.Code;
-import org.apache.zeppelin.interpreter.InterpreterUtils;
-import org.apache.zeppelin.interpreter.WrappedInterpreter;
-import org.apache.zeppelin.interpreter.remote.RemoteEventClientWrapper;
-import org.apache.zeppelin.interpreter.thrift.InterpreterCompletion;
-import org.apache.zeppelin.interpreter.util.InterpreterOutputStream;
-import org.apache.zeppelin.resource.ResourcePool;
-import org.apache.zeppelin.resource.WellKnownResourceName;
-import org.apache.zeppelin.scheduler.Scheduler;
-import org.apache.zeppelin.scheduler.SchedulerFactory;
-import org.apache.zeppelin.spark.dep.SparkDependencyContext;
-import org.apache.zeppelin.spark.dep.SparkDependencyResolver;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import scala.Console;
-import scala.Enumeration.Value;
-import scala.None;
-import scala.Option;
-import scala.Some;
-import scala.Tuple2;
-import scala.collection.Iterator;
-import scala.collection.JavaConversions;
-import scala.collection.JavaConverters;
-import scala.collection.Seq;
-import scala.collection.convert.WrapAsJava$;
-import scala.collection.mutable.HashMap;
-import scala.collection.mutable.HashSet;
-import scala.reflect.io.AbstractFile;
-import scala.tools.nsc.Global;
-import scala.tools.nsc.Settings;
-import scala.tools.nsc.interpreter.Completion.Candidates;
-import scala.tools.nsc.interpreter.Completion.ScalaCompleter;
-import scala.tools.nsc.interpreter.IMain;
-import scala.tools.nsc.interpreter.Results;
-import scala.tools.nsc.settings.MutableSettings;
-import scala.tools.nsc.settings.MutableSettings.BooleanSetting;
-import scala.tools.nsc.settings.MutableSettings.PathSetting;
-
-/**
- * Spark interpreter for Zeppelin.
- *
- */
-public class SparkInterpreter extends Interpreter {
-  public static Logger logger = LoggerFactory.getLogger(SparkInterpreter.class);
-
-  private SparkZeppelinContext z;
-  private SparkILoop interpreter;
-  /**
-   * intp - org.apache.spark.repl.SparkIMain (scala 2.10)
-   * intp - scala.tools.nsc.interpreter.IMain; (scala 2.11)
-   */
-  private Object intp;
-  private SparkConf conf;
-  private static SparkContext sc;
-  private static SQLContext sqlc;
-  private static InterpreterHookRegistry hooks;
-  private static SparkEnv env;
-  private static Object sparkSession;    // spark 2.x
-  private static JobProgressListener sparkListener;
-  private static AbstractFile classOutputDir;
-  private static Integer sharedInterpreterLock = new Integer(0);
-  private static AtomicInteger numReferenceOfSparkContext = new AtomicInteger(0);
-
-  private InterpreterOutputStream out;
-  private SparkDependencyResolver dep;
-  private static String sparkUrl;
-
-  /**
-   * completer - org.apache.spark.repl.SparkJLineCompletion (scala 2.10)
-   */
-  private Object completer = null;
-
-  private Map<String, Object> binder;
-  private SparkVersion sparkVersion;
-  private static File outputDir;          // class outputdir for scala 2.11
-  private Object classServer;      // classserver for scala 2.11
-  private JavaSparkContext jsc;
-  private boolean enableSupportedVersionCheck;
-
-  public SparkInterpreter(Properties property) {
-    super(property);
-    out = new InterpreterOutputStream(logger);
-  }
-
-  public SparkInterpreter(Properties property, SparkContext sc) {
-    this(property);
-
-    this.sc = sc;
-    env = SparkEnv.get();
-    sparkListener = setupListeners(this.sc);
-  }
-
-  public SparkContext getSparkContext() {
-    synchronized (sharedInterpreterLock) {
-      if (sc == null) {
-        sc = createSparkContext();
-        env = SparkEnv.get();
-        sparkListener = setupListeners(sc);
-      }
-      return sc;
-    }
-  }
-
-  public JavaSparkContext getJavaSparkContext() {
-    synchronized (sharedInterpreterLock) {
-      if (jsc == null) {
-        jsc = JavaSparkContext.fromSparkContext(sc);
-      }
-      return jsc;
-    }
-  }
-
-  public boolean isSparkContextInitialized() {
-    synchronized (sharedInterpreterLock) {
-      return sc != null;
-    }
-  }
-
-  static JobProgressListener setupListeners(SparkContext context) {
-    JobProgressListener pl = new JobProgressListener(context.getConf()) {
-      @Override
-      public synchronized void onJobStart(SparkListenerJobStart jobStart) {
-        super.onJobStart(jobStart);
-        int jobId = jobStart.jobId();
-        String jobGroupId = jobStart.properties().getProperty("spark.jobGroup.id");
-        String uiEnabled = jobStart.properties().getProperty("spark.ui.enabled");
-        String jobUrl = getJobUrl(jobId);
-        String noteId = Utils.getNoteId(jobGroupId);
-        String paragraphId = Utils.getParagraphId(jobGroupId);
-        // Button visible if Spark UI property not set, set as invalid boolean or true
-        java.lang.Boolean showSparkUI =
-                uiEnabled == null || !uiEnabled.trim().toLowerCase().equals("false");
-        if (showSparkUI && jobUrl != null) {
-          RemoteEventClientWrapper eventClient = BaseZeppelinContext.getEventClient();
-          Map<String, String> infos = new java.util.HashMap<>();
-          infos.put("jobUrl", jobUrl);
-          infos.put("label", "SPARK JOB");
-          infos.put("tooltip", "View in Spark web UI");
-          if (eventClient != null) {
-            eventClient.onParaInfosReceived(noteId, paragraphId, infos);
-          }
-        }
-      }
-
-      private String getJobUrl(int jobId) {
-        String jobUrl = null;
-        if (sparkUrl != null) {
-          jobUrl = sparkUrl + "/jobs/job/?id=" + jobId;
-        }
-        return jobUrl;
-      }
-
-    };
-    try {
-      Object listenerBus = context.getClass().getMethod("listenerBus").invoke(context);
-
-      Method[] methods = listenerBus.getClass().getMethods();
-      Method addListenerMethod = null;
-      for (Method m : methods) {
-        if (!m.getName().equals("addListener")) {
-          continue;
-        }
-
-        Class<?>[] parameterTypes = m.getParameterTypes();
-
-        if (parameterTypes.length != 1) {
-          continue;
-        }
-
-        if (!parameterTypes[0].isAssignableFrom(JobProgressListener.class)) {
-          continue;
-        }
-
-        addListenerMethod = m;
-        break;
-      }
-
-      if (addListenerMethod != null) {
-        addListenerMethod.invoke(listenerBus, pl);
-      } else {
-        return null;
-      }
-    } catch (NoSuchMethodException | SecurityException | IllegalAccessException
-        | IllegalArgumentException | InvocationTargetException e) {
-      logger.error(e.toString(), e);
-      return null;
-    }
-    return pl;
-  }
-
-  private boolean useHiveContext() {
-    return java.lang.Boolean.parseBoolean(getProperty("zeppelin.spark.useHiveContext"));
-  }
-
-  /**
-   * See org.apache.spark.sql.SparkSession.hiveClassesArePresent
-   * @return
-   */
-  private boolean hiveClassesArePresent() {
-    try {
-      this.getClass().forName("org.apache.spark.sql.hive.execution.InsertIntoHiveTable");
-      this.getClass().forName("org.apache.hadoop.hive.conf.HiveConf");
-      return true;
-    } catch (ClassNotFoundException | NoClassDefFoundError e) {
-      return false;
-    }
-  }
-
-  private boolean importImplicit() {
-    return java.lang.Boolean.parseBoolean(getProperty("zeppelin.spark.importImplicit"));
-  }
-
-  public Object getSparkSession() {
-    synchronized (sharedInterpreterLock) {
-      if (sparkSession == null) {
-        createSparkSession();
-      }
-      return sparkSession;
-    }
-  }
-
-  public SQLContext getSQLContext() {
-    synchronized (sharedInterpreterLock) {
-      if (Utils.isSpark2()) {
-        return getSQLContext_2();
-      } else {
-        return getSQLContext_1();
-      }
-    }
-  }
-
-  /**
-   * Get SQLContext for spark 2.x
-   */
-  private SQLContext getSQLContext_2() {
-    if (sqlc == null) {
-      sqlc = (SQLContext) Utils.invokeMethod(sparkSession, "sqlContext");
-    }
-    return sqlc;
-  }
-
-  public SQLContext getSQLContext_1() {
-    if (sqlc == null) {
-      if (useHiveContext()) {
-        String name = "org.apache.spark.sql.hive.HiveContext";
-        Constructor<?> hc;
-        try {
-          hc = getClass().getClassLoader().loadClass(name)
-              .getConstructor(SparkContext.class);
-          sqlc = (SQLContext) hc.newInstance(getSparkContext());
-        } catch (NoSuchMethodException | SecurityException
-            | ClassNotFoundException | InstantiationException
-            | IllegalAccessException | IllegalArgumentException
-            | InvocationTargetException e) {
-          logger.warn("Can't create HiveContext. Fallback to SQLContext", e);
-          // when hive dependency is not loaded, it'll fail.
-          // in this case SQLContext can be used.
-          sqlc = new SQLContext(getSparkContext());
-        }
-      } else {
-        sqlc = new SQLContext(getSparkContext());
-      }
-    }
-    return sqlc;
-  }
-
-
-  public SparkDependencyResolver getDependencyResolver() {
-    if (dep == null) {
-      dep = new SparkDependencyResolver(
-          (Global) Utils.invokeMethod(intp, "global"),
-          (ClassLoader) Utils.invokeMethod(Utils.invokeMethod(intp, "classLoader"), "getParent"),
-          sc,
-          getProperty("zeppelin.dep.localrepo"),
-          getProperty("zeppelin.dep.additionalRemoteRepository"));
-    }
-    return dep;
-  }
-
-  private DepInterpreter getDepInterpreter() {
-    Interpreter p = getInterpreterInTheSameSessionByClassName(DepInterpreter.class.getName());
-    if (p == null) {
-      return null;
-    }
-
-    while (p instanceof WrappedInterpreter) {
-      p = ((WrappedInterpreter) p).getInnerInterpreter();
-    }
-    return (DepInterpreter) p;
-  }
-
-  public boolean isYarnMode() {
-    String master = getProperty("master");
-    if (master == null) {
-      master = getProperty("spark.master", "local[*]");
-    }
-    return master.startsWith("yarn");
-  }
-
-  /**
-   * Spark 2.x
-   * Create SparkSession
-   */
-  public Object createSparkSession() {
-    // use local mode for embedded spark mode when spark.master is not found
-    conf.setIfMissing("spark.master", "local");
-    logger.info("------ Create new SparkSession {} -------", conf.get("spark.master"));
-    String execUri = System.getenv("SPARK_EXECUTOR_URI");
-    if (outputDir != null) {
-      conf.set("spark.repl.class.outputDir", outputDir.getAbsolutePath());
-    }
-
-    if (execUri != null) {
-      conf.set("spark.executor.uri", execUri);
-    }
-    conf.set("spark.scheduler.mode", "FAIR");
-
-    Properties intpProperty = getProperties();
-    for (Object k : intpProperty.keySet()) {
-      String key = (String) k;
-      String val = toString(intpProperty.get(key));
-      if (!val.trim().isEmpty()) {
-        if (key.startsWith("spark.")) {
-          logger.debug(String.format("SparkConf: key = [%s], value = [%s]", key, val));
-          conf.set(key, val);
-        }
-        if (key.startsWith("zeppelin.spark.")) {
-          String sparkPropertyKey = key.substring("zeppelin.spark.".length());
-          logger.debug(String.format("SparkConf: key = [%s], value = [%s]", sparkPropertyKey, val));
-          conf.set(sparkPropertyKey, val);
-        }
-      }
-    }
-
-    Class SparkSession = Utils.findClass("org.apache.spark.sql.SparkSession");
-    Object builder = Utils.invokeStaticMethod(SparkSession, "builder");
-    Utils.invokeMethod(builder, "config", new Class[]{ SparkConf.class }, new Object[]{ conf });
-
-    if (useHiveContext()) {
-      if (hiveClassesArePresent()) {
-        Utils.invokeMethod(builder, "enableHiveSupport");
-        sparkSession = Utils.invokeMethod(builder, "getOrCreate");
-        logger.info("Created Spark session with Hive support");
-      } else {
-        Utils.invokeMethod(builder, "config",
-            new Class[]{ String.class, String.class},
-            new Object[]{ "spark.sql.catalogImplementation", "in-memory"});
-        sparkSession = Utils.invokeMethod(builder, "getOrCreate");
-        logger.info("Created Spark session with Hive support use in-memory catalogImplementation");
-      }
-    } else {
-      sparkSession = Utils.invokeMethod(builder, "getOrCreate");
-      logger.info("Created Spark session");
-    }
-
-    return sparkSession;
-  }
-
-  public SparkContext createSparkContext() {
-    if (Utils.isSpark2()) {
-      return createSparkContext_2();
-    } else {
-      return createSparkContext_1();
-    }
-  }
-
-  /**
-   * Create SparkContext for spark 2.x
-   * @return
-   */
-  private SparkContext createSparkContext_2() {
-    return (SparkContext) Utils.invokeMethod(sparkSession, "sparkContext");
-  }
-
-  public SparkContext createSparkContext_1() {
-    // use local mode for embedded spark mode when spark.master is not found
-    if (!conf.contains("spark.master")) {
-      conf.setMaster("local");
-    }
-    logger.info("------ Create new SparkContext {} -------", conf.get("spark.master"));
-
-    String execUri = System.getenv("SPARK_EXECUTOR_URI");
-    String[] jars = null;
-
-    if (Utils.isScala2_10()) {
-      jars = (String[]) Utils.invokeStaticMethod(SparkILoop.class, "getAddedJars");
-    } else {
-      jars = (String[]) Utils.invokeStaticMethod(
-              Utils.findClass("org.apache.spark.repl.Main"), "getAddedJars");
-    }
-
-    String classServerUri = null;
-    String replClassOutputDirectory = null;
-
-    try { // in case of spark 1.1x, spark 1.2x
-      Method classServer = intp.getClass().getMethod("classServer");
-      Object httpServer = classServer.invoke(intp);
-      classServerUri = (String) Utils.invokeMethod(httpServer, "uri");
-    } catch (NoSuchMethodException | SecurityException | IllegalAccessException
-        | IllegalArgumentException | InvocationTargetException e) {
-      // continue
-    }
-
-    if (classServerUri == null) {
-      try { // for spark 1.3x
-        Method classServer = intp.getClass().getMethod("classServerUri");
-        classServerUri = (String) classServer.invoke(intp);
-      } catch (NoSuchMethodException | SecurityException | IllegalAccessException
-          | 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]",
-          e.getMessage()));
-      }
-    }
-
-    if (classServerUri == null) {
-      try { // for RcpEnv
-        Method getClassOutputDirectory = intp.getClass().getMethod("getClassOutputDirectory");
-        File classOutputDirectory = (File) getClassOutputDirectory.invoke(intp);
-        replClassOutputDirectory = classOutputDirectory.getAbsolutePath();
-      } catch (NoSuchMethodException | SecurityException | IllegalAccessException
-              | IllegalArgumentException | InvocationTargetException e) {
-        // continue
-      }
-    }
-
-    if (Utils.isScala2_11()) {
-      classServer = createHttpServer(outputDir);
-      Utils.invokeMethod(classServer, "start");
-      classServerUri = (String) Utils.invokeMethod(classServer, "uri");
-    }
-
-    if (classServerUri != null) {
-      conf.set("spark.repl.class.uri", classServerUri);
-    }
-
-    if (replClassOutputDirectory != null) {
-      conf.set("spark.repl.class.outputDir", replClassOutputDirectory);
-    }
-
-    if (jars.length > 0) {
-      conf.setJars(jars);
-    }
-
-    if (execUri != null) {
-      conf.set("spark.executor.uri", execUri);
-    }
-    conf.set("spark.scheduler.mode", "FAIR");
-
-    Properties intpProperty = getProperties();
-    for (Object k : intpProperty.keySet()) {
-      String key = (String) k;
-      String val = toString(intpProperty.get(key));
-      if (!val.trim().isEmpty()) {
-        if (key.startsWith("spark.")) {
-          logger.debug(String.format("SparkConf: key = [%s], value = [%s]", key, val));
-          conf.set(key, val);
-        }
-
-        if (key.startsWith("zeppelin.spark.")) {
-          String sparkPropertyKey = key.substring("zeppelin.spark.".length());
-          logger.debug(String.format("SparkConf: key = [%s], value = [%s]", sparkPropertyKey, val));
-          conf.set(sparkPropertyKey, val);
-        }
-      }
-    }
-    SparkContext sparkContext = new SparkContext(conf);
-    return sparkContext;
-  }
-
-  static final String toString(Object o) {
-    return (o instanceof String) ? (String) o : "";
-  }
-
-  public static boolean useSparkSubmit() {
-    return null != System.getenv("SPARK_SUBMIT");
-  }
-
-  public boolean printREPLOutput() {
-    return java.lang.Boolean.parseBoolean(getProperty("zeppelin.spark.printREPLOutput"));
-  }
-
-  @Override
-  public void open() throws InterpreterException {
-    this.enableSupportedVersionCheck = java.lang.Boolean.parseBoolean(
-        getProperty("zeppelin.spark.enableSupportedVersionCheck", "true"));
-
-    // set properties and do login before creating any spark stuff for secured cluster
-    if (isYarnMode()) {
-      System.setProperty("SPARK_YARN_MODE", "true");
-    }
-    if (getProperties().containsKey("spark.yarn.keytab") &&
-            getProperties().containsKey("spark.yarn.principal")) {
-      try {
-        String keytab = getProperties().getProperty("spark.yarn.keytab");
-        String principal = getProperties().getProperty("spark.yarn.principal");
-        UserGroupInformation.loginUserFromKeytab(principal, keytab);
-      } catch (IOException e) {
-        throw new RuntimeException("Can not pass kerberos authentication", e);
-      }
-    }
-
-    conf = new SparkConf();
-    URL[] urls = getClassloaderUrls();
-
-    // Very nice discussion about how scala compiler handle classpath
-    // https://groups.google.com/forum/#!topic/scala-user/MlVwo2xCCI0
-
-    /*
-     * > val env = new nsc.Settings(errLogger) > env.usejavacp.value = true > val p = new
-     * Interpreter(env) > p.setContextClassLoader > Alternatively you can set the class path through
-     * nsc.Settings.classpath.
-     *
-     * >> val settings = new Settings() >> settings.usejavacp.value = true >>
-     * settings.classpath.value += File.pathSeparator + >> System.getProperty("java.class.path") >>
-     * val in = new Interpreter(settings) { >> override protected def parentClassLoader =
-     * getClass.getClassLoader >> } >> in.setContextClassLoader()
-     */
-    Settings settings = new Settings();
-
-    // process args
-    String args = getProperty("args");
-    if (args == null) {
-      args = "";
-    }
-
-    String[] argsArray = args.split(" ");
-    LinkedList<String> argList = new LinkedList<>();
-    for (String arg : argsArray) {
-      argList.add(arg);
-    }
-
-    DepInterpreter depInterpreter = getDepInterpreter();
-    String depInterpreterClasspath = "";
-    if (depInterpreter != null) {
-      SparkDependencyContext depc = depInterpreter.getDependencyContext();
-      if (depc != null) {
-        List<File> files = depc.getFiles();
-        if (files != null) {
-          for (File f : files) {
-            if (depInterpreterClasspath.length() > 0) {
-              depInterpreterClasspath += File.pathSeparator;
-            }
-            depInterpreterClasspath += f.getAbsolutePath();
-          }
-        }
-      }
-    }
-
-
-    if (Utils.isScala2_10()) {
-      scala.collection.immutable.List<String> list =
-          JavaConversions.asScalaBuffer(argList).toList();
-
-      Object sparkCommandLine = Utils.instantiateClass(
-          "org.apache.spark.repl.SparkCommandLine",
-          new Class[]{ scala.collection.immutable.List.class },
-          new Object[]{ list });
-
-      settings = (Settings) Utils.invokeMethod(sparkCommandLine, "settings");
-    } else {
-      String sparkReplClassDir = getProperty("spark.repl.classdir");
-      if (sparkReplClassDir == null) {
-        sparkReplClassDir = System.getProperty("spark.repl.classdir");
-      }
-      if (sparkReplClassDir == null) {
-        sparkReplClassDir = System.getProperty("java.io.tmpdir");
-      }
-
-      synchronized (sharedInterpreterLock) {
-        if (outputDir == null) {
-          outputDir = createTempDir(sparkReplClassDir);
-        }
-      }
-      argList.add("-Yrepl-class-based");
-      argList.add("-Yrepl-outdir");
-      argList.add(outputDir.getAbsolutePath());
-
-      String classpath = "";
-      if (conf.contains("spark.jars")) {
-        classpath = StringUtils.join(conf.get("spark.jars").split(","), File.separator);
-      }
-
-      if (!depInterpreterClasspath.isEmpty()) {
-        if (!classpath.isEmpty()) {
-          classpath += File.separator;
-        }
-        classpath += depInterpreterClasspath;
-      }
-
-      if (!classpath.isEmpty()) {
-        argList.add("-classpath");
-        argList.add(classpath);
-      }
-
-      scala.collection.immutable.List<String> list =
-          JavaConversions.asScalaBuffer(argList).toList();
-
-      settings.processArguments(list, true);
-    }
-
-    // set classpath for scala compiler
-    PathSetting pathSettings = settings.classpath();
-    String classpath = "";
-
-    List<File> paths = currentClassPath();
-    for (File f : paths) {
-      if (classpath.length() > 0) {
-        classpath += File.pathSeparator;
-      }
-      classpath += f.getAbsolutePath();
-    }
-
-    if (urls != null) {
-      for (URL u : urls) {
-        if (classpath.length() > 0) {
-          classpath += File.pathSeparator;
-        }
-        classpath += u.getFile();
-      }
-    }
-
-    // add dependency from DepInterpreter
-    if (classpath.length() > 0) {
-      classpath += File.pathSeparator;
-    }
-    classpath += depInterpreterClasspath;
-
-    // add dependency from local repo
-    String localRepo = getProperty("zeppelin.interpreter.localRepo");
-    if (localRepo != null) {
-      File localRepoDir = new File(localRepo);
-      if (localRepoDir.exists()) {
-        File[] files = localRepoDir.listFiles();
-        if (files != null) {
-          for (File f : files) {
-            if (classpath.length() > 0) {
-              classpath += File.pathSeparator;
-            }
-            classpath += f.getAbsolutePath();
-          }
-        }
-      }
-    }
-
-    pathSettings.v_$eq(classpath);
-    settings.scala$tools$nsc$settings$ScalaSettings$_setter_$classpath_$eq(pathSettings);
-
-    // set classloader for scala compiler
-    settings.explicitParentLoader_$eq(new Some<>(Thread.currentThread()
-        .getContextClassLoader()));
-    BooleanSetting b = (BooleanSetting) settings.usejavacp();
-    b.v_$eq(true);
-    settings.scala$tools$nsc$settings$StandardScalaSettings$_setter_$usejavacp_$eq(b);
-
-    /* Required for scoped mode.
-     * In scoped mode multiple scala compiler (repl) generates class in the same directory.
-     * Class names is not randomly generated and look like '$line12.$read$$iw$$iw'
-     * Therefore it's possible to generated class conflict(overwrite) with other repl generated
-     * class.
-     *
-     * To prevent generated class name conflict,
-     * change prefix of generated class name from each scala compiler (repl) instance.
-     *
-     * In Spark 2.x, REPL generated wrapper class name should compatible with the pattern
-     * ^(\$line(?:\d+)\.\$read)(?:\$\$iw)+$
-     *
-     * As hashCode() can return a negative integer value and the minus character '-' is invalid
-     * in a package name we change it to a numeric value '0' which still conforms to the regexp.
-     * 
-     */
-    System.setProperty("scala.repl.name.line", ("$line" + this.hashCode()).replace('-', '0'));
-
-    // To prevent 'File name too long' error on some file system.
-    MutableSettings.IntSetting numClassFileSetting = settings.maxClassfileName();
-    numClassFileSetting.v_$eq(128);
-    settings.scala$tools$nsc$settings$ScalaSettings$_setter_$maxClassfileName_$eq(
-        numClassFileSetting);
-
-    synchronized (sharedInterpreterLock) {
-      /* create scala repl */
-      if (printREPLOutput()) {
-        this.interpreter = new SparkILoop((java.io.BufferedReader) null, new PrintWriter(out));
-      } else {
-        this.interpreter = new SparkILoop((java.io.BufferedReader) null,
-            new PrintWriter(Console.out(), false));
-      }
-
-      interpreter.settings_$eq(settings);
-
-      interpreter.createInterpreter();
-
-      intp = Utils.invokeMethod(interpreter, "intp");
-      Utils.invokeMethod(intp, "setContextClassLoader");
-      Utils.invokeMethod(intp, "initializeSynchronous");
-
-      if (Utils.isScala2_10()) {
-        if (classOutputDir == null) {
-          classOutputDir = settings.outputDirs().getSingleOutput().get();
-        } else {
-          // change SparkIMain class output dir
-          settings.outputDirs().setSingleOutput(classOutputDir);
-          ClassLoader cl = (ClassLoader) Utils.invokeMethod(intp, "classLoader");
-          try {
-            Field rootField = cl.getClass().getSuperclass().getDeclaredField("root");
-            rootField.setAccessible(true);
-            rootField.set(cl, classOutputDir);
-          } catch (NoSuchFieldException | IllegalAccessException e) {
-            logger.error(e.getMessage(), e);
-          }
-        }
-      }
-
-      if (Utils.findClass("org.apache.spark.repl.SparkJLineCompletion", true) != null) {
-        completer = Utils.instantiateClass(
-            "org.apache.spark.repl.SparkJLineCompletion",
-            new Class[]{Utils.findClass("org.apache.spark.repl.SparkIMain")},
-            new Object[]{intp});
-      } else if (Utils.findClass(
-          "scala.tools.nsc.interpreter.PresentationCompilerCompleter", true) != null) {
-        completer = Utils.instantiateClass(
-            "scala.tools.nsc.interpreter.PresentationCompilerCompleter",
-            new Class[]{ IMain.class },
-            new Object[]{ intp });
-      } else if (Utils.findClass(
-          "scala.tools.nsc.interpreter.JLineCompletion", true) != null) {
-        completer = Utils.instantiateClass(
-            "scala.tools.nsc.interpreter.JLineCompletion",
-            new Class[]{ IMain.class },
-            new Object[]{ intp });
-      }
-
-      if (Utils.isSpark2()) {
-        sparkSession = getSparkSession();
-      }
-      sc = getSparkContext();
-      if (sc.getPoolForName("fair").isEmpty()) {
-        Value schedulingMode = org.apache.spark.scheduler.SchedulingMode.FAIR();
-        int minimumShare = 0;
-        int weight = 1;
-        Pool pool = new Pool("fair", schedulingMode, minimumShare, weight);
-        sc.taskScheduler().rootPool().addSchedulable(pool);
-      }
-
-      sparkVersion = SparkVersion.fromVersionString(sc.version());
-
-      sqlc = getSQLContext();
-
-      dep = getDependencyResolver();
-      
-      hooks = getInterpreterGroup().getInterpreterHookRegistry();
-
-      z = new SparkZeppelinContext(sc, sqlc, hooks,
-              Integer.parseInt(getProperty("zeppelin.spark.maxResult")));
-
-      interpret("@transient val _binder = new java.util.HashMap[String, Object]()");
-      Map<String, Object> binder;
-      if (Utils.isScala2_10()) {
-        binder = (Map<String, Object>) getValue("_binder");
-      } else {
-        binder = (Map<String, Object>) getLastObject();
-      }
-      binder.put("sc", sc);
-      binder.put("sqlc", sqlc);
-      binder.put("z", z);
-
-      if (Utils.isSpark2()) {
-        binder.put("spark", sparkSession);
-      }
-
-      interpret("@transient val z = "
-              + "_binder.get(\"z\").asInstanceOf[org.apache.zeppelin.spark.SparkZeppelinContext]");
-      interpret("@transient val sc = "
-              + "_binder.get(\"sc\").asInstanceOf[org.apache.spark.SparkContext]");
-      interpret("@transient val sqlc = "
-              + "_binder.get(\"sqlc\").asInstanceOf[org.apache.spark.sql.SQLContext]");
-      interpret("@transient val sqlContext = "
-              + "_binder.get(\"sqlc\").asInstanceOf[org.apache.spark.sql.SQLContext]");
-
-      if (Utils.isSpark2()) {
-        interpret("@transient val spark = "
-            + "_binder.get(\"spark\").asInstanceOf[org.apache.spark.sql.SparkSession]");
-      }
-
-      interpret("import org.apache.spark.SparkContext._");
-
-      if (importImplicit()) {
-        if (Utils.isSpark2()) {
-          interpret("import spark.implicits._");
-          interpret("import spark.sql");
-          interpret("import org.apache.spark.sql.functions._");
-        } else {
-          if (sparkVersion.oldSqlContextImplicits()) {
-            interpret("import sqlContext._");
-          } else {
-            interpret("import sqlContext.implicits._");
-            interpret("import sqlContext.sql");
-            interpret("import org.apache.spark.sql.functions._");
-          }
-        }
-      }
-    }
-
-    /* Temporary disabling DisplayUtils. see https://issues.apache.org/jira/browse/ZEPPELIN-127
-     *
-    // Utility functions for display
-    intp.interpret("import org.apache.zeppelin.spark.utils.DisplayUtils._");
-
-    // Scala implicit value for spark.maxResult
-    intp.interpret("import org.apache.zeppelin.spark.utils.SparkMaxResult");
-    intp.interpret("implicit val sparkMaxResult = new SparkMaxResult(" +
-            Integer.parseInt(getProperty("zeppelin.spark.maxResult")) + ")");
-     */
-
-    if (Utils.isScala2_10()) {
-      try {
-        if (sparkVersion.oldLoadFilesMethodName()) {
-          Method loadFiles = this.interpreter.getClass().getMethod("loadFiles", Settings.class);
-          loadFiles.invoke(this.interpreter, settings);
-        } else {
-          Method loadFiles = this.interpreter.getClass().getMethod(
-              "org$apache$spark$repl$SparkILoop$$loadFiles", Settings.class);
-          loadFiles.invoke(this.interpreter, settings);
-        }
-      } catch (NoSuchMethodException | SecurityException | IllegalAccessException
-          | IllegalArgumentException | InvocationTargetException e) {
-        throw new InterpreterException(e);
-      }
-    }
-
-    // add jar from DepInterpreter
-    if (depInterpreter != null) {
-      SparkDependencyContext depc = depInterpreter.getDependencyContext();
-      if (depc != null) {
-        List<File> files = depc.getFilesDist();
-        if (files != null) {
-          for (File f : files) {
-            if (f.getName().toLowerCase().endsWith(".jar")) {
-              sc.addJar(f.getAbsolutePath());
-              logger.info("sc.addJar(" + f.getAbsolutePath() + ")");
-            } else {
-              sc.addFile(f.getAbsolutePath());
-              logger.info("sc.addFile(" + f.getAbsolutePath() + ")");
-            }
-          }
-        }
-      }
-    }
-
-    // add jar from local repo
-    if (localRepo != null) {
-      File localRepoDir = new File(localRepo);
-      if (localRepoDir.exists()) {
-        File[] files = localRepoDir.listFiles();
-        if (files != null) {
-          for (File f : files) {
-            if (f.getName().toLowerCase().endsWith(".jar")) {
-              sc.addJar(f.getAbsolutePath());
-              logger.info("sc.addJar(" + f.getAbsolutePath() + ")");
-            } else {
-              sc.addFile(f.getAbsolutePath());
-              logger.info("sc.addFile(" + f.getAbsolutePath() + ")");
-            }
-          }
-        }
-      }
-    }
-
-    numReferenceOfSparkContext.incrementAndGet();
-  }
-
-  public String getSparkUIUrl() {
-    if (sparkUrl != null) {
-      return sparkUrl;
-    }
-
-    String sparkUrlProp = getProperty("zeppelin.spark.uiWebUrl", "");
-    if (!StringUtils.isBlank(sparkUrlProp)) {
-      return sparkUrlProp;
-    }
-
-    if (sparkVersion.newerThanEquals(SparkVersion.SPARK_2_0_0)) {
-      Option<String> uiWebUrlOption = (Option<String>) Utils.invokeMethod(sc, "uiWebUrl");
-      if (uiWebUrlOption.isDefined()) {
-        return uiWebUrlOption.get();
-      }
-    } else {
-      Option<SparkUI> sparkUIOption = (Option<SparkUI>) Utils.invokeMethod(sc, "ui");
-      if (sparkUIOption.isDefined()) {
-        return (String) Utils.invokeMethod(sparkUIOption.get(), "appUIAddress");
-      }
-    }
-    return null;
-  }
-
-  private Results.Result interpret(String line) {
-    out.ignoreLeadingNewLinesFromScalaReporter();
-    return (Results.Result) Utils.invokeMethod(
-        intp,
-        "interpret",
-        new Class[] {String.class},
-        new Object[] {line});
-  }
-
-  public void populateSparkWebUrl(InterpreterContext ctx) {
-    sparkUrl = getSparkUIUrl();
-    Map<String, String> infos = new java.util.HashMap<>();
-    infos.put("url", sparkUrl);
-    String uiEnabledProp = getProperty("spark.ui.enabled", "true");
-    java.lang.Boolean uiEnabled = java.lang.Boolean.parseBoolean(
-            uiEnabledProp.trim());
-    if (!uiEnabled) {
-      infos.put("message", "Spark UI disabled");
-    } else {
-      if (StringUtils.isNotBlank(sparkUrl)) {
-        infos.put("message", "Spark UI enabled");
-      } else {
-        infos.put("message", "No spark url defined");
-      }
-    }
-    if (ctx != null && ctx.getClient() != null) {
-      logger.info("Sending metadata to Zeppelin server: {}", infos.toString());
-      getZeppelinContext().setEventClient(ctx.getClient());
-      ctx.getClient().onMetaInfosReceived(infos);
-    }
-  }
-
-  private List<File> currentClassPath() {
-    List<File> paths = classPath(Thread.currentThread().getContextClassLoader());
-    String[] cps = System.getProperty("java.class.path").split(File.pathSeparator);
-    if (cps != null) {
-      for (String cp : cps) {
-        paths.add(new File(cp));
-      }
-    }
-    return paths;
-  }
-
-  private List<File> classPath(ClassLoader cl) {
-    List<File> paths = new LinkedList<>();
-    if (cl == null) {
-      return paths;
-    }
-
-    if (cl instanceof URLClassLoader) {
-      URLClassLoader ucl = (URLClassLoader) cl;
-      URL[] urls = ucl.getURLs();
-      if (urls != null) {
-        for (URL url : urls) {
-          paths.add(new File(url.getFile()));
-        }
-      }
-    }
-    return paths;
-  }
-
-  @Override
-  public List<InterpreterCompletion> completion(String buf, int cursor,
-      InterpreterContext interpreterContext) {
-    if (completer == null) {
-      logger.warn("Can't find completer");
-      return new LinkedList<>();
-    }
-
-    if (buf.length() < cursor) {
-      cursor = buf.length();
-    }
-
-    ScalaCompleter c = (ScalaCompleter) Utils.invokeMethod(completer, "completer");
-    
-    if (Utils.isScala2_10() || !Utils.isCompilerAboveScala2_11_7()) {
-      String singleToken = getCompletionTargetString(buf, cursor);
-      Candidates ret = c.complete(singleToken, singleToken.length());
-      
-      List<String> candidates = WrapAsJava$.MODULE$.seqAsJavaList(ret.candidates());
-      List<InterpreterCompletion> completions = new LinkedList<>();
-  
-      for (String candidate : candidates) {
-        completions.add(new InterpreterCompletion(candidate, candidate, StringUtils.EMPTY));
-      }
-  
-      return completions;
-    } else {
-      Candidates ret = c.complete(buf, cursor);
-  
-      List<String> candidates = WrapAsJava$.MODULE$.seqAsJavaList(ret.candidates());
-      List<InterpreterCompletion> completions = new LinkedList<>();
-  
-      for (String candidate : candidates) {
-        completions.add(new InterpreterCompletion(candidate, candidate, StringUtils.EMPTY));
-      }
-  
-      return completions;
-    }
-  }
-
-  private String getCompletionTargetString(String text, int cursor) {
-    String[] completionSeqCharaters = {" ", "\n", "\t"};
-    int completionEndPosition = cursor;
-    int completionStartPosition = cursor;
-    int indexOfReverseSeqPostion = cursor;
-
-    String resultCompletionText = "";
-    String completionScriptText = "";
-    try {
-      completionScriptText = text.substring(0, cursor);
-    }
-    catch (Exception e) {
-      logger.error(e.toString());
-      return null;
-    }
-    completionEndPosition = completionScriptText.length();
-
-    String tempReverseCompletionText = new StringBuilder(completionScriptText).reverse().toString();
-
-    for (String seqCharacter : completionSeqCharaters) {
-      indexOfReverseSeqPostion = tempReverseCompletionText.indexOf(seqCharacter);
-
-      if (indexOfReverseSeqPostion < completionStartPosition && indexOfReverseSeqPostion > 0) {
-        completionStartPosition = indexOfReverseSeqPostion;
-      }
-
-    }
-
-    if (completionStartPosition == completionEndPosition) {
-      completionStartPosition = 0;
-    }
-    else
-    {
-      completionStartPosition = completionEndPosition - completionStartPosition;
-    }
-    resultCompletionText = completionScriptText.substring(
-            completionStartPosition , completionEndPosition);
-
-    return resultCompletionText;
-  }
-
-  /*
-   * this method doesn't work in scala 2.11
-   * Somehow intp.valueOfTerm returns scala.None always with -Yrepl-class-based option
-   */
-  public Object getValue(String name) {
-    Object ret = Utils.invokeMethod(
-            intp, "valueOfTerm", new Class[]{String.class}, new Object[]{name});
-
-    if (ret instanceof None || ret instanceof scala.None$) {
-      return null;
-    } else if (ret instanceof Some) {
-      return ((Some) ret).get();
-    } else {
-      return ret;
-    }
-  }
-
-  public Object getLastObject() {
-    IMain.Request r = (IMain.Request) Utils.invokeMethod(intp, "lastRequest");
-    if (r == null || r.lineRep() == null) {
-      return null;
-    }
-    Object obj = r.lineRep().call("$result",
-        JavaConversions.asScalaBuffer(new LinkedList<>()));
-    return obj;
-  }
-
-  boolean isUnsupportedSparkVersion() {
-    return enableSupportedVersionCheck  && sparkVersion.isUnsupportedVersion();
-  }
-
-  /**
-   * Interpret a single line.
-   */
-  @Override
-  public InterpreterResult interpret(String line, InterpreterContext context) {
-    if (isUnsupportedSparkVersion()) {
-      return new InterpreterResult(Code.ERROR, "Spark " + sparkVersion.toString()
-          + " is not supported");
-    }
-    populateSparkWebUrl(context);
-    z.setInterpreterContext(context);
-    if (line == null || line.trim().length() == 0) {
-      return new InterpreterResult(Code.SUCCESS);
-    }
-    return interpret(line.split("\n"), context);
-  }
-
-  public InterpreterResult interpret(String[] lines, InterpreterContext context) {
-    synchronized (this) {
-      z.setGui(context.getGui());
-      z.setNoteGui(context.getNoteGui());
-      String jobDesc = "Started by: " + Utils.getUserName(context.getAuthenticationInfo());
-      sc.setJobGroup(Utils.buildJobGroupId(context), jobDesc, false);
-      InterpreterResult r = interpretInput(lines, context);
-      sc.clearJobGroup();
-      return r;
-    }
-  }
-
-  public InterpreterResult interpretInput(String[] lines, InterpreterContext context) {
-    SparkEnv.set(env);
-
-    String[] linesToRun = new String[lines.length];
-    for (int i = 0; i < lines.length; i++) {
-      linesToRun[i] = lines[i];
-    }
-
-    Console.setOut(context.out);
-    out.setInterpreterOutput(context.out);
-    context.out.clear();
-    Code r = null;
-    String incomplete = "";
-    boolean inComment = false;
-
-    for (int l = 0; l < linesToRun.length; l++) {
-      String s = linesToRun[l];
-      // check if next line starts with "." (but not ".." or "./") it is treated as an invocation
-      if (l + 1 < linesToRun.length) {
-        String nextLine = linesToRun[l + 1].trim();
-        boolean continuation = false;
-        if (nextLine.isEmpty()
-           || nextLine.startsWith("//")         // skip empty line or comment
-           || nextLine.startsWith("}")
-           || nextLine.startsWith("object")) {  // include "} object" for Scala companion object
-          continuation = true;
-        } else if (!inComment && nextLine.startsWith("/*")) {
-          inComment = true;
-          continuation = true;
-        } else if (inComment && nextLine.lastIndexOf("*/") >= 0) {
-          inComment = false;
-          continuation = true;
-        } else if (nextLine.length() > 1
-                && nextLine.charAt(0) == '.'
-                && nextLine.charAt(1) != '.'     // ".."
-                && nextLine.charAt(1) != '/') {  // "./"
-          continuation = true;
-        } else if (inComment) {
-          continuation = true;
-        }
-        if (continuation) {
-          incomplete += s + "\n";
-          continue;
-        }
-      }
-
-      scala.tools.nsc.interpreter.Results.Result res = null;
-      try {
-        res = interpret(incomplete + s);
-      } catch (Exception e) {
-        sc.clearJobGroup();
-        out.setInterpreterOutput(null);
-        logger.info("Interpreter exception", e);
-        return new InterpreterResult(Code.ERROR, InterpreterUtils.getMostRelevantMessage(e));
-      }
-
-      r = getResultCode(res);
-
-      if (r == Code.ERROR) {
-        sc.clearJobGroup();
-        out.setInterpreterOutput(null);
-        return new InterpreterResult(r, "");
-      } else if (r == Code.INCOMPLETE) {
-        incomplete += s + "\n";
-      } else {
-        incomplete = "";
-      }
-    }
-
-    // make sure code does not finish with comment
-    if (r == Code.INCOMPLETE) {
-      scala.tools.nsc.interpreter.Results.Result res = null;
-      res = interpret(incomplete + "\nprint(\"\")");
-      r = getResultCode(res);
-    }
-
-    if (r == Code.INCOMPLETE) {
-      sc.clearJobGroup();
-      out.setInterpreterOutput(null);
-      return new InterpreterResult(r, "Incomplete expression");
-    } else {
-      sc.clearJobGroup();
-      putLatestVarInResourcePool(context);
-      out.setInterpreterOutput(null);
-      return new InterpreterResult(Code.SUCCESS);
-    }
-  }
-
-  private void putLatestVarInResourcePool(InterpreterContext context) {
-    String varName = (String) Utils.invokeMethod(intp, "mostRecentVar");
-    if (varName == null || varName.isEmpty()) {
-      return;
-    }
-    Object lastObj = null;
-    try {
-      if (Utils.isScala2_10()) {
-        lastObj = getValue(varName);
-      } else {
-        lastObj = getLastObject();
-      }
-    } catch (NullPointerException e) {
-      // Some case, scala.tools.nsc.interpreter.IMain$ReadEvalPrint.call throws an NPE
-      logger.error(e.getMessage(), e);
-    }
-
-    if (lastObj != null) {
-      ResourcePool resourcePool = context.getResourcePool();
-      resourcePool.put(context.getNoteId(), context.getParagraphId(),
-          WellKnownResourceName.ZeppelinReplResult.toString(), lastObj);
-    }
-  };
-
-
-  @Override
-  public void cancel(InterpreterContext context) {
-    sc.cancelJobGroup(Utils.buildJobGroupId(context));
-  }
-
-  @Override
-  public int getProgress(InterpreterContext context) {
-    String jobGroup = Utils.buildJobGroupId(context);
-    int completedTasks = 0;
-    int totalTasks = 0;
-
-    DAGScheduler scheduler = sc.dagScheduler();
-    if (scheduler == null) {
-      return 0;
-    }
-    HashSet<ActiveJob> jobs = scheduler.activeJobs();
-    if (jobs == null || jobs.size() == 0) {
-      return 0;
-    }
-    Iterator<ActiveJob> it = jobs.iterator();
-    while (it.hasNext()) {
-      ActiveJob job = it.next();
-      String g = (String) job.properties().get("spark.jobGroup.id");
-      if (jobGroup.equals(g)) {
-        int[] progressInfo = null;
-        try {
-          Object finalStage = job.getClass().getMethod("finalStage").invoke(job);
-          if (sparkVersion.getProgress1_0()) {
-            progressInfo = getProgressFromStage_1_0x(sparkListener, finalStage);
-          } else {
-            progressInfo = getProgressFromStage_1_1x(sparkListener, finalStage);
-          }
-        } catch (IllegalAccessException | IllegalArgumentException
-            | InvocationTargetException | NoSuchMethodException
-            | SecurityException e) {
-          logger.error("Can't get progress info", e);
-          return 0;
-        }
-        totalTasks += progressInfo[0];
-        completedTasks += progressInfo[1];
-      }
-    }
-
-    if (totalTasks == 0) {
-      return 0;
-    }
-    return completedTasks * 100 / totalTasks;
-  }
-
-  private int[] getProgressFromStage_1_0x(JobProgressListener sparkListener, Object stage)
-      throws IllegalAccessException, IllegalArgumentException,
-      InvocationTargetException, NoSuchMethodException, SecurityException {
-    int numTasks = (int) stage.getClass().getMethod("numTasks").invoke(stage);
-    int completedTasks = 0;
-
-    int id = (int) stage.getClass().getMethod("id").invoke(stage);
-
-    Object completedTaskInfo = null;
-
-    completedTaskInfo = JavaConversions.mapAsJavaMap(
-        (HashMap<Object, Object>) sparkListener.getClass()
-            .getMethod("stageIdToTasksComplete").invoke(sparkListener)).get(id);
-
-    if (completedTaskInfo != null) {
-      completedTasks += (int) completedTaskInfo;
-    }
-    List<Object> parents = JavaConversions.seqAsJavaList((Seq<Object>) stage.getClass()
-        .getMethod("parents").invoke(stage));
-    if (parents != null) {
-      for (Object s : parents) {
-        int[] p = getProgressFromStage_1_0x(sparkListener, s);
-        numTasks += p[0];
-        completedTasks += p[1];
-      }
-    }
-
-    return new int[] {numTasks, completedTasks};
-  }
-
-  private int[] getProgressFromStage_1_1x(JobProgressListener sparkListener, Object stage)
-      throws IllegalAccessException, IllegalArgumentException,
-      InvocationTargetException, NoSuchMethodException, SecurityException {
-    int numTasks = (int) stage.getClass().getMethod("numTasks").invoke(stage);
-    int completedTasks = 0;
-    int id = (int) stage.getClass().getMethod("id").invoke(stage);
-
-    try {
-      Method stageIdToData = sparkListener.getClass().getMethod("stageIdToData");
-      HashMap<Tuple2<Object, Object>, Object> stageIdData =
-          (HashMap<Tuple2<Object, Object>, Object>) stageIdToData.invoke(sparkListener);
-      Class<?> stageUIDataClass =
-          this.getClass().forName("org.apache.spark.ui.jobs.UIData$StageUIData");
-
-      Method numCompletedTasks = stageUIDataClass.getMethod("numCompleteTasks");
-      Set<Tuple2<Object, Object>> keys =
-          JavaConverters.setAsJavaSetConverter(stageIdData.keySet()).asJava();
-      for (Tuple2<Object, Object> k : keys) {
-        if (id == (int) k._1()) {
-          Object uiData = stageIdData.get(k).get();
-          completedTasks += (int) numCompletedTasks.invoke(uiData);
-        }
-      }
-    } catch (Exception e) {
-      logger.error("Error on getting progress information", e);
-    }
-
-    List<Object> parents = JavaConversions.seqAsJavaList((Seq<Object>) stage.getClass()
-        .getMethod("parents").invoke(stage));
-    if (parents != null) {
-      for (Object s : parents) {
-        int[] p = getProgressFromStage_1_1x(sparkListener, s);
-        numTasks += p[0];
-        completedTasks += p[1];
-      }
-    }
-    return new int[] {numTasks, completedTasks};
-  }
-
-  private Code getResultCode(scala.tools.nsc.interpreter.Results.Result r) {
-    if (r instanceof scala.tools.nsc.interpreter.Results.Success$) {
-      return Code.SUCCESS;
-    } else if (r instanceof scala.tools.nsc.interpreter.Results.Incomplete$) {
-      return Code.INCOMPLETE;
-    } else {
-      return Code.ERROR;
-    }
-  }
-
-  @Override
-  public void close() {
-    logger.info("Close interpreter");
-
-    if (numReferenceOfSparkContext.decrementAndGet() == 0) {
-      if (sparkSession != null) {
-        Utils.invokeMethod(sparkSession, "stop");
-      } else if (sc != null){
-        sc.stop();
-      }
-      sparkSession = null;
-      sc = null;
-      jsc = null;
-      if (classServer != null) {
-        Utils.invokeMethod(classServer, "stop");
-        classServer = null;
-      }
-    }
-
-    Utils.invokeMethod(intp, "close");
-  }
-
-  @Override
-  public FormType getFormType() {
-    return FormType.NATIVE;
-  }
-
-  public JobProgressListener getJobProgressListener() {
-    return sparkListener;
-  }
-
-  @Override
-  public Scheduler getScheduler() {
-    return SchedulerFactory.singleton().createOrGetFIFOScheduler(
-      SparkInterpreter.class.getName() + this.hashCode());
-  }
-
-  public SparkZeppelinContext getZeppelinContext() {
-    return z;
-  }
-
-  public SparkVersion getSparkVersion() {
-    return sparkVersion;
-  }
-
-  private File createTempDir(String dir) {
-    File file = null;
-
-    // try Utils.createTempDir()
-    file = (File) Utils.invokeStaticMethod(
-      Utils.findClass("org.apache.spark.util.Utils"),
-      "createTempDir",
-      new Class[]{String.class, String.class},
-      new Object[]{dir, "spark"});
-
-    // fallback to old method
-    if (file == null) {
-      file = (File) Utils.invokeStaticMethod(
-        Utils.findClass("org.apache.spark.util.Utils"),
-        "createTempDir",
-        new Class[]{String.class},
-        new Object[]{dir});
-    }
-
-    return file;
-  }
-
-  private Object createHttpServer(File outputDir) {
-    SparkConf conf = new SparkConf();
-    try {
-      // try to create HttpServer
-      Constructor<?> constructor = getClass().getClassLoader()
-          .loadClass("org.apache.spark.HttpServer")
-          .getConstructor(new Class[]{
-            SparkConf.class, File.class, SecurityManager.class, int.class, String.class});
-
-      Object securityManager = createSecurityManager(conf);
-      return constructor.newInstance(new Object[]{
-        conf, outputDir, securityManager, 0, "HTTP Server"});
-
-    } catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException |
-        InstantiationException | InvocationTargetException e) {
-      // fallback to old constructor
-      Constructor<?> constructor = null;
-      try {
-        constructor = getClass().getClassLoader()
-            .loadClass("org.apache.spark.HttpServer")
-            .getConstructor(new Class[]{
-              File.class, SecurityManager.class, int.class, String.class});
-        return constructor.newInstance(new Object[] {
-          outputDir, createSecurityManager(conf), 0, "HTTP Server"});
-      } catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException |
-          InstantiationException | InvocationTargetException e1) {
-        logger.error(e1.getMessage(), e1);
-        return null;
-      }
-    }
-  }
-
-  /**
-   * Constructor signature of SecurityManager changes in spark 2.1.0, so we use this method to
-   * create SecurityManager properly for different versions of spark
-   *
-   * @param conf
-   * @return
-   * @throws ClassNotFoundException
-   * @throws NoSuchMethodException
-   * @throws IllegalAccessException
-   * @throws InvocationTargetException
-   * @throws InstantiationException
-   */
-  private Object createSecurityManager(SparkConf conf) throws ClassNotFoundException,
-      NoSuchMethodException, IllegalAccessException, InvocationTargetException,
-      InstantiationException {
-    Object securityManager = null;
-    try {
-      Constructor<?> smConstructor = getClass().getClassLoader()
-          .loadClass("org.apache.spark.SecurityManager")
-          .getConstructor(new Class[]{ SparkConf.class, scala.Option.class });
-      securityManager = smConstructor.newInstance(conf, null);
-    } catch (NoSuchMethodException e) {
-      Constructor<?> smConstructor = getClass().getClassLoader()
-          .loadClass("org.apache.spark.SecurityManager")
-          .getConstructor(new Class[]{ SparkConf.class });
-      securityManager = smConstructor.newInstance(conf);
-    }
-    return securityManager;
-  }
-}

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/d762b528/spark/src/main/java/org/apache/zeppelin/spark/SparkRInterpreter.java
----------------------------------------------------------------------
diff --git a/spark/src/main/java/org/apache/zeppelin/spark/SparkRInterpreter.java b/spark/src/main/java/org/apache/zeppelin/spark/SparkRInterpreter.java
deleted file mode 100644
index 1bdd4dc..0000000
--- a/spark/src/main/java/org/apache/zeppelin/spark/SparkRInterpreter.java
+++ /dev/null
@@ -1,250 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.zeppelin.spark;
-
-import static org.apache.zeppelin.spark.ZeppelinRDisplay.render;
-
-import com.fasterxml.jackson.databind.JsonNode;
-import com.fasterxml.jackson.databind.ObjectMapper;
-
-import org.apache.spark.SparkContext;
-import org.apache.spark.SparkRBackend;
-import org.apache.spark.api.java.JavaSparkContext;
-import org.apache.zeppelin.interpreter.*;
-import org.apache.zeppelin.interpreter.thrift.InterpreterCompletion;
-import org.apache.zeppelin.scheduler.Scheduler;
-import org.apache.zeppelin.scheduler.SchedulerFactory;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Properties;
-
-/**
- * R and SparkR interpreter with visualization support.
- */
-public class SparkRInterpreter extends Interpreter {
-  private static final Logger logger = LoggerFactory.getLogger(SparkRInterpreter.class);
-
-  private static String renderOptions;
-  private SparkInterpreter sparkInterpreter;
-  private ZeppelinR zeppelinR;
-  private SparkContext sc;
-  private JavaSparkContext jsc;
-
-  public SparkRInterpreter(Properties property) {
-    super(property);
-  }
-
-  @Override
-  public void open() throws InterpreterException {
-    String rCmdPath = getProperty("zeppelin.R.cmd");
-    String sparkRLibPath;
-
-    if (System.getenv("SPARK_HOME") != null) {
-      sparkRLibPath = System.getenv("SPARK_HOME") + "/R/lib";
-    } else {
-      sparkRLibPath = System.getenv("ZEPPELIN_HOME") + "/interpreter/spark/R/lib";
-      // workaround to make sparkr work without SPARK_HOME
-      System.setProperty("spark.test.home", System.getenv("ZEPPELIN_HOME") + "/interpreter/spark");
-    }
-    synchronized (SparkRBackend.backend()) {
-      if (!SparkRBackend.isStarted()) {
-        SparkRBackend.init();
-        SparkRBackend.start();
-      }
-    }
-
-    int port = SparkRBackend.port();
-
-    this.sparkInterpreter = getSparkInterpreter();
-    this.sc = sparkInterpreter.getSparkContext();
-    this.jsc = sparkInterpreter.getJavaSparkContext();
-    SparkVersion sparkVersion = new SparkVersion(sc.version());
-    ZeppelinRContext.setSparkContext(sc);
-    ZeppelinRContext.setJavaSparkContext(jsc);
-    if (Utils.isSpark2()) {
-      ZeppelinRContext.setSparkSession(sparkInterpreter.getSparkSession());
-    }
-    ZeppelinRContext.setSqlContext(sparkInterpreter.getSQLContext());
-    ZeppelinRContext.setZeppelinContext(sparkInterpreter.getZeppelinContext());
-
-    zeppelinR = new ZeppelinR(rCmdPath, sparkRLibPath, port, sparkVersion);
-    try {
-      zeppelinR.open();
-    } catch (IOException e) {
-      logger.error("Exception while opening SparkRInterpreter", e);
-      throw new InterpreterException(e);
-    }
-
-    if (useKnitr()) {
-      zeppelinR.eval("library('knitr')");
-    }
-    renderOptions = getProperty("zeppelin.R.render.options");
-  }
-
-  String getJobGroup(InterpreterContext context){
-    return "zeppelin-" + context.getParagraphId();
-  }
-
-  @Override
-  public InterpreterResult interpret(String lines, InterpreterContext interpreterContext)
-      throws InterpreterException {
-
-    SparkInterpreter sparkInterpreter = getSparkInterpreter();
-    sparkInterpreter.populateSparkWebUrl(interpreterContext);
-    if (sparkInterpreter.isUnsupportedSparkVersion()) {
-      return new InterpreterResult(InterpreterResult.Code.ERROR, "Spark "
-          + sparkInterpreter.getSparkVersion().toString() + " is not supported");
-    }
-
-    String jobGroup = Utils.buildJobGroupId(interpreterContext);
-    String jobDesc = "Started by: " +
-       Utils.getUserName(interpreterContext.getAuthenticationInfo());
-    sparkInterpreter.getSparkContext().setJobGroup(jobGroup, jobDesc, false);
-
-    String imageWidth = getProperty("zeppelin.R.image.width");
-
-    String[] sl = lines.split("\n");
-    if (sl[0].contains("{") && sl[0].contains("}")) {
-      String jsonConfig = sl[0].substring(sl[0].indexOf("{"), sl[0].indexOf("}") + 1);
-      ObjectMapper m = new ObjectMapper();
-      try {
-        JsonNode rootNode = m.readTree(jsonConfig);
-        JsonNode imageWidthNode = rootNode.path("imageWidth");
-        if (!imageWidthNode.isMissingNode()) imageWidth = imageWidthNode.textValue();
-      }
-      catch (Exception e) {
-        logger.warn("Can not parse json config: " + jsonConfig, e);
-      }
-      finally {
-        lines = lines.replace(jsonConfig, "");
-      }
-    }
-
-    String setJobGroup = "";
-    // assign setJobGroup to dummy__, otherwise it would print NULL for this statement
-    if (Utils.isSpark2()) {
-      setJobGroup = "dummy__ <- setJobGroup(\"" + jobGroup +
-          "\", \" +" + jobDesc + "\", TRUE)";
-    } else if (getSparkInterpreter().getSparkVersion().newerThanEquals(SparkVersion.SPARK_1_5_0)) {
-      setJobGroup = "dummy__ <- setJobGroup(sc, \"" + jobGroup +
-          "\", \"" + jobDesc + "\", TRUE)";
-    }
-    logger.debug("set JobGroup:" + setJobGroup);
-    lines = setJobGroup + "\n" + lines;
-
-    try {
-      // render output with knitr
-      if (useKnitr()) {
-        zeppelinR.setInterpreterOutput(null);
-        zeppelinR.set(".zcmd", "\n```{r " + renderOptions + "}\n" + lines + "\n```");
-        zeppelinR.eval(".zres <- knit2html(text=.zcmd)");
-        String html = zeppelinR.getS0(".zres");
-
-        RDisplay rDisplay = render(html, imageWidth);
-
-        return new InterpreterResult(
-            rDisplay.code(),
-            rDisplay.type(),
-            rDisplay.content()
-        );
-      } else {
-        // alternatively, stream the output (without knitr)
-        zeppelinR.setInterpreterOutput(interpreterContext.out);
-        zeppelinR.eval(lines);
-        return new InterpreterResult(InterpreterResult.Code.SUCCESS, "");
-      }
-    } catch (Exception e) {
-      logger.error("Exception while connecting to R", e);
-      return new InterpreterResult(InterpreterResult.Code.ERROR, e.getMessage());
-    } finally {
-      try {
-      } catch (Exception e) {
-        // Do nothing...
-      }
-    }
-  }
-
-  @Override
-  public void close() {
-    zeppelinR.close();
-  }
-
-  @Override
-  public void cancel(InterpreterContext context) {
-    if (this.sc != null) {
-      sc.cancelJobGroup(getJobGroup(context));
-    }
-  }
-
-  @Override
-  public FormType getFormType() {
-    return FormType.NONE;
-  }
-
-  @Override
-  public int getProgress(InterpreterContext context) {
-    if (sparkInterpreter != null) {
-      return sparkInterpreter.getProgress(context);
-    } else {
-      return 0;
-    }
-  }
-
-  @Override
-  public Scheduler getScheduler() {
-    return SchedulerFactory.singleton().createOrGetFIFOScheduler(
-            SparkRInterpreter.class.getName() + this.hashCode());
-  }
-
-  @Override
-  public List<InterpreterCompletion> completion(String buf, int cursor,
-      InterpreterContext interpreterContext) {
-    return new ArrayList<>();
-  }
-
-  private SparkInterpreter getSparkInterpreter() throws InterpreterException {
-    LazyOpenInterpreter lazy = null;
-    SparkInterpreter spark = null;
-    Interpreter p = getInterpreterInTheSameSessionByClassName(SparkInterpreter.class.getName());
-
-    while (p instanceof WrappedInterpreter) {
-      if (p instanceof LazyOpenInterpreter) {
-        lazy = (LazyOpenInterpreter) p;
-      }
-      p = ((WrappedInterpreter) p).getInnerInterpreter();
-    }
-    spark = (SparkInterpreter) p;
-
-    if (lazy != null) {
-      lazy.open();
-    }
-    return spark;
-  }
-
-  private boolean useKnitr() {
-    try {
-      return Boolean.parseBoolean(getProperty("zeppelin.R.knitr"));
-    } catch (Exception e) {
-      return false;
-    }
-  }
-}

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/d762b528/spark/src/main/java/org/apache/zeppelin/spark/SparkSqlInterpreter.java
----------------------------------------------------------------------
diff --git a/spark/src/main/java/org/apache/zeppelin/spark/SparkSqlInterpreter.java b/spark/src/main/java/org/apache/zeppelin/spark/SparkSqlInterpreter.java
deleted file mode 100644
index 9709f9e..0000000
--- a/spark/src/main/java/org/apache/zeppelin/spark/SparkSqlInterpreter.java
+++ /dev/null
@@ -1,187 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.zeppelin.spark;
-
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.util.List;
-import java.util.Properties;
-import java.util.concurrent.atomic.AtomicInteger;
-
-import org.apache.spark.SparkContext;
-import org.apache.spark.sql.SQLContext;
-import org.apache.zeppelin.interpreter.Interpreter;
-import org.apache.zeppelin.interpreter.InterpreterContext;
-import org.apache.zeppelin.interpreter.InterpreterException;
-import org.apache.zeppelin.interpreter.InterpreterResult;
-import org.apache.zeppelin.interpreter.InterpreterResult.Code;
-import org.apache.zeppelin.interpreter.LazyOpenInterpreter;
-import org.apache.zeppelin.interpreter.WrappedInterpreter;
-import org.apache.zeppelin.interpreter.thrift.InterpreterCompletion;
-import org.apache.zeppelin.scheduler.Scheduler;
-import org.apache.zeppelin.scheduler.SchedulerFactory;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Spark SQL interpreter for Zeppelin.
- */
-public class SparkSqlInterpreter extends Interpreter {
-  private Logger logger = LoggerFactory.getLogger(SparkSqlInterpreter.class);
-
-  public static final String MAX_RESULTS = "zeppelin.spark.maxResult";
-
-  AtomicInteger num = new AtomicInteger(0);
-
-  private int maxResult;
-
-  public SparkSqlInterpreter(Properties property) {
-    super(property);
-  }
-
-  @Override
-  public void open() {
-    this.maxResult = Integer.parseInt(getProperty(MAX_RESULTS));
-  }
-
-  private SparkInterpreter getSparkInterpreter() throws InterpreterException {
-    LazyOpenInterpreter lazy = null;
-    SparkInterpreter spark = null;
-    Interpreter p = getInterpreterInTheSameSessionByClassName(SparkInterpreter.class.getName());
-
-    while (p instanceof WrappedInterpreter) {
-      if (p instanceof LazyOpenInterpreter) {
-        lazy = (LazyOpenInterpreter) p;
-      }
-      p = ((WrappedInterpreter) p).getInnerInterpreter();
-    }
-    spark = (SparkInterpreter) p;
-
-    if (lazy != null) {
-      lazy.open();
-    }
-    return spark;
-  }
-
-  public boolean concurrentSQL() {
-    return Boolean.parseBoolean(getProperty("zeppelin.spark.concurrentSQL"));
-  }
-
-  @Override
-  public void close() {}
-
-  @Override
-  public InterpreterResult interpret(String st, InterpreterContext context)
-      throws InterpreterException {
-    SQLContext sqlc = null;
-    SparkInterpreter sparkInterpreter = getSparkInterpreter();
-
-    if (sparkInterpreter.isUnsupportedSparkVersion()) {
-      return new InterpreterResult(Code.ERROR, "Spark "
-          + sparkInterpreter.getSparkVersion().toString() + " is not supported");
-    }
-
-    sparkInterpreter.populateSparkWebUrl(context);
-    sparkInterpreter.getZeppelinContext().setInterpreterContext(context);
-    sqlc = sparkInterpreter.getSQLContext();
-    SparkContext sc = sqlc.sparkContext();
-    if (concurrentSQL()) {
-      sc.setLocalProperty("spark.scheduler.pool", "fair");
-    } else {
-      sc.setLocalProperty("spark.scheduler.pool", null);
-    }
-
-    String jobDesc = "Started by: " + Utils.getUserName(context.getAuthenticationInfo());
-    sc.setJobGroup(Utils.buildJobGroupId(context), jobDesc, false);
-    Object rdd = null;
-    try {
-      // method signature of sqlc.sql() is changed
-      // from  def sql(sqlText: String): SchemaRDD (1.2 and prior)
-      // to    def sql(sqlText: String): DataFrame (1.3 and later).
-      // Therefore need to use reflection to keep binary compatibility for all spark versions.
-      Method sqlMethod = sqlc.getClass().getMethod("sql", String.class);
-      rdd = sqlMethod.invoke(sqlc, st);
-    } catch (InvocationTargetException ite) {
-      if (Boolean.parseBoolean(getProperty("zeppelin.spark.sql.stacktrace"))) {
-        throw new InterpreterException(ite);
-      }
-      logger.error("Invocation target exception", ite);
-      String msg = ite.getTargetException().getMessage()
-              + "\nset zeppelin.spark.sql.stacktrace = true to see full stacktrace";
-      return new InterpreterResult(Code.ERROR, msg);
-    } catch (NoSuchMethodException | SecurityException | IllegalAccessException
-        | IllegalArgumentException e) {
-      throw new InterpreterException(e);
-    }
-
-    String msg = sparkInterpreter.getZeppelinContext().showData(rdd);
-    sc.clearJobGroup();
-    return new InterpreterResult(Code.SUCCESS, msg);
-  }
-
-  @Override
-  public void cancel(InterpreterContext context) throws InterpreterException {
-    SparkInterpreter sparkInterpreter = getSparkInterpreter();
-    SQLContext sqlc = sparkInterpreter.getSQLContext();
-    SparkContext sc = sqlc.sparkContext();
-
-    sc.cancelJobGroup(Utils.buildJobGroupId(context));
-  }
-
-  @Override
-  public FormType getFormType() {
-    return FormType.SIMPLE;
-  }
-
-
-  @Override
-  public int getProgress(InterpreterContext context) throws InterpreterException {
-    SparkInterpreter sparkInterpreter = getSparkInterpreter();
-    return sparkInterpreter.getProgress(context);
-  }
-
-  @Override
-  public Scheduler getScheduler() {
-    if (concurrentSQL()) {
-      int maxConcurrency = 10;
-      return SchedulerFactory.singleton().createOrGetParallelScheduler(
-          SparkSqlInterpreter.class.getName() + this.hashCode(), maxConcurrency);
-    } else {
-      // getSparkInterpreter() calls open() inside.
-      // That means if SparkInterpreter is not opened, it'll wait until SparkInterpreter open.
-      // In this moment UI displays 'READY' or 'FINISHED' instead of 'PENDING' or 'RUNNING'.
-      // It's because of scheduler is not created yet, and scheduler is created by this function.
-      // Therefore, we can still use getSparkInterpreter() here, but it's better and safe
-      // to getSparkInterpreter without opening it.
-
-      Interpreter intp =
-          getInterpreterInTheSameSessionByClassName(SparkInterpreter.class.getName());
-      if (intp != null) {
-        return intp.getScheduler();
-      } else {
-        return null;
-      }
-    }
-  }
-
-  @Override
-  public List<InterpreterCompletion> completion(String buf, int cursor,
-      InterpreterContext interpreterContext) {
-    return null;
-  }
-}

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/d762b528/spark/src/main/java/org/apache/zeppelin/spark/SparkVersion.java
----------------------------------------------------------------------
diff --git a/spark/src/main/java/org/apache/zeppelin/spark/SparkVersion.java b/spark/src/main/java/org/apache/zeppelin/spark/SparkVersion.java
deleted file mode 100644
index 4b02798..0000000
--- a/spark/src/main/java/org/apache/zeppelin/spark/SparkVersion.java
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.zeppelin.spark;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Provide reading comparing capability of spark version returned from SparkContext.version()
- */
-public class SparkVersion {
-  Logger logger = LoggerFactory.getLogger(SparkVersion.class);
-
-  public static final SparkVersion SPARK_1_0_0 = SparkVersion.fromVersionString("1.0.0");
-  public static final SparkVersion SPARK_1_1_0 = SparkVersion.fromVersionString("1.1.0");
-  public static final SparkVersion SPARK_1_2_0 = SparkVersion.fromVersionString("1.2.0");
-  public static final SparkVersion SPARK_1_3_0 = SparkVersion.fromVersionString("1.3.0");
-  public static final SparkVersion SPARK_1_4_0 = SparkVersion.fromVersionString("1.4.0");
-  public static final SparkVersion SPARK_1_5_0 = SparkVersion.fromVersionString("1.5.0");
-  public static final SparkVersion SPARK_1_6_0 = SparkVersion.fromVersionString("1.6.0");
-
-  public static final SparkVersion SPARK_2_0_0 = SparkVersion.fromVersionString("2.0.0");
-  public static final SparkVersion SPARK_2_3_0 = SparkVersion.fromVersionString("2.3.0");
-
-  public static final SparkVersion MIN_SUPPORTED_VERSION =  SPARK_1_0_0;
-  public static final SparkVersion UNSUPPORTED_FUTURE_VERSION = SPARK_2_3_0;
-
-  private int version;
-  private String versionString;
-
-  SparkVersion(String versionString) {
-    this.versionString = versionString;
-
-    try {
-      int pos = versionString.indexOf('-');
-
-      String numberPart = versionString;
-      if (pos > 0) {
-        numberPart = versionString.substring(0, pos);
-      }
-
-      String versions[] = numberPart.split("\\.");
-      int major = Integer.parseInt(versions[0]);
-      int minor = Integer.parseInt(versions[1]);
-      int patch = Integer.parseInt(versions[2]);
-      // version is always 5 digits. (e.g. 2.0.0 -> 20000, 1.6.2 -> 10602)
-      version = Integer.parseInt(String.format("%d%02d%02d", major, minor, patch));
-    } catch (Exception e) {
-      logger.error("Can not recognize Spark version " + versionString +
-          ". Assume it's a future release", e);
-
-      // assume it is future release
-      version = 99999;
-    }
-  }
-
-  public int toNumber() {
-    return version;
-  }
-
-  public String toString() {
-    return versionString;
-  }
-
-  public boolean isUnsupportedVersion() {
-    return olderThan(MIN_SUPPORTED_VERSION) || newerThanEquals(UNSUPPORTED_FUTURE_VERSION);
-  }
-
-  public static SparkVersion fromVersionString(String versionString) {
-    return new SparkVersion(versionString);
-  }
-
-  public boolean isPysparkSupported() {
-    return this.newerThanEquals(SPARK_1_2_0);
-  }
-
-  public boolean isSparkRSupported() {
-    return this.newerThanEquals(SPARK_1_4_0);
-  }
-
-  public boolean hasDataFrame() {
-    return this.newerThanEquals(SPARK_1_4_0);
-  }
-
-  public boolean getProgress1_0() {
-    return this.olderThan(SPARK_1_1_0);
-  }
-
-  public boolean oldLoadFilesMethodName() {
-    return this.olderThan(SPARK_1_3_0);
-  }
-
-  public boolean oldSqlContextImplicits() {
-    return this.olderThan(SPARK_1_3_0);
-  }
-
-  public boolean equals(Object versionToCompare) {
-    return version == ((SparkVersion) versionToCompare).version;
-  }
-
-  public boolean newerThan(SparkVersion versionToCompare) {
-    return version > versionToCompare.version;
-  }
-
-  public boolean newerThanEquals(SparkVersion versionToCompare) {
-    return version >= versionToCompare.version;
-  }
-
-  public boolean olderThan(SparkVersion versionToCompare) {
-    return version < versionToCompare.version;
-  }
-
-  public boolean olderThanEquals(SparkVersion versionToCompare) {
-    return version <= versionToCompare.version;
-  }
-}

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/d762b528/spark/src/main/java/org/apache/zeppelin/spark/SparkZeppelinContext.java
----------------------------------------------------------------------
diff --git a/spark/src/main/java/org/apache/zeppelin/spark/SparkZeppelinContext.java b/spark/src/main/java/org/apache/zeppelin/spark/SparkZeppelinContext.java
deleted file mode 100644
index 92dc0b1..0000000
--- a/spark/src/main/java/org/apache/zeppelin/spark/SparkZeppelinContext.java
+++ /dev/null
@@ -1,314 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.zeppelin.spark;
-
-import com.google.common.collect.Lists;
-import org.apache.spark.SparkContext;
-import org.apache.spark.sql.SQLContext;
-import org.apache.spark.sql.catalyst.expressions.Attribute;
-import org.apache.zeppelin.annotation.ZeppelinApi;
-import org.apache.zeppelin.display.AngularObjectWatcher;
-import org.apache.zeppelin.display.Input;
-import org.apache.zeppelin.display.ui.OptionInput;
-import org.apache.zeppelin.interpreter.*;
-import scala.Tuple2;
-import scala.Unit;
-
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.util.*;
-
-import static scala.collection.JavaConversions.asJavaIterable;
-import static scala.collection.JavaConversions.collectionAsScalaIterable;
-
-/**
- * ZeppelinContext for Spark
- */
-public class SparkZeppelinContext extends BaseZeppelinContext {
-
-
-  private SparkContext sc;
-  public SQLContext sqlContext;
-  private List<Class> supportedClasses;
-  private Map<String, String> interpreterClassMap;
-
-  public SparkZeppelinContext(
-      SparkContext sc, SQLContext sql,
-      InterpreterHookRegistry hooks,
-      int maxResult) {
-    super(hooks, maxResult);
-    this.sc = sc;
-    this.sqlContext = sql;
-
-    interpreterClassMap = new HashMap<String, String>();
-    interpreterClassMap.put("spark", "org.apache.zeppelin.spark.SparkInterpreter");
-    interpreterClassMap.put("sql", "org.apache.zeppelin.spark.SparkSqlInterpreter");
-    interpreterClassMap.put("dep", "org.apache.zeppelin.spark.DepInterpreter");
-    interpreterClassMap.put("pyspark", "org.apache.zeppelin.spark.PySparkInterpreter");
-
-    this.supportedClasses = new ArrayList<>();
-    try {
-      supportedClasses.add(this.getClass().forName("org.apache.spark.sql.Dataset"));
-    } catch (ClassNotFoundException e) {
-    }
-
-    try {
-      supportedClasses.add(this.getClass().forName("org.apache.spark.sql.DataFrame"));
-    } catch (ClassNotFoundException e) {
-    }
-
-    try {
-      supportedClasses.add(this.getClass().forName("org.apache.spark.sql.SchemaRDD"));
-    } catch (ClassNotFoundException e) {
-    }
-
-    if (supportedClasses.isEmpty()) {
-      throw new RuntimeException("Can not load Dataset/DataFrame/SchemaRDD class");
-    }
-  }
-
-  @Override
-  public List<Class> getSupportedClasses() {
-    return supportedClasses;
-  }
-
-  @Override
-  public Map<String, String> getInterpreterClassMap() {
-    return interpreterClassMap;
-  }
-
-  @Override
-  public String showData(Object df) {
-    Object[] rows = null;
-    Method take;
-    String jobGroup = Utils.buildJobGroupId(interpreterContext);
-    sc.setJobGroup(jobGroup, "Zeppelin", false);
-
-    try {
-      // convert it to DataFrame if it is Dataset, as we will iterate all the records
-      // and assume it is type Row.
-      if (df.getClass().getCanonicalName().equals("org.apache.spark.sql.Dataset")) {
-        Method convertToDFMethod = df.getClass().getMethod("toDF");
-        df = convertToDFMethod.invoke(df);
-      }
-      take = df.getClass().getMethod("take", int.class);
-      rows = (Object[]) take.invoke(df, maxResult + 1);
-    } catch (NoSuchMethodException | SecurityException | IllegalAccessException
-        | IllegalArgumentException | InvocationTargetException | ClassCastException e) {
-      sc.clearJobGroup();
-      throw new RuntimeException(e);
-    }
-
-    List<Attribute> columns = null;
-    // get field names
-    try {
-      // Use reflection because of classname returned by queryExecution changes from
-      // Spark <1.5.2 org.apache.spark.sql.SQLContext$QueryExecution
-      // Spark 1.6.0> org.apache.spark.sql.hive.HiveContext$QueryExecution
-      Object qe = df.getClass().getMethod("queryExecution").invoke(df);
-      Object a = qe.getClass().getMethod("analyzed").invoke(qe);
-      scala.collection.Seq seq = (scala.collection.Seq) a.getClass().getMethod("output").invoke(a);
-
-      columns = (List<Attribute>) scala.collection.JavaConverters.seqAsJavaListConverter(seq)
-          .asJava();
-    } catch (NoSuchMethodException | SecurityException | IllegalAccessException
-        | IllegalArgumentException | InvocationTargetException e) {
-      throw new RuntimeException(e);
-    }
-
-    StringBuilder msg = new StringBuilder();
-    msg.append("%table ");
-    for (Attribute col : columns) {
-      msg.append(col.name() + "\t");
-    }
-    String trim = msg.toString().trim();
-    msg = new StringBuilder(trim);
-    msg.append("\n");
-
-    // ArrayType, BinaryType, BooleanType, ByteType, DecimalType, DoubleType, DynamicType,
-    // FloatType, FractionalType, IntegerType, IntegralType, LongType, MapType, NativeType,
-    // NullType, NumericType, ShortType, StringType, StructType
-
-    try {
-      for (int r = 0; r < maxResult && r < rows.length; r++) {
-        Object row = rows[r];
-        Method isNullAt = row.getClass().getMethod("isNullAt", int.class);
-        Method apply = row.getClass().getMethod("apply", int.class);
-
-        for (int i = 0; i < columns.size(); i++) {
-          if (!(Boolean) isNullAt.invoke(row, i)) {
-            msg.append(apply.invoke(row, i).toString());
-          } else {
-            msg.append("null");
-          }
-          if (i != columns.size() - 1) {
-            msg.append("\t");
-          }
-        }
-        msg.append("\n");
-      }
-    } catch (NoSuchMethodException | SecurityException | IllegalAccessException
-        | IllegalArgumentException | InvocationTargetException e) {
-      throw new RuntimeException(e);
-    }
-
-    if (rows.length > maxResult) {
-      msg.append("\n");
-      msg.append(ResultMessages.getExceedsLimitRowsMessage(maxResult,
-          SparkSqlInterpreter.MAX_RESULTS));
-    }
-
-    sc.clearJobGroup();
-    return msg.toString();
-  }
-
-  @ZeppelinApi
-  public Object select(String name, scala.collection.Iterable<Tuple2<Object, String>> options) {
-    return select(name, "", options);
-  }
-
-  @ZeppelinApi
-  public Object select(String name, Object defaultValue,
-                       scala.collection.Iterable<Tuple2<Object, String>> options) {
-    return select(name, defaultValue, tuplesToParamOptions(options));
-  }
-
-  @ZeppelinApi
-  public scala.collection.Seq<Object> checkbox(
-      String name,
-      scala.collection.Iterable<Tuple2<Object, String>> options) {
-    List<Object> allChecked = new LinkedList<>();
-    for (Tuple2<Object, String> option : asJavaIterable(options)) {
-      allChecked.add(option._1());
-    }
-    return checkbox(name, collectionAsScalaIterable(allChecked), options);
-  }
-
-  @ZeppelinApi
-  public scala.collection.Seq<Object> checkbox(
-      String name,
-      scala.collection.Iterable<Object> defaultChecked,
-      scala.collection.Iterable<Tuple2<Object, String>> options) {
-    List<Object> defaultCheckedList = Lists.newArrayList(asJavaIterable(defaultChecked).iterator());
-    Collection<Object> checkbox = checkbox(name, defaultCheckedList, tuplesToParamOptions(options));
-    List<Object> checkboxList = Arrays.asList(checkbox.toArray());
-    return scala.collection.JavaConversions.asScalaBuffer(checkboxList).toSeq();
-  }
-
-  @ZeppelinApi
-  public Object noteSelect(String name, scala.collection.Iterable<Tuple2<Object, String>> options) {
-    return noteSelect(name, "", options);
-  }
-
-  @ZeppelinApi
-  public Object noteSelect(String name, Object defaultValue,
-                       scala.collection.Iterable<Tuple2<Object, String>> options) {
-    return noteSelect(name, defaultValue, tuplesToParamOptions(options));
-  }
-
-  @ZeppelinApi
-  public scala.collection.Seq<Object> noteCheckbox(
-      String name,
-      scala.collection.Iterable<Tuple2<Object, String>> options) {
-    List<Object> allChecked = new LinkedList<>();
-    for (Tuple2<Object, String> option : asJavaIterable(options)) {
-      allChecked.add(option._1());
-    }
-    return noteCheckbox(name, collectionAsScalaIterable(allChecked), options);
-  }
-
-  @ZeppelinApi
-  public scala.collection.Seq<Object> noteCheckbox(
-      String name,
-      scala.collection.Iterable<Object> defaultChecked,
-      scala.collection.Iterable<Tuple2<Object, String>> options) {
-    List<Object> defaultCheckedList = Lists.newArrayList(asJavaIterable(defaultChecked).iterator());
-    Collection<Object> checkbox = noteCheckbox(name, defaultCheckedList,
-        tuplesToParamOptions(options));
-    List<Object> checkboxList = Arrays.asList(checkbox.toArray());
-    return scala.collection.JavaConversions.asScalaBuffer(checkboxList).toSeq();
-  }
-
-  private OptionInput.ParamOption[] tuplesToParamOptions(
-      scala.collection.Iterable<Tuple2<Object, String>> options) {
-    int n = options.size();
-    OptionInput.ParamOption[] paramOptions = new OptionInput.ParamOption[n];
-    Iterator<Tuple2<Object, String>> it = asJavaIterable(options).iterator();
-
-    int i = 0;
-    while (it.hasNext()) {
-      Tuple2<Object, String> valueAndDisplayValue = it.next();
-      paramOptions[i++] = new OptionInput.ParamOption(valueAndDisplayValue._1(),
-          valueAndDisplayValue._2());
-    }
-
-    return paramOptions;
-  }
-
-  @ZeppelinApi
-  public void angularWatch(String name,
-                           final scala.Function2<Object, Object, Unit> func) {
-    angularWatch(name, interpreterContext.getNoteId(), func);
-  }
-
-  @Deprecated
-  public void angularWatchGlobal(String name,
-                                 final scala.Function2<Object, Object, Unit> func) {
-    angularWatch(name, null, func);
-  }
-
-  @ZeppelinApi
-  public void angularWatch(
-      String name,
-      final scala.Function3<Object, Object, InterpreterContext, Unit> func) {
-    angularWatch(name, interpreterContext.getNoteId(), func);
-  }
-
-  @Deprecated
-  public void angularWatchGlobal(
-      String name,
-      final scala.Function3<Object, Object, InterpreterContext, Unit> func) {
-    angularWatch(name, null, func);
-  }
-
-  private void angularWatch(String name, String noteId,
-                            final scala.Function2<Object, Object, Unit> func) {
-    AngularObjectWatcher w = new AngularObjectWatcher(getInterpreterContext()) {
-      @Override
-      public void watch(Object oldObject, Object newObject,
-                        InterpreterContext context) {
-        func.apply(newObject, newObject);
-      }
-    };
-    angularWatch(name, noteId, w);
-  }
-
-  private void angularWatch(
-      String name,
-      String noteId,
-      final scala.Function3<Object, Object, InterpreterContext, Unit> func) {
-    AngularObjectWatcher w = new AngularObjectWatcher(getInterpreterContext()) {
-      @Override
-      public void watch(Object oldObject, Object newObject,
-                        InterpreterContext context) {
-        func.apply(oldObject, newObject, context);
-      }
-    };
-    angularWatch(name, noteId, w);
-  }
-}


[06/10] zeppelin git commit: ZEPPELIN-3111. Refactor SparkInterpreter

Posted by zj...@apache.org.
http://git-wip-us.apache.org/repos/asf/zeppelin/blob/d762b528/spark/interpreter/src/test/java/org/apache/zeppelin/spark/NewSparkInterpreterTest.java
----------------------------------------------------------------------
diff --git a/spark/interpreter/src/test/java/org/apache/zeppelin/spark/NewSparkInterpreterTest.java b/spark/interpreter/src/test/java/org/apache/zeppelin/spark/NewSparkInterpreterTest.java
new file mode 100644
index 0000000..cfcf2a5
--- /dev/null
+++ b/spark/interpreter/src/test/java/org/apache/zeppelin/spark/NewSparkInterpreterTest.java
@@ -0,0 +1,389 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.zeppelin.spark;
+
+import org.apache.zeppelin.display.AngularObjectRegistry;
+import org.apache.zeppelin.display.GUI;
+import org.apache.zeppelin.display.ui.CheckBox;
+import org.apache.zeppelin.display.ui.Select;
+import org.apache.zeppelin.display.ui.TextBox;
+import org.apache.zeppelin.interpreter.InterpreterContext;
+import org.apache.zeppelin.interpreter.InterpreterException;
+import org.apache.zeppelin.interpreter.InterpreterGroup;
+import org.apache.zeppelin.interpreter.InterpreterOutput;
+import org.apache.zeppelin.interpreter.InterpreterOutputListener;
+import org.apache.zeppelin.interpreter.InterpreterResult;
+import org.apache.zeppelin.interpreter.InterpreterResultMessageOutput;
+import org.apache.zeppelin.interpreter.thrift.InterpreterCompletion;
+import org.apache.zeppelin.user.AuthenticationInfo;
+import org.junit.After;
+import org.junit.Test;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.net.URL;
+import java.nio.channels.Channels;
+import java.nio.channels.ReadableByteChannel;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Properties;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+
+
+public class NewSparkInterpreterTest {
+
+  private SparkInterpreter interpreter;
+
+  // catch the streaming output in onAppend
+  private volatile String output = "";
+  // catch the interpreter output in onUpdate
+  private InterpreterResultMessageOutput messageOutput;
+
+  @Test
+  public void testSparkInterpreter() throws IOException, InterruptedException, InterpreterException {
+    Properties properties = new Properties();
+    properties.setProperty("spark.master", "local");
+    properties.setProperty("spark.app.name", "test");
+    properties.setProperty("zeppelin.spark.maxResult", "100");
+    properties.setProperty("zeppelin.spark.test", "true");
+    properties.setProperty("zeppelin.spark.useNew", "true");
+    interpreter = new SparkInterpreter(properties);
+    assertTrue(interpreter.getDelegation() instanceof NewSparkInterpreter);
+    interpreter.setInterpreterGroup(mock(InterpreterGroup.class));
+    interpreter.open();
+
+    InterpreterResult result = interpreter.interpret("val a=\"hello world\"", getInterpreterContext());
+    assertEquals(InterpreterResult.Code.SUCCESS, result.code());
+    assertEquals("a: String = hello world\n", output);
+
+    result = interpreter.interpret("print(a)", getInterpreterContext());
+    assertEquals(InterpreterResult.Code.SUCCESS, result.code());
+    assertEquals("hello world", output);
+
+    // incomplete
+    result = interpreter.interpret("println(a", getInterpreterContext());
+    assertEquals(InterpreterResult.Code.INCOMPLETE, result.code());
+
+    // syntax error
+    result = interpreter.interpret("println(b)", getInterpreterContext());
+    assertEquals(InterpreterResult.Code.ERROR, result.code());
+    assertTrue(output.contains("not found: value b"));
+
+    // multiple line
+    result = interpreter.interpret("\"123\".\ntoInt", getInterpreterContext());
+    assertEquals(InterpreterResult.Code.SUCCESS, result.code());
+
+    // single line comment
+    result = interpreter.interpret("/*comment here*/", getInterpreterContext());
+    assertEquals(InterpreterResult.Code.SUCCESS, result.code());
+
+    result = interpreter.interpret("/*comment here*/\nprint(\"hello world\")", getInterpreterContext());
+    assertEquals(InterpreterResult.Code.SUCCESS, result.code());
+
+    // multiple line comment
+    result = interpreter.interpret("/*line 1 \n line 2*/", getInterpreterContext());
+    assertEquals(InterpreterResult.Code.SUCCESS, result.code());
+
+    // test function
+    result = interpreter.interpret("def add(x:Int, y:Int)\n{ return x+y }", getInterpreterContext());
+    assertEquals(InterpreterResult.Code.SUCCESS, result.code());
+
+    result = interpreter.interpret("print(add(1,2))", getInterpreterContext());
+    assertEquals(InterpreterResult.Code.SUCCESS, result.code());
+
+    result = interpreter.interpret("/*line 1 \n line 2*/print(\"hello world\")", getInterpreterContext());
+    assertEquals(InterpreterResult.Code.SUCCESS, result.code());
+
+    // companion object
+    result = interpreter.interpret("class Counter {\n " +
+        "var value: Long = 0} \n" +
+        "object Counter {\n def apply(x: Long) = new Counter()\n}", getInterpreterContext());
+    assertEquals(InterpreterResult.Code.SUCCESS, result.code());
+
+    // spark rdd operation
+    result = interpreter.interpret("sc.range(1, 10).sum", getInterpreterContext());
+    assertEquals(InterpreterResult.Code.SUCCESS, result.code());
+    assertTrue(output.contains("45"));
+
+    // case class
+    result = interpreter.interpret("val bankText = sc.textFile(\"bank.csv\")", getInterpreterContext());
+    assertEquals(InterpreterResult.Code.SUCCESS, result.code());
+    result = interpreter.interpret(
+        "case class Bank(age:Integer, job:String, marital : String, education : String, balance : Integer)\n",
+        getInterpreterContext());
+    assertEquals(InterpreterResult.Code.SUCCESS, result.code());
+    result = interpreter.interpret(
+        "val bank = bankText.map(s=>s.split(\";\")).filter(s => s(0)!=\"\\\"age\\\"\").map(\n" +
+            "    s => Bank(s(0).toInt, \n" +
+            "            s(1).replaceAll(\"\\\"\", \"\"),\n" +
+            "            s(2).replaceAll(\"\\\"\", \"\"),\n" +
+            "            s(3).replaceAll(\"\\\"\", \"\"),\n" +
+            "            s(5).replaceAll(\"\\\"\", \"\").toInt\n" +
+            "        )\n" +
+            ")", getInterpreterContext());
+    assertEquals(InterpreterResult.Code.SUCCESS, result.code());
+
+    // spark version
+    result = interpreter.interpret("sc.version", getInterpreterContext());
+    assertEquals(InterpreterResult.Code.SUCCESS, result.code());
+
+    // spark sql test
+    String version = output.trim();
+    if (version.contains("String = 1.")) {
+      result = interpreter.interpret("sqlContext", getInterpreterContext());
+      assertEquals(InterpreterResult.Code.SUCCESS, result.code());
+
+      result = interpreter.interpret(
+          "val df = sqlContext.createDataFrame(Seq((1,\"a\"),(2,\"b\")))\n" +
+              "df.show()", getInterpreterContext());
+      assertEquals(InterpreterResult.Code.SUCCESS, result.code());
+      assertTrue(output.contains(
+              "+---+---+\n" +
+              "| _1| _2|\n" +
+              "+---+---+\n" +
+              "|  1|  a|\n" +
+              "|  2|  b|\n" +
+              "+---+---+"));
+    } else if (version.contains("String = 2.")) {
+      result = interpreter.interpret("spark", getInterpreterContext());
+      assertEquals(InterpreterResult.Code.SUCCESS, result.code());
+
+      result = interpreter.interpret(
+          "val df = spark.createDataFrame(Seq((1,\"a\"),(2,\"b\")))\n" +
+              "df.show()", getInterpreterContext());
+      assertEquals(InterpreterResult.Code.SUCCESS, result.code());
+      assertTrue(output.contains(
+              "+---+---+\n" +
+              "| _1| _2|\n" +
+              "+---+---+\n" +
+              "|  1|  a|\n" +
+              "|  2|  b|\n" +
+              "+---+---+"));
+    }
+
+    // ZeppelinContext
+    result = interpreter.interpret("z.show(df)", getInterpreterContext());
+    assertEquals(InterpreterResult.Code.SUCCESS, result.code());
+    assertEquals(InterpreterResult.Type.TABLE, messageOutput.getType());
+    messageOutput.flush();
+    assertEquals("_1\t_2\n1\ta\n2\tb\n", messageOutput.toInterpreterResultMessage().getData());
+
+    InterpreterContext context = getInterpreterContext();
+    result = interpreter.interpret("z.input(\"name\", \"default_name\")", context);
+    assertEquals(InterpreterResult.Code.SUCCESS, result.code());
+    assertEquals(1, context.getGui().getForms().size());
+    assertTrue(context.getGui().getForms().get("name") instanceof TextBox);
+    TextBox textBox = (TextBox) context.getGui().getForms().get("name");
+    assertEquals("name", textBox.getName());
+    assertEquals("default_name", textBox.getDefaultValue());
+
+    context = getInterpreterContext();
+    result = interpreter.interpret("z.checkbox(\"checkbox_1\", Seq(\"value_2\"), Seq((\"value_1\", \"name_1\"), (\"value_2\", \"name_2\")))", context);
+    assertEquals(InterpreterResult.Code.SUCCESS, result.code());
+    assertEquals(1, context.getGui().getForms().size());
+    assertTrue(context.getGui().getForms().get("checkbox_1") instanceof CheckBox);
+    CheckBox checkBox = (CheckBox) context.getGui().getForms().get("checkbox_1");
+    assertEquals("checkbox_1", checkBox.getName());
+    assertEquals(1, checkBox.getDefaultValue().length);
+    assertEquals("value_2", checkBox.getDefaultValue()[0]);
+    assertEquals(2, checkBox.getOptions().length);
+    assertEquals("value_1", checkBox.getOptions()[0].getValue());
+    assertEquals("name_1", checkBox.getOptions()[0].getDisplayName());
+    assertEquals("value_2", checkBox.getOptions()[1].getValue());
+    assertEquals("name_2", checkBox.getOptions()[1].getDisplayName());
+
+    context = getInterpreterContext();
+    result = interpreter.interpret("z.select(\"select_1\", Seq(\"value_2\"), Seq((\"value_1\", \"name_1\"), (\"value_2\", \"name_2\")))", context);
+    assertEquals(InterpreterResult.Code.SUCCESS, result.code());
+    assertEquals(1, context.getGui().getForms().size());
+    assertTrue(context.getGui().getForms().get("select_1") instanceof Select);
+    Select select = (Select) context.getGui().getForms().get("select_1");
+    assertEquals("select_1", select.getName());
+    // TODO(zjffdu) it seems a bug of GUI, the default value should be 'value_2', but it is List(value_2)
+    // assertEquals("value_2", select.getDefaultValue());
+    assertEquals(2, select.getOptions().length);
+    assertEquals("value_1", select.getOptions()[0].getValue());
+    assertEquals("name_1", select.getOptions()[0].getDisplayName());
+    assertEquals("value_2", select.getOptions()[1].getValue());
+    assertEquals("name_2", select.getOptions()[1].getDisplayName());
+
+
+    // completions
+    List<InterpreterCompletion> completions = interpreter.completion("a.", 2, getInterpreterContext());
+    assertTrue(completions.size() > 0);
+
+    completions = interpreter.completion("a.isEm", 6, getInterpreterContext());
+    assertEquals(1, completions.size());
+    assertEquals("isEmpty", completions.get(0).name);
+
+    completions = interpreter.completion("sc.ra", 5, getInterpreterContext());
+    assertEquals(1, completions.size());
+    assertEquals("range", completions.get(0).name);
+
+
+    // Zeppelin-Display
+    result = interpreter.interpret("import org.apache.zeppelin.display.angular.notebookscope._\n" +
+        "import AngularElem._", getInterpreterContext());
+    assertEquals(InterpreterResult.Code.SUCCESS, result.code());
+
+    result = interpreter.interpret("<div style=\"color:blue\">\n" +
+        "<h4>Hello Angular Display System</h4>\n" +
+        "</div>.display", getInterpreterContext());
+    assertEquals(InterpreterResult.Code.SUCCESS, result.code());
+    assertEquals(InterpreterResult.Type.ANGULAR, messageOutput.getType());
+    assertTrue(messageOutput.toInterpreterResultMessage().getData().contains("Hello Angular Display System"));
+
+    result = interpreter.interpret("<div class=\"btn btn-success\">\n" +
+        "  Click me\n" +
+        "</div>.onClick{() =>\n" +
+        "  println(\"hello world\")\n" +
+        "}.display", getInterpreterContext());
+    assertEquals(InterpreterResult.Code.SUCCESS, result.code());
+    assertEquals(InterpreterResult.Type.ANGULAR, messageOutput.getType());
+    assertTrue(messageOutput.toInterpreterResultMessage().getData().contains("Click me"));
+
+    // getProgress
+    final InterpreterContext context2 = getInterpreterContext();
+    Thread interpretThread = new Thread() {
+      @Override
+      public void run() {
+        InterpreterResult result = null;
+        try {
+          result = interpreter.interpret(
+              "val df = sc.parallelize(1 to 10, 2).foreach(e=>Thread.sleep(1000))", context2);
+        } catch (InterpreterException e) {
+          e.printStackTrace();
+        }
+        assertEquals(InterpreterResult.Code.SUCCESS, result.code());
+      }
+    };
+    interpretThread.start();
+    boolean nonZeroProgress = false;
+    int progress = 0;
+    while(interpretThread.isAlive()) {
+      progress = interpreter.getProgress(context2);
+      assertTrue(progress >= 0);
+      if (progress != 0 && progress != 100) {
+        nonZeroProgress = true;
+      }
+      Thread.sleep(100);
+    }
+    assertTrue(nonZeroProgress);
+
+    // cancel
+    final InterpreterContext context3 = getInterpreterContext();
+    interpretThread = new Thread() {
+      @Override
+      public void run() {
+        InterpreterResult result = null;
+        try {
+          result = interpreter.interpret(
+              "val df = sc.parallelize(1 to 10, 2).foreach(e=>Thread.sleep(1000))", context3);
+        } catch (InterpreterException e) {
+          e.printStackTrace();
+        }
+        assertEquals(InterpreterResult.Code.ERROR, result.code());
+        assertTrue(output.contains("cancelled"));
+      }
+    };
+
+    interpretThread.start();
+    // sleep 1 second to wait for the spark job start
+    Thread.sleep(1000);
+    interpreter.cancel(context3);
+    interpretThread.join();
+  }
+
+  @Test
+  public void testDependencies() throws IOException, InterpreterException {
+    Properties properties = new Properties();
+    properties.setProperty("spark.master", "local");
+    properties.setProperty("spark.app.name", "test");
+    properties.setProperty("zeppelin.spark.maxResult", "100");
+    properties.setProperty("zeppelin.spark.useNew", "true");
+
+    // download spark-avro jar
+    URL website = new URL("http://repo1.maven.org/maven2/com/databricks/spark-avro_2.11/3.2.0/spark-avro_2.11-3.2.0.jar");
+    ReadableByteChannel rbc = Channels.newChannel(website.openStream());
+    File avroJarFile = new File("spark-avro_2.11-3.2.0.jar");
+    FileOutputStream fos = new FileOutputStream(avroJarFile);
+    fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
+
+    properties.setProperty("spark.jars", avroJarFile.getAbsolutePath());
+
+    interpreter = new SparkInterpreter(properties);
+    assertTrue(interpreter.getDelegation() instanceof NewSparkInterpreter);
+    interpreter.setInterpreterGroup(mock(InterpreterGroup.class));
+    interpreter.open();
+
+    InterpreterResult result = interpreter.interpret("import com.databricks.spark.avro._", getInterpreterContext());
+    assertEquals(InterpreterResult.Code.SUCCESS, result.code());
+  }
+
+  @After
+  public void tearDown() throws InterpreterException {
+    if (this.interpreter != null) {
+      this.interpreter.close();
+    }
+  }
+
+  private InterpreterContext getInterpreterContext() {
+    output = "";
+    return new InterpreterContext(
+        "noteId",
+        "paragraphId",
+        "replName",
+        "paragraphTitle",
+        "paragraphText",
+        new AuthenticationInfo(),
+        new HashMap<String, Object>(),
+        new GUI(),
+        new GUI(),
+        new AngularObjectRegistry("spark", null),
+        null,
+        null,
+        new InterpreterOutput(
+
+            new InterpreterOutputListener() {
+              @Override
+              public void onUpdateAll(InterpreterOutput out) {
+
+              }
+
+              @Override
+              public void onAppend(int index, InterpreterResultMessageOutput out, byte[] line) {
+                try {
+                  output = out.toInterpreterResultMessage().getData();
+                } catch (IOException e) {
+                  e.printStackTrace();
+                }
+              }
+
+              @Override
+              public void onUpdate(int index, InterpreterResultMessageOutput out) {
+                messageOutput = out;
+              }
+            })
+    );
+  }
+}

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/d762b528/spark/interpreter/src/test/java/org/apache/zeppelin/spark/NewSparkSqlInterpreterTest.java
----------------------------------------------------------------------
diff --git a/spark/interpreter/src/test/java/org/apache/zeppelin/spark/NewSparkSqlInterpreterTest.java b/spark/interpreter/src/test/java/org/apache/zeppelin/spark/NewSparkSqlInterpreterTest.java
new file mode 100644
index 0000000..42289ff
--- /dev/null
+++ b/spark/interpreter/src/test/java/org/apache/zeppelin/spark/NewSparkSqlInterpreterTest.java
@@ -0,0 +1,173 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.zeppelin.spark;
+
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.Properties;
+
+import com.google.common.io.Files;
+import org.apache.zeppelin.display.AngularObjectRegistry;
+import org.apache.zeppelin.resource.LocalResourcePool;
+import org.apache.zeppelin.user.AuthenticationInfo;
+import org.apache.zeppelin.display.GUI;
+import org.apache.zeppelin.interpreter.*;
+import org.apache.zeppelin.interpreter.InterpreterResult.Type;
+import org.junit.*;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+public class NewSparkSqlInterpreterTest {
+
+  private static SparkSqlInterpreter sqlInterpreter;
+  private static SparkInterpreter sparkInterpreter;
+  private static InterpreterContext context;
+  private static InterpreterGroup intpGroup;
+
+  @BeforeClass
+  public static void setUp() throws Exception {
+    Properties p = new Properties();
+    p.setProperty("spark.master", "local");
+    p.setProperty("spark.app.name", "test");
+    p.setProperty("zeppelin.spark.maxResult", "10");
+    p.setProperty("zeppelin.spark.concurrentSQL", "false");
+    p.setProperty("zeppelin.spark.sqlInterpreter.stacktrace", "false");
+    p.setProperty("zeppelin.spark.useNew", "true");
+    intpGroup = new InterpreterGroup();
+    sparkInterpreter = new SparkInterpreter(p);
+    sparkInterpreter.setInterpreterGroup(intpGroup);
+
+    sqlInterpreter = new SparkSqlInterpreter(p);
+    sqlInterpreter.setInterpreterGroup(intpGroup);
+    intpGroup.put("session_1", new LinkedList<Interpreter>());
+    intpGroup.get("session_1").add(sparkInterpreter);
+    intpGroup.get("session_1").add(sqlInterpreter);
+
+    sparkInterpreter.open();
+    sqlInterpreter.open();
+
+    context = new InterpreterContext("note", "id", null, "title", "text", new AuthenticationInfo(),
+        new HashMap<String, Object>(), new GUI(), new GUI(),
+        new AngularObjectRegistry(intpGroup.getId(), null),
+        new LocalResourcePool("id"),
+        new LinkedList<InterpreterContextRunner>(), new InterpreterOutput(null));
+  }
+
+  @AfterClass
+  public static void tearDown() throws InterpreterException {
+    sqlInterpreter.close();
+    sparkInterpreter.close();
+  }
+
+  boolean isDataFrameSupported() {
+    return sparkInterpreter.getSparkVersion().hasDataFrame();
+  }
+
+  @Test
+  public void test() throws InterpreterException {
+    sparkInterpreter.interpret("case class Test(name:String, age:Int)", context);
+    sparkInterpreter.interpret("val test = sc.parallelize(Seq(Test(\"moon\", 33), Test(\"jobs\", 51), Test(\"gates\", 51), Test(\"park\", 34)))", context);
+    if (isDataFrameSupported()) {
+      sparkInterpreter.interpret("test.toDF.registerTempTable(\"test\")", context);
+    } else {
+      sparkInterpreter.interpret("test.registerTempTable(\"test\")", context);
+    }
+
+    InterpreterResult ret = sqlInterpreter.interpret("select name, age from test where age < 40", context);
+    assertEquals(InterpreterResult.Code.SUCCESS, ret.code());
+    assertEquals(Type.TABLE, ret.message().get(0).getType());
+    assertEquals("name\tage\nmoon\t33\npark\t34\n", ret.message().get(0).getData());
+
+    ret = sqlInterpreter.interpret("select wrong syntax", context);
+    assertEquals(InterpreterResult.Code.ERROR, ret.code());
+    assertTrue(ret.message().get(0).getData().length() > 0);
+
+    assertEquals(InterpreterResult.Code.SUCCESS, sqlInterpreter.interpret("select case when name='aa' then name else name end from test", context).code());
+  }
+
+  @Test
+  public void testStruct() throws InterpreterException {
+    sparkInterpreter.interpret("case class Person(name:String, age:Int)", context);
+    sparkInterpreter.interpret("case class People(group:String, person:Person)", context);
+    sparkInterpreter.interpret(
+        "val gr = sc.parallelize(Seq(People(\"g1\", Person(\"moon\",33)), People(\"g2\", Person(\"sun\",11))))",
+        context);
+    if (isDataFrameSupported()) {
+      sparkInterpreter.interpret("gr.toDF.registerTempTable(\"gr\")", context);
+    } else {
+      sparkInterpreter.interpret("gr.registerTempTable(\"gr\")", context);
+    }
+
+    InterpreterResult ret = sqlInterpreter.interpret("select * from gr", context);
+    assertEquals(InterpreterResult.Code.SUCCESS, ret.code());
+  }
+
+  public void test_null_value_in_row() throws InterpreterException {
+    sparkInterpreter.interpret("import org.apache.spark.sql._", context);
+    if (isDataFrameSupported()) {
+      sparkInterpreter.interpret(
+          "import org.apache.spark.sql.types.{StructType,StructField,StringType,IntegerType}",
+          context);
+    }
+    sparkInterpreter.interpret(
+        "def toInt(s:String): Any = {try { s.trim().toInt} catch {case e:Exception => null}}",
+        context);
+    sparkInterpreter.interpret(
+        "val schema = StructType(Seq(StructField(\"name\", StringType, false),StructField(\"age\" , IntegerType, true),StructField(\"other\" , StringType, false)))",
+        context);
+    sparkInterpreter.interpret(
+        "val csv = sc.parallelize(Seq((\"jobs, 51, apple\"), (\"gates, , microsoft\")))",
+        context);
+    sparkInterpreter.interpret(
+        "val raw = csv.map(_.split(\",\")).map(p => Row(p(0),toInt(p(1)),p(2)))",
+        context);
+    if (isDataFrameSupported()) {
+      sparkInterpreter.interpret("val people = sqlContext.createDataFrame(raw, schema)",
+          context);
+      sparkInterpreter.interpret("people.toDF.registerTempTable(\"people\")", context);
+    } else {
+      sparkInterpreter.interpret("val people = sqlContext.applySchema(raw, schema)",
+          context);
+      sparkInterpreter.interpret("people.registerTempTable(\"people\")", context);
+    }
+
+    InterpreterResult ret = sqlInterpreter.interpret(
+        "select name, age from people where name = 'gates'", context);
+    assertEquals(InterpreterResult.Code.SUCCESS, ret.code());
+    assertEquals(Type.TABLE, ret.message().get(0).getType());
+    assertEquals("name\tage\ngates\tnull\n", ret.message().get(0).getData());
+  }
+
+  @Test
+  public void testMaxResults() throws InterpreterException {
+    sparkInterpreter.interpret("case class P(age:Int)", context);
+    sparkInterpreter.interpret(
+        "val gr = sc.parallelize(Seq(P(1),P(2),P(3),P(4),P(5),P(6),P(7),P(8),P(9),P(10),P(11)))",
+        context);
+    if (isDataFrameSupported()) {
+      sparkInterpreter.interpret("gr.toDF.registerTempTable(\"gr\")", context);
+    } else {
+      sparkInterpreter.interpret("gr.registerTempTable(\"gr\")", context);
+    }
+
+    InterpreterResult ret = sqlInterpreter.interpret("select * from gr", context);
+    assertEquals(InterpreterResult.Code.SUCCESS, ret.code());
+    assertTrue(ret.message().get(1).getData().contains("alert-warning"));
+  }
+}

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/d762b528/spark/interpreter/src/test/java/org/apache/zeppelin/spark/OldSparkInterpreterTest.java
----------------------------------------------------------------------
diff --git a/spark/interpreter/src/test/java/org/apache/zeppelin/spark/OldSparkInterpreterTest.java b/spark/interpreter/src/test/java/org/apache/zeppelin/spark/OldSparkInterpreterTest.java
new file mode 100644
index 0000000..14214a2
--- /dev/null
+++ b/spark/interpreter/src/test/java/org/apache/zeppelin/spark/OldSparkInterpreterTest.java
@@ -0,0 +1,368 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.zeppelin.spark;
+
+import org.apache.spark.SparkConf;
+import org.apache.spark.SparkContext;
+import org.apache.zeppelin.display.AngularObjectRegistry;
+import org.apache.zeppelin.display.GUI;
+import org.apache.zeppelin.interpreter.Interpreter;
+import org.apache.zeppelin.interpreter.InterpreterContext;
+import org.apache.zeppelin.interpreter.InterpreterContextRunner;
+import org.apache.zeppelin.interpreter.InterpreterException;
+import org.apache.zeppelin.interpreter.InterpreterGroup;
+import org.apache.zeppelin.interpreter.InterpreterOutput;
+import org.apache.zeppelin.interpreter.InterpreterResult;
+import org.apache.zeppelin.interpreter.InterpreterResult.Code;
+import org.apache.zeppelin.interpreter.remote.RemoteEventClientWrapper;
+import org.apache.zeppelin.interpreter.thrift.InterpreterCompletion;
+import org.apache.zeppelin.resource.LocalResourcePool;
+import org.apache.zeppelin.resource.WellKnownResourceName;
+import org.apache.zeppelin.user.AuthenticationInfo;
+import org.junit.AfterClass;
+import org.junit.Assume;
+import org.junit.BeforeClass;
+import org.junit.ClassRule;
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.junit.runners.MethodSorters;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+public class OldSparkInterpreterTest {
+
+  @ClassRule
+  public static TemporaryFolder tmpDir = new TemporaryFolder();
+
+  static SparkInterpreter repl;
+  static InterpreterGroup intpGroup;
+  static InterpreterContext context;
+  static Logger LOGGER = LoggerFactory.getLogger(OldSparkInterpreterTest.class);
+  static Map<String, Map<String, String>> paraIdToInfosMap =
+      new HashMap<>();
+
+  /**
+   * Get spark version number as a numerical value.
+   * eg. 1.1.x => 11, 1.2.x => 12, 1.3.x => 13 ...
+   */
+  public static int getSparkVersionNumber(SparkInterpreter repl) {
+    if (repl == null) {
+      return 0;
+    }
+
+    String[] split = repl.getSparkContext().version().split("\\.");
+    int version = Integer.parseInt(split[0]) * 10 + Integer.parseInt(split[1]);
+    return version;
+  }
+
+  public static Properties getSparkTestProperties(TemporaryFolder tmpDir) throws IOException {
+    Properties p = new Properties();
+    p.setProperty("master", "local[*]");
+    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");
+    p.setProperty("zeppelin.dep.localrepo", tmpDir.newFolder().getAbsolutePath());
+    p.setProperty("zeppelin.spark.property_1", "value_1");
+    return p;
+  }
+
+  @BeforeClass
+  public static void setUp() throws Exception {
+    intpGroup = new InterpreterGroup();
+    intpGroup.put("note", new LinkedList<Interpreter>());
+    repl = new SparkInterpreter(getSparkTestProperties(tmpDir));
+    repl.setInterpreterGroup(intpGroup);
+    intpGroup.get("note").add(repl);
+    repl.open();
+
+    final RemoteEventClientWrapper remoteEventClientWrapper = new RemoteEventClientWrapper() {
+
+      @Override
+      public void onParaInfosReceived(String noteId, String paragraphId,
+          Map<String, String> infos) {
+        if (infos != null) {
+          paraIdToInfosMap.put(paragraphId, infos);
+        }
+      }
+
+      @Override
+      public void onMetaInfosReceived(Map<String, String> infos) {
+      }
+    };
+    context = new InterpreterContext("note", "id", null, "title", "text",
+        new AuthenticationInfo(),
+        new HashMap<String, Object>(),
+        new GUI(),
+        new GUI(),
+        new AngularObjectRegistry(intpGroup.getId(), null),
+        new LocalResourcePool("id"),
+        new LinkedList<InterpreterContextRunner>(),
+        new InterpreterOutput(null)) {
+        
+        @Override
+        public RemoteEventClientWrapper getClient() {
+          return remoteEventClientWrapper;
+        }
+    };
+    // The first para interpretdr will set the Eventclient wrapper
+    //SparkInterpreter.interpret(String, InterpreterContext) ->
+    //SparkInterpreter.populateSparkWebUrl(InterpreterContext) ->
+    //ZeppelinContext.setEventClient(RemoteEventClientWrapper)
+    //running a dummy to ensure that we dont have any race conditions among tests
+    repl.interpret("sc", context);
+  }
+
+  @AfterClass
+  public static void tearDown() throws InterpreterException {
+    repl.close();
+  }
+
+  @Test
+  public void testBasicIntp() throws InterpreterException {
+    assertEquals(InterpreterResult.Code.SUCCESS,
+        repl.interpret("val a = 1\nval b = 2", context).code());
+
+    // when interpret incomplete expression
+    InterpreterResult incomplete = repl.interpret("val a = \"\"\"", context);
+    assertEquals(InterpreterResult.Code.INCOMPLETE, incomplete.code());
+    assertTrue(incomplete.message().get(0).getData().length() > 0); // expecting some error
+                                                   // message
+
+    /*
+     * assertEquals(1, repl.getValue("a")); assertEquals(2, repl.getValue("b"));
+     * repl.interpret("val ver = sc.version");
+     * assertNotNull(repl.getValue("ver")); assertEquals("HELLO\n",
+     * repl.interpret("println(\"HELLO\")").message());
+     */
+  }
+
+  @Test
+  public void testNonStandardSparkProperties() throws IOException, InterpreterException {
+    // throw NoSuchElementException if no such property is found
+    InterpreterResult result = repl.interpret("sc.getConf.get(\"property_1\")", context);
+    assertEquals(InterpreterResult.Code.SUCCESS, result.code());
+  }
+
+  @Test
+  public void testNextLineInvocation() throws InterpreterException {
+    assertEquals(InterpreterResult.Code.SUCCESS, repl.interpret("\"123\"\n.toInt", context).code());
+  }
+
+  @Test
+  public void testNextLineComments() throws InterpreterException {
+    assertEquals(InterpreterResult.Code.SUCCESS, repl.interpret("\"123\"\n/*comment here\n*/.toInt", context).code());
+  }
+
+  @Test
+  public void testNextLineCompanionObject() throws InterpreterException {
+    String code = "class Counter {\nvar value: Long = 0\n}\n // comment\n\n object Counter {\n def apply(x: Long) = new Counter()\n}";
+    assertEquals(InterpreterResult.Code.SUCCESS, repl.interpret(code, context).code());
+  }
+
+  @Test
+  public void testEndWithComment() throws InterpreterException {
+    assertEquals(InterpreterResult.Code.SUCCESS, repl.interpret("val c=1\n//comment", context).code());
+  }
+
+  @Test
+  public void testListener() {
+    SparkContext sc = repl.getSparkContext();
+    assertNotNull(OldSparkInterpreter.setupListeners(sc));
+  }
+
+  @Test
+  public void testCreateDataFrame() throws InterpreterException {
+    if (getSparkVersionNumber(repl) >= 13) {
+      repl.interpret("case class Person(name:String, age:Int)\n", context);
+      repl.interpret("val people = sc.parallelize(Seq(Person(\"moon\", 33), Person(\"jobs\", 51), Person(\"gates\", 51), Person(\"park\", 34)))\n", context);
+      repl.interpret("people.toDF.count", context);
+      assertEquals(new Long(4), context.getResourcePool().get(
+          context.getNoteId(),
+          context.getParagraphId(),
+          WellKnownResourceName.ZeppelinReplResult.toString()).get());
+    }
+  }
+
+  @Test
+  public void testZShow() throws InterpreterException {
+    String code = "";
+    repl.interpret("case class Person(name:String, age:Int)\n", context);
+    repl.interpret("val people = sc.parallelize(Seq(Person(\"moon\", 33), Person(\"jobs\", 51), Person(\"gates\", 51), Person(\"park\", 34)))\n", context);
+    if (getSparkVersionNumber(repl) < 13) {
+      repl.interpret("people.registerTempTable(\"people\")", context);
+      code = "z.show(sqlc.sql(\"select * from people\"))";
+    } else {
+      code = "z.show(people.toDF)";
+    }
+      assertEquals(Code.SUCCESS, repl.interpret(code, context).code());
+  }
+
+  @Test
+  public void testSparkSql() throws IOException, InterpreterException {
+    repl.interpret("case class Person(name:String, age:Int)\n", context);
+    repl.interpret("val people = sc.parallelize(Seq(Person(\"moon\", 33), Person(\"jobs\", 51), Person(\"gates\", 51), Person(\"park\", 34)))\n", context);
+    assertEquals(Code.SUCCESS, repl.interpret("people.take(3)", context).code());
+
+
+    if (getSparkVersionNumber(repl) <= 11) { // spark 1.2 or later does not allow create multiple
+      // SparkContext in the same jvm by default.
+      // create new interpreter
+      SparkInterpreter repl2 = new SparkInterpreter(getSparkTestProperties(tmpDir));
+      repl2.setInterpreterGroup(intpGroup);
+      intpGroup.get("note").add(repl2);
+      repl2.open();
+
+      repl2.interpret("case class Man(name:String, age:Int)", context);
+      repl2.interpret("val man = sc.parallelize(Seq(Man(\"moon\", 33), Man(\"jobs\", 51), Man(\"gates\", 51), Man(\"park\", 34)))", context);
+      assertEquals(Code.SUCCESS, repl2.interpret("man.take(3)", context).code());
+      repl2.close();
+    }
+  }
+
+  @Test
+  public void testReferencingUndefinedVal() throws InterpreterException {
+    InterpreterResult result = repl.interpret("def category(min: Int) = {"
+        + "    if (0 <= value) \"error\"" + "}", context);
+    assertEquals(Code.ERROR, result.code());
+  }
+
+  @Test
+  public void emptyConfigurationVariablesOnlyForNonSparkProperties() {
+    Properties intpProperty = repl.getProperties();
+    SparkConf sparkConf = repl.getSparkContext().getConf();
+    for (Object oKey : intpProperty.keySet()) {
+      String key = (String) oKey;
+      String value = (String) intpProperty.get(key);
+      LOGGER.debug(String.format("[%s]: [%s]", key, value));
+      if (key.startsWith("spark.") && value.isEmpty()) {
+        assertTrue(String.format("configuration starting from 'spark.' should not be empty. [%s]", key), !sparkConf.contains(key) || !sparkConf.get(key).isEmpty());
+      }
+    }
+  }
+
+  @Test
+  public void shareSingleSparkContext() throws InterruptedException, IOException, InterpreterException {
+    // create another SparkInterpreter
+    SparkInterpreter repl2 = new SparkInterpreter(getSparkTestProperties(tmpDir));
+    repl2.setInterpreterGroup(intpGroup);
+    intpGroup.get("note").add(repl2);
+    repl2.open();
+
+    assertEquals(Code.SUCCESS,
+        repl.interpret("print(sc.parallelize(1 to 10).count())", context).code());
+    assertEquals(Code.SUCCESS,
+        repl2.interpret("print(sc.parallelize(1 to 10).count())", context).code());
+
+    repl2.close();
+  }
+
+  @Test
+  public void testEnableImplicitImport() throws IOException, InterpreterException {
+    if (getSparkVersionNumber(repl) >= 13) {
+      // Set option of importing implicits to "true", and initialize new Spark repl
+      Properties p = getSparkTestProperties(tmpDir);
+      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() throws IOException, InterpreterException {
+    if (getSparkVersionNumber(repl) >= 13) {
+      // 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(tmpDir);
+      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();
+    }
+  }
+
+  @Test
+  public void testCompletion() throws InterpreterException {
+    List<InterpreterCompletion> completions = repl.completion("sc.", "sc.".length(), null);
+    assertTrue(completions.size() > 0);
+  }
+
+  @Test
+  public void testMultilineCompletion() throws InterpreterException {
+    String buf = "val x = 1\nsc.";
+	List<InterpreterCompletion> completions = repl.completion(buf, buf.length(), null);
+    assertTrue(completions.size() > 0);
+  }
+
+  @Test
+  public void testMultilineCompletionNewVar() throws InterpreterException {
+    Assume.assumeFalse("this feature does not work with scala 2.10", Utils.isScala2_10());
+    Assume.assumeTrue("This feature does not work with scala < 2.11.8", Utils.isCompilerAboveScala2_11_7());
+    String buf = "val x = sc\nx.";
+	  List<InterpreterCompletion> completions = repl.completion(buf, buf.length(), null);
+    assertTrue(completions.size() > 0);
+  }
+
+  @Test
+  public void testParagraphUrls() throws InterpreterException {
+    String paraId = "test_para_job_url";
+    InterpreterContext intpCtx = new InterpreterContext("note", paraId, null, "title", "text",
+        new AuthenticationInfo(),
+        new HashMap<String, Object>(),
+        new GUI(),
+        new GUI(),
+        new AngularObjectRegistry(intpGroup.getId(), null),
+        new LocalResourcePool("id"),
+        new LinkedList<InterpreterContextRunner>(),
+        new InterpreterOutput(null));
+    repl.interpret("sc.parallelize(1 to 10).map(x => {x}).collect", intpCtx);
+    Map<String, String> paraInfos = paraIdToInfosMap.get(intpCtx.getParagraphId());
+    String jobUrl = null;
+    if (paraInfos != null) {
+      jobUrl = paraInfos.get("jobUrl");
+    }
+    String sparkUIUrl = repl.getSparkUIUrl();
+    assertNotNull(jobUrl);
+    assertTrue(jobUrl.startsWith(sparkUIUrl + "/jobs/job/?id="));
+
+  }
+}

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/d762b528/spark/interpreter/src/test/java/org/apache/zeppelin/spark/OldSparkSqlInterpreterTest.java
----------------------------------------------------------------------
diff --git a/spark/interpreter/src/test/java/org/apache/zeppelin/spark/OldSparkSqlInterpreterTest.java b/spark/interpreter/src/test/java/org/apache/zeppelin/spark/OldSparkSqlInterpreterTest.java
new file mode 100644
index 0000000..d0b0874
--- /dev/null
+++ b/spark/interpreter/src/test/java/org/apache/zeppelin/spark/OldSparkSqlInterpreterTest.java
@@ -0,0 +1,189 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.zeppelin.spark;
+
+import org.apache.zeppelin.display.AngularObjectRegistry;
+import org.apache.zeppelin.display.GUI;
+import org.apache.zeppelin.interpreter.Interpreter;
+import org.apache.zeppelin.interpreter.InterpreterContext;
+import org.apache.zeppelin.interpreter.InterpreterContextRunner;
+import org.apache.zeppelin.interpreter.InterpreterException;
+import org.apache.zeppelin.interpreter.InterpreterGroup;
+import org.apache.zeppelin.interpreter.InterpreterOutput;
+import org.apache.zeppelin.interpreter.InterpreterResult;
+import org.apache.zeppelin.interpreter.InterpreterResult.Type;
+import org.apache.zeppelin.resource.LocalResourcePool;
+import org.apache.zeppelin.user.AuthenticationInfo;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.Properties;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+public class OldSparkSqlInterpreterTest {
+
+  @ClassRule
+  public static TemporaryFolder tmpDir = new TemporaryFolder();
+
+  static SparkSqlInterpreter sql;
+  static SparkInterpreter repl;
+  static InterpreterContext context;
+  static InterpreterGroup intpGroup;
+
+  @BeforeClass
+  public static void setUp() throws Exception {
+    Properties p = new Properties();
+    p.putAll(OldSparkInterpreterTest.getSparkTestProperties(tmpDir));
+    p.setProperty("zeppelin.spark.maxResult", "10");
+    p.setProperty("zeppelin.spark.concurrentSQL", "false");
+    p.setProperty("zeppelin.spark.sql.stacktrace", "false");
+
+    repl = new SparkInterpreter(p);
+    intpGroup = new InterpreterGroup();
+    repl.setInterpreterGroup(intpGroup);
+    repl.open();
+    OldSparkInterpreterTest.repl = repl;
+    OldSparkInterpreterTest.intpGroup = intpGroup;
+
+    sql = new SparkSqlInterpreter(p);
+
+    intpGroup = new InterpreterGroup();
+    intpGroup.put("note", new LinkedList<Interpreter>());
+    intpGroup.get("note").add(repl);
+    intpGroup.get("note").add(sql);
+    sql.setInterpreterGroup(intpGroup);
+    sql.open();
+
+    context = new InterpreterContext("note", "id", null, "title", "text", new AuthenticationInfo(),
+        new HashMap<String, Object>(), new GUI(), new GUI(),
+        new AngularObjectRegistry(intpGroup.getId(), null),
+        new LocalResourcePool("id"),
+        new LinkedList<InterpreterContextRunner>(), new InterpreterOutput(null));
+  }
+
+  @AfterClass
+  public static void tearDown() throws InterpreterException {
+    sql.close();
+    repl.close();
+  }
+
+  boolean isDataFrameSupported() {
+    return OldSparkInterpreterTest.getSparkVersionNumber(repl) >= 13;
+  }
+
+  @Test
+  public void test() throws InterpreterException {
+    repl.interpret("case class Test(name:String, age:Int)", context);
+    repl.interpret("val test = sc.parallelize(Seq(Test(\"moon\", 33), Test(\"jobs\", 51), Test(\"gates\", 51), Test(\"park\", 34)))", context);
+    if (isDataFrameSupported()) {
+      repl.interpret("test.toDF.registerTempTable(\"test\")", context);
+    } else {
+      repl.interpret("test.registerTempTable(\"test\")", context);
+    }
+
+    InterpreterResult ret = sql.interpret("select name, age from test where age < 40", context);
+    assertEquals(InterpreterResult.Code.SUCCESS, ret.code());
+    assertEquals(Type.TABLE, ret.message().get(0).getType());
+    assertEquals("name\tage\nmoon\t33\npark\t34\n", ret.message().get(0).getData());
+
+    ret = sql.interpret("select wrong syntax", context);
+    assertEquals(InterpreterResult.Code.ERROR, ret.code());
+    assertTrue(ret.message().get(0).getData().length() > 0);
+
+    assertEquals(InterpreterResult.Code.SUCCESS, sql.interpret("select case when name==\"aa\" then name else name end from test", context).code());
+  }
+
+  @Test
+  public void testStruct() throws InterpreterException {
+    repl.interpret("case class Person(name:String, age:Int)", context);
+    repl.interpret("case class People(group:String, person:Person)", context);
+    repl.interpret(
+        "val gr = sc.parallelize(Seq(People(\"g1\", Person(\"moon\",33)), People(\"g2\", Person(\"sun\",11))))",
+        context);
+    if (isDataFrameSupported()) {
+      repl.interpret("gr.toDF.registerTempTable(\"gr\")", context);
+    } else {
+      repl.interpret("gr.registerTempTable(\"gr\")", context);
+    }
+
+    InterpreterResult ret = sql.interpret("select * from gr", context);
+    assertEquals(InterpreterResult.Code.SUCCESS, ret.code());
+  }
+
+  @Test
+  public void test_null_value_in_row() throws InterpreterException {
+    repl.interpret("import org.apache.spark.sql._", context);
+    if (isDataFrameSupported()) {
+      repl.interpret(
+          "import org.apache.spark.sql.types.{StructType,StructField,StringType,IntegerType}",
+          context);
+    }
+    repl.interpret(
+        "def toInt(s:String): Any = {try { s.trim().toInt} catch {case e:Exception => null}}",
+        context);
+    repl.interpret(
+        "val schema = StructType(Seq(StructField(\"name\", StringType, false),StructField(\"age\" , IntegerType, true),StructField(\"other\" , StringType, false)))",
+        context);
+    repl.interpret(
+        "val csv = sc.parallelize(Seq((\"jobs, 51, apple\"), (\"gates, , microsoft\")))",
+        context);
+    repl.interpret(
+        "val raw = csv.map(_.split(\",\")).map(p => Row(p(0),toInt(p(1)),p(2)))",
+        context);
+    if (isDataFrameSupported()) {
+      repl.interpret("val people = sqlContext.createDataFrame(raw, schema)",
+          context);
+      repl.interpret("people.toDF.registerTempTable(\"people\")", context);
+    } else {
+      repl.interpret("val people = sqlContext.applySchema(raw, schema)",
+          context);
+      repl.interpret("people.registerTempTable(\"people\")", context);
+    }
+
+    InterpreterResult ret = sql.interpret(
+        "select name, age from people where name = 'gates'", context);
+    System.err.println("RET=" + ret.message());
+    assertEquals(InterpreterResult.Code.SUCCESS, ret.code());
+    assertEquals(Type.TABLE, ret.message().get(0).getType());
+    assertEquals("name\tage\ngates\tnull\n", ret.message().get(0).getData());
+  }
+
+  @Test
+  public void testMaxResults() throws InterpreterException {
+    repl.interpret("case class P(age:Int)", context);
+    repl.interpret(
+        "val gr = sc.parallelize(Seq(P(1),P(2),P(3),P(4),P(5),P(6),P(7),P(8),P(9),P(10),P(11)))",
+        context);
+    if (isDataFrameSupported()) {
+      repl.interpret("gr.toDF.registerTempTable(\"gr\")", context);
+    } else {
+      repl.interpret("gr.registerTempTable(\"gr\")", context);
+    }
+
+    InterpreterResult ret = sql.interpret("select * from gr", context);
+    assertEquals(InterpreterResult.Code.SUCCESS, ret.code());
+    assertTrue(ret.message().get(1).getData().contains("alert-warning"));
+  }
+}

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/d762b528/spark/interpreter/src/test/java/org/apache/zeppelin/spark/PySparkInterpreterMatplotlibTest.java
----------------------------------------------------------------------
diff --git a/spark/interpreter/src/test/java/org/apache/zeppelin/spark/PySparkInterpreterMatplotlibTest.java b/spark/interpreter/src/test/java/org/apache/zeppelin/spark/PySparkInterpreterMatplotlibTest.java
new file mode 100644
index 0000000..2d40871
--- /dev/null
+++ b/spark/interpreter/src/test/java/org/apache/zeppelin/spark/PySparkInterpreterMatplotlibTest.java
@@ -0,0 +1,250 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.zeppelin.spark;
+
+import org.apache.zeppelin.display.AngularObjectRegistry;
+import org.apache.zeppelin.display.GUI;
+import org.apache.zeppelin.interpreter.*;
+import org.apache.zeppelin.interpreter.InterpreterResult.Type;
+import org.apache.zeppelin.resource.LocalResourcePool;
+import org.apache.zeppelin.user.AuthenticationInfo;
+import org.junit.*;
+import org.junit.rules.TemporaryFolder;
+import org.junit.runners.MethodSorters;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Properties;
+
+import static org.junit.Assert.*;
+
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+public class PySparkInterpreterMatplotlibTest {
+
+  @ClassRule
+  public static TemporaryFolder tmpDir = new TemporaryFolder();
+
+  static SparkInterpreter sparkInterpreter;
+  static PySparkInterpreter pyspark;
+  static InterpreterGroup intpGroup;
+  static Logger LOGGER = LoggerFactory.getLogger(PySparkInterpreterTest.class);
+  static InterpreterContext context;
+
+  public static class AltPySparkInterpreter extends PySparkInterpreter {
+    /**
+     * Since pyspark output is  sent to an outputstream rather than
+     * being directly provided by interpret(), this subclass is created to
+     * override interpret() to append the result from the outputStream
+     * for the sake of convenience in testing.
+     */
+    public AltPySparkInterpreter(Properties property) {
+      super(property);
+    }
+
+    /**
+     * This code is mainly copied from RemoteInterpreterServer.java which
+     * normally handles this in real use cases.
+     */
+    @Override
+    public InterpreterResult interpret(String st, InterpreterContext context) throws InterpreterException {
+      context.out.clear();
+      InterpreterResult result = super.interpret(st, context);
+      List<InterpreterResultMessage> resultMessages = null;
+      try {
+        context.out.flush();
+        resultMessages = context.out.toInterpreterResultMessage();
+      } catch (IOException e) {
+        e.printStackTrace();
+      }
+      resultMessages.addAll(result.message());
+
+      return new InterpreterResult(result.code(), resultMessages);
+    }
+  }
+
+  private static Properties getPySparkTestProperties() throws IOException {
+    Properties p = new Properties();
+    p.setProperty("spark.master", "local[*]");
+    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");
+    p.setProperty("zeppelin.pyspark.python", "python");
+    p.setProperty("zeppelin.dep.localrepo", tmpDir.newFolder().getAbsolutePath());
+    p.setProperty("zeppelin.pyspark.useIPython", "false");
+    return p;
+  }
+
+  /**
+   * Get spark version number as a numerical value.
+   * eg. 1.1.x => 11, 1.2.x => 12, 1.3.x => 13 ...
+   */
+  public static int getSparkVersionNumber() {
+    if (sparkInterpreter == null) {
+      return 0;
+    }
+
+    String[] split = sparkInterpreter.getSparkContext().version().split("\\.");
+    int version = Integer.parseInt(split[0]) * 10 + Integer.parseInt(split[1]);
+    return version;
+  }
+
+  @BeforeClass
+  public static void setUp() throws Exception {
+    intpGroup = new InterpreterGroup();
+    intpGroup.put("note", new LinkedList<Interpreter>());
+    context = new InterpreterContext("note", "id", null, "title", "text",
+        new AuthenticationInfo(),
+        new HashMap<String, Object>(),
+        new GUI(),
+        new GUI(),
+        new AngularObjectRegistry(intpGroup.getId(), null),
+        new LocalResourcePool("id"),
+        new LinkedList<InterpreterContextRunner>(),
+        new InterpreterOutput(null));
+    InterpreterContext.set(context);
+
+    sparkInterpreter = new SparkInterpreter(getPySparkTestProperties());
+    intpGroup.get("note").add(sparkInterpreter);
+    sparkInterpreter.setInterpreterGroup(intpGroup);
+    sparkInterpreter.open();
+
+    pyspark = new AltPySparkInterpreter(getPySparkTestProperties());
+    intpGroup.get("note").add(pyspark);
+    pyspark.setInterpreterGroup(intpGroup);
+    pyspark.open();
+
+    context = new InterpreterContext("note", "id", null, "title", "text",
+        new AuthenticationInfo(),
+        new HashMap<String, Object>(),
+        new GUI(),
+        new GUI(),
+        new AngularObjectRegistry(intpGroup.getId(), null),
+        new LocalResourcePool("id"),
+        new LinkedList<InterpreterContextRunner>(),
+        new InterpreterOutput(null));
+  }
+
+  @AfterClass
+  public static void tearDown() throws InterpreterException {
+    pyspark.close();
+    sparkInterpreter.close();
+  }
+
+  @Test
+  public void dependenciesAreInstalled() throws InterpreterException {
+    // matplotlib
+    InterpreterResult ret = pyspark.interpret("import matplotlib", context);
+    assertEquals(ret.message().toString(), InterpreterResult.Code.SUCCESS, ret.code());
+
+    // inline backend
+    ret = pyspark.interpret("import backend_zinline", context);
+    assertEquals(ret.message().toString(), InterpreterResult.Code.SUCCESS, ret.code());
+  }
+
+  @Test
+  public void showPlot() throws InterpreterException {
+    // Simple plot test
+    InterpreterResult ret;
+    ret = pyspark.interpret("import matplotlib.pyplot as plt", context);
+    ret = pyspark.interpret("plt.close()", context);
+    ret = pyspark.interpret("z.configure_mpl(interactive=False)", context);
+    ret = pyspark.interpret("plt.plot([1, 2, 3])", context);
+    ret = pyspark.interpret("plt.show()", context);
+
+    assertEquals(ret.message().toString(), InterpreterResult.Code.SUCCESS, ret.code());
+    assertEquals(ret.message().toString(), Type.HTML, ret.message().get(0).getType());
+    assertTrue(ret.message().get(0).getData().contains("data:image/png;base64"));
+    assertTrue(ret.message().get(0).getData().contains("<div>"));
+  }
+
+  @Test
+  // Test for when configuration is set to auto-close figures after show().
+  public void testClose() throws InterpreterException {
+    InterpreterResult ret;
+    InterpreterResult ret1;
+    InterpreterResult ret2;
+    ret = pyspark.interpret("import matplotlib.pyplot as plt", context);
+    ret = pyspark.interpret("plt.close()", context);
+    ret = pyspark.interpret("z.configure_mpl(interactive=False, close=True, angular=False)", context);
+    ret = pyspark.interpret("plt.plot([1, 2, 3])", context);
+    ret1 = pyspark.interpret("plt.show()", context);
+
+    // Second call to show() should print nothing, and Type should be TEXT.
+    // This is because when close=True, there should be no living instances
+    // of FigureManager, causing show() to return before setting the output
+    // type to HTML.
+    ret = pyspark.interpret("plt.show()", context);
+    assertEquals(0, ret.message().size());
+
+    // Now test that new plot is drawn. It should be identical to the
+    // previous one.
+    ret = pyspark.interpret("plt.plot([1, 2, 3])", context);
+    ret2 = pyspark.interpret("plt.show()", context);
+    assertEquals(ret1.message().get(0).getType(), ret2.message().get(0).getType());
+    assertEquals(ret1.message().get(0).getData(), ret2.message().get(0).getData());
+  }
+
+  @Test
+  // Test for when configuration is set to not auto-close figures after show().
+  public void testNoClose() throws InterpreterException {
+    InterpreterResult ret;
+    InterpreterResult ret1;
+    InterpreterResult ret2;
+    ret = pyspark.interpret("import matplotlib.pyplot as plt", context);
+    ret = pyspark.interpret("plt.close()", context);
+    ret = pyspark.interpret("z.configure_mpl(interactive=False, close=False, angular=False)", context);
+    ret = pyspark.interpret("plt.plot([1, 2, 3])", context);
+    ret1 = pyspark.interpret("plt.show()", context);
+
+    // Second call to show() should print nothing, and Type should be HTML.
+    // This is because when close=False, there should be living instances
+    // of FigureManager, causing show() to set the output
+    // type to HTML even though the figure is inactive.
+    ret = pyspark.interpret("plt.show()", context);
+    assertEquals(ret.message().toString(), InterpreterResult.Code.SUCCESS, ret.code());
+
+    // Now test that plot can be reshown if it is updated. It should be
+    // different from the previous one because it will plot the same line
+    // again but in a different color.
+    ret = pyspark.interpret("plt.plot([1, 2, 3])", context);
+    ret2 = pyspark.interpret("plt.show()", context);
+    assertNotSame(ret1.message().get(0).getData(), ret2.message().get(0).getData());
+  }
+
+  @Test
+  // Test angular mode
+  public void testAngular() throws InterpreterException {
+    InterpreterResult ret;
+    ret = pyspark.interpret("import matplotlib.pyplot as plt", context);
+    ret = pyspark.interpret("plt.close()", context);
+    ret = pyspark.interpret("z.configure_mpl(interactive=False, close=False, angular=True)", context);
+    ret = pyspark.interpret("plt.plot([1, 2, 3])", context);
+    ret = pyspark.interpret("plt.show()", context);
+    assertEquals(ret.message().toString(), InterpreterResult.Code.SUCCESS, ret.code());
+    assertEquals(ret.message().toString(), Type.ANGULAR, ret.message().get(0).getType());
+
+    // Check if the figure data is in the Angular Object Registry
+    AngularObjectRegistry registry = context.getAngularObjectRegistry();
+    String figureData = registry.getAll("note", null).get(0).toString();
+    assertTrue(figureData.contains("data:image/png;base64"));
+  }
+}

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/d762b528/spark/interpreter/src/test/java/org/apache/zeppelin/spark/PySparkInterpreterTest.java
----------------------------------------------------------------------
diff --git a/spark/interpreter/src/test/java/org/apache/zeppelin/spark/PySparkInterpreterTest.java b/spark/interpreter/src/test/java/org/apache/zeppelin/spark/PySparkInterpreterTest.java
new file mode 100644
index 0000000..00972b4
--- /dev/null
+++ b/spark/interpreter/src/test/java/org/apache/zeppelin/spark/PySparkInterpreterTest.java
@@ -0,0 +1,193 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.zeppelin.spark;
+
+import org.apache.zeppelin.display.AngularObjectRegistry;
+import org.apache.zeppelin.display.GUI;
+import org.apache.zeppelin.interpreter.*;
+import org.apache.zeppelin.interpreter.thrift.InterpreterCompletion;
+import org.apache.zeppelin.resource.LocalResourcePool;
+import org.apache.zeppelin.user.AuthenticationInfo;
+import org.junit.*;
+import org.junit.rules.TemporaryFolder;
+import org.junit.runners.MethodSorters;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Properties;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import static org.junit.Assert.*;
+
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+public class PySparkInterpreterTest {
+
+  @ClassRule
+  public static TemporaryFolder tmpDir = new TemporaryFolder();
+
+  static SparkInterpreter sparkInterpreter;
+  static PySparkInterpreter pySparkInterpreter;
+  static InterpreterGroup intpGroup;
+  static InterpreterContext context;
+
+  private static Properties getPySparkTestProperties() throws IOException {
+    Properties p = new Properties();
+    p.setProperty("spark.master", "local");
+    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");
+    p.setProperty("zeppelin.pyspark.python", "python");
+    p.setProperty("zeppelin.dep.localrepo", tmpDir.newFolder().getAbsolutePath());
+    p.setProperty("zeppelin.pyspark.useIPython", "false");
+    p.setProperty("zeppelin.spark.test", "true");
+    return p;
+  }
+
+  /**
+   * Get spark version number as a numerical value.
+   * eg. 1.1.x => 11, 1.2.x => 12, 1.3.x => 13 ...
+   */
+  public static int getSparkVersionNumber() {
+    if (sparkInterpreter == null) {
+      return 0;
+    }
+
+    String[] split = sparkInterpreter.getSparkContext().version().split("\\.");
+    int version = Integer.parseInt(split[0]) * 10 + Integer.parseInt(split[1]);
+    return version;
+  }
+
+  @BeforeClass
+  public static void setUp() throws Exception {
+    intpGroup = new InterpreterGroup();
+    intpGroup.put("note", new LinkedList<Interpreter>());
+
+    context = new InterpreterContext("note", "id", null, "title", "text",
+        new AuthenticationInfo(),
+        new HashMap<String, Object>(),
+        new GUI(),
+        new GUI(),
+        new AngularObjectRegistry(intpGroup.getId(), null),
+        new LocalResourcePool("id"),
+        new LinkedList<InterpreterContextRunner>(),
+        new InterpreterOutput(null));
+    InterpreterContext.set(context);
+
+    sparkInterpreter = new SparkInterpreter(getPySparkTestProperties());
+    intpGroup.get("note").add(sparkInterpreter);
+    sparkInterpreter.setInterpreterGroup(intpGroup);
+    sparkInterpreter.open();
+
+    pySparkInterpreter = new PySparkInterpreter(getPySparkTestProperties());
+    intpGroup.get("note").add(pySparkInterpreter);
+    pySparkInterpreter.setInterpreterGroup(intpGroup);
+    pySparkInterpreter.open();
+
+
+  }
+
+  @AfterClass
+  public static void tearDown() throws InterpreterException {
+    pySparkInterpreter.close();
+    sparkInterpreter.close();
+  }
+
+  @Test
+  public void testBasicIntp() throws InterpreterException {
+    if (getSparkVersionNumber() > 11) {
+      assertEquals(InterpreterResult.Code.SUCCESS,
+        pySparkInterpreter.interpret("a = 1\n", context).code());
+    }
+
+    InterpreterResult result = pySparkInterpreter.interpret(
+        "from pyspark.streaming import StreamingContext\n" +
+            "import time\n" +
+            "ssc = StreamingContext(sc, 1)\n" +
+            "rddQueue = []\n" +
+            "for i in range(5):\n" +
+            "    rddQueue += [ssc.sparkContext.parallelize([j for j in range(1, 1001)], 10)]\n" +
+            "inputStream = ssc.queueStream(rddQueue)\n" +
+            "mappedStream = inputStream.map(lambda x: (x % 10, 1))\n" +
+            "reducedStream = mappedStream.reduceByKey(lambda a, b: a + b)\n" +
+            "reducedStream.pprint()\n" +
+            "ssc.start()\n" +
+            "time.sleep(6)\n" +
+            "ssc.stop(stopSparkContext=False, stopGraceFully=True)", context);
+    assertEquals(InterpreterResult.Code.SUCCESS, result.code());
+  }
+
+  @Test
+  public void testCompletion() throws InterpreterException {
+    if (getSparkVersionNumber() > 11) {
+      List<InterpreterCompletion> completions = pySparkInterpreter.completion("sc.", "sc.".length(), null);
+      assertTrue(completions.size() > 0);
+    }
+  }
+
+  @Test
+  public void testRedefinitionZeppelinContext() throws InterpreterException {
+    if (getSparkVersionNumber() > 11) {
+      String redefinitionCode = "z = 1\n";
+      String restoreCode = "z = __zeppelin__\n";
+      String validCode = "z.input(\"test\")\n";
+
+      assertEquals(InterpreterResult.Code.SUCCESS, pySparkInterpreter.interpret(validCode, context).code());
+      assertEquals(InterpreterResult.Code.SUCCESS, pySparkInterpreter.interpret(redefinitionCode, context).code());
+      assertEquals(InterpreterResult.Code.ERROR, pySparkInterpreter.interpret(validCode, context).code());
+      assertEquals(InterpreterResult.Code.SUCCESS, pySparkInterpreter.interpret(restoreCode, context).code());
+      assertEquals(InterpreterResult.Code.SUCCESS, pySparkInterpreter.interpret(validCode, context).code());
+    }
+  }
+
+  private class infinityPythonJob implements Runnable {
+    @Override
+    public void run() {
+      String code = "import time\nwhile True:\n  time.sleep(1)" ;
+      InterpreterResult ret = null;
+      try {
+        ret = pySparkInterpreter.interpret(code, context);
+      } catch (InterpreterException e) {
+        e.printStackTrace();
+      }
+      assertNotNull(ret);
+      Pattern expectedMessage = Pattern.compile("KeyboardInterrupt");
+      Matcher m = expectedMessage.matcher(ret.message().toString());
+      assertTrue(m.find());
+    }
+  }
+
+  @Test
+  public void testCancelIntp() throws InterruptedException, InterpreterException {
+    if (getSparkVersionNumber() > 11) {
+      assertEquals(InterpreterResult.Code.SUCCESS,
+        pySparkInterpreter.interpret("a = 1\n", context).code());
+
+      Thread t = new Thread(new infinityPythonJob());
+      t.start();
+      Thread.sleep(5000);
+      pySparkInterpreter.cancel(context);
+      assertTrue(t.isAlive());
+      t.join(2000);
+      assertFalse(t.isAlive());
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/d762b528/spark/interpreter/src/test/java/org/apache/zeppelin/spark/SparkRInterpreterTest.java
----------------------------------------------------------------------
diff --git a/spark/interpreter/src/test/java/org/apache/zeppelin/spark/SparkRInterpreterTest.java b/spark/interpreter/src/test/java/org/apache/zeppelin/spark/SparkRInterpreterTest.java
new file mode 100644
index 0000000..2d585f5
--- /dev/null
+++ b/spark/interpreter/src/test/java/org/apache/zeppelin/spark/SparkRInterpreterTest.java
@@ -0,0 +1,99 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.zeppelin.spark;
+
+import org.apache.zeppelin.display.AngularObjectRegistry;
+import org.apache.zeppelin.display.GUI;
+import org.apache.zeppelin.interpreter.InterpreterContext;
+import org.apache.zeppelin.interpreter.InterpreterException;
+import org.apache.zeppelin.interpreter.InterpreterGroup;
+import org.apache.zeppelin.interpreter.InterpreterResult;
+import org.apache.zeppelin.interpreter.LazyOpenInterpreter;
+import org.apache.zeppelin.user.AuthenticationInfo;
+import org.junit.Test;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Properties;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+public class SparkRInterpreterTest {
+
+  private SparkRInterpreter sparkRInterpreter;
+  private SparkInterpreter sparkInterpreter;
+
+
+  @Test
+  public void testSparkRInterpreter() throws IOException, InterruptedException, InterpreterException {
+    Properties properties = new Properties();
+    properties.setProperty("spark.master", "local");
+    properties.setProperty("spark.app.name", "test");
+    properties.setProperty("zeppelin.spark.maxResult", "100");
+    properties.setProperty("zeppelin.spark.test", "true");
+    properties.setProperty("zeppelin.spark.useNew", "true");
+    properties.setProperty("zeppelin.R.knitr", "true");
+
+    sparkRInterpreter = new SparkRInterpreter(properties);
+    sparkInterpreter = new SparkInterpreter(properties);
+
+    InterpreterGroup interpreterGroup = new InterpreterGroup();
+    interpreterGroup.addInterpreterToSession(new LazyOpenInterpreter(sparkRInterpreter), "session_1");
+    interpreterGroup.addInterpreterToSession(new LazyOpenInterpreter(sparkInterpreter), "session_1");
+    sparkRInterpreter.setInterpreterGroup(interpreterGroup);
+    sparkInterpreter.setInterpreterGroup(interpreterGroup);
+
+    sparkRInterpreter.open();
+
+    InterpreterResult result = sparkRInterpreter.interpret("1+1", getInterpreterContext());
+    assertEquals(InterpreterResult.Code.SUCCESS, result.code());
+    assertTrue(result.message().get(0).getData().contains("2"));
+
+    result = sparkRInterpreter.interpret("sparkR.version()", getInterpreterContext());
+    assertEquals(InterpreterResult.Code.SUCCESS, result.code());
+    if (result.message().get(0).getData().contains("2.")) {
+      // spark 2.x
+      result = sparkRInterpreter.interpret("df <- as.DataFrame(faithful)\nhead(df)", getInterpreterContext());
+      assertEquals(InterpreterResult.Code.SUCCESS, result.code());
+      assertTrue(result.message().get(0).getData().contains("eruptions waiting"));
+    } else {
+      // spark 1.x
+      result = sparkRInterpreter.interpret("df <- createDataFrame(sqlContext, faithful)\nhead(df)", getInterpreterContext());
+      assertEquals(InterpreterResult.Code.SUCCESS, result.code());
+      assertTrue(result.message().get(0).getData().contains("eruptions waiting"));
+    }
+  }
+
+  private InterpreterContext getInterpreterContext() {
+    return new InterpreterContext(
+        "noteId",
+        "paragraphId",
+        "replName",
+        "paragraphTitle",
+        "paragraphText",
+        new AuthenticationInfo(),
+        new HashMap<String, Object>(),
+        new GUI(),
+        new GUI(),
+        new AngularObjectRegistry("spark", null),
+        null,
+        null,
+        null);
+  }
+}

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/d762b528/spark/interpreter/src/test/java/org/apache/zeppelin/spark/SparkVersionTest.java
----------------------------------------------------------------------
diff --git a/spark/interpreter/src/test/java/org/apache/zeppelin/spark/SparkVersionTest.java b/spark/interpreter/src/test/java/org/apache/zeppelin/spark/SparkVersionTest.java
new file mode 100644
index 0000000..3dc8f4e
--- /dev/null
+++ b/spark/interpreter/src/test/java/org/apache/zeppelin/spark/SparkVersionTest.java
@@ -0,0 +1,71 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.zeppelin.spark;
+
+import static org.junit.Assert.*;
+
+import org.junit.Test;
+
+public class SparkVersionTest {
+
+  @Test
+  public void testUnknownSparkVersion() {
+    assertEquals(99999, SparkVersion.fromVersionString("DEV-10.10").toNumber());
+  }
+
+  @Test
+  public void testUnsupportedVersion() {
+    assertTrue(SparkVersion.fromVersionString("9.9.9").isUnsupportedVersion());
+    assertFalse(SparkVersion.fromVersionString("1.5.9").isUnsupportedVersion());
+    assertTrue(SparkVersion.fromVersionString("0.9.0").isUnsupportedVersion());
+    assertTrue(SparkVersion.UNSUPPORTED_FUTURE_VERSION.isUnsupportedVersion());
+    // should support spark2 version of HDP 2.5
+    assertFalse(SparkVersion.fromVersionString("2.0.0.2.5.0.0-1245").isUnsupportedVersion());
+  }
+
+  @Test
+  public void testSparkVersion() {
+    // test equals
+    assertEquals(SparkVersion.SPARK_1_2_0, SparkVersion.fromVersionString("1.2.0"));
+    assertEquals(SparkVersion.SPARK_1_5_0, SparkVersion.fromVersionString("1.5.0-SNAPSHOT"));
+    assertEquals(SparkVersion.SPARK_1_5_0, SparkVersion.fromVersionString("1.5.0-SNAPSHOT"));
+    // test spark2 version of HDP 2.5
+    assertEquals(SparkVersion.SPARK_2_0_0, SparkVersion.fromVersionString("2.0.0.2.5.0.0-1245"));
+
+    // test newer than
+    assertFalse(SparkVersion.SPARK_1_2_0.newerThan(SparkVersion.SPARK_1_2_0));
+    assertFalse(SparkVersion.SPARK_1_2_0.newerThan(SparkVersion.SPARK_1_3_0));
+    assertTrue(SparkVersion.SPARK_1_2_0.newerThan(SparkVersion.SPARK_1_1_0));
+
+    assertTrue(SparkVersion.SPARK_1_2_0.newerThanEquals(SparkVersion.SPARK_1_2_0));
+    assertFalse(SparkVersion.SPARK_1_2_0.newerThanEquals(SparkVersion.SPARK_1_3_0));
+    assertTrue(SparkVersion.SPARK_1_2_0.newerThanEquals(SparkVersion.SPARK_1_1_0));
+
+    // test older than
+    assertFalse(SparkVersion.SPARK_1_2_0.olderThan(SparkVersion.SPARK_1_2_0));
+    assertFalse(SparkVersion.SPARK_1_2_0.olderThan(SparkVersion.SPARK_1_1_0));
+    assertTrue(SparkVersion.SPARK_1_2_0.olderThan(SparkVersion.SPARK_1_3_0));
+
+    assertTrue(SparkVersion.SPARK_1_2_0.olderThanEquals(SparkVersion.SPARK_1_2_0));
+    assertFalse(SparkVersion.SPARK_1_2_0.olderThanEquals(SparkVersion.SPARK_1_1_0));
+    assertTrue(SparkVersion.SPARK_1_2_0.olderThanEquals(SparkVersion.SPARK_1_3_0));
+
+    // conversion
+    assertEquals(10200, SparkVersion.SPARK_1_2_0.toNumber());
+    assertEquals("1.2.0", SparkVersion.SPARK_1_2_0.toString());
+  }
+}

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/d762b528/spark/interpreter/src/test/resources/log4j.properties
----------------------------------------------------------------------
diff --git a/spark/interpreter/src/test/resources/log4j.properties b/spark/interpreter/src/test/resources/log4j.properties
new file mode 100644
index 0000000..6958d4c
--- /dev/null
+++ b/spark/interpreter/src/test/resources/log4j.properties
@@ -0,0 +1,52 @@
+#
+# 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.
+#
+
+# Direct log messages to stdout
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.Target=System.out
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c:%L - %m%n
+#log4j.appender.stdout.layout.ConversionPattern=
+#%5p [%t] (%F:%L) - %m%n
+#%-4r [%t] %-5p %c %x - %m%n
+#
+
+# Root logger option
+log4j.rootLogger=INFO, stdout
+ 
+#mute some noisy guys
+log4j.logger.org.apache.hadoop.mapred=WARN
+log4j.logger.org.apache.hadoop.hive.ql=WARN
+log4j.logger.org.apache.hadoop.hive.metastore=WARN
+log4j.logger.org.apache.haadoop.hive.service.HiveServer=WARN
+log4j.logger.org.apache.zeppelin.scheduler=WARN
+
+log4j.logger.org.quartz=WARN
+log4j.logger.DataNucleus=WARN
+log4j.logger.DataNucleus.MetaData=ERROR
+log4j.logger.DataNucleus.Datastore=ERROR
+
+# Log all JDBC parameters
+log4j.logger.org.hibernate.type=ALL
+
+log4j.logger.org.apache.zeppelin.interpreter=DEBUG
+log4j.logger.org.apache.zeppelin.spark=DEBUG
+
+log4j.logger.org.apache.zeppelin.python.IPythonInterpreter=DEBUG
+log4j.logger.org.apache.zeppelin.python.IPythonClient=DEBUG
+log4j.logger.org.apache.spark.repl.Main=INFO
+

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/d762b528/spark/interpreter/src/test/scala/org/apache/zeppelin/spark/utils/DisplayFunctionsTest.scala
----------------------------------------------------------------------
diff --git a/spark/interpreter/src/test/scala/org/apache/zeppelin/spark/utils/DisplayFunctionsTest.scala b/spark/interpreter/src/test/scala/org/apache/zeppelin/spark/utils/DisplayFunctionsTest.scala
new file mode 100644
index 0000000..2638f17
--- /dev/null
+++ b/spark/interpreter/src/test/scala/org/apache/zeppelin/spark/utils/DisplayFunctionsTest.scala
@@ -0,0 +1,173 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.zeppelin.spark.utils
+
+import java.io.ByteArrayOutputStream
+
+import org.apache.spark.rdd.RDD
+import org.apache.spark.{SparkContext, SparkConf}
+import org.scalatest._
+import org.scalatest.{BeforeAndAfter}
+
+case class Person(login : String, name: String, age: Int)
+
+class DisplayFunctionsTest extends FlatSpec with BeforeAndAfter with BeforeAndAfterEach with Matchers {
+  var sc: SparkContext = null
+  var testTuples:List[(String, String, Int)] = null
+  var testPersons:List[Person] = null
+  var testRDDTuples: RDD[(String,String,Int)]  = null
+  var testRDDPersons: RDD[Person]  = null
+  var stream: ByteArrayOutputStream = null
+  
+  before {
+    val sparkConf: SparkConf = new SparkConf(true)
+      .setAppName("test-DisplayFunctions")
+      .setMaster("local")
+    sc = new SparkContext(sparkConf)
+    testTuples = List(("jdoe", "John DOE", 32), ("hsue", "Helen SUE", 27), ("rsmith", "Richard SMITH", 45))
+    testRDDTuples = sc.parallelize(testTuples)
+    testPersons = List(Person("jdoe", "John DOE", 32), Person("hsue", "Helen SUE", 27), Person("rsmith", "Richard SMITH", 45))
+    testRDDPersons = sc.parallelize(testPersons)
+  }
+
+  override def beforeEach() {
+    stream = new java.io.ByteArrayOutputStream()
+    super.beforeEach() // To be stackable, must call super.beforeEach
+  }
+
+
+  "DisplayFunctions" should "generate correct column headers for tuples" in {
+    implicit val sparkMaxResult = new SparkMaxResult(100)
+    Console.withOut(stream) {
+      new DisplayRDDFunctions[(String,String,Int)](testRDDTuples).display("Login","Name","Age")
+    }
+
+    stream.toString("UTF-8") should be("%table Login\tName\tAge\n" +
+      "jdoe\tJohn DOE\t32\n" +
+      "hsue\tHelen SUE\t27\n" +
+      "rsmith\tRichard SMITH\t45\n")
+  }
+
+  "DisplayFunctions" should "generate correct column headers for case class" in {
+    implicit val sparkMaxResult = new SparkMaxResult(100)
+    Console.withOut(stream) {
+      new DisplayRDDFunctions[Person](testRDDPersons).display("Login","Name","Age")
+    }
+
+    stream.toString("UTF-8") should be("%table Login\tName\tAge\n" +
+      "jdoe\tJohn DOE\t32\n" +
+      "hsue\tHelen SUE\t27\n" +
+      "rsmith\tRichard SMITH\t45\n")
+  }
+
+  "DisplayFunctions" should "truncate exceeding column headers for tuples" in {
+    implicit val sparkMaxResult = new SparkMaxResult(100)
+    Console.withOut(stream) {
+      new DisplayRDDFunctions[(String,String,Int)](testRDDTuples).display("Login","Name","Age","xxx","yyy")
+    }
+
+    stream.toString("UTF-8") should be("%table Login\tName\tAge\n" +
+      "jdoe\tJohn DOE\t32\n" +
+      "hsue\tHelen SUE\t27\n" +
+      "rsmith\tRichard SMITH\t45\n")
+  }
+
+  "DisplayFunctions" should "pad missing column headers with ColumnXXX for tuples" in {
+    implicit val sparkMaxResult = new SparkMaxResult(100)
+    Console.withOut(stream) {
+      new DisplayRDDFunctions[(String,String,Int)](testRDDTuples).display("Login")
+    }
+
+    stream.toString("UTF-8") should be("%table Login\tColumn2\tColumn3\n" +
+      "jdoe\tJohn DOE\t32\n" +
+      "hsue\tHelen SUE\t27\n" +
+      "rsmith\tRichard SMITH\t45\n")
+  }
+
+  "DisplayUtils" should "restricts RDD to sparkMaxresult with implicit limit" in {
+
+    implicit val sparkMaxResult = new SparkMaxResult(2)
+
+    Console.withOut(stream) {
+      new DisplayRDDFunctions[(String,String,Int)](testRDDTuples).display("Login")
+    }
+
+    stream.toString("UTF-8") should be("%table Login\tColumn2\tColumn3\n" +
+      "jdoe\tJohn DOE\t32\n" +
+      "hsue\tHelen SUE\t27\n")
+  }
+
+  "DisplayUtils" should "restricts RDD to sparkMaxresult with explicit limit" in {
+
+    implicit val sparkMaxResult = new SparkMaxResult(2)
+
+    Console.withOut(stream) {
+      new DisplayRDDFunctions[(String,String,Int)](testRDDTuples).display(1,"Login")
+    }
+
+    stream.toString("UTF-8") should be("%table Login\tColumn2\tColumn3\n" +
+      "jdoe\tJohn DOE\t32\n")
+  }
+
+  "DisplayFunctions" should "display traversable of tuples" in {
+
+    Console.withOut(stream) {
+      new DisplayTraversableFunctions[(String,String,Int)](testTuples).display("Login","Name","Age")
+    }
+
+    stream.toString("UTF-8") should be("%table Login\tName\tAge\n" +
+      "jdoe\tJohn DOE\t32\n" +
+      "hsue\tHelen SUE\t27\n" +
+      "rsmith\tRichard SMITH\t45\n")
+  }
+
+  "DisplayFunctions" should "display traversable of case class" in {
+
+    Console.withOut(stream) {
+      new DisplayTraversableFunctions[Person](testPersons).display("Login","Name","Age")
+    }
+
+    stream.toString("UTF-8") should be("%table Login\tName\tAge\n" +
+      "jdoe\tJohn DOE\t32\n" +
+      "hsue\tHelen SUE\t27\n" +
+      "rsmith\tRichard SMITH\t45\n")
+  }
+
+  "DisplayUtils" should "display HTML" in {
+    DisplayUtils.html() should be ("%html ")
+    DisplayUtils.html("test") should be ("%html test")
+  }
+
+  "DisplayUtils" should "display img" in {
+    DisplayUtils.img("http://www.google.com") should be ("<img src='http://www.google.com' />")
+    DisplayUtils.img64() should be ("%img ")
+    DisplayUtils.img64("abcde") should be ("%img abcde")
+  }
+
+  override def afterEach() {
+    try super.afterEach() // To be stackable, must call super.afterEach
+    stream = null
+  }
+
+  after {
+    sc.stop()
+  }
+
+
+}
+
+


[08/10] zeppelin git commit: ZEPPELIN-3111. Refactor SparkInterpreter

Posted by zj...@apache.org.
http://git-wip-us.apache.org/repos/asf/zeppelin/blob/d762b528/spark/interpreter/src/main/java/org/apache/zeppelin/spark/PySparkInterpreter.java
----------------------------------------------------------------------
diff --git a/spark/interpreter/src/main/java/org/apache/zeppelin/spark/PySparkInterpreter.java b/spark/interpreter/src/main/java/org/apache/zeppelin/spark/PySparkInterpreter.java
new file mode 100644
index 0000000..0703ad7
--- /dev/null
+++ b/spark/interpreter/src/main/java/org/apache/zeppelin/spark/PySparkInterpreter.java
@@ -0,0 +1,751 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.zeppelin.spark;
+
+import com.google.gson.Gson;
+import org.apache.commons.compress.utils.IOUtils;
+import org.apache.commons.exec.CommandLine;
+import org.apache.commons.exec.DefaultExecutor;
+import org.apache.commons.exec.ExecuteException;
+import org.apache.commons.exec.ExecuteResultHandler;
+import org.apache.commons.exec.ExecuteWatchdog;
+import org.apache.commons.exec.PumpStreamHandler;
+import org.apache.commons.exec.environment.EnvironmentUtils;
+import org.apache.commons.lang.StringUtils;
+import org.apache.spark.SparkConf;
+import org.apache.spark.api.java.JavaSparkContext;
+import org.apache.spark.sql.SQLContext;
+import org.apache.zeppelin.interpreter.Interpreter;
+import org.apache.zeppelin.interpreter.InterpreterContext;
+import org.apache.zeppelin.interpreter.InterpreterException;
+import org.apache.zeppelin.interpreter.InterpreterGroup;
+import org.apache.zeppelin.interpreter.InterpreterHookRegistry.HookType;
+import org.apache.zeppelin.interpreter.InterpreterResult;
+import org.apache.zeppelin.interpreter.InterpreterResult.Code;
+import org.apache.zeppelin.interpreter.InterpreterResultMessage;
+import org.apache.zeppelin.interpreter.LazyOpenInterpreter;
+import org.apache.zeppelin.interpreter.WrappedInterpreter;
+import org.apache.zeppelin.interpreter.thrift.InterpreterCompletion;
+import org.apache.zeppelin.interpreter.util.InterpreterOutputStream;
+import org.apache.zeppelin.spark.dep.SparkDependencyContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import py4j.GatewayServer;
+
+import java.io.BufferedWriter;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.io.PipedInputStream;
+import java.io.PipedOutputStream;
+import java.net.MalformedURLException;
+import java.net.ServerSocket;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+/**
+ *
+ */
+public class PySparkInterpreter extends Interpreter implements ExecuteResultHandler {
+  private static final Logger LOGGER = LoggerFactory.getLogger(PySparkInterpreter.class);
+  private GatewayServer gatewayServer;
+  private DefaultExecutor executor;
+  private int port;
+  private InterpreterOutputStream outputStream;
+  private BufferedWriter ins;
+  private PipedInputStream in;
+  private ByteArrayOutputStream input;
+  private String scriptPath;
+  boolean pythonscriptRunning = false;
+  private static final int MAX_TIMEOUT_SEC = 10;
+  private long pythonPid;
+
+  private IPySparkInterpreter iPySparkInterpreter;
+
+  public PySparkInterpreter(Properties property) {
+    super(property);
+
+    pythonPid = -1;
+    try {
+      File scriptFile = File.createTempFile("zeppelin_pyspark-", ".py");
+      scriptPath = scriptFile.getAbsolutePath();
+    } catch (IOException e) {
+      throw new RuntimeException(e);
+    }
+  }
+
+  private void createPythonScript() throws InterpreterException {
+    ClassLoader classLoader = getClass().getClassLoader();
+    File out = new File(scriptPath);
+
+    if (out.exists() && out.isDirectory()) {
+      throw new InterpreterException("Can't create python script " + out.getAbsolutePath());
+    }
+
+    try {
+      FileOutputStream outStream = new FileOutputStream(out);
+      IOUtils.copy(
+          classLoader.getResourceAsStream("python/zeppelin_pyspark.py"),
+          outStream);
+      outStream.close();
+    } catch (IOException e) {
+      throw new InterpreterException(e);
+    }
+
+    LOGGER.info("File {} created", scriptPath);
+  }
+
+  @Override
+  public void open() throws InterpreterException {
+    // try IPySparkInterpreter first
+    iPySparkInterpreter = getIPySparkInterpreter();
+    if (getProperty("zeppelin.pyspark.useIPython", "true").equals("true") &&
+        StringUtils.isEmpty(
+            iPySparkInterpreter.checkIPythonPrerequisite(getPythonExec(getProperties())))) {
+      try {
+        iPySparkInterpreter.open();
+        if (InterpreterContext.get() != null) {
+          // don't print it when it is in testing, just for easy output check in test.
+          InterpreterContext.get().out.write(("IPython is available, " +
+              "use IPython for PySparkInterpreter\n")
+              .getBytes());
+        }
+        LOGGER.info("Use IPySparkInterpreter to replace PySparkInterpreter");
+        return;
+      } catch (Exception e) {
+        LOGGER.warn("Fail to open IPySparkInterpreter", e);
+      }
+    }
+    iPySparkInterpreter = null;
+    if (getProperty("zeppelin.pyspark.useIPython", "true").equals("true")) {
+      // don't print it when it is in testing, just for easy output check in test.
+      try {
+        InterpreterContext.get().out.write(("IPython is not available, " +
+            "use the native PySparkInterpreter\n")
+            .getBytes());
+      } catch (IOException e) {
+        LOGGER.warn("Fail to write InterpreterOutput", e);
+      }
+    }
+
+    // Add matplotlib display hook
+    InterpreterGroup intpGroup = getInterpreterGroup();
+    if (intpGroup != null && intpGroup.getInterpreterHookRegistry() != null) {
+      registerHook(HookType.POST_EXEC_DEV, "__zeppelin__._displayhook()");
+    }
+    DepInterpreter depInterpreter = getDepInterpreter();
+
+    // load libraries from Dependency Interpreter
+    URL [] urls = new URL[0];
+    List<URL> urlList = new LinkedList<>();
+
+    if (depInterpreter != null) {
+      SparkDependencyContext depc = depInterpreter.getDependencyContext();
+      if (depc != null) {
+        List<File> files = depc.getFiles();
+        if (files != null) {
+          for (File f : files) {
+            try {
+              urlList.add(f.toURI().toURL());
+            } catch (MalformedURLException e) {
+              LOGGER.error("Error", e);
+            }
+          }
+        }
+      }
+    }
+
+    String localRepo = getProperty("zeppelin.interpreter.localRepo");
+    if (localRepo != null) {
+      File localRepoDir = new File(localRepo);
+      if (localRepoDir.exists()) {
+        File[] files = localRepoDir.listFiles();
+        if (files != null) {
+          for (File f : files) {
+            try {
+              urlList.add(f.toURI().toURL());
+            } catch (MalformedURLException e) {
+              LOGGER.error("Error", e);
+            }
+          }
+        }
+      }
+    }
+
+    urls = urlList.toArray(urls);
+    ClassLoader oldCl = Thread.currentThread().getContextClassLoader();
+    try {
+      URLClassLoader newCl = new URLClassLoader(urls, oldCl);
+      Thread.currentThread().setContextClassLoader(newCl);
+      createGatewayServerAndStartScript();
+    } catch (Exception e) {
+      LOGGER.error("Error", e);
+      throw new InterpreterException(e);
+    } finally {
+      Thread.currentThread().setContextClassLoader(oldCl);
+    }
+  }
+
+  private Map setupPySparkEnv() throws IOException, InterpreterException {
+    Map env = EnvironmentUtils.getProcEnvironment();
+
+    // only set PYTHONPATH in local or yarn-client mode.
+    // yarn-cluster will setup PYTHONPATH automatically.
+    SparkConf conf = getSparkConf();
+    if (!conf.get("spark.submit.deployMode", "client").equals("cluster")) {
+      if (!env.containsKey("PYTHONPATH")) {
+        env.put("PYTHONPATH", PythonUtils.sparkPythonPath());
+      } else {
+        env.put("PYTHONPATH", PythonUtils.sparkPythonPath());
+      }
+    }
+
+    // get additional class paths when using SPARK_SUBMIT and not using YARN-CLIENT
+    // also, add all packages to PYTHONPATH since there might be transitive dependencies
+    if (SparkInterpreter.useSparkSubmit() &&
+        !getSparkInterpreter().isYarnMode()) {
+
+      String sparkSubmitJars = getSparkConf().get("spark.jars").replace(",", ":");
+
+      if (!"".equals(sparkSubmitJars)) {
+        env.put("PYTHONPATH", env.get("PYTHONPATH") + sparkSubmitJars);
+      }
+    }
+
+    LOGGER.info("PYTHONPATH: " + env.get("PYTHONPATH"));
+
+    // set PYSPARK_PYTHON
+    if (getSparkConf().contains("spark.pyspark.python")) {
+      env.put("PYSPARK_PYTHON", getSparkConf().get("spark.pyspark.python"));
+    }
+    return env;
+  }
+
+  // Run python shell
+  // Choose python in the order of
+  // PYSPARK_DRIVER_PYTHON > PYSPARK_PYTHON > zeppelin.pyspark.python
+  public static String getPythonExec(Properties properties) {
+    String pythonExec = properties.getProperty("zeppelin.pyspark.python", "python");
+    if (System.getenv("PYSPARK_PYTHON") != null) {
+      pythonExec = System.getenv("PYSPARK_PYTHON");
+    }
+    if (System.getenv("PYSPARK_DRIVER_PYTHON") != null) {
+      pythonExec = System.getenv("PYSPARK_DRIVER_PYTHON");
+    }
+    return pythonExec;
+  }
+
+  private void createGatewayServerAndStartScript() throws InterpreterException {
+    // create python script
+    createPythonScript();
+
+    port = findRandomOpenPortOnAllLocalInterfaces();
+
+    gatewayServer = new GatewayServer(this, port);
+    gatewayServer.start();
+
+    String pythonExec = getPythonExec(getProperties());
+    LOGGER.info("pythonExec: " + pythonExec);
+    CommandLine cmd = CommandLine.parse(pythonExec);
+    cmd.addArgument(scriptPath, false);
+    cmd.addArgument(Integer.toString(port), false);
+    cmd.addArgument(Integer.toString(getSparkInterpreter().getSparkVersion().toNumber()), false);
+    executor = new DefaultExecutor();
+    outputStream = new InterpreterOutputStream(LOGGER);
+    PipedOutputStream ps = new PipedOutputStream();
+    in = null;
+    try {
+      in = new PipedInputStream(ps);
+    } catch (IOException e1) {
+      throw new InterpreterException(e1);
+    }
+    ins = new BufferedWriter(new OutputStreamWriter(ps));
+
+    input = new ByteArrayOutputStream();
+
+    PumpStreamHandler streamHandler = new PumpStreamHandler(outputStream, outputStream, in);
+    executor.setStreamHandler(streamHandler);
+    executor.setWatchdog(new ExecuteWatchdog(ExecuteWatchdog.INFINITE_TIMEOUT));
+
+    try {
+      Map env = setupPySparkEnv();
+      executor.execute(cmd, env, this);
+      pythonscriptRunning = true;
+    } catch (IOException e) {
+      throw new InterpreterException(e);
+    }
+
+
+    try {
+      input.write("import sys, getopt\n".getBytes());
+      ins.flush();
+    } catch (IOException e) {
+      throw new InterpreterException(e);
+    }
+  }
+
+  private int findRandomOpenPortOnAllLocalInterfaces() throws InterpreterException {
+    int port;
+    try (ServerSocket socket = new ServerSocket(0);) {
+      port = socket.getLocalPort();
+      socket.close();
+    } catch (IOException e) {
+      throw new InterpreterException(e);
+    }
+    return port;
+  }
+
+  @Override
+  public void close() throws InterpreterException {
+    if (iPySparkInterpreter != null) {
+      iPySparkInterpreter.close();
+      return;
+    }
+    executor.getWatchdog().destroyProcess();
+    new File(scriptPath).delete();
+    gatewayServer.shutdown();
+  }
+
+  PythonInterpretRequest pythonInterpretRequest = null;
+
+  /**
+   *
+   */
+  public class PythonInterpretRequest {
+    public String statements;
+    public String jobGroup;
+    public String jobDescription;
+
+    public PythonInterpretRequest(String statements, String jobGroup,
+        String jobDescription) {
+      this.statements = statements;
+      this.jobGroup = jobGroup;
+      this.jobDescription = jobDescription;
+    }
+
+    public String statements() {
+      return statements;
+    }
+
+    public String jobGroup() {
+      return jobGroup;
+    }
+
+    public String jobDescription() {
+      return jobDescription;
+    }
+  }
+
+  Integer statementSetNotifier = new Integer(0);
+
+  public PythonInterpretRequest getStatements() {
+    synchronized (statementSetNotifier) {
+      while (pythonInterpretRequest == null) {
+        try {
+          statementSetNotifier.wait(1000);
+        } catch (InterruptedException e) {
+        }
+      }
+      PythonInterpretRequest req = pythonInterpretRequest;
+      pythonInterpretRequest = null;
+      return req;
+    }
+  }
+
+  String statementOutput = null;
+  boolean statementError = false;
+  Integer statementFinishedNotifier = new Integer(0);
+
+  public void setStatementsFinished(String out, boolean error) {
+    synchronized (statementFinishedNotifier) {
+      LOGGER.debug("Setting python statement output: " + out + ", error: " + error);
+      statementOutput = out;
+      statementError = error;
+      statementFinishedNotifier.notify();
+    }
+  }
+
+  boolean pythonScriptInitialized = false;
+  Integer pythonScriptInitializeNotifier = new Integer(0);
+
+  public void onPythonScriptInitialized(long pid) {
+    pythonPid = pid;
+    synchronized (pythonScriptInitializeNotifier) {
+      LOGGER.debug("onPythonScriptInitialized is called");
+      pythonScriptInitialized = true;
+      pythonScriptInitializeNotifier.notifyAll();
+    }
+  }
+
+  public void appendOutput(String message) throws IOException {
+    LOGGER.debug("Output from python process: " + message);
+    outputStream.getInterpreterOutput().write(message);
+  }
+
+  @Override
+  public InterpreterResult interpret(String st, InterpreterContext context)
+      throws InterpreterException {
+    SparkInterpreter sparkInterpreter = getSparkInterpreter();
+    sparkInterpreter.populateSparkWebUrl(context);
+    if (sparkInterpreter.isUnsupportedSparkVersion()) {
+      return new InterpreterResult(Code.ERROR, "Spark "
+          + sparkInterpreter.getSparkVersion().toString() + " is not supported");
+    }
+
+    if (iPySparkInterpreter != null) {
+      return iPySparkInterpreter.interpret(st, context);
+    }
+
+    if (!pythonscriptRunning) {
+      return new InterpreterResult(Code.ERROR, "python process not running"
+          + outputStream.toString());
+    }
+
+    outputStream.setInterpreterOutput(context.out);
+
+    synchronized (pythonScriptInitializeNotifier) {
+      long startTime = System.currentTimeMillis();
+      while (pythonScriptInitialized == false
+          && pythonscriptRunning
+          && System.currentTimeMillis() - startTime < MAX_TIMEOUT_SEC * 1000) {
+        try {
+          pythonScriptInitializeNotifier.wait(1000);
+        } catch (InterruptedException e) {
+          e.printStackTrace();
+        }
+      }
+    }
+
+    List<InterpreterResultMessage> errorMessage;
+    try {
+      context.out.flush();
+      errorMessage = context.out.toInterpreterResultMessage();
+    } catch (IOException e) {
+      throw new InterpreterException(e);
+    }
+
+
+    if (pythonscriptRunning == false) {
+      // python script failed to initialize and terminated
+      errorMessage.add(new InterpreterResultMessage(
+          InterpreterResult.Type.TEXT, "failed to start pyspark"));
+      return new InterpreterResult(Code.ERROR, errorMessage);
+    }
+    if (pythonScriptInitialized == false) {
+      // timeout. didn't get initialized message
+      errorMessage.add(new InterpreterResultMessage(
+          InterpreterResult.Type.TEXT, "pyspark is not responding"));
+      return new InterpreterResult(Code.ERROR, errorMessage);
+    }
+
+    if (!sparkInterpreter.getSparkVersion().isPysparkSupported()) {
+      errorMessage.add(new InterpreterResultMessage(
+          InterpreterResult.Type.TEXT,
+          "pyspark " + sparkInterpreter.getSparkContext().version() + " is not supported"));
+      return new InterpreterResult(Code.ERROR, errorMessage);
+    }
+    String jobGroup = Utils.buildJobGroupId(context);
+    String jobDesc = "Started by: " + Utils.getUserName(context.getAuthenticationInfo());
+    SparkZeppelinContext __zeppelin__ = sparkInterpreter.getZeppelinContext();
+    __zeppelin__.setInterpreterContext(context);
+    __zeppelin__.setGui(context.getGui());
+    __zeppelin__.setNoteGui(context.getNoteGui());
+    pythonInterpretRequest = new PythonInterpretRequest(st, jobGroup, jobDesc);
+    statementOutput = null;
+
+    synchronized (statementSetNotifier) {
+      statementSetNotifier.notify();
+    }
+
+    synchronized (statementFinishedNotifier) {
+      while (statementOutput == null) {
+        try {
+          statementFinishedNotifier.wait(1000);
+        } catch (InterruptedException e) {
+        }
+      }
+    }
+
+    if (statementError) {
+      return new InterpreterResult(Code.ERROR, statementOutput);
+    } else {
+
+      try {
+        context.out.flush();
+      } catch (IOException e) {
+        throw new InterpreterException(e);
+      }
+
+      return new InterpreterResult(Code.SUCCESS);
+    }
+  }
+
+  public void interrupt() throws IOException, InterpreterException {
+    if (pythonPid > -1) {
+      LOGGER.info("Sending SIGINT signal to PID : " + pythonPid);
+      Runtime.getRuntime().exec("kill -SIGINT " + pythonPid);
+    } else {
+      LOGGER.warn("Non UNIX/Linux system, close the interpreter");
+      close();
+    }
+  }
+
+  @Override
+  public void cancel(InterpreterContext context) throws InterpreterException {
+    if (iPySparkInterpreter != null) {
+      iPySparkInterpreter.cancel(context);
+      return;
+    }
+    SparkInterpreter sparkInterpreter = getSparkInterpreter();
+    sparkInterpreter.cancel(context);
+    try {
+      interrupt();
+    } catch (IOException e) {
+      LOGGER.error("Error", e);
+    }
+  }
+
+  @Override
+  public FormType getFormType() {
+    return FormType.NATIVE;
+  }
+
+  @Override
+  public int getProgress(InterpreterContext context) throws InterpreterException {
+    if (iPySparkInterpreter != null) {
+      return iPySparkInterpreter.getProgress(context);
+    }
+    SparkInterpreter sparkInterpreter = getSparkInterpreter();
+    return sparkInterpreter.getProgress(context);
+  }
+
+
+  @Override
+  public List<InterpreterCompletion> completion(String buf, int cursor,
+                                                InterpreterContext interpreterContext)
+      throws InterpreterException {
+    if (iPySparkInterpreter != null) {
+      return iPySparkInterpreter.completion(buf, cursor, interpreterContext);
+    }
+    if (buf.length() < cursor) {
+      cursor = buf.length();
+    }
+    String completionString = getCompletionTargetString(buf, cursor);
+    String completionCommand = "completion.getCompletion('" + completionString + "')";
+
+    //start code for completion
+    SparkInterpreter sparkInterpreter = getSparkInterpreter();
+    if (sparkInterpreter.isUnsupportedSparkVersion() || pythonscriptRunning == false) {
+      return new LinkedList<>();
+    }
+
+    pythonInterpretRequest = new PythonInterpretRequest(completionCommand, "", "");
+    statementOutput = null;
+
+    synchronized (statementSetNotifier) {
+      statementSetNotifier.notify();
+    }
+
+    String[] completionList = null;
+    synchronized (statementFinishedNotifier) {
+      long startTime = System.currentTimeMillis();
+      while (statementOutput == null
+        && pythonscriptRunning) {
+        try {
+          if (System.currentTimeMillis() - startTime > MAX_TIMEOUT_SEC * 1000) {
+            LOGGER.error("pyspark completion didn't have response for {}sec.", MAX_TIMEOUT_SEC);
+            break;
+          }
+          statementFinishedNotifier.wait(1000);
+        } catch (InterruptedException e) {
+          // not working
+          LOGGER.info("wait drop");
+          return new LinkedList<>();
+        }
+      }
+      if (statementError) {
+        return new LinkedList<>();
+      }
+      Gson gson = new Gson();
+      completionList = gson.fromJson(statementOutput, String[].class);
+    }
+    //end code for completion
+
+    if (completionList == null) {
+      return new LinkedList<>();
+    }
+
+    List<InterpreterCompletion> results = new LinkedList<>();
+    for (String name: completionList) {
+      results.add(new InterpreterCompletion(name, name, StringUtils.EMPTY));
+    }
+    return results;
+  }
+
+  private String getCompletionTargetString(String text, int cursor) {
+    String[] completionSeqCharaters = {" ", "\n", "\t"};
+    int completionEndPosition = cursor;
+    int completionStartPosition = cursor;
+    int indexOfReverseSeqPostion = cursor;
+
+    String resultCompletionText = "";
+    String completionScriptText = "";
+    try {
+      completionScriptText = text.substring(0, cursor);
+    }
+    catch (Exception e) {
+      LOGGER.error(e.toString());
+      return null;
+    }
+    completionEndPosition = completionScriptText.length();
+
+    String tempReverseCompletionText = new StringBuilder(completionScriptText).reverse().toString();
+
+    for (String seqCharacter : completionSeqCharaters) {
+      indexOfReverseSeqPostion = tempReverseCompletionText.indexOf(seqCharacter);
+
+      if (indexOfReverseSeqPostion < completionStartPosition && indexOfReverseSeqPostion > 0) {
+        completionStartPosition = indexOfReverseSeqPostion;
+      }
+
+    }
+
+    if (completionStartPosition == completionEndPosition) {
+      completionStartPosition = 0;
+    }
+    else
+    {
+      completionStartPosition = completionEndPosition - completionStartPosition;
+    }
+    resultCompletionText = completionScriptText.substring(
+            completionStartPosition , completionEndPosition);
+
+    return resultCompletionText;
+  }
+
+
+  private SparkInterpreter getSparkInterpreter() throws InterpreterException {
+    LazyOpenInterpreter lazy = null;
+    SparkInterpreter spark = null;
+    Interpreter p = getInterpreterInTheSameSessionByClassName(SparkInterpreter.class.getName());
+
+    while (p instanceof WrappedInterpreter) {
+      if (p instanceof LazyOpenInterpreter) {
+        lazy = (LazyOpenInterpreter) p;
+      }
+      p = ((WrappedInterpreter) p).getInnerInterpreter();
+    }
+    spark = (SparkInterpreter) p;
+
+    if (lazy != null) {
+      lazy.open();
+    }
+    return spark;
+  }
+
+  private IPySparkInterpreter getIPySparkInterpreter() {
+    LazyOpenInterpreter lazy = null;
+    IPySparkInterpreter iPySpark = null;
+    Interpreter p = getInterpreterInTheSameSessionByClassName(IPySparkInterpreter.class.getName());
+
+    while (p instanceof WrappedInterpreter) {
+      if (p instanceof LazyOpenInterpreter) {
+        lazy = (LazyOpenInterpreter) p;
+      }
+      p = ((WrappedInterpreter) p).getInnerInterpreter();
+    }
+    iPySpark = (IPySparkInterpreter) p;
+    return iPySpark;
+  }
+
+  public SparkZeppelinContext getZeppelinContext() throws InterpreterException {
+    SparkInterpreter sparkIntp = getSparkInterpreter();
+    if (sparkIntp != null) {
+      return getSparkInterpreter().getZeppelinContext();
+    } else {
+      return null;
+    }
+  }
+
+  public JavaSparkContext getJavaSparkContext() throws InterpreterException {
+    SparkInterpreter intp = getSparkInterpreter();
+    if (intp == null) {
+      return null;
+    } else {
+      return new JavaSparkContext(intp.getSparkContext());
+    }
+  }
+
+  public Object getSparkSession() throws InterpreterException {
+    SparkInterpreter intp = getSparkInterpreter();
+    if (intp == null) {
+      return null;
+    } else {
+      return intp.getSparkSession();
+    }
+  }
+
+  public SparkConf getSparkConf() throws InterpreterException {
+    JavaSparkContext sc = getJavaSparkContext();
+    if (sc == null) {
+      return null;
+    } else {
+      return getJavaSparkContext().getConf();
+    }
+  }
+
+  public SQLContext getSQLContext() throws InterpreterException {
+    SparkInterpreter intp = getSparkInterpreter();
+    if (intp == null) {
+      return null;
+    } else {
+      return intp.getSQLContext();
+    }
+  }
+
+  private DepInterpreter getDepInterpreter() {
+    Interpreter p = getInterpreterInTheSameSessionByClassName(DepInterpreter.class.getName());
+    if (p == null) {
+      return null;
+    }
+
+    while (p instanceof WrappedInterpreter) {
+      p = ((WrappedInterpreter) p).getInnerInterpreter();
+    }
+    return (DepInterpreter) p;
+  }
+
+
+  @Override
+  public void onProcessComplete(int exitValue) {
+    pythonscriptRunning = false;
+    LOGGER.info("python process terminated. exit code " + exitValue);
+  }
+
+  @Override
+  public void onProcessFailed(ExecuteException e) {
+    pythonscriptRunning = false;
+    LOGGER.error("python process failed", e);
+  }
+}

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/d762b528/spark/interpreter/src/main/java/org/apache/zeppelin/spark/PythonUtils.java
----------------------------------------------------------------------
diff --git a/spark/interpreter/src/main/java/org/apache/zeppelin/spark/PythonUtils.java b/spark/interpreter/src/main/java/org/apache/zeppelin/spark/PythonUtils.java
new file mode 100644
index 0000000..8182690
--- /dev/null
+++ b/spark/interpreter/src/main/java/org/apache/zeppelin/spark/PythonUtils.java
@@ -0,0 +1,96 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package org.apache.zeppelin.spark;
+
+import org.apache.commons.lang3.StringUtils;
+
+import java.io.File;
+import java.io.FilenameFilter;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Util class for PySpark
+ */
+public class PythonUtils {
+
+  /**
+   * Get the PYTHONPATH for PySpark, either from SPARK_HOME, if it is set, or from ZEPPELIN_HOME
+   * when it is embedded mode.
+   *
+   * This method will called in zeppelin server process and spark driver process when it is
+   * local or yarn-client mode.
+   */
+  public static String sparkPythonPath() {
+    List<String> pythonPath = new ArrayList<String>();
+    String sparkHome = System.getenv("SPARK_HOME");
+    String zeppelinHome = System.getenv("ZEPPELIN_HOME");
+    if (zeppelinHome == null) {
+      zeppelinHome = new File("..").getAbsolutePath();
+    }
+    if (sparkHome != null) {
+      // non-embedded mode when SPARK_HOME is specified.
+      File pyspark = new File(sparkHome, "python/lib/pyspark.zip");
+      if (!pyspark.exists()) {
+        throw new RuntimeException("No pyspark.zip found under " + sparkHome + "/python/lib");
+      }
+      pythonPath.add(pyspark.getAbsolutePath());
+      File[] py4j = new File(sparkHome + "/python/lib").listFiles(new FilenameFilter() {
+        @Override
+        public boolean accept(File dir, String name) {
+          return name.startsWith("py4j");
+        }
+      });
+      if (py4j.length == 0) {
+        throw new RuntimeException("No py4j files found under " + sparkHome + "/python/lib");
+      } else if (py4j.length > 1) {
+        throw new RuntimeException("Multiple py4j files found under " + sparkHome + "/python/lib");
+      } else {
+        pythonPath.add(py4j[0].getAbsolutePath());
+      }
+    } else {
+      // embedded mode
+      File pyspark = new File(zeppelinHome, "interpreter/spark/pyspark/pyspark.zip");
+      if (!pyspark.exists()) {
+        throw new RuntimeException("No pyspark.zip found: " + pyspark.getAbsolutePath());
+      }
+      pythonPath.add(pyspark.getAbsolutePath());
+      File[] py4j = new File(zeppelinHome, "interpreter/spark/pyspark").listFiles(
+          new FilenameFilter() {
+            @Override
+            public boolean accept(File dir, String name) {
+              return name.startsWith("py4j");
+            }
+          });
+      if (py4j.length == 0) {
+        throw new RuntimeException("No py4j files found under " + zeppelinHome +
+            "/interpreter/spark/pyspark");
+      } else if (py4j.length > 1) {
+        throw new RuntimeException("Multiple py4j files found under " + sparkHome +
+            "/interpreter/spark/pyspark");
+      } else {
+        pythonPath.add(py4j[0].getAbsolutePath());
+      }
+    }
+
+    // add ${ZEPPELIN_HOME}/interpreter/lib/python for all the cases
+    pythonPath.add(zeppelinHome + "/interpreter/lib/python");
+    return StringUtils.join(pythonPath, ":");
+  }
+}

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/d762b528/spark/interpreter/src/main/java/org/apache/zeppelin/spark/SparkInterpreter.java
----------------------------------------------------------------------
diff --git a/spark/interpreter/src/main/java/org/apache/zeppelin/spark/SparkInterpreter.java b/spark/interpreter/src/main/java/org/apache/zeppelin/spark/SparkInterpreter.java
new file mode 100644
index 0000000..d9be573
--- /dev/null
+++ b/spark/interpreter/src/main/java/org/apache/zeppelin/spark/SparkInterpreter.java
@@ -0,0 +1,163 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.zeppelin.spark;
+
+import org.apache.spark.SparkContext;
+import org.apache.spark.api.java.JavaSparkContext;
+import org.apache.spark.sql.SQLContext;
+import org.apache.zeppelin.interpreter.Interpreter;
+import org.apache.zeppelin.interpreter.InterpreterContext;
+import org.apache.zeppelin.interpreter.InterpreterException;
+import org.apache.zeppelin.interpreter.InterpreterResult;
+import org.apache.zeppelin.interpreter.thrift.InterpreterCompletion;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.List;
+import java.util.Properties;
+
+/**
+ * It is the Wrapper of OldSparkInterpreter & NewSparkInterpreter.
+ * Property zeppelin.spark.useNew control which one to use.
+ */
+public class SparkInterpreter extends AbstractSparkInterpreter {
+
+  private static final Logger LOGGER = LoggerFactory.getLogger(SparkInterpreter.class);
+
+  // either OldSparkInterpreter or NewSparkInterpreter
+  private AbstractSparkInterpreter delegation;
+
+
+  public SparkInterpreter(Properties properties) {
+    super(properties);
+    if (Boolean.parseBoolean(properties.getProperty("zeppelin.spark.useNew", "false"))) {
+      delegation = new NewSparkInterpreter(properties);
+    } else {
+      delegation = new OldSparkInterpreter(properties);
+    }
+  }
+
+  @Override
+  public void open() throws InterpreterException {
+    delegation.setInterpreterGroup(getInterpreterGroup());
+    delegation.setUserName(getUserName());
+    delegation.setClassloaderUrls(getClassloaderUrls());
+
+    delegation.open();
+  }
+
+  @Override
+  public void close() throws InterpreterException {
+    delegation.close();
+  }
+
+  @Override
+  public InterpreterResult interpret(String st, InterpreterContext context)
+      throws InterpreterException {
+    return delegation.interpret(st, context);
+  }
+
+  @Override
+  public void cancel(InterpreterContext context) throws InterpreterException {
+    delegation.cancel(context);
+  }
+
+  @Override
+  public List<InterpreterCompletion> completion(String buf,
+                                                int cursor,
+                                                InterpreterContext interpreterContext)
+      throws InterpreterException {
+    return delegation.completion(buf, cursor, interpreterContext);
+  }
+
+  @Override
+  public FormType getFormType() {
+    return FormType.NATIVE;
+  }
+
+  @Override
+  public int getProgress(InterpreterContext context) throws InterpreterException {
+    return delegation.getProgress(context);
+  }
+
+  public AbstractSparkInterpreter getDelegation() {
+    return delegation;
+  }
+
+
+  @Override
+  public SparkContext getSparkContext() {
+    return delegation.getSparkContext();
+  }
+
+  @Override
+  public SQLContext getSQLContext() {
+    return delegation.getSQLContext();
+  }
+
+  @Override
+  public Object getSparkSession() {
+    return delegation.getSparkSession();
+  }
+
+  @Override
+  public boolean isSparkContextInitialized() {
+    return delegation.isSparkContextInitialized();
+  }
+
+  @Override
+  public SparkVersion getSparkVersion() {
+    return delegation.getSparkVersion();
+  }
+
+  @Override
+  public JavaSparkContext getJavaSparkContext() {
+    return delegation.getJavaSparkContext();
+  }
+
+  @Override
+  public void populateSparkWebUrl(InterpreterContext ctx) {
+    delegation.populateSparkWebUrl(ctx);
+  }
+
+  @Override
+  public SparkZeppelinContext getZeppelinContext() {
+    return delegation.getZeppelinContext();
+  }
+
+  @Override
+  public String getSparkUIUrl() {
+    return delegation.getSparkUIUrl();
+  }
+
+  public boolean isUnsupportedSparkVersion() {
+    return delegation.isUnsupportedSparkVersion();
+  }
+
+  public boolean isYarnMode() {
+    String master = getProperty("master");
+    if (master == null) {
+      master = getProperty("spark.master", "local[*]");
+    }
+    return master.startsWith("yarn");
+  }
+
+  public static boolean useSparkSubmit() {
+    return null != System.getenv("SPARK_SUBMIT");
+  }
+}

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/d762b528/spark/interpreter/src/main/java/org/apache/zeppelin/spark/SparkRInterpreter.java
----------------------------------------------------------------------
diff --git a/spark/interpreter/src/main/java/org/apache/zeppelin/spark/SparkRInterpreter.java b/spark/interpreter/src/main/java/org/apache/zeppelin/spark/SparkRInterpreter.java
new file mode 100644
index 0000000..dbaeabe
--- /dev/null
+++ b/spark/interpreter/src/main/java/org/apache/zeppelin/spark/SparkRInterpreter.java
@@ -0,0 +1,250 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.zeppelin.spark;
+
+import static org.apache.zeppelin.spark.ZeppelinRDisplay.render;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import org.apache.spark.SparkContext;
+import org.apache.spark.SparkRBackend;
+import org.apache.spark.api.java.JavaSparkContext;
+import org.apache.zeppelin.interpreter.*;
+import org.apache.zeppelin.interpreter.thrift.InterpreterCompletion;
+import org.apache.zeppelin.scheduler.Scheduler;
+import org.apache.zeppelin.scheduler.SchedulerFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Properties;
+
+/**
+ * R and SparkR interpreter with visualization support.
+ */
+public class SparkRInterpreter extends Interpreter {
+  private static final Logger logger = LoggerFactory.getLogger(SparkRInterpreter.class);
+
+  private static String renderOptions;
+  private SparkInterpreter sparkInterpreter;
+  private ZeppelinR zeppelinR;
+  private SparkContext sc;
+  private JavaSparkContext jsc;
+
+  public SparkRInterpreter(Properties property) {
+    super(property);
+  }
+
+  @Override
+  public void open() throws InterpreterException {
+    String rCmdPath = getProperty("zeppelin.R.cmd", "R");
+    String sparkRLibPath;
+
+    if (System.getenv("SPARK_HOME") != null) {
+      sparkRLibPath = System.getenv("SPARK_HOME") + "/R/lib";
+    } else {
+      sparkRLibPath = System.getenv("ZEPPELIN_HOME") + "/interpreter/spark/R/lib";
+      // workaround to make sparkr work without SPARK_HOME
+      System.setProperty("spark.test.home", System.getenv("ZEPPELIN_HOME") + "/interpreter/spark");
+    }
+    synchronized (SparkRBackend.backend()) {
+      if (!SparkRBackend.isStarted()) {
+        SparkRBackend.init();
+        SparkRBackend.start();
+      }
+    }
+
+    int port = SparkRBackend.port();
+
+    this.sparkInterpreter = getSparkInterpreter();
+    this.sc = sparkInterpreter.getSparkContext();
+    this.jsc = sparkInterpreter.getJavaSparkContext();
+    SparkVersion sparkVersion = new SparkVersion(sc.version());
+    ZeppelinRContext.setSparkContext(sc);
+    ZeppelinRContext.setJavaSparkContext(jsc);
+    if (Utils.isSpark2()) {
+      ZeppelinRContext.setSparkSession(sparkInterpreter.getSparkSession());
+    }
+    ZeppelinRContext.setSqlContext(sparkInterpreter.getSQLContext());
+    ZeppelinRContext.setZeppelinContext(sparkInterpreter.getZeppelinContext());
+
+    zeppelinR = new ZeppelinR(rCmdPath, sparkRLibPath, port, sparkVersion);
+    try {
+      zeppelinR.open();
+    } catch (IOException e) {
+      logger.error("Exception while opening SparkRInterpreter", e);
+      throw new InterpreterException(e);
+    }
+
+    if (useKnitr()) {
+      zeppelinR.eval("library('knitr')");
+    }
+    renderOptions = getProperty("zeppelin.R.render.options");
+  }
+
+  String getJobGroup(InterpreterContext context){
+    return "zeppelin-" + context.getParagraphId();
+  }
+
+  @Override
+  public InterpreterResult interpret(String lines, InterpreterContext interpreterContext)
+      throws InterpreterException {
+
+    SparkInterpreter sparkInterpreter = getSparkInterpreter();
+    sparkInterpreter.populateSparkWebUrl(interpreterContext);
+    if (sparkInterpreter.isUnsupportedSparkVersion()) {
+      return new InterpreterResult(InterpreterResult.Code.ERROR, "Spark "
+          + sparkInterpreter.getSparkVersion().toString() + " is not supported");
+    }
+
+    String jobGroup = Utils.buildJobGroupId(interpreterContext);
+    String jobDesc = "Started by: " +
+       Utils.getUserName(interpreterContext.getAuthenticationInfo());
+    sparkInterpreter.getSparkContext().setJobGroup(jobGroup, jobDesc, false);
+
+    String imageWidth = getProperty("zeppelin.R.image.width");
+
+    String[] sl = lines.split("\n");
+    if (sl[0].contains("{") && sl[0].contains("}")) {
+      String jsonConfig = sl[0].substring(sl[0].indexOf("{"), sl[0].indexOf("}") + 1);
+      ObjectMapper m = new ObjectMapper();
+      try {
+        JsonNode rootNode = m.readTree(jsonConfig);
+        JsonNode imageWidthNode = rootNode.path("imageWidth");
+        if (!imageWidthNode.isMissingNode()) imageWidth = imageWidthNode.textValue();
+      }
+      catch (Exception e) {
+        logger.warn("Can not parse json config: " + jsonConfig, e);
+      }
+      finally {
+        lines = lines.replace(jsonConfig, "");
+      }
+    }
+
+    String setJobGroup = "";
+    // assign setJobGroup to dummy__, otherwise it would print NULL for this statement
+    if (Utils.isSpark2()) {
+      setJobGroup = "dummy__ <- setJobGroup(\"" + jobGroup +
+          "\", \" +" + jobDesc + "\", TRUE)";
+    } else if (getSparkInterpreter().getSparkVersion().newerThanEquals(SparkVersion.SPARK_1_5_0)) {
+      setJobGroup = "dummy__ <- setJobGroup(sc, \"" + jobGroup +
+          "\", \"" + jobDesc + "\", TRUE)";
+    }
+    logger.debug("set JobGroup:" + setJobGroup);
+    lines = setJobGroup + "\n" + lines;
+
+    try {
+      // render output with knitr
+      if (useKnitr()) {
+        zeppelinR.setInterpreterOutput(null);
+        zeppelinR.set(".zcmd", "\n```{r " + renderOptions + "}\n" + lines + "\n```");
+        zeppelinR.eval(".zres <- knit2html(text=.zcmd)");
+        String html = zeppelinR.getS0(".zres");
+
+        RDisplay rDisplay = render(html, imageWidth);
+
+        return new InterpreterResult(
+            rDisplay.code(),
+            rDisplay.type(),
+            rDisplay.content()
+        );
+      } else {
+        // alternatively, stream the output (without knitr)
+        zeppelinR.setInterpreterOutput(interpreterContext.out);
+        zeppelinR.eval(lines);
+        return new InterpreterResult(InterpreterResult.Code.SUCCESS, "");
+      }
+    } catch (Exception e) {
+      logger.error("Exception while connecting to R", e);
+      return new InterpreterResult(InterpreterResult.Code.ERROR, e.getMessage());
+    } finally {
+      try {
+      } catch (Exception e) {
+        // Do nothing...
+      }
+    }
+  }
+
+  @Override
+  public void close() {
+    zeppelinR.close();
+  }
+
+  @Override
+  public void cancel(InterpreterContext context) {
+    if (this.sc != null) {
+      sc.cancelJobGroup(getJobGroup(context));
+    }
+  }
+
+  @Override
+  public FormType getFormType() {
+    return FormType.NONE;
+  }
+
+  @Override
+  public int getProgress(InterpreterContext context) throws InterpreterException {
+    if (sparkInterpreter != null) {
+      return sparkInterpreter.getProgress(context);
+    } else {
+      return 0;
+    }
+  }
+
+  @Override
+  public Scheduler getScheduler() {
+    return SchedulerFactory.singleton().createOrGetFIFOScheduler(
+            SparkRInterpreter.class.getName() + this.hashCode());
+  }
+
+  @Override
+  public List<InterpreterCompletion> completion(String buf, int cursor,
+                                                InterpreterContext interpreterContext) {
+    return new ArrayList<>();
+  }
+
+  private SparkInterpreter getSparkInterpreter() throws InterpreterException {
+    LazyOpenInterpreter lazy = null;
+    SparkInterpreter spark = null;
+    Interpreter p = getInterpreterInTheSameSessionByClassName(SparkInterpreter.class.getName());
+
+    while (p instanceof WrappedInterpreter) {
+      if (p instanceof LazyOpenInterpreter) {
+        lazy = (LazyOpenInterpreter) p;
+      }
+      p = ((WrappedInterpreter) p).getInnerInterpreter();
+    }
+    spark = (SparkInterpreter) p;
+
+    if (lazy != null) {
+      lazy.open();
+    }
+    return spark;
+  }
+
+  private boolean useKnitr() {
+    try {
+      return Boolean.parseBoolean(getProperty("zeppelin.R.knitr"));
+    } catch (Exception e) {
+      return false;
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/d762b528/spark/interpreter/src/main/java/org/apache/zeppelin/spark/SparkSqlInterpreter.java
----------------------------------------------------------------------
diff --git a/spark/interpreter/src/main/java/org/apache/zeppelin/spark/SparkSqlInterpreter.java b/spark/interpreter/src/main/java/org/apache/zeppelin/spark/SparkSqlInterpreter.java
new file mode 100644
index 0000000..9709f9e
--- /dev/null
+++ b/spark/interpreter/src/main/java/org/apache/zeppelin/spark/SparkSqlInterpreter.java
@@ -0,0 +1,187 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.zeppelin.spark;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.List;
+import java.util.Properties;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.apache.spark.SparkContext;
+import org.apache.spark.sql.SQLContext;
+import org.apache.zeppelin.interpreter.Interpreter;
+import org.apache.zeppelin.interpreter.InterpreterContext;
+import org.apache.zeppelin.interpreter.InterpreterException;
+import org.apache.zeppelin.interpreter.InterpreterResult;
+import org.apache.zeppelin.interpreter.InterpreterResult.Code;
+import org.apache.zeppelin.interpreter.LazyOpenInterpreter;
+import org.apache.zeppelin.interpreter.WrappedInterpreter;
+import org.apache.zeppelin.interpreter.thrift.InterpreterCompletion;
+import org.apache.zeppelin.scheduler.Scheduler;
+import org.apache.zeppelin.scheduler.SchedulerFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Spark SQL interpreter for Zeppelin.
+ */
+public class SparkSqlInterpreter extends Interpreter {
+  private Logger logger = LoggerFactory.getLogger(SparkSqlInterpreter.class);
+
+  public static final String MAX_RESULTS = "zeppelin.spark.maxResult";
+
+  AtomicInteger num = new AtomicInteger(0);
+
+  private int maxResult;
+
+  public SparkSqlInterpreter(Properties property) {
+    super(property);
+  }
+
+  @Override
+  public void open() {
+    this.maxResult = Integer.parseInt(getProperty(MAX_RESULTS));
+  }
+
+  private SparkInterpreter getSparkInterpreter() throws InterpreterException {
+    LazyOpenInterpreter lazy = null;
+    SparkInterpreter spark = null;
+    Interpreter p = getInterpreterInTheSameSessionByClassName(SparkInterpreter.class.getName());
+
+    while (p instanceof WrappedInterpreter) {
+      if (p instanceof LazyOpenInterpreter) {
+        lazy = (LazyOpenInterpreter) p;
+      }
+      p = ((WrappedInterpreter) p).getInnerInterpreter();
+    }
+    spark = (SparkInterpreter) p;
+
+    if (lazy != null) {
+      lazy.open();
+    }
+    return spark;
+  }
+
+  public boolean concurrentSQL() {
+    return Boolean.parseBoolean(getProperty("zeppelin.spark.concurrentSQL"));
+  }
+
+  @Override
+  public void close() {}
+
+  @Override
+  public InterpreterResult interpret(String st, InterpreterContext context)
+      throws InterpreterException {
+    SQLContext sqlc = null;
+    SparkInterpreter sparkInterpreter = getSparkInterpreter();
+
+    if (sparkInterpreter.isUnsupportedSparkVersion()) {
+      return new InterpreterResult(Code.ERROR, "Spark "
+          + sparkInterpreter.getSparkVersion().toString() + " is not supported");
+    }
+
+    sparkInterpreter.populateSparkWebUrl(context);
+    sparkInterpreter.getZeppelinContext().setInterpreterContext(context);
+    sqlc = sparkInterpreter.getSQLContext();
+    SparkContext sc = sqlc.sparkContext();
+    if (concurrentSQL()) {
+      sc.setLocalProperty("spark.scheduler.pool", "fair");
+    } else {
+      sc.setLocalProperty("spark.scheduler.pool", null);
+    }
+
+    String jobDesc = "Started by: " + Utils.getUserName(context.getAuthenticationInfo());
+    sc.setJobGroup(Utils.buildJobGroupId(context), jobDesc, false);
+    Object rdd = null;
+    try {
+      // method signature of sqlc.sql() is changed
+      // from  def sql(sqlText: String): SchemaRDD (1.2 and prior)
+      // to    def sql(sqlText: String): DataFrame (1.3 and later).
+      // Therefore need to use reflection to keep binary compatibility for all spark versions.
+      Method sqlMethod = sqlc.getClass().getMethod("sql", String.class);
+      rdd = sqlMethod.invoke(sqlc, st);
+    } catch (InvocationTargetException ite) {
+      if (Boolean.parseBoolean(getProperty("zeppelin.spark.sql.stacktrace"))) {
+        throw new InterpreterException(ite);
+      }
+      logger.error("Invocation target exception", ite);
+      String msg = ite.getTargetException().getMessage()
+              + "\nset zeppelin.spark.sql.stacktrace = true to see full stacktrace";
+      return new InterpreterResult(Code.ERROR, msg);
+    } catch (NoSuchMethodException | SecurityException | IllegalAccessException
+        | IllegalArgumentException e) {
+      throw new InterpreterException(e);
+    }
+
+    String msg = sparkInterpreter.getZeppelinContext().showData(rdd);
+    sc.clearJobGroup();
+    return new InterpreterResult(Code.SUCCESS, msg);
+  }
+
+  @Override
+  public void cancel(InterpreterContext context) throws InterpreterException {
+    SparkInterpreter sparkInterpreter = getSparkInterpreter();
+    SQLContext sqlc = sparkInterpreter.getSQLContext();
+    SparkContext sc = sqlc.sparkContext();
+
+    sc.cancelJobGroup(Utils.buildJobGroupId(context));
+  }
+
+  @Override
+  public FormType getFormType() {
+    return FormType.SIMPLE;
+  }
+
+
+  @Override
+  public int getProgress(InterpreterContext context) throws InterpreterException {
+    SparkInterpreter sparkInterpreter = getSparkInterpreter();
+    return sparkInterpreter.getProgress(context);
+  }
+
+  @Override
+  public Scheduler getScheduler() {
+    if (concurrentSQL()) {
+      int maxConcurrency = 10;
+      return SchedulerFactory.singleton().createOrGetParallelScheduler(
+          SparkSqlInterpreter.class.getName() + this.hashCode(), maxConcurrency);
+    } else {
+      // getSparkInterpreter() calls open() inside.
+      // That means if SparkInterpreter is not opened, it'll wait until SparkInterpreter open.
+      // In this moment UI displays 'READY' or 'FINISHED' instead of 'PENDING' or 'RUNNING'.
+      // It's because of scheduler is not created yet, and scheduler is created by this function.
+      // Therefore, we can still use getSparkInterpreter() here, but it's better and safe
+      // to getSparkInterpreter without opening it.
+
+      Interpreter intp =
+          getInterpreterInTheSameSessionByClassName(SparkInterpreter.class.getName());
+      if (intp != null) {
+        return intp.getScheduler();
+      } else {
+        return null;
+      }
+    }
+  }
+
+  @Override
+  public List<InterpreterCompletion> completion(String buf, int cursor,
+      InterpreterContext interpreterContext) {
+    return null;
+  }
+}

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/d762b528/spark/interpreter/src/main/java/org/apache/zeppelin/spark/SparkVersion.java
----------------------------------------------------------------------
diff --git a/spark/interpreter/src/main/java/org/apache/zeppelin/spark/SparkVersion.java b/spark/interpreter/src/main/java/org/apache/zeppelin/spark/SparkVersion.java
new file mode 100644
index 0000000..4b02798
--- /dev/null
+++ b/spark/interpreter/src/main/java/org/apache/zeppelin/spark/SparkVersion.java
@@ -0,0 +1,130 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.zeppelin.spark;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Provide reading comparing capability of spark version returned from SparkContext.version()
+ */
+public class SparkVersion {
+  Logger logger = LoggerFactory.getLogger(SparkVersion.class);
+
+  public static final SparkVersion SPARK_1_0_0 = SparkVersion.fromVersionString("1.0.0");
+  public static final SparkVersion SPARK_1_1_0 = SparkVersion.fromVersionString("1.1.0");
+  public static final SparkVersion SPARK_1_2_0 = SparkVersion.fromVersionString("1.2.0");
+  public static final SparkVersion SPARK_1_3_0 = SparkVersion.fromVersionString("1.3.0");
+  public static final SparkVersion SPARK_1_4_0 = SparkVersion.fromVersionString("1.4.0");
+  public static final SparkVersion SPARK_1_5_0 = SparkVersion.fromVersionString("1.5.0");
+  public static final SparkVersion SPARK_1_6_0 = SparkVersion.fromVersionString("1.6.0");
+
+  public static final SparkVersion SPARK_2_0_0 = SparkVersion.fromVersionString("2.0.0");
+  public static final SparkVersion SPARK_2_3_0 = SparkVersion.fromVersionString("2.3.0");
+
+  public static final SparkVersion MIN_SUPPORTED_VERSION =  SPARK_1_0_0;
+  public static final SparkVersion UNSUPPORTED_FUTURE_VERSION = SPARK_2_3_0;
+
+  private int version;
+  private String versionString;
+
+  SparkVersion(String versionString) {
+    this.versionString = versionString;
+
+    try {
+      int pos = versionString.indexOf('-');
+
+      String numberPart = versionString;
+      if (pos > 0) {
+        numberPart = versionString.substring(0, pos);
+      }
+
+      String versions[] = numberPart.split("\\.");
+      int major = Integer.parseInt(versions[0]);
+      int minor = Integer.parseInt(versions[1]);
+      int patch = Integer.parseInt(versions[2]);
+      // version is always 5 digits. (e.g. 2.0.0 -> 20000, 1.6.2 -> 10602)
+      version = Integer.parseInt(String.format("%d%02d%02d", major, minor, patch));
+    } catch (Exception e) {
+      logger.error("Can not recognize Spark version " + versionString +
+          ". Assume it's a future release", e);
+
+      // assume it is future release
+      version = 99999;
+    }
+  }
+
+  public int toNumber() {
+    return version;
+  }
+
+  public String toString() {
+    return versionString;
+  }
+
+  public boolean isUnsupportedVersion() {
+    return olderThan(MIN_SUPPORTED_VERSION) || newerThanEquals(UNSUPPORTED_FUTURE_VERSION);
+  }
+
+  public static SparkVersion fromVersionString(String versionString) {
+    return new SparkVersion(versionString);
+  }
+
+  public boolean isPysparkSupported() {
+    return this.newerThanEquals(SPARK_1_2_0);
+  }
+
+  public boolean isSparkRSupported() {
+    return this.newerThanEquals(SPARK_1_4_0);
+  }
+
+  public boolean hasDataFrame() {
+    return this.newerThanEquals(SPARK_1_4_0);
+  }
+
+  public boolean getProgress1_0() {
+    return this.olderThan(SPARK_1_1_0);
+  }
+
+  public boolean oldLoadFilesMethodName() {
+    return this.olderThan(SPARK_1_3_0);
+  }
+
+  public boolean oldSqlContextImplicits() {
+    return this.olderThan(SPARK_1_3_0);
+  }
+
+  public boolean equals(Object versionToCompare) {
+    return version == ((SparkVersion) versionToCompare).version;
+  }
+
+  public boolean newerThan(SparkVersion versionToCompare) {
+    return version > versionToCompare.version;
+  }
+
+  public boolean newerThanEquals(SparkVersion versionToCompare) {
+    return version >= versionToCompare.version;
+  }
+
+  public boolean olderThan(SparkVersion versionToCompare) {
+    return version < versionToCompare.version;
+  }
+
+  public boolean olderThanEquals(SparkVersion versionToCompare) {
+    return version <= versionToCompare.version;
+  }
+}

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/d762b528/spark/interpreter/src/main/java/org/apache/zeppelin/spark/SparkZeppelinContext.java
----------------------------------------------------------------------
diff --git a/spark/interpreter/src/main/java/org/apache/zeppelin/spark/SparkZeppelinContext.java b/spark/interpreter/src/main/java/org/apache/zeppelin/spark/SparkZeppelinContext.java
new file mode 100644
index 0000000..8847039
--- /dev/null
+++ b/spark/interpreter/src/main/java/org/apache/zeppelin/spark/SparkZeppelinContext.java
@@ -0,0 +1,312 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.zeppelin.spark;
+
+import com.google.common.collect.Lists;
+import org.apache.spark.SparkContext;
+import org.apache.spark.sql.SQLContext;
+import org.apache.spark.sql.catalyst.expressions.Attribute;
+import org.apache.zeppelin.annotation.ZeppelinApi;
+import org.apache.zeppelin.display.AngularObjectWatcher;
+import org.apache.zeppelin.display.Input;
+import org.apache.zeppelin.display.ui.OptionInput;
+import org.apache.zeppelin.interpreter.*;
+import scala.Tuple2;
+import scala.Unit;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.*;
+
+import static scala.collection.JavaConversions.asJavaCollection;
+import static scala.collection.JavaConversions.asJavaIterable;
+import static scala.collection.JavaConversions.collectionAsScalaIterable;
+
+/**
+ * ZeppelinContext for Spark
+ */
+public class SparkZeppelinContext extends BaseZeppelinContext {
+
+  private SparkContext sc;
+  private List<Class> supportedClasses;
+  private Map<String, String> interpreterClassMap;
+
+  public SparkZeppelinContext(
+      SparkContext sc,
+      InterpreterHookRegistry hooks,
+      int maxResult) {
+    super(hooks, maxResult);
+    this.sc = sc;
+
+    interpreterClassMap = new HashMap();
+    interpreterClassMap.put("spark", "org.apache.zeppelin.spark.SparkInterpreter");
+    interpreterClassMap.put("sql", "org.apache.zeppelin.spark.SparkSqlInterpreter");
+    interpreterClassMap.put("dep", "org.apache.zeppelin.spark.DepInterpreter");
+    interpreterClassMap.put("pyspark", "org.apache.zeppelin.spark.PySparkInterpreter");
+
+    this.supportedClasses = new ArrayList<>();
+    try {
+      supportedClasses.add(this.getClass().forName("org.apache.spark.sql.Dataset"));
+    } catch (ClassNotFoundException e) {
+    }
+
+    try {
+      supportedClasses.add(this.getClass().forName("org.apache.spark.sql.DataFrame"));
+    } catch (ClassNotFoundException e) {
+    }
+
+    try {
+      supportedClasses.add(this.getClass().forName("org.apache.spark.sql.SchemaRDD"));
+    } catch (ClassNotFoundException e) {
+    }
+
+    if (supportedClasses.isEmpty()) {
+      throw new RuntimeException("Can not load Dataset/DataFrame/SchemaRDD class");
+    }
+  }
+
+  @Override
+  public List<Class> getSupportedClasses() {
+    return supportedClasses;
+  }
+
+  @Override
+  public Map<String, String> getInterpreterClassMap() {
+    return interpreterClassMap;
+  }
+
+  @Override
+  public String showData(Object df) {
+    Object[] rows = null;
+    Method take;
+    String jobGroup = Utils.buildJobGroupId(interpreterContext);
+    sc.setJobGroup(jobGroup, "Zeppelin", false);
+
+    try {
+      // convert it to DataFrame if it is Dataset, as we will iterate all the records
+      // and assume it is type Row.
+      if (df.getClass().getCanonicalName().equals("org.apache.spark.sql.Dataset")) {
+        Method convertToDFMethod = df.getClass().getMethod("toDF");
+        df = convertToDFMethod.invoke(df);
+      }
+      take = df.getClass().getMethod("take", int.class);
+      rows = (Object[]) take.invoke(df, maxResult + 1);
+    } catch (NoSuchMethodException | SecurityException | IllegalAccessException
+        | IllegalArgumentException | InvocationTargetException | ClassCastException e) {
+      sc.clearJobGroup();
+      throw new RuntimeException(e);
+    }
+
+    List<Attribute> columns = null;
+    // get field names
+    try {
+      // Use reflection because of classname returned by queryExecution changes from
+      // Spark <1.5.2 org.apache.spark.sql.SQLContext$QueryExecution
+      // Spark 1.6.0> org.apache.spark.sql.hive.HiveContext$QueryExecution
+      Object qe = df.getClass().getMethod("queryExecution").invoke(df);
+      Object a = qe.getClass().getMethod("analyzed").invoke(qe);
+      scala.collection.Seq seq = (scala.collection.Seq) a.getClass().getMethod("output").invoke(a);
+
+      columns = (List<Attribute>) scala.collection.JavaConverters.seqAsJavaListConverter(seq)
+          .asJava();
+    } catch (NoSuchMethodException | SecurityException | IllegalAccessException
+        | IllegalArgumentException | InvocationTargetException e) {
+      throw new RuntimeException(e);
+    }
+
+    StringBuilder msg = new StringBuilder();
+    msg.append("%table ");
+    for (Attribute col : columns) {
+      msg.append(col.name() + "\t");
+    }
+    String trim = msg.toString().trim();
+    msg = new StringBuilder(trim);
+    msg.append("\n");
+
+    // ArrayType, BinaryType, BooleanType, ByteType, DecimalType, DoubleType, DynamicType,
+    // FloatType, FractionalType, IntegerType, IntegralType, LongType, MapType, NativeType,
+    // NullType, NumericType, ShortType, StringType, StructType
+
+    try {
+      for (int r = 0; r < maxResult && r < rows.length; r++) {
+        Object row = rows[r];
+        Method isNullAt = row.getClass().getMethod("isNullAt", int.class);
+        Method apply = row.getClass().getMethod("apply", int.class);
+
+        for (int i = 0; i < columns.size(); i++) {
+          if (!(Boolean) isNullAt.invoke(row, i)) {
+            msg.append(apply.invoke(row, i).toString());
+          } else {
+            msg.append("null");
+          }
+          if (i != columns.size() - 1) {
+            msg.append("\t");
+          }
+        }
+        msg.append("\n");
+      }
+    } catch (NoSuchMethodException | SecurityException | IllegalAccessException
+        | IllegalArgumentException | InvocationTargetException e) {
+      throw new RuntimeException(e);
+    }
+
+    if (rows.length > maxResult) {
+      msg.append("\n");
+      msg.append(ResultMessages.getExceedsLimitRowsMessage(maxResult,
+          SparkSqlInterpreter.MAX_RESULTS));
+    }
+
+    sc.clearJobGroup();
+    return msg.toString();
+  }
+
+  @ZeppelinApi
+  public Object select(String name, scala.collection.Iterable<Tuple2<Object, String>> options) {
+    return select(name, "", options);
+  }
+
+  @ZeppelinApi
+  public Object select(String name, Object defaultValue,
+                       scala.collection.Iterable<Tuple2<Object, String>> options) {
+    return select(name, defaultValue, tuplesToParamOptions(options));
+  }
+
+  @ZeppelinApi
+  public scala.collection.Seq<Object> checkbox(
+      String name,
+      scala.collection.Iterable<Tuple2<Object, String>> options) {
+    List<Object> allChecked = new LinkedList<>();
+    for (Tuple2<Object, String> option : asJavaIterable(options)) {
+      allChecked.add(option._1());
+    }
+    return checkbox(name, collectionAsScalaIterable(allChecked), options);
+  }
+
+  @ZeppelinApi
+  public scala.collection.Seq<Object> checkbox(
+      String name,
+      scala.collection.Iterable<Object> defaultChecked,
+      scala.collection.Iterable<Tuple2<Object, String>> options) {
+    List<Object> defaultCheckedList = Lists.newArrayList(asJavaIterable(defaultChecked).iterator());
+    Collection<Object> checkbox = checkbox(name, defaultCheckedList, tuplesToParamOptions(options));
+    List<Object> checkboxList = Arrays.asList(checkbox.toArray());
+    return scala.collection.JavaConversions.asScalaBuffer(checkboxList).toSeq();
+  }
+
+  @ZeppelinApi
+  public Object noteSelect(String name, scala.collection.Iterable<Tuple2<Object, String>> options) {
+    return noteSelect(name, "", options);
+  }
+
+  @ZeppelinApi
+  public Object noteSelect(String name, Object defaultValue,
+                       scala.collection.Iterable<Tuple2<Object, String>> options) {
+    return noteSelect(name, defaultValue, tuplesToParamOptions(options));
+  }
+
+  @ZeppelinApi
+  public scala.collection.Seq<Object> noteCheckbox(
+      String name,
+      scala.collection.Iterable<Tuple2<Object, String>> options) {
+    List<Object> allChecked = new LinkedList<>();
+    for (Tuple2<Object, String> option : asJavaIterable(options)) {
+      allChecked.add(option._1());
+    }
+    return noteCheckbox(name, collectionAsScalaIterable(allChecked), options);
+  }
+
+  @ZeppelinApi
+  public scala.collection.Seq<Object> noteCheckbox(
+      String name,
+      scala.collection.Iterable<Object> defaultChecked,
+      scala.collection.Iterable<Tuple2<Object, String>> options) {
+    List<Object> defaultCheckedList = Lists.newArrayList(asJavaIterable(defaultChecked).iterator());
+    Collection<Object> checkbox = noteCheckbox(name, defaultCheckedList,
+        tuplesToParamOptions(options));
+    List<Object> checkboxList = Arrays.asList(checkbox.toArray());
+    return scala.collection.JavaConversions.asScalaBuffer(checkboxList).toSeq();
+  }
+
+  private OptionInput.ParamOption[] tuplesToParamOptions(
+      scala.collection.Iterable<Tuple2<Object, String>> options) {
+    int n = options.size();
+    OptionInput.ParamOption[] paramOptions = new OptionInput.ParamOption[n];
+    Iterator<Tuple2<Object, String>> it = asJavaIterable(options).iterator();
+
+    int i = 0;
+    while (it.hasNext()) {
+      Tuple2<Object, String> valueAndDisplayValue = it.next();
+      paramOptions[i++] = new OptionInput.ParamOption(valueAndDisplayValue._1(),
+          valueAndDisplayValue._2());
+    }
+
+    return paramOptions;
+  }
+
+  @ZeppelinApi
+  public void angularWatch(String name,
+                           final scala.Function2<Object, Object, Unit> func) {
+    angularWatch(name, interpreterContext.getNoteId(), func);
+  }
+
+  @Deprecated
+  public void angularWatchGlobal(String name,
+                                 final scala.Function2<Object, Object, Unit> func) {
+    angularWatch(name, null, func);
+  }
+
+  @ZeppelinApi
+  public void angularWatch(
+      String name,
+      final scala.Function3<Object, Object, InterpreterContext, Unit> func) {
+    angularWatch(name, interpreterContext.getNoteId(), func);
+  }
+
+  @Deprecated
+  public void angularWatchGlobal(
+      String name,
+      final scala.Function3<Object, Object, InterpreterContext, Unit> func) {
+    angularWatch(name, null, func);
+  }
+
+  private void angularWatch(String name, String noteId,
+                            final scala.Function2<Object, Object, Unit> func) {
+    AngularObjectWatcher w = new AngularObjectWatcher(getInterpreterContext()) {
+      @Override
+      public void watch(Object oldObject, Object newObject,
+                        InterpreterContext context) {
+        func.apply(newObject, newObject);
+      }
+    };
+    angularWatch(name, noteId, w);
+  }
+
+  private void angularWatch(
+      String name,
+      String noteId,
+      final scala.Function3<Object, Object, InterpreterContext, Unit> func) {
+    AngularObjectWatcher w = new AngularObjectWatcher(getInterpreterContext()) {
+      @Override
+      public void watch(Object oldObject, Object newObject,
+                        InterpreterContext context) {
+        func.apply(oldObject, newObject, context);
+      }
+    };
+    angularWatch(name, noteId, w);
+  }
+}

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/d762b528/spark/interpreter/src/main/java/org/apache/zeppelin/spark/Utils.java
----------------------------------------------------------------------
diff --git a/spark/interpreter/src/main/java/org/apache/zeppelin/spark/Utils.java b/spark/interpreter/src/main/java/org/apache/zeppelin/spark/Utils.java
new file mode 100644
index 0000000..82bf210
--- /dev/null
+++ b/spark/interpreter/src/main/java/org/apache/zeppelin/spark/Utils.java
@@ -0,0 +1,177 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.zeppelin.spark;
+
+import org.apache.zeppelin.interpreter.InterpreterContext;
+import org.apache.zeppelin.user.AuthenticationInfo;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.util.Properties;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Utility and helper functions for the Spark Interpreter
+ */
+class Utils {
+  public static Logger logger = LoggerFactory.getLogger(Utils.class);
+  private static final String SCALA_COMPILER_VERSION = evaluateScalaCompilerVersion();
+
+  static Object invokeMethod(Object o, String name) {
+    return invokeMethod(o, name, new Class[]{}, new Object[]{});
+  }
+
+  static Object invokeMethod(Object o, String name, Class<?>[] argTypes, Object[] params) {
+    try {
+      return o.getClass().getMethod(name, argTypes).invoke(o, params);
+    } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
+      logger.error(e.getMessage(), e);
+    }
+    return null;
+  }
+
+  static Object invokeStaticMethod(Class<?> c, String name, Class<?>[] argTypes, Object[] params) {
+    try {
+      return c.getMethod(name, argTypes).invoke(null, params);
+    } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
+      logger.error(e.getMessage(), e);
+    }
+    return null;
+  }
+
+  static Object invokeStaticMethod(Class<?> c, String name) {
+    return invokeStaticMethod(c, name, new Class[]{}, new Object[]{});
+  }
+
+  static Class<?> findClass(String name) {
+    return findClass(name, false);
+  }
+
+  static Class<?> findClass(String name, boolean silence) {
+    try {
+      return Class.forName(name);
+    } catch (ClassNotFoundException e) {
+      if (!silence) {
+        logger.error(e.getMessage(), e);
+      }
+      return null;
+    }
+  }
+
+  static Object instantiateClass(String name, Class<?>[] argTypes, Object[] params) {
+    try {
+      Constructor<?> constructor = Utils.class.getClassLoader()
+              .loadClass(name).getConstructor(argTypes);
+      return constructor.newInstance(params);
+    } catch (NoSuchMethodException | ClassNotFoundException | IllegalAccessException |
+      InstantiationException | InvocationTargetException e) {
+      logger.error(e.getMessage(), e);
+    }
+    return null;
+  }
+
+  // function works after intp is initialized
+  static boolean isScala2_10() {
+    try {
+      Class.forName("org.apache.spark.repl.SparkIMain");
+      return true;
+    } catch (ClassNotFoundException e) {
+      return false;
+    } catch (IncompatibleClassChangeError e) {
+      return false;
+    }
+  }
+
+  static boolean isScala2_11() {
+    return !isScala2_10();
+  }
+  
+  static boolean isCompilerAboveScala2_11_7() {
+    if (isScala2_10() || SCALA_COMPILER_VERSION == null) {
+      return false;
+    }
+    Pattern p = Pattern.compile("([0-9]+)[.]([0-9]+)[.]([0-9]+)");
+    Matcher m = p.matcher(SCALA_COMPILER_VERSION);
+    if (m.matches()) {
+      int major = Integer.parseInt(m.group(1));
+      int minor = Integer.parseInt(m.group(2));
+      int bugfix = Integer.parseInt(m.group(3));
+      return (major > 2 || (major == 2 && minor > 11) || (major == 2 && minor == 11 && bugfix > 7));
+    }
+    return false;
+  }
+
+  private static String evaluateScalaCompilerVersion() {
+    String version = null;
+    try {
+      Properties p = new Properties();
+      Class<?> completionClass = findClass("scala.tools.nsc.interpreter.JLineCompletion");
+      if (completionClass != null) {
+        try (java.io.InputStream in = completionClass.getClass()
+          .getResourceAsStream("/compiler.properties")) {
+          p.load(in);
+          version = p.getProperty("version.number");
+        } catch (java.io.IOException e) {
+          logger.error("Failed to evaluate Scala compiler version", e);
+        }
+      }
+    } catch (RuntimeException e) {
+      logger.error("Failed to evaluate Scala compiler version", e);
+    }
+    return version;
+  }
+
+  static boolean isSpark2() {
+    try {
+      Class.forName("org.apache.spark.sql.SparkSession");
+      return true;
+    } catch (ClassNotFoundException e) {
+      return false;
+    }
+  }
+  
+  public static String buildJobGroupId(InterpreterContext context) {
+    return "zeppelin-" + context.getNoteId() + "-" + context.getParagraphId();
+  }
+
+  public static String getNoteId(String jobgroupId) {
+    int indexOf = jobgroupId.indexOf("-");
+    int secondIndex = jobgroupId.indexOf("-", indexOf + 1);
+    return jobgroupId.substring(indexOf + 1, secondIndex);
+  }
+
+  public static String getParagraphId(String jobgroupId) {
+    int indexOf = jobgroupId.indexOf("-");
+    int secondIndex = jobgroupId.indexOf("-", indexOf + 1);
+    return jobgroupId.substring(secondIndex + 1, jobgroupId.length());
+  }
+
+  public static String getUserName(AuthenticationInfo info) {
+    String uName = "";
+    if (info != null) {
+      uName = info.getUser();
+    }
+    if (uName == null || uName.isEmpty()) {
+      uName = "anonymous";
+    }
+    return uName;
+  }
+}

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/d762b528/spark/interpreter/src/main/java/org/apache/zeppelin/spark/ZeppelinR.java
----------------------------------------------------------------------
diff --git a/spark/interpreter/src/main/java/org/apache/zeppelin/spark/ZeppelinR.java b/spark/interpreter/src/main/java/org/apache/zeppelin/spark/ZeppelinR.java
new file mode 100644
index 0000000..130d849
--- /dev/null
+++ b/spark/interpreter/src/main/java/org/apache/zeppelin/spark/ZeppelinR.java
@@ -0,0 +1,394 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.zeppelin.spark;
+
+import org.apache.commons.exec.*;
+import org.apache.commons.exec.environment.EnvironmentUtils;
+import org.apache.commons.io.IOUtils;
+import org.apache.zeppelin.interpreter.InterpreterException;
+import org.apache.zeppelin.interpreter.InterpreterOutput;
+import org.apache.zeppelin.interpreter.InterpreterOutputListener;
+import org.apache.zeppelin.interpreter.InterpreterResultMessageOutput;
+import org.apache.zeppelin.interpreter.util.InterpreterOutputStream;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.*;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * R repl interaction
+ */
+public class ZeppelinR implements ExecuteResultHandler {
+  Logger logger = LoggerFactory.getLogger(ZeppelinR.class);
+  private final String rCmdPath;
+  private final SparkVersion sparkVersion;
+  private DefaultExecutor executor;
+  private InterpreterOutputStream outputStream;
+  private PipedOutputStream input;
+  private final String scriptPath;
+  private final String libPath;
+  static Map<Integer, ZeppelinR> zeppelinR = Collections.synchronizedMap(
+      new HashMap<Integer, ZeppelinR>());
+
+  private InterpreterOutput initialOutput;
+  private final int port;
+  private boolean rScriptRunning;
+
+  /**
+   * To be notified R repl initialization
+   */
+  boolean rScriptInitialized = false;
+  Integer rScriptInitializeNotifier = new Integer(0);
+
+  /**
+   * Request to R repl
+   */
+  Request rRequestObject = null;
+  Integer rRequestNotifier = new Integer(0);
+
+  /**
+   * Request object
+   *
+   * type : "eval", "set", "get"
+   * stmt : statement to evaluate when type is "eval"
+   *        key when type is "set" or "get"
+   * value : value object when type is "put"
+   */
+  public static class Request {
+    String type;
+    String stmt;
+    Object value;
+
+    public Request(String type, String stmt, Object value) {
+      this.type = type;
+      this.stmt = stmt;
+      this.value = value;
+    }
+
+    public String getType() {
+      return type;
+    }
+
+    public String getStmt() {
+      return stmt;
+    }
+
+    public Object getValue() {
+      return value;
+    }
+  }
+
+  /**
+   * Response from R repl
+   */
+  Object rResponseValue = null;
+  boolean rResponseError = false;
+  Integer rResponseNotifier = new Integer(0);
+
+  /**
+   * Create ZeppelinR instance
+   * @param rCmdPath R repl commandline path
+   * @param libPath sparkr library path
+   */
+  public ZeppelinR(String rCmdPath, String libPath, int sparkRBackendPort,
+      SparkVersion sparkVersion) {
+    this.rCmdPath = rCmdPath;
+    this.libPath = libPath;
+    this.sparkVersion = sparkVersion;
+    this.port = sparkRBackendPort;
+    try {
+      File scriptFile = File.createTempFile("zeppelin_sparkr-", ".R");
+      scriptPath = scriptFile.getAbsolutePath();
+    } catch (IOException e) {
+      throw new RuntimeException(e);
+    }
+  }
+
+  /**
+   * Start R repl
+   * @throws IOException
+   */
+  public void open() throws IOException, InterpreterException {
+    createRScript();
+
+    zeppelinR.put(hashCode(), this);
+
+    CommandLine cmd = CommandLine.parse(rCmdPath);
+    cmd.addArgument("--no-save");
+    cmd.addArgument("--no-restore");
+    cmd.addArgument("-f");
+    cmd.addArgument(scriptPath);
+    cmd.addArgument("--args");
+    cmd.addArgument(Integer.toString(hashCode()));
+    cmd.addArgument(Integer.toString(port));
+    cmd.addArgument(libPath);
+    cmd.addArgument(Integer.toString(sparkVersion.toNumber()));
+    
+    // dump out the R command to facilitate manually running it, e.g. for fault diagnosis purposes
+    logger.debug(cmd.toString());
+
+    executor = new DefaultExecutor();
+    outputStream = new InterpreterOutputStream(logger);
+
+    input = new PipedOutputStream();
+    PipedInputStream in = new PipedInputStream(input);
+
+    PumpStreamHandler streamHandler = new PumpStreamHandler(outputStream, outputStream, in);
+    executor.setWatchdog(new ExecuteWatchdog(ExecuteWatchdog.INFINITE_TIMEOUT));
+    executor.setStreamHandler(streamHandler);
+    Map env = EnvironmentUtils.getProcEnvironment();
+
+
+    initialOutput = new InterpreterOutput(null);
+    outputStream.setInterpreterOutput(initialOutput);
+    executor.execute(cmd, env, this);
+    rScriptRunning = true;
+
+    // flush output
+    eval("cat('')");
+  }
+
+  /**
+   * Evaluate expression
+   * @param expr
+   * @return
+   */
+  public Object eval(String expr) throws InterpreterException {
+    synchronized (this) {
+      rRequestObject = new Request("eval", expr, null);
+      return request();
+    }
+  }
+
+  /**
+   * assign value to key
+   * @param key
+   * @param value
+   */
+  public void set(String key, Object value) throws InterpreterException {
+    synchronized (this) {
+      rRequestObject = new Request("set", key, value);
+      request();
+    }
+  }
+
+  /**
+   * get value of key
+   * @param key
+   * @return
+   */
+  public Object get(String key) throws InterpreterException {
+    synchronized (this) {
+      rRequestObject = new Request("get", key, null);
+      return request();
+    }
+  }
+
+  /**
+   * get value of key, as a string
+   * @param key
+   * @return
+   */
+  public String getS0(String key) throws InterpreterException {
+    synchronized (this) {
+      rRequestObject = new Request("getS", key, null);
+      return (String) request();
+    }
+  }
+
+  /**
+   * Send request to r repl and return response
+   * @return responseValue
+   */
+  private Object request() throws RuntimeException, InterpreterException {
+    if (!rScriptRunning) {
+      throw new RuntimeException("r repl is not running");
+    }
+
+    // wait for rscript initialized
+    if (!rScriptInitialized) {
+      waitForRScriptInitialized();
+    }
+
+    rResponseValue = null;
+
+    synchronized (rRequestNotifier) {
+      rRequestNotifier.notify();
+    }
+
+    Object respValue = null;
+    synchronized (rResponseNotifier) {
+      while (rResponseValue == null && rScriptRunning) {
+        try {
+          rResponseNotifier.wait(1000);
+        } catch (InterruptedException e) {
+          logger.error(e.getMessage(), e);
+        }
+      }
+      respValue = rResponseValue;
+      rResponseValue = null;
+    }
+
+    if (rResponseError) {
+      throw new RuntimeException(respValue.toString());
+    } else {
+      return respValue;
+    }
+  }
+
+  /**
+   * Wait until src/main/resources/R/zeppelin_sparkr.R is initialized
+   * and call onScriptInitialized()
+   *
+   * @throws InterpreterException
+   */
+  private void waitForRScriptInitialized() throws InterpreterException {
+    synchronized (rScriptInitializeNotifier) {
+      long startTime = System.nanoTime();
+      while (rScriptInitialized == false &&
+          rScriptRunning &&
+          System.nanoTime() - startTime < 10L * 1000 * 1000000) {
+        try {
+          rScriptInitializeNotifier.wait(1000);
+        } catch (InterruptedException e) {
+          logger.error(e.getMessage(), e);
+        }
+      }
+    }
+
+    String errorMessage = "";
+    try {
+      initialOutput.flush();
+      errorMessage = new String(initialOutput.toByteArray());
+    } catch (IOException e) {
+      e.printStackTrace();
+    }
+
+    if (rScriptInitialized == false) {
+      throw new InterpreterException("sparkr is not responding " + errorMessage);
+    }
+  }
+
+  /**
+   * invoked by src/main/resources/R/zeppelin_sparkr.R
+   * @return
+   */
+  public Request getRequest() {
+    synchronized (rRequestNotifier) {
+      while (rRequestObject == null) {
+        try {
+          rRequestNotifier.wait(1000);
+        } catch (InterruptedException e) {
+          logger.error(e.getMessage(), e);
+        }
+      }
+
+      Request req = rRequestObject;
+      rRequestObject = null;
+      return req;
+    }
+  }
+
+  /**
+   * invoked by src/main/resources/R/zeppelin_sparkr.R
+   * @param value
+   * @param error
+   */
+  public void setResponse(Object value, boolean error) {
+    synchronized (rResponseNotifier) {
+      rResponseValue = value;
+      rResponseError = error;
+      rResponseNotifier.notify();
+    }
+  }
+
+  /**
+   * invoked by src/main/resources/R/zeppelin_sparkr.R
+   */
+  public void onScriptInitialized() {
+    synchronized (rScriptInitializeNotifier) {
+      rScriptInitialized = true;
+      rScriptInitializeNotifier.notifyAll();
+    }
+  }
+
+  /**
+   * Create R script in tmp dir
+   */
+  private void createRScript() throws InterpreterException {
+    ClassLoader classLoader = getClass().getClassLoader();
+    File out = new File(scriptPath);
+
+    if (out.exists() && out.isDirectory()) {
+      throw new InterpreterException("Can't create r script " + out.getAbsolutePath());
+    }
+
+    try {
+      FileOutputStream outStream = new FileOutputStream(out);
+      IOUtils.copy(
+          classLoader.getResourceAsStream("R/zeppelin_sparkr.R"),
+          outStream);
+      outStream.close();
+    } catch (IOException e) {
+      throw new InterpreterException(e);
+    }
+
+    logger.info("File {} created", scriptPath);
+  }
+
+  /**
+   * Terminate this R repl
+   */
+  public void close() {
+    executor.getWatchdog().destroyProcess();
+    new File(scriptPath).delete();
+    zeppelinR.remove(hashCode());
+  }
+
+  /**
+   * Get instance
+   * This method will be invoded from zeppelin_sparkr.R
+   * @param hashcode
+   * @return
+   */
+  public static ZeppelinR getZeppelinR(int hashcode) {
+    return zeppelinR.get(hashcode);
+  }
+
+  /**
+   * Pass InterpreterOutput to capture the repl output
+   * @param out
+   */
+  public void setInterpreterOutput(InterpreterOutput out) {
+    outputStream.setInterpreterOutput(out);
+  }
+
+  @Override
+  public void onProcessComplete(int i) {
+    logger.info("process complete {}", i);
+    rScriptRunning = false;
+  }
+
+  @Override
+  public void onProcessFailed(ExecuteException e) {
+    logger.error(e.getMessage(), e);
+    rScriptRunning = false;
+  }
+}


[02/10] zeppelin git commit: ZEPPELIN-3111. Refactor SparkInterpreter

Posted by zj...@apache.org.
http://git-wip-us.apache.org/repos/asf/zeppelin/blob/d762b528/spark/src/main/java/org/apache/zeppelin/spark/Utils.java
----------------------------------------------------------------------
diff --git a/spark/src/main/java/org/apache/zeppelin/spark/Utils.java b/spark/src/main/java/org/apache/zeppelin/spark/Utils.java
deleted file mode 100644
index 82bf210..0000000
--- a/spark/src/main/java/org/apache/zeppelin/spark/Utils.java
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.zeppelin.spark;
-
-import org.apache.zeppelin.interpreter.InterpreterContext;
-import org.apache.zeppelin.user.AuthenticationInfo;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.lang.reflect.Constructor;
-import java.lang.reflect.InvocationTargetException;
-import java.util.Properties;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * Utility and helper functions for the Spark Interpreter
- */
-class Utils {
-  public static Logger logger = LoggerFactory.getLogger(Utils.class);
-  private static final String SCALA_COMPILER_VERSION = evaluateScalaCompilerVersion();
-
-  static Object invokeMethod(Object o, String name) {
-    return invokeMethod(o, name, new Class[]{}, new Object[]{});
-  }
-
-  static Object invokeMethod(Object o, String name, Class<?>[] argTypes, Object[] params) {
-    try {
-      return o.getClass().getMethod(name, argTypes).invoke(o, params);
-    } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
-      logger.error(e.getMessage(), e);
-    }
-    return null;
-  }
-
-  static Object invokeStaticMethod(Class<?> c, String name, Class<?>[] argTypes, Object[] params) {
-    try {
-      return c.getMethod(name, argTypes).invoke(null, params);
-    } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
-      logger.error(e.getMessage(), e);
-    }
-    return null;
-  }
-
-  static Object invokeStaticMethod(Class<?> c, String name) {
-    return invokeStaticMethod(c, name, new Class[]{}, new Object[]{});
-  }
-
-  static Class<?> findClass(String name) {
-    return findClass(name, false);
-  }
-
-  static Class<?> findClass(String name, boolean silence) {
-    try {
-      return Class.forName(name);
-    } catch (ClassNotFoundException e) {
-      if (!silence) {
-        logger.error(e.getMessage(), e);
-      }
-      return null;
-    }
-  }
-
-  static Object instantiateClass(String name, Class<?>[] argTypes, Object[] params) {
-    try {
-      Constructor<?> constructor = Utils.class.getClassLoader()
-              .loadClass(name).getConstructor(argTypes);
-      return constructor.newInstance(params);
-    } catch (NoSuchMethodException | ClassNotFoundException | IllegalAccessException |
-      InstantiationException | InvocationTargetException e) {
-      logger.error(e.getMessage(), e);
-    }
-    return null;
-  }
-
-  // function works after intp is initialized
-  static boolean isScala2_10() {
-    try {
-      Class.forName("org.apache.spark.repl.SparkIMain");
-      return true;
-    } catch (ClassNotFoundException e) {
-      return false;
-    } catch (IncompatibleClassChangeError e) {
-      return false;
-    }
-  }
-
-  static boolean isScala2_11() {
-    return !isScala2_10();
-  }
-  
-  static boolean isCompilerAboveScala2_11_7() {
-    if (isScala2_10() || SCALA_COMPILER_VERSION == null) {
-      return false;
-    }
-    Pattern p = Pattern.compile("([0-9]+)[.]([0-9]+)[.]([0-9]+)");
-    Matcher m = p.matcher(SCALA_COMPILER_VERSION);
-    if (m.matches()) {
-      int major = Integer.parseInt(m.group(1));
-      int minor = Integer.parseInt(m.group(2));
-      int bugfix = Integer.parseInt(m.group(3));
-      return (major > 2 || (major == 2 && minor > 11) || (major == 2 && minor == 11 && bugfix > 7));
-    }
-    return false;
-  }
-
-  private static String evaluateScalaCompilerVersion() {
-    String version = null;
-    try {
-      Properties p = new Properties();
-      Class<?> completionClass = findClass("scala.tools.nsc.interpreter.JLineCompletion");
-      if (completionClass != null) {
-        try (java.io.InputStream in = completionClass.getClass()
-          .getResourceAsStream("/compiler.properties")) {
-          p.load(in);
-          version = p.getProperty("version.number");
-        } catch (java.io.IOException e) {
-          logger.error("Failed to evaluate Scala compiler version", e);
-        }
-      }
-    } catch (RuntimeException e) {
-      logger.error("Failed to evaluate Scala compiler version", e);
-    }
-    return version;
-  }
-
-  static boolean isSpark2() {
-    try {
-      Class.forName("org.apache.spark.sql.SparkSession");
-      return true;
-    } catch (ClassNotFoundException e) {
-      return false;
-    }
-  }
-  
-  public static String buildJobGroupId(InterpreterContext context) {
-    return "zeppelin-" + context.getNoteId() + "-" + context.getParagraphId();
-  }
-
-  public static String getNoteId(String jobgroupId) {
-    int indexOf = jobgroupId.indexOf("-");
-    int secondIndex = jobgroupId.indexOf("-", indexOf + 1);
-    return jobgroupId.substring(indexOf + 1, secondIndex);
-  }
-
-  public static String getParagraphId(String jobgroupId) {
-    int indexOf = jobgroupId.indexOf("-");
-    int secondIndex = jobgroupId.indexOf("-", indexOf + 1);
-    return jobgroupId.substring(secondIndex + 1, jobgroupId.length());
-  }
-
-  public static String getUserName(AuthenticationInfo info) {
-    String uName = "";
-    if (info != null) {
-      uName = info.getUser();
-    }
-    if (uName == null || uName.isEmpty()) {
-      uName = "anonymous";
-    }
-    return uName;
-  }
-}

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/d762b528/spark/src/main/java/org/apache/zeppelin/spark/ZeppelinR.java
----------------------------------------------------------------------
diff --git a/spark/src/main/java/org/apache/zeppelin/spark/ZeppelinR.java b/spark/src/main/java/org/apache/zeppelin/spark/ZeppelinR.java
deleted file mode 100644
index 130d849..0000000
--- a/spark/src/main/java/org/apache/zeppelin/spark/ZeppelinR.java
+++ /dev/null
@@ -1,394 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.zeppelin.spark;
-
-import org.apache.commons.exec.*;
-import org.apache.commons.exec.environment.EnvironmentUtils;
-import org.apache.commons.io.IOUtils;
-import org.apache.zeppelin.interpreter.InterpreterException;
-import org.apache.zeppelin.interpreter.InterpreterOutput;
-import org.apache.zeppelin.interpreter.InterpreterOutputListener;
-import org.apache.zeppelin.interpreter.InterpreterResultMessageOutput;
-import org.apache.zeppelin.interpreter.util.InterpreterOutputStream;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.io.*;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * R repl interaction
- */
-public class ZeppelinR implements ExecuteResultHandler {
-  Logger logger = LoggerFactory.getLogger(ZeppelinR.class);
-  private final String rCmdPath;
-  private final SparkVersion sparkVersion;
-  private DefaultExecutor executor;
-  private InterpreterOutputStream outputStream;
-  private PipedOutputStream input;
-  private final String scriptPath;
-  private final String libPath;
-  static Map<Integer, ZeppelinR> zeppelinR = Collections.synchronizedMap(
-      new HashMap<Integer, ZeppelinR>());
-
-  private InterpreterOutput initialOutput;
-  private final int port;
-  private boolean rScriptRunning;
-
-  /**
-   * To be notified R repl initialization
-   */
-  boolean rScriptInitialized = false;
-  Integer rScriptInitializeNotifier = new Integer(0);
-
-  /**
-   * Request to R repl
-   */
-  Request rRequestObject = null;
-  Integer rRequestNotifier = new Integer(0);
-
-  /**
-   * Request object
-   *
-   * type : "eval", "set", "get"
-   * stmt : statement to evaluate when type is "eval"
-   *        key when type is "set" or "get"
-   * value : value object when type is "put"
-   */
-  public static class Request {
-    String type;
-    String stmt;
-    Object value;
-
-    public Request(String type, String stmt, Object value) {
-      this.type = type;
-      this.stmt = stmt;
-      this.value = value;
-    }
-
-    public String getType() {
-      return type;
-    }
-
-    public String getStmt() {
-      return stmt;
-    }
-
-    public Object getValue() {
-      return value;
-    }
-  }
-
-  /**
-   * Response from R repl
-   */
-  Object rResponseValue = null;
-  boolean rResponseError = false;
-  Integer rResponseNotifier = new Integer(0);
-
-  /**
-   * Create ZeppelinR instance
-   * @param rCmdPath R repl commandline path
-   * @param libPath sparkr library path
-   */
-  public ZeppelinR(String rCmdPath, String libPath, int sparkRBackendPort,
-      SparkVersion sparkVersion) {
-    this.rCmdPath = rCmdPath;
-    this.libPath = libPath;
-    this.sparkVersion = sparkVersion;
-    this.port = sparkRBackendPort;
-    try {
-      File scriptFile = File.createTempFile("zeppelin_sparkr-", ".R");
-      scriptPath = scriptFile.getAbsolutePath();
-    } catch (IOException e) {
-      throw new RuntimeException(e);
-    }
-  }
-
-  /**
-   * Start R repl
-   * @throws IOException
-   */
-  public void open() throws IOException, InterpreterException {
-    createRScript();
-
-    zeppelinR.put(hashCode(), this);
-
-    CommandLine cmd = CommandLine.parse(rCmdPath);
-    cmd.addArgument("--no-save");
-    cmd.addArgument("--no-restore");
-    cmd.addArgument("-f");
-    cmd.addArgument(scriptPath);
-    cmd.addArgument("--args");
-    cmd.addArgument(Integer.toString(hashCode()));
-    cmd.addArgument(Integer.toString(port));
-    cmd.addArgument(libPath);
-    cmd.addArgument(Integer.toString(sparkVersion.toNumber()));
-    
-    // dump out the R command to facilitate manually running it, e.g. for fault diagnosis purposes
-    logger.debug(cmd.toString());
-
-    executor = new DefaultExecutor();
-    outputStream = new InterpreterOutputStream(logger);
-
-    input = new PipedOutputStream();
-    PipedInputStream in = new PipedInputStream(input);
-
-    PumpStreamHandler streamHandler = new PumpStreamHandler(outputStream, outputStream, in);
-    executor.setWatchdog(new ExecuteWatchdog(ExecuteWatchdog.INFINITE_TIMEOUT));
-    executor.setStreamHandler(streamHandler);
-    Map env = EnvironmentUtils.getProcEnvironment();
-
-
-    initialOutput = new InterpreterOutput(null);
-    outputStream.setInterpreterOutput(initialOutput);
-    executor.execute(cmd, env, this);
-    rScriptRunning = true;
-
-    // flush output
-    eval("cat('')");
-  }
-
-  /**
-   * Evaluate expression
-   * @param expr
-   * @return
-   */
-  public Object eval(String expr) throws InterpreterException {
-    synchronized (this) {
-      rRequestObject = new Request("eval", expr, null);
-      return request();
-    }
-  }
-
-  /**
-   * assign value to key
-   * @param key
-   * @param value
-   */
-  public void set(String key, Object value) throws InterpreterException {
-    synchronized (this) {
-      rRequestObject = new Request("set", key, value);
-      request();
-    }
-  }
-
-  /**
-   * get value of key
-   * @param key
-   * @return
-   */
-  public Object get(String key) throws InterpreterException {
-    synchronized (this) {
-      rRequestObject = new Request("get", key, null);
-      return request();
-    }
-  }
-
-  /**
-   * get value of key, as a string
-   * @param key
-   * @return
-   */
-  public String getS0(String key) throws InterpreterException {
-    synchronized (this) {
-      rRequestObject = new Request("getS", key, null);
-      return (String) request();
-    }
-  }
-
-  /**
-   * Send request to r repl and return response
-   * @return responseValue
-   */
-  private Object request() throws RuntimeException, InterpreterException {
-    if (!rScriptRunning) {
-      throw new RuntimeException("r repl is not running");
-    }
-
-    // wait for rscript initialized
-    if (!rScriptInitialized) {
-      waitForRScriptInitialized();
-    }
-
-    rResponseValue = null;
-
-    synchronized (rRequestNotifier) {
-      rRequestNotifier.notify();
-    }
-
-    Object respValue = null;
-    synchronized (rResponseNotifier) {
-      while (rResponseValue == null && rScriptRunning) {
-        try {
-          rResponseNotifier.wait(1000);
-        } catch (InterruptedException e) {
-          logger.error(e.getMessage(), e);
-        }
-      }
-      respValue = rResponseValue;
-      rResponseValue = null;
-    }
-
-    if (rResponseError) {
-      throw new RuntimeException(respValue.toString());
-    } else {
-      return respValue;
-    }
-  }
-
-  /**
-   * Wait until src/main/resources/R/zeppelin_sparkr.R is initialized
-   * and call onScriptInitialized()
-   *
-   * @throws InterpreterException
-   */
-  private void waitForRScriptInitialized() throws InterpreterException {
-    synchronized (rScriptInitializeNotifier) {
-      long startTime = System.nanoTime();
-      while (rScriptInitialized == false &&
-          rScriptRunning &&
-          System.nanoTime() - startTime < 10L * 1000 * 1000000) {
-        try {
-          rScriptInitializeNotifier.wait(1000);
-        } catch (InterruptedException e) {
-          logger.error(e.getMessage(), e);
-        }
-      }
-    }
-
-    String errorMessage = "";
-    try {
-      initialOutput.flush();
-      errorMessage = new String(initialOutput.toByteArray());
-    } catch (IOException e) {
-      e.printStackTrace();
-    }
-
-    if (rScriptInitialized == false) {
-      throw new InterpreterException("sparkr is not responding " + errorMessage);
-    }
-  }
-
-  /**
-   * invoked by src/main/resources/R/zeppelin_sparkr.R
-   * @return
-   */
-  public Request getRequest() {
-    synchronized (rRequestNotifier) {
-      while (rRequestObject == null) {
-        try {
-          rRequestNotifier.wait(1000);
-        } catch (InterruptedException e) {
-          logger.error(e.getMessage(), e);
-        }
-      }
-
-      Request req = rRequestObject;
-      rRequestObject = null;
-      return req;
-    }
-  }
-
-  /**
-   * invoked by src/main/resources/R/zeppelin_sparkr.R
-   * @param value
-   * @param error
-   */
-  public void setResponse(Object value, boolean error) {
-    synchronized (rResponseNotifier) {
-      rResponseValue = value;
-      rResponseError = error;
-      rResponseNotifier.notify();
-    }
-  }
-
-  /**
-   * invoked by src/main/resources/R/zeppelin_sparkr.R
-   */
-  public void onScriptInitialized() {
-    synchronized (rScriptInitializeNotifier) {
-      rScriptInitialized = true;
-      rScriptInitializeNotifier.notifyAll();
-    }
-  }
-
-  /**
-   * Create R script in tmp dir
-   */
-  private void createRScript() throws InterpreterException {
-    ClassLoader classLoader = getClass().getClassLoader();
-    File out = new File(scriptPath);
-
-    if (out.exists() && out.isDirectory()) {
-      throw new InterpreterException("Can't create r script " + out.getAbsolutePath());
-    }
-
-    try {
-      FileOutputStream outStream = new FileOutputStream(out);
-      IOUtils.copy(
-          classLoader.getResourceAsStream("R/zeppelin_sparkr.R"),
-          outStream);
-      outStream.close();
-    } catch (IOException e) {
-      throw new InterpreterException(e);
-    }
-
-    logger.info("File {} created", scriptPath);
-  }
-
-  /**
-   * Terminate this R repl
-   */
-  public void close() {
-    executor.getWatchdog().destroyProcess();
-    new File(scriptPath).delete();
-    zeppelinR.remove(hashCode());
-  }
-
-  /**
-   * Get instance
-   * This method will be invoded from zeppelin_sparkr.R
-   * @param hashcode
-   * @return
-   */
-  public static ZeppelinR getZeppelinR(int hashcode) {
-    return zeppelinR.get(hashcode);
-  }
-
-  /**
-   * Pass InterpreterOutput to capture the repl output
-   * @param out
-   */
-  public void setInterpreterOutput(InterpreterOutput out) {
-    outputStream.setInterpreterOutput(out);
-  }
-
-  @Override
-  public void onProcessComplete(int i) {
-    logger.info("process complete {}", i);
-    rScriptRunning = false;
-  }
-
-  @Override
-  public void onProcessFailed(ExecuteException e) {
-    logger.error(e.getMessage(), e);
-    rScriptRunning = false;
-  }
-}

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/d762b528/spark/src/main/java/org/apache/zeppelin/spark/ZeppelinRContext.java
----------------------------------------------------------------------
diff --git a/spark/src/main/java/org/apache/zeppelin/spark/ZeppelinRContext.java b/spark/src/main/java/org/apache/zeppelin/spark/ZeppelinRContext.java
deleted file mode 100644
index 80ea03b..0000000
--- a/spark/src/main/java/org/apache/zeppelin/spark/ZeppelinRContext.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.zeppelin.spark;
-
-import org.apache.spark.SparkContext;
-import org.apache.spark.api.java.JavaSparkContext;
-import org.apache.spark.sql.SQLContext;
-
-/**
- * Contains the Spark and Zeppelin Contexts made available to SparkR.
- */
-public class ZeppelinRContext {
-  private static SparkContext sparkContext;
-  private static SQLContext sqlContext;
-  private static SparkZeppelinContext zeppelinContext;
-  private static Object sparkSession;
-  private static JavaSparkContext javaSparkContext;
-
-  public static void setSparkContext(SparkContext sparkContext) {
-    ZeppelinRContext.sparkContext = sparkContext;
-  }
-
-  public static void setZeppelinContext(SparkZeppelinContext zeppelinContext) {
-    ZeppelinRContext.zeppelinContext = zeppelinContext;
-  }
-
-  public static void setSqlContext(SQLContext sqlContext) {
-    ZeppelinRContext.sqlContext = sqlContext;
-  }
-
-  public static void setSparkSession(Object sparkSession) {
-    ZeppelinRContext.sparkSession = sparkSession;
-  }
-
-  public static SparkContext getSparkContext() {
-    return sparkContext;
-  }
-
-  public static SQLContext getSqlContext() {
-    return sqlContext;
-  }
-
-  public static SparkZeppelinContext getZeppelinContext() {
-    return zeppelinContext;
-  }
-
-  public static Object getSparkSession() {
-    return sparkSession;
-  }
-
-  public static void setJavaSparkContext(JavaSparkContext jsc) { javaSparkContext = jsc; }
-
-  public static JavaSparkContext getJavaSparkContext() { return javaSparkContext; }
-}

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/d762b528/spark/src/main/java/org/apache/zeppelin/spark/dep/SparkDependencyContext.java
----------------------------------------------------------------------
diff --git a/spark/src/main/java/org/apache/zeppelin/spark/dep/SparkDependencyContext.java b/spark/src/main/java/org/apache/zeppelin/spark/dep/SparkDependencyContext.java
deleted file mode 100644
index 0235fc6..0000000
--- a/spark/src/main/java/org/apache/zeppelin/spark/dep/SparkDependencyContext.java
+++ /dev/null
@@ -1,181 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.zeppelin.spark.dep;
-
-import java.io.File;
-import java.net.MalformedURLException;
-import java.util.LinkedList;
-import java.util.List;
-
-import org.apache.zeppelin.dep.Booter;
-import org.apache.zeppelin.dep.Dependency;
-import org.apache.zeppelin.dep.Repository;
-
-import org.sonatype.aether.RepositorySystem;
-import org.sonatype.aether.RepositorySystemSession;
-import org.sonatype.aether.artifact.Artifact;
-import org.sonatype.aether.collection.CollectRequest;
-import org.sonatype.aether.graph.DependencyFilter;
-import org.sonatype.aether.repository.RemoteRepository;
-import org.sonatype.aether.repository.Authentication;
-import org.sonatype.aether.resolution.ArtifactResolutionException;
-import org.sonatype.aether.resolution.ArtifactResult;
-import org.sonatype.aether.resolution.DependencyRequest;
-import org.sonatype.aether.resolution.DependencyResolutionException;
-import org.sonatype.aether.util.artifact.DefaultArtifact;
-import org.sonatype.aether.util.artifact.JavaScopes;
-import org.sonatype.aether.util.filter.DependencyFilterUtils;
-import org.sonatype.aether.util.filter.PatternExclusionsDependencyFilter;
-
-
-/**
- *
- */
-public class SparkDependencyContext {
-  List<Dependency> dependencies = new LinkedList<>();
-  List<Repository> repositories = new LinkedList<>();
-
-  List<File> files = new LinkedList<>();
-  List<File> filesDist = new LinkedList<>();
-  private RepositorySystem system = Booter.newRepositorySystem();
-  private RepositorySystemSession session;
-  private RemoteRepository mavenCentral = Booter.newCentralRepository();
-  private RemoteRepository mavenLocal = Booter.newLocalRepository();
-  private List<RemoteRepository> additionalRepos = new LinkedList<>();
-
-  public SparkDependencyContext(String localRepoPath, String additionalRemoteRepository) {
-    session =  Booter.newRepositorySystemSession(system, localRepoPath);
-    addRepoFromProperty(additionalRemoteRepository);
-  }
-
-  public Dependency load(String lib) {
-    Dependency dep = new Dependency(lib);
-
-    if (dependencies.contains(dep)) {
-      dependencies.remove(dep);
-    }
-    dependencies.add(dep);
-    return dep;
-  }
-
-  public Repository addRepo(String name) {
-    Repository rep = new Repository(name);
-    repositories.add(rep);
-    return rep;
-  }
-
-  public void reset() {
-    dependencies = new LinkedList<>();
-    repositories = new LinkedList<>();
-
-    files = new LinkedList<>();
-    filesDist = new LinkedList<>();
-  }
-
-  private void addRepoFromProperty(String listOfRepo) {
-    if (listOfRepo != null) {
-      String[] repos = listOfRepo.split(";");
-      for (String repo : repos) {
-        String[] parts = repo.split(",");
-        if (parts.length == 3) {
-          String id = parts[0].trim();
-          String url = parts[1].trim();
-          boolean isSnapshot = Boolean.parseBoolean(parts[2].trim());
-          if (id.length() > 1 && url.length() > 1) {
-            RemoteRepository rr = new RemoteRepository(id, "default", url);
-            rr.setPolicy(isSnapshot, null);
-            additionalRepos.add(rr);
-          }
-        }
-      }
-    }
-  }
-
-  /**
-   * fetch all artifacts
-   * @return
-   * @throws MalformedURLException
-   * @throws ArtifactResolutionException
-   * @throws DependencyResolutionException
-   */
-  public List<File> fetch() throws MalformedURLException,
-      DependencyResolutionException, ArtifactResolutionException {
-
-    for (Dependency dep : dependencies) {
-      if (!dep.isLocalFsArtifact()) {
-        List<ArtifactResult> artifacts = fetchArtifactWithDep(dep);
-        for (ArtifactResult artifact : artifacts) {
-          if (dep.isDist()) {
-            filesDist.add(artifact.getArtifact().getFile());
-          }
-          files.add(artifact.getArtifact().getFile());
-        }
-      } else {
-        if (dep.isDist()) {
-          filesDist.add(new File(dep.getGroupArtifactVersion()));
-        }
-        files.add(new File(dep.getGroupArtifactVersion()));
-      }
-    }
-
-    return files;
-  }
-
-  private List<ArtifactResult> fetchArtifactWithDep(Dependency dep)
-      throws DependencyResolutionException, ArtifactResolutionException {
-    Artifact artifact = new DefaultArtifact(
-        SparkDependencyResolver.inferScalaVersion(dep.getGroupArtifactVersion()));
-
-    DependencyFilter classpathFlter = DependencyFilterUtils
-        .classpathFilter(JavaScopes.COMPILE);
-    PatternExclusionsDependencyFilter exclusionFilter = new PatternExclusionsDependencyFilter(
-        SparkDependencyResolver.inferScalaVersion(dep.getExclusions()));
-
-    CollectRequest collectRequest = new CollectRequest();
-    collectRequest.setRoot(new org.sonatype.aether.graph.Dependency(artifact,
-        JavaScopes.COMPILE));
-
-    collectRequest.addRepository(mavenCentral);
-    collectRequest.addRepository(mavenLocal);
-    for (RemoteRepository repo : additionalRepos) {
-      collectRequest.addRepository(repo);
-    }
-    for (Repository repo : repositories) {
-      RemoteRepository rr = new RemoteRepository(repo.getId(), "default", repo.getUrl());
-      rr.setPolicy(repo.isSnapshot(), null);
-      Authentication auth = repo.getAuthentication();
-      if (auth != null) {
-        rr.setAuthentication(auth);
-      }
-      collectRequest.addRepository(rr);
-    }
-
-    DependencyRequest dependencyRequest = new DependencyRequest(collectRequest,
-        DependencyFilterUtils.andFilter(exclusionFilter, classpathFlter));
-
-    return system.resolveDependencies(session, dependencyRequest).getArtifactResults();
-  }
-
-  public List<File> getFiles() {
-    return files;
-  }
-
-  public List<File> getFilesDist() {
-    return filesDist;
-  }
-}

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/d762b528/spark/src/main/java/org/apache/zeppelin/spark/dep/SparkDependencyResolver.java
----------------------------------------------------------------------
diff --git a/spark/src/main/java/org/apache/zeppelin/spark/dep/SparkDependencyResolver.java b/spark/src/main/java/org/apache/zeppelin/spark/dep/SparkDependencyResolver.java
deleted file mode 100644
index 46224a8..0000000
--- a/spark/src/main/java/org/apache/zeppelin/spark/dep/SparkDependencyResolver.java
+++ /dev/null
@@ -1,351 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.zeppelin.spark.dep;
-
-import java.io.File;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.net.URL;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.List;
-
-import org.apache.commons.lang.StringUtils;
-import org.apache.spark.SparkContext;
-import org.apache.zeppelin.dep.AbstractDependencyResolver;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.sonatype.aether.artifact.Artifact;
-import org.sonatype.aether.collection.CollectRequest;
-import org.sonatype.aether.graph.Dependency;
-import org.sonatype.aether.graph.DependencyFilter;
-import org.sonatype.aether.repository.RemoteRepository;
-import org.sonatype.aether.resolution.ArtifactResult;
-import org.sonatype.aether.resolution.DependencyRequest;
-import org.sonatype.aether.util.artifact.DefaultArtifact;
-import org.sonatype.aether.util.artifact.JavaScopes;
-import org.sonatype.aether.util.filter.DependencyFilterUtils;
-import org.sonatype.aether.util.filter.PatternExclusionsDependencyFilter;
-
-import scala.Some;
-import scala.collection.IndexedSeq;
-import scala.reflect.io.AbstractFile;
-import scala.tools.nsc.Global;
-import scala.tools.nsc.backend.JavaPlatform;
-import scala.tools.nsc.util.ClassPath;
-import scala.tools.nsc.util.MergedClassPath;
-
-/**
- * Deps resolver.
- * Add new dependencies from mvn repo (at runtime) to Spark interpreter group.
- */
-public class SparkDependencyResolver extends AbstractDependencyResolver {
-  Logger logger = LoggerFactory.getLogger(SparkDependencyResolver.class);
-  private Global global;
-  private ClassLoader runtimeClassLoader;
-  private SparkContext sc;
-
-  private final String[] exclusions = new String[] {"org.scala-lang:scala-library",
-                                                    "org.scala-lang:scala-compiler",
-                                                    "org.scala-lang:scala-reflect",
-                                                    "org.scala-lang:scalap",
-                                                    "org.apache.zeppelin:zeppelin-zengine",
-                                                    "org.apache.zeppelin:zeppelin-spark",
-                                                    "org.apache.zeppelin:zeppelin-server"};
-
-  public SparkDependencyResolver(Global global,
-                                 ClassLoader runtimeClassLoader,
-                                 SparkContext sc,
-                                 String localRepoPath,
-                                 String additionalRemoteRepository) {
-    super(localRepoPath);
-    this.global = global;
-    this.runtimeClassLoader = runtimeClassLoader;
-    this.sc = sc;
-    addRepoFromProperty(additionalRemoteRepository);
-  }
-
-  private void addRepoFromProperty(String listOfRepo) {
-    if (listOfRepo != null) {
-      String[] repos = listOfRepo.split(";");
-      for (String repo : repos) {
-        String[] parts = repo.split(",");
-        if (parts.length == 3) {
-          String id = parts[0].trim();
-          String url = parts[1].trim();
-          boolean isSnapshot = Boolean.parseBoolean(parts[2].trim());
-          if (id.length() > 1 && url.length() > 1) {
-            addRepo(id, url, isSnapshot);
-          }
-        }
-      }
-    }
-  }
-
-  private void updateCompilerClassPath(URL[] urls) throws IllegalAccessException,
-      IllegalArgumentException, InvocationTargetException {
-
-    JavaPlatform platform = (JavaPlatform) global.platform();
-    MergedClassPath<AbstractFile> newClassPath = mergeUrlsIntoClassPath(platform, urls);
-
-    Method[] methods = platform.getClass().getMethods();
-    for (Method m : methods) {
-      if (m.getName().endsWith("currentClassPath_$eq")) {
-        m.invoke(platform, new Some(newClassPath));
-        break;
-      }
-    }
-
-    // NOTE: Must use reflection until this is exposed/fixed upstream in Scala
-    List<String> classPaths = new LinkedList<>();
-    for (URL url : urls) {
-      classPaths.add(url.getPath());
-    }
-
-    // Reload all jars specified into our compiler
-    global.invalidateClassPathEntries(scala.collection.JavaConversions.asScalaBuffer(classPaths)
-        .toList());
-  }
-
-  // Until spark 1.1.x
-  // check https://github.com/apache/spark/commit/191d7cf2a655d032f160b9fa181730364681d0e7
-  private void updateRuntimeClassPath_1_x(URL[] urls) throws SecurityException,
-      IllegalAccessException, IllegalArgumentException,
-      InvocationTargetException, NoSuchMethodException {
-    Method addURL;
-    addURL = runtimeClassLoader.getClass().getDeclaredMethod("addURL", new Class[] {URL.class});
-    addURL.setAccessible(true);
-    for (URL url : urls) {
-      addURL.invoke(runtimeClassLoader, url);
-    }
-  }
-
-  private void updateRuntimeClassPath_2_x(URL[] urls) throws SecurityException,
-      IllegalAccessException, IllegalArgumentException,
-      InvocationTargetException, NoSuchMethodException {
-    Method addURL;
-    addURL = runtimeClassLoader.getClass().getDeclaredMethod("addNewUrl", new Class[] {URL.class});
-    addURL.setAccessible(true);
-    for (URL url : urls) {
-      addURL.invoke(runtimeClassLoader, url);
-    }
-  }
-
-  private MergedClassPath<AbstractFile> mergeUrlsIntoClassPath(JavaPlatform platform, URL[] urls) {
-    IndexedSeq<ClassPath<AbstractFile>> entries =
-        ((MergedClassPath<AbstractFile>) platform.classPath()).entries();
-    List<ClassPath<AbstractFile>> cp = new LinkedList<>();
-
-    for (int i = 0; i < entries.size(); i++) {
-      cp.add(entries.apply(i));
-    }
-
-    for (URL url : urls) {
-      AbstractFile file;
-      if ("file".equals(url.getProtocol())) {
-        File f = new File(url.getPath());
-        if (f.isDirectory()) {
-          file = AbstractFile.getDirectory(scala.reflect.io.File.jfile2path(f));
-        } else {
-          file = AbstractFile.getFile(scala.reflect.io.File.jfile2path(f));
-        }
-      } else {
-        file = AbstractFile.getURL(url);
-      }
-
-      ClassPath<AbstractFile> newcp = platform.classPath().context().newClassPath(file);
-
-      // distinct
-      if (cp.contains(newcp) == false) {
-        cp.add(newcp);
-      }
-    }
-
-    return new MergedClassPath(scala.collection.JavaConversions.asScalaBuffer(cp).toIndexedSeq(),
-        platform.classPath().context());
-  }
-
-  public List<String> load(String artifact,
-      boolean addSparkContext) throws Exception {
-    return load(artifact, new LinkedList<String>(), addSparkContext);
-  }
-
-  public List<String> load(String artifact, Collection<String> excludes,
-      boolean addSparkContext) throws Exception {
-    if (StringUtils.isBlank(artifact)) {
-      // Should throw here
-      throw new RuntimeException("Invalid artifact to load");
-    }
-
-    // <groupId>:<artifactId>[:<extension>[:<classifier>]]:<version>
-    int numSplits = artifact.split(":").length;
-    if (numSplits >= 3 && numSplits <= 6) {
-      return loadFromMvn(artifact, excludes, addSparkContext);
-    } else {
-      loadFromFs(artifact, addSparkContext);
-      LinkedList<String> libs = new LinkedList<>();
-      libs.add(artifact);
-      return libs;
-    }
-  }
-
-  private void loadFromFs(String artifact, boolean addSparkContext) throws Exception {
-    File jarFile = new File(artifact);
-
-    global.new Run();
-
-    if (sc.version().startsWith("1.1")) {
-      updateRuntimeClassPath_1_x(new URL[] {jarFile.toURI().toURL()});
-    } else {
-      updateRuntimeClassPath_2_x(new URL[] {jarFile.toURI().toURL()});
-    }
-
-    if (addSparkContext) {
-      sc.addJar(jarFile.getAbsolutePath());
-    }
-  }
-
-  private List<String> loadFromMvn(String artifact, Collection<String> excludes,
-      boolean addSparkContext) throws Exception {
-    List<String> loadedLibs = new LinkedList<>();
-    Collection<String> allExclusions = new LinkedList<>();
-    allExclusions.addAll(excludes);
-    allExclusions.addAll(Arrays.asList(exclusions));
-
-    List<ArtifactResult> listOfArtifact;
-    listOfArtifact = getArtifactsWithDep(artifact, allExclusions);
-
-    Iterator<ArtifactResult> it = listOfArtifact.iterator();
-    while (it.hasNext()) {
-      Artifact a = it.next().getArtifact();
-      String gav = a.getGroupId() + ":" + a.getArtifactId() + ":" + a.getVersion();
-      for (String exclude : allExclusions) {
-        if (gav.startsWith(exclude)) {
-          it.remove();
-          break;
-        }
-      }
-    }
-
-    List<URL> newClassPathList = new LinkedList<>();
-    List<File> files = new LinkedList<>();
-    for (ArtifactResult artifactResult : listOfArtifact) {
-      logger.info("Load " + artifactResult.getArtifact().getGroupId() + ":"
-          + artifactResult.getArtifact().getArtifactId() + ":"
-          + artifactResult.getArtifact().getVersion());
-      newClassPathList.add(artifactResult.getArtifact().getFile().toURI().toURL());
-      files.add(artifactResult.getArtifact().getFile());
-      loadedLibs.add(artifactResult.getArtifact().getGroupId() + ":"
-          + artifactResult.getArtifact().getArtifactId() + ":"
-          + artifactResult.getArtifact().getVersion());
-    }
-
-    global.new Run();
-    if (sc.version().startsWith("1.1")) {
-      updateRuntimeClassPath_1_x(newClassPathList.toArray(new URL[0]));
-    } else {
-      updateRuntimeClassPath_2_x(newClassPathList.toArray(new URL[0]));
-    }
-    updateCompilerClassPath(newClassPathList.toArray(new URL[0]));
-
-    if (addSparkContext) {
-      for (File f : files) {
-        sc.addJar(f.getAbsolutePath());
-      }
-    }
-
-    return loadedLibs;
-  }
-
-  /**
-   * @param dependency
-   * @param excludes list of pattern can either be of the form groupId:artifactId
-   * @return
-   * @throws Exception
-   */
-  @Override
-  public List<ArtifactResult> getArtifactsWithDep(String dependency,
-      Collection<String> excludes) throws Exception {
-    Artifact artifact = new DefaultArtifact(inferScalaVersion(dependency));
-    DependencyFilter classpathFilter = DependencyFilterUtils.classpathFilter(JavaScopes.COMPILE);
-    PatternExclusionsDependencyFilter exclusionFilter =
-        new PatternExclusionsDependencyFilter(inferScalaVersion(excludes));
-
-    CollectRequest collectRequest = new CollectRequest();
-    collectRequest.setRoot(new Dependency(artifact, JavaScopes.COMPILE));
-
-    synchronized (repos) {
-      for (RemoteRepository repo : repos) {
-        collectRequest.addRepository(repo);
-      }
-    }
-    DependencyRequest dependencyRequest = new DependencyRequest(collectRequest,
-        DependencyFilterUtils.andFilter(exclusionFilter, classpathFilter));
-    return system.resolveDependencies(session, dependencyRequest).getArtifactResults();
-  }
-
-  public static Collection<String> inferScalaVersion(Collection<String> artifact) {
-    List<String> list = new LinkedList<>();
-    for (String a : artifact) {
-      list.add(inferScalaVersion(a));
-    }
-    return list;
-  }
-
-  public static String inferScalaVersion(String artifact) {
-    int pos = artifact.indexOf(":");
-    if (pos < 0 || pos + 2 >= artifact.length()) {
-      // failed to infer
-      return artifact;
-    }
-
-    if (':' == artifact.charAt(pos + 1)) {
-      String restOfthem = "";
-      String versionSep = ":";
-
-      String groupId = artifact.substring(0, pos);
-      int nextPos = artifact.indexOf(":", pos + 2);
-      if (nextPos < 0) {
-        if (artifact.charAt(artifact.length() - 1) == '*') {
-          nextPos = artifact.length() - 1;
-          versionSep = "";
-          restOfthem = "*";
-        } else {
-          versionSep = "";
-          nextPos = artifact.length();
-        }
-      }
-
-      String artifactId = artifact.substring(pos + 2, nextPos);
-      if (nextPos < artifact.length()) {
-        if (!restOfthem.equals("*")) {
-          restOfthem = artifact.substring(nextPos + 1);
-        }
-      }
-
-      String [] version = scala.util.Properties.versionNumberString().split("[.]");
-      String scalaVersion = version[0] + "." + version[1];
-
-      return groupId + ":" + artifactId + "_" + scalaVersion + versionSep + restOfthem;
-    } else {
-      return artifact;
-    }
-  }
-}

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/d762b528/spark/src/main/resources/R/zeppelin_sparkr.R
----------------------------------------------------------------------
diff --git a/spark/src/main/resources/R/zeppelin_sparkr.R b/spark/src/main/resources/R/zeppelin_sparkr.R
deleted file mode 100644
index 525c6c5..0000000
--- a/spark/src/main/resources/R/zeppelin_sparkr.R
+++ /dev/null
@@ -1,105 +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.
-#
-
-args <- commandArgs(trailingOnly = TRUE)
-
-hashCode <- as.integer(args[1])
-port <- as.integer(args[2])
-libPath <- args[3]
-version <- as.integer(args[4])
-rm(args)
-
-print(paste("Port ", toString(port)))
-print(paste("LibPath ", libPath))
-
-.libPaths(c(file.path(libPath), .libPaths()))
-library(SparkR)
-
-
-SparkR:::connectBackend("localhost", port, 6000)
-
-# scStartTime is needed by R/pkg/R/sparkR.R
-assign(".scStartTime", as.integer(Sys.time()), envir = SparkR:::.sparkREnv)
-
-# getZeppelinR
-.zeppelinR = SparkR:::callJStatic("org.apache.zeppelin.spark.ZeppelinR", "getZeppelinR", hashCode)
-
-# setup spark env
-assign(".sc", SparkR:::callJStatic("org.apache.zeppelin.spark.ZeppelinRContext", "getSparkContext"), envir = SparkR:::.sparkREnv)
-assign("sc", get(".sc", envir = SparkR:::.sparkREnv), envir=.GlobalEnv)
-if (version >= 20000) {
-  assign(".sparkRsession", SparkR:::callJStatic("org.apache.zeppelin.spark.ZeppelinRContext", "getSparkSession"), envir = SparkR:::.sparkREnv)
-  assign("spark", get(".sparkRsession", envir = SparkR:::.sparkREnv), envir = .GlobalEnv)
-  assign(".sparkRjsc", SparkR:::callJStatic("org.apache.zeppelin.spark.ZeppelinRContext", "getJavaSparkContext"), envir = SparkR:::.sparkREnv)
-}
-assign(".sqlc", SparkR:::callJStatic("org.apache.zeppelin.spark.ZeppelinRContext", "getSqlContext"), envir = SparkR:::.sparkREnv)
-assign("sqlContext", get(".sqlc", envir = SparkR:::.sparkREnv), envir = .GlobalEnv)
-assign(".zeppelinContext", SparkR:::callJStatic("org.apache.zeppelin.spark.ZeppelinRContext", "getZeppelinContext"), envir = .GlobalEnv)
-
-z.put <- function(name, object) {
-  SparkR:::callJMethod(.zeppelinContext, "put", name, object)
-}
-z.get <- function(name) {
-  SparkR:::callJMethod(.zeppelinContext, "get", name)
-}
-z.input <- function(name, value) {
-  SparkR:::callJMethod(.zeppelinContext, "input", name, value)
-}
-
-# notify script is initialized
-SparkR:::callJMethod(.zeppelinR, "onScriptInitialized")
-
-while (TRUE) {
-  req <- SparkR:::callJMethod(.zeppelinR, "getRequest")
-  type <-  SparkR:::callJMethod(req, "getType")
-  stmt <- SparkR:::callJMethod(req, "getStmt")
-  value <- SparkR:::callJMethod(req, "getValue")
-  
-  if (type == "eval") {
-    tryCatch({
-      ret <- eval(parse(text=stmt))
-      SparkR:::callJMethod(.zeppelinR, "setResponse", "", FALSE)
-    }, error = function(e) {
-      SparkR:::callJMethod(.zeppelinR, "setResponse", toString(e), TRUE)
-    })    
-  } else if (type == "set") {
-    tryCatch({
-      ret <- assign(stmt, value)
-      SparkR:::callJMethod(.zeppelinR, "setResponse", "", FALSE)
-    }, error = function(e) {
-      SparkR:::callJMethod(.zeppelinR, "setResponse", toString(e), TRUE)
-    })
-  } else if (type == "get") {
-    tryCatch({      
-      ret <- eval(parse(text=stmt))
-      SparkR:::callJMethod(.zeppelinR, "setResponse", ret, FALSE)
-    }, error = function(e) {
-      SparkR:::callJMethod(.zeppelinR, "setResponse", toString(e), TRUE)
-    })
-  } else if (type == "getS") {
-    tryCatch({
-      ret <- eval(parse(text=stmt))
-      SparkR:::callJMethod(.zeppelinR, "setResponse", toString(ret), FALSE)
-    }, error = function(e) {
-      SparkR:::callJMethod(.zeppelinR, "setResponse", toString(e), TRUE)
-    })
-  } else {
-    # unsupported type
-    SparkR:::callJMethod(.zeppelinR, "setResponse", paste("Unsupported type ", type), TRUE)
-  }
-}

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/d762b528/spark/src/main/resources/interpreter-setting.json
----------------------------------------------------------------------
diff --git a/spark/src/main/resources/interpreter-setting.json b/spark/src/main/resources/interpreter-setting.json
deleted file mode 100644
index f45c85c..0000000
--- a/spark/src/main/resources/interpreter-setting.json
+++ /dev/null
@@ -1,226 +0,0 @@
-[
-  {
-    "group": "spark",
-    "name": "spark",
-    "className": "org.apache.zeppelin.spark.SparkInterpreter",
-    "defaultInterpreter": true,
-    "properties": {
-      "spark.executor.memory": {
-        "envName": null,
-        "propertyName": "spark.executor.memory",
-        "defaultValue": "",
-        "description": "Executor memory per worker instance. ex) 512m, 32g",
-        "type": "string"
-      },
-      "args": {
-        "envName": null,
-        "propertyName": null,
-        "defaultValue": "",
-        "description": "spark commandline args",
-        "type": "textarea"
-      },
-      "zeppelin.spark.useHiveContext": {
-        "envName": "ZEPPELIN_SPARK_USEHIVECONTEXT",
-        "propertyName": "zeppelin.spark.useHiveContext",
-        "defaultValue": true,
-        "description": "Use HiveContext instead of SQLContext if it is true.",
-        "type": "checkbox"
-      },
-      "spark.app.name": {
-        "envName": "SPARK_APP_NAME",
-        "propertyName": "spark.app.name",
-        "defaultValue": "Zeppelin",
-        "description": "The name of spark application.",
-        "type": "string"
-      },
-      "zeppelin.spark.printREPLOutput": {
-        "envName": null,
-        "propertyName": "zeppelin.spark.printREPLOutput",
-        "defaultValue": true,
-        "description": "Print REPL output",
-        "type": "checkbox"
-      },
-      "spark.cores.max": {
-        "envName": null,
-        "propertyName": "spark.cores.max",
-        "defaultValue": "",
-        "description": "Total number of cores to use. Empty value uses all available core.",
-        "type": "number"
-      },
-      "zeppelin.spark.maxResult": {
-        "envName": "ZEPPELIN_SPARK_MAXRESULT",
-        "propertyName": "zeppelin.spark.maxResult",
-        "defaultValue": "1000",
-        "description": "Max number of Spark SQL result to display.",
-        "type": "number"
-      },
-      "master": {
-        "envName": "MASTER",
-        "propertyName": "spark.master",
-        "defaultValue": "local[*]",
-        "description": "Spark master uri. ex) spark://masterhost:7077",
-        "type": "string"
-      },
-      "zeppelin.spark.enableSupportedVersionCheck": {
-        "envName": null,
-        "propertyName": "zeppelin.spark.enableSupportedVersionCheck",
-        "defaultValue": true,
-        "description": "Do not change - developer only setting, not for production use",
-        "type": "checkbox"
-      },
-      "zeppelin.spark.uiWebUrl": {
-        "envName": null,
-        "propertyName": "zeppelin.spark.uiWebUrl",
-        "defaultValue": "",
-        "description": "Override Spark UI default URL",
-        "type": "string"
-      }
-    },
-    "editor": {
-      "language": "scala",
-      "editOnDblClick": false,
-      "completionKey": "TAB"
-    }
-  },
-  {
-    "group": "spark",
-    "name": "sql",
-    "className": "org.apache.zeppelin.spark.SparkSqlInterpreter",
-    "properties": {
-      "zeppelin.spark.concurrentSQL": {
-        "envName": "ZEPPELIN_SPARK_CONCURRENTSQL",
-        "propertyName": "zeppelin.spark.concurrentSQL",
-        "defaultValue": false,
-        "description": "Execute multiple SQL concurrently if set true.",
-        "type": "checkbox"
-      },
-      "zeppelin.spark.sql.stacktrace": {
-        "envName": "ZEPPELIN_SPARK_SQL_STACKTRACE",
-        "propertyName": "zeppelin.spark.sql.stacktrace",
-        "defaultValue": false,
-        "description": "Show full exception stacktrace for SQL queries if set to true.",
-        "type": "checkbox"
-      },
-      "zeppelin.spark.maxResult": {
-        "envName": "ZEPPELIN_SPARK_MAXRESULT",
-        "propertyName": "zeppelin.spark.maxResult",
-        "defaultValue": "1000",
-        "description": "Max number of Spark SQL result to display.",
-        "type": "number"
-      },
-      "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.",
-        "type": "checkbox"
-      }
-    },
-    "editor": {
-      "language": "sql",
-      "editOnDblClick": false,
-      "completionKey": "TAB"
-    }
-  },
-  {
-    "group": "spark",
-    "name": "dep",
-    "className": "org.apache.zeppelin.spark.DepInterpreter",
-    "properties": {
-      "zeppelin.dep.localrepo": {
-        "envName": "ZEPPELIN_DEP_LOCALREPO",
-        "propertyName": null,
-        "defaultValue": "local-repo",
-        "description": "local repository for dependency loader",
-        "type": "string"
-      },
-      "zeppelin.dep.additionalRemoteRepository": {
-        "envName": null,
-        "propertyName": null,
-        "defaultValue": "spark-packages,http://dl.bintray.com/spark-packages/maven,false;",
-        "description": "A list of 'id,remote-repository-URL,is-snapshot;' for each remote repository.",
-        "type": "textarea"
-      }
-    },
-    "editor": {
-      "language": "scala",
-      "editOnDblClick": false,
-      "completionKey": "TAB"
-    }
-  },
-  {
-    "group": "spark",
-    "name": "pyspark",
-    "className": "org.apache.zeppelin.spark.PySparkInterpreter",
-    "properties": {
-      "zeppelin.pyspark.python": {
-        "envName": "PYSPARK_PYTHON",
-        "propertyName": null,
-        "defaultValue": "python",
-        "description": "Python command to run pyspark with",
-        "type": "string"
-      },
-      "zeppelin.pyspark.useIPython": {
-        "envName": null,
-        "propertyName": "zeppelin.pyspark.useIPython",
-        "defaultValue": true,
-        "description": "whether use IPython when it is available",
-        "type": "checkbox"
-      }
-    },
-    "editor": {
-      "language": "python",
-      "editOnDblClick": false,
-      "completionKey": "TAB"
-    }
-  },
-  {
-    "group": "spark",
-    "name": "ipyspark",
-    "className": "org.apache.zeppelin.spark.IPySparkInterpreter",
-    "properties": {},
-    "editor": {
-      "language": "python",
-      "editOnDblClick": false
-    }
-  },
-  {
-    "group": "spark",
-    "name": "r",
-    "className": "org.apache.zeppelin.spark.SparkRInterpreter",
-    "properties": {
-      "zeppelin.R.knitr": {
-        "envName": "ZEPPELIN_R_KNITR",
-        "propertyName": "zeppelin.R.knitr",
-        "defaultValue": true,
-        "description": "whether use knitr or not",
-        "type": "checkbox"
-      },
-      "zeppelin.R.cmd": {
-        "envName": "ZEPPELIN_R_CMD",
-        "propertyName": "zeppelin.R.cmd",
-        "defaultValue": "R",
-        "description": "R repl path",
-        "type": "string"
-      },
-      "zeppelin.R.image.width": {
-        "envName": "ZEPPELIN_R_IMAGE_WIDTH",
-        "propertyName": "zeppelin.R.image.width",
-        "defaultValue": "100%",
-        "description": "",
-        "type": "number"
-      },
-      "zeppelin.R.render.options": {
-        "envName": "ZEPPELIN_R_RENDER_OPTIONS",
-        "propertyName": "zeppelin.R.render.options",
-        "defaultValue": "out.format = 'html', comment = NA, echo = FALSE, results = 'asis', message = F, warning = F, fig.retina = 2",
-        "description": "",
-        "type": "textarea"
-      }
-    },
-    "editor": {
-      "language": "r",
-      "editOnDblClick": false
-    }
-  }
-]

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/d762b528/spark/src/main/resources/python/zeppelin_ipyspark.py
----------------------------------------------------------------------
diff --git a/spark/src/main/resources/python/zeppelin_ipyspark.py b/spark/src/main/resources/python/zeppelin_ipyspark.py
deleted file mode 100644
index 324f481..0000000
--- a/spark/src/main/resources/python/zeppelin_ipyspark.py
+++ /dev/null
@@ -1,53 +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.
-#
-
-
-from py4j.java_gateway import java_import, JavaGateway, GatewayClient
-from pyspark.conf import SparkConf
-from pyspark.context import SparkContext
-
-# for back compatibility
-from pyspark.sql import SQLContext
-
-# start JVM gateway
-client = GatewayClient(port=${JVM_GATEWAY_PORT})
-gateway = JavaGateway(client, auto_convert=True)
-
-java_import(gateway.jvm, "org.apache.spark.SparkEnv")
-java_import(gateway.jvm, "org.apache.spark.SparkConf")
-java_import(gateway.jvm, "org.apache.spark.api.java.*")
-java_import(gateway.jvm, "org.apache.spark.api.python.*")
-java_import(gateway.jvm, "org.apache.spark.mllib.api.python.*")
-
-intp = gateway.entry_point
-jsc = intp.getJavaSparkContext()
-
-java_import(gateway.jvm, "org.apache.spark.sql.*")
-java_import(gateway.jvm, "org.apache.spark.sql.hive.*")
-java_import(gateway.jvm, "scala.Tuple2")
-
-jconf = jsc.getConf()
-conf = SparkConf(_jvm=gateway.jvm, _jconf=jconf)
-sc = _zsc_ = SparkContext(jsc=jsc, gateway=gateway, conf=conf)
-
-if intp.isSpark2():
-    from pyspark.sql import SparkSession
-
-    spark = __zSpark__ = SparkSession(sc, intp.getSparkSession())
-    sqlContext = sqlc = __zSqlc__ = __zSpark__._wrapped
-else:
-    sqlContext = sqlc = __zSqlc__ = SQLContext(sparkContext=sc, sqlContext=intp.getSQLContext())

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/d762b528/spark/src/main/resources/python/zeppelin_pyspark.py
----------------------------------------------------------------------
diff --git a/spark/src/main/resources/python/zeppelin_pyspark.py b/spark/src/main/resources/python/zeppelin_pyspark.py
deleted file mode 100644
index c10855a..0000000
--- a/spark/src/main/resources/python/zeppelin_pyspark.py
+++ /dev/null
@@ -1,393 +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.
-#
-
-import os, sys, getopt, traceback, json, re
-
-from py4j.java_gateway import java_import, JavaGateway, GatewayClient
-from py4j.protocol import Py4JJavaError
-from pyspark.conf import SparkConf
-from pyspark.context import SparkContext
-import ast
-import warnings
-
-# for back compatibility
-from pyspark.sql import SQLContext, HiveContext, Row
-
-class Logger(object):
-  def __init__(self):
-    pass
-
-  def write(self, message):
-    intp.appendOutput(message)
-
-  def reset(self):
-    pass
-
-  def flush(self):
-    pass
-
-
-class PyZeppelinContext(dict):
-  def __init__(self, zc):
-    self.z = zc
-    self._displayhook = lambda *args: None
-
-  def show(self, obj):
-    from pyspark.sql import DataFrame
-    if isinstance(obj, DataFrame):
-      print(self.z.showData(obj._jdf))
-    else:
-      print(str(obj))
-
-  # By implementing special methods it makes operating on it more Pythonic
-  def __setitem__(self, key, item):
-    self.z.put(key, item)
-
-  def __getitem__(self, key):
-    return self.z.get(key)
-
-  def __delitem__(self, key):
-    self.z.remove(key)
-
-  def __contains__(self, item):
-    return self.z.containsKey(item)
-
-  def add(self, key, value):
-    self.__setitem__(key, value)
-
-  def put(self, key, value):
-    self.__setitem__(key, value)
-
-  def get(self, key):
-    return self.__getitem__(key)
-
-  def getInterpreterContext(self):
-    return self.z.getInterpreterContext()
-
-  def input(self, name, defaultValue=""):
-    return self.z.input(name, defaultValue)
-
-  def textbox(self, name, defaultValue=""):
-    return self.z.textbox(name, defaultValue)
-
-  def noteTextbox(self, name, defaultValue=""):
-    return self.z.noteTextbox(name, defaultValue)
-
-  def select(self, name, options, defaultValue=""):
-    # auto_convert to ArrayList doesn't match the method signature on JVM side
-    return self.z.select(name, defaultValue, self.getParamOptions(options))
-
-  def noteSelect(self, name, options, defaultValue=""):
-    return self.z.noteSelect(name, defaultValue, self.getParamOptions(options))
-
-  def checkbox(self, name, options, defaultChecked=None):
-    optionsIterable = self.getParamOptions(options)
-    defaultCheckedIterables = self.getDefaultChecked(defaultChecked)
-    checkedItems = gateway.jvm.scala.collection.JavaConversions.seqAsJavaList(self.z.checkbox(name, defaultCheckedIterables, optionsIterable))
-    result = []
-    for checkedItem in checkedItems:
-      result.append(checkedItem)
-    return result;
-
-  def noteCheckbox(self, name, options, defaultChecked=None):
-    optionsIterable = self.getParamOptions(options)
-    defaultCheckedIterables = self.getDefaultChecked(defaultChecked)
-    checkedItems = gateway.jvm.scala.collection.JavaConversions.seqAsJavaList(self.z.noteCheckbox(name, defaultCheckedIterables, optionsIterable))
-    result = []
-    for checkedItem in checkedItems:
-      result.append(checkedItem)
-    return result;
-
-  def getParamOptions(self, options):
-    tuples = list(map(lambda items: self.__tupleToScalaTuple2(items), options))
-    return gateway.jvm.scala.collection.JavaConversions.collectionAsScalaIterable(tuples)
-
-  def getDefaultChecked(self, defaultChecked):
-    if defaultChecked is None:
-      defaultChecked = []
-    return gateway.jvm.scala.collection.JavaConversions.collectionAsScalaIterable(defaultChecked)
-
-  def registerHook(self, event, cmd, replName=None):
-    if replName is None:
-      self.z.registerHook(event, cmd)
-    else:
-      self.z.registerHook(event, cmd, replName)
-
-  def unregisterHook(self, event, replName=None):
-    if replName is None:
-      self.z.unregisterHook(event)
-    else:
-      self.z.unregisterHook(event, replName)
-
-  def getHook(self, event, replName=None):
-    if replName is None:
-      return self.z.getHook(event)
-    return self.z.getHook(event, replName)
-
-  def _setup_matplotlib(self):
-    # If we don't have matplotlib installed don't bother continuing
-    try:
-      import matplotlib
-    except ImportError:
-      return
-    
-    # Make sure custom backends are available in the PYTHONPATH
-    rootdir = os.environ.get('ZEPPELIN_HOME', os.getcwd())
-    mpl_path = os.path.join(rootdir, 'interpreter', 'lib', 'python')
-    if mpl_path not in sys.path:
-      sys.path.append(mpl_path)
-    
-    # Finally check if backend exists, and if so configure as appropriate
-    try:
-      matplotlib.use('module://backend_zinline')
-      import backend_zinline
-      
-      # Everything looks good so make config assuming that we are using
-      # an inline backend
-      self._displayhook = backend_zinline.displayhook
-      self.configure_mpl(width=600, height=400, dpi=72, fontsize=10,
-                         interactive=True, format='png', context=self.z)
-    except ImportError:
-      # Fall back to Agg if no custom backend installed
-      matplotlib.use('Agg')
-      warnings.warn("Unable to load inline matplotlib backend, "
-                    "falling back to Agg")
-
-  def configure_mpl(self, **kwargs):
-    import mpl_config
-    mpl_config.configure(**kwargs)
-
-  def __tupleToScalaTuple2(self, tuple):
-    if (len(tuple) == 2):
-      return gateway.jvm.scala.Tuple2(tuple[0], tuple[1])
-    else:
-      raise IndexError("options must be a list of tuple of 2")
-
-
-class SparkVersion(object):
-  SPARK_1_4_0 = 10400
-  SPARK_1_3_0 = 10300
-  SPARK_2_0_0 = 20000
-
-  def __init__(self, versionNumber):
-    self.version = versionNumber
-
-  def isAutoConvertEnabled(self):
-    return self.version >= self.SPARK_1_4_0
-
-  def isImportAllPackageUnderSparkSql(self):
-    return self.version >= self.SPARK_1_3_0
-
-  def isSpark2(self):
-    return self.version >= self.SPARK_2_0_0
-
-class PySparkCompletion:
-  def __init__(self, interpreterObject):
-    self.interpreterObject = interpreterObject
-
-  def getGlobalCompletion(self):
-    objectDefList = []
-    try:
-      for completionItem in list(globals().keys()):
-        objectDefList.append(completionItem)
-    except:
-      return None
-    else:
-      return objectDefList
-
-  def getMethodCompletion(self, text_value):
-    execResult = locals()
-    if text_value == None:
-      return None
-    completion_target = text_value
-    try:
-      if len(completion_target) <= 0:
-        return None
-      if text_value[-1] == ".":
-        completion_target = text_value[:-1]
-      exec("{} = dir({})".format("objectDefList", completion_target), globals(), execResult)
-    except:
-      return None
-    else:
-      return list(execResult['objectDefList'])
-
-
-  def getCompletion(self, text_value):
-    completionList = set()
-
-    globalCompletionList = self.getGlobalCompletion()
-    if globalCompletionList != None:
-      for completionItem in list(globalCompletionList):
-        completionList.add(completionItem)
-
-    if text_value != None:
-      objectCompletionList = self.getMethodCompletion(text_value)
-      if objectCompletionList != None:
-        for completionItem in list(objectCompletionList):
-          completionList.add(completionItem)
-    if len(completionList) <= 0:
-      self.interpreterObject.setStatementsFinished("", False)
-    else:
-      result = json.dumps(list(filter(lambda x : not re.match("^__.*", x), list(completionList))))
-      self.interpreterObject.setStatementsFinished(result, False)
-
-client = GatewayClient(port=int(sys.argv[1]))
-sparkVersion = SparkVersion(int(sys.argv[2]))
-if sparkVersion.isSpark2():
-  from pyspark.sql import SparkSession
-else:
-  from pyspark.sql import SchemaRDD
-
-if sparkVersion.isAutoConvertEnabled():
-  gateway = JavaGateway(client, auto_convert = True)
-else:
-  gateway = JavaGateway(client)
-
-java_import(gateway.jvm, "org.apache.spark.SparkEnv")
-java_import(gateway.jvm, "org.apache.spark.SparkConf")
-java_import(gateway.jvm, "org.apache.spark.api.java.*")
-java_import(gateway.jvm, "org.apache.spark.api.python.*")
-java_import(gateway.jvm, "org.apache.spark.mllib.api.python.*")
-
-intp = gateway.entry_point
-output = Logger()
-sys.stdout = output
-sys.stderr = output
-intp.onPythonScriptInitialized(os.getpid())
-
-jsc = intp.getJavaSparkContext()
-
-if sparkVersion.isImportAllPackageUnderSparkSql():
-  java_import(gateway.jvm, "org.apache.spark.sql.*")
-  java_import(gateway.jvm, "org.apache.spark.sql.hive.*")
-else:
-  java_import(gateway.jvm, "org.apache.spark.sql.SQLContext")
-  java_import(gateway.jvm, "org.apache.spark.sql.hive.HiveContext")
-  java_import(gateway.jvm, "org.apache.spark.sql.hive.LocalHiveContext")
-  java_import(gateway.jvm, "org.apache.spark.sql.hive.TestHiveContext")
-
-
-java_import(gateway.jvm, "scala.Tuple2")
-
-_zcUserQueryNameSpace = {}
-
-jconf = intp.getSparkConf()
-conf = SparkConf(_jvm = gateway.jvm, _jconf = jconf)
-sc = _zsc_ = SparkContext(jsc=jsc, gateway=gateway, conf=conf)
-_zcUserQueryNameSpace["_zsc_"] = _zsc_
-_zcUserQueryNameSpace["sc"] = sc
-
-if sparkVersion.isSpark2():
-  spark = __zSpark__ = SparkSession(sc, intp.getSparkSession())
-  sqlc = __zSqlc__ = __zSpark__._wrapped
-  _zcUserQueryNameSpace["sqlc"] = sqlc
-  _zcUserQueryNameSpace["__zSqlc__"] = __zSqlc__
-  _zcUserQueryNameSpace["spark"] = spark
-  _zcUserQueryNameSpace["__zSpark__"] = __zSpark__
-else:
-  sqlc = __zSqlc__ = SQLContext(sparkContext=sc, sqlContext=intp.getSQLContext())
-  _zcUserQueryNameSpace["sqlc"] = sqlc
-  _zcUserQueryNameSpace["__zSqlc__"] = sqlc
-
-sqlContext = __zSqlc__
-_zcUserQueryNameSpace["sqlContext"] = sqlContext
-
-completion = __zeppelin_completion__ = PySparkCompletion(intp)
-_zcUserQueryNameSpace["completion"] = completion
-_zcUserQueryNameSpace["__zeppelin_completion__"] = __zeppelin_completion__
-
-z = __zeppelin__ = PyZeppelinContext(intp.getZeppelinContext())
-__zeppelin__._setup_matplotlib()
-_zcUserQueryNameSpace["z"] = z
-_zcUserQueryNameSpace["__zeppelin__"] = __zeppelin__
-
-while True :
-  req = intp.getStatements()
-  try:
-    stmts = req.statements().split("\n")
-    jobGroup = req.jobGroup()
-    jobDesc = req.jobDescription()
-    
-    # Get post-execute hooks
-    try:
-      global_hook = intp.getHook('post_exec_dev')
-    except:
-      global_hook = None
-      
-    try:
-      user_hook = __zeppelin__.getHook('post_exec')
-    except:
-      user_hook = None
-      
-    nhooks = 0
-    for hook in (global_hook, user_hook):
-      if hook:
-        nhooks += 1
-
-    if stmts:
-      # use exec mode to compile the statements except the last statement,
-      # so that the last statement's evaluation will be printed to stdout
-      sc.setJobGroup(jobGroup, jobDesc)
-      code = compile('\n'.join(stmts), '<stdin>', 'exec', ast.PyCF_ONLY_AST, 1)
-      to_run_hooks = []
-      if (nhooks > 0):
-        to_run_hooks = code.body[-nhooks:]
-      to_run_exec, to_run_single = (code.body[:-(nhooks + 1)],
-                                    [code.body[-(nhooks + 1)]])
-
-      try:
-        for node in to_run_exec:
-          mod = ast.Module([node])
-          code = compile(mod, '<stdin>', 'exec')
-          exec(code, _zcUserQueryNameSpace)
-
-        for node in to_run_single:
-          mod = ast.Interactive([node])
-          code = compile(mod, '<stdin>', 'single')
-          exec(code, _zcUserQueryNameSpace)
-          
-        for node in to_run_hooks:
-          mod = ast.Module([node])
-          code = compile(mod, '<stdin>', 'exec')
-          exec(code, _zcUserQueryNameSpace)
-
-        intp.setStatementsFinished("", False)
-      except Py4JJavaError:
-        # raise it to outside try except
-        raise
-      except:
-        exception = traceback.format_exc()
-        m = re.search("File \"<stdin>\", line (\d+).*", exception)
-        if m:
-          line_no = int(m.group(1))
-          intp.setStatementsFinished(
-            "Fail to execute line {}: {}\n".format(line_no, stmts[line_no - 1]) + exception, True)
-        else:
-          intp.setStatementsFinished(exception, True)
-    else:
-      intp.setStatementsFinished("", False)
-
-  except Py4JJavaError:
-    excInnerError = traceback.format_exc() # format_tb() does not return the inner exception
-    innerErrorStart = excInnerError.find("Py4JJavaError:")
-    if innerErrorStart > -1:
-       excInnerError = excInnerError[innerErrorStart:]
-    intp.setStatementsFinished(excInnerError + str(sys.exc_info()), True)
-  except:
-    intp.setStatementsFinished(traceback.format_exc(), True)
-
-  output.reset()

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/d762b528/spark/src/main/scala/org/apache/spark/SparkRBackend.scala
----------------------------------------------------------------------
diff --git a/spark/src/main/scala/org/apache/spark/SparkRBackend.scala b/spark/src/main/scala/org/apache/spark/SparkRBackend.scala
deleted file mode 100644
index 05f1ac0..0000000
--- a/spark/src/main/scala/org/apache/spark/SparkRBackend.scala
+++ /dev/null
@@ -1,54 +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.spark
-
-import org.apache.spark.api.r.RBackend
-
-object SparkRBackend {
-  val backend : RBackend = new RBackend()
-  private var started = false;
-  private var portNumber = 0;
-
-  val backendThread : Thread = new Thread("SparkRBackend") {
-    override def run() {
-      backend.run()
-    }
-  }
-
-  def init() : Int = {
-    portNumber = backend.init()
-    portNumber
-  }
-
-  def start() : Unit = {
-    backendThread.start()
-    started = true
-  }
-
-  def close() : Unit = {
-    backend.close()
-    backendThread.join()
-  }
-
-  def isStarted() : Boolean = {
-    started
-  }
-
-  def port(): Int = {
-    return portNumber
-  }
-}

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/d762b528/spark/src/main/scala/org/apache/zeppelin/spark/ZeppelinRDisplay.scala
----------------------------------------------------------------------
diff --git a/spark/src/main/scala/org/apache/zeppelin/spark/ZeppelinRDisplay.scala b/spark/src/main/scala/org/apache/zeppelin/spark/ZeppelinRDisplay.scala
deleted file mode 100644
index a9014c2..0000000
--- a/spark/src/main/scala/org/apache/zeppelin/spark/ZeppelinRDisplay.scala
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.zeppelin.spark
-
-import org.apache.zeppelin.interpreter.InterpreterResult.Code
-import org.apache.zeppelin.interpreter.InterpreterResult.Code.{SUCCESS}
-import org.apache.zeppelin.interpreter.InterpreterResult.Type
-import org.apache.zeppelin.interpreter.InterpreterResult.Type.{TEXT, HTML, TABLE, IMG}
-import org.jsoup.Jsoup
-import org.jsoup.nodes.Element
-import org.jsoup.nodes.Document.OutputSettings
-import org.jsoup.safety.Whitelist
-
-import scala.collection.JavaConversions._
-import scala.util.matching.Regex
-
-case class RDisplay(content: String, `type`: Type, code: Code)
-
-object ZeppelinRDisplay {
-
-  val pattern = new Regex("""^ *\[\d*\] """)
-
-  def render(html: String, imageWidth: String): RDisplay = {
-
-    val document = Jsoup.parse(html)
-    document.outputSettings().prettyPrint(false)
-
-    val body = document.body()
-
-    if (body.getElementsByTag("p").isEmpty) return RDisplay(body.html(), HTML, SUCCESS)
-
-    val bodyHtml = body.html()
-
-    if (! bodyHtml.contains("<img")
-      &&  ! bodyHtml.contains("<script")
-      && ! bodyHtml.contains("%html ")
-      && ! bodyHtml.contains("%table ")
-      && ! bodyHtml.contains("%img ")
-    ) {
-      return textDisplay(body)
-    }
-
-    if (bodyHtml.contains("%table")) {
-      return tableDisplay(body)
-    }
-
-    if (bodyHtml.contains("%img")) {
-      return imgDisplay(body)
-    }
-
-    return htmlDisplay(body, imageWidth)
-  }
-
-  private def textDisplay(body: Element): RDisplay = {
-    // remove HTML tag while preserving whitespaces and newlines
-    val text = Jsoup.clean(body.html(), "",
-      Whitelist.none(), new OutputSettings().prettyPrint(false))
-    RDisplay(text, TEXT, SUCCESS)
-  }
-
-  private def tableDisplay(body: Element): RDisplay = {
-    val p = body.getElementsByTag("p").first().html.replace("“%table " , "").replace("”", "")
-    val r = (pattern findFirstIn p).getOrElse("")
-    val table = p.replace(r, "").replace("\\t", "\t").replace("\\n", "\n")
-    RDisplay(table, TABLE, SUCCESS)
-  }
-
-  private def imgDisplay(body: Element): RDisplay = {
-    val p = body.getElementsByTag("p").first().html.replace("“%img " , "").replace("”", "")
-    val r = (pattern findFirstIn p).getOrElse("")
-    val img = p.replace(r, "")
-    RDisplay(img, IMG, SUCCESS)
-  }
-
-  private def htmlDisplay(body: Element, imageWidth: String): RDisplay = {
-    var div = new String()
-
-    for (element <- body.children) {
-
-      val eHtml = element.html()
-      var eOuterHtml = element.outerHtml()
-
-      eOuterHtml = eOuterHtml.replace("“%html " , "").replace("”", "")
-
-      val r = (pattern findFirstIn eHtml).getOrElse("")
-
-      div = div + eOuterHtml.replace(r, "")
-    }
-
-    val content =  div
-      .replaceAll("src=\"//", "src=\"http://")
-      .replaceAll("href=\"//", "href=\"http://")
-
-    body.html(content)
-
-    for (image <- body.getElementsByTag("img")) {
-      image.attr("width", imageWidth)
-    }
-
-    RDisplay(body.html, HTML, SUCCESS)
-  }
-}

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/d762b528/spark/src/main/scala/org/apache/zeppelin/spark/utils/DisplayUtils.scala
----------------------------------------------------------------------
diff --git a/spark/src/main/scala/org/apache/zeppelin/spark/utils/DisplayUtils.scala b/spark/src/main/scala/org/apache/zeppelin/spark/utils/DisplayUtils.scala
deleted file mode 100644
index 8181434..0000000
--- a/spark/src/main/scala/org/apache/zeppelin/spark/utils/DisplayUtils.scala
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.zeppelin.spark.utils
-
-import java.lang.StringBuilder
-
-import org.apache.spark.rdd.RDD
-
-import scala.collection.IterableLike
-
-object DisplayUtils {
-
-  implicit def toDisplayRDDFunctions[T <: Product](rdd: RDD[T]): DisplayRDDFunctions[T] = new DisplayRDDFunctions[T](rdd)
-
-  implicit def toDisplayTraversableFunctions[T <: Product](traversable: Traversable[T]): DisplayTraversableFunctions[T] = new DisplayTraversableFunctions[T](traversable)
-
-  def html(htmlContent: String = "") = s"%html $htmlContent"
-
-  def img64(base64Content: String = "") = s"%img $base64Content"
-
-  def img(url: String) = s"<img src='$url' />"
-}
-
-trait DisplayCollection[T <: Product] {
-
-  def printFormattedData(traversable: Traversable[T], columnLabels: String*): Unit = {
-    val providedLabelCount: Int = columnLabels.size
-    var maxColumnCount:Int = 1
-    val headers = new StringBuilder("%table ")
-
-    val data = new StringBuilder("")
-
-    traversable.foreach(tuple => {
-      maxColumnCount = math.max(maxColumnCount,tuple.productArity)
-      data.append(tuple.productIterator.mkString("\t")).append("\n")
-    })
-
-    if (providedLabelCount > maxColumnCount) {
-      headers.append(columnLabels.take(maxColumnCount).mkString("\t")).append("\n")
-    } else if (providedLabelCount < maxColumnCount) {
-      val missingColumnHeaders = ((providedLabelCount+1) to maxColumnCount).foldLeft[String](""){
-        (stringAccumulator,index) =>  if (index==1) s"Column$index" else s"$stringAccumulator\tColumn$index"
-      }
-
-      headers.append(columnLabels.mkString("\t")).append(missingColumnHeaders).append("\n")
-    } else {
-      headers.append(columnLabels.mkString("\t")).append("\n")
-    }
-
-    headers.append(data)
-
-    print(headers.toString)
-  }
-
-}
-
-class DisplayRDDFunctions[T <: Product] (val rdd: RDD[T]) extends DisplayCollection[T] {
-
-  def display(columnLabels: String*)(implicit sparkMaxResult: SparkMaxResult): Unit = {
-    printFormattedData(rdd.take(sparkMaxResult.maxResult), columnLabels: _*)
-  }
-
-  def display(sparkMaxResult:Int, columnLabels: String*): Unit = {
-    printFormattedData(rdd.take(sparkMaxResult), columnLabels: _*)
-  }
-}
-
-class DisplayTraversableFunctions[T <: Product] (val traversable: Traversable[T]) extends DisplayCollection[T] {
-
-  def display(columnLabels: String*): Unit = {
-    printFormattedData(traversable, columnLabels: _*)
-  }
-}
-
-class SparkMaxResult(val maxResult: Int) extends Serializable

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/d762b528/spark/src/test/java/org/apache/zeppelin/spark/DepInterpreterTest.java
----------------------------------------------------------------------
diff --git a/spark/src/test/java/org/apache/zeppelin/spark/DepInterpreterTest.java b/spark/src/test/java/org/apache/zeppelin/spark/DepInterpreterTest.java
deleted file mode 100644
index e177d49..0000000
--- a/spark/src/test/java/org/apache/zeppelin/spark/DepInterpreterTest.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.zeppelin.spark;
-
-import static org.junit.Assert.assertEquals;
-
-import java.io.IOException;
-import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.Properties;
-
-import org.apache.zeppelin.display.AngularObjectRegistry;
-import org.apache.zeppelin.user.AuthenticationInfo;
-import org.apache.zeppelin.display.GUI;
-import org.apache.zeppelin.interpreter.*;
-import org.apache.zeppelin.interpreter.InterpreterResult.Code;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.TemporaryFolder;
-
-public class DepInterpreterTest {
-
-  @Rule
-  public TemporaryFolder tmpDir = new TemporaryFolder();
-
-  private DepInterpreter dep;
-  private InterpreterContext context;
-
-  private Properties getTestProperties() throws IOException {
-    Properties p = new Properties();
-    p.setProperty("zeppelin.dep.localrepo", tmpDir.newFolder().getAbsolutePath());
-    p.setProperty("zeppelin.dep.additionalRemoteRepository", "spark-packages,http://dl.bintray.com/spark-packages/maven,false;");
-    return p;
-  }
-
-  @Before
-  public void setUp() throws Exception {
-    Properties p = getTestProperties();
-
-    dep = new DepInterpreter(p);
-    dep.open();
-
-    InterpreterGroup intpGroup = new InterpreterGroup();
-    intpGroup.put("note", new LinkedList<Interpreter>());
-    intpGroup.get("note").add(new SparkInterpreter(p));
-    intpGroup.get("note").add(dep);
-    dep.setInterpreterGroup(intpGroup);
-
-    context = new InterpreterContext("note", "id", null, "title", "text", new AuthenticationInfo(),
-        new HashMap<String, Object>(), new GUI(), new GUI(),
-        new AngularObjectRegistry(intpGroup.getId(), null),
-        null,
-        new LinkedList<InterpreterContextRunner>(), null);
-  }
-
-  @After
-  public void tearDown() throws Exception {
-    dep.close();
-  }
-
-  @Test
-  public void testDefault() {
-    dep.getDependencyContext().reset();
-    InterpreterResult ret = dep.interpret("z.load(\"org.apache.commons:commons-csv:1.1\")", context);
-    assertEquals(Code.SUCCESS, ret.code());
-
-    assertEquals(1, dep.getDependencyContext().getFiles().size());
-    assertEquals(1, dep.getDependencyContext().getFilesDist().size());
-
-    // Add a test for the spark-packages repo - default in additionalRemoteRepository
-    ret = dep.interpret("z.load(\"amplab:spark-indexedrdd:0.3\")", context);
-    assertEquals(Code.SUCCESS, ret.code());
-
-    // Reset at the end of the test
-    dep.getDependencyContext().reset();
-  }
-}


[10/10] zeppelin git commit: ZEPPELIN-3111. Refactor SparkInterpreter

Posted by zj...@apache.org.
ZEPPELIN-3111. Refactor SparkInterpreter

### What is this PR for?
This is for the refactoring of SparkInterpreter. See design doc. https://docs.google.com/document/d/1AfGg3aGXonDyri1jrP4MMFT4Y4j3wpN1t8kL-GAKSUc/edit?usp=sharing

### What type of PR is it?
[Refactoring]

### Todos
* [ ] - Task

### What is the Jira issue?
* https://issues.apache.org/jira/browse/ZEPPELIN-3111

### How should this be tested?
* Unit test is added.

### Screenshots (if appropriate)

### Questions:
* Does the licenses files need update? No
* Is there breaking changes for older versions? No
* Does this needs documentation? No

Author: Jeff Zhang <zj...@apache.org>

Closes #2709 from zjffdu/ZEPPELIN-3111 and squashes the following commits:

aae4b09 [Jeff Zhang] ZEPPELIN-3111. Refactor SparkInterpreter


Project: http://git-wip-us.apache.org/repos/asf/zeppelin/repo
Commit: http://git-wip-us.apache.org/repos/asf/zeppelin/commit/d762b528
Tree: http://git-wip-us.apache.org/repos/asf/zeppelin/tree/d762b528
Diff: http://git-wip-us.apache.org/repos/asf/zeppelin/diff/d762b528

Branch: refs/heads/master
Commit: d762b5288536201d8a2964891c556efaa1bae867
Parents: 6664412
Author: Jeff Zhang <zj...@apache.org>
Authored: Mon Jul 17 13:02:09 2017 +0800
Committer: Jeff Zhang <zj...@apache.org>
Committed: Fri Feb 2 14:00:35 2018 +0800

----------------------------------------------------------------------
 .travis.yml                                     |   32 +-
 bin/interpreter.sh                              |    2 +-
 docs/interpreter/spark.md                       |    4 +
 pom.xml                                         |   19 +-
 python/pom.xml                                  |   41 +-
 .../zeppelin/python/IPythonInterpreter.java     |    6 +-
 .../zeppelin/python/PythonInterpreter.java      |    8 +-
 .../zeppelin/python/IPythonInterpreterTest.java |   14 +-
 .../python/PythonInterpreterMatplotlibTest.java |    2 +-
 .../zeppelin/python/PythonInterpreterTest.java  |    2 +-
 r/pom.xml                                       |    7 -
 spark-dependencies/pom.xml                      | 1042 ------------
 spark/interpreter/figure/null-1.png             |  Bin 0 -> 13599 bytes
 spark/interpreter/pom.xml                       |  573 +++++++
 .../spark/AbstractSparkInterpreter.java         |   57 +
 .../apache/zeppelin/spark/DepInterpreter.java   |  363 +++++
 .../zeppelin/spark/IPySparkInterpreter.java     |  128 ++
 .../zeppelin/spark/NewSparkInterpreter.java     |  390 +++++
 .../zeppelin/spark/OldSparkInterpreter.java     | 1525 ++++++++++++++++++
 .../zeppelin/spark/PySparkInterpreter.java      |  751 +++++++++
 .../org/apache/zeppelin/spark/PythonUtils.java  |   96 ++
 .../apache/zeppelin/spark/SparkInterpreter.java |  163 ++
 .../zeppelin/spark/SparkRInterpreter.java       |  250 +++
 .../zeppelin/spark/SparkSqlInterpreter.java     |  187 +++
 .../org/apache/zeppelin/spark/SparkVersion.java |  130 ++
 .../zeppelin/spark/SparkZeppelinContext.java    |  312 ++++
 .../java/org/apache/zeppelin/spark/Utils.java   |  177 ++
 .../org/apache/zeppelin/spark/ZeppelinR.java    |  394 +++++
 .../apache/zeppelin/spark/ZeppelinRContext.java |   69 +
 .../spark/dep/SparkDependencyContext.java       |  181 +++
 .../spark/dep/SparkDependencyResolver.java      |  351 ++++
 .../src/main/resources/R/zeppelin_sparkr.R      |  105 ++
 .../src/main/resources/interpreter-setting.json |  233 +++
 .../main/resources/python/zeppelin_ipyspark.py  |   53 +
 .../main/resources/python/zeppelin_pyspark.py   |  393 +++++
 .../scala/org/apache/spark/SparkRBackend.scala  |   54 +
 .../zeppelin/spark/ZeppelinRDisplay.scala       |  117 ++
 .../zeppelin/spark/utils/DisplayUtils.scala     |   90 ++
 .../zeppelin/spark/DepInterpreterTest.java      |   94 ++
 .../zeppelin/spark/IPySparkInterpreterTest.java |  204 +++
 .../zeppelin/spark/NewSparkInterpreterTest.java |  389 +++++
 .../spark/NewSparkSqlInterpreterTest.java       |  173 ++
 .../zeppelin/spark/OldSparkInterpreterTest.java |  368 +++++
 .../spark/OldSparkSqlInterpreterTest.java       |  189 +++
 .../spark/PySparkInterpreterMatplotlibTest.java |  250 +++
 .../zeppelin/spark/PySparkInterpreterTest.java  |  193 +++
 .../zeppelin/spark/SparkRInterpreterTest.java   |   99 ++
 .../apache/zeppelin/spark/SparkVersionTest.java |   71 +
 .../src/test/resources/log4j.properties         |   52 +
 .../spark/utils/DisplayFunctionsTest.scala      |  173 ++
 spark/pom.xml                                   |  871 +++-------
 spark/scala-2.10/pom.xml                        |   41 +
 spark/scala-2.10/spark-scala-parent             |    1 +
 .../spark/SparkScala210Interpreter.scala        |  141 ++
 spark/scala-2.11/pom.xml                        |   41 +
 spark/scala-2.11/spark-scala-parent             |    1 +
 .../src/main/resources/log4j.properties         |   50 +
 .../spark/SparkScala211Interpreter.scala        |  140 ++
 spark/spark-dependencies/pom.xml                |  591 +++++++
 spark/spark-scala-parent/pom.xml                |  172 ++
 .../spark/BaseSparkScalaInterpreter.scala       |  338 ++++
 .../apache/zeppelin/spark/DepInterpreter.java   |  363 -----
 .../zeppelin/spark/IPySparkInterpreter.java     |  128 --
 .../zeppelin/spark/PySparkInterpreter.java      |  745 ---------
 .../org/apache/zeppelin/spark/PythonUtils.java  |   96 --
 .../apache/zeppelin/spark/SparkInterpreter.java | 1525 ------------------
 .../zeppelin/spark/SparkRInterpreter.java       |  250 ---
 .../zeppelin/spark/SparkSqlInterpreter.java     |  187 ---
 .../org/apache/zeppelin/spark/SparkVersion.java |  130 --
 .../zeppelin/spark/SparkZeppelinContext.java    |  314 ----
 .../java/org/apache/zeppelin/spark/Utils.java   |  177 --
 .../org/apache/zeppelin/spark/ZeppelinR.java    |  394 -----
 .../apache/zeppelin/spark/ZeppelinRContext.java |   69 -
 .../spark/dep/SparkDependencyContext.java       |  181 ---
 .../spark/dep/SparkDependencyResolver.java      |  351 ----
 spark/src/main/resources/R/zeppelin_sparkr.R    |  105 --
 .../src/main/resources/interpreter-setting.json |  226 ---
 .../main/resources/python/zeppelin_ipyspark.py  |   53 -
 .../main/resources/python/zeppelin_pyspark.py   |  393 -----
 .../scala/org/apache/spark/SparkRBackend.scala  |   54 -
 .../zeppelin/spark/ZeppelinRDisplay.scala       |  117 --
 .../zeppelin/spark/utils/DisplayUtils.scala     |   90 --
 .../zeppelin/spark/DepInterpreterTest.java      |   94 --
 .../zeppelin/spark/IPySparkInterpreterTest.java |  206 ---
 .../spark/PySparkInterpreterMatplotlibTest.java |  241 ---
 .../zeppelin/spark/PySparkInterpreterTest.java  |  194 ---
 .../zeppelin/spark/SparkInterpreterTest.java    |  355 ----
 .../zeppelin/spark/SparkSqlInterpreterTest.java |  180 ---
 .../apache/zeppelin/spark/SparkVersionTest.java |   71 -
 .../spark/dep/SparkDependencyResolverTest.java  |   51 -
 spark/src/test/resources/log4j.properties       |   49 -
 .../spark/utils/DisplayFunctionsTest.scala      |  173 --
 testing/install_external_dependencies.sh        |    4 +-
 zeppelin-display/pom.xml                        |   12 +-
 .../zeppelin/integration/SparkParagraphIT.java  |    2 +-
 .../interpreter/BaseZeppelinContext.java        |    2 +
 .../remote/RemoteInterpreterServer.java         |    9 +-
 zeppelin-server/pom.xml                         |    6 +
 .../zeppelin/rest/AbstractTestRestApi.java      |   15 +-
 .../zeppelin/rest/ZeppelinSparkClusterTest.java |    5 +-
 zeppelin-zengine/pom.xml                        |    2 +-
 101 files changed, 11241 insertions(+), 9341 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/zeppelin/blob/d762b528/.travis.yml
----------------------------------------------------------------------
diff --git a/.travis.yml b/.travis.yml
index 677209b..ce935b2 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -68,7 +68,7 @@ matrix:
       dist: trusty
       addons:
         firefox: "31.0"
-      env: PYTHON="3" SCALA_VER="2.11" SPARK_VER="2.2.0" HADOOP_VER="2.6" PROFILE="-Pspark-2.2 -Pweb-ci -Pscalding -Phelium-dev -Pexamples -Pscala-2.11" BUILD_FLAG="package -Pbuild-distr -DskipRat" TEST_FLAG="verify -Pusing-packaged-distr -DskipRat" MODULES="-pl ${INTERPRETERS}" TEST_PROJECTS="-Dtests.to.exclude=**/ZeppelinSparkClusterTest.java,**/org.apache.zeppelin.spark.*,**/HeliumApplicationFactoryTest.java -DfailIfNoTests=false"
+      env: PYTHON="3" SCALA_VER="2.11" SPARK_VER="2.2.0" HADOOP_VER="2.6" PROFILE="-Pspark-2.2 -Pweb-ci -Pscalding -Phelium-dev -Pexamples -Pscala-2.11" BUILD_FLAG="package -Pbuild-distr -DskipRat" TEST_FLAG="verify -Pusing-packaged-distr -DskipRat" MODULES="-pl ${INTERPRETERS}" TEST_PROJECTS="-Dtests.to.exclude=**/ZeppelinSparkClusterTest.java,**/org/apache/zeppelin/spark/*,**/HeliumApplicationFactoryTest.java -DfailIfNoTests=false"
 
     # Test selenium with spark module for 1.6.3
     - jdk: "oraclejdk8"
@@ -82,43 +82,43 @@ matrix:
       dist: trusty
       env: PYTHON="3" SCALA_VER="2.10" PROFILE="-Pscalding" BUILD_FLAG="install -DskipTests -DskipRat -Pr" TEST_FLAG="test -DskipRat" MODULES="-pl $(echo .,zeppelin-interpreter,${INTERPRETERS} | sed 's/!//g')" TEST_PROJECTS=""
 
-    # Test spark module for 2.2.0 with scala 2.11, livy
+    # Test spark module for 2.2.0 with scala 2.11
     - jdk: "oraclejdk8"
       dist: trusty
-      env: PYTHON="2" SCALA_VER="2.11" SPARK_VER="2.2.0" HADOOP_VER="2.6" PROFILE="-Pweb-ci -Pspark-2.2 -Phadoop3 -Phadoop-2.6 -Pscala-2.11" SPARKR="true" BUILD_FLAG="install -DskipTests -DskipRat" TEST_FLAG="test -DskipRat" MODULES="-pl .,zeppelin-interpreter,zeppelin-zengine,zeppelin-server,zeppelin-display,spark-dependencies,spark,python,livy" TEST_PROJECTS="-Dtest=ZeppelinSparkClusterTest,org.apache.zeppelin.spark.*,org.apache.zeppelin.livy.* -DfailIfNoTests=false"
+      env: PYTHON="2" SCALA_VER="2.11" SPARK_VER="2.2.0" HADOOP_VER="2.6" PROFILE="-Pweb-ci -Pspark-2.2 -Phadoop3 -Phadoop-2.6 -Pscala-2.11" SPARKR="true" BUILD_FLAG="install -DskipTests -DskipRat" TEST_FLAG="test -DskipRat" MODULES="-pl .,zeppelin-interpreter,zeppelin-zengine,zeppelin-server,zeppelin-display,spark/interpreter,spark/scala-2.10,spark/scala-2.11,spark/spark-dependencies,python" TEST_PROJECTS="-Dtest=ZeppelinSparkClusterTest,org.apache.zeppelin.spark.*,org.apache.zeppelin.livy.* -DfailIfNoTests=false"
 
-    # Test spark module for 2.1.0 with scala 2.11, livy
+    # Test spark module for 2.1.0 with scala 2.11
     - jdk: "openjdk7"
       dist: trusty
-      env: PYTHON="2" SCALA_VER="2.11" SPARK_VER="2.1.0" HADOOP_VER="2.6" PROFILE="-Pweb-ci -Pspark-2.1 -Phadoop2 -Phadoop-2.6 -Pscala-2.11" SPARKR="true" BUILD_FLAG="install -DskipTests -DskipRat" TEST_FLAG="test -DskipRat" MODULES="-pl .,zeppelin-interpreter,zeppelin-zengine,zeppelin-server,zeppelin-display,spark-dependencies,spark,python,livy" TEST_PROJECTS="-Dtest=ZeppelinSparkClusterTest,org.apache.zeppelin.spark.*,org.apache.zeppelin.livy.* -DfailIfNoTests=false"
+      env: PYTHON="2" SCALA_VER="2.11" SPARK_VER="2.1.0" HADOOP_VER="2.6" PROFILE="-Pweb-ci -Pspark-2.1 -Phadoop2 -Phadoop-2.6 -Pscala-2.11" SPARKR="true" BUILD_FLAG="install -DskipTests -DskipRat" TEST_FLAG="test -DskipRat" MODULES="-pl .,zeppelin-interpreter,zeppelin-zengine,zeppelin-server,zeppelin-display,spark/interpreter,spark/scala-2.10,spark/scala-2.11,spark/spark-dependencies,python" TEST_PROJECTS="-Dtest=ZeppelinSparkClusterTest,org.apache.zeppelin.spark.*,org.apache.zeppelin.livy.* -DfailIfNoTests=false"
 
     # Test spark module for 2.0.2 with scala 2.11
     - jdk: "oraclejdk8"
       dist: trusty
-      env: PYTHON="2" SCALA_VER="2.11" SPARK_VER="2.0.2" HADOOP_VER="2.6" PROFILE="-Pweb-ci -Pspark-2.0 -Phadoop3 -Phadoop-2.6 -Pscala-2.11" SPARKR="true" BUILD_FLAG="install -DskipTests -DskipRat" TEST_FLAG="test -DskipRat" MODULES="-pl .,zeppelin-interpreter,zeppelin-zengine,zeppelin-server,zeppelin-display,spark-dependencies,spark,python" TEST_PROJECTS="-Dtest=ZeppelinSparkClusterTest,org.apache.zeppelin.spark.* -DfailIfNoTests=false"
+      env: PYTHON="2" SCALA_VER="2.11" SPARK_VER="2.0.2" HADOOP_VER="2.6" PROFILE="-Pweb-ci -Pspark-2.0 -Phadoop3 -Phadoop-2.6 -Pscala-2.11" SPARKR="true" BUILD_FLAG="install -DskipTests -DskipRat" TEST_FLAG="test -DskipRat" MODULES="-pl .,zeppelin-interpreter,zeppelin-zengine,zeppelin-server,zeppelin-display,spark/interpreter,spark/scala-2.10,spark/scala-2.11,spark/spark-dependencies,python" TEST_PROJECTS="-Dtest=ZeppelinSparkClusterTest,org.apache.zeppelin.spark.* -DfailIfNoTests=false"
 
-    # Test spark module for 1.6.3 with scala 2.10
+    # Test spark module for 1.6.3 with scala 2.11
     - jdk: "openjdk7"
       dist: trusty
-      env: PYTHON="3" SCALA_VER="2.10" SPARK_VER="1.6.3" HADOOP_VER="2.6" PROFILE="-Pweb-ci -Pspark-1.6 -Phadoop2 -Phadoop-2.6 -Pscala-2.10" SPARKR="true" BUILD_FLAG="install -DskipTests -DskipRat" TEST_FLAG="test -DskipRat" MODULES="-pl .,zeppelin-interpreter,zeppelin-zengine,zeppelin-server,zeppelin-display,spark-dependencies,spark,python" TEST_PROJECTS="-Dtest=ZeppelinSparkClusterTest,org.apache.zeppelin.spark.*,org.apache.zeppelin.spark.* -DfailIfNoTests=false"
+      env: PYTHON="3" SCALA_VER="2.10" SPARK_VER="1.6.3" HADOOP_VER="2.6" PROFILE="-Pweb-ci -Pspark-1.6 -Phadoop2 -Phadoop-2.6 -Pscala-2.10" SPARKR="true" BUILD_FLAG="install -DskipTests -DskipRat" TEST_FLAG="test -DskipRat" MODULES="-pl .,zeppelin-interpreter,zeppelin-zengine,zeppelin-server,zeppelin-display,spark/interpreter,spark/scala-2.10,spark/scala-2.11,spark/spark-dependencies,python" TEST_PROJECTS="-Dtest=ZeppelinSparkClusterTest,org.apache.zeppelin.spark.*,org.apache.zeppelin.spark.* -DfailIfNoTests=false"
 
     # Test spark module for 1.6.3 with scala 2.11
     - jdk: "oraclejdk8"
       dist: trusty
-      env: PYTHON="2" SCALA_VER="2.11" SPARK_VER="1.6.3" HADOOP_VER="2.6" PROFILE="-Pweb-ci -Pspark-1.6 -Phadoop3 -Phadoop-2.6 -Pscala-2.11" SPARKR="true" BUILD_FLAG="install -DskipTests -DskipRat" TEST_FLAG="test -DskipRat" MODULES="-pl .,zeppelin-interpreter,zeppelin-zengine,zeppelin-server,zeppelin-display,spark-dependencies,spark,python" TEST_PROJECTS="-Dtest=ZeppelinSparkClusterTest,org.apache.zeppelin.spark.* -DfailIfNoTests=false"
+      env: PYTHON="2" SCALA_VER="2.11" SPARK_VER="1.6.3" HADOOP_VER="2.6" PROFILE="-Pweb-ci -Pspark-1.6 -Phadoop3 -Phadoop-2.6 -Pscala-2.11" SPARKR="true" BUILD_FLAG="install -DskipTests -DskipRat" TEST_FLAG="test -DskipRat" MODULES="-pl .,zeppelin-interpreter,zeppelin-zengine,zeppelin-server,zeppelin-display,spark/interpreter,spark/scala-2.10,spark/scala-2.11,spark/spark-dependencies,python" TEST_PROJECTS="-Dtest=ZeppelinSparkClusterTest,org.apache.zeppelin.spark.* -DfailIfNoTests=false"
 
     # Test python/pyspark with python 2, livy 0.2
     - sudo: required
       dist: trusty
       jdk: "openjdk7"
-      env: PYTHON="2" SCALA_VER="2.10" SPARK_VER="1.6.1" HADOOP_VER="2.6" LIVY_VER="0.4.0-incubating" PROFILE="-Pspark-1.6 -Phadoop2 -Phadoop-2.6 -Pscala-2.10" BUILD_FLAG="install -am -DskipTests -DskipRat" TEST_FLAG="verify -DskipRat" MODULES="-pl .,zeppelin-interpreter,zeppelin-display,spark-dependencies,spark,python,livy" TEST_PROJECTS="-Dtest=LivySQLInterpreterTest,org.apache.zeppelin.spark.PySpark*Test,org.apache.zeppelin.python.* -Dpyspark.test.exclude='' -DfailIfNoTests=false"
+      env: PYTHON="2" SCALA_VER="2.10" SPARK_VER="1.6.1" HADOOP_VER="2.6" LIVY_VER="0.4.0-incubating" PROFILE="-Pspark-1.6 -Phadoop2 -Phadoop-2.6 -Plivy-0.2 -Pscala-2.10" BUILD_FLAG="install -am -DskipTests -DskipRat" TEST_FLAG="verify -DskipRat" MODULES="-pl .,zeppelin-interpreter,zeppelin-display,spark/interpreter,spark/scala-2.10,spark/scala-2.11,spark/spark-dependencies,python,livy" TEST_PROJECTS="-Dtest=LivySQLInterpreterTest,org.apache.zeppelin.spark.PySpark*Test,org.apache.zeppelin.python.* -Dpyspark.test.exclude='' -DfailIfNoTests=false"
 
     # Test python/pyspark with python 3, livy 0.3
     - sudo: required
       dist: trusty
       jdk: "openjdk7"
-      env: PYTHON="3" SCALA_VER="2.11" SPARK_VER="2.0.0" HADOOP_VER="2.6" LIVY_VER="0.4.0-incubating" PROFILE="-Pspark-2.0 -Phadoop3 -Phadoop-2.6 -Pscala-2.11" BUILD_FLAG="install -am -DskipTests -DskipRat" TEST_FLAG="verify -DskipRat" MODULES="-pl .,zeppelin-interpreter,zeppelin-display,spark-dependencies,spark,python,livy" TEST_PROJECTS="-Dtest=LivySQLInterpreterTest,org.apache.zeppelin.spark.PySpark*Test,org.apache.zeppelin.python.* -Dpyspark.test.exclude='' -DfailIfNoTests=false"
-
+      env: PYTHON="3" SCALA_VER="2.11" SPARK_VER="2.0.0" HADOOP_VER="2.6" LIVY_VER="0.4.0-incubating" PROFILE="-Pspark-2.0 -Phadoop3 -Phadoop-2.6 -Pscala-2.11 -Plivy-0.3" BUILD_FLAG="install -am -DskipTests -DskipRat" TEST_FLAG="verify -DskipRat" MODULES="-pl .,zeppelin-interpreter,zeppelin-display,spark/interpreter,spark/scala-2.10,spark/scala-2.11,spark/spark-dependencies,python,livy" TEST_PROJECTS="-Dtest=LivySQLInterpreterTest,org.apache.zeppelin.spark.PySpark*Test,org.apache.zeppelin.python.* -Dpyspark.test.exclude='' -DfailIfNoTests=false"
+      
 before_install:
   # check files included in commit range, clear bower_components if a bower.json file has changed.
   # bower cache clearing can also be forced by putting "bower clear" or "clear bower" in a commit message
@@ -133,7 +133,7 @@ before_install:
   - ls -la .spark-dist ${HOME}/.m2/repository/.cache/maven-download-plugin || true
   - ls .node_modules && cp -r .node_modules zeppelin-web/node_modules || echo "node_modules are not cached"
   - "/sbin/start-stop-daemon --start --quiet --pidfile /tmp/custom_xvfb_99.pid --make-pidfile --background --exec /usr/bin/Xvfb -- :99 -ac -screen 0 1600x1024x16"
-  - ./dev/change_scala_version.sh $SCALA_VER
+  #- ./dev/change_scala_version.sh $SCALA_VER
   - source ~/.environ
 
 install:
@@ -145,9 +145,11 @@ before_script:
   - if [[ -n $LIVY_VER ]]; then ./testing/downloadLivy.sh $LIVY_VER; fi
   - if [[ -n $LIVY_VER ]]; then export LIVY_HOME=`pwd`/livy-$LIVY_VER-bin; fi
   - if [[ -n $LIVY_VER ]]; then export SPARK_HOME=`pwd`/spark-$SPARK_VER-bin-hadoop$HADOOP_VER; fi
-  - export SPARK_HOME=`pwd`/spark-$SPARK_VER-bin-hadoop$HADOOP_VER
-  - echo "export SPARK_HOME=`pwd`/spark-$SPARK_VER-bin-hadoop$HADOOP_VER" > conf/zeppelin-env.sh
+  - if [[ -n $SPARK_VER ]]; then export SPARK_HOME=`pwd`/spark-$SPARK_VER-bin-hadoop$HADOOP_VER; fi
+  - if [[ -n $SPARK_VER ]]; then echo "export SPARK_HOME=`pwd`/spark-$SPARK_VER-bin-hadoop$HADOOP_VER" > conf/zeppelin-env.sh; fi
   - echo "export ZEPPELIN_HELIUM_REGISTRY=helium" >> conf/zeppelin-env.sh
+  - echo "export SPARK_PRINT_LAUNCH_COMMAND=true" >> conf/zeppelin-env.sh
+  - export SPARK_PRINT_LAUNCH_COMMAND=true
   - tail conf/zeppelin-env.sh
   # https://docs.travis-ci.com/user/gui-and-headless-browsers/#Using-xvfb-to-Run-Tests-That-Require-a-GUI
   - if [[ -n $TEST_MODULES ]]; then export DISPLAY=:99.0; sh -e /etc/init.d/xvfb start; sleep 3; fi

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/d762b528/bin/interpreter.sh
----------------------------------------------------------------------
diff --git a/bin/interpreter.sh b/bin/interpreter.sh
index aa25646..45ee0ce 100755
--- a/bin/interpreter.sh
+++ b/bin/interpreter.sh
@@ -121,7 +121,7 @@ if [[ "${INTERPRETER_ID}" == "spark" ]]; then
   fi
   if [[ -n "${SPARK_HOME}" ]]; then
     export SPARK_SUBMIT="${SPARK_HOME}/bin/spark-submit"
-    SPARK_APP_JAR="$(ls ${ZEPPELIN_HOME}/interpreter/spark/zeppelin-spark*.jar)"
+    SPARK_APP_JAR="$(ls ${ZEPPELIN_HOME}/interpreter/spark/spark-interpreter*.jar)"
     # This will evantually passes SPARK_APP_JAR to classpath of SparkIMain
     ZEPPELIN_INTP_CLASSPATH+=":${SPARK_APP_JAR}"
 

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/d762b528/docs/interpreter/spark.md
----------------------------------------------------------------------
diff --git a/docs/interpreter/spark.md b/docs/interpreter/spark.md
index da957c6..90b1608 100644
--- a/docs/interpreter/spark.md
+++ b/docs/interpreter/spark.md
@@ -199,6 +199,10 @@ Zeppelin support both yarn client and yarn cluster mode (yarn cluster mode is su
 You can either specify them in `zeppelin-env.sh`, or in interpreter setting page. Specifying them in `zeppelin-env.sh` means you can use only one version of `spark` & `hadoop`. Specifying them
 in interpreter setting page means you can use multiple versions of `spark` & `hadoop` in one zeppelin instance.
 
+### 4. New Version of SparkInterpreter
+There's one new version of SparkInterpreter starting with better spark support and code completion from Zeppelin 0.8.0, by default we still use the old version of SparkInterpreter.
+If you want to use the new one, you can configure `zeppelin.spark.useNew` as `true` in its interpreter setting.
+
 ## SparkContext, SQLContext, SparkSession, ZeppelinContext
 SparkContext, SQLContext and ZeppelinContext are automatically created and exposed as variable names `sc`, `sqlContext` and `z`, respectively, in Scala, Python and R environments.
 Staring from 0.6.1 SparkSession is available as variable `spark` when you are using Spark 2.x.

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/d762b528/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index 725db41..2c230cb 100644
--- a/pom.xml
+++ b/pom.xml
@@ -56,9 +56,11 @@
     <module>zeppelin-interpreter</module>
     <module>zeppelin-zengine</module>
     <module>zeppelin-display</module>
-    <module>spark-dependencies</module>
     <module>groovy</module>
-    <module>spark</module>
+    <module>spark/scala-2.10</module>
+    <module>spark/scala-2.11</module>
+    <module>spark/interpreter</module>
+    <module>spark/spark-dependencies</module>
     <module>markdown</module>
     <module>angular</module>
     <module>shell</module>
@@ -86,6 +88,7 @@
 
   <properties>
     <!-- language versions -->
+    <java.version>1.7</java.version>
     <scala.version>2.10.5</scala.version>
     <scala.binary.version>2.10</scala.binary.version>
     <scalatest.version>2.2.4</scalatest.version>
@@ -329,8 +332,8 @@
         <artifactId>maven-compiler-plugin</artifactId>
         <version>${plugin.compiler.version}</version>
         <configuration>
-          <source>1.7</source>
-          <target>1.7</target>
+          <source>${java.version}</source>
+          <target>${java.version}</target>
         </configuration>
       </plugin>
 
@@ -739,9 +742,6 @@
   <profiles>
     <profile>
       <id>scala-2.10</id>
-      <activation>
-        <activeByDefault>true</activeByDefault>
-      </activation>
       <properties>
         <scala.version>2.10.5</scala.version>
         <scala.binary.version>2.10</scala.binary.version>
@@ -750,8 +750,11 @@
 
     <profile>
       <id>scala-2.11</id>
+      <activation>
+        <activeByDefault>true</activeByDefault>
+      </activation>
       <properties>
-        <scala.version>2.11.7</scala.version>
+        <scala.version>2.11.8</scala.version>
         <scala.binary.version>2.11</scala.binary.version>
       </properties>
     </profile>

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/d762b528/python/pom.xml
----------------------------------------------------------------------
diff --git a/python/pom.xml b/python/pom.xml
index 3ce47b0..c14d4b1 100644
--- a/python/pom.xml
+++ b/python/pom.xml
@@ -43,6 +43,7 @@
     <pypi.repo.url>https://pypi.python.org/packages</pypi.repo.url>
     <python.py4j.repo.folder>/64/5c/01e13b68e8caafece40d549f232c9b5677ad1016071a48d04cc3895acaa3</python.py4j.repo.folder>
     <grpc.version>1.4.0</grpc.version>
+    <plugin.shade.version>2.4.1</plugin.shade.version>
   </properties>
 
   <dependencies>
@@ -90,13 +91,7 @@
       <artifactId>grpc-stub</artifactId>
       <version>${grpc.version}</version>
     </dependency>
-
-    <dependency>
-      <groupId>com.google.guava</groupId>
-      <artifactId>guava</artifactId>
-      <version>18.0</version>
-    </dependency>
-
+    
     <!-- test libraries -->
     <dependency>
       <groupId>junit</groupId>
@@ -203,6 +198,38 @@
       </plugin>
 
       <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-shade-plugin</artifactId>
+        <version>${plugin.shade.version}</version>
+        <configuration>
+          <transformers>
+            <transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer" />
+            <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
+              <resource>reference.conf</resource>
+            </transformer>
+          </transformers>
+          <relocations>
+            <relocation>
+              <pattern>com.google.common</pattern>
+              <shadedPattern>org.apache.zeppelin.com.google.common</shadedPattern>
+            </relocation>
+            <relocation>
+              <pattern>py4j</pattern>
+              <shadedPattern>org.apache.zeppelin.py4j</shadedPattern>
+            </relocation>
+          </relocations>
+        </configuration>
+        <executions>
+          <execution>
+            <phase>package</phase>
+            <goals>
+              <goal>shade</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+
+      <plugin>
         <artifactId>maven-enforcer-plugin</artifactId>
       </plugin>
       <plugin>

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/d762b528/python/src/main/java/org/apache/zeppelin/python/IPythonInterpreter.java
----------------------------------------------------------------------
diff --git a/python/src/main/java/org/apache/zeppelin/python/IPythonInterpreter.java b/python/src/main/java/org/apache/zeppelin/python/IPythonInterpreter.java
index bd687be..81cfeb2 100644
--- a/python/src/main/java/org/apache/zeppelin/python/IPythonInterpreter.java
+++ b/python/src/main/java/org/apache/zeppelin/python/IPythonInterpreter.java
@@ -299,7 +299,7 @@ public class IPythonInterpreter extends Interpreter implements ExecuteResultHand
   }
 
   @Override
-  public void close() {
+  public void close() throws InterpreterException {
     if (watchDog != null) {
       LOGGER.debug("Kill IPython Process");
       ipythonClient.stop(StopRequest.newBuilder().build());
@@ -327,7 +327,7 @@ public class IPythonInterpreter extends Interpreter implements ExecuteResultHand
   }
 
   @Override
-  public void cancel(InterpreterContext context) {
+  public void cancel(InterpreterContext context) throws InterpreterException {
     ipythonClient.cancel(CancelRequest.newBuilder().build());
   }
 
@@ -337,7 +337,7 @@ public class IPythonInterpreter extends Interpreter implements ExecuteResultHand
   }
 
   @Override
-  public int getProgress(InterpreterContext context) {
+  public int getProgress(InterpreterContext context) throws InterpreterException {
     return 0;
   }
 

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/d762b528/python/src/main/java/org/apache/zeppelin/python/PythonInterpreter.java
----------------------------------------------------------------------
diff --git a/python/src/main/java/org/apache/zeppelin/python/PythonInterpreter.java b/python/src/main/java/org/apache/zeppelin/python/PythonInterpreter.java
index b13cb8a..028f1c6 100644
--- a/python/src/main/java/org/apache/zeppelin/python/PythonInterpreter.java
+++ b/python/src/main/java/org/apache/zeppelin/python/PythonInterpreter.java
@@ -285,7 +285,7 @@ public class PythonInterpreter extends Interpreter implements ExecuteResultHandl
   }
 
   @Override
-  public void close() {
+  public void close() throws InterpreterException {
     if (iPythonInterpreter != null) {
       iPythonInterpreter.close();
       return;
@@ -463,7 +463,7 @@ public class PythonInterpreter extends Interpreter implements ExecuteResultHandl
     return context;
   }
 
-  public void interrupt() throws IOException {
+  public void interrupt() throws IOException, InterpreterException {
     if (pythonPid > -1) {
       logger.info("Sending SIGINT signal to PID : " + pythonPid);
       Runtime.getRuntime().exec("kill -SIGINT " + pythonPid);
@@ -474,7 +474,7 @@ public class PythonInterpreter extends Interpreter implements ExecuteResultHandl
   }
 
   @Override
-  public void cancel(InterpreterContext context) {
+  public void cancel(InterpreterContext context) throws InterpreterException {
     if (iPythonInterpreter != null) {
       iPythonInterpreter.cancel(context);
     }
@@ -491,7 +491,7 @@ public class PythonInterpreter extends Interpreter implements ExecuteResultHandl
   }
 
   @Override
-  public int getProgress(InterpreterContext context) {
+  public int getProgress(InterpreterContext context) throws InterpreterException {
     if (iPythonInterpreter != null) {
       return iPythonInterpreter.getProgress(context);
     }

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/d762b528/python/src/test/java/org/apache/zeppelin/python/IPythonInterpreterTest.java
----------------------------------------------------------------------
diff --git a/python/src/test/java/org/apache/zeppelin/python/IPythonInterpreterTest.java b/python/src/test/java/org/apache/zeppelin/python/IPythonInterpreterTest.java
index d89ddac..cb854d6 100644
--- a/python/src/test/java/org/apache/zeppelin/python/IPythonInterpreterTest.java
+++ b/python/src/test/java/org/apache/zeppelin/python/IPythonInterpreterTest.java
@@ -66,7 +66,7 @@ public class IPythonInterpreterTest {
   }
 
   @After
-  public void close() {
+  public void close() throws InterpreterException {
     interpreter.close();
   }
 
@@ -81,6 +81,9 @@ public class IPythonInterpreterTest {
     InterpreterResult result = interpreter.interpret("from __future__ import print_function", getInterpreterContext());
     assertEquals(InterpreterResult.Code.SUCCESS, result.code());
 
+    result = interpreter.interpret("import sys\nprint(sys.version_info)", getInterpreterContext());
+    assertEquals(InterpreterResult.Code.SUCCESS, result.code());
+
     // single output without print
     InterpreterContext context = getInterpreterContext();
     result = interpreter.interpret("'hello world'", context);
@@ -195,6 +198,9 @@ public class IPythonInterpreterTest {
 
     context = getInterpreterContext();
     completions = interpreter.completion("sys.std", 7, context);
+    for (InterpreterCompletion completion : completions) {
+      System.out.println(completion.getValue());
+    }
     assertEquals(3, completions.size());
     assertEquals("stderr", completions.get(0).getValue());
     assertEquals("stdin", completions.get(1).getValue());
@@ -308,6 +314,7 @@ public class IPythonInterpreterTest {
     context = getInterpreterContext();
     result = interpreter.interpret("from bokeh.io import output_notebook, show\n" +
         "from bokeh.plotting import figure\n" +
+        "import bkzep\n" +
         "output_notebook(notebook_type='zeppelin')", context);
     Thread.sleep(100);
     assertEquals(InterpreterResult.Code.SUCCESS, result.code());
@@ -329,10 +336,11 @@ public class IPythonInterpreterTest {
     Thread.sleep(100);
     assertEquals(InterpreterResult.Code.SUCCESS, result.code());
     interpreterResultMessages = context.out.getInterpreterResultMessages();
-    assertEquals(1, interpreterResultMessages.size());
+    assertEquals(2, interpreterResultMessages.size());
     assertEquals(InterpreterResult.Type.HTML, interpreterResultMessages.get(0).getType());
+    assertEquals(InterpreterResult.Type.HTML, interpreterResultMessages.get(1).getType());
     // docs_json is the source data of plotting which bokeh would use to render the plotting.
-    assertTrue(interpreterResultMessages.get(0).getData().contains("docs_json"));
+    assertTrue(interpreterResultMessages.get(1).getData().contains("docs_json"));
 
     // ggplot
     context = getInterpreterContext();

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/d762b528/python/src/test/java/org/apache/zeppelin/python/PythonInterpreterMatplotlibTest.java
----------------------------------------------------------------------
diff --git a/python/src/test/java/org/apache/zeppelin/python/PythonInterpreterMatplotlibTest.java b/python/src/test/java/org/apache/zeppelin/python/PythonInterpreterMatplotlibTest.java
index 8c088dc..1ab9cf1 100644
--- a/python/src/test/java/org/apache/zeppelin/python/PythonInterpreterMatplotlibTest.java
+++ b/python/src/test/java/org/apache/zeppelin/python/PythonInterpreterMatplotlibTest.java
@@ -80,7 +80,7 @@ public class PythonInterpreterMatplotlibTest implements InterpreterOutputListene
   }
 
   @After
-  public void afterTest() throws IOException {
+  public void afterTest() throws IOException, InterpreterException {
     python.close();
   }
 

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/d762b528/python/src/test/java/org/apache/zeppelin/python/PythonInterpreterTest.java
----------------------------------------------------------------------
diff --git a/python/src/test/java/org/apache/zeppelin/python/PythonInterpreterTest.java b/python/src/test/java/org/apache/zeppelin/python/PythonInterpreterTest.java
index 4f08d50..1143b9e 100644
--- a/python/src/test/java/org/apache/zeppelin/python/PythonInterpreterTest.java
+++ b/python/src/test/java/org/apache/zeppelin/python/PythonInterpreterTest.java
@@ -93,7 +93,7 @@ public class PythonInterpreterTest implements InterpreterOutputListener {
   }
 
   @After
-  public void afterTest() throws IOException {
+  public void afterTest() throws IOException, InterpreterException {
     pythonInterpreter.close();
   }
 

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/d762b528/r/pom.xml
----------------------------------------------------------------------
diff --git a/r/pom.xml b/r/pom.xml
index 8c80b34..fef12e3 100644
--- a/r/pom.xml
+++ b/r/pom.xml
@@ -70,13 +70,6 @@
 
     <dependency>
       <groupId>${project.groupId}</groupId>
-      <artifactId>zeppelin-spark-dependencies_${scala.binary.version}</artifactId>
-      <version>${project.version}</version>
-      <scope>provided</scope>
-    </dependency>
-
-    <dependency>
-      <groupId>${project.groupId}</groupId>
       <artifactId>zeppelin-interpreter</artifactId>
       <version>${project.version}</version>
       <scope>provided</scope>

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/d762b528/spark-dependencies/pom.xml
----------------------------------------------------------------------
diff --git a/spark-dependencies/pom.xml b/spark-dependencies/pom.xml
deleted file mode 100644
index 15138cd..0000000
--- a/spark-dependencies/pom.xml
+++ /dev/null
@@ -1,1042 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-  ~ Licensed to the Apache Software Foundation (ASF) under one or more
-  ~ contributor license agreements.  See the NOTICE file distributed with
-  ~ this work for additional information regarding copyright ownership.
-  ~ The ASF licenses this file to You under the Apache License, Version 2.0
-  ~ (the "License"); you may not use this file except in compliance with
-  ~ the License.  You may obtain a copy of the License at
-  ~
-  ~    http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-  -->
-
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
-  <modelVersion>4.0.0</modelVersion>
-
-  <parent>
-    <artifactId>zeppelin</artifactId>
-    <groupId>org.apache.zeppelin</groupId>
-    <version>0.9.0-SNAPSHOT</version>
-    <relativePath>..</relativePath>
-  </parent>
-
-  <groupId>org.apache.zeppelin</groupId>
-  <artifactId>zeppelin-spark-dependencies_2.10</artifactId>
-  <packaging>jar</packaging>
-  <version>0.9.0-SNAPSHOT</version>
-  <name>Zeppelin: Spark dependencies</name>
-  <description>Zeppelin spark support</description>
-
-  <properties>
-    <!-- library version defined in this section brought from spark 1.4.1 and it's dependency.
-         Therefore changing only spark.version is not going to be enough when this module
-         support new version of spark to make the new version as default supported version.
-
-         Each profile (spark-2.0, spark-1.6, etc) will overrides necessary dependency version.
-         So we'll make one of those profile 'activateByDefault' to make it default supported version
-         instead of changing spark.version in this section.
-    -->
-
-    <spark.version>1.4.1</spark.version>
-    <hadoop.version>2.3.0</hadoop.version>
-    <yarn.version>${hadoop.version}</yarn.version>
-    <avro.version>1.7.7</avro.version>
-    <avro.mapred.classifier/>
-    <jets3t.version>0.7.1</jets3t.version>
-    <protobuf.version>2.4.1</protobuf.version>
-
-    <akka.group>org.spark-project.akka</akka.group>
-    <akka.version>2.3.4-spark</akka.version>
-
-    <spark.archive>spark-${spark.version}</spark.archive>
-    <spark.src.download.url>
-      http://d3kbcqa49mib13.cloudfront.net/${spark.archive}.tgz
-    </spark.src.download.url>
-    <spark.bin.download.url>
-      http://d3kbcqa49mib13.cloudfront.net/${spark.archive}-bin-without-hadoop.tgz
-    </spark.bin.download.url>
-    <spark.py4j.version>0.8.2.1</spark.py4j.version>
-
-    <!--plugin versions-->
-    <plugin.shade.version>2.3</plugin.shade.version>
-  </properties>
-
-  <dependencyManagement>
-    <dependencies>
-      <dependency>
-        <groupId>org.apache.avro</groupId>
-        <artifactId>avro</artifactId>
-        <version>${avro.version}</version>
-      </dependency>
-      <dependency>
-        <groupId>org.apache.avro</groupId>
-        <artifactId>avro-ipc</artifactId>
-        <version>${avro.version}</version>
-        <exclusions>
-          <exclusion>
-            <groupId>io.netty</groupId>
-            <artifactId>netty</artifactId>
-          </exclusion>
-          <exclusion>
-            <groupId>org.mortbay.jetty</groupId>
-            <artifactId>jetty</artifactId>
-          </exclusion>
-          <exclusion>
-            <groupId>org.mortbay.jetty</groupId>
-            <artifactId>jetty-util</artifactId>
-          </exclusion>
-          <exclusion>
-            <groupId>org.mortbay.jetty</groupId>
-            <artifactId>servlet-api</artifactId>
-          </exclusion>
-          <exclusion>
-            <groupId>org.apache.velocity</groupId>
-            <artifactId>velocity</artifactId>
-          </exclusion>
-        </exclusions>
-      </dependency>
-      <dependency>
-        <groupId>org.apache.avro</groupId>
-        <artifactId>avro-mapred</artifactId>
-        <version>${avro.version}</version>
-        <classifier>${avro.mapred.classifier}</classifier>
-        <exclusions>
-          <exclusion>
-            <groupId>io.netty</groupId>
-            <artifactId>netty</artifactId>
-          </exclusion>
-          <exclusion>
-            <groupId>org.mortbay.jetty</groupId>
-            <artifactId>jetty</artifactId>
-          </exclusion>
-          <exclusion>
-            <groupId>org.mortbay.jetty</groupId>
-            <artifactId>jetty-util</artifactId>
-          </exclusion>
-          <exclusion>
-            <groupId>org.mortbay.jetty</groupId>
-            <artifactId>servlet-api</artifactId>
-          </exclusion>
-          <exclusion>
-            <groupId>org.apache.velocity</groupId>
-            <artifactId>velocity</artifactId>
-          </exclusion>
-        </exclusions>
-      </dependency>
-
-      <!-- See SPARK-1556 for info on this dependency: -->
-      <dependency>
-        <groupId>net.java.dev.jets3t</groupId>
-        <artifactId>jets3t</artifactId>
-        <version>${jets3t.version}</version>
-        <scope>runtime</scope>
-        <exclusions>
-          <exclusion>
-            <groupId>commons-logging</groupId>
-            <artifactId>commons-logging</artifactId>
-          </exclusion>
-        </exclusions>
-      </dependency>
-      <dependency>
-        <groupId>org.apache.hadoop</groupId>
-        <artifactId>hadoop-yarn-api</artifactId>
-        <version>${yarn.version}</version>
-        <exclusions>
-          <exclusion>
-            <groupId>asm</groupId>
-            <artifactId>asm</artifactId>
-          </exclusion>
-          <exclusion>
-            <groupId>org.ow2.asm</groupId>
-            <artifactId>asm</artifactId>
-          </exclusion>
-          <exclusion>
-            <groupId>org.jboss.netty</groupId>
-            <artifactId>netty</artifactId>
-          </exclusion>
-          <exclusion>
-            <groupId>commons-logging</groupId>
-            <artifactId>commons-logging</artifactId>
-          </exclusion>
-        </exclusions>
-      </dependency>
-
-      <dependency>
-        <groupId>org.apache.hadoop</groupId>
-        <artifactId>hadoop-yarn-common</artifactId>
-        <version>${yarn.version}</version>
-        <exclusions>
-          <exclusion>
-            <groupId>asm</groupId>
-            <artifactId>asm</artifactId>
-          </exclusion>
-          <exclusion>
-            <groupId>org.ow2.asm</groupId>
-            <artifactId>asm</artifactId>
-          </exclusion>
-          <exclusion>
-            <groupId>org.jboss.netty</groupId>
-            <artifactId>netty</artifactId>
-          </exclusion>
-          <exclusion>
-            <groupId>javax.servlet</groupId>
-            <artifactId>servlet-api</artifactId>
-          </exclusion>
-          <exclusion>
-            <groupId>commons-logging</groupId>
-            <artifactId>commons-logging</artifactId>
-          </exclusion>
-        </exclusions>
-      </dependency>
-
-      <dependency>
-        <groupId>org.apache.hadoop</groupId>
-        <artifactId>hadoop-yarn-server-web-proxy</artifactId>
-        <version>${yarn.version}</version>
-        <exclusions>
-          <exclusion>
-            <groupId>asm</groupId>
-            <artifactId>asm</artifactId>
-          </exclusion>
-          <exclusion>
-            <groupId>org.ow2.asm</groupId>
-            <artifactId>asm</artifactId>
-          </exclusion>
-          <exclusion>
-            <groupId>org.jboss.netty</groupId>
-            <artifactId>netty</artifactId>
-          </exclusion>
-          <exclusion>
-            <groupId>javax.servlet</groupId>
-            <artifactId>servlet-api</artifactId>
-          </exclusion>
-          <exclusion>
-            <groupId>commons-logging</groupId>
-            <artifactId>commons-logging</artifactId>
-          </exclusion>
-        </exclusions>
-      </dependency>
-
-      <dependency>
-        <groupId>org.apache.hadoop</groupId>
-        <artifactId>hadoop-yarn-client</artifactId>
-        <version>${yarn.version}</version>
-        <exclusions>
-          <exclusion>
-            <groupId>asm</groupId>
-            <artifactId>asm</artifactId>
-          </exclusion>
-          <exclusion>
-            <groupId>org.ow2.asm</groupId>
-            <artifactId>asm</artifactId>
-          </exclusion>
-          <exclusion>
-            <groupId>org.jboss.netty</groupId>
-            <artifactId>netty</artifactId>
-          </exclusion>
-          <exclusion>
-            <groupId>javax.servlet</groupId>
-            <artifactId>servlet-api</artifactId>
-          </exclusion>
-          <exclusion>
-            <groupId>commons-logging</groupId>
-            <artifactId>commons-logging</artifactId>
-          </exclusion>
-        </exclusions>
-      </dependency>
-    </dependencies>
-  </dependencyManagement>
-
-  <dependencies>
-    <!-- Spark -->
-    <dependency>
-      <groupId>org.apache.spark</groupId>
-      <artifactId>spark-core_${scala.binary.version}</artifactId>
-      <version>${spark.version}</version>
-      <exclusions>
-        <exclusion>
-          <groupId>org.apache.hadoop</groupId>
-          <artifactId>hadoop-client</artifactId>
-        </exclusion>
-      </exclusions>
-    </dependency>
-
-    <dependency>
-      <groupId>org.apache.spark</groupId>
-      <artifactId>spark-repl_${scala.binary.version}</artifactId>
-      <version>${spark.version}</version>
-    </dependency>
-
-    <dependency>
-      <groupId>org.apache.spark</groupId>
-      <artifactId>spark-sql_${scala.binary.version}</artifactId>
-      <version>${spark.version}</version>
-    </dependency>
-
-    <dependency>
-      <groupId>org.apache.spark</groupId>
-      <artifactId>spark-hive_${scala.binary.version}</artifactId>
-      <version>${spark.version}</version>
-    </dependency>
-
-    <dependency>
-      <groupId>org.apache.spark</groupId>
-      <artifactId>spark-streaming_${scala.binary.version}</artifactId>
-      <version>${spark.version}</version>
-    </dependency>
-
-    <dependency>
-      <groupId>org.apache.spark</groupId>
-      <artifactId>spark-catalyst_${scala.binary.version}</artifactId>
-      <version>${spark.version}</version>
-    </dependency>
-
-    <!-- hadoop -->
-    <dependency>
-      <groupId>org.apache.hadoop</groupId>
-      <artifactId>hadoop-client</artifactId>
-      <version>${hadoop.version}</version>
-    </dependency>
-
-
-    <dependency>
-      <groupId>com.google.protobuf</groupId>
-      <artifactId>protobuf-java</artifactId>
-      <version>${protobuf.version}</version>
-    </dependency>
-
-    <dependency>
-      <groupId>${akka.group}</groupId>
-      <artifactId>akka-actor_${scala.binary.version}</artifactId>
-      <version>${akka.version}</version>
-    </dependency>
-    <dependency>
-      <groupId>${akka.group}</groupId>
-      <artifactId>akka-remote_${scala.binary.version}</artifactId>
-      <version>${akka.version}</version>
-    </dependency>
-    <dependency>
-      <groupId>${akka.group}</groupId>
-      <artifactId>akka-slf4j_${scala.binary.version}</artifactId>
-      <version>${akka.version}</version>
-    </dependency>
-    <dependency>
-      <groupId>${akka.group}</groupId>
-      <artifactId>akka-testkit_${scala.binary.version}</artifactId>
-      <version>${akka.version}</version>
-    </dependency>
-    <dependency>
-      <groupId>${akka.group}</groupId>
-      <artifactId>akka-zeromq_${scala.binary.version}</artifactId>
-      <version>${akka.version}</version>
-      <exclusions>
-        <exclusion>
-          <groupId>${akka.group}</groupId>
-          <artifactId>akka-actor_${scala.binary.version}</artifactId>
-        </exclusion>
-      </exclusions>
-    </dependency>
-
-    <!-- yarn (not supported for Spark v1.5.0 or higher) -->
-    <dependency>
-      <groupId>org.apache.spark</groupId>
-      <artifactId>spark-yarn_${scala.binary.version}</artifactId>
-      <version>${spark.version}</version>
-    </dependency>
-
-    <dependency>
-      <groupId>org.apache.hadoop</groupId>
-      <artifactId>hadoop-yarn-api</artifactId>
-      <version>${yarn.version}</version>
-    </dependency>
-
-  </dependencies>
-
-  <profiles>
-    <profile>
-      <id>spark-1.1</id>
-      <dependencies>
-
-      </dependencies>
-      <properties>
-        <spark.version>1.1.1</spark.version>
-        <akka.version>2.2.3-shaded-protobuf</akka.version>
-      </properties>
-    </profile>
-
-    <profile>
-      <id>cassandra-spark-1.1</id>
-      <dependencies>
-        <dependency>
-          <groupId>com.datastax.spark</groupId>
-          <artifactId>spark-cassandra-connector_${scala.binary.version}</artifactId>
-          <version>1.1.1</version>
-          <exclusions>
-            <exclusion>
-              <groupId>org.joda</groupId>
-              <artifactId>joda-convert</artifactId>
-            </exclusion>
-          </exclusions>
-        </dependency>
-      </dependencies>
-      <properties>
-        <spark.version>1.1.1</spark.version>
-        <akka.version>2.2.3-shaded-protobuf</akka.version>
-      </properties>
-    </profile>
-
-    <profile>
-      <id>spark-1.2</id>
-      <dependencies>
-      </dependencies>
-      <properties>
-        <spark.version>1.2.1</spark.version>
-      </properties>
-    </profile>
-
-    <profile>
-      <id>cassandra-spark-1.2</id>
-      <properties>
-        <spark.version>1.2.1</spark.version>
-      </properties>
-      <dependencies>
-        <dependency>
-          <groupId>com.datastax.spark</groupId>
-          <artifactId>spark-cassandra-connector_${scala.binary.version}</artifactId>
-          <version>1.2.1</version>
-          <exclusions>
-            <exclusion>
-              <groupId>org.joda</groupId>
-              <artifactId>joda-convert</artifactId>
-            </exclusion>
-          </exclusions>
-        </dependency>
-      </dependencies>
-    </profile>
-
-    <profile>
-      <id>spark-1.3</id>
-
-      <properties>
-        <spark.version>1.3.1</spark.version>
-      </properties>
-
-      <dependencies>
-      </dependencies>
-
-    </profile>
-
-    <profile>
-      <id>cassandra-spark-1.3</id>
-      <properties>
-        <spark.version>1.3.0</spark.version>
-      </properties>
-
-      <dependencies>
-        <dependency>
-          <groupId>com.datastax.spark</groupId>
-          <artifactId>spark-cassandra-connector_${scala.binary.version}</artifactId>
-          <version>1.3.1</version>
-          <exclusions>
-            <exclusion>
-              <groupId>org.joda</groupId>
-              <artifactId>joda-convert</artifactId>
-            </exclusion>
-          </exclusions>
-        </dependency>
-      </dependencies>
-    </profile>
-
-    <profile>
-      <id>spark-1.4</id>
-      <properties>
-        <spark.version>1.4.1</spark.version>
-      </properties>
-
-      <dependencies>
-      </dependencies>
-    </profile>
-
-    <profile>
-      <id>cassandra-spark-1.4</id>
-      <properties>
-        <spark.version>1.4.1</spark.version>
-      </properties>
-
-      <dependencies>
-        <dependency>
-          <groupId>com.datastax.spark</groupId>
-          <artifactId>spark-cassandra-connector_${scala.binary.version}</artifactId>
-          <version>1.4.0</version>
-          <exclusions>
-            <exclusion>
-              <groupId>org.joda</groupId>
-              <artifactId>joda-convert</artifactId>
-            </exclusion>
-          </exclusions>
-        </dependency>
-      </dependencies>
-    </profile>
-
-    <profile>
-      <id>spark-1.5</id>
-      <properties>
-        <spark.version>1.5.2</spark.version>
-        <akka.group>com.typesafe.akka</akka.group>
-        <akka.version>2.3.11</akka.version>
-        <protobuf.version>2.5.0</protobuf.version>
-      </properties>
-
-      <dependencies>
-      </dependencies>
-    </profile>
-
-    <profile>
-      <id>cassandra-spark-1.5</id>
-      <properties>
-        <spark.version>1.5.1</spark.version>
-        <akka.group>com.typesafe.akka</akka.group>
-        <akka.version>2.3.11</akka.version>
-        <protobuf.version>2.5.0</protobuf.version>
-        <guava.version>16.0.1</guava.version>
-      </properties>
-
-      <dependencies>
-        <dependency>
-          <groupId>com.datastax.spark</groupId>
-          <artifactId>spark-cassandra-connector_${scala.binary.version}</artifactId>
-          <version>1.5.0</version>
-          <exclusions>
-            <exclusion>
-              <groupId>org.joda</groupId>
-              <artifactId>joda-convert</artifactId>
-            </exclusion>
-          </exclusions>
-        </dependency>
-      </dependencies>
-    </profile>
-
-    <profile>
-      <id>spark-1.6</id>
-      <properties>
-        <spark.version>1.6.3</spark.version>
-        <spark.py4j.version>0.9</spark.py4j.version>
-        <akka.group>com.typesafe.akka</akka.group>
-        <akka.version>2.3.11</akka.version>
-        <protobuf.version>2.5.0</protobuf.version>
-      </properties>
-    </profile>
-
-    <profile>
-      <id>spark-2.0</id>
-      <properties>
-        <spark.version>2.0.2</spark.version>
-        <protobuf.version>2.5.0</protobuf.version>
-        <spark.py4j.version>0.10.3</spark.py4j.version>
-      </properties>
-    </profile>
-
-    <profile>
-      <id>spark-2.1</id>
-      <properties>
-        <spark.version>2.1.0</spark.version>
-        <protobuf.version>2.5.0</protobuf.version>
-        <spark.py4j.version>0.10.4</spark.py4j.version>
-        <scala.version>2.11.8</scala.version>
-      </properties>
-    </profile>
-
-    <profile>
-      <id>spark-2.2</id>
-      <activation>
-        <activeByDefault>true</activeByDefault>
-      </activation>
-      <properties>
-        <spark.version>2.2.0</spark.version>
-        <protobuf.version>2.5.0</protobuf.version>
-        <spark.py4j.version>0.10.4</spark.py4j.version>
-      </properties>
-    </profile>
-
-    <profile>
-      <id>hadoop-0.23</id>
-      <!-- SPARK-1121: Adds an explicit dependency on Avro to work around a
-        Hadoop 0.23.X issue -->
-      <dependencies>
-        <dependency>
-          <groupId>org.apache.avro</groupId>
-          <artifactId>avro</artifactId>
-        </dependency>
-      </dependencies>
-      <properties>
-        <hadoop.version>0.23.10</hadoop.version>
-      </properties>
-    </profile>
-
-    <profile>
-      <id>hadoop-1</id>
-      <properties>
-        <hadoop.version>1.0.4</hadoop.version>
-        <avro.mapred.classifier>hadoop1</avro.mapred.classifier>
-        <codehaus.jackson.version>1.8.8</codehaus.jackson.version>
-        <akka.group>org.spark-project.akka</akka.group>
-      </properties>
-    </profile>
-
-    <profile>
-      <id>hadoop-2.2</id>
-      <properties>
-        <hadoop.version>2.2.0</hadoop.version>
-        <protobuf.version>2.5.0</protobuf.version>
-        <avro.mapred.classifier>hadoop2</avro.mapred.classifier>
-      </properties>
-    </profile>
-
-    <profile>
-      <id>hadoop-2.3</id>
-      <properties>
-        <hadoop.version>2.3.0</hadoop.version>
-        <protobuf.version>2.5.0</protobuf.version>
-        <jets3t.version>0.9.3</jets3t.version>
-        <avro.mapred.classifier>hadoop2</avro.mapred.classifier>
-      </properties>
-    </profile>
-
-    <profile>
-      <id>hadoop-2.4</id>
-      <properties>
-        <hadoop.version>2.4.0</hadoop.version>
-        <protobuf.version>2.5.0</protobuf.version>
-        <jets3t.version>0.9.3</jets3t.version>
-        <avro.mapred.classifier>hadoop2</avro.mapred.classifier>
-      </properties>
-    </profile>
-
-    <profile>
-      <id>hadoop-2.6</id>
-      <properties>
-        <hadoop.version>2.6.0</hadoop.version>
-        <protobuf.version>2.5.0</protobuf.version>
-        <jets3t.version>0.9.3</jets3t.version>
-        <avro.mapred.classifier>hadoop2</avro.mapred.classifier>
-      </properties>
-    </profile>
-
-    <profile>
-      <id>hadoop-2.7</id>
-      <properties>
-        <hadoop.version>2.7.2</hadoop.version>
-        <protobuf.version>2.5.0</protobuf.version>
-        <jets3t.version>0.9.0</jets3t.version>
-        <avro.mapred.classifier>hadoop2</avro.mapred.classifier>
-      </properties>
-    </profile>
-
-    <profile>
-      <id>mapr3</id>
-      <activation>
-        <activeByDefault>false</activeByDefault>
-      </activation>
-      <properties>
-        <hadoop.version>1.0.3-mapr-3.0.3</hadoop.version>
-        <yarn.version>2.3.0-mapr-4.0.0-FCS</yarn.version>
-        <jets3t.version>0.7.1</jets3t.version>
-      </properties>
-      <repositories>
-        <repository>
-          <id>mapr-releases</id>
-          <url>http://repository.mapr.com/maven/</url>
-          <snapshots>
-            <enabled>false</enabled>
-          </snapshots>
-          <releases>
-            <enabled>true</enabled>
-          </releases>
-        </repository>
-      </repositories>
-    </profile>
-
-    <profile>
-      <id>mapr40</id>
-      <activation>
-        <activeByDefault>false</activeByDefault>
-      </activation>
-      <properties>
-        <hadoop.version>2.4.1-mapr-1503</hadoop.version>
-        <yarn.version>2.4.1-mapr-1503</yarn.version>
-        <jets3t.version>0.9.3</jets3t.version>
-      </properties>
-      <dependencies>
-        <dependency>
-          <groupId>org.apache.curator</groupId>
-          <artifactId>curator-recipes</artifactId>
-          <version>2.4.0</version>
-          <exclusions>
-            <exclusion>
-              <groupId>org.apache.zookeeper</groupId>
-              <artifactId>zookeeper</artifactId>
-            </exclusion>
-          </exclusions>
-        </dependency>
-        <dependency>
-          <groupId>org.apache.zookeeper</groupId>
-          <artifactId>zookeeper</artifactId>
-          <version>3.4.5-mapr-1503</version>
-        </dependency>
-      </dependencies>
-      <repositories>
-        <repository>
-          <id>mapr-releases</id>
-          <url>http://repository.mapr.com/maven/</url>
-          <snapshots>
-            <enabled>false</enabled>
-          </snapshots>
-          <releases>
-            <enabled>true</enabled>
-          </releases>
-        </repository>
-      </repositories>
-    </profile>
-
-    <profile>
-      <id>mapr41</id>
-      <activation>
-        <activeByDefault>false</activeByDefault>
-      </activation>
-      <properties>
-        <hadoop.version>2.5.1-mapr-1503</hadoop.version>
-        <yarn.version>2.5.1-mapr-1503</yarn.version>
-        <jets3t.version>0.7.1</jets3t.version>
-      </properties>
-      <dependencies>
-        <dependency>
-          <groupId>org.apache.curator</groupId>
-          <artifactId>curator-recipes</artifactId>
-          <version>2.4.0</version>
-          <exclusions>
-            <exclusion>
-              <groupId>org.apache.zookeeper</groupId>
-              <artifactId>zookeeper</artifactId>
-            </exclusion>
-          </exclusions>
-        </dependency>
-        <dependency>
-          <groupId>org.apache.zookeeper</groupId>
-          <artifactId>zookeeper</artifactId>
-          <version>3.4.5-mapr-1503</version>
-        </dependency>
-      </dependencies>
-      <repositories>
-        <repository>
-          <id>mapr-releases</id>
-          <url>http://repository.mapr.com/maven/</url>
-          <snapshots>
-            <enabled>false</enabled>
-          </snapshots>
-          <releases>
-            <enabled>true</enabled>
-          </releases>
-        </repository>
-      </repositories>
-    </profile>
-
-    <profile>
-      <id>mapr50</id>
-      <activation>
-        <activeByDefault>false</activeByDefault>
-      </activation>
-      <properties>
-        <hadoop.version>2.7.0-mapr-1506</hadoop.version>
-        <yarn.version>2.7.0-mapr-1506</yarn.version>
-        <jets3t.version>0.9.3</jets3t.version>
-      </properties>
-      <dependencies>
-        <dependency>
-          <groupId>org.apache.curator</groupId>
-          <artifactId>curator-recipes</artifactId>
-          <version>2.4.0</version>
-          <exclusions>
-            <exclusion>
-              <groupId>org.apache.zookeeper</groupId>
-              <artifactId>zookeeper</artifactId>
-            </exclusion>
-          </exclusions>
-        </dependency>
-        <dependency>
-          <groupId>org.apache.zookeeper</groupId>
-          <artifactId>zookeeper</artifactId>
-          <version>3.4.5-mapr-1503</version>
-        </dependency>
-      </dependencies>
-      <repositories>
-        <repository>
-          <id>mapr-releases</id>
-          <url>http://repository.mapr.com/maven/</url>
-          <snapshots>
-            <enabled>false</enabled>
-          </snapshots>
-          <releases>
-            <enabled>true</enabled>
-          </releases>
-        </repository>
-      </repositories>
-    </profile>
-
-    <profile>
-      <id>mapr51</id>
-      <activation>
-        <activeByDefault>false</activeByDefault>
-      </activation>
-      <properties>
-        <hadoop.version>2.7.0-mapr-1602</hadoop.version>
-        <yarn.version>2.7.0-mapr-1602</yarn.version>
-        <jets3t.version>0.9.3</jets3t.version>
-      </properties>
-      <dependencies>
-        <dependency>
-          <groupId>org.apache.curator</groupId>
-          <artifactId>curator-recipes</artifactId>
-          <version>2.4.0</version>
-          <exclusions>
-            <exclusion>
-              <groupId>org.apache.zookeeper</groupId>
-              <artifactId>zookeeper</artifactId>
-            </exclusion>
-          </exclusions>
-        </dependency>
-        <dependency>
-          <groupId>org.apache.zookeeper</groupId>
-          <artifactId>zookeeper</artifactId>
-          <version>3.4.5-mapr-1503</version>
-        </dependency>
-      </dependencies>
-      <repositories>
-        <repository>
-          <id>mapr-releases</id>
-          <url>http://repository.mapr.com/maven/</url>
-          <snapshots>
-            <enabled>false</enabled>
-          </snapshots>
-          <releases>
-            <enabled>true</enabled>
-          </releases>
-        </repository>
-      </repositories>
-    </profile>
-
-  </profiles>
-
-  <build>
-    <plugins>
-      <plugin>
-        <artifactId>maven-enforcer-plugin</artifactId>
-        <executions>
-          <execution>
-            <id>enforce</id>
-            <phase>none</phase>
-          </execution>
-        </executions>
-      </plugin>
-
-      <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-surefire-plugin</artifactId>
-        <configuration>
-          <forkCount>1</forkCount>
-          <reuseForks>false</reuseForks>
-          <argLine>-Xmx1024m -XX:MaxPermSize=256m</argLine>
-        </configuration>
-      </plugin>
-
-      <plugin>
-        <groupId>com.googlecode.maven-download-plugin</groupId>
-        <artifactId>download-maven-plugin</artifactId>
-        <version>${plugin.download.version}</version>
-      </plugin>
-
-      <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-shade-plugin</artifactId>
-        <version>${plugin.shade.version}</version>
-        <configuration>
-          <filters>
-            <filter>
-              <artifact>*:*</artifact>
-              <excludes>
-                <exclude>org/datanucleus/**</exclude>
-                <exclude>META-INF/*.SF</exclude>
-                <exclude>META-INF/*.DSA</exclude>
-                <exclude>META-INF/*.RSA</exclude>
-              </excludes>
-            </filter>
-          </filters>
-          <transformers>
-            <transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
-            <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
-              <resource>reference.conf</resource>
-            </transformer>
-          </transformers>
-        </configuration>
-        <executions>
-          <execution>
-            <phase>package</phase>
-            <goals>
-              <goal>shade</goal>
-            </goals>
-          </execution>
-        </executions>
-      </plugin>
-
-      <!-- Deploy datanucleus jars to the interpreter/spark directory -->
-      <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-dependency-plugin</artifactId>
-        <executions>
-          <execution>
-            <id>copy-dependencies</id>
-            <phase>package</phase>
-            <goals>
-              <goal>copy-dependencies</goal>
-            </goals>
-            <configuration>
-              <outputDirectory>${project.build.directory}/../../interpreter/spark/dep</outputDirectory>
-              <overWriteReleases>false</overWriteReleases>
-              <overWriteSnapshots>false</overWriteSnapshots>
-              <overWriteIfNewer>true</overWriteIfNewer>
-              <includeGroupIds>org.datanucleus</includeGroupIds>
-            </configuration>
-          </execution>
-          <execution>
-            <phase>package</phase>
-            <goals>
-              <goal>copy</goal>
-            </goals>
-            <configuration>
-              <outputDirectory>${project.build.directory}/../../interpreter/spark/dep</outputDirectory>
-              <overWriteReleases>false</overWriteReleases>
-              <overWriteSnapshots>false</overWriteSnapshots>
-              <overWriteIfNewer>true</overWriteIfNewer>
-              <artifactItems>
-                <artifactItem>
-                  <groupId>${project.groupId}</groupId>
-                  <artifactId>${project.artifactId}</artifactId>
-                  <version>${project.version}</version>
-                  <type>${project.packaging}</type>
-                </artifactItem>
-              </artifactItems>
-            </configuration>
-          </execution>
-        </executions>
-      </plugin>
-
-      <!-- include pyspark by default -->
-      <plugin>
-        <groupId>com.googlecode.maven-download-plugin</groupId>
-        <artifactId>download-maven-plugin</artifactId>
-        <executions>
-          <execution>
-            <id>download-pyspark-files</id>
-            <phase>validate</phase>
-            <goals>
-              <goal>wget</goal>
-            </goals>
-            <configuration>
-              <readTimeOut>60000</readTimeOut>
-              <retries>5</retries>
-              <unpack>true</unpack>
-              <url>${spark.src.download.url}</url>
-              <outputDirectory>${project.build.directory}</outputDirectory>
-            </configuration>
-          </execution>
-        </executions>
-      </plugin>
-
-      <plugin>
-        <artifactId>maven-clean-plugin</artifactId>
-        <configuration>
-          <filesets>
-            <fileset>
-              <directory>${basedir}/../python/build</directory>
-            </fileset>
-          </filesets>
-        </configuration>
-      </plugin>
-
-      <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-antrun-plugin</artifactId>
-        <executions>
-          <execution>
-            <id>zip-pyspark-files</id>
-            <phase>generate-resources</phase>
-            <goals>
-              <goal>run</goal>
-            </goals>
-            <configuration>
-              <target>
-                <delete dir="../interpreter/spark/pyspark"/>
-                <copy todir="../interpreter/spark/pyspark"
-                      file="${project.build.directory}/${spark.archive}/python/lib/py4j-${spark.py4j.version}-src.zip"/>
-                <zip destfile="${project.build.directory}/../../interpreter/spark/pyspark/pyspark.zip"
-                     basedir="${project.build.directory}/${spark.archive}/python"
-                     includes="pyspark/*.py,pyspark/**/*.py"/>
-              </target>
-            </configuration>
-          </execution>
-        </executions>
-      </plugin>
-
-      <!-- include sparkr by default -->
-      <plugin>
-        <groupId>com.googlecode.maven-download-plugin</groupId>
-        <artifactId>download-maven-plugin</artifactId>
-        <executions>
-          <execution>
-            <id>download-sparkr-files</id>
-            <phase>validate</phase>
-            <goals>
-              <goal>wget</goal>
-            </goals>
-            <configuration>
-              <readTimeOut>60000</readTimeOut>
-              <retries>5</retries>
-              <url>${spark.bin.download.url}</url>
-              <unpack>true</unpack>
-              <outputDirectory>${project.build.directory}</outputDirectory>
-            </configuration>
-          </execution>
-        </executions>
-      </plugin>
-      <plugin>
-        <artifactId>maven-resources-plugin</artifactId>
-        <version>2.7</version>
-        <executions>
-          <execution>
-            <id>copy-sparkr-files</id>
-            <phase>generate-resources</phase>
-            <goals>
-              <goal>copy-resources</goal>
-            </goals>
-            <configuration>
-              <outputDirectory>${project.build.directory}/../../interpreter/spark/R/lib</outputDirectory>
-              <resources>
-                <resource>
-                  <directory>
-                    ${project.build.directory}/spark-${spark.version}-bin-without-hadoop/R/lib
-                  </directory>
-                </resource>
-              </resources>
-            </configuration>
-          </execution>
-        </executions>
-      </plugin>
-    </plugins>
-  </build>
-</project>

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/d762b528/spark/interpreter/figure/null-1.png
----------------------------------------------------------------------
diff --git a/spark/interpreter/figure/null-1.png b/spark/interpreter/figure/null-1.png
new file mode 100644
index 0000000..8b1ce07
Binary files /dev/null and b/spark/interpreter/figure/null-1.png differ

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/d762b528/spark/interpreter/pom.xml
----------------------------------------------------------------------
diff --git a/spark/interpreter/pom.xml b/spark/interpreter/pom.xml
new file mode 100644
index 0000000..4496462
--- /dev/null
+++ b/spark/interpreter/pom.xml
@@ -0,0 +1,573 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one or more
+  ~ contributor license agreements.  See the NOTICE file distributed with
+  ~ this work for additional information regarding copyright ownership.
+  ~ The ASF licenses this file to You under the Apache License, Version 2.0
+  ~ (the "License"); you may not use this file except in compliance with
+  ~ the License.  You may obtain a copy of the License at
+  ~
+  ~    http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <artifactId>spark-parent</artifactId>
+    <groupId>org.apache.zeppelin</groupId>
+    <version>0.9.0-SNAPSHOT</version>
+    <relativePath>../pom.xml</relativePath>
+  </parent>
+
+  <groupId>org.apache.zeppelin</groupId>
+  <artifactId>spark-interpreter</artifactId>
+  <packaging>jar</packaging>
+  <version>0.9.0-SNAPSHOT</version>
+  <name>Zeppelin: Spark Interpreter</name>
+  <description>Zeppelin spark support</description>
+
+  <properties>
+    <interpreter.name>spark</interpreter.name>
+    <!--library versions-->
+    <jsoup.version>1.8.2</jsoup.version>
+    <commons.exec.version>1.3</commons.exec.version>
+    <commons.compress.version>1.9</commons.compress.version>
+    <maven.plugin.api.version>3.0</maven.plugin.api.version>
+    <aether.version>1.12</aether.version>
+    <maven.aeither.provider.version>3.0.3</maven.aeither.provider.version>
+    <wagon.version>1.0</wagon.version>
+
+    <datanucleus.rdbms.version>3.2.9</datanucleus.rdbms.version>
+    <datanucleus.apijdo.version>3.2.6</datanucleus.apijdo.version>
+    <datanucleus.core.version>3.2.10</datanucleus.core.version>
+
+    <scala.compile.version>${scala.version}</scala.compile.version>
+    <!-- settings -->
+    <pyspark.test.exclude>**/PySparkInterpreterMatplotlibTest.java</pyspark.test.exclude>
+    <pyspark.test.include>**/*Test.*</pyspark.test.include>
+
+
+    <spark.archive>spark-${spark.version}</spark.archive>
+    <spark.src.download.url>
+      http://d3kbcqa49mib13.cloudfront.net/${spark.archive}.tgz
+    </spark.src.download.url>
+    <spark.bin.download.url>
+      http://d3kbcqa49mib13.cloudfront.net/spark-${spark.version}-bin-without-hadoop.tgz
+    </spark.bin.download.url>
+
+  </properties>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.zeppelin</groupId>
+      <artifactId>zeppelin-display</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+
+    <dependency>
+      <groupId>org.apache.zeppelin</groupId>
+      <artifactId>spark-scala-2.11</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+
+    <dependency>
+      <groupId>org.apache.zeppelin</groupId>
+      <artifactId>spark-scala-2.10</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+
+    <dependency>
+      <groupId>org.apache.zeppelin</groupId>
+      <artifactId>zeppelin-interpreter</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+
+    <dependency>
+      <groupId>org.apache.zeppelin</groupId>
+      <artifactId>zeppelin-python</artifactId>
+      <version>${project.version}</version>
+      <exclusions>
+        <exclusion>
+          <groupId>net.sf.py4j</groupId>
+          <artifactId>py4j</artifactId>
+        </exclusion>
+      </exclusions>
+    </dependency>
+
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>zeppelin-python</artifactId>
+      <version>${project.version}</version>
+      <classifier>tests</classifier>
+      <scope>test</scope>
+      <exclusions>
+        <exclusion>
+          <groupId>net.sf.py4j</groupId>
+          <artifactId>py4j</artifactId>
+        </exclusion>
+      </exclusions>
+    </dependency>
+
+    <dependency>
+      <groupId>org.apache.spark</groupId>
+      <artifactId>spark-repl_${scala.binary.version}</artifactId>
+      <version>${spark.version}</version>
+      <scope>provided</scope>
+    </dependency>
+
+    <dependency>
+      <groupId>org.apache.spark</groupId>
+      <artifactId>spark-core_${scala.binary.version}</artifactId>
+      <version>${spark.version}</version>
+      <scope>provided</scope>
+    </dependency>
+
+    <dependency>
+      <groupId>org.apache.spark</groupId>
+      <artifactId>spark-hive_${scala.binary.version}</artifactId>
+      <version>${spark.version}</version>
+      <scope>provided</scope>
+      <exclusions>
+        <exclusion>
+          <groupId>com.fasterxml.jackson.core</groupId>
+          <artifactId>jackson-databind</artifactId>
+        </exclusion>
+        <exclusion>
+          <groupId>com.fasterxml.jackson.core</groupId>
+          <artifactId>jackson-annotations</artifactId>
+        </exclusion>
+      </exclusions>
+    </dependency>
+
+    <!-- Aether :: maven dependency resolution -->
+    <dependency>
+      <groupId>org.apache.maven</groupId>
+      <artifactId>maven-plugin-api</artifactId>
+      <version>${maven.plugin.api.version}</version>
+      <exclusions>
+        <exclusion>
+          <groupId>org.codehaus.plexus</groupId>
+          <artifactId>plexus-utils</artifactId>
+        </exclusion>
+        <exclusion>
+          <groupId>org.sonatype.sisu</groupId>
+          <artifactId>sisu-inject-plexus</artifactId>
+        </exclusion>
+        <exclusion>
+          <groupId>org.apache.maven</groupId>
+          <artifactId>maven-model</artifactId>
+        </exclusion>
+      </exclusions>
+    </dependency>
+
+    <dependency>
+      <groupId>org.sonatype.aether</groupId>
+      <artifactId>aether-api</artifactId>
+      <version>${aether.version}</version>
+    </dependency>
+
+    <dependency>
+      <groupId>org.sonatype.aether</groupId>
+      <artifactId>aether-util</artifactId>
+      <version>${aether.version}</version>
+    </dependency>
+
+    <dependency>
+      <groupId>org.sonatype.aether</groupId>
+      <artifactId>aether-impl</artifactId>
+      <version>${aether.version}</version>
+    </dependency>
+
+    <dependency>
+      <groupId>org.apache.maven</groupId>
+      <artifactId>maven-aether-provider</artifactId>
+      <version>${maven.aeither.provider.version}</version>
+      <exclusions>
+        <exclusion>
+          <groupId>org.sonatype.aether</groupId>
+          <artifactId>aether-api</artifactId>
+        </exclusion>
+        <exclusion>
+          <groupId>org.sonatype.aether</groupId>
+          <artifactId>aether-spi</artifactId>
+        </exclusion>
+        <exclusion>
+          <groupId>org.sonatype.aether</groupId>
+          <artifactId>aether-util</artifactId>
+        </exclusion>
+        <exclusion>
+          <groupId>org.sonatype.aether</groupId>
+          <artifactId>aether-impl</artifactId>
+        </exclusion>
+        <exclusion>
+          <groupId>org.codehaus.plexus</groupId>
+          <artifactId>plexus-utils</artifactId>
+        </exclusion>
+      </exclusions>
+    </dependency>
+
+    <dependency>
+      <groupId>org.sonatype.aether</groupId>
+      <artifactId>aether-connector-file</artifactId>
+      <version>${aether.version}</version>
+    </dependency>
+
+    <dependency>
+      <groupId>org.sonatype.aether</groupId>
+      <artifactId>aether-connector-wagon</artifactId>
+      <version>${aether.version}</version>
+      <exclusions>
+        <exclusion>
+          <groupId>org.apache.maven.wagon</groupId>
+          <artifactId>wagon-provider-api</artifactId>
+        </exclusion>
+      </exclusions>
+    </dependency>
+
+    <dependency>
+      <groupId>org.apache.maven.wagon</groupId>
+      <artifactId>wagon-provider-api</artifactId>
+      <version>${wagon.version}</version>
+      <exclusions>
+        <exclusion>
+          <groupId>org.codehaus.plexus</groupId>
+          <artifactId>plexus-utils</artifactId>
+        </exclusion>
+      </exclusions>
+    </dependency>
+
+    <dependency>
+      <groupId>org.apache.maven.wagon</groupId>
+      <artifactId>wagon-http-lightweight</artifactId>
+      <version>${wagon.version}</version>
+      <exclusions>
+        <exclusion>
+          <groupId>org.apache.maven.wagon</groupId>
+          <artifactId>wagon-http-shared</artifactId>
+        </exclusion>
+      </exclusions>
+    </dependency>
+
+    <dependency>
+      <groupId>org.apache.maven.wagon</groupId>
+      <artifactId>wagon-http</artifactId>
+      <version>${wagon.version}</version>
+      <exclusions>
+      </exclusions>
+    </dependency>
+
+    <dependency>
+      <groupId>org.apache.commons</groupId>
+      <artifactId>commons-exec</artifactId>
+      <version>${commons.exec.version}</version>
+    </dependency>
+
+    <dependency>
+      <groupId>org.scala-lang</groupId>
+      <artifactId>scala-library</artifactId>
+      <version>${scala.version}</version>
+      <scope>provided</scope>
+    </dependency>
+
+    <dependency>
+      <groupId>org.scala-lang</groupId>
+      <artifactId>scala-compiler</artifactId>
+      <version>${scala.version}</version>
+      <scope>provided</scope>
+    </dependency>
+
+    <dependency>
+      <groupId>org.scala-lang</groupId>
+      <artifactId>scala-reflect</artifactId>
+      <version>${scala.version}</version>
+      <scope>provided</scope>
+    </dependency>
+
+    <dependency>
+      <groupId>commons-lang</groupId>
+      <artifactId>commons-lang</artifactId>
+      <scope>provided</scope>
+    </dependency>
+
+    <dependency>
+      <groupId>org.apache.commons</groupId>
+      <artifactId>commons-compress</artifactId>
+      <version>${commons.compress.version}</version>
+      <scope>provided</scope>
+    </dependency>
+
+    <dependency>
+      <groupId>org.jsoup</groupId>
+      <artifactId>jsoup</artifactId>
+      <version>${jsoup.version}</version>
+    </dependency>
+
+    <!--test libraries-->
+    <dependency>
+      <groupId>org.scalatest</groupId>
+      <artifactId>scalatest_${scala.binary.version}</artifactId>
+      <version>${scalatest.version}</version>
+      <scope>test</scope>
+    </dependency>
+
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <scope>test</scope>
+    </dependency>
+
+    <dependency>
+      <groupId>org.datanucleus</groupId>
+      <artifactId>datanucleus-core</artifactId>
+      <version>${datanucleus.core.version}</version>
+      <scope>test</scope>
+    </dependency>
+
+    <dependency>
+      <groupId>org.datanucleus</groupId>
+      <artifactId>datanucleus-api-jdo</artifactId>
+      <version>${datanucleus.apijdo.version}</version>
+      <scope>test</scope>
+    </dependency>
+
+    <dependency>
+      <groupId>org.datanucleus</groupId>
+      <artifactId>datanucleus-rdbms</artifactId>
+      <version>${datanucleus.rdbms.version}</version>
+      <scope>test</scope>
+    </dependency>
+
+    <dependency>
+      <groupId>org.mockito</groupId>
+      <artifactId>mockito-core</artifactId>
+      <scope>test</scope>
+    </dependency>
+
+    <dependency>
+      <groupId>org.powermock</groupId>
+      <artifactId>powermock-api-mockito</artifactId>
+      <scope>test</scope>
+    </dependency>
+
+    <dependency>
+      <groupId>org.powermock</groupId>
+      <artifactId>powermock-module-junit4</artifactId>
+      <scope>test</scope>
+    </dependency>
+
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <artifactId>maven-enforcer-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>enforce</id>
+            <phase>none</phase>
+          </execution>
+        </executions>
+
+        <configuration>
+          <rules>
+            <requireJavaVersion>
+              <version>1.7</version>
+            </requireJavaVersion>
+          </rules>
+        </configuration>
+      </plugin>
+
+      <plugin>
+        <groupId>com.googlecode.maven-download-plugin</groupId>
+        <artifactId>download-maven-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>download-pyspark-files</id>
+            <phase>validate</phase>
+            <goals>
+              <goal>wget</goal>
+            </goals>
+            <configuration>
+              <readTimeOut>60000</readTimeOut>
+              <retries>5</retries>
+              <unpack>true</unpack>
+              <url>${spark.src.download.url}</url>
+              <outputDirectory>${project.build.directory}</outputDirectory>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-antrun-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>zip-pyspark-files</id>
+            <phase>generate-resources</phase>
+            <goals>
+              <goal>run</goal>
+            </goals>
+            <configuration>
+              <target>
+                <delete dir="../../interpreter/spark/pyspark" />
+                <copy file="${project.build.directory}/${spark.archive}/python/lib/py4j-${py4j.version}-src.zip" todir="${project.build.directory}/../../../interpreter/spark/pyspark" />
+                <zip basedir="${project.build.directory}/${spark.archive}/python" destfile="${project.build.directory}/../../../interpreter/spark/pyspark/pyspark.zip" includes="pyspark/*.py,pyspark/**/*.py" />
+              </target>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+
+      <plugin>
+        <groupId>org.scalatest</groupId>
+        <artifactId>scalatest-maven-plugin</artifactId>
+      </plugin>
+
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-surefire-plugin</artifactId>
+        <configuration>
+          <forkCount>1</forkCount>
+          <reuseForks>false</reuseForks>
+          <argLine>-Xmx1024m -XX:MaxPermSize=256m</argLine>
+          <excludes>
+            <exclude>**/SparkRInterpreterTest.java</exclude>
+            <exclude>${pyspark.test.exclude}</exclude>
+            <exclude>${tests.to.exclude}</exclude>
+          </excludes>
+          <environmentVariables>
+            <PYTHONPATH>${project.build.directory}/../../../interpreter/spark/pyspark/pyspark.zip:${project.build.directory}/../../../interpreter/lib/python/:${project.build.directory}/../../../interpreter/spark/pyspark/py4j-${py4j.version}-src.zip:.</PYTHONPATH>
+            <ZEPPELIN_HOME>${basedir}/../../</ZEPPELIN_HOME>
+          </environmentVariables>
+        </configuration>
+      </plugin>
+
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-shade-plugin</artifactId>
+        <version>${plugin.shade.version}</version>
+        <configuration>
+          <!--<createDependencyReducedPom>false</createDependencyReducedPom>-->
+          <filters>
+            <filter>
+              <artifact>*:*</artifact>
+              <excludes>
+                <exclude>org/datanucleus/**</exclude>
+                <exclude>META-INF/*.SF</exclude>
+                <exclude>META-INF/*.DSA</exclude>
+                <exclude>META-INF/*.RSA</exclude>
+              </excludes>
+            </filter>
+          </filters>
+          <transformers>
+            <transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer" />
+            <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
+              <resource>reference.conf</resource>
+            </transformer>
+          </transformers>
+          <relocations>
+            <relocation>
+              <pattern>io.netty</pattern>
+              <shadedPattern>org.apache.zeppelin.io.netty</shadedPattern>
+            </relocation>
+            <relocation>
+              <pattern>com.google</pattern>
+              <shadedPattern>org.apache.zeppelin.com.google</shadedPattern>
+            </relocation>
+            <relocation>
+              <pattern>py4j.</pattern>
+              <shadedPattern>org.apache.zeppelin.py4j.</shadedPattern>
+            </relocation>
+          </relocations>
+        </configuration>
+        <executions>
+          <execution>
+            <phase>package</phase>
+            <goals>
+              <goal>shade</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+
+
+      <plugin>
+        <artifactId>maven-dependency-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>copy-dependencies</id>
+            <phase>none</phase>
+            <configuration>
+              <skip>true</skip>
+            </configuration>
+          </execution>
+
+          <execution>
+            <id>copy-interpreter-dependencies</id>
+            <phase>none</phase>
+            <configuration>
+              <skip>true</skip>
+            </configuration>
+          </execution>
+          <execution>
+            <id>copy-artifact</id>
+            <phase>none</phase>
+            <configuration>
+              <skip>true</skip>
+            </configuration>
+          </execution>
+
+
+          <execution>
+            <id>copy-spark-interpreter</id>
+            <phase>package</phase>
+            <goals>
+              <goal>copy</goal>
+            </goals>
+            <configuration>
+              <outputDirectory>${project.build.directory}/../../../interpreter/spark</outputDirectory>
+              <overWriteReleases>false</overWriteReleases>
+              <overWriteSnapshots>false</overWriteSnapshots>
+              <overWriteIfNewer>true</overWriteIfNewer>
+              <artifactItems>
+                <artifactItem>
+                  <groupId>${project.groupId}</groupId>
+                  <artifactId>${project.artifactId}</artifactId>
+                  <version>${project.version}</version>
+                  <type>${project.packaging}</type>
+                </artifactItem>
+              </artifactItems>
+            </configuration>
+          </execution>
+
+        </executions>
+      </plugin>
+
+      <plugin>
+        <artifactId>maven-resources-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>copy-interpreter-setting</id>
+            <phase>package</phase>
+            <goals>
+              <goal>resources</goal>
+            </goals>
+            <configuration>
+              <outputDirectory>${project.build.directory}/../../../interpreter/${interpreter.name}</outputDirectory>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+
+    </plugins>
+  </build>
+
+</project>


[05/10] zeppelin git commit: ZEPPELIN-3111. Refactor SparkInterpreter

Posted by zj...@apache.org.
http://git-wip-us.apache.org/repos/asf/zeppelin/blob/d762b528/spark/pom.xml
----------------------------------------------------------------------
diff --git a/spark/pom.xml b/spark/pom.xml
index 1972f26..06b7d9f 100644
--- a/spark/pom.xml
+++ b/spark/pom.xml
@@ -16,680 +16,227 @@
   ~ limitations under the License.
   -->
 
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
-  <modelVersion>4.0.0</modelVersion>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <artifactId>interpreter-parent</artifactId>
+        <groupId>org.apache.zeppelin</groupId>
+        <version>0.9.0-SNAPSHOT</version>
+        <relativePath>../interpreter-parent/pom.xml</relativePath>
+    </parent>
 
-  <parent>
-    <artifactId>zeppelin</artifactId>
     <groupId>org.apache.zeppelin</groupId>
+    <artifactId>spark-parent</artifactId>
+    <packaging>pom</packaging>
     <version>0.9.0-SNAPSHOT</version>
-    <relativePath>..</relativePath>
-  </parent>
-
-  <groupId>org.apache.zeppelin</groupId>
-  <artifactId>zeppelin-spark_2.10</artifactId>
-  <packaging>jar</packaging>
-  <version>0.9.0-SNAPSHOT</version>
-  <name>Zeppelin: Spark</name>
-  <description>Zeppelin spark support</description>
-
-  <properties>
-    <!--library versions-->
-    <jsoup.version>1.8.2</jsoup.version>
-    <spark.version>2.0.2</spark.version>
-    <guava.version>14.0.1</guava.version>
-    <commons.exec.version>1.3</commons.exec.version>
-    <commons.compress.version>1.9</commons.compress.version>
-    <maven.plugin.api.version>3.0</maven.plugin.api.version>
-    <aether.version>1.12</aether.version>
-    <maven.aeither.provider.version>3.0.3</maven.aeither.provider.version>
-    <wagon.version>1.0</wagon.version>
-
-    <datanucleus.rdbms.version>3.2.9</datanucleus.rdbms.version>
-    <datanucleus.apijdo.version>3.2.6</datanucleus.apijdo.version>
-    <datanucleus.core.version>3.2.10</datanucleus.core.version>
-
-    <!--plugin versions-->
-    <plugin.shade.version>2.3</plugin.shade.version>
-    <plugin.scala.version>2.15.2</plugin.scala.version>
-
-    <!-- settings -->
-    <pyspark.test.exclude>**/PySparkInterpreterMatplotlibTest.java</pyspark.test.exclude>
-    <pyspark.test.include>**/*Test.*</pyspark.test.include>
-  </properties>
-
-  <dependencies>
-    <dependency>
-      <groupId>${project.groupId}</groupId>
-      <artifactId>zeppelin-display_${scala.binary.version}</artifactId>
-      <version>${project.version}</version>
-    </dependency>
-
-    <dependency>
-      <groupId>${project.groupId}</groupId>
-      <artifactId>zeppelin-interpreter</artifactId>
-      <version>${project.version}</version>
-    </dependency>
-
-    <dependency>
-      <groupId>${project.groupId}</groupId>
-      <artifactId>zeppelin-python</artifactId>
-      <version>${project.version}</version>
-      <exclusions>
-        <exclusion>
-          <groupId>net.sf.py4j</groupId>
-          <artifactId>py4j</artifactId>
-        </exclusion>
-      </exclusions>
-    </dependency>
-
-    <dependency>
-      <groupId>${project.groupId}</groupId>
-      <artifactId>zeppelin-python</artifactId>
-      <version>${project.version}</version>
-      <classifier>tests</classifier>
-      <scope>test</scope>
-      <exclusions>
-        <exclusion>
-          <groupId>net.sf.py4j</groupId>
-          <artifactId>py4j</artifactId>
-        </exclusion>
-      </exclusions>
-    </dependency>
-
-    <dependency>
-      <groupId>org.slf4j</groupId>
-      <artifactId>slf4j-api</artifactId>
-    </dependency>
-
-    <dependency>
-      <groupId>org.slf4j</groupId>
-      <artifactId>slf4j-log4j12</artifactId>
-    </dependency>
-
-    <dependency>
-      <groupId>org.apache.spark</groupId>
-      <artifactId>spark-repl_${scala.binary.version}</artifactId>
-      <version>${spark.version}</version>
-      <scope>provided</scope>
-    </dependency>
-
-    <dependency>
-      <groupId>org.apache.spark</groupId>
-      <artifactId>spark-hive_${scala.binary.version}</artifactId>
-      <version>${spark.version}</version>
-      <scope>provided</scope>
-    </dependency>
-
-    <!-- Aether :: maven dependency resolution -->
-    <dependency>
-      <groupId>org.apache.maven</groupId>
-      <artifactId>maven-plugin-api</artifactId>
-      <version>${maven.plugin.api.version}</version>
-      <exclusions>
-        <exclusion>
-          <groupId>org.codehaus.plexus</groupId>
-          <artifactId>plexus-utils</artifactId>
-        </exclusion>
-        <exclusion>
-          <groupId>org.sonatype.sisu</groupId>
-          <artifactId>sisu-inject-plexus</artifactId>
-        </exclusion>
-        <exclusion>
-          <groupId>org.apache.maven</groupId>
-          <artifactId>maven-model</artifactId>
-        </exclusion>
-      </exclusions>
-    </dependency>
-
-    <dependency>
-      <groupId>org.sonatype.aether</groupId>
-      <artifactId>aether-api</artifactId>
-      <version>${aether.version}</version>
-    </dependency>
-
-    <dependency>
-      <groupId>org.sonatype.aether</groupId>
-      <artifactId>aether-util</artifactId>
-      <version>${aether.version}</version>
-    </dependency>
-
-    <dependency>
-      <groupId>org.sonatype.aether</groupId>
-      <artifactId>aether-impl</artifactId>
-      <version>${aether.version}</version>
-    </dependency>
-
-    <dependency>
-      <groupId>org.apache.maven</groupId>
-      <artifactId>maven-aether-provider</artifactId>
-      <version>${maven.aeither.provider.version}</version>
-      <exclusions>
-        <exclusion>
-          <groupId>org.sonatype.aether</groupId>
-          <artifactId>aether-api</artifactId>
-        </exclusion>
-        <exclusion>
-          <groupId>org.sonatype.aether</groupId>
-          <artifactId>aether-spi</artifactId>
-        </exclusion>
-        <exclusion>
-          <groupId>org.sonatype.aether</groupId>
-          <artifactId>aether-util</artifactId>
-        </exclusion>
-        <exclusion>
-          <groupId>org.sonatype.aether</groupId>
-          <artifactId>aether-impl</artifactId>
-        </exclusion>
-        <exclusion>
-          <groupId>org.codehaus.plexus</groupId>
-          <artifactId>plexus-utils</artifactId>
-        </exclusion>
-      </exclusions>
-    </dependency>
-
-    <dependency>
-      <groupId>org.sonatype.aether</groupId>
-      <artifactId>aether-connector-file</artifactId>
-      <version>${aether.version}</version>
-    </dependency>
-
-    <dependency>
-      <groupId>org.sonatype.aether</groupId>
-      <artifactId>aether-connector-wagon</artifactId>
-      <version>${aether.version}</version>
-      <exclusions>
-        <exclusion>
-          <groupId>org.apache.maven.wagon</groupId>
-          <artifactId>wagon-provider-api</artifactId>
-        </exclusion>
-      </exclusions>
-    </dependency>
-
-    <dependency>
-      <groupId>org.apache.maven.wagon</groupId>
-      <artifactId>wagon-provider-api</artifactId>
-      <version>${wagon.version}</version>
-      <exclusions>
-        <exclusion>
-          <groupId>org.codehaus.plexus</groupId>
-          <artifactId>plexus-utils</artifactId>
-        </exclusion>
-      </exclusions>
-    </dependency>
-
-    <dependency>
-      <groupId>org.apache.maven.wagon</groupId>
-      <artifactId>wagon-http-lightweight</artifactId>
-      <version>${wagon.version}</version>
-      <exclusions>
-        <exclusion>
-          <groupId>org.apache.maven.wagon</groupId>
-          <artifactId>wagon-http-shared</artifactId>
-        </exclusion>
-      </exclusions>
-    </dependency>
-
-    <dependency>
-      <groupId>org.apache.maven.wagon</groupId>
-      <artifactId>wagon-http</artifactId>
-      <version>${wagon.version}</version>
-      <exclusions>
-      </exclusions>
-    </dependency>
-
-    <dependency>
-      <groupId>org.apache.commons</groupId>
-      <artifactId>commons-exec</artifactId>
-      <version>${commons.exec.version}</version>
-    </dependency>
-
-    <dependency>
-      <groupId>org.scala-lang</groupId>
-      <artifactId>scala-library</artifactId>
-      <version>${scala.version}</version>
-      <scope>provided</scope>
-    </dependency>
-
-    <dependency>
-      <groupId>org.scala-lang</groupId>
-      <artifactId>scala-compiler</artifactId>
-      <version>${scala.version}</version>
-      <scope>provided</scope>
-    </dependency>
-
-    <dependency>
-      <groupId>org.scala-lang</groupId>
-      <artifactId>scala-reflect</artifactId>
-      <version>${scala.version}</version>
-      <scope>provided</scope>
-    </dependency>
-
-    <dependency>
-      <groupId>commons-lang</groupId>
-      <artifactId>commons-lang</artifactId>
-      <scope>provided</scope>
-    </dependency>
-
-    <dependency>
-      <groupId>org.apache.commons</groupId>
-      <artifactId>commons-compress</artifactId>
-      <version>${commons.compress.version}</version>
-      <scope>provided</scope>
-    </dependency>
-
-    <dependency>
-      <groupId>org.jsoup</groupId>
-      <artifactId>jsoup</artifactId>
-      <version>${jsoup.version}</version>
-    </dependency>
-
-    <!--test libraries-->
-    <dependency>
-      <groupId>org.scalatest</groupId>
-      <artifactId>scalatest_${scala.binary.version}</artifactId>
-      <version>${scalatest.version}</version>
-      <scope>test</scope>
-    </dependency>
-
-    <dependency>
-      <groupId>junit</groupId>
-      <artifactId>junit</artifactId>
-      <scope>test</scope>
-    </dependency>
-
-    <dependency>
-      <groupId>org.datanucleus</groupId>
-      <artifactId>datanucleus-core</artifactId>
-      <version>${datanucleus.core.version}</version>
-      <scope>test</scope>
-    </dependency>
-
-    <dependency>
-      <groupId>org.datanucleus</groupId>
-      <artifactId>datanucleus-api-jdo</artifactId>
-      <version>${datanucleus.apijdo.version}</version>
-      <scope>test</scope>
-    </dependency>
-
-    <dependency>
-      <groupId>org.datanucleus</groupId>
-      <artifactId>datanucleus-rdbms</artifactId>
-      <version>${datanucleus.rdbms.version}</version>
-      <scope>test</scope>
-    </dependency>
-
-    <dependency>
-      <groupId>org.mockito</groupId>
-      <artifactId>mockito-core</artifactId>
-      <scope>test</scope>
-    </dependency>
-
-    <dependency>
-      <groupId>org.powermock</groupId>
-      <artifactId>powermock-api-mockito</artifactId>
-      <scope>test</scope>
-    </dependency>
-
-    <dependency>
-      <groupId>org.powermock</groupId>
-      <artifactId>powermock-module-junit4</artifactId>
-      <scope>test</scope>
-    </dependency>
-
-  </dependencies>
-
-  <build>
-    <plugins>
-      <plugin>
-        <artifactId>maven-enforcer-plugin</artifactId>
-        <executions>
-          <execution>
-            <id>enforce</id>
-            <phase>none</phase>
-          </execution>
-        </executions>
-      </plugin>
-
-      <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-surefire-plugin</artifactId>
-        <configuration>
-          <forkCount>1</forkCount>
-          <reuseForks>false</reuseForks>
-          <argLine>-Xmx1024m -XX:MaxPermSize=256m</argLine>
-          <excludes>
-            <exclude>**/SparkRInterpreterTest.java</exclude>
-            <exclude>${pyspark.test.exclude}</exclude>
-          </excludes>
-          <environmentVariables>
-            <!-- local pyspark execution needs PYTHONPATH otherwise python daemon in executor side will fail
-            e.g. sc.range(1,10).sum()
-            -->
-            <PYTHONPATH>../interpreter/spark/pyspark/pyspark.zip:../interpreter/spark/pyspark/py4j-${spark.py4j.version}-src.zip:../interpreter/lib/python</PYTHONPATH>
-          </environmentVariables>
-        </configuration>
-      </plugin>
-
-      <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-shade-plugin</artifactId>
-        <version>${plugin.shade.version}</version>
-        <configuration>
-          <filters>
-            <filter>
-              <artifact>*:*</artifact>
-              <excludes>
-                <exclude>META-INF/*.SF</exclude>
-                <exclude>META-INF/*.DSA</exclude>
-                <exclude>META-INF/*.RSA</exclude>
-              </excludes>
-            </filter>
-          </filters>
-          <transformers>
-            <transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
-            <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
-              <resource>reference.conf</resource>
-            </transformer>
-          </transformers>
-
-          <relocations>
-            <!-- shade guava and proto-buf, because it might conflict with those of spark -->
-            <relocation>
-              <pattern>com.google</pattern>
-              <shadedPattern>org.apache.zeppelin.com.google</shadedPattern>
-            </relocation>
-            <!-- shade netty, because it might conflict with that of spark-->
-            <relocation>
-              <pattern>io.netty</pattern>
-              <shadedPattern>org.apache.zeppelin.io.netty</shadedPattern>
-            </relocation>
-          </relocations>
-        </configuration>
-        <executions>
-          <execution>
-            <phase>package</phase>
-            <goals>
-              <goal>shade</goal>
-            </goals>
-          </execution>
-        </executions>
-      </plugin>
-
-      <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-dependency-plugin</artifactId>
-        <executions>
-          <execution>
-            <phase>package</phase>
-            <goals>
-              <goal>copy</goal>
-            </goals>
-            <configuration>
-              <outputDirectory>${project.build.directory}/../../interpreter/spark</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>
-
-      <!-- Plugin to compile Scala code -->
-      <plugin>
-        <groupId>org.scala-tools</groupId>
-        <artifactId>maven-scala-plugin</artifactId>
-        <version>${plugin.scala.version}</version>
-        <configuration>
-            <scalaVersion>${scala.version}</scalaVersion>
-          <excludes>
-            <exclude>**/ZeppelinR.scala</exclude>
-            <exclude>**/SparkRBackend.scala</exclude>
-          </excludes>
-        </configuration>
-        <executions>
-          <execution>
-            <id>compile</id>
-            <goals>
-              <goal>compile</goal>
-            </goals>
-            <phase>compile</phase>
-          </execution>
-          <execution>
-            <id>test-compile</id>
-            <goals>
-              <goal>testCompile</goal>
-            </goals>
-            <phase>test-compile</phase>
-          </execution>
-          <execution>
-            <phase>process-resources</phase>
-            <goals>
-              <goal>compile</goal>
-            </goals>
-          </execution>
-        </executions>
-      </plugin>
-
-      <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-compiler-plugin</artifactId>
-        <configuration>
-          <excludes combine.self="override"></excludes>
-          <testExcludes combine.self="override">
-            <testExclude>${pyspark.test.exclude}</testExclude>
-          </testExcludes>
-        </configuration>
-      </plugin>
-      <plugin>
-        <groupId>org.scala-tools</groupId>
-        <artifactId>maven-scala-plugin</artifactId>
-        <configuration>
-          <excludes combine.self="override">
-          </excludes>
-        </configuration>
-      </plugin>
-      <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-surefire-plugin</artifactId>
-        <configuration>
-          <excludes combine.self="override">
-            <exclude>${pyspark.test.exclude}</exclude>
-          </excludes>
-        </configuration>
-      </plugin>
-
-      <!-- include sparkr by default -->
-      <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-compiler-plugin</artifactId>
-        <configuration>
-          <excludes combine.self="override"></excludes>
-          <testExcludes combine.self="override">
-            <testExclude>${pyspark.test.exclude}</testExclude>
-          </testExcludes>
-        </configuration>
-      </plugin>
-      <plugin>
-        <groupId>org.scala-tools</groupId>
-        <artifactId>maven-scala-plugin</artifactId>
-        <configuration>
-          <excludes combine.self="override">
-          </excludes>
-        </configuration>
-      </plugin>
-      <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-surefire-plugin</artifactId>
-        <configuration>
-          <excludes combine.self="override">
-            <exclude>${pyspark.test.exclude}</exclude>
-          </excludes>
-        </configuration>
-      </plugin>
-
-      <plugin>
-        <artifactId>maven-resources-plugin</artifactId>
-        <executions>
-          <execution>
-            <id>copy-interpreter-setting</id>
-            <phase>package</phase>
-            <goals>
-              <goal>resources</goal>
-            </goals>
-            <configuration>
-              <outputDirectory>${project.build.directory}/../../interpreter/spark</outputDirectory>
-            </configuration>
-          </execution>
-        </executions>
-      </plugin>
-    </plugins>
-  </build>
-
-  <profiles>
-    <profile>
-      <id>spark-1.4</id>
-      <properties>
-        <spark.version>1.4.1</spark.version>
-      </properties>
-
-      <dependencies>
-      </dependencies>
-    </profile>
-
-    <profile>
-      <id>spark-1.5</id>
-      <properties>
-        <spark.version>1.5.2</spark.version>
-        <akka.group>com.typesafe.akka</akka.group>
-        <akka.version>2.3.11</akka.version>
-        <protobuf.version>2.5.0</protobuf.version>
-      </properties>
-    </profile>
-
-    <profile>
-      <id>spark-1.6</id>
-      <properties>
-        <spark.version>1.6.3</spark.version>
-        <spark.py4j.version>0.9</spark.py4j.version>
-        <akka.group>com.typesafe.akka</akka.group>
-        <akka.version>2.3.11</akka.version>
-        <protobuf.version>2.5.0</protobuf.version>
-      </properties>
-    </profile>
-
-    <profile>
-      <id>spark-2.0</id>
-      <properties>
-        <spark.version>2.0.2</spark.version>
-        <protobuf.version>2.5.0</protobuf.version>
-        <spark.py4j.version>0.10.3</spark.py4j.version>
-      </properties>
-    </profile>
+    <name>spark-parent</name>
+    <description>Zeppelin spark support</description>
+
+    <properties>
+        <!--library versions-->
+        <datanucleus.rdbms.version>3.2.9</datanucleus.rdbms.version>
+        <datanucleus.apijdo.version>3.2.6</datanucleus.apijdo.version>
+        <datanucleus.core.version>3.2.10</datanucleus.core.version>
+
+        <!--plugin versions-->
+        <plugin.shade.version>2.4.1</plugin.shade.version>
+        <plugin.scala.version>2.15.2</plugin.scala.version>
+        <!-- spark versions -->
+        <spark.version>2.2.0</spark.version>
+        <py4j.version>0.10.4</py4j.version>
+    </properties>
 
-    <profile>
-      <id>spark-2.1</id>
-      <properties>
-        <spark.version>2.1.0</spark.version>
-        <protobuf.version>2.5.0</protobuf.version>
-        <spark.py4j.version>0.10.4</spark.py4j.version>
-        <scala.version>2.11.8</scala.version>
-      </properties>
-    </profile>
+    <dependencies>
 
-    <profile>
-      <id>spark-2.2</id>
-      <activation>
-        <activeByDefault>true</activeByDefault>
-      </activation>
-      <properties>
-        <spark.version>2.2.0</spark.version>
-        <protobuf.version>2.5.0</protobuf.version>
-        <spark.py4j.version>0.10.4</spark.py4j.version>
-      </properties>
-    </profile>
+        <dependency>
+            <groupId>org.apache.zeppelin</groupId>
+            <artifactId>zeppelin-interpreter</artifactId>
+            <version>${project.version}</version>
+        </dependency>
 
-    <profile>
-      <id>hadoop-0.23</id>
-      <!-- SPARK-1121: Adds an explicit dependency on Avro to work around a
-        Hadoop 0.23.X issue -->
-      <dependencies>
+        <!--test libraries-->
         <dependency>
-          <groupId>org.apache.avro</groupId>
-          <artifactId>avro</artifactId>
+            <groupId>org.apache.zeppelin</groupId>
+            <artifactId>zeppelin-display</artifactId>
+            <version>${project.version}</version>
+            <scope>test</scope>
         </dependency>
-      </dependencies>
-      <properties>
-        <hadoop.version>0.23.10</hadoop.version>
-      </properties>
-    </profile>
 
-    <profile>
-      <id>hadoop-1</id>
-      <properties>
-        <hadoop.version>1.0.4</hadoop.version>
-        <avro.mapred.classifier>hadoop1</avro.mapred.classifier>
-        <codehaus.jackson.version>1.8.8</codehaus.jackson.version>
-        <akka.group>org.spark-project.akka</akka.group>
-      </properties>
-    </profile>
+        <dependency>
+            <groupId>org.scalatest</groupId>
+            <artifactId>scalatest_${scala.binary.version}</artifactId>
+            <version>${scalatest.version}</version>
+            <scope>test</scope>
+        </dependency>
 
-    <profile>
-      <id>hadoop-2.2</id>
-      <properties>
-        <hadoop.version>2.2.0</hadoop.version>
-        <protobuf.version>2.5.0</protobuf.version>
-        <avro.mapred.classifier>hadoop2</avro.mapred.classifier>
-      </properties>
-    </profile>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
 
-    <profile>
-      <id>hadoop-2.3</id>
-      <properties>
-        <hadoop.version>2.3.0</hadoop.version>
-        <protobuf.version>2.5.0</protobuf.version>
-        <jets3t.version>0.9.3</jets3t.version>
-        <avro.mapred.classifier>hadoop2</avro.mapred.classifier>
-      </properties>
-    </profile>
+        <dependency>
+            <groupId>org.datanucleus</groupId>
+            <artifactId>datanucleus-core</artifactId>
+            <version>${datanucleus.core.version}</version>
+            <scope>test</scope>
+        </dependency>
 
-    <profile>
-      <id>hadoop-2.4</id>
-      <properties>
-        <hadoop.version>2.4.0</hadoop.version>
-        <protobuf.version>2.5.0</protobuf.version>
-        <jets3t.version>0.9.3</jets3t.version>
-        <avro.mapred.classifier>hadoop2</avro.mapred.classifier>
-      </properties>
-    </profile>
+        <dependency>
+            <groupId>org.datanucleus</groupId>
+            <artifactId>datanucleus-api-jdo</artifactId>
+            <version>${datanucleus.apijdo.version}</version>
+            <scope>test</scope>
+        </dependency>
 
-    <profile>
-      <id>hadoop-2.6</id>
-      <properties>
-        <hadoop.version>2.6.0</hadoop.version>
-        <protobuf.version>2.5.0</protobuf.version>
-        <jets3t.version>0.9.3</jets3t.version>
-        <avro.mapred.classifier>hadoop2</avro.mapred.classifier>
-      </properties>
-    </profile>
+        <dependency>
+            <groupId>org.datanucleus</groupId>
+            <artifactId>datanucleus-rdbms</artifactId>
+            <version>${datanucleus.rdbms.version}</version>
+            <scope>test</scope>
+        </dependency>
 
-    <profile>
-      <id>hadoop-2.7</id>
-      <properties>
-        <hadoop.version>2.7.2</hadoop.version>
-        <protobuf.version>2.5.0</protobuf.version>
-        <jets3t.version>0.9.0</jets3t.version>
-        <avro.mapred.classifier>hadoop2</avro.mapred.classifier>
-      </properties>
-    </profile>
-  </profiles>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <artifactId>maven-enforcer-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>enforce</id>
+                        <phase>none</phase>
+                    </execution>
+                </executions>
+            </plugin>
+
+            <plugin>
+                <groupId>org.scalatest</groupId>
+                <artifactId>scalatest-maven-plugin</artifactId>
+                <configuration>
+                    <reportsDirectory>${project.build.directory}/surefire-reports</reportsDirectory>
+                    <junitxml>.</junitxml>
+                    <filereports>WDF TestSuite.txt</filereports>
+                </configuration>
+                <executions>
+                    <execution>
+                        <id>test</id>
+                        <goals>
+                            <goal>test</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+
+            <plugin>
+                <groupId>net.alchim31.maven</groupId>
+                <artifactId>scala-maven-plugin</artifactId>
+                <version>3.2.2</version>
+                <executions>
+                    <execution>
+                        <id>eclipse-add-source</id>
+                        <goals>
+                            <goal>add-source</goal>
+                        </goals>
+                    </execution>
+                    <execution>
+                        <id>scala-compile-first</id>
+                        <phase>process-resources</phase>
+                        <goals>
+                            <goal>compile</goal>
+                        </goals>
+                    </execution>
+                    <execution>
+                        <id>scala-test-compile-first</id>
+                        <phase>process-test-resources</phase>
+                        <goals>
+                            <goal>testCompile</goal>
+                        </goals>
+                    </execution>
+                </executions>
+                <configuration>
+                    <scalaVersion>${scala.compile.version}</scalaVersion>
+                    <!--<recompileMode>incremental</recompileMode>-->
+                    <!--<useZincServer>true</useZincServer>-->
+                    <args>
+                        <arg>-unchecked</arg>
+                        <arg>-deprecation</arg>
+                        <arg>-feature</arg>
+                    </args>
+                    <jvmArgs>
+                        <jvmArg>-Xms1024m</jvmArg>
+                        <jvmArg>-Xmx1024m</jvmArg>
+                        <jvmArg>-XX:PermSize=${PermGen}</jvmArg>
+                        <jvmArg>-XX:MaxPermSize=${MaxPermGen}</jvmArg>
+                    </jvmArgs>
+                    <javacArgs>
+                        <javacArg>-source</javacArg>
+                        <javacArg>${java.version}</javacArg>
+                        <javacArg>-target</javacArg>
+                        <javacArg>${java.version}</javacArg>
+                        <javacArg>-Xlint:all,-serial,-path,-options</javacArg>
+                    </javacArgs>
+                </configuration>
+            </plugin>
+
+        </plugins>
+    </build>
+
+
+    <profiles>
+        <profile>
+            <id>spark-2.2</id>
+            <activation>
+                <activeByDefault>true</activeByDefault>
+            </activation>
+            <properties>
+                <spark.version>2.2.0</spark.version>
+                <py4j.version>0.10.4</py4j.version>
+            </properties>
+        </profile>
+
+        <profile>
+            <id>spark-2.1</id>
+            <properties>
+                <spark.version>2.1.0</spark.version>
+                <py4j.version>0.10.4</py4j.version>
+            </properties>
+        </profile>
+
+        <profile>
+            <id>spark-2.0</id>
+            <properties>
+                <spark.version>2.0.2</spark.version>
+                <py4j.version>0.10.3</py4j.version>
+            </properties>
+        </profile>
+
+        <profile>
+            <id>spark-1.6</id>
+            <properties>
+                <spark.version>1.6.3</spark.version>
+                <py4j.version>0.9</py4j.version>
+            </properties>
+        </profile>
+
+        <profile>
+            <id>spark-1.5</id>
+            <properties>
+                <spark.version>1.5.2</spark.version>
+                <py4j.version>0.8.2.1</py4j.version>
+            </properties>
+        </profile>
+
+        <profile>
+            <id>spark-1.4</id>
+            <properties>
+                <spark.version>1.4.1</spark.version>
+                <py4j.version>0.8.2.1</py4j.version>
+            </properties>
+        </profile>
+
+    </profiles>
 </project>

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/d762b528/spark/scala-2.10/pom.xml
----------------------------------------------------------------------
diff --git a/spark/scala-2.10/pom.xml b/spark/scala-2.10/pom.xml
new file mode 100644
index 0000000..e32e620
--- /dev/null
+++ b/spark/scala-2.10/pom.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one or more
+  ~ contributor license agreements.  See the NOTICE file distributed with
+  ~ this work for additional information regarding copyright ownership.
+  ~ The ASF licenses this file to You under the Apache License, Version 2.0
+  ~ (the "License"); you may not use this file except in compliance with
+  ~ the License.  You may obtain a copy of the License at
+  ~
+  ~    http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>org.apache.zeppelin</groupId>
+  <artifactId>spark-scala-2.10</artifactId>
+  <version>0.9.0-SNAPSHOT</version>
+  <packaging>jar</packaging>
+  <name>Spark Interpreter: Scala_2.10</name>
+
+  <parent>
+    <groupId>org.apache.zeppelin</groupId>
+    <artifactId>spark-scala-parent</artifactId>
+    <version>0.9.0-SNAPSHOT</version>
+    <relativePath>../spark-scala-parent/pom.xml</relativePath>
+  </parent>
+
+  <properties>
+    <scala.version>2.10.5</scala.version>
+    <scala.binary.version>2.10</scala.binary.version>
+    <scala.compile.version>${scala.version}</scala.compile.version>
+  </properties>
+
+</project>

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/d762b528/spark/scala-2.10/spark-scala-parent
----------------------------------------------------------------------
diff --git a/spark/scala-2.10/spark-scala-parent b/spark/scala-2.10/spark-scala-parent
new file mode 120000
index 0000000..e5e899e
--- /dev/null
+++ b/spark/scala-2.10/spark-scala-parent
@@ -0,0 +1 @@
+../spark-scala-parent
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/d762b528/spark/scala-2.10/src/main/scala/org/apache/zeppelin/spark/SparkScala210Interpreter.scala
----------------------------------------------------------------------
diff --git a/spark/scala-2.10/src/main/scala/org/apache/zeppelin/spark/SparkScala210Interpreter.scala b/spark/scala-2.10/src/main/scala/org/apache/zeppelin/spark/SparkScala210Interpreter.scala
new file mode 100644
index 0000000..43aa864
--- /dev/null
+++ b/spark/scala-2.10/src/main/scala/org/apache/zeppelin/spark/SparkScala210Interpreter.scala
@@ -0,0 +1,141 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.zeppelin.spark
+
+import java.io.File
+import java.nio.file.{Files, Paths}
+
+import org.apache.spark.SparkConf
+import org.apache.spark.repl.SparkILoop
+import org.apache.spark.repl.SparkILoop._
+import org.apache.zeppelin.interpreter.thrift.InterpreterCompletion
+import org.apache.zeppelin.interpreter.util.InterpreterOutputStream
+import org.apache.zeppelin.interpreter.{InterpreterContext, InterpreterResult}
+import org.slf4j.{Logger, LoggerFactory}
+
+import scala.tools.nsc.Settings
+import scala.tools.nsc.interpreter._
+
+/**
+  * SparkInterpreter for scala-2.10
+  */
+class SparkScala210Interpreter(override val conf: SparkConf,
+                               override val depFiles: java.util.List[String])
+  extends BaseSparkScalaInterpreter(conf, depFiles) {
+
+  lazy override val LOGGER: Logger = LoggerFactory.getLogger(getClass)
+
+  private var sparkILoop: SparkILoop = _
+
+  override val interpreterOutput =
+    new InterpreterOutputStream(LoggerFactory.getLogger(classOf[SparkScala210Interpreter]))
+
+  override def open(): Unit = {
+    super.open()
+    // redirect the output of open to InterpreterOutputStream, so that user can have more
+    // diagnose info in frontend
+    if (InterpreterContext.get() != null) {
+      interpreterOutput.setInterpreterOutput(InterpreterContext.get().out)
+    }
+    val rootDir = conf.get("spark.repl.classdir", System.getProperty("java.io.tmpdir"))
+    val outputDir = Files.createTempDirectory(Paths.get(rootDir), "spark").toFile
+    outputDir.deleteOnExit()
+    conf.set("spark.repl.class.outputDir", outputDir.getAbsolutePath)
+    // Only Spark1 requires to create http server, Spark2 removes HttpServer class.
+    startHttpServer(outputDir).foreach { case (server, uri) =>
+      sparkHttpServer = server
+      conf.set("spark.repl.class.uri", uri)
+    }
+
+    val settings = new Settings()
+    settings.embeddedDefaults(Thread.currentThread().getContextClassLoader())
+    settings.usejavacp.value = true
+    settings.classpath.value = getUserJars.mkString(File.pathSeparator)
+    Console.setOut(interpreterOutput)
+    sparkILoop = new SparkILoop(null, new JPrintWriter(Console.out, true))
+
+    setDeclaredField(sparkILoop, "settings", settings)
+    callMethod(sparkILoop, "createInterpreter")
+    sparkILoop.initializeSynchronous()
+    callMethod(sparkILoop, "postInitialization")
+    val reader = callMethod(sparkILoop,
+      "org$apache$spark$repl$SparkILoop$$chooseReader",
+      Array(settings.getClass), Array(settings)).asInstanceOf[InteractiveReader]
+    setDeclaredField(sparkILoop, "org$apache$spark$repl$SparkILoop$$in", reader)
+    scalaCompleter = reader.completion.completer()
+
+    createSparkContext()
+  }
+
+  override def close(): Unit = {
+    super.close()
+    if (sparkILoop != null) {
+      callMethod(sparkILoop, "org$apache$spark$repl$SparkILoop$$closeInterpreter")
+    }
+  }
+
+  protected override def interpret(code: String, context: InterpreterContext): InterpreterResult = {
+    if (context != null) {
+      interpreterOutput.setInterpreterOutput(context.out)
+      context.out.clear()
+    } else {
+      interpreterOutput.setInterpreterOutput(null)
+    }
+
+    Console.withOut(if (context != null) context.out else Console.out) {
+      interpreterOutput.ignoreLeadingNewLinesFromScalaReporter()
+      // add print("") at the end in case the last line is comment which lead to INCOMPLETE
+      val lines = code.split("\\n") ++ List("print(\"\")")
+      var incompleteCode = ""
+      var lastStatus: InterpreterResult.Code = null
+      for (line <- lines if !line.trim.isEmpty) {
+        val nextLine = if (incompleteCode != "") {
+          incompleteCode + "\n" + line
+        } else {
+          line
+        }
+        scalaInterpret(nextLine) match {
+          case scala.tools.nsc.interpreter.IR.Success =>
+            // continue the next line
+            incompleteCode = ""
+            lastStatus = InterpreterResult.Code.SUCCESS
+          case error@scala.tools.nsc.interpreter.IR.Error =>
+            return new InterpreterResult(InterpreterResult.Code.ERROR)
+          case scala.tools.nsc.interpreter.IR.Incomplete =>
+            // put this line into inCompleteCode for the next execution.
+            incompleteCode = incompleteCode + "\n" + line
+            lastStatus = InterpreterResult.Code.INCOMPLETE
+        }
+      }
+      // flush all output before returning result to frontend
+      Console.flush()
+      interpreterOutput.setInterpreterOutput(null)
+      return new InterpreterResult(lastStatus)
+    }
+  }
+
+  def scalaInterpret(code: String): scala.tools.nsc.interpreter.IR.Result =
+    sparkILoop.interpret(code)
+
+  protected def bind(name: String, tpe: String, value: Object, modifier: List[String]): Unit = {
+    sparkILoop.beQuietDuring {
+      sparkILoop.bind(name, tpe, value, modifier)
+    }
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/d762b528/spark/scala-2.11/pom.xml
----------------------------------------------------------------------
diff --git a/spark/scala-2.11/pom.xml b/spark/scala-2.11/pom.xml
new file mode 100644
index 0000000..d9113d1
--- /dev/null
+++ b/spark/scala-2.11/pom.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one or more
+  ~ contributor license agreements.  See the NOTICE file distributed with
+  ~ this work for additional information regarding copyright ownership.
+  ~ The ASF licenses this file to You under the Apache License, Version 2.0
+  ~ (the "License"); you may not use this file except in compliance with
+  ~ the License.  You may obtain a copy of the License at
+  ~
+  ~    http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>org.apache.zeppelin</groupId>
+  <artifactId>spark-scala-2.11</artifactId>
+  <version>0.9.0-SNAPSHOT</version>
+  <packaging>jar</packaging>
+  <name>Spark Interpreter: Scala_2.11</name>
+
+  <parent>
+    <groupId>org.apache.zeppelin</groupId>
+    <artifactId>spark-scala-parent</artifactId>
+    <version>0.9.0-SNAPSHOT</version>
+    <relativePath>../spark-scala-parent/pom.xml</relativePath>
+  </parent>
+
+  <properties>
+    <scala.version>2.11.8</scala.version>
+    <scala.binary.version>2.11</scala.binary.version>
+    <scala.compile.version>${scala.version}</scala.compile.version>
+  </properties>
+
+</project>

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/d762b528/spark/scala-2.11/spark-scala-parent
----------------------------------------------------------------------
diff --git a/spark/scala-2.11/spark-scala-parent b/spark/scala-2.11/spark-scala-parent
new file mode 120000
index 0000000..e5e899e
--- /dev/null
+++ b/spark/scala-2.11/spark-scala-parent
@@ -0,0 +1 @@
+../spark-scala-parent
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/d762b528/spark/scala-2.11/src/main/resources/log4j.properties
----------------------------------------------------------------------
diff --git a/spark/scala-2.11/src/main/resources/log4j.properties b/spark/scala-2.11/src/main/resources/log4j.properties
new file mode 100644
index 0000000..0c90b21
--- /dev/null
+++ b/spark/scala-2.11/src/main/resources/log4j.properties
@@ -0,0 +1,50 @@
+#
+# 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.
+#
+
+# Direct log messages to stdout
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.Target=System.out
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c:%L - %m%n
+#log4j.appender.stdout.layout.ConversionPattern=
+#%5p [%t] (%F:%L) - %m%n
+#%-4r [%t] %-5p %c %x - %m%n
+#
+
+# Root logger option
+log4j.rootLogger=INFO, stdout
+ 
+#mute some noisy guys
+log4j.logger.org.apache.hadoop.mapred=WARN
+log4j.logger.org.apache.hadoop.hive.ql=WARN
+log4j.logger.org.apache.hadoop.hive.metastore=WARN
+log4j.logger.org.apache.haadoop.hive.service.HiveServer=WARN
+log4j.logger.org.apache.zeppelin.scheduler=WARN
+
+log4j.logger.org.quartz=WARN
+log4j.logger.DataNucleus=WARN
+log4j.logger.DataNucleus.MetaData=ERROR
+log4j.logger.DataNucleus.Datastore=ERROR
+
+# Log all JDBC parameters
+log4j.logger.org.hibernate.type=ALL
+
+log4j.logger.org.apache.zeppelin.interpreter=DEBUG
+log4j.logger.org.apache.zeppelin.spark=DEBUG
+
+
+log4j.logger.org.apache.spark.repl.Main=INFO

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/d762b528/spark/scala-2.11/src/main/scala/org/apache/zeppelin/spark/SparkScala211Interpreter.scala
----------------------------------------------------------------------
diff --git a/spark/scala-2.11/src/main/scala/org/apache/zeppelin/spark/SparkScala211Interpreter.scala b/spark/scala-2.11/src/main/scala/org/apache/zeppelin/spark/SparkScala211Interpreter.scala
new file mode 100644
index 0000000..e145260
--- /dev/null
+++ b/spark/scala-2.11/src/main/scala/org/apache/zeppelin/spark/SparkScala211Interpreter.scala
@@ -0,0 +1,140 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.zeppelin.spark
+
+import java.io.{BufferedReader, File}
+import java.net.URLClassLoader
+import java.nio.file.{Files, Paths}
+
+import org.apache.spark.SparkConf
+import org.apache.zeppelin.interpreter.thrift.InterpreterCompletion
+import org.apache.zeppelin.interpreter.util.InterpreterOutputStream
+import org.apache.zeppelin.interpreter.{InterpreterContext, InterpreterResult}
+import org.slf4j.LoggerFactory
+import org.slf4j.Logger
+
+import scala.tools.nsc.Settings
+import scala.tools.nsc.interpreter._
+
+/**
+  * SparkInterpreter for scala-2.11
+  */
+class SparkScala211Interpreter(override val conf: SparkConf,
+                               override val depFiles: java.util.List[String])
+  extends BaseSparkScalaInterpreter(conf, depFiles) {
+
+  lazy override val LOGGER: Logger = LoggerFactory.getLogger(getClass)
+
+  private var sparkILoop: ILoop = _
+
+  override val interpreterOutput = new InterpreterOutputStream(LOGGER)
+
+  override def open(): Unit = {
+    super.open()
+    if (conf.get("spark.master", "local") == "yarn-client") {
+      System.setProperty("SPARK_YARN_MODE", "true")
+    }
+    // Only Spark1 requires to create http server, Spark2 removes HttpServer class.
+    val rootDir = conf.get("spark.repl.classdir", System.getProperty("java.io.tmpdir"))
+    val outputDir = Files.createTempDirectory(Paths.get(rootDir), "spark").toFile
+    outputDir.deleteOnExit()
+    conf.set("spark.repl.class.outputDir", outputDir.getAbsolutePath)
+    startHttpServer(outputDir).foreach { case (server, uri) =>
+      sparkHttpServer = server
+      conf.set("spark.repl.class.uri", uri)
+    }
+
+    val settings = new Settings()
+    settings.processArguments(List("-Yrepl-class-based",
+      "-Yrepl-outdir", s"${outputDir.getAbsolutePath}"), true)
+    settings.embeddedDefaults(Thread.currentThread().getContextClassLoader())
+    settings.usejavacp.value = true
+    settings.classpath.value = getUserJars.mkString(File.pathSeparator)
+
+    val replOut = new JPrintWriter(interpreterOutput, true)
+    sparkILoop = new ILoop(None, replOut)
+    sparkILoop.settings = settings
+    sparkILoop.createInterpreter()
+
+    val in0 = getField(sparkILoop, "scala$tools$nsc$interpreter$ILoop$$in0").asInstanceOf[Option[BufferedReader]]
+    val reader = in0.fold(sparkILoop.chooseReader(settings))(r => SimpleReader(r, replOut, interactive = true))
+
+    sparkILoop.in = reader
+    sparkILoop.initializeSynchronous()
+    callMethod(sparkILoop, "scala$tools$nsc$interpreter$ILoop$$loopPostInit")
+    this.scalaCompleter = reader.completion.completer()
+
+    createSparkContext()
+  }
+
+  protected def bind(name: String, tpe: String, value: Object, modifier: List[String]): Unit = {
+    sparkILoop.beQuietDuring {
+      sparkILoop.bind(name, tpe, value, modifier)
+    }
+  }
+
+
+  override def close(): Unit = {
+    super.close()
+    if (sparkILoop != null) {
+      sparkILoop.closeInterpreter()
+    }
+  }
+
+  protected override def interpret(code: String, context: InterpreterContext): InterpreterResult = {
+    if (context != null) {
+      interpreterOutput.setInterpreterOutput(context.out)
+      context.out.clear()
+    }
+
+    Console.withOut(if (context != null) context.out else Console.out) {
+      interpreterOutput.ignoreLeadingNewLinesFromScalaReporter()
+      // add print("") at the end in case the last line is comment which lead to INCOMPLETE
+      val lines = code.split("\\n") ++ List("print(\"\")")
+      var incompleteCode = ""
+      var lastStatus: InterpreterResult.Code = null
+      for (line <- lines if !line.trim.isEmpty) {
+        val nextLine = if (incompleteCode != "") {
+          incompleteCode + "\n" + line
+        } else {
+          line
+        }
+        scalaInterpret(nextLine) match {
+          case scala.tools.nsc.interpreter.IR.Success =>
+            // continue the next line
+            incompleteCode = ""
+            lastStatus = InterpreterResult.Code.SUCCESS
+          case error@scala.tools.nsc.interpreter.IR.Error =>
+            return new InterpreterResult(InterpreterResult.Code.ERROR)
+          case scala.tools.nsc.interpreter.IR.Incomplete =>
+            // put this line into inCompleteCode for the next execution.
+            incompleteCode = incompleteCode + "\n" + line
+            lastStatus = InterpreterResult.Code.INCOMPLETE
+        }
+      }
+      // flush all output before returning result to frontend
+      Console.flush()
+      interpreterOutput.setInterpreterOutput(null)
+      return new InterpreterResult(lastStatus)
+    }
+  }
+
+  def scalaInterpret(code: String): scala.tools.nsc.interpreter.IR.Result =
+    sparkILoop.interpret(code)
+
+}

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/d762b528/spark/spark-dependencies/pom.xml
----------------------------------------------------------------------
diff --git a/spark/spark-dependencies/pom.xml b/spark/spark-dependencies/pom.xml
new file mode 100644
index 0000000..7643dc9
--- /dev/null
+++ b/spark/spark-dependencies/pom.xml
@@ -0,0 +1,591 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one or more
+  ~ contributor license agreements.  See the NOTICE file distributed with
+  ~ this work for additional information regarding copyright ownership.
+  ~ The ASF licenses this file to You under the Apache License, Version 2.0
+  ~ (the "License"); you may not use this file except in compliance with
+  ~ the License.  You may obtain a copy of the License at
+  ~
+  ~    http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <artifactId>spark-parent</artifactId>
+    <groupId>org.apache.zeppelin</groupId>
+    <version>0.9.0-SNAPSHOT</version>
+    <relativePath>..</relativePath>
+  </parent>
+
+  <groupId>org.apache.zeppelin</groupId>
+  <artifactId>zeppelin-spark-dependencies_2.10</artifactId>
+  <packaging>jar</packaging>
+  <version>0.9.0-SNAPSHOT</version>
+  <name>Zeppelin: Spark dependencies</name>
+  <description>Zeppelin spark support</description>
+
+  <properties>
+    <!-- library version defined in this section brought from spark 1.4.1 and it's dependency.
+         Therefore changing only spark.version is not going to be enough when this module
+         support new version of spark to make the new version as default supported version.
+
+         Each profile (spark-2.0, spark-1.6, etc) will overrides necessary dependency version.
+         So we'll make one of those profile 'activateByDefault' to make it default supported version
+         instead of changing spark.version in this section.
+    -->
+
+    <hadoop.version>2.3.0</hadoop.version>
+    <yarn.version>${hadoop.version}</yarn.version>
+    <avro.version>1.7.7</avro.version>
+    <avro.mapred.classifier/>
+    <jets3t.version>0.7.1</jets3t.version>
+    <protobuf.version>2.4.1</protobuf.version>
+
+    <akka.group>org.spark-project.akka</akka.group>
+    <akka.version>2.3.4-spark</akka.version>
+
+    <spark.archive>spark-${spark.version}</spark.archive>
+    <spark.src.download.url>
+      http://d3kbcqa49mib13.cloudfront.net/${spark.archive}.tgz
+    </spark.src.download.url>
+    <spark.bin.download.url>
+      http://d3kbcqa49mib13.cloudfront.net/${spark.archive}-bin-without-hadoop.tgz
+    </spark.bin.download.url>
+
+    <!--plugin versions-->
+    <plugin.shade.version>2.3</plugin.shade.version>
+  </properties>
+
+  <dependencyManagement>
+    <dependencies>
+      <dependency>
+        <groupId>org.apache.avro</groupId>
+        <artifactId>avro</artifactId>
+        <version>${avro.version}</version>
+      </dependency>
+      <dependency>
+        <groupId>org.apache.avro</groupId>
+        <artifactId>avro-ipc</artifactId>
+        <version>${avro.version}</version>
+        <exclusions>
+          <exclusion>
+            <groupId>io.netty</groupId>
+            <artifactId>netty</artifactId>
+          </exclusion>
+          <exclusion>
+            <groupId>org.mortbay.jetty</groupId>
+            <artifactId>jetty</artifactId>
+          </exclusion>
+          <exclusion>
+            <groupId>org.mortbay.jetty</groupId>
+            <artifactId>jetty-util</artifactId>
+          </exclusion>
+          <exclusion>
+            <groupId>org.mortbay.jetty</groupId>
+            <artifactId>servlet-api</artifactId>
+          </exclusion>
+          <exclusion>
+            <groupId>org.apache.velocity</groupId>
+            <artifactId>velocity</artifactId>
+          </exclusion>
+        </exclusions>
+      </dependency>
+      <dependency>
+        <groupId>org.apache.avro</groupId>
+        <artifactId>avro-mapred</artifactId>
+        <version>${avro.version}</version>
+        <classifier>${avro.mapred.classifier}</classifier>
+        <exclusions>
+          <exclusion>
+            <groupId>io.netty</groupId>
+            <artifactId>netty</artifactId>
+          </exclusion>
+          <exclusion>
+            <groupId>org.mortbay.jetty</groupId>
+            <artifactId>jetty</artifactId>
+          </exclusion>
+          <exclusion>
+            <groupId>org.mortbay.jetty</groupId>
+            <artifactId>jetty-util</artifactId>
+          </exclusion>
+          <exclusion>
+            <groupId>org.mortbay.jetty</groupId>
+            <artifactId>servlet-api</artifactId>
+          </exclusion>
+          <exclusion>
+            <groupId>org.apache.velocity</groupId>
+            <artifactId>velocity</artifactId>
+          </exclusion>
+        </exclusions>
+      </dependency>
+
+      <!-- See SPARK-1556 for info on this dependency: -->
+      <dependency>
+        <groupId>net.java.dev.jets3t</groupId>
+        <artifactId>jets3t</artifactId>
+        <version>${jets3t.version}</version>
+        <scope>runtime</scope>
+        <exclusions>
+          <exclusion>
+            <groupId>commons-logging</groupId>
+            <artifactId>commons-logging</artifactId>
+          </exclusion>
+        </exclusions>
+      </dependency>
+      <dependency>
+        <groupId>org.apache.hadoop</groupId>
+        <artifactId>hadoop-yarn-api</artifactId>
+        <version>${yarn.version}</version>
+        <exclusions>
+          <exclusion>
+            <groupId>asm</groupId>
+            <artifactId>asm</artifactId>
+          </exclusion>
+          <exclusion>
+            <groupId>org.ow2.asm</groupId>
+            <artifactId>asm</artifactId>
+          </exclusion>
+          <exclusion>
+            <groupId>org.jboss.netty</groupId>
+            <artifactId>netty</artifactId>
+          </exclusion>
+          <exclusion>
+            <groupId>commons-logging</groupId>
+            <artifactId>commons-logging</artifactId>
+          </exclusion>
+        </exclusions>
+      </dependency>
+
+      <dependency>
+        <groupId>org.apache.hadoop</groupId>
+        <artifactId>hadoop-yarn-common</artifactId>
+        <version>${yarn.version}</version>
+        <exclusions>
+          <exclusion>
+            <groupId>asm</groupId>
+            <artifactId>asm</artifactId>
+          </exclusion>
+          <exclusion>
+            <groupId>org.ow2.asm</groupId>
+            <artifactId>asm</artifactId>
+          </exclusion>
+          <exclusion>
+            <groupId>org.jboss.netty</groupId>
+            <artifactId>netty</artifactId>
+          </exclusion>
+          <exclusion>
+            <groupId>javax.servlet</groupId>
+            <artifactId>servlet-api</artifactId>
+          </exclusion>
+          <exclusion>
+            <groupId>commons-logging</groupId>
+            <artifactId>commons-logging</artifactId>
+          </exclusion>
+        </exclusions>
+      </dependency>
+
+      <dependency>
+        <groupId>org.apache.hadoop</groupId>
+        <artifactId>hadoop-yarn-server-web-proxy</artifactId>
+        <version>${yarn.version}</version>
+        <exclusions>
+          <exclusion>
+            <groupId>asm</groupId>
+            <artifactId>asm</artifactId>
+          </exclusion>
+          <exclusion>
+            <groupId>org.ow2.asm</groupId>
+            <artifactId>asm</artifactId>
+          </exclusion>
+          <exclusion>
+            <groupId>org.jboss.netty</groupId>
+            <artifactId>netty</artifactId>
+          </exclusion>
+          <exclusion>
+            <groupId>javax.servlet</groupId>
+            <artifactId>servlet-api</artifactId>
+          </exclusion>
+          <exclusion>
+            <groupId>commons-logging</groupId>
+            <artifactId>commons-logging</artifactId>
+          </exclusion>
+        </exclusions>
+      </dependency>
+
+      <dependency>
+        <groupId>org.apache.hadoop</groupId>
+        <artifactId>hadoop-yarn-client</artifactId>
+        <version>${yarn.version}</version>
+        <exclusions>
+          <exclusion>
+            <groupId>asm</groupId>
+            <artifactId>asm</artifactId>
+          </exclusion>
+          <exclusion>
+            <groupId>org.ow2.asm</groupId>
+            <artifactId>asm</artifactId>
+          </exclusion>
+          <exclusion>
+            <groupId>org.jboss.netty</groupId>
+            <artifactId>netty</artifactId>
+          </exclusion>
+          <exclusion>
+            <groupId>javax.servlet</groupId>
+            <artifactId>servlet-api</artifactId>
+          </exclusion>
+          <exclusion>
+            <groupId>commons-logging</groupId>
+            <artifactId>commons-logging</artifactId>
+          </exclusion>
+        </exclusions>
+      </dependency>
+    </dependencies>
+  </dependencyManagement>
+
+  <dependencies>
+    <!-- Spark -->
+    <dependency>
+      <groupId>org.apache.spark</groupId>
+      <artifactId>spark-core_${scala.binary.version}</artifactId>
+      <version>${spark.version}</version>
+      <exclusions>
+        <exclusion>
+          <groupId>org.apache.hadoop</groupId>
+          <artifactId>hadoop-client</artifactId>
+        </exclusion>
+      </exclusions>
+    </dependency>
+
+    <dependency>
+      <groupId>org.apache.spark</groupId>
+      <artifactId>spark-repl_${scala.binary.version}</artifactId>
+      <version>${spark.version}</version>
+    </dependency>
+
+    <dependency>
+      <groupId>org.apache.spark</groupId>
+      <artifactId>spark-sql_${scala.binary.version}</artifactId>
+      <version>${spark.version}</version>
+    </dependency>
+
+    <dependency>
+      <groupId>org.apache.spark</groupId>
+      <artifactId>spark-hive_${scala.binary.version}</artifactId>
+      <version>${spark.version}</version>
+    </dependency>
+
+    <dependency>
+      <groupId>org.apache.spark</groupId>
+      <artifactId>spark-streaming_${scala.binary.version}</artifactId>
+      <version>${spark.version}</version>
+    </dependency>
+
+    <dependency>
+      <groupId>org.apache.spark</groupId>
+      <artifactId>spark-catalyst_${scala.binary.version}</artifactId>
+      <version>${spark.version}</version>
+    </dependency>
+
+    <!-- hadoop -->
+    <dependency>
+      <groupId>org.apache.hadoop</groupId>
+      <artifactId>hadoop-client</artifactId>
+      <version>${hadoop.version}</version>
+    </dependency>
+
+
+    <dependency>
+      <groupId>com.google.protobuf</groupId>
+      <artifactId>protobuf-java</artifactId>
+      <version>${protobuf.version}</version>
+    </dependency>
+
+    <dependency>
+      <groupId>${akka.group}</groupId>
+      <artifactId>akka-actor_${scala.binary.version}</artifactId>
+      <version>${akka.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>${akka.group}</groupId>
+      <artifactId>akka-remote_${scala.binary.version}</artifactId>
+      <version>${akka.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>${akka.group}</groupId>
+      <artifactId>akka-slf4j_${scala.binary.version}</artifactId>
+      <version>${akka.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>${akka.group}</groupId>
+      <artifactId>akka-testkit_${scala.binary.version}</artifactId>
+      <version>${akka.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>${akka.group}</groupId>
+      <artifactId>akka-zeromq_${scala.binary.version}</artifactId>
+      <version>${akka.version}</version>
+      <exclusions>
+        <exclusion>
+          <groupId>${akka.group}</groupId>
+          <artifactId>akka-actor_${scala.binary.version}</artifactId>
+        </exclusion>
+      </exclusions>
+    </dependency>
+
+    <!-- yarn (not supported for Spark v1.5.0 or higher) -->
+    <dependency>
+      <groupId>org.apache.spark</groupId>
+      <artifactId>spark-yarn_${scala.binary.version}</artifactId>
+      <version>${spark.version}</version>
+    </dependency>
+
+    <dependency>
+      <groupId>org.apache.hadoop</groupId>
+      <artifactId>hadoop-yarn-api</artifactId>
+      <version>${yarn.version}</version>
+    </dependency>
+
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <artifactId>maven-enforcer-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>enforce</id>
+            <phase>none</phase>
+          </execution>
+        </executions>
+      </plugin>
+
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-surefire-plugin</artifactId>
+        <configuration>
+          <forkCount>1</forkCount>
+          <reuseForks>false</reuseForks>
+          <argLine>-Xmx1024m -XX:MaxPermSize=256m</argLine>
+        </configuration>
+      </plugin>
+
+      <plugin>
+        <groupId>com.googlecode.maven-download-plugin</groupId>
+        <artifactId>download-maven-plugin</artifactId>
+        <version>${plugin.download.version}</version>
+      </plugin>
+
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-shade-plugin</artifactId>
+        <version>${plugin.shade.version}</version>
+        <configuration>
+          <filters>
+            <filter>
+              <artifact>*:*</artifact>
+              <excludes>
+                <exclude>org/datanucleus/**</exclude>
+                <exclude>META-INF/*.SF</exclude>
+                <exclude>META-INF/*.DSA</exclude>
+                <exclude>META-INF/*.RSA</exclude>
+              </excludes>
+            </filter>
+          </filters>
+          <transformers>
+            <transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
+            <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
+              <resource>reference.conf</resource>
+            </transformer>
+          </transformers>
+        </configuration>
+        <executions>
+          <execution>
+            <phase>package</phase>
+            <goals>
+              <goal>shade</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+
+      <!-- Deploy datanucleus jars to the interpreter/spark directory -->
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-dependency-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>copy-interpreter-dependencies</id>
+            <phase>package</phase>
+            <goals>
+              <goal>copy-dependencies</goal>
+            </goals>
+            <configuration>
+              <skip>true</skip>
+            </configuration>
+          </execution>
+
+          <execution>
+            <id>copy-spark-interpreter-dependencies</id>
+            <phase>package</phase>
+            <goals>
+              <goal>copy-dependencies</goal>
+            </goals>
+            <configuration>
+              <outputDirectory>${project.build.directory}/../../../interpreter/spark/dep</outputDirectory>
+              <overWriteReleases>false</overWriteReleases>
+              <overWriteSnapshots>false</overWriteSnapshots>
+              <overWriteIfNewer>true</overWriteIfNewer>
+              <includeGroupIds>org.datanucleus</includeGroupIds>
+            </configuration>
+          </execution>
+          <execution>
+            <id>copy-artifact</id>
+            <phase>package</phase>
+            <goals>
+              <goal>copy</goal>
+            </goals>
+            <configuration>
+              <outputDirectory>${project.build.directory}/../../../interpreter/spark/dep</outputDirectory>
+              <overWriteReleases>false</overWriteReleases>
+              <overWriteSnapshots>false</overWriteSnapshots>
+              <overWriteIfNewer>true</overWriteIfNewer>
+              <artifactItems>
+                <artifactItem>
+                  <groupId>${project.groupId}</groupId>
+                  <artifactId>${project.artifactId}</artifactId>
+                  <version>${project.version}</version>
+                  <type>${project.packaging}</type>
+                </artifactItem>
+              </artifactItems>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+
+      <plugin>
+        <artifactId>maven-resources-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>copy-interpreter-setting</id>
+            <phase>none</phase>
+            <configuration>
+              <skip>true</skip>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+
+      <!-- include pyspark by default -->
+      <plugin>
+        <groupId>com.googlecode.maven-download-plugin</groupId>
+        <artifactId>download-maven-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>download-pyspark-files</id>
+            <phase>validate</phase>
+            <goals>
+              <goal>wget</goal>
+            </goals>
+            <configuration>
+              <readTimeOut>60000</readTimeOut>
+              <retries>5</retries>
+              <unpack>true</unpack>
+              <url>${spark.src.download.url}</url>
+              <outputDirectory>${project.build.directory}</outputDirectory>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+
+      <plugin>
+        <artifactId>maven-clean-plugin</artifactId>
+        <configuration>
+          <filesets>
+            <fileset>
+              <directory>${basedir}/../python/build</directory>
+            </fileset>
+          </filesets>
+        </configuration>
+      </plugin>
+
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-antrun-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>zip-pyspark-files</id>
+            <phase>generate-resources</phase>
+            <goals>
+              <goal>run</goal>
+            </goals>
+            <configuration>
+              <target>
+                <delete dir="../../interpreter/spark/pyspark"/>
+                <copy todir="../../interpreter/spark/pyspark"
+                      file="${project.build.directory}/${spark.archive}/python/lib/py4j-${py4j.version}-src.zip"/>
+                <zip destfile="${project.build.directory}/../../../interpreter/spark/pyspark/pyspark.zip"
+                     basedir="${project.build.directory}/${spark.archive}/python"
+                     includes="pyspark/*.py,pyspark/**/*.py"/>
+              </target>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+
+      <!-- include sparkr by default -->
+      <plugin>
+        <groupId>com.googlecode.maven-download-plugin</groupId>
+        <artifactId>download-maven-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>download-sparkr-files</id>
+            <phase>validate</phase>
+            <goals>
+              <goal>wget</goal>
+            </goals>
+            <configuration>
+              <readTimeOut>60000</readTimeOut>
+              <retries>5</retries>
+              <url>${spark.bin.download.url}</url>
+              <unpack>true</unpack>
+              <outputDirectory>${project.build.directory}</outputDirectory>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+      <plugin>
+        <artifactId>maven-resources-plugin</artifactId>
+        <version>2.7</version>
+        <executions>
+          <execution>
+            <id>copy-sparkr-files</id>
+            <phase>generate-resources</phase>
+            <goals>
+              <goal>copy-resources</goal>
+            </goals>
+            <configuration>
+              <outputDirectory>${project.build.directory}/../../../interpreter/spark/R/lib</outputDirectory>
+              <resources>
+                <resource>
+                  <directory>
+                    ${project.build.directory}/spark-${spark.version}-bin-without-hadoop/R/lib
+                  </directory>
+                </resource>
+              </resources>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+  </build>
+</project>

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/d762b528/spark/spark-scala-parent/pom.xml
----------------------------------------------------------------------
diff --git a/spark/spark-scala-parent/pom.xml b/spark/spark-scala-parent/pom.xml
new file mode 100644
index 0000000..830fa59
--- /dev/null
+++ b/spark/spark-scala-parent/pom.xml
@@ -0,0 +1,172 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one or more
+  ~ contributor license agreements.  See the NOTICE file distributed with
+  ~ this work for additional information regarding copyright ownership.
+  ~ The ASF licenses this file to You under the Apache License, Version 2.0
+  ~ (the "License"); you may not use this file except in compliance with
+  ~ the License.  You may obtain a copy of the License at
+  ~
+  ~    http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+    <parent>
+        <artifactId>spark-parent</artifactId>
+        <groupId>org.apache.zeppelin</groupId>
+        <version>0.9.0-SNAPSHOT</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+
+    <modelVersion>4.0.0</modelVersion>
+    <groupId>org.apache.zeppelin</groupId>
+    <artifactId>spark-scala-parent</artifactId>
+    <version>0.9.0-SNAPSHOT</version>
+    <packaging>pom</packaging>
+
+    <dependencies>
+
+        <dependency>
+            <groupId>org.apache.zeppelin</groupId>
+            <artifactId>zeppelin-interpreter</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.spark</groupId>
+            <artifactId>spark-repl_${scala.binary.version}</artifactId>
+            <version>${spark.version}</version>
+            <scope>provided</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.spark</groupId>
+            <artifactId>spark-core_${scala.binary.version}</artifactId>
+            <version>${spark.version}</version>
+            <scope>provided</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.spark</groupId>
+            <artifactId>spark-hive_${scala.binary.version}</artifactId>
+            <version>${spark.version}</version>
+            <scope>provided</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.scala-lang</groupId>
+            <artifactId>scala-compiler</artifactId>
+            <version>${scala.version}</version>
+            <scope>provided</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.scala-lang</groupId>
+            <artifactId>scala-library</artifactId>
+            <version>${scala.version}</version>
+            <scope>provided</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.scala-lang</groupId>
+            <artifactId>scala-reflect</artifactId>
+            <version>${scala.version}</version>
+            <scope>provided</scope>
+        </dependency>
+
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.codehaus.mojo</groupId>
+                <artifactId>build-helper-maven-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>add-scala-sources</id>
+                        <phase>generate-sources</phase>
+                        <goals>
+                            <goal>add-source</goal>
+                        </goals>
+                        <configuration>
+                            <sources>
+                                <source>${project.basedir}/../spark-scala-parent/src/main/scala</source>
+                            </sources>
+                        </configuration>
+                    </execution>
+                    <execution>
+                        <id>add-scala-test-sources</id>
+                        <phase>generate-test-sources</phase>
+                        <goals>
+                            <goal>add-test-source</goal>
+                        </goals>
+                        <configuration>
+                            <sources>
+                                <source>${project.basedir}/../spark-scala-parent/src/test/scala</source>
+                            </sources>
+                        </configuration>
+                    </execution>
+                    <execution>
+                        <id>add-resource</id>
+                        <phase>generate-resources</phase>
+                        <goals>
+                            <goal>add-resource</goal>
+                        </goals>
+                        <configuration>
+                            <resources>
+                                <resource>
+                                    <directory>${project.basedir}/../spark-scala-parent/src/main/resources</directory>
+                                </resource>
+                            </resources>
+                        </configuration>
+                    </execution>
+                    <execution>
+                        <id>add-test-resource</id>
+                        <phase>generate-test-resources</phase>
+                        <goals>
+                            <goal>add-test-resource</goal>
+                        </goals>
+                        <configuration>
+                            <resources>
+                                <resource>
+                                    <directory>${project.basedir}/../spark-scala-parent/src/test/resources</directory>
+                                </resource>
+                            </resources>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+
+            <plugin>
+                <artifactId>maven-dependency-plugin</artifactId>
+                <configuration>
+                    <skip>true</skip>
+                </configuration>
+            </plugin>
+
+            <plugin>
+                <artifactId>maven-resources-plugin</artifactId>
+                <executions>
+                    <execution>
+                    <id>copy-interpreter-setting</id>
+                    <phase>none</phase>
+                    <configuration>
+                        <skip>true</skip>
+                    </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+
+        </plugins>
+    </build>
+
+</project>
\ No newline at end of file


[07/10] zeppelin git commit: ZEPPELIN-3111. Refactor SparkInterpreter

Posted by zj...@apache.org.
http://git-wip-us.apache.org/repos/asf/zeppelin/blob/d762b528/spark/interpreter/src/main/java/org/apache/zeppelin/spark/ZeppelinRContext.java
----------------------------------------------------------------------
diff --git a/spark/interpreter/src/main/java/org/apache/zeppelin/spark/ZeppelinRContext.java b/spark/interpreter/src/main/java/org/apache/zeppelin/spark/ZeppelinRContext.java
new file mode 100644
index 0000000..80ea03b
--- /dev/null
+++ b/spark/interpreter/src/main/java/org/apache/zeppelin/spark/ZeppelinRContext.java
@@ -0,0 +1,69 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.zeppelin.spark;
+
+import org.apache.spark.SparkContext;
+import org.apache.spark.api.java.JavaSparkContext;
+import org.apache.spark.sql.SQLContext;
+
+/**
+ * Contains the Spark and Zeppelin Contexts made available to SparkR.
+ */
+public class ZeppelinRContext {
+  private static SparkContext sparkContext;
+  private static SQLContext sqlContext;
+  private static SparkZeppelinContext zeppelinContext;
+  private static Object sparkSession;
+  private static JavaSparkContext javaSparkContext;
+
+  public static void setSparkContext(SparkContext sparkContext) {
+    ZeppelinRContext.sparkContext = sparkContext;
+  }
+
+  public static void setZeppelinContext(SparkZeppelinContext zeppelinContext) {
+    ZeppelinRContext.zeppelinContext = zeppelinContext;
+  }
+
+  public static void setSqlContext(SQLContext sqlContext) {
+    ZeppelinRContext.sqlContext = sqlContext;
+  }
+
+  public static void setSparkSession(Object sparkSession) {
+    ZeppelinRContext.sparkSession = sparkSession;
+  }
+
+  public static SparkContext getSparkContext() {
+    return sparkContext;
+  }
+
+  public static SQLContext getSqlContext() {
+    return sqlContext;
+  }
+
+  public static SparkZeppelinContext getZeppelinContext() {
+    return zeppelinContext;
+  }
+
+  public static Object getSparkSession() {
+    return sparkSession;
+  }
+
+  public static void setJavaSparkContext(JavaSparkContext jsc) { javaSparkContext = jsc; }
+
+  public static JavaSparkContext getJavaSparkContext() { return javaSparkContext; }
+}

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/d762b528/spark/interpreter/src/main/java/org/apache/zeppelin/spark/dep/SparkDependencyContext.java
----------------------------------------------------------------------
diff --git a/spark/interpreter/src/main/java/org/apache/zeppelin/spark/dep/SparkDependencyContext.java b/spark/interpreter/src/main/java/org/apache/zeppelin/spark/dep/SparkDependencyContext.java
new file mode 100644
index 0000000..0235fc6
--- /dev/null
+++ b/spark/interpreter/src/main/java/org/apache/zeppelin/spark/dep/SparkDependencyContext.java
@@ -0,0 +1,181 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.zeppelin.spark.dep;
+
+import java.io.File;
+import java.net.MalformedURLException;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.apache.zeppelin.dep.Booter;
+import org.apache.zeppelin.dep.Dependency;
+import org.apache.zeppelin.dep.Repository;
+
+import org.sonatype.aether.RepositorySystem;
+import org.sonatype.aether.RepositorySystemSession;
+import org.sonatype.aether.artifact.Artifact;
+import org.sonatype.aether.collection.CollectRequest;
+import org.sonatype.aether.graph.DependencyFilter;
+import org.sonatype.aether.repository.RemoteRepository;
+import org.sonatype.aether.repository.Authentication;
+import org.sonatype.aether.resolution.ArtifactResolutionException;
+import org.sonatype.aether.resolution.ArtifactResult;
+import org.sonatype.aether.resolution.DependencyRequest;
+import org.sonatype.aether.resolution.DependencyResolutionException;
+import org.sonatype.aether.util.artifact.DefaultArtifact;
+import org.sonatype.aether.util.artifact.JavaScopes;
+import org.sonatype.aether.util.filter.DependencyFilterUtils;
+import org.sonatype.aether.util.filter.PatternExclusionsDependencyFilter;
+
+
+/**
+ *
+ */
+public class SparkDependencyContext {
+  List<Dependency> dependencies = new LinkedList<>();
+  List<Repository> repositories = new LinkedList<>();
+
+  List<File> files = new LinkedList<>();
+  List<File> filesDist = new LinkedList<>();
+  private RepositorySystem system = Booter.newRepositorySystem();
+  private RepositorySystemSession session;
+  private RemoteRepository mavenCentral = Booter.newCentralRepository();
+  private RemoteRepository mavenLocal = Booter.newLocalRepository();
+  private List<RemoteRepository> additionalRepos = new LinkedList<>();
+
+  public SparkDependencyContext(String localRepoPath, String additionalRemoteRepository) {
+    session =  Booter.newRepositorySystemSession(system, localRepoPath);
+    addRepoFromProperty(additionalRemoteRepository);
+  }
+
+  public Dependency load(String lib) {
+    Dependency dep = new Dependency(lib);
+
+    if (dependencies.contains(dep)) {
+      dependencies.remove(dep);
+    }
+    dependencies.add(dep);
+    return dep;
+  }
+
+  public Repository addRepo(String name) {
+    Repository rep = new Repository(name);
+    repositories.add(rep);
+    return rep;
+  }
+
+  public void reset() {
+    dependencies = new LinkedList<>();
+    repositories = new LinkedList<>();
+
+    files = new LinkedList<>();
+    filesDist = new LinkedList<>();
+  }
+
+  private void addRepoFromProperty(String listOfRepo) {
+    if (listOfRepo != null) {
+      String[] repos = listOfRepo.split(";");
+      for (String repo : repos) {
+        String[] parts = repo.split(",");
+        if (parts.length == 3) {
+          String id = parts[0].trim();
+          String url = parts[1].trim();
+          boolean isSnapshot = Boolean.parseBoolean(parts[2].trim());
+          if (id.length() > 1 && url.length() > 1) {
+            RemoteRepository rr = new RemoteRepository(id, "default", url);
+            rr.setPolicy(isSnapshot, null);
+            additionalRepos.add(rr);
+          }
+        }
+      }
+    }
+  }
+
+  /**
+   * fetch all artifacts
+   * @return
+   * @throws MalformedURLException
+   * @throws ArtifactResolutionException
+   * @throws DependencyResolutionException
+   */
+  public List<File> fetch() throws MalformedURLException,
+      DependencyResolutionException, ArtifactResolutionException {
+
+    for (Dependency dep : dependencies) {
+      if (!dep.isLocalFsArtifact()) {
+        List<ArtifactResult> artifacts = fetchArtifactWithDep(dep);
+        for (ArtifactResult artifact : artifacts) {
+          if (dep.isDist()) {
+            filesDist.add(artifact.getArtifact().getFile());
+          }
+          files.add(artifact.getArtifact().getFile());
+        }
+      } else {
+        if (dep.isDist()) {
+          filesDist.add(new File(dep.getGroupArtifactVersion()));
+        }
+        files.add(new File(dep.getGroupArtifactVersion()));
+      }
+    }
+
+    return files;
+  }
+
+  private List<ArtifactResult> fetchArtifactWithDep(Dependency dep)
+      throws DependencyResolutionException, ArtifactResolutionException {
+    Artifact artifact = new DefaultArtifact(
+        SparkDependencyResolver.inferScalaVersion(dep.getGroupArtifactVersion()));
+
+    DependencyFilter classpathFlter = DependencyFilterUtils
+        .classpathFilter(JavaScopes.COMPILE);
+    PatternExclusionsDependencyFilter exclusionFilter = new PatternExclusionsDependencyFilter(
+        SparkDependencyResolver.inferScalaVersion(dep.getExclusions()));
+
+    CollectRequest collectRequest = new CollectRequest();
+    collectRequest.setRoot(new org.sonatype.aether.graph.Dependency(artifact,
+        JavaScopes.COMPILE));
+
+    collectRequest.addRepository(mavenCentral);
+    collectRequest.addRepository(mavenLocal);
+    for (RemoteRepository repo : additionalRepos) {
+      collectRequest.addRepository(repo);
+    }
+    for (Repository repo : repositories) {
+      RemoteRepository rr = new RemoteRepository(repo.getId(), "default", repo.getUrl());
+      rr.setPolicy(repo.isSnapshot(), null);
+      Authentication auth = repo.getAuthentication();
+      if (auth != null) {
+        rr.setAuthentication(auth);
+      }
+      collectRequest.addRepository(rr);
+    }
+
+    DependencyRequest dependencyRequest = new DependencyRequest(collectRequest,
+        DependencyFilterUtils.andFilter(exclusionFilter, classpathFlter));
+
+    return system.resolveDependencies(session, dependencyRequest).getArtifactResults();
+  }
+
+  public List<File> getFiles() {
+    return files;
+  }
+
+  public List<File> getFilesDist() {
+    return filesDist;
+  }
+}

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/d762b528/spark/interpreter/src/main/java/org/apache/zeppelin/spark/dep/SparkDependencyResolver.java
----------------------------------------------------------------------
diff --git a/spark/interpreter/src/main/java/org/apache/zeppelin/spark/dep/SparkDependencyResolver.java b/spark/interpreter/src/main/java/org/apache/zeppelin/spark/dep/SparkDependencyResolver.java
new file mode 100644
index 0000000..46224a8
--- /dev/null
+++ b/spark/interpreter/src/main/java/org/apache/zeppelin/spark/dep/SparkDependencyResolver.java
@@ -0,0 +1,351 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.zeppelin.spark.dep;
+
+import java.io.File;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.net.URL;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.spark.SparkContext;
+import org.apache.zeppelin.dep.AbstractDependencyResolver;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.sonatype.aether.artifact.Artifact;
+import org.sonatype.aether.collection.CollectRequest;
+import org.sonatype.aether.graph.Dependency;
+import org.sonatype.aether.graph.DependencyFilter;
+import org.sonatype.aether.repository.RemoteRepository;
+import org.sonatype.aether.resolution.ArtifactResult;
+import org.sonatype.aether.resolution.DependencyRequest;
+import org.sonatype.aether.util.artifact.DefaultArtifact;
+import org.sonatype.aether.util.artifact.JavaScopes;
+import org.sonatype.aether.util.filter.DependencyFilterUtils;
+import org.sonatype.aether.util.filter.PatternExclusionsDependencyFilter;
+
+import scala.Some;
+import scala.collection.IndexedSeq;
+import scala.reflect.io.AbstractFile;
+import scala.tools.nsc.Global;
+import scala.tools.nsc.backend.JavaPlatform;
+import scala.tools.nsc.util.ClassPath;
+import scala.tools.nsc.util.MergedClassPath;
+
+/**
+ * Deps resolver.
+ * Add new dependencies from mvn repo (at runtime) to Spark interpreter group.
+ */
+public class SparkDependencyResolver extends AbstractDependencyResolver {
+  Logger logger = LoggerFactory.getLogger(SparkDependencyResolver.class);
+  private Global global;
+  private ClassLoader runtimeClassLoader;
+  private SparkContext sc;
+
+  private final String[] exclusions = new String[] {"org.scala-lang:scala-library",
+                                                    "org.scala-lang:scala-compiler",
+                                                    "org.scala-lang:scala-reflect",
+                                                    "org.scala-lang:scalap",
+                                                    "org.apache.zeppelin:zeppelin-zengine",
+                                                    "org.apache.zeppelin:zeppelin-spark",
+                                                    "org.apache.zeppelin:zeppelin-server"};
+
+  public SparkDependencyResolver(Global global,
+                                 ClassLoader runtimeClassLoader,
+                                 SparkContext sc,
+                                 String localRepoPath,
+                                 String additionalRemoteRepository) {
+    super(localRepoPath);
+    this.global = global;
+    this.runtimeClassLoader = runtimeClassLoader;
+    this.sc = sc;
+    addRepoFromProperty(additionalRemoteRepository);
+  }
+
+  private void addRepoFromProperty(String listOfRepo) {
+    if (listOfRepo != null) {
+      String[] repos = listOfRepo.split(";");
+      for (String repo : repos) {
+        String[] parts = repo.split(",");
+        if (parts.length == 3) {
+          String id = parts[0].trim();
+          String url = parts[1].trim();
+          boolean isSnapshot = Boolean.parseBoolean(parts[2].trim());
+          if (id.length() > 1 && url.length() > 1) {
+            addRepo(id, url, isSnapshot);
+          }
+        }
+      }
+    }
+  }
+
+  private void updateCompilerClassPath(URL[] urls) throws IllegalAccessException,
+      IllegalArgumentException, InvocationTargetException {
+
+    JavaPlatform platform = (JavaPlatform) global.platform();
+    MergedClassPath<AbstractFile> newClassPath = mergeUrlsIntoClassPath(platform, urls);
+
+    Method[] methods = platform.getClass().getMethods();
+    for (Method m : methods) {
+      if (m.getName().endsWith("currentClassPath_$eq")) {
+        m.invoke(platform, new Some(newClassPath));
+        break;
+      }
+    }
+
+    // NOTE: Must use reflection until this is exposed/fixed upstream in Scala
+    List<String> classPaths = new LinkedList<>();
+    for (URL url : urls) {
+      classPaths.add(url.getPath());
+    }
+
+    // Reload all jars specified into our compiler
+    global.invalidateClassPathEntries(scala.collection.JavaConversions.asScalaBuffer(classPaths)
+        .toList());
+  }
+
+  // Until spark 1.1.x
+  // check https://github.com/apache/spark/commit/191d7cf2a655d032f160b9fa181730364681d0e7
+  private void updateRuntimeClassPath_1_x(URL[] urls) throws SecurityException,
+      IllegalAccessException, IllegalArgumentException,
+      InvocationTargetException, NoSuchMethodException {
+    Method addURL;
+    addURL = runtimeClassLoader.getClass().getDeclaredMethod("addURL", new Class[] {URL.class});
+    addURL.setAccessible(true);
+    for (URL url : urls) {
+      addURL.invoke(runtimeClassLoader, url);
+    }
+  }
+
+  private void updateRuntimeClassPath_2_x(URL[] urls) throws SecurityException,
+      IllegalAccessException, IllegalArgumentException,
+      InvocationTargetException, NoSuchMethodException {
+    Method addURL;
+    addURL = runtimeClassLoader.getClass().getDeclaredMethod("addNewUrl", new Class[] {URL.class});
+    addURL.setAccessible(true);
+    for (URL url : urls) {
+      addURL.invoke(runtimeClassLoader, url);
+    }
+  }
+
+  private MergedClassPath<AbstractFile> mergeUrlsIntoClassPath(JavaPlatform platform, URL[] urls) {
+    IndexedSeq<ClassPath<AbstractFile>> entries =
+        ((MergedClassPath<AbstractFile>) platform.classPath()).entries();
+    List<ClassPath<AbstractFile>> cp = new LinkedList<>();
+
+    for (int i = 0; i < entries.size(); i++) {
+      cp.add(entries.apply(i));
+    }
+
+    for (URL url : urls) {
+      AbstractFile file;
+      if ("file".equals(url.getProtocol())) {
+        File f = new File(url.getPath());
+        if (f.isDirectory()) {
+          file = AbstractFile.getDirectory(scala.reflect.io.File.jfile2path(f));
+        } else {
+          file = AbstractFile.getFile(scala.reflect.io.File.jfile2path(f));
+        }
+      } else {
+        file = AbstractFile.getURL(url);
+      }
+
+      ClassPath<AbstractFile> newcp = platform.classPath().context().newClassPath(file);
+
+      // distinct
+      if (cp.contains(newcp) == false) {
+        cp.add(newcp);
+      }
+    }
+
+    return new MergedClassPath(scala.collection.JavaConversions.asScalaBuffer(cp).toIndexedSeq(),
+        platform.classPath().context());
+  }
+
+  public List<String> load(String artifact,
+      boolean addSparkContext) throws Exception {
+    return load(artifact, new LinkedList<String>(), addSparkContext);
+  }
+
+  public List<String> load(String artifact, Collection<String> excludes,
+      boolean addSparkContext) throws Exception {
+    if (StringUtils.isBlank(artifact)) {
+      // Should throw here
+      throw new RuntimeException("Invalid artifact to load");
+    }
+
+    // <groupId>:<artifactId>[:<extension>[:<classifier>]]:<version>
+    int numSplits = artifact.split(":").length;
+    if (numSplits >= 3 && numSplits <= 6) {
+      return loadFromMvn(artifact, excludes, addSparkContext);
+    } else {
+      loadFromFs(artifact, addSparkContext);
+      LinkedList<String> libs = new LinkedList<>();
+      libs.add(artifact);
+      return libs;
+    }
+  }
+
+  private void loadFromFs(String artifact, boolean addSparkContext) throws Exception {
+    File jarFile = new File(artifact);
+
+    global.new Run();
+
+    if (sc.version().startsWith("1.1")) {
+      updateRuntimeClassPath_1_x(new URL[] {jarFile.toURI().toURL()});
+    } else {
+      updateRuntimeClassPath_2_x(new URL[] {jarFile.toURI().toURL()});
+    }
+
+    if (addSparkContext) {
+      sc.addJar(jarFile.getAbsolutePath());
+    }
+  }
+
+  private List<String> loadFromMvn(String artifact, Collection<String> excludes,
+      boolean addSparkContext) throws Exception {
+    List<String> loadedLibs = new LinkedList<>();
+    Collection<String> allExclusions = new LinkedList<>();
+    allExclusions.addAll(excludes);
+    allExclusions.addAll(Arrays.asList(exclusions));
+
+    List<ArtifactResult> listOfArtifact;
+    listOfArtifact = getArtifactsWithDep(artifact, allExclusions);
+
+    Iterator<ArtifactResult> it = listOfArtifact.iterator();
+    while (it.hasNext()) {
+      Artifact a = it.next().getArtifact();
+      String gav = a.getGroupId() + ":" + a.getArtifactId() + ":" + a.getVersion();
+      for (String exclude : allExclusions) {
+        if (gav.startsWith(exclude)) {
+          it.remove();
+          break;
+        }
+      }
+    }
+
+    List<URL> newClassPathList = new LinkedList<>();
+    List<File> files = new LinkedList<>();
+    for (ArtifactResult artifactResult : listOfArtifact) {
+      logger.info("Load " + artifactResult.getArtifact().getGroupId() + ":"
+          + artifactResult.getArtifact().getArtifactId() + ":"
+          + artifactResult.getArtifact().getVersion());
+      newClassPathList.add(artifactResult.getArtifact().getFile().toURI().toURL());
+      files.add(artifactResult.getArtifact().getFile());
+      loadedLibs.add(artifactResult.getArtifact().getGroupId() + ":"
+          + artifactResult.getArtifact().getArtifactId() + ":"
+          + artifactResult.getArtifact().getVersion());
+    }
+
+    global.new Run();
+    if (sc.version().startsWith("1.1")) {
+      updateRuntimeClassPath_1_x(newClassPathList.toArray(new URL[0]));
+    } else {
+      updateRuntimeClassPath_2_x(newClassPathList.toArray(new URL[0]));
+    }
+    updateCompilerClassPath(newClassPathList.toArray(new URL[0]));
+
+    if (addSparkContext) {
+      for (File f : files) {
+        sc.addJar(f.getAbsolutePath());
+      }
+    }
+
+    return loadedLibs;
+  }
+
+  /**
+   * @param dependency
+   * @param excludes list of pattern can either be of the form groupId:artifactId
+   * @return
+   * @throws Exception
+   */
+  @Override
+  public List<ArtifactResult> getArtifactsWithDep(String dependency,
+      Collection<String> excludes) throws Exception {
+    Artifact artifact = new DefaultArtifact(inferScalaVersion(dependency));
+    DependencyFilter classpathFilter = DependencyFilterUtils.classpathFilter(JavaScopes.COMPILE);
+    PatternExclusionsDependencyFilter exclusionFilter =
+        new PatternExclusionsDependencyFilter(inferScalaVersion(excludes));
+
+    CollectRequest collectRequest = new CollectRequest();
+    collectRequest.setRoot(new Dependency(artifact, JavaScopes.COMPILE));
+
+    synchronized (repos) {
+      for (RemoteRepository repo : repos) {
+        collectRequest.addRepository(repo);
+      }
+    }
+    DependencyRequest dependencyRequest = new DependencyRequest(collectRequest,
+        DependencyFilterUtils.andFilter(exclusionFilter, classpathFilter));
+    return system.resolveDependencies(session, dependencyRequest).getArtifactResults();
+  }
+
+  public static Collection<String> inferScalaVersion(Collection<String> artifact) {
+    List<String> list = new LinkedList<>();
+    for (String a : artifact) {
+      list.add(inferScalaVersion(a));
+    }
+    return list;
+  }
+
+  public static String inferScalaVersion(String artifact) {
+    int pos = artifact.indexOf(":");
+    if (pos < 0 || pos + 2 >= artifact.length()) {
+      // failed to infer
+      return artifact;
+    }
+
+    if (':' == artifact.charAt(pos + 1)) {
+      String restOfthem = "";
+      String versionSep = ":";
+
+      String groupId = artifact.substring(0, pos);
+      int nextPos = artifact.indexOf(":", pos + 2);
+      if (nextPos < 0) {
+        if (artifact.charAt(artifact.length() - 1) == '*') {
+          nextPos = artifact.length() - 1;
+          versionSep = "";
+          restOfthem = "*";
+        } else {
+          versionSep = "";
+          nextPos = artifact.length();
+        }
+      }
+
+      String artifactId = artifact.substring(pos + 2, nextPos);
+      if (nextPos < artifact.length()) {
+        if (!restOfthem.equals("*")) {
+          restOfthem = artifact.substring(nextPos + 1);
+        }
+      }
+
+      String [] version = scala.util.Properties.versionNumberString().split("[.]");
+      String scalaVersion = version[0] + "." + version[1];
+
+      return groupId + ":" + artifactId + "_" + scalaVersion + versionSep + restOfthem;
+    } else {
+      return artifact;
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/d762b528/spark/interpreter/src/main/resources/R/zeppelin_sparkr.R
----------------------------------------------------------------------
diff --git a/spark/interpreter/src/main/resources/R/zeppelin_sparkr.R b/spark/interpreter/src/main/resources/R/zeppelin_sparkr.R
new file mode 100644
index 0000000..525c6c5
--- /dev/null
+++ b/spark/interpreter/src/main/resources/R/zeppelin_sparkr.R
@@ -0,0 +1,105 @@
+#
+# 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.
+#
+
+args <- commandArgs(trailingOnly = TRUE)
+
+hashCode <- as.integer(args[1])
+port <- as.integer(args[2])
+libPath <- args[3]
+version <- as.integer(args[4])
+rm(args)
+
+print(paste("Port ", toString(port)))
+print(paste("LibPath ", libPath))
+
+.libPaths(c(file.path(libPath), .libPaths()))
+library(SparkR)
+
+
+SparkR:::connectBackend("localhost", port, 6000)
+
+# scStartTime is needed by R/pkg/R/sparkR.R
+assign(".scStartTime", as.integer(Sys.time()), envir = SparkR:::.sparkREnv)
+
+# getZeppelinR
+.zeppelinR = SparkR:::callJStatic("org.apache.zeppelin.spark.ZeppelinR", "getZeppelinR", hashCode)
+
+# setup spark env
+assign(".sc", SparkR:::callJStatic("org.apache.zeppelin.spark.ZeppelinRContext", "getSparkContext"), envir = SparkR:::.sparkREnv)
+assign("sc", get(".sc", envir = SparkR:::.sparkREnv), envir=.GlobalEnv)
+if (version >= 20000) {
+  assign(".sparkRsession", SparkR:::callJStatic("org.apache.zeppelin.spark.ZeppelinRContext", "getSparkSession"), envir = SparkR:::.sparkREnv)
+  assign("spark", get(".sparkRsession", envir = SparkR:::.sparkREnv), envir = .GlobalEnv)
+  assign(".sparkRjsc", SparkR:::callJStatic("org.apache.zeppelin.spark.ZeppelinRContext", "getJavaSparkContext"), envir = SparkR:::.sparkREnv)
+}
+assign(".sqlc", SparkR:::callJStatic("org.apache.zeppelin.spark.ZeppelinRContext", "getSqlContext"), envir = SparkR:::.sparkREnv)
+assign("sqlContext", get(".sqlc", envir = SparkR:::.sparkREnv), envir = .GlobalEnv)
+assign(".zeppelinContext", SparkR:::callJStatic("org.apache.zeppelin.spark.ZeppelinRContext", "getZeppelinContext"), envir = .GlobalEnv)
+
+z.put <- function(name, object) {
+  SparkR:::callJMethod(.zeppelinContext, "put", name, object)
+}
+z.get <- function(name) {
+  SparkR:::callJMethod(.zeppelinContext, "get", name)
+}
+z.input <- function(name, value) {
+  SparkR:::callJMethod(.zeppelinContext, "input", name, value)
+}
+
+# notify script is initialized
+SparkR:::callJMethod(.zeppelinR, "onScriptInitialized")
+
+while (TRUE) {
+  req <- SparkR:::callJMethod(.zeppelinR, "getRequest")
+  type <-  SparkR:::callJMethod(req, "getType")
+  stmt <- SparkR:::callJMethod(req, "getStmt")
+  value <- SparkR:::callJMethod(req, "getValue")
+  
+  if (type == "eval") {
+    tryCatch({
+      ret <- eval(parse(text=stmt))
+      SparkR:::callJMethod(.zeppelinR, "setResponse", "", FALSE)
+    }, error = function(e) {
+      SparkR:::callJMethod(.zeppelinR, "setResponse", toString(e), TRUE)
+    })    
+  } else if (type == "set") {
+    tryCatch({
+      ret <- assign(stmt, value)
+      SparkR:::callJMethod(.zeppelinR, "setResponse", "", FALSE)
+    }, error = function(e) {
+      SparkR:::callJMethod(.zeppelinR, "setResponse", toString(e), TRUE)
+    })
+  } else if (type == "get") {
+    tryCatch({      
+      ret <- eval(parse(text=stmt))
+      SparkR:::callJMethod(.zeppelinR, "setResponse", ret, FALSE)
+    }, error = function(e) {
+      SparkR:::callJMethod(.zeppelinR, "setResponse", toString(e), TRUE)
+    })
+  } else if (type == "getS") {
+    tryCatch({
+      ret <- eval(parse(text=stmt))
+      SparkR:::callJMethod(.zeppelinR, "setResponse", toString(ret), FALSE)
+    }, error = function(e) {
+      SparkR:::callJMethod(.zeppelinR, "setResponse", toString(e), TRUE)
+    })
+  } else {
+    # unsupported type
+    SparkR:::callJMethod(.zeppelinR, "setResponse", paste("Unsupported type ", type), TRUE)
+  }
+}

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/d762b528/spark/interpreter/src/main/resources/interpreter-setting.json
----------------------------------------------------------------------
diff --git a/spark/interpreter/src/main/resources/interpreter-setting.json b/spark/interpreter/src/main/resources/interpreter-setting.json
new file mode 100644
index 0000000..7e647d7
--- /dev/null
+++ b/spark/interpreter/src/main/resources/interpreter-setting.json
@@ -0,0 +1,233 @@
+[
+  {
+    "group": "spark",
+    "name": "spark",
+    "className": "org.apache.zeppelin.spark.SparkInterpreter",
+    "defaultInterpreter": true,
+    "properties": {
+      "spark.executor.memory": {
+        "envName": null,
+        "propertyName": "spark.executor.memory",
+        "defaultValue": "",
+        "description": "Executor memory per worker instance. ex) 512m, 32g",
+        "type": "string"
+      },
+      "args": {
+        "envName": null,
+        "propertyName": null,
+        "defaultValue": "",
+        "description": "spark commandline args",
+        "type": "textarea"
+      },
+      "zeppelin.spark.useHiveContext": {
+        "envName": "ZEPPELIN_SPARK_USEHIVECONTEXT",
+        "propertyName": "zeppelin.spark.useHiveContext",
+        "defaultValue": true,
+        "description": "Use HiveContext instead of SQLContext if it is true.",
+        "type": "checkbox"
+      },
+      "spark.app.name": {
+        "envName": "SPARK_APP_NAME",
+        "propertyName": "spark.app.name",
+        "defaultValue": "Zeppelin",
+        "description": "The name of spark application.",
+        "type": "string"
+      },
+      "zeppelin.spark.printREPLOutput": {
+        "envName": null,
+        "propertyName": "zeppelin.spark.printREPLOutput",
+        "defaultValue": true,
+        "description": "Print REPL output",
+        "type": "checkbox"
+      },
+      "spark.cores.max": {
+        "envName": null,
+        "propertyName": "spark.cores.max",
+        "defaultValue": "",
+        "description": "Total number of cores to use. Empty value uses all available core.",
+        "type": "number"
+      },
+      "zeppelin.spark.maxResult": {
+        "envName": "ZEPPELIN_SPARK_MAXRESULT",
+        "propertyName": "zeppelin.spark.maxResult",
+        "defaultValue": "1000",
+        "description": "Max number of Spark SQL result to display.",
+        "type": "number"
+      },
+      "master": {
+        "envName": "MASTER",
+        "propertyName": "spark.master",
+        "defaultValue": "local[*]",
+        "description": "Spark master uri. ex) spark://masterhost:7077",
+        "type": "string"
+      },
+      "zeppelin.spark.enableSupportedVersionCheck": {
+        "envName": null,
+        "propertyName": "zeppelin.spark.enableSupportedVersionCheck",
+        "defaultValue": true,
+        "description": "Do not change - developer only setting, not for production use",
+        "type": "checkbox"
+      },
+      "zeppelin.spark.uiWebUrl": {
+        "envName": null,
+        "propertyName": "zeppelin.spark.uiWebUrl",
+        "defaultValue": "",
+        "description": "Override Spark UI default URL",
+        "type": "string"
+      },
+      "zeppelin.spark.useNew": {
+        "envName": null,
+        "propertyName": "zeppelin.spark.useNew",
+        "defaultValue": "false",
+        "description": "Whether use new spark interpreter implementation",
+        "type": "checkbox"
+      }
+    },
+    "editor": {
+      "language": "scala",
+      "editOnDblClick": false,
+      "completionKey": "TAB"
+    }
+  },
+  {
+    "group": "spark",
+    "name": "sql",
+    "className": "org.apache.zeppelin.spark.SparkSqlInterpreter",
+    "properties": {
+      "zeppelin.spark.concurrentSQL": {
+        "envName": "ZEPPELIN_SPARK_CONCURRENTSQL",
+        "propertyName": "zeppelin.spark.concurrentSQL",
+        "defaultValue": false,
+        "description": "Execute multiple SQL concurrently if set true.",
+        "type": "checkbox"
+      },
+      "zeppelin.spark.sql.stacktrace": {
+        "envName": "ZEPPELIN_SPARK_SQL_STACKTRACE",
+        "propertyName": "zeppelin.spark.sql.stacktrace",
+        "defaultValue": false,
+        "description": "Show full exception stacktrace for SQL queries if set to true.",
+        "type": "checkbox"
+      },
+      "zeppelin.spark.maxResult": {
+        "envName": "ZEPPELIN_SPARK_MAXRESULT",
+        "propertyName": "zeppelin.spark.maxResult",
+        "defaultValue": "1000",
+        "description": "Max number of Spark SQL result to display.",
+        "type": "number"
+      },
+      "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.",
+        "type": "checkbox"
+      }
+    },
+    "editor": {
+      "language": "sql",
+      "editOnDblClick": false,
+      "completionKey": "TAB"
+    }
+  },
+  {
+    "group": "spark",
+    "name": "dep",
+    "className": "org.apache.zeppelin.spark.DepInterpreter",
+    "properties": {
+      "zeppelin.dep.localrepo": {
+        "envName": "ZEPPELIN_DEP_LOCALREPO",
+        "propertyName": null,
+        "defaultValue": "local-repo",
+        "description": "local repository for dependency loader",
+        "type": "string"
+      },
+      "zeppelin.dep.additionalRemoteRepository": {
+        "envName": null,
+        "propertyName": null,
+        "defaultValue": "spark-packages,http://dl.bintray.com/spark-packages/maven,false;",
+        "description": "A list of 'id,remote-repository-URL,is-snapshot;' for each remote repository.",
+        "type": "textarea"
+      }
+    },
+    "editor": {
+      "language": "scala",
+      "editOnDblClick": false,
+      "completionKey": "TAB"
+    }
+  },
+  {
+    "group": "spark",
+    "name": "pyspark",
+    "className": "org.apache.zeppelin.spark.PySparkInterpreter",
+    "properties": {
+      "zeppelin.pyspark.python": {
+        "envName": "PYSPARK_PYTHON",
+        "propertyName": null,
+        "defaultValue": "python",
+        "description": "Python command to run pyspark with",
+        "type": "string"
+      },
+      "zeppelin.pyspark.useIPython": {
+        "envName": null,
+        "propertyName": "zeppelin.pyspark.useIPython",
+        "defaultValue": true,
+        "description": "whether use IPython when it is available",
+        "type": "checkbox"
+      }
+    },
+    "editor": {
+      "language": "python",
+      "editOnDblClick": false,
+      "completionKey": "TAB"
+    }
+  },
+  {
+    "group": "spark",
+    "name": "ipyspark",
+    "className": "org.apache.zeppelin.spark.IPySparkInterpreter",
+    "properties": {},
+    "editor": {
+      "language": "python",
+      "editOnDblClick": false
+    }
+  },
+  {
+    "group": "spark",
+    "name": "r",
+    "className": "org.apache.zeppelin.spark.SparkRInterpreter",
+    "properties": {
+      "zeppelin.R.knitr": {
+        "envName": "ZEPPELIN_R_KNITR",
+        "propertyName": "zeppelin.R.knitr",
+        "defaultValue": true,
+        "description": "whether use knitr or not",
+        "type": "checkbox"
+      },
+      "zeppelin.R.cmd": {
+        "envName": "ZEPPELIN_R_CMD",
+        "propertyName": "zeppelin.R.cmd",
+        "defaultValue": "R",
+        "description": "R repl path",
+        "type": "string"
+      },
+      "zeppelin.R.image.width": {
+        "envName": "ZEPPELIN_R_IMAGE_WIDTH",
+        "propertyName": "zeppelin.R.image.width",
+        "defaultValue": "100%",
+        "description": "",
+        "type": "number"
+      },
+      "zeppelin.R.render.options": {
+        "envName": "ZEPPELIN_R_RENDER_OPTIONS",
+        "propertyName": "zeppelin.R.render.options",
+        "defaultValue": "out.format = 'html', comment = NA, echo = FALSE, results = 'asis', message = F, warning = F, fig.retina = 2",
+        "description": "",
+        "type": "textarea"
+      }
+    },
+    "editor": {
+      "language": "r",
+      "editOnDblClick": false
+    }
+  }
+]

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/d762b528/spark/interpreter/src/main/resources/python/zeppelin_ipyspark.py
----------------------------------------------------------------------
diff --git a/spark/interpreter/src/main/resources/python/zeppelin_ipyspark.py b/spark/interpreter/src/main/resources/python/zeppelin_ipyspark.py
new file mode 100644
index 0000000..324f481
--- /dev/null
+++ b/spark/interpreter/src/main/resources/python/zeppelin_ipyspark.py
@@ -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.
+#
+
+
+from py4j.java_gateway import java_import, JavaGateway, GatewayClient
+from pyspark.conf import SparkConf
+from pyspark.context import SparkContext
+
+# for back compatibility
+from pyspark.sql import SQLContext
+
+# start JVM gateway
+client = GatewayClient(port=${JVM_GATEWAY_PORT})
+gateway = JavaGateway(client, auto_convert=True)
+
+java_import(gateway.jvm, "org.apache.spark.SparkEnv")
+java_import(gateway.jvm, "org.apache.spark.SparkConf")
+java_import(gateway.jvm, "org.apache.spark.api.java.*")
+java_import(gateway.jvm, "org.apache.spark.api.python.*")
+java_import(gateway.jvm, "org.apache.spark.mllib.api.python.*")
+
+intp = gateway.entry_point
+jsc = intp.getJavaSparkContext()
+
+java_import(gateway.jvm, "org.apache.spark.sql.*")
+java_import(gateway.jvm, "org.apache.spark.sql.hive.*")
+java_import(gateway.jvm, "scala.Tuple2")
+
+jconf = jsc.getConf()
+conf = SparkConf(_jvm=gateway.jvm, _jconf=jconf)
+sc = _zsc_ = SparkContext(jsc=jsc, gateway=gateway, conf=conf)
+
+if intp.isSpark2():
+    from pyspark.sql import SparkSession
+
+    spark = __zSpark__ = SparkSession(sc, intp.getSparkSession())
+    sqlContext = sqlc = __zSqlc__ = __zSpark__._wrapped
+else:
+    sqlContext = sqlc = __zSqlc__ = SQLContext(sparkContext=sc, sqlContext=intp.getSQLContext())

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/d762b528/spark/interpreter/src/main/resources/python/zeppelin_pyspark.py
----------------------------------------------------------------------
diff --git a/spark/interpreter/src/main/resources/python/zeppelin_pyspark.py b/spark/interpreter/src/main/resources/python/zeppelin_pyspark.py
new file mode 100644
index 0000000..c10855a
--- /dev/null
+++ b/spark/interpreter/src/main/resources/python/zeppelin_pyspark.py
@@ -0,0 +1,393 @@
+#
+# 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 os, sys, getopt, traceback, json, re
+
+from py4j.java_gateway import java_import, JavaGateway, GatewayClient
+from py4j.protocol import Py4JJavaError
+from pyspark.conf import SparkConf
+from pyspark.context import SparkContext
+import ast
+import warnings
+
+# for back compatibility
+from pyspark.sql import SQLContext, HiveContext, Row
+
+class Logger(object):
+  def __init__(self):
+    pass
+
+  def write(self, message):
+    intp.appendOutput(message)
+
+  def reset(self):
+    pass
+
+  def flush(self):
+    pass
+
+
+class PyZeppelinContext(dict):
+  def __init__(self, zc):
+    self.z = zc
+    self._displayhook = lambda *args: None
+
+  def show(self, obj):
+    from pyspark.sql import DataFrame
+    if isinstance(obj, DataFrame):
+      print(self.z.showData(obj._jdf))
+    else:
+      print(str(obj))
+
+  # By implementing special methods it makes operating on it more Pythonic
+  def __setitem__(self, key, item):
+    self.z.put(key, item)
+
+  def __getitem__(self, key):
+    return self.z.get(key)
+
+  def __delitem__(self, key):
+    self.z.remove(key)
+
+  def __contains__(self, item):
+    return self.z.containsKey(item)
+
+  def add(self, key, value):
+    self.__setitem__(key, value)
+
+  def put(self, key, value):
+    self.__setitem__(key, value)
+
+  def get(self, key):
+    return self.__getitem__(key)
+
+  def getInterpreterContext(self):
+    return self.z.getInterpreterContext()
+
+  def input(self, name, defaultValue=""):
+    return self.z.input(name, defaultValue)
+
+  def textbox(self, name, defaultValue=""):
+    return self.z.textbox(name, defaultValue)
+
+  def noteTextbox(self, name, defaultValue=""):
+    return self.z.noteTextbox(name, defaultValue)
+
+  def select(self, name, options, defaultValue=""):
+    # auto_convert to ArrayList doesn't match the method signature on JVM side
+    return self.z.select(name, defaultValue, self.getParamOptions(options))
+
+  def noteSelect(self, name, options, defaultValue=""):
+    return self.z.noteSelect(name, defaultValue, self.getParamOptions(options))
+
+  def checkbox(self, name, options, defaultChecked=None):
+    optionsIterable = self.getParamOptions(options)
+    defaultCheckedIterables = self.getDefaultChecked(defaultChecked)
+    checkedItems = gateway.jvm.scala.collection.JavaConversions.seqAsJavaList(self.z.checkbox(name, defaultCheckedIterables, optionsIterable))
+    result = []
+    for checkedItem in checkedItems:
+      result.append(checkedItem)
+    return result;
+
+  def noteCheckbox(self, name, options, defaultChecked=None):
+    optionsIterable = self.getParamOptions(options)
+    defaultCheckedIterables = self.getDefaultChecked(defaultChecked)
+    checkedItems = gateway.jvm.scala.collection.JavaConversions.seqAsJavaList(self.z.noteCheckbox(name, defaultCheckedIterables, optionsIterable))
+    result = []
+    for checkedItem in checkedItems:
+      result.append(checkedItem)
+    return result;
+
+  def getParamOptions(self, options):
+    tuples = list(map(lambda items: self.__tupleToScalaTuple2(items), options))
+    return gateway.jvm.scala.collection.JavaConversions.collectionAsScalaIterable(tuples)
+
+  def getDefaultChecked(self, defaultChecked):
+    if defaultChecked is None:
+      defaultChecked = []
+    return gateway.jvm.scala.collection.JavaConversions.collectionAsScalaIterable(defaultChecked)
+
+  def registerHook(self, event, cmd, replName=None):
+    if replName is None:
+      self.z.registerHook(event, cmd)
+    else:
+      self.z.registerHook(event, cmd, replName)
+
+  def unregisterHook(self, event, replName=None):
+    if replName is None:
+      self.z.unregisterHook(event)
+    else:
+      self.z.unregisterHook(event, replName)
+
+  def getHook(self, event, replName=None):
+    if replName is None:
+      return self.z.getHook(event)
+    return self.z.getHook(event, replName)
+
+  def _setup_matplotlib(self):
+    # If we don't have matplotlib installed don't bother continuing
+    try:
+      import matplotlib
+    except ImportError:
+      return
+    
+    # Make sure custom backends are available in the PYTHONPATH
+    rootdir = os.environ.get('ZEPPELIN_HOME', os.getcwd())
+    mpl_path = os.path.join(rootdir, 'interpreter', 'lib', 'python')
+    if mpl_path not in sys.path:
+      sys.path.append(mpl_path)
+    
+    # Finally check if backend exists, and if so configure as appropriate
+    try:
+      matplotlib.use('module://backend_zinline')
+      import backend_zinline
+      
+      # Everything looks good so make config assuming that we are using
+      # an inline backend
+      self._displayhook = backend_zinline.displayhook
+      self.configure_mpl(width=600, height=400, dpi=72, fontsize=10,
+                         interactive=True, format='png', context=self.z)
+    except ImportError:
+      # Fall back to Agg if no custom backend installed
+      matplotlib.use('Agg')
+      warnings.warn("Unable to load inline matplotlib backend, "
+                    "falling back to Agg")
+
+  def configure_mpl(self, **kwargs):
+    import mpl_config
+    mpl_config.configure(**kwargs)
+
+  def __tupleToScalaTuple2(self, tuple):
+    if (len(tuple) == 2):
+      return gateway.jvm.scala.Tuple2(tuple[0], tuple[1])
+    else:
+      raise IndexError("options must be a list of tuple of 2")
+
+
+class SparkVersion(object):
+  SPARK_1_4_0 = 10400
+  SPARK_1_3_0 = 10300
+  SPARK_2_0_0 = 20000
+
+  def __init__(self, versionNumber):
+    self.version = versionNumber
+
+  def isAutoConvertEnabled(self):
+    return self.version >= self.SPARK_1_4_0
+
+  def isImportAllPackageUnderSparkSql(self):
+    return self.version >= self.SPARK_1_3_0
+
+  def isSpark2(self):
+    return self.version >= self.SPARK_2_0_0
+
+class PySparkCompletion:
+  def __init__(self, interpreterObject):
+    self.interpreterObject = interpreterObject
+
+  def getGlobalCompletion(self):
+    objectDefList = []
+    try:
+      for completionItem in list(globals().keys()):
+        objectDefList.append(completionItem)
+    except:
+      return None
+    else:
+      return objectDefList
+
+  def getMethodCompletion(self, text_value):
+    execResult = locals()
+    if text_value == None:
+      return None
+    completion_target = text_value
+    try:
+      if len(completion_target) <= 0:
+        return None
+      if text_value[-1] == ".":
+        completion_target = text_value[:-1]
+      exec("{} = dir({})".format("objectDefList", completion_target), globals(), execResult)
+    except:
+      return None
+    else:
+      return list(execResult['objectDefList'])
+
+
+  def getCompletion(self, text_value):
+    completionList = set()
+
+    globalCompletionList = self.getGlobalCompletion()
+    if globalCompletionList != None:
+      for completionItem in list(globalCompletionList):
+        completionList.add(completionItem)
+
+    if text_value != None:
+      objectCompletionList = self.getMethodCompletion(text_value)
+      if objectCompletionList != None:
+        for completionItem in list(objectCompletionList):
+          completionList.add(completionItem)
+    if len(completionList) <= 0:
+      self.interpreterObject.setStatementsFinished("", False)
+    else:
+      result = json.dumps(list(filter(lambda x : not re.match("^__.*", x), list(completionList))))
+      self.interpreterObject.setStatementsFinished(result, False)
+
+client = GatewayClient(port=int(sys.argv[1]))
+sparkVersion = SparkVersion(int(sys.argv[2]))
+if sparkVersion.isSpark2():
+  from pyspark.sql import SparkSession
+else:
+  from pyspark.sql import SchemaRDD
+
+if sparkVersion.isAutoConvertEnabled():
+  gateway = JavaGateway(client, auto_convert = True)
+else:
+  gateway = JavaGateway(client)
+
+java_import(gateway.jvm, "org.apache.spark.SparkEnv")
+java_import(gateway.jvm, "org.apache.spark.SparkConf")
+java_import(gateway.jvm, "org.apache.spark.api.java.*")
+java_import(gateway.jvm, "org.apache.spark.api.python.*")
+java_import(gateway.jvm, "org.apache.spark.mllib.api.python.*")
+
+intp = gateway.entry_point
+output = Logger()
+sys.stdout = output
+sys.stderr = output
+intp.onPythonScriptInitialized(os.getpid())
+
+jsc = intp.getJavaSparkContext()
+
+if sparkVersion.isImportAllPackageUnderSparkSql():
+  java_import(gateway.jvm, "org.apache.spark.sql.*")
+  java_import(gateway.jvm, "org.apache.spark.sql.hive.*")
+else:
+  java_import(gateway.jvm, "org.apache.spark.sql.SQLContext")
+  java_import(gateway.jvm, "org.apache.spark.sql.hive.HiveContext")
+  java_import(gateway.jvm, "org.apache.spark.sql.hive.LocalHiveContext")
+  java_import(gateway.jvm, "org.apache.spark.sql.hive.TestHiveContext")
+
+
+java_import(gateway.jvm, "scala.Tuple2")
+
+_zcUserQueryNameSpace = {}
+
+jconf = intp.getSparkConf()
+conf = SparkConf(_jvm = gateway.jvm, _jconf = jconf)
+sc = _zsc_ = SparkContext(jsc=jsc, gateway=gateway, conf=conf)
+_zcUserQueryNameSpace["_zsc_"] = _zsc_
+_zcUserQueryNameSpace["sc"] = sc
+
+if sparkVersion.isSpark2():
+  spark = __zSpark__ = SparkSession(sc, intp.getSparkSession())
+  sqlc = __zSqlc__ = __zSpark__._wrapped
+  _zcUserQueryNameSpace["sqlc"] = sqlc
+  _zcUserQueryNameSpace["__zSqlc__"] = __zSqlc__
+  _zcUserQueryNameSpace["spark"] = spark
+  _zcUserQueryNameSpace["__zSpark__"] = __zSpark__
+else:
+  sqlc = __zSqlc__ = SQLContext(sparkContext=sc, sqlContext=intp.getSQLContext())
+  _zcUserQueryNameSpace["sqlc"] = sqlc
+  _zcUserQueryNameSpace["__zSqlc__"] = sqlc
+
+sqlContext = __zSqlc__
+_zcUserQueryNameSpace["sqlContext"] = sqlContext
+
+completion = __zeppelin_completion__ = PySparkCompletion(intp)
+_zcUserQueryNameSpace["completion"] = completion
+_zcUserQueryNameSpace["__zeppelin_completion__"] = __zeppelin_completion__
+
+z = __zeppelin__ = PyZeppelinContext(intp.getZeppelinContext())
+__zeppelin__._setup_matplotlib()
+_zcUserQueryNameSpace["z"] = z
+_zcUserQueryNameSpace["__zeppelin__"] = __zeppelin__
+
+while True :
+  req = intp.getStatements()
+  try:
+    stmts = req.statements().split("\n")
+    jobGroup = req.jobGroup()
+    jobDesc = req.jobDescription()
+    
+    # Get post-execute hooks
+    try:
+      global_hook = intp.getHook('post_exec_dev')
+    except:
+      global_hook = None
+      
+    try:
+      user_hook = __zeppelin__.getHook('post_exec')
+    except:
+      user_hook = None
+      
+    nhooks = 0
+    for hook in (global_hook, user_hook):
+      if hook:
+        nhooks += 1
+
+    if stmts:
+      # use exec mode to compile the statements except the last statement,
+      # so that the last statement's evaluation will be printed to stdout
+      sc.setJobGroup(jobGroup, jobDesc)
+      code = compile('\n'.join(stmts), '<stdin>', 'exec', ast.PyCF_ONLY_AST, 1)
+      to_run_hooks = []
+      if (nhooks > 0):
+        to_run_hooks = code.body[-nhooks:]
+      to_run_exec, to_run_single = (code.body[:-(nhooks + 1)],
+                                    [code.body[-(nhooks + 1)]])
+
+      try:
+        for node in to_run_exec:
+          mod = ast.Module([node])
+          code = compile(mod, '<stdin>', 'exec')
+          exec(code, _zcUserQueryNameSpace)
+
+        for node in to_run_single:
+          mod = ast.Interactive([node])
+          code = compile(mod, '<stdin>', 'single')
+          exec(code, _zcUserQueryNameSpace)
+          
+        for node in to_run_hooks:
+          mod = ast.Module([node])
+          code = compile(mod, '<stdin>', 'exec')
+          exec(code, _zcUserQueryNameSpace)
+
+        intp.setStatementsFinished("", False)
+      except Py4JJavaError:
+        # raise it to outside try except
+        raise
+      except:
+        exception = traceback.format_exc()
+        m = re.search("File \"<stdin>\", line (\d+).*", exception)
+        if m:
+          line_no = int(m.group(1))
+          intp.setStatementsFinished(
+            "Fail to execute line {}: {}\n".format(line_no, stmts[line_no - 1]) + exception, True)
+        else:
+          intp.setStatementsFinished(exception, True)
+    else:
+      intp.setStatementsFinished("", False)
+
+  except Py4JJavaError:
+    excInnerError = traceback.format_exc() # format_tb() does not return the inner exception
+    innerErrorStart = excInnerError.find("Py4JJavaError:")
+    if innerErrorStart > -1:
+       excInnerError = excInnerError[innerErrorStart:]
+    intp.setStatementsFinished(excInnerError + str(sys.exc_info()), True)
+  except:
+    intp.setStatementsFinished(traceback.format_exc(), True)
+
+  output.reset()

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/d762b528/spark/interpreter/src/main/scala/org/apache/spark/SparkRBackend.scala
----------------------------------------------------------------------
diff --git a/spark/interpreter/src/main/scala/org/apache/spark/SparkRBackend.scala b/spark/interpreter/src/main/scala/org/apache/spark/SparkRBackend.scala
new file mode 100644
index 0000000..05f1ac0
--- /dev/null
+++ b/spark/interpreter/src/main/scala/org/apache/spark/SparkRBackend.scala
@@ -0,0 +1,54 @@
+/*
+ * 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.spark
+
+import org.apache.spark.api.r.RBackend
+
+object SparkRBackend {
+  val backend : RBackend = new RBackend()
+  private var started = false;
+  private var portNumber = 0;
+
+  val backendThread : Thread = new Thread("SparkRBackend") {
+    override def run() {
+      backend.run()
+    }
+  }
+
+  def init() : Int = {
+    portNumber = backend.init()
+    portNumber
+  }
+
+  def start() : Unit = {
+    backendThread.start()
+    started = true
+  }
+
+  def close() : Unit = {
+    backend.close()
+    backendThread.join()
+  }
+
+  def isStarted() : Boolean = {
+    started
+  }
+
+  def port(): Int = {
+    return portNumber
+  }
+}

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/d762b528/spark/interpreter/src/main/scala/org/apache/zeppelin/spark/ZeppelinRDisplay.scala
----------------------------------------------------------------------
diff --git a/spark/interpreter/src/main/scala/org/apache/zeppelin/spark/ZeppelinRDisplay.scala b/spark/interpreter/src/main/scala/org/apache/zeppelin/spark/ZeppelinRDisplay.scala
new file mode 100644
index 0000000..a9014c2
--- /dev/null
+++ b/spark/interpreter/src/main/scala/org/apache/zeppelin/spark/ZeppelinRDisplay.scala
@@ -0,0 +1,117 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.zeppelin.spark
+
+import org.apache.zeppelin.interpreter.InterpreterResult.Code
+import org.apache.zeppelin.interpreter.InterpreterResult.Code.{SUCCESS}
+import org.apache.zeppelin.interpreter.InterpreterResult.Type
+import org.apache.zeppelin.interpreter.InterpreterResult.Type.{TEXT, HTML, TABLE, IMG}
+import org.jsoup.Jsoup
+import org.jsoup.nodes.Element
+import org.jsoup.nodes.Document.OutputSettings
+import org.jsoup.safety.Whitelist
+
+import scala.collection.JavaConversions._
+import scala.util.matching.Regex
+
+case class RDisplay(content: String, `type`: Type, code: Code)
+
+object ZeppelinRDisplay {
+
+  val pattern = new Regex("""^ *\[\d*\] """)
+
+  def render(html: String, imageWidth: String): RDisplay = {
+
+    val document = Jsoup.parse(html)
+    document.outputSettings().prettyPrint(false)
+
+    val body = document.body()
+
+    if (body.getElementsByTag("p").isEmpty) return RDisplay(body.html(), HTML, SUCCESS)
+
+    val bodyHtml = body.html()
+
+    if (! bodyHtml.contains("<img")
+      &&  ! bodyHtml.contains("<script")
+      && ! bodyHtml.contains("%html ")
+      && ! bodyHtml.contains("%table ")
+      && ! bodyHtml.contains("%img ")
+    ) {
+      return textDisplay(body)
+    }
+
+    if (bodyHtml.contains("%table")) {
+      return tableDisplay(body)
+    }
+
+    if (bodyHtml.contains("%img")) {
+      return imgDisplay(body)
+    }
+
+    return htmlDisplay(body, imageWidth)
+  }
+
+  private def textDisplay(body: Element): RDisplay = {
+    // remove HTML tag while preserving whitespaces and newlines
+    val text = Jsoup.clean(body.html(), "",
+      Whitelist.none(), new OutputSettings().prettyPrint(false))
+    RDisplay(text, TEXT, SUCCESS)
+  }
+
+  private def tableDisplay(body: Element): RDisplay = {
+    val p = body.getElementsByTag("p").first().html.replace("“%table " , "").replace("”", "")
+    val r = (pattern findFirstIn p).getOrElse("")
+    val table = p.replace(r, "").replace("\\t", "\t").replace("\\n", "\n")
+    RDisplay(table, TABLE, SUCCESS)
+  }
+
+  private def imgDisplay(body: Element): RDisplay = {
+    val p = body.getElementsByTag("p").first().html.replace("“%img " , "").replace("”", "")
+    val r = (pattern findFirstIn p).getOrElse("")
+    val img = p.replace(r, "")
+    RDisplay(img, IMG, SUCCESS)
+  }
+
+  private def htmlDisplay(body: Element, imageWidth: String): RDisplay = {
+    var div = new String()
+
+    for (element <- body.children) {
+
+      val eHtml = element.html()
+      var eOuterHtml = element.outerHtml()
+
+      eOuterHtml = eOuterHtml.replace("“%html " , "").replace("”", "")
+
+      val r = (pattern findFirstIn eHtml).getOrElse("")
+
+      div = div + eOuterHtml.replace(r, "")
+    }
+
+    val content =  div
+      .replaceAll("src=\"//", "src=\"http://")
+      .replaceAll("href=\"//", "href=\"http://")
+
+    body.html(content)
+
+    for (image <- body.getElementsByTag("img")) {
+      image.attr("width", imageWidth)
+    }
+
+    RDisplay(body.html, HTML, SUCCESS)
+  }
+}

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/d762b528/spark/interpreter/src/main/scala/org/apache/zeppelin/spark/utils/DisplayUtils.scala
----------------------------------------------------------------------
diff --git a/spark/interpreter/src/main/scala/org/apache/zeppelin/spark/utils/DisplayUtils.scala b/spark/interpreter/src/main/scala/org/apache/zeppelin/spark/utils/DisplayUtils.scala
new file mode 100644
index 0000000..8181434
--- /dev/null
+++ b/spark/interpreter/src/main/scala/org/apache/zeppelin/spark/utils/DisplayUtils.scala
@@ -0,0 +1,90 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.zeppelin.spark.utils
+
+import java.lang.StringBuilder
+
+import org.apache.spark.rdd.RDD
+
+import scala.collection.IterableLike
+
+object DisplayUtils {
+
+  implicit def toDisplayRDDFunctions[T <: Product](rdd: RDD[T]): DisplayRDDFunctions[T] = new DisplayRDDFunctions[T](rdd)
+
+  implicit def toDisplayTraversableFunctions[T <: Product](traversable: Traversable[T]): DisplayTraversableFunctions[T] = new DisplayTraversableFunctions[T](traversable)
+
+  def html(htmlContent: String = "") = s"%html $htmlContent"
+
+  def img64(base64Content: String = "") = s"%img $base64Content"
+
+  def img(url: String) = s"<img src='$url' />"
+}
+
+trait DisplayCollection[T <: Product] {
+
+  def printFormattedData(traversable: Traversable[T], columnLabels: String*): Unit = {
+    val providedLabelCount: Int = columnLabels.size
+    var maxColumnCount:Int = 1
+    val headers = new StringBuilder("%table ")
+
+    val data = new StringBuilder("")
+
+    traversable.foreach(tuple => {
+      maxColumnCount = math.max(maxColumnCount,tuple.productArity)
+      data.append(tuple.productIterator.mkString("\t")).append("\n")
+    })
+
+    if (providedLabelCount > maxColumnCount) {
+      headers.append(columnLabels.take(maxColumnCount).mkString("\t")).append("\n")
+    } else if (providedLabelCount < maxColumnCount) {
+      val missingColumnHeaders = ((providedLabelCount+1) to maxColumnCount).foldLeft[String](""){
+        (stringAccumulator,index) =>  if (index==1) s"Column$index" else s"$stringAccumulator\tColumn$index"
+      }
+
+      headers.append(columnLabels.mkString("\t")).append(missingColumnHeaders).append("\n")
+    } else {
+      headers.append(columnLabels.mkString("\t")).append("\n")
+    }
+
+    headers.append(data)
+
+    print(headers.toString)
+  }
+
+}
+
+class DisplayRDDFunctions[T <: Product] (val rdd: RDD[T]) extends DisplayCollection[T] {
+
+  def display(columnLabels: String*)(implicit sparkMaxResult: SparkMaxResult): Unit = {
+    printFormattedData(rdd.take(sparkMaxResult.maxResult), columnLabels: _*)
+  }
+
+  def display(sparkMaxResult:Int, columnLabels: String*): Unit = {
+    printFormattedData(rdd.take(sparkMaxResult), columnLabels: _*)
+  }
+}
+
+class DisplayTraversableFunctions[T <: Product] (val traversable: Traversable[T]) extends DisplayCollection[T] {
+
+  def display(columnLabels: String*): Unit = {
+    printFormattedData(traversable, columnLabels: _*)
+  }
+}
+
+class SparkMaxResult(val maxResult: Int) extends Serializable

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/d762b528/spark/interpreter/src/test/java/org/apache/zeppelin/spark/DepInterpreterTest.java
----------------------------------------------------------------------
diff --git a/spark/interpreter/src/test/java/org/apache/zeppelin/spark/DepInterpreterTest.java b/spark/interpreter/src/test/java/org/apache/zeppelin/spark/DepInterpreterTest.java
new file mode 100644
index 0000000..e177d49
--- /dev/null
+++ b/spark/interpreter/src/test/java/org/apache/zeppelin/spark/DepInterpreterTest.java
@@ -0,0 +1,94 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.zeppelin.spark;
+
+import static org.junit.Assert.assertEquals;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.Properties;
+
+import org.apache.zeppelin.display.AngularObjectRegistry;
+import org.apache.zeppelin.user.AuthenticationInfo;
+import org.apache.zeppelin.display.GUI;
+import org.apache.zeppelin.interpreter.*;
+import org.apache.zeppelin.interpreter.InterpreterResult.Code;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+
+public class DepInterpreterTest {
+
+  @Rule
+  public TemporaryFolder tmpDir = new TemporaryFolder();
+
+  private DepInterpreter dep;
+  private InterpreterContext context;
+
+  private Properties getTestProperties() throws IOException {
+    Properties p = new Properties();
+    p.setProperty("zeppelin.dep.localrepo", tmpDir.newFolder().getAbsolutePath());
+    p.setProperty("zeppelin.dep.additionalRemoteRepository", "spark-packages,http://dl.bintray.com/spark-packages/maven,false;");
+    return p;
+  }
+
+  @Before
+  public void setUp() throws Exception {
+    Properties p = getTestProperties();
+
+    dep = new DepInterpreter(p);
+    dep.open();
+
+    InterpreterGroup intpGroup = new InterpreterGroup();
+    intpGroup.put("note", new LinkedList<Interpreter>());
+    intpGroup.get("note").add(new SparkInterpreter(p));
+    intpGroup.get("note").add(dep);
+    dep.setInterpreterGroup(intpGroup);
+
+    context = new InterpreterContext("note", "id", null, "title", "text", new AuthenticationInfo(),
+        new HashMap<String, Object>(), new GUI(), new GUI(),
+        new AngularObjectRegistry(intpGroup.getId(), null),
+        null,
+        new LinkedList<InterpreterContextRunner>(), null);
+  }
+
+  @After
+  public void tearDown() throws Exception {
+    dep.close();
+  }
+
+  @Test
+  public void testDefault() {
+    dep.getDependencyContext().reset();
+    InterpreterResult ret = dep.interpret("z.load(\"org.apache.commons:commons-csv:1.1\")", context);
+    assertEquals(Code.SUCCESS, ret.code());
+
+    assertEquals(1, dep.getDependencyContext().getFiles().size());
+    assertEquals(1, dep.getDependencyContext().getFilesDist().size());
+
+    // Add a test for the spark-packages repo - default in additionalRemoteRepository
+    ret = dep.interpret("z.load(\"amplab:spark-indexedrdd:0.3\")", context);
+    assertEquals(Code.SUCCESS, ret.code());
+
+    // Reset at the end of the test
+    dep.getDependencyContext().reset();
+  }
+}

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/d762b528/spark/interpreter/src/test/java/org/apache/zeppelin/spark/IPySparkInterpreterTest.java
----------------------------------------------------------------------
diff --git a/spark/interpreter/src/test/java/org/apache/zeppelin/spark/IPySparkInterpreterTest.java b/spark/interpreter/src/test/java/org/apache/zeppelin/spark/IPySparkInterpreterTest.java
new file mode 100644
index 0000000..765237c
--- /dev/null
+++ b/spark/interpreter/src/test/java/org/apache/zeppelin/spark/IPySparkInterpreterTest.java
@@ -0,0 +1,204 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.zeppelin.spark;
+
+
+import com.google.common.io.Files;
+import org.apache.zeppelin.display.GUI;
+import org.apache.zeppelin.interpreter.Interpreter;
+import org.apache.zeppelin.interpreter.InterpreterContext;
+import org.apache.zeppelin.interpreter.InterpreterException;
+import org.apache.zeppelin.interpreter.InterpreterGroup;
+import org.apache.zeppelin.interpreter.InterpreterOutput;
+import org.apache.zeppelin.interpreter.InterpreterResult;
+import org.apache.zeppelin.interpreter.InterpreterResultMessage;
+import org.apache.zeppelin.interpreter.thrift.InterpreterCompletion;
+import org.apache.zeppelin.python.IPythonInterpreterTest;
+import org.apache.zeppelin.user.AuthenticationInfo;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Properties;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+public class IPySparkInterpreterTest {
+
+  private IPySparkInterpreter iPySparkInterpreter;
+  private InterpreterGroup intpGroup;
+
+  @Before
+  public void setup() throws InterpreterException {
+    Properties p = new Properties();
+    p.setProperty("spark.master", "local[4]");
+    p.setProperty("master", "local[4]");
+    p.setProperty("spark.submit.deployMode", "client");
+    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");
+    p.setProperty("zeppelin.pyspark.python", "python");
+    p.setProperty("zeppelin.dep.localrepo", Files.createTempDir().getAbsolutePath());
+
+    intpGroup = new InterpreterGroup();
+    intpGroup.put("session_1", new LinkedList<Interpreter>());
+
+    SparkInterpreter sparkInterpreter = new SparkInterpreter(p);
+    intpGroup.get("session_1").add(sparkInterpreter);
+    sparkInterpreter.setInterpreterGroup(intpGroup);
+    sparkInterpreter.open();
+
+    iPySparkInterpreter = new IPySparkInterpreter(p);
+    intpGroup.get("session_1").add(iPySparkInterpreter);
+    iPySparkInterpreter.setInterpreterGroup(intpGroup);
+    iPySparkInterpreter.open();
+  }
+
+
+  @After
+  public void tearDown() throws InterpreterException {
+    if (iPySparkInterpreter != null) {
+      iPySparkInterpreter.close();
+    }
+  }
+
+  @Test
+  public void testBasics() throws InterruptedException, IOException, InterpreterException {
+    // all the ipython test should pass too.
+    IPythonInterpreterTest.testInterpreter(iPySparkInterpreter);
+
+    // rdd
+    InterpreterContext context = getInterpreterContext();
+    InterpreterResult result = iPySparkInterpreter.interpret("sc.range(1,10).sum()", context);
+    Thread.sleep(100);
+    assertEquals(InterpreterResult.Code.SUCCESS, result.code());
+    List<InterpreterResultMessage> interpreterResultMessages = context.out.getInterpreterResultMessages();
+    assertEquals("45", interpreterResultMessages.get(0).getData());
+
+    context = getInterpreterContext();
+    result = iPySparkInterpreter.interpret("sc.version", context);
+    Thread.sleep(100);
+    assertEquals(InterpreterResult.Code.SUCCESS, result.code());
+    interpreterResultMessages = context.out.getInterpreterResultMessages();
+    // spark sql
+    context = getInterpreterContext();
+    if (interpreterResultMessages.get(0).getData().startsWith("'1.") ||
+        interpreterResultMessages.get(0).getData().startsWith("u'1.")) {
+      result = iPySparkInterpreter.interpret("df = sqlContext.createDataFrame([(1,'a'),(2,'b')])\ndf.show()", context);
+      assertEquals(InterpreterResult.Code.SUCCESS, result.code());
+      interpreterResultMessages = context.out.getInterpreterResultMessages();
+      assertEquals(
+          "+---+---+\n" +
+              "| _1| _2|\n" +
+              "+---+---+\n" +
+              "|  1|  a|\n" +
+              "|  2|  b|\n" +
+              "+---+---+\n\n", interpreterResultMessages.get(0).getData());
+    } else {
+      result = iPySparkInterpreter.interpret("df = spark.createDataFrame([(1,'a'),(2,'b')])\ndf.show()", context);
+      assertEquals(InterpreterResult.Code.SUCCESS, result.code());
+      interpreterResultMessages = context.out.getInterpreterResultMessages();
+      assertEquals(
+          "+---+---+\n" +
+              "| _1| _2|\n" +
+              "+---+---+\n" +
+              "|  1|  a|\n" +
+              "|  2|  b|\n" +
+              "+---+---+\n\n", interpreterResultMessages.get(0).getData());
+    }
+
+    // cancel
+    final InterpreterContext context2 = getInterpreterContext();
+
+    Thread thread = new Thread() {
+      @Override
+      public void run() {
+        InterpreterResult result = iPySparkInterpreter.interpret("import time\nsc.range(1,10).foreach(lambda x: time.sleep(1))", context2);
+        assertEquals(InterpreterResult.Code.ERROR, result.code());
+        List<InterpreterResultMessage> interpreterResultMessages = null;
+        try {
+          interpreterResultMessages = context2.out.getInterpreterResultMessages();
+          assertTrue(interpreterResultMessages.get(0).getData().contains("KeyboardInterrupt"));
+        } catch (IOException e) {
+          e.printStackTrace();
+        }
+      }
+    };
+    thread.start();
+
+    // sleep 1 second to wait for the spark job starts
+    Thread.sleep(1000);
+    iPySparkInterpreter.cancel(context);
+    thread.join();
+
+    // completions
+    List<InterpreterCompletion> completions = iPySparkInterpreter.completion("sc.ran", 6, getInterpreterContext());
+    assertEquals(1, completions.size());
+    assertEquals("range", completions.get(0).getValue());
+
+    // pyspark streaming
+
+    Class klass = py4j.GatewayServer.class;
+    URL location = klass.getResource('/' + klass.getName().replace('.', '/') + ".class");
+    System.out.println("py4j location: " + location);
+    context = getInterpreterContext();
+    result = iPySparkInterpreter.interpret(
+        "from pyspark.streaming import StreamingContext\n" +
+            "import time\n" +
+            "ssc = StreamingContext(sc, 1)\n" +
+            "rddQueue = []\n" +
+            "for i in range(5):\n" +
+            "    rddQueue += [ssc.sparkContext.parallelize([j for j in range(1, 1001)], 10)]\n" +
+            "inputStream = ssc.queueStream(rddQueue)\n" +
+            "mappedStream = inputStream.map(lambda x: (x % 10, 1))\n" +
+            "reducedStream = mappedStream.reduceByKey(lambda a, b: a + b)\n" +
+            "reducedStream.pprint()\n" +
+            "ssc.start()\n" +
+            "time.sleep(6)\n" +
+            "ssc.stop(stopSparkContext=False, stopGraceFully=True)", context);
+    Thread.sleep(1000);
+    assertEquals(InterpreterResult.Code.SUCCESS, result.code());
+    interpreterResultMessages = context.out.getInterpreterResultMessages();
+    assertEquals(1, interpreterResultMessages.size());
+//    assertTrue(interpreterResultMessages.get(0).getData().contains("(0, 100)"));
+  }
+
+  private InterpreterContext getInterpreterContext() {
+    return new InterpreterContext(
+        "noteId",
+        "paragraphId",
+        "replName",
+        "paragraphTitle",
+        "paragraphText",
+        new AuthenticationInfo(),
+        new HashMap<String, Object>(),
+        new GUI(),
+        new GUI(),
+        null,
+        null,
+        null,
+        new InterpreterOutput(null));
+  }
+}