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/06/27 05:04:58 UTC

zeppelin git commit: ZEPPELIN-3348. Enable paragraph level properties

Repository: zeppelin
Updated Branches:
  refs/heads/master 7e028903c -> 5d8803149


ZEPPELIN-3348. Enable paragraph level properties

### What is this PR for?
This PR is trying to introduce paragraph level properties so that user can customize the interpreter behavior in paragraph level.  User can specify the paragraph level properties after the repl name (e.g. `%spark(pool=p1, imageWidth=200)`)

The jdbc interpreter is another example (like `%jdbc(hive)`, but we use other kind of hack method for that before. This PR also update jdbc interpreter to adopt the paragraph level properties.

This PR just allow user to specify paragraph level properties and pass them to interpreter. It is interpreter's responsibility to use these paragraph level properties. So there will be some follow up work to customize interpreter at paragraph level. E.g. allow spark interpreter to specify the queue for paragraph.

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

### Todos
* [ ] - Task

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

### How should this be tested?
* CI pass

### 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 #3039 from zjffdu/ZEPPELIN-3348 and squashes the following commits:

7c9e65422 [Jeff Zhang] ZEPPELIN-3348. Enable paragraph level properties


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

Branch: refs/heads/master
Commit: 5d8803149a9993a1d19f23aa55caf5346e7018d3
Parents: 7e02890
Author: Jeff Zhang <zj...@apache.org>
Authored: Thu Jun 21 14:04:40 2018 +0800
Committer: Jeff Zhang <zj...@apache.org>
Committed: Wed Jun 27 13:04:27 2018 +0800

----------------------------------------------------------------------
 .../apache/zeppelin/jdbc/JDBCInterpreter.java   |  33 ++--
 .../zeppelin/jdbc/JDBCInterpreterTest.java      |  74 +++++---
 .../interpreter/InterpreterContext.java         |   9 +
 .../remote/RemoteInterpreterServer.java         |  28 +---
 .../interpreter/thrift/AngularObjectId.java     |   2 +-
 .../thrift/AppOutputAppendEvent.java            |   2 +-
 .../thrift/AppOutputUpdateEvent.java            |   2 +-
 .../thrift/AppStatusUpdateEvent.java            |   2 +-
 .../thrift/InterpreterCompletion.java           |   2 +-
 .../interpreter/thrift/OutputAppendEvent.java   |   2 +-
 .../thrift/OutputUpdateAllEvent.java            |   2 +-
 .../interpreter/thrift/OutputUpdateEvent.java   |   2 +-
 .../interpreter/thrift/RegisterInfo.java        |   2 +-
 .../thrift/RemoteApplicationResult.java         |   2 +-
 .../thrift/RemoteInterpreterContext.java        | 167 ++++++++++++++++++-
 .../thrift/RemoteInterpreterEvent.java          |   2 +-
 .../thrift/RemoteInterpreterEventService.java   |   2 +-
 .../thrift/RemoteInterpreterResult.java         |  38 ++---
 .../thrift/RemoteInterpreterResultMessage.java  |   2 +-
 .../thrift/RemoteInterpreterService.java        | 114 ++++++-------
 .../interpreter/thrift/RunParagraphsEvent.java  |   2 +-
 .../ZeppelinServerResourceParagraphRunner.java  |   2 +-
 .../main/thrift/RemoteInterpreterService.thrift |   1 +
 .../zeppelin/rest/ZeppelinSparkClusterTest.java |   6 +
 .../interpreter/remote/RemoteInterpreter.java   |   3 +-
 .../org/apache/zeppelin/notebook/Paragraph.java |  38 ++++-
 .../apache/zeppelin/notebook/ParagraphTest.java |  42 +++++
 27 files changed, 411 insertions(+), 172 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/zeppelin/blob/5d880314/jdbc/src/main/java/org/apache/zeppelin/jdbc/JDBCInterpreter.java
----------------------------------------------------------------------
diff --git a/jdbc/src/main/java/org/apache/zeppelin/jdbc/JDBCInterpreter.java b/jdbc/src/main/java/org/apache/zeppelin/jdbc/JDBCInterpreter.java
index 7aae644..c0c48aa 100644
--- a/jdbc/src/main/java/org/apache/zeppelin/jdbc/JDBCInterpreter.java
+++ b/jdbc/src/main/java/org/apache/zeppelin/jdbc/JDBCInterpreter.java
@@ -48,6 +48,7 @@ import java.util.Arrays;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Map;
 import java.util.Properties;
 import java.util.Set;
 import java.util.concurrent.ExecutorService;
@@ -787,12 +788,7 @@ public class JDBCInterpreter extends KerberosInterpreter {
     String cmd = Boolean.parseBoolean(getProperty("zeppelin.jdbc.interpolation")) ?
             interpolate(originalCmd, contextInterpreter.getResourcePool()) : originalCmd;
     logger.debug("Run SQL command '{}'", cmd);
-    String propertyKey = getPropertyKey(cmd);
-
-    if (null != propertyKey && !propertyKey.equals(DEFAULT_KEY)) {
-      cmd = cmd.substring(propertyKey.length() + 2);
-    }
-
+    String propertyKey = getPropertyKey(contextInterpreter);
     cmd = cmd.trim();
     logger.debug("PropertyKey: {}, SQL command: '{}'", propertyKey, cmd);
     return executeSql(propertyKey, cmd, contextInterpreter);
@@ -811,20 +807,19 @@ public class JDBCInterpreter extends KerberosInterpreter {
     }
   }
 
-  public String getPropertyKey(String cmd) {
-    boolean firstLineIndex = cmd.startsWith("(");
-
-    if (firstLineIndex) {
-      int configStartIndex = cmd.indexOf("(");
-      int configLastIndex = cmd.indexOf(")");
-      if (configStartIndex != -1 && configLastIndex != -1) {
-        return cmd.substring(configStartIndex + 1, configLastIndex);
-      } else {
-        return null;
+  public String getPropertyKey(InterpreterContext interpreterContext) {
+    Map<String, String> localProperties = interpreterContext.getLocalProperties();
+    // It is recommended to use this kind of format: %jdbc(db=mysql)
+    if (localProperties.containsKey("db")) {
+      return localProperties.get("db");
+    }
+    // %jdbc(mysql) is only for backward compatibility
+    for (Map.Entry<String, String> entry : localProperties.entrySet()) {
+      if (entry.getKey().equals(entry.getValue())) {
+        return entry.getKey();
       }
-    } else {
-      return DEFAULT_KEY;
     }
+    return DEFAULT_KEY;
   }
 
   @Override
@@ -850,7 +845,7 @@ public class JDBCInterpreter extends KerberosInterpreter {
   public List<InterpreterCompletion> completion(String buf, int cursor,
       InterpreterContext interpreterContext) throws InterpreterException {
     List<InterpreterCompletion> candidates = new ArrayList<>();
-    String propertyKey = getPropertyKey(buf);
+    String propertyKey = getPropertyKey(interpreterContext);
     String sqlCompleterKey =
         String.format("%s.%s", interpreterContext.getAuthenticationInfo().getUser(), propertyKey);
     SqlCompleter sqlCompleter = sqlCompletersMap.get(sqlCompleterKey);

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/5d880314/jdbc/src/test/java/org/apache/zeppelin/jdbc/JDBCInterpreterTest.java
----------------------------------------------------------------------
diff --git a/jdbc/src/test/java/org/apache/zeppelin/jdbc/JDBCInterpreterTest.java b/jdbc/src/test/java/org/apache/zeppelin/jdbc/JDBCInterpreterTest.java
index 5ce8d6e..62f6550 100644
--- a/jdbc/src/test/java/org/apache/zeppelin/jdbc/JDBCInterpreterTest.java
+++ b/jdbc/src/test/java/org/apache/zeppelin/jdbc/JDBCInterpreterTest.java
@@ -43,7 +43,9 @@ import java.sql.DriverManager;
 import java.sql.PreparedStatement;
 import java.sql.SQLException;
 import java.sql.Statement;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 import java.util.Properties;
 
 import com.mockrunner.jdbc.BasicJDBCTestCaseAdapter;
@@ -107,28 +109,27 @@ public class JDBCInterpreterTest extends BasicJDBCTestCaseAdapter {
 
 
   @Test
-  public void testForParsePropertyKey() throws IOException {
+  public void testForParsePropertyKey() {
     JDBCInterpreter t = new JDBCInterpreter(new Properties());
+    Map<String, String> localProperties = new HashMap<>();
+    InterpreterContext interpreterContext = InterpreterContext.builder()
+        .setLocalProperties(localProperties)
+        .build();
+    assertEquals(JDBCInterpreter.DEFAULT_KEY, t.getPropertyKey(interpreterContext));
 
-    assertEquals(t.getPropertyKey("(fake) select max(cant) from test_table where id >= 2452640"),
-        "fake");
-
-    assertEquals(t.getPropertyKey("() select max(cant) from test_table where id >= 2452640"),
-        "");
-
-    assertEquals(t.getPropertyKey(")fake( select max(cant) from test_table where id >= 2452640"),
-        "default");
-
-    // when you use a %jdbc(prefix1), prefix1 is the propertyKey as form part of the cmd string
-    assertEquals(t.getPropertyKey(
-            "(prefix1)\n select max(cant) from test_table where id >= 2452640"), "prefix1");
-
-    assertEquals(t.getPropertyKey("(prefix2) select max(cant) from test_table where id >= 2452640"),
-            "prefix2");
+    localProperties = new HashMap<>();
+    localProperties.put("db", "mysql");
+    interpreterContext = InterpreterContext.builder()
+        .setLocalProperties(localProperties)
+        .build();
+    assertEquals("mysql", t.getPropertyKey(interpreterContext));
 
-    // when you use a %jdbc, prefix is the default
-    assertEquals(t.getPropertyKey("select max(cant) from test_table where id >= 2452640"),
-            "default");
+    localProperties = new HashMap<>();
+    localProperties.put("hive", "hive");
+    interpreterContext = InterpreterContext.builder()
+        .setLocalProperties(localProperties)
+        .build();
+    assertEquals("hive", t.getPropertyKey(interpreterContext));
   }
 
   @Test
@@ -143,9 +144,14 @@ public class JDBCInterpreterTest extends BasicJDBCTestCaseAdapter {
     JDBCInterpreter t = new JDBCInterpreter(properties);
     t.open();
 
-    String sqlQuery = "(fake) select * from test_table";
-
-    InterpreterResult interpreterResult = t.interpret(sqlQuery, interpreterContext);
+    String sqlQuery = "select * from test_table";
+    Map<String, String> localProperties = new HashMap<>();
+    localProperties.put("db", "fake");
+    InterpreterContext context = InterpreterContext.builder()
+        .setAuthenticationInfo(new AuthenticationInfo("testUser"))
+        .setLocalProperties(localProperties)
+        .build();
+    InterpreterResult interpreterResult = t.interpret(sqlQuery, context);
 
     // if prefix not found return ERROR and Prefix not found.
     assertEquals(InterpreterResult.Code.ERROR, interpreterResult.code());
@@ -539,11 +545,18 @@ public class JDBCInterpreterTest extends BasicJDBCTestCaseAdapter {
             "create table test_precode_2 (id int); insert into test_precode_2 values (2);");
     JDBCInterpreter jdbcInterpreter = new JDBCInterpreter(properties);
     jdbcInterpreter.open();
-    jdbcInterpreter.executePrecode(interpreterContext);
 
-    String sqlQuery = "(anotherPrefix) select *from test_precode_2";
+    Map<String, String> localProperties = new HashMap<>();
+    localProperties.put("db", "anotherPrefix");
+    InterpreterContext context = InterpreterContext.builder()
+        .setAuthenticationInfo(new AuthenticationInfo("testUser"))
+        .setLocalProperties(localProperties)
+        .build();
+    jdbcInterpreter.executePrecode(context);
 
-    InterpreterResult interpreterResult = jdbcInterpreter.interpret(sqlQuery, interpreterContext);
+    String sqlQuery = "select * from test_precode_2";
+
+    InterpreterResult interpreterResult = jdbcInterpreter.interpret(sqlQuery, context);
 
     assertEquals(InterpreterResult.Code.SUCCESS, interpreterResult.code());
     assertEquals(InterpreterResult.Type.TABLE, interpreterResult.message().get(0).getType());
@@ -601,9 +614,16 @@ public class JDBCInterpreterTest extends BasicJDBCTestCaseAdapter {
     JDBCInterpreter jdbcInterpreter = new JDBCInterpreter(properties);
     jdbcInterpreter.open();
 
-    String sqlQuery = "(anotherPrefix) select @v";
+    Map<String, String> localProperties = new HashMap<>();
+    localProperties.put("db", "anotherPrefix");
+    InterpreterContext context = InterpreterContext.builder()
+        .setAuthenticationInfo(new AuthenticationInfo("testUser"))
+        .setLocalProperties(localProperties)
+        .build();
+
+    String sqlQuery = "select @v";
 
-    InterpreterResult interpreterResult = jdbcInterpreter.interpret(sqlQuery, interpreterContext);
+    InterpreterResult interpreterResult = jdbcInterpreter.interpret(sqlQuery, context);
 
     assertEquals(InterpreterResult.Code.SUCCESS, interpreterResult.code());
     assertEquals(InterpreterResult.Type.TABLE, interpreterResult.message().get(0).getType());

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/5d880314/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/InterpreterContext.java
----------------------------------------------------------------------
diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/InterpreterContext.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/InterpreterContext.java
index ecff46b..b58821a 100644
--- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/InterpreterContext.java
+++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/InterpreterContext.java
@@ -59,6 +59,7 @@ public class InterpreterContext {
   private ResourcePool resourcePool;
   private String interpreterClassName;
   private Map<String, Integer> progressMap;
+  private Map<String, String> localProperties = new HashMap<>();
   private RemoteInterpreterEventClient intpEventClient;
 
   /**
@@ -146,6 +147,10 @@ public class InterpreterContext {
       return this;
     }
 
+    public Builder setLocalProperties(Map<String, String> localProperties) {
+      context.localProperties = localProperties;
+      return this;
+    }
 
     public InterpreterContext build() {
       InterpreterContext.set(context);
@@ -182,6 +187,10 @@ public class InterpreterContext {
     return paragraphTitle;
   }
 
+  public Map<String, String> getLocalProperties() {
+    return localProperties;
+  }
+
   public AuthenticationInfo getAuthenticationInfo() {
     return authenticationInfo;
   }

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/5d880314/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 a8ca10f..6e548ad 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
@@ -749,23 +749,13 @@ public class RemoteInterpreterServer extends Thread
   }
 
   private InterpreterContext convert(RemoteInterpreterContext ric, InterpreterOutput output) {
-    //    List<InterpreterContextRunner> contextRunners = new LinkedList<>();
-    //    List<InterpreterContextRunner> runners = gson.fromJson(ric.getRunners(),
-    //        new TypeToken<List<RemoteInterpreterContextRunner>>() {
-    //        }.getType());
-    //
-    //    if (runners != null) {
-    //      for (InterpreterContextRunner r : runners) {
-    //        contextRunners.add(new ParagraphRunner(this, r.getNoteId(), r.getParagraphId()));
-    //      }
-    //    }
-
     return InterpreterContext.builder()
         .setNoteId(ric.getNoteId())
         .setParagraphId(ric.getParagraphId())
         .setReplName(ric.getReplName())
         .setParagraphTitle(ric.getParagraphTitle())
         .setParagraphText(ric.getParagraphText())
+        .setLocalProperties(ric.getLocalProperties())
         .setAuthenticationInfo(AuthenticationInfo.fromJson(ric.getAuthenticationInfo()))
         .setGUI(GUI.fromJson(ric.getGui()))
         .setNoteGUI(GUI.fromJson(ric.getNoteGui()))
@@ -775,22 +765,6 @@ public class RemoteInterpreterServer extends Thread
         .setIntpEventClient(intpEventClient)
         .setProgressMap(progressMap)
         .build();
-    //    return new InterpreterContext(
-    //        ric.getNoteId(),
-    //        ric.getParagraphId(),
-    //        ric.getReplName(),
-    //        ric.getParagraphTitle(),
-    //        ric.getParagraphText(),
-    //        AuthenticationInfo.fromJson(ric.getAuthenticationInfo()),
-    //        (Map<String, Object>) gson.fromJson(ric.getConfig(),
-    //            new TypeToken<Map<String, Object>>() {
-    //            }.getType()),
-    //        GUI.fromJson(ric.getGui()),
-    //        GUI.fromJson(ric.getNoteGui()),
-    //        interpreterGroup.getAngularObjectRegistry(),
-    //        interpreterGroup.getResourcePool(),
-    //        output, intpEventClient,
-    //        progressMap);
   }
 
 

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/5d880314/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/AngularObjectId.java
----------------------------------------------------------------------
diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/AngularObjectId.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/AngularObjectId.java
index 98902cc..eecb138 100644
--- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/AngularObjectId.java
+++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/AngularObjectId.java
@@ -51,7 +51,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 @SuppressWarnings({"cast", "rawtypes", "serial", "unchecked"})
-@Generated(value = "Autogenerated by Thrift Compiler (0.9.2)", date = "2018-6-19")
+@Generated(value = "Autogenerated by Thrift Compiler (0.9.2)", date = "2018-6-21")
 public class AngularObjectId implements org.apache.thrift.TBase<AngularObjectId, AngularObjectId._Fields>, java.io.Serializable, Cloneable, Comparable<AngularObjectId> {
   private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("AngularObjectId");
 

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/5d880314/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/AppOutputAppendEvent.java
----------------------------------------------------------------------
diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/AppOutputAppendEvent.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/AppOutputAppendEvent.java
index a144101..bb01dbc 100644
--- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/AppOutputAppendEvent.java
+++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/AppOutputAppendEvent.java
@@ -51,7 +51,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 @SuppressWarnings({"cast", "rawtypes", "serial", "unchecked"})
-@Generated(value = "Autogenerated by Thrift Compiler (0.9.2)", date = "2018-6-19")
+@Generated(value = "Autogenerated by Thrift Compiler (0.9.2)", date = "2018-6-21")
 public class AppOutputAppendEvent implements org.apache.thrift.TBase<AppOutputAppendEvent, AppOutputAppendEvent._Fields>, java.io.Serializable, Cloneable, Comparable<AppOutputAppendEvent> {
   private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("AppOutputAppendEvent");
 

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/5d880314/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/AppOutputUpdateEvent.java
----------------------------------------------------------------------
diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/AppOutputUpdateEvent.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/AppOutputUpdateEvent.java
index 067b377..22af593 100644
--- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/AppOutputUpdateEvent.java
+++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/AppOutputUpdateEvent.java
@@ -51,7 +51,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 @SuppressWarnings({"cast", "rawtypes", "serial", "unchecked"})
-@Generated(value = "Autogenerated by Thrift Compiler (0.9.2)", date = "2018-6-19")
+@Generated(value = "Autogenerated by Thrift Compiler (0.9.2)", date = "2018-6-21")
 public class AppOutputUpdateEvent implements org.apache.thrift.TBase<AppOutputUpdateEvent, AppOutputUpdateEvent._Fields>, java.io.Serializable, Cloneable, Comparable<AppOutputUpdateEvent> {
   private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("AppOutputUpdateEvent");
 

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/5d880314/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/AppStatusUpdateEvent.java
----------------------------------------------------------------------
diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/AppStatusUpdateEvent.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/AppStatusUpdateEvent.java
index b6e07b4..66e95af 100644
--- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/AppStatusUpdateEvent.java
+++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/AppStatusUpdateEvent.java
@@ -51,7 +51,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 @SuppressWarnings({"cast", "rawtypes", "serial", "unchecked"})
-@Generated(value = "Autogenerated by Thrift Compiler (0.9.2)", date = "2018-6-19")
+@Generated(value = "Autogenerated by Thrift Compiler (0.9.2)", date = "2018-6-21")
 public class AppStatusUpdateEvent implements org.apache.thrift.TBase<AppStatusUpdateEvent, AppStatusUpdateEvent._Fields>, java.io.Serializable, Cloneable, Comparable<AppStatusUpdateEvent> {
   private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("AppStatusUpdateEvent");
 

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/5d880314/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/InterpreterCompletion.java
----------------------------------------------------------------------
diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/InterpreterCompletion.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/InterpreterCompletion.java
index 3026260..0ef0a86 100644
--- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/InterpreterCompletion.java
+++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/InterpreterCompletion.java
@@ -51,7 +51,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 @SuppressWarnings({"cast", "rawtypes", "serial", "unchecked"})
-@Generated(value = "Autogenerated by Thrift Compiler (0.9.2)", date = "2018-6-19")
+@Generated(value = "Autogenerated by Thrift Compiler (0.9.2)", date = "2018-6-21")
 public class InterpreterCompletion implements org.apache.thrift.TBase<InterpreterCompletion, InterpreterCompletion._Fields>, java.io.Serializable, Cloneable, Comparable<InterpreterCompletion> {
   private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("InterpreterCompletion");
 

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/5d880314/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/OutputAppendEvent.java
----------------------------------------------------------------------
diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/OutputAppendEvent.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/OutputAppendEvent.java
index 3e114a6..7f15a8b 100644
--- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/OutputAppendEvent.java
+++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/OutputAppendEvent.java
@@ -51,7 +51,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 @SuppressWarnings({"cast", "rawtypes", "serial", "unchecked"})
-@Generated(value = "Autogenerated by Thrift Compiler (0.9.2)", date = "2018-6-19")
+@Generated(value = "Autogenerated by Thrift Compiler (0.9.2)", date = "2018-6-21")
 public class OutputAppendEvent implements org.apache.thrift.TBase<OutputAppendEvent, OutputAppendEvent._Fields>, java.io.Serializable, Cloneable, Comparable<OutputAppendEvent> {
   private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("OutputAppendEvent");
 

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/5d880314/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/OutputUpdateAllEvent.java
----------------------------------------------------------------------
diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/OutputUpdateAllEvent.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/OutputUpdateAllEvent.java
index d9c5b7a..715822c 100644
--- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/OutputUpdateAllEvent.java
+++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/OutputUpdateAllEvent.java
@@ -51,7 +51,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 @SuppressWarnings({"cast", "rawtypes", "serial", "unchecked"})
-@Generated(value = "Autogenerated by Thrift Compiler (0.9.2)", date = "2018-6-19")
+@Generated(value = "Autogenerated by Thrift Compiler (0.9.2)", date = "2018-6-21")
 public class OutputUpdateAllEvent implements org.apache.thrift.TBase<OutputUpdateAllEvent, OutputUpdateAllEvent._Fields>, java.io.Serializable, Cloneable, Comparable<OutputUpdateAllEvent> {
   private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("OutputUpdateAllEvent");
 

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/5d880314/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/OutputUpdateEvent.java
----------------------------------------------------------------------
diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/OutputUpdateEvent.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/OutputUpdateEvent.java
index 0e60c24..17ff089 100644
--- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/OutputUpdateEvent.java
+++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/OutputUpdateEvent.java
@@ -51,7 +51,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 @SuppressWarnings({"cast", "rawtypes", "serial", "unchecked"})
-@Generated(value = "Autogenerated by Thrift Compiler (0.9.2)", date = "2018-6-19")
+@Generated(value = "Autogenerated by Thrift Compiler (0.9.2)", date = "2018-6-21")
 public class OutputUpdateEvent implements org.apache.thrift.TBase<OutputUpdateEvent, OutputUpdateEvent._Fields>, java.io.Serializable, Cloneable, Comparable<OutputUpdateEvent> {
   private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("OutputUpdateEvent");
 

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/5d880314/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RegisterInfo.java
----------------------------------------------------------------------
diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RegisterInfo.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RegisterInfo.java
index 2a1b508..d4264d4 100644
--- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RegisterInfo.java
+++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RegisterInfo.java
@@ -51,7 +51,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 @SuppressWarnings({"cast", "rawtypes", "serial", "unchecked"})
-@Generated(value = "Autogenerated by Thrift Compiler (0.9.2)", date = "2018-6-19")
+@Generated(value = "Autogenerated by Thrift Compiler (0.9.2)", date = "2018-6-21")
 public class RegisterInfo implements org.apache.thrift.TBase<RegisterInfo, RegisterInfo._Fields>, java.io.Serializable, Cloneable, Comparable<RegisterInfo> {
   private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("RegisterInfo");
 

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/5d880314/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteApplicationResult.java
----------------------------------------------------------------------
diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteApplicationResult.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteApplicationResult.java
index 87d06e9..1188535 100644
--- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteApplicationResult.java
+++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteApplicationResult.java
@@ -51,7 +51,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 @SuppressWarnings({"cast", "rawtypes", "serial", "unchecked"})
-@Generated(value = "Autogenerated by Thrift Compiler (0.9.2)", date = "2018-6-19")
+@Generated(value = "Autogenerated by Thrift Compiler (0.9.2)", date = "2018-6-21")
 public class RemoteApplicationResult implements org.apache.thrift.TBase<RemoteApplicationResult, RemoteApplicationResult._Fields>, java.io.Serializable, Cloneable, Comparable<RemoteApplicationResult> {
   private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("RemoteApplicationResult");
 

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/5d880314/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterContext.java
----------------------------------------------------------------------
diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterContext.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterContext.java
index eab70fd..fa4421d 100644
--- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterContext.java
+++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterContext.java
@@ -51,7 +51,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 @SuppressWarnings({"cast", "rawtypes", "serial", "unchecked"})
-@Generated(value = "Autogenerated by Thrift Compiler (0.9.2)", date = "2018-6-19")
+@Generated(value = "Autogenerated by Thrift Compiler (0.9.2)", date = "2018-6-21")
 public class RemoteInterpreterContext implements org.apache.thrift.TBase<RemoteInterpreterContext, RemoteInterpreterContext._Fields>, java.io.Serializable, Cloneable, Comparable<RemoteInterpreterContext> {
   private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("RemoteInterpreterContext");
 
@@ -64,6 +64,7 @@ public class RemoteInterpreterContext implements org.apache.thrift.TBase<RemoteI
   private static final org.apache.thrift.protocol.TField CONFIG_FIELD_DESC = new org.apache.thrift.protocol.TField("config", org.apache.thrift.protocol.TType.STRING, (short)7);
   private static final org.apache.thrift.protocol.TField GUI_FIELD_DESC = new org.apache.thrift.protocol.TField("gui", org.apache.thrift.protocol.TType.STRING, (short)8);
   private static final org.apache.thrift.protocol.TField NOTE_GUI_FIELD_DESC = new org.apache.thrift.protocol.TField("noteGui", org.apache.thrift.protocol.TType.STRING, (short)9);
+  private static final org.apache.thrift.protocol.TField LOCAL_PROPERTIES_FIELD_DESC = new org.apache.thrift.protocol.TField("localProperties", org.apache.thrift.protocol.TType.MAP, (short)10);
 
   private static final Map<Class<? extends IScheme>, SchemeFactory> schemes = new HashMap<Class<? extends IScheme>, SchemeFactory>();
   static {
@@ -80,6 +81,7 @@ public class RemoteInterpreterContext implements org.apache.thrift.TBase<RemoteI
   public String config; // required
   public String gui; // required
   public String noteGui; // required
+  public Map<String,String> localProperties; // required
 
   /** The set of fields this struct contains, along with convenience methods for finding and manipulating them. */
   public enum _Fields implements org.apache.thrift.TFieldIdEnum {
@@ -91,7 +93,8 @@ public class RemoteInterpreterContext implements org.apache.thrift.TBase<RemoteI
     AUTHENTICATION_INFO((short)6, "authenticationInfo"),
     CONFIG((short)7, "config"),
     GUI((short)8, "gui"),
-    NOTE_GUI((short)9, "noteGui");
+    NOTE_GUI((short)9, "noteGui"),
+    LOCAL_PROPERTIES((short)10, "localProperties");
 
     private static final Map<String, _Fields> byName = new HashMap<String, _Fields>();
 
@@ -124,6 +127,8 @@ public class RemoteInterpreterContext implements org.apache.thrift.TBase<RemoteI
           return GUI;
         case 9: // NOTE_GUI
           return NOTE_GUI;
+        case 10: // LOCAL_PROPERTIES
+          return LOCAL_PROPERTIES;
         default:
           return null;
       }
@@ -185,6 +190,10 @@ public class RemoteInterpreterContext implements org.apache.thrift.TBase<RemoteI
         new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRING)));
     tmpMap.put(_Fields.NOTE_GUI, new org.apache.thrift.meta_data.FieldMetaData("noteGui", org.apache.thrift.TFieldRequirementType.DEFAULT, 
         new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRING)));
+    tmpMap.put(_Fields.LOCAL_PROPERTIES, new org.apache.thrift.meta_data.FieldMetaData("localProperties", org.apache.thrift.TFieldRequirementType.DEFAULT, 
+        new org.apache.thrift.meta_data.MapMetaData(org.apache.thrift.protocol.TType.MAP, 
+            new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRING), 
+            new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRING))));
     metaDataMap = Collections.unmodifiableMap(tmpMap);
     org.apache.thrift.meta_data.FieldMetaData.addStructMetaDataMap(RemoteInterpreterContext.class, metaDataMap);
   }
@@ -201,7 +210,8 @@ public class RemoteInterpreterContext implements org.apache.thrift.TBase<RemoteI
     String authenticationInfo,
     String config,
     String gui,
-    String noteGui)
+    String noteGui,
+    Map<String,String> localProperties)
   {
     this();
     this.noteId = noteId;
@@ -213,6 +223,7 @@ public class RemoteInterpreterContext implements org.apache.thrift.TBase<RemoteI
     this.config = config;
     this.gui = gui;
     this.noteGui = noteGui;
+    this.localProperties = localProperties;
   }
 
   /**
@@ -246,6 +257,10 @@ public class RemoteInterpreterContext implements org.apache.thrift.TBase<RemoteI
     if (other.isSetNoteGui()) {
       this.noteGui = other.noteGui;
     }
+    if (other.isSetLocalProperties()) {
+      Map<String,String> __this__localProperties = new HashMap<String,String>(other.localProperties);
+      this.localProperties = __this__localProperties;
+    }
   }
 
   public RemoteInterpreterContext deepCopy() {
@@ -263,6 +278,7 @@ public class RemoteInterpreterContext implements org.apache.thrift.TBase<RemoteI
     this.config = null;
     this.gui = null;
     this.noteGui = null;
+    this.localProperties = null;
   }
 
   public String getNoteId() {
@@ -481,6 +497,41 @@ public class RemoteInterpreterContext implements org.apache.thrift.TBase<RemoteI
     }
   }
 
+  public int getLocalPropertiesSize() {
+    return (this.localProperties == null) ? 0 : this.localProperties.size();
+  }
+
+  public void putToLocalProperties(String key, String val) {
+    if (this.localProperties == null) {
+      this.localProperties = new HashMap<String,String>();
+    }
+    this.localProperties.put(key, val);
+  }
+
+  public Map<String,String> getLocalProperties() {
+    return this.localProperties;
+  }
+
+  public RemoteInterpreterContext setLocalProperties(Map<String,String> localProperties) {
+    this.localProperties = localProperties;
+    return this;
+  }
+
+  public void unsetLocalProperties() {
+    this.localProperties = null;
+  }
+
+  /** Returns true if field localProperties is set (has been assigned a value) and false otherwise */
+  public boolean isSetLocalProperties() {
+    return this.localProperties != null;
+  }
+
+  public void setLocalPropertiesIsSet(boolean value) {
+    if (!value) {
+      this.localProperties = null;
+    }
+  }
+
   public void setFieldValue(_Fields field, Object value) {
     switch (field) {
     case NOTE_ID:
@@ -555,6 +606,14 @@ public class RemoteInterpreterContext implements org.apache.thrift.TBase<RemoteI
       }
       break;
 
+    case LOCAL_PROPERTIES:
+      if (value == null) {
+        unsetLocalProperties();
+      } else {
+        setLocalProperties((Map<String,String>)value);
+      }
+      break;
+
     }
   }
 
@@ -587,6 +646,9 @@ public class RemoteInterpreterContext implements org.apache.thrift.TBase<RemoteI
     case NOTE_GUI:
       return getNoteGui();
 
+    case LOCAL_PROPERTIES:
+      return getLocalProperties();
+
     }
     throw new IllegalStateException();
   }
@@ -616,6 +678,8 @@ public class RemoteInterpreterContext implements org.apache.thrift.TBase<RemoteI
       return isSetGui();
     case NOTE_GUI:
       return isSetNoteGui();
+    case LOCAL_PROPERTIES:
+      return isSetLocalProperties();
     }
     throw new IllegalStateException();
   }
@@ -714,6 +778,15 @@ public class RemoteInterpreterContext implements org.apache.thrift.TBase<RemoteI
         return false;
     }
 
+    boolean this_present_localProperties = true && this.isSetLocalProperties();
+    boolean that_present_localProperties = true && that.isSetLocalProperties();
+    if (this_present_localProperties || that_present_localProperties) {
+      if (!(this_present_localProperties && that_present_localProperties))
+        return false;
+      if (!this.localProperties.equals(that.localProperties))
+        return false;
+    }
+
     return true;
   }
 
@@ -766,6 +839,11 @@ public class RemoteInterpreterContext implements org.apache.thrift.TBase<RemoteI
     if (present_noteGui)
       list.add(noteGui);
 
+    boolean present_localProperties = true && (isSetLocalProperties());
+    list.add(present_localProperties);
+    if (present_localProperties)
+      list.add(localProperties);
+
     return list.hashCode();
   }
 
@@ -867,6 +945,16 @@ public class RemoteInterpreterContext implements org.apache.thrift.TBase<RemoteI
         return lastComparison;
       }
     }
+    lastComparison = Boolean.valueOf(isSetLocalProperties()).compareTo(other.isSetLocalProperties());
+    if (lastComparison != 0) {
+      return lastComparison;
+    }
+    if (isSetLocalProperties()) {
+      lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.localProperties, other.localProperties);
+      if (lastComparison != 0) {
+        return lastComparison;
+      }
+    }
     return 0;
   }
 
@@ -958,6 +1046,14 @@ public class RemoteInterpreterContext implements org.apache.thrift.TBase<RemoteI
       sb.append(this.noteGui);
     }
     first = false;
+    if (!first) sb.append(", ");
+    sb.append("localProperties:");
+    if (this.localProperties == null) {
+      sb.append("null");
+    } else {
+      sb.append(this.localProperties);
+    }
+    first = false;
     sb.append(")");
     return sb.toString();
   }
@@ -1073,6 +1169,26 @@ public class RemoteInterpreterContext implements org.apache.thrift.TBase<RemoteI
               org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);
             }
             break;
+          case 10: // LOCAL_PROPERTIES
+            if (schemeField.type == org.apache.thrift.protocol.TType.MAP) {
+              {
+                org.apache.thrift.protocol.TMap _map0 = iprot.readMapBegin();
+                struct.localProperties = new HashMap<String,String>(2*_map0.size);
+                String _key1;
+                String _val2;
+                for (int _i3 = 0; _i3 < _map0.size; ++_i3)
+                {
+                  _key1 = iprot.readString();
+                  _val2 = iprot.readString();
+                  struct.localProperties.put(_key1, _val2);
+                }
+                iprot.readMapEnd();
+              }
+              struct.setLocalPropertiesIsSet(true);
+            } else { 
+              org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);
+            }
+            break;
           default:
             org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);
         }
@@ -1133,6 +1249,19 @@ public class RemoteInterpreterContext implements org.apache.thrift.TBase<RemoteI
         oprot.writeString(struct.noteGui);
         oprot.writeFieldEnd();
       }
+      if (struct.localProperties != null) {
+        oprot.writeFieldBegin(LOCAL_PROPERTIES_FIELD_DESC);
+        {
+          oprot.writeMapBegin(new org.apache.thrift.protocol.TMap(org.apache.thrift.protocol.TType.STRING, org.apache.thrift.protocol.TType.STRING, struct.localProperties.size()));
+          for (Map.Entry<String, String> _iter4 : struct.localProperties.entrySet())
+          {
+            oprot.writeString(_iter4.getKey());
+            oprot.writeString(_iter4.getValue());
+          }
+          oprot.writeMapEnd();
+        }
+        oprot.writeFieldEnd();
+      }
       oprot.writeFieldStop();
       oprot.writeStructEnd();
     }
@@ -1178,7 +1307,10 @@ public class RemoteInterpreterContext implements org.apache.thrift.TBase<RemoteI
       if (struct.isSetNoteGui()) {
         optionals.set(8);
       }
-      oprot.writeBitSet(optionals, 9);
+      if (struct.isSetLocalProperties()) {
+        optionals.set(9);
+      }
+      oprot.writeBitSet(optionals, 10);
       if (struct.isSetNoteId()) {
         oprot.writeString(struct.noteId);
       }
@@ -1206,12 +1338,22 @@ public class RemoteInterpreterContext implements org.apache.thrift.TBase<RemoteI
       if (struct.isSetNoteGui()) {
         oprot.writeString(struct.noteGui);
       }
+      if (struct.isSetLocalProperties()) {
+        {
+          oprot.writeI32(struct.localProperties.size());
+          for (Map.Entry<String, String> _iter5 : struct.localProperties.entrySet())
+          {
+            oprot.writeString(_iter5.getKey());
+            oprot.writeString(_iter5.getValue());
+          }
+        }
+      }
     }
 
     @Override
     public void read(org.apache.thrift.protocol.TProtocol prot, RemoteInterpreterContext struct) throws org.apache.thrift.TException {
       TTupleProtocol iprot = (TTupleProtocol) prot;
-      BitSet incoming = iprot.readBitSet(9);
+      BitSet incoming = iprot.readBitSet(10);
       if (incoming.get(0)) {
         struct.noteId = iprot.readString();
         struct.setNoteIdIsSet(true);
@@ -1248,6 +1390,21 @@ public class RemoteInterpreterContext implements org.apache.thrift.TBase<RemoteI
         struct.noteGui = iprot.readString();
         struct.setNoteGuiIsSet(true);
       }
+      if (incoming.get(9)) {
+        {
+          org.apache.thrift.protocol.TMap _map6 = new org.apache.thrift.protocol.TMap(org.apache.thrift.protocol.TType.STRING, org.apache.thrift.protocol.TType.STRING, iprot.readI32());
+          struct.localProperties = new HashMap<String,String>(2*_map6.size);
+          String _key7;
+          String _val8;
+          for (int _i9 = 0; _i9 < _map6.size; ++_i9)
+          {
+            _key7 = iprot.readString();
+            _val8 = iprot.readString();
+            struct.localProperties.put(_key7, _val8);
+          }
+        }
+        struct.setLocalPropertiesIsSet(true);
+      }
     }
   }
 

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/5d880314/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterEvent.java
----------------------------------------------------------------------
diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterEvent.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterEvent.java
index ddb675c..fb14878 100644
--- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterEvent.java
+++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterEvent.java
@@ -51,7 +51,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 @SuppressWarnings({"cast", "rawtypes", "serial", "unchecked"})
-@Generated(value = "Autogenerated by Thrift Compiler (0.9.2)", date = "2018-6-19")
+@Generated(value = "Autogenerated by Thrift Compiler (0.9.2)", date = "2018-6-21")
 public class RemoteInterpreterEvent implements org.apache.thrift.TBase<RemoteInterpreterEvent, RemoteInterpreterEvent._Fields>, java.io.Serializable, Cloneable, Comparable<RemoteInterpreterEvent> {
   private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("RemoteInterpreterEvent");
 

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/5d880314/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterEventService.java
----------------------------------------------------------------------
diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterEventService.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterEventService.java
index 32193ad..df8760f 100644
--- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterEventService.java
+++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterEventService.java
@@ -51,7 +51,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 @SuppressWarnings({"cast", "rawtypes", "serial", "unchecked"})
-@Generated(value = "Autogenerated by Thrift Compiler (0.9.2)", date = "2018-6-19")
+@Generated(value = "Autogenerated by Thrift Compiler (0.9.2)", date = "2018-6-21")
 public class RemoteInterpreterEventService {
 
   public interface Iface {

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/5d880314/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterResult.java
----------------------------------------------------------------------
diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterResult.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterResult.java
index 3938bbb..808bc29 100644
--- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterResult.java
+++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterResult.java
@@ -51,7 +51,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 @SuppressWarnings({"cast", "rawtypes", "serial", "unchecked"})
-@Generated(value = "Autogenerated by Thrift Compiler (0.9.2)", date = "2018-6-19")
+@Generated(value = "Autogenerated by Thrift Compiler (0.9.2)", date = "2018-6-21")
 public class RemoteInterpreterResult implements org.apache.thrift.TBase<RemoteInterpreterResult, RemoteInterpreterResult._Fields>, java.io.Serializable, Cloneable, Comparable<RemoteInterpreterResult> {
   private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("RemoteInterpreterResult");
 
@@ -704,14 +704,14 @@ public class RemoteInterpreterResult implements org.apache.thrift.TBase<RemoteIn
           case 2: // MSG
             if (schemeField.type == org.apache.thrift.protocol.TType.LIST) {
               {
-                org.apache.thrift.protocol.TList _list0 = iprot.readListBegin();
-                struct.msg = new ArrayList<RemoteInterpreterResultMessage>(_list0.size);
-                RemoteInterpreterResultMessage _elem1;
-                for (int _i2 = 0; _i2 < _list0.size; ++_i2)
+                org.apache.thrift.protocol.TList _list10 = iprot.readListBegin();
+                struct.msg = new ArrayList<RemoteInterpreterResultMessage>(_list10.size);
+                RemoteInterpreterResultMessage _elem11;
+                for (int _i12 = 0; _i12 < _list10.size; ++_i12)
                 {
-                  _elem1 = new RemoteInterpreterResultMessage();
-                  _elem1.read(iprot);
-                  struct.msg.add(_elem1);
+                  _elem11 = new RemoteInterpreterResultMessage();
+                  _elem11.read(iprot);
+                  struct.msg.add(_elem11);
                 }
                 iprot.readListEnd();
               }
@@ -768,9 +768,9 @@ public class RemoteInterpreterResult implements org.apache.thrift.TBase<RemoteIn
         oprot.writeFieldBegin(MSG_FIELD_DESC);
         {
           oprot.writeListBegin(new org.apache.thrift.protocol.TList(org.apache.thrift.protocol.TType.STRUCT, struct.msg.size()));
-          for (RemoteInterpreterResultMessage _iter3 : struct.msg)
+          for (RemoteInterpreterResultMessage _iter13 : struct.msg)
           {
-            _iter3.write(oprot);
+            _iter13.write(oprot);
           }
           oprot.writeListEnd();
         }
@@ -831,9 +831,9 @@ public class RemoteInterpreterResult implements org.apache.thrift.TBase<RemoteIn
       if (struct.isSetMsg()) {
         {
           oprot.writeI32(struct.msg.size());
-          for (RemoteInterpreterResultMessage _iter4 : struct.msg)
+          for (RemoteInterpreterResultMessage _iter14 : struct.msg)
           {
-            _iter4.write(oprot);
+            _iter14.write(oprot);
           }
         }
       }
@@ -858,14 +858,14 @@ public class RemoteInterpreterResult implements org.apache.thrift.TBase<RemoteIn
       }
       if (incoming.get(1)) {
         {
-          org.apache.thrift.protocol.TList _list5 = new org.apache.thrift.protocol.TList(org.apache.thrift.protocol.TType.STRUCT, iprot.readI32());
-          struct.msg = new ArrayList<RemoteInterpreterResultMessage>(_list5.size);
-          RemoteInterpreterResultMessage _elem6;
-          for (int _i7 = 0; _i7 < _list5.size; ++_i7)
+          org.apache.thrift.protocol.TList _list15 = new org.apache.thrift.protocol.TList(org.apache.thrift.protocol.TType.STRUCT, iprot.readI32());
+          struct.msg = new ArrayList<RemoteInterpreterResultMessage>(_list15.size);
+          RemoteInterpreterResultMessage _elem16;
+          for (int _i17 = 0; _i17 < _list15.size; ++_i17)
           {
-            _elem6 = new RemoteInterpreterResultMessage();
-            _elem6.read(iprot);
-            struct.msg.add(_elem6);
+            _elem16 = new RemoteInterpreterResultMessage();
+            _elem16.read(iprot);
+            struct.msg.add(_elem16);
           }
         }
         struct.setMsgIsSet(true);

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/5d880314/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterResultMessage.java
----------------------------------------------------------------------
diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterResultMessage.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterResultMessage.java
index 5b50eaf..9f97b16 100644
--- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterResultMessage.java
+++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterResultMessage.java
@@ -51,7 +51,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 @SuppressWarnings({"cast", "rawtypes", "serial", "unchecked"})
-@Generated(value = "Autogenerated by Thrift Compiler (0.9.2)", date = "2018-6-19")
+@Generated(value = "Autogenerated by Thrift Compiler (0.9.2)", date = "2018-6-21")
 public class RemoteInterpreterResultMessage implements org.apache.thrift.TBase<RemoteInterpreterResultMessage, RemoteInterpreterResultMessage._Fields>, java.io.Serializable, Cloneable, Comparable<RemoteInterpreterResultMessage> {
   private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("RemoteInterpreterResultMessage");
 

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/5d880314/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterService.java
----------------------------------------------------------------------
diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterService.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterService.java
index 410c2e8..ea0475b 100644
--- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterService.java
+++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterService.java
@@ -51,7 +51,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 @SuppressWarnings({"cast", "rawtypes", "serial", "unchecked"})
-@Generated(value = "Autogenerated by Thrift Compiler (0.9.2)", date = "2018-6-19")
+@Generated(value = "Autogenerated by Thrift Compiler (0.9.2)", date = "2018-6-21")
 public class RemoteInterpreterService {
 
   public interface Iface {
@@ -3804,15 +3804,15 @@ public class RemoteInterpreterService {
             case 4: // PROPERTIES
               if (schemeField.type == org.apache.thrift.protocol.TType.MAP) {
                 {
-                  org.apache.thrift.protocol.TMap _map8 = iprot.readMapBegin();
-                  struct.properties = new HashMap<String,String>(2*_map8.size);
-                  String _key9;
-                  String _val10;
-                  for (int _i11 = 0; _i11 < _map8.size; ++_i11)
+                  org.apache.thrift.protocol.TMap _map18 = iprot.readMapBegin();
+                  struct.properties = new HashMap<String,String>(2*_map18.size);
+                  String _key19;
+                  String _val20;
+                  for (int _i21 = 0; _i21 < _map18.size; ++_i21)
                   {
-                    _key9 = iprot.readString();
-                    _val10 = iprot.readString();
-                    struct.properties.put(_key9, _val10);
+                    _key19 = iprot.readString();
+                    _val20 = iprot.readString();
+                    struct.properties.put(_key19, _val20);
                   }
                   iprot.readMapEnd();
                 }
@@ -3863,10 +3863,10 @@ public class RemoteInterpreterService {
           oprot.writeFieldBegin(PROPERTIES_FIELD_DESC);
           {
             oprot.writeMapBegin(new org.apache.thrift.protocol.TMap(org.apache.thrift.protocol.TType.STRING, org.apache.thrift.protocol.TType.STRING, struct.properties.size()));
-            for (Map.Entry<String, String> _iter12 : struct.properties.entrySet())
+            for (Map.Entry<String, String> _iter22 : struct.properties.entrySet())
             {
-              oprot.writeString(_iter12.getKey());
-              oprot.writeString(_iter12.getValue());
+              oprot.writeString(_iter22.getKey());
+              oprot.writeString(_iter22.getValue());
             }
             oprot.writeMapEnd();
           }
@@ -3923,10 +3923,10 @@ public class RemoteInterpreterService {
         if (struct.isSetProperties()) {
           {
             oprot.writeI32(struct.properties.size());
-            for (Map.Entry<String, String> _iter13 : struct.properties.entrySet())
+            for (Map.Entry<String, String> _iter23 : struct.properties.entrySet())
             {
-              oprot.writeString(_iter13.getKey());
-              oprot.writeString(_iter13.getValue());
+              oprot.writeString(_iter23.getKey());
+              oprot.writeString(_iter23.getValue());
             }
           }
         }
@@ -3953,15 +3953,15 @@ public class RemoteInterpreterService {
         }
         if (incoming.get(3)) {
           {
-            org.apache.thrift.protocol.TMap _map14 = new org.apache.thrift.protocol.TMap(org.apache.thrift.protocol.TType.STRING, org.apache.thrift.protocol.TType.STRING, iprot.readI32());
-            struct.properties = new HashMap<String,String>(2*_map14.size);
-            String _key15;
-            String _val16;
-            for (int _i17 = 0; _i17 < _map14.size; ++_i17)
+            org.apache.thrift.protocol.TMap _map24 = new org.apache.thrift.protocol.TMap(org.apache.thrift.protocol.TType.STRING, org.apache.thrift.protocol.TType.STRING, iprot.readI32());
+            struct.properties = new HashMap<String,String>(2*_map24.size);
+            String _key25;
+            String _val26;
+            for (int _i27 = 0; _i27 < _map24.size; ++_i27)
             {
-              _key15 = iprot.readString();
-              _val16 = iprot.readString();
-              struct.properties.put(_key15, _val16);
+              _key25 = iprot.readString();
+              _val26 = iprot.readString();
+              struct.properties.put(_key25, _val26);
             }
           }
           struct.setPropertiesIsSet(true);
@@ -10386,14 +10386,14 @@ public class RemoteInterpreterService {
             case 0: // SUCCESS
               if (schemeField.type == org.apache.thrift.protocol.TType.LIST) {
                 {
-                  org.apache.thrift.protocol.TList _list18 = iprot.readListBegin();
-                  struct.success = new ArrayList<InterpreterCompletion>(_list18.size);
-                  InterpreterCompletion _elem19;
-                  for (int _i20 = 0; _i20 < _list18.size; ++_i20)
+                  org.apache.thrift.protocol.TList _list28 = iprot.readListBegin();
+                  struct.success = new ArrayList<InterpreterCompletion>(_list28.size);
+                  InterpreterCompletion _elem29;
+                  for (int _i30 = 0; _i30 < _list28.size; ++_i30)
                   {
-                    _elem19 = new InterpreterCompletion();
-                    _elem19.read(iprot);
-                    struct.success.add(_elem19);
+                    _elem29 = new InterpreterCompletion();
+                    _elem29.read(iprot);
+                    struct.success.add(_elem29);
                   }
                   iprot.readListEnd();
                 }
@@ -10421,9 +10421,9 @@ public class RemoteInterpreterService {
           oprot.writeFieldBegin(SUCCESS_FIELD_DESC);
           {
             oprot.writeListBegin(new org.apache.thrift.protocol.TList(org.apache.thrift.protocol.TType.STRUCT, struct.success.size()));
-            for (InterpreterCompletion _iter21 : struct.success)
+            for (InterpreterCompletion _iter31 : struct.success)
             {
-              _iter21.write(oprot);
+              _iter31.write(oprot);
             }
             oprot.writeListEnd();
           }
@@ -10454,9 +10454,9 @@ public class RemoteInterpreterService {
         if (struct.isSetSuccess()) {
           {
             oprot.writeI32(struct.success.size());
-            for (InterpreterCompletion _iter22 : struct.success)
+            for (InterpreterCompletion _iter32 : struct.success)
             {
-              _iter22.write(oprot);
+              _iter32.write(oprot);
             }
           }
         }
@@ -10468,14 +10468,14 @@ public class RemoteInterpreterService {
         BitSet incoming = iprot.readBitSet(1);
         if (incoming.get(0)) {
           {
-            org.apache.thrift.protocol.TList _list23 = new org.apache.thrift.protocol.TList(org.apache.thrift.protocol.TType.STRUCT, iprot.readI32());
-            struct.success = new ArrayList<InterpreterCompletion>(_list23.size);
-            InterpreterCompletion _elem24;
-            for (int _i25 = 0; _i25 < _list23.size; ++_i25)
+            org.apache.thrift.protocol.TList _list33 = new org.apache.thrift.protocol.TList(org.apache.thrift.protocol.TType.STRUCT, iprot.readI32());
+            struct.success = new ArrayList<InterpreterCompletion>(_list33.size);
+            InterpreterCompletion _elem34;
+            for (int _i35 = 0; _i35 < _list33.size; ++_i35)
             {
-              _elem24 = new InterpreterCompletion();
-              _elem24.read(iprot);
-              struct.success.add(_elem24);
+              _elem34 = new InterpreterCompletion();
+              _elem34.read(iprot);
+              struct.success.add(_elem34);
             }
           }
           struct.setSuccessIsSet(true);
@@ -12369,13 +12369,13 @@ public class RemoteInterpreterService {
             case 0: // SUCCESS
               if (schemeField.type == org.apache.thrift.protocol.TType.LIST) {
                 {
-                  org.apache.thrift.protocol.TList _list26 = iprot.readListBegin();
-                  struct.success = new ArrayList<String>(_list26.size);
-                  String _elem27;
-                  for (int _i28 = 0; _i28 < _list26.size; ++_i28)
+                  org.apache.thrift.protocol.TList _list36 = iprot.readListBegin();
+                  struct.success = new ArrayList<String>(_list36.size);
+                  String _elem37;
+                  for (int _i38 = 0; _i38 < _list36.size; ++_i38)
                   {
-                    _elem27 = iprot.readString();
-                    struct.success.add(_elem27);
+                    _elem37 = iprot.readString();
+                    struct.success.add(_elem37);
                   }
                   iprot.readListEnd();
                 }
@@ -12403,9 +12403,9 @@ public class RemoteInterpreterService {
           oprot.writeFieldBegin(SUCCESS_FIELD_DESC);
           {
             oprot.writeListBegin(new org.apache.thrift.protocol.TList(org.apache.thrift.protocol.TType.STRING, struct.success.size()));
-            for (String _iter29 : struct.success)
+            for (String _iter39 : struct.success)
             {
-              oprot.writeString(_iter29);
+              oprot.writeString(_iter39);
             }
             oprot.writeListEnd();
           }
@@ -12436,9 +12436,9 @@ public class RemoteInterpreterService {
         if (struct.isSetSuccess()) {
           {
             oprot.writeI32(struct.success.size());
-            for (String _iter30 : struct.success)
+            for (String _iter40 : struct.success)
             {
-              oprot.writeString(_iter30);
+              oprot.writeString(_iter40);
             }
           }
         }
@@ -12450,13 +12450,13 @@ public class RemoteInterpreterService {
         BitSet incoming = iprot.readBitSet(1);
         if (incoming.get(0)) {
           {
-            org.apache.thrift.protocol.TList _list31 = new org.apache.thrift.protocol.TList(org.apache.thrift.protocol.TType.STRING, iprot.readI32());
-            struct.success = new ArrayList<String>(_list31.size);
-            String _elem32;
-            for (int _i33 = 0; _i33 < _list31.size; ++_i33)
+            org.apache.thrift.protocol.TList _list41 = new org.apache.thrift.protocol.TList(org.apache.thrift.protocol.TType.STRING, iprot.readI32());
+            struct.success = new ArrayList<String>(_list41.size);
+            String _elem42;
+            for (int _i43 = 0; _i43 < _list41.size; ++_i43)
             {
-              _elem32 = iprot.readString();
-              struct.success.add(_elem32);
+              _elem42 = iprot.readString();
+              struct.success.add(_elem42);
             }
           }
           struct.setSuccessIsSet(true);

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/5d880314/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RunParagraphsEvent.java
----------------------------------------------------------------------
diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RunParagraphsEvent.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RunParagraphsEvent.java
index 96fb87a..de10733 100644
--- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RunParagraphsEvent.java
+++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RunParagraphsEvent.java
@@ -51,7 +51,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 @SuppressWarnings({"cast", "rawtypes", "serial", "unchecked"})
-@Generated(value = "Autogenerated by Thrift Compiler (0.9.2)", date = "2018-6-19")
+@Generated(value = "Autogenerated by Thrift Compiler (0.9.2)", date = "2018-6-21")
 public class RunParagraphsEvent implements org.apache.thrift.TBase<RunParagraphsEvent, RunParagraphsEvent._Fields>, java.io.Serializable, Cloneable, Comparable<RunParagraphsEvent> {
   private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("RunParagraphsEvent");
 

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/5d880314/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/ZeppelinServerResourceParagraphRunner.java
----------------------------------------------------------------------
diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/ZeppelinServerResourceParagraphRunner.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/ZeppelinServerResourceParagraphRunner.java
index cdcd057..5637f64 100644
--- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/ZeppelinServerResourceParagraphRunner.java
+++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/ZeppelinServerResourceParagraphRunner.java
@@ -51,7 +51,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 @SuppressWarnings({"cast", "rawtypes", "serial", "unchecked"})
-@Generated(value = "Autogenerated by Thrift Compiler (0.9.2)", date = "2018-6-19")
+@Generated(value = "Autogenerated by Thrift Compiler (0.9.2)", date = "2018-6-21")
 public class ZeppelinServerResourceParagraphRunner implements org.apache.thrift.TBase<ZeppelinServerResourceParagraphRunner, ZeppelinServerResourceParagraphRunner._Fields>, java.io.Serializable, Cloneable, Comparable<ZeppelinServerResourceParagraphRunner> {
   private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("ZeppelinServerResourceParagraphRunner");
 

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/5d880314/zeppelin-interpreter/src/main/thrift/RemoteInterpreterService.thrift
----------------------------------------------------------------------
diff --git a/zeppelin-interpreter/src/main/thrift/RemoteInterpreterService.thrift b/zeppelin-interpreter/src/main/thrift/RemoteInterpreterService.thrift
index fcc14b0..9a1cf67 100644
--- a/zeppelin-interpreter/src/main/thrift/RemoteInterpreterService.thrift
+++ b/zeppelin-interpreter/src/main/thrift/RemoteInterpreterService.thrift
@@ -28,6 +28,7 @@ struct RemoteInterpreterContext {
   7: string config,   // json serialized config
   8: string gui,      // json serialized gui
   9: string noteGui,      // json serialized note gui
+  10: map<string, string> localProperties
 }
 
 struct RemoteInterpreterResultMessage {

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/5d880314/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 c9e1289..edfbc65 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
@@ -162,6 +162,12 @@ public class ZeppelinSparkClusterTest extends AbstractTestRestApi {
     note.run(p.getId(), true);
     assertEquals(Status.ERROR, p.getStatus());
     assertTrue(p.getResult().message().get(0).getData().contains("error: "));
+
+    // test local properties
+    p.setText("%spark(p1=v1,p2=v2) print(z.getInterpreterContext().getLocalProperties().size())");
+    note.run(p.getId(), true);
+    assertEquals(Status.FINISHED, p.getStatus());
+    assertEquals("2", p.getResult().message().get(0).getData());
   }
 
   @Test

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/5d880314/zeppelin-zengine/src/main/java/org/apache/zeppelin/interpreter/remote/RemoteInterpreter.java
----------------------------------------------------------------------
diff --git a/zeppelin-zengine/src/main/java/org/apache/zeppelin/interpreter/remote/RemoteInterpreter.java b/zeppelin-zengine/src/main/java/org/apache/zeppelin/interpreter/remote/RemoteInterpreter.java
index efbe648..3173122 100644
--- a/zeppelin-zengine/src/main/java/org/apache/zeppelin/interpreter/remote/RemoteInterpreter.java
+++ b/zeppelin-zengine/src/main/java/org/apache/zeppelin/interpreter/remote/RemoteInterpreter.java
@@ -397,7 +397,8 @@ public class RemoteInterpreter extends Interpreter {
   private RemoteInterpreterContext convert(InterpreterContext ic) {
     return new RemoteInterpreterContext(ic.getNoteId(), ic.getParagraphId(), ic.getReplName(),
         ic.getParagraphTitle(), ic.getParagraphText(), gson.toJson(ic.getAuthenticationInfo()),
-        gson.toJson(ic.getConfig()), ic.getGui().toJson(), gson.toJson(ic.getNoteGui()));
+        gson.toJson(ic.getConfig()), ic.getGui().toJson(), gson.toJson(ic.getNoteGui()),
+        ic.getLocalProperties());
   }
 
   private InterpreterResult convert(RemoteInterpreterResult result) {

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/5d880314/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Paragraph.java
----------------------------------------------------------------------
diff --git a/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Paragraph.java b/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Paragraph.java
index c76b3da..bc92249 100644
--- a/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Paragraph.java
+++ b/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Paragraph.java
@@ -31,6 +31,7 @@ import java.util.Set;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
+import org.apache.commons.lang.StringUtils;
 import org.apache.zeppelin.common.JsonSerializable;
 import org.apache.zeppelin.display.AngularObject;
 import org.apache.zeppelin.display.AngularObjectRegistry;
@@ -74,7 +75,8 @@ import com.google.common.collect.Maps;
 public class Paragraph extends Job implements Cloneable, JsonSerializable {
 
   private static Logger logger = LoggerFactory.getLogger(Paragraph.class);
-  private static Pattern REPL_PATTERN = Pattern.compile("(\\s*)%([\\w\\.]+).*", Pattern.DOTALL);
+  private static Pattern REPL_PATTERN =
+      Pattern.compile("(\\s*)%([\\w\\.]+)(\\(.*?\\))?.*", Pattern.DOTALL);
 
   private transient InterpreterFactory interpreterFactory;
   private transient Interpreter interpreter;
@@ -85,6 +87,7 @@ public class Paragraph extends Job implements Cloneable, JsonSerializable {
   private String title;
   private String text;  // text is composed of intpText and scriptText.
   private transient String intpText;
+  private transient Map<String, String> localProperties = new HashMap<>();
   private transient String scriptText;
   private String user;
   private Date dateUpdated;
@@ -188,11 +191,36 @@ public class Paragraph extends Job implements Cloneable, JsonSerializable {
   public void parseText() {
     // parse text to get interpreter component
     if (this.text != null) {
+      // clean localProperties, otherwise previous localProperties will be used for the next run
+      this.localProperties.clear();
       Matcher matcher = REPL_PATTERN.matcher(this.text);
       if (matcher.matches()) {
         String headingSpace = matcher.group(1);
         this.intpText = matcher.group(2);
-        this.scriptText = this.text.substring(headingSpace.length() + intpText.length() + 1).trim();
+
+        if (matcher.groupCount() == 3 && matcher.group(3) != null) {
+          String localPropertiesText = matcher.group(3);
+          String[] splits = localPropertiesText.substring(1, localPropertiesText.length() -1)
+              .split(",");
+          for (String split : splits) {
+            String[] kv = split.split("=");
+            if (StringUtils.isBlank(split) || kv.length == 0) {
+              continue;
+            }
+            if (kv.length > 2) {
+              throw new RuntimeException("Invalid paragraph properties format: " + split);
+            }
+            if (kv.length == 1) {
+              localProperties.put(kv[0].trim(), kv[0].trim());
+            } else {
+              localProperties.put(kv[0].trim(), kv[1].trim());
+            }
+          }
+          this.scriptText = this.text.substring(headingSpace.length() + intpText.length() +
+              localPropertiesText.length() + 1).trim();
+        } else {
+          this.scriptText = this.text.substring(headingSpace.length() + intpText.length() + 1).trim();
+        }
       } else {
         this.intpText = "";
         this.scriptText = this.text.trim();
@@ -233,6 +261,10 @@ public class Paragraph extends Job implements Cloneable, JsonSerializable {
     return note;
   }
 
+  public Map<String, String> getLocalProperties() {
+    return localProperties;
+  }
+
   public boolean isEnabled() {
     Boolean enabled = (Boolean) config.get("enabled");
     return enabled == null || enabled.booleanValue();
@@ -568,6 +600,7 @@ public class Paragraph extends Job implements Cloneable, JsonSerializable {
             .setReplName(intpText)
             .setParagraphTitle(title)
             .setParagraphText(text)
+            .setLocalProperties(localProperties)
             .setAuthenticationInfo(authenticationInfo)
             .setConfig(config)
             .setGUI(settings)
@@ -611,6 +644,7 @@ public class Paragraph extends Job implements Cloneable, JsonSerializable {
             .setParagraphTitle(title)
             .setParagraphText(text)
             .setAuthenticationInfo(authenticationInfo)
+            .setLocalProperties(localProperties)
             .setConfig(config)
             .setGUI(settings)
             .setNoteGUI(getNoteGui())

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/5d880314/zeppelin-zengine/src/test/java/org/apache/zeppelin/notebook/ParagraphTest.java
----------------------------------------------------------------------
diff --git a/zeppelin-zengine/src/test/java/org/apache/zeppelin/notebook/ParagraphTest.java b/zeppelin-zengine/src/test/java/org/apache/zeppelin/notebook/ParagraphTest.java
index e46b739..07bd608 100644
--- a/zeppelin-zengine/src/test/java/org/apache/zeppelin/notebook/ParagraphTest.java
+++ b/zeppelin-zengine/src/test/java/org/apache/zeppelin/notebook/ParagraphTest.java
@@ -51,10 +51,13 @@ import org.apache.zeppelin.interpreter.InterpreterSetting.Status;
 import org.apache.zeppelin.resource.ResourcePool;
 import org.apache.zeppelin.user.AuthenticationInfo;
 import org.apache.zeppelin.user.Credentials;
+import org.junit.Rule;
 import org.junit.Test;
 
 import java.util.HashMap;
 import java.util.Map;
+
+import org.junit.rules.ExpectedException;
 import org.mockito.Mockito;
 
 public class ParagraphTest extends AbstractInterpreterTest {
@@ -100,6 +103,45 @@ public class ParagraphTest extends AbstractInterpreterTest {
   }
 
   @Test
+  public void testParagraphProperties() {
+    Note note = createNote();
+    Paragraph paragraph = new Paragraph(note, null, interpreterFactory);
+    paragraph.setText("%test(p1=v1,p2=v2) a");
+    assertEquals("test", paragraph.getIntpText());
+    assertEquals("a", paragraph.getScriptText());
+    assertEquals(2, paragraph.getLocalProperties().size());
+    assertEquals("v1", paragraph.getLocalProperties().get("p1"));
+    assertEquals("v2", paragraph.getLocalProperties().get("p2"));
+
+    // properties with space
+    paragraph.setText("%test(p1=v1,  p2=v2) a");
+    assertEquals("test", paragraph.getIntpText());
+    assertEquals("a", paragraph.getScriptText());
+    assertEquals(2, paragraph.getLocalProperties().size());
+    assertEquals("v1", paragraph.getLocalProperties().get("p1"));
+    assertEquals("v2", paragraph.getLocalProperties().get("p2"));
+
+    // empty properties
+    paragraph.setText("%test() a");
+    assertEquals("test", paragraph.getIntpText());
+    assertEquals("a", paragraph.getScriptText());
+    assertEquals(0, paragraph.getLocalProperties().size());
+  }
+
+  @Rule
+  public ExpectedException expectedEx = ExpectedException.none();
+
+  @Test
+  public void testInvalidProperties() {
+    expectedEx.expect(RuntimeException.class);
+    expectedEx.expectMessage("Invalid paragraph properties format");
+
+    Note note = createNote();
+    Paragraph paragraph = new Paragraph(note, null, interpreterFactory);
+    paragraph.setText("%test(p1=v1=v2) a");
+  }
+
+  @Test
   public void replInvalid() {
     Note note = createNote();
     Paragraph paragraph = new Paragraph(note, null, interpreterFactory);