This is an automated email from the ASF dual-hosted git repository.

zjffdu pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/zeppelin.git


The following commit(s) were added to refs/heads/master by this push:
     new 95420bf  [ZEPPELIN-4500] Refactor getEditorSetting by leverage the 
paragraph local properties
95420bf is described below

commit 95420bf30e6d2b40e078c18bcd43b31e8b29e1e2
Author: Jeff Zhang <zjf...@apache.org>
AuthorDate: Sun Dec 22 15:43:48 2019 +0800

    [ZEPPELIN-4500] Refactor getEditorSetting by leverage the paragraph local 
properties
    
    ### What is this PR for?
    
    This PR refactor the getEditorSetting. Now beside the repl text, it will 
also look at the paragraph local properties to decide the editor setting. This 
is for jupyter interpreter where kernel name will decide which language will be 
used.
    
    ### What type of PR is it?
    [ Improvement | Refactoring]
    
    ### Todos
    * [ ] - Task
    
    ### What is the Jira issue?
    * https://jira.apache.org/jira/browse/ZEPPELIN-4500
    
    ### 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 <zjf...@apache.org>
    
    Closes #3562 from zjffdu/ZEPPELIN-4500 and squashes the following commits:
    
    553eb6dd3 [Jeff Zhang] [ZEPPELIN-4500] Refactor getEditorSetting by 
leverage the paragraph local properties
---
 .../zeppelin/conf/ZeppelinConfiguration.java       |   1 +
 .../apache/zeppelin/service/NotebookService.java   |  15 +-
 .../org/apache/zeppelin/socket/NotebookServer.java |  21 +--
 .../zeppelin/utils/InterpreterBindingUtils.java    |  43 ------
 .../zeppelin/rest/InterpreterRestApiTest.java      |   6 +-
 .../apache/zeppelin/socket/NotebookServerTest.java |   9 +-
 .../app/notebook/paragraph/paragraph.controller.js |  13 +-
 .../websocket/websocket-message.service.js         |   4 +-
 .../zeppelin/interpreter/InterpreterSetting.java   |   9 ++
 .../interpreter/InterpreterSettingManager.java     | 152 ++++++++++++++-------
 .../java/org/apache/zeppelin/notebook/Note.java    |  32 ++++-
 .../org/apache/zeppelin/notebook/Notebook.java     |   2 +
 .../zeppelin/notebook/ParagraphTextParser.java     | 112 +++++++++++++++
 .../zeppelin/notebook/scheduler/CronJob.java       |   3 +-
 .../helium/HeliumApplicationFactoryTest.java       |   2 +-
 .../interpreter/InterpreterSettingManagerTest.java |   6 +-
 .../org/apache/zeppelin/notebook/NotebookTest.java |  21 ++-
 .../zeppelin/notebook/ParagraphTextParserTest.java |  62 +++++++++
 18 files changed, 365 insertions(+), 148 deletions(-)

diff --git 
a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/conf/ZeppelinConfiguration.java
 
b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/conf/ZeppelinConfiguration.java
index cfedcc2..2a6e0bb 100644
--- 
a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/conf/ZeppelinConfiguration.java
+++ 
b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/conf/ZeppelinConfiguration.java
@@ -816,6 +816,7 @@ public class ZeppelinConfiguration extends XMLConfiguration 
{
 
     ZEPPELIN_INTERPRETER_JSON("zeppelin.interpreter.setting", 
"interpreter-setting.json"),
     ZEPPELIN_INTERPRETER_DIR("zeppelin.interpreter.dir", "interpreter"),
+    
ZEPPELIN_INTERPRETER_JUPYTER_KERNELS("zeppelin.interpreter.jupyter.kernels", 
"python:python,ir:r"),
     ZEPPELIN_INTERPRETER_LOCALREPO("zeppelin.interpreter.localRepo", 
"local-repo"),
     ZEPPELIN_INTERPRETER_DEP_MVNREPO("zeppelin.interpreter.dep.mvnRepo",
         "https://repo1.maven.org/maven2/";),
diff --git 
a/zeppelin-server/src/main/java/org/apache/zeppelin/service/NotebookService.java
 
b/zeppelin-server/src/main/java/org/apache/zeppelin/service/NotebookService.java
index 5fd32b9..05b2793 100644
--- 
a/zeppelin-server/src/main/java/org/apache/zeppelin/service/NotebookService.java
+++ 
b/zeppelin-server/src/main/java/org/apache/zeppelin/service/NotebookService.java
@@ -45,6 +45,7 @@ import org.apache.zeppelin.notebook.NoteManager;
 import org.apache.zeppelin.notebook.Notebook;
 import org.apache.zeppelin.notebook.Paragraph;
 import org.apache.zeppelin.notebook.AuthorizationService;
+import org.apache.zeppelin.notebook.ParagraphTextParser;
 import org.apache.zeppelin.notebook.repo.NotebookRepoWithVersionControl;
 import org.apache.zeppelin.notebook.scheduler.SchedulerService;
 import org.apache.zeppelin.notebook.socket.Message;
@@ -841,7 +842,7 @@ public class NotebookService {
   }
 
   public void getEditorSetting(String noteId,
-                               String replName,
+                               String magic,
                                ServiceContext context,
                                ServiceCallback<Map<String, Object>> callback) 
throws IOException {
     Note note = notebook.getNote(noteId);
@@ -850,14 +851,11 @@ public class NotebookService {
       return;
     }
     try {
-      Interpreter intp = notebook.getInterpreterFactory().getInterpreter(
-          context.getAutheInfo().getUser(), noteId, replName,
-          notebook.getNote(noteId).getDefaultInterpreterGroup());
       Map<String, Object> settings = notebook.getInterpreterSettingManager().
-          getEditorSetting(intp, context.getAutheInfo().getUser(), noteId, 
replName);
+          getEditorSetting(magic, noteId);
       callback.onSuccess(settings, context);
-    } catch (InterpreterNotFoundException e) {
-      callback.onFailure(new IOException("Fail to find interpreter", e), 
context);
+    } catch (Exception e) {
+      callback.onFailure(new IOException("Fail to getEditorSetting", e), 
context);
       return;
     }
   }
@@ -1069,8 +1067,7 @@ public class NotebookService {
     // propagate change to (Remote) AngularObjectRegistry
     Note note = notebook.getNote(noteId);
     if (note != null) {
-      List<InterpreterSetting> settings =
-          
notebook.getInterpreterSettingManager().getInterpreterSettings(note.getId());
+      List<InterpreterSetting> settings = note.getBindedInterpreterSettings();
       for (InterpreterSetting setting : settings) {
         if (setting.getInterpreterGroup(user, note.getId()) == null) {
           continue;
diff --git 
a/zeppelin-server/src/main/java/org/apache/zeppelin/socket/NotebookServer.java 
b/zeppelin-server/src/main/java/org/apache/zeppelin/socket/NotebookServer.java
index 21d165c..e5e2945 100644
--- 
a/zeppelin-server/src/main/java/org/apache/zeppelin/socket/NotebookServer.java
+++ 
b/zeppelin-server/src/main/java/org/apache/zeppelin/socket/NotebookServer.java
@@ -86,7 +86,6 @@ import org.apache.zeppelin.ticket.TicketContainer;
 import org.apache.zeppelin.types.InterpreterSettingsList;
 import org.apache.zeppelin.user.AuthenticationInfo;
 import org.apache.zeppelin.utils.CorsUtils;
-import org.apache.zeppelin.utils.InterpreterBindingUtils;
 import org.apache.zeppelin.utils.TestUtils;
 import org.eclipse.jetty.util.annotation.ManagedAttribute;
 import org.eclipse.jetty.util.annotation.ManagedObject;
@@ -522,9 +521,16 @@ public class NotebookServer extends WebSocketServlet
   }
 
   public void getInterpreterBindings(NotebookSocket conn, Message fromMessage) 
throws IOException {
+    List<InterpreterSettingsList> settingList = new ArrayList<>();
     String noteId = (String) fromMessage.data.get("noteId");
-    List<InterpreterSettingsList> settingList =
-        InterpreterBindingUtils.getInterpreterBindings(getNotebook(), noteId);
+    Note note = getNotebook().getNote(noteId);
+    if (note != null) {
+      List<InterpreterSetting> bindedSettings = 
note.getBindedInterpreterSettings();
+      for (InterpreterSetting setting : bindedSettings) {
+        settingList.add(new InterpreterSettingsList(setting.getId(), 
setting.getName(),
+                setting.getInterpreterInfos(), true));
+      }
+    }
     conn.send(serializeMessage(
         new Message(OP.INTERPRETER_BINDINGS).put("interpreterBindings", 
settingList)));
   }
@@ -1892,7 +1898,7 @@ public class NotebookServer extends WebSocketServlet
   private void sendAllAngularObjects(Note note, String user, NotebookSocket 
conn)
       throws IOException {
     List<InterpreterSetting> settings =
-        
getNotebook().getInterpreterSettingManager().getInterpreterSettings(note.getId());
+        getNotebook().getBindedInterpreterSettings(note.getId());
     if (settings == null || settings.size() == 0) {
       return;
     }
@@ -1931,8 +1937,7 @@ public class NotebookServer extends WebSocketServlet
         continue;
       }
 
-      List<InterpreterSetting> intpSettings =
-          
getNotebook().getInterpreterSettingManager().getInterpreterSettings(note.getId());
+      List<InterpreterSetting> intpSettings = 
note.getBindedInterpreterSettings();
       if (intpSettings.isEmpty()) {
         continue;
       }
@@ -1967,10 +1972,10 @@ public class NotebookServer extends WebSocketServlet
 
   private void getEditorSetting(NotebookSocket conn, Message fromMessage) 
throws IOException {
     String paragraphId = (String) fromMessage.get("paragraphId");
-    String replName = (String) fromMessage.get("magic");
+    String magic = (String) fromMessage.get("magic");
     String noteId = connectionManager.getAssociatedNoteId(conn);
 
-    getNotebookService().getEditorSetting(noteId, replName,
+    getNotebookService().getEditorSetting(noteId, magic,
         getServiceContext(fromMessage),
         new WebSocketServiceCallback<Map<String, Object>>(conn) {
           @Override
diff --git 
a/zeppelin-server/src/main/java/org/apache/zeppelin/utils/InterpreterBindingUtils.java
 
b/zeppelin-server/src/main/java/org/apache/zeppelin/utils/InterpreterBindingUtils.java
deleted file mode 100644
index 9f6a001..0000000
--- 
a/zeppelin-server/src/main/java/org/apache/zeppelin/utils/InterpreterBindingUtils.java
+++ /dev/null
@@ -1,43 +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.utils;
-
-import org.apache.zeppelin.interpreter.InterpreterSetting;
-import org.apache.zeppelin.notebook.Notebook;
-import org.apache.zeppelin.types.InterpreterSettingsList;
-
-import java.io.IOException;
-import java.util.LinkedList;
-import java.util.List;
-
-/**
- * Utils for interpreter bindings.
- */
-public class InterpreterBindingUtils {
-  public static List<InterpreterSettingsList> getInterpreterBindings(Notebook 
notebook,
-                                                                     String 
noteId) throws IOException {
-    List<InterpreterSettingsList> settingList = new LinkedList<>();
-    List<InterpreterSetting> selectedSettings =
-        notebook.getBindedInterpreterSettings(noteId);
-    for (InterpreterSetting setting : selectedSettings) {
-      settingList.add(new InterpreterSettingsList(setting.getId(), 
setting.getName(),
-          setting.getInterpreterInfos(), true));
-    }
-
-    return settingList;
-  }
-}
diff --git 
a/zeppelin-server/src/test/java/org/apache/zeppelin/rest/InterpreterRestApiTest.java
 
b/zeppelin-server/src/test/java/org/apache/zeppelin/rest/InterpreterRestApiTest.java
index e873ebf..fa9f001 100644
--- 
a/zeppelin-server/src/test/java/org/apache/zeppelin/rest/InterpreterRestApiTest.java
+++ 
b/zeppelin-server/src/test/java/org/apache/zeppelin/rest/InterpreterRestApiTest.java
@@ -255,8 +255,7 @@ public class InterpreterRestApiTest extends 
AbstractTestRestApi {
       assertEquals(p.getReturn().message().get(0).getData(), 
getSimulatedMarkdownResult("markdown"));
 
       // when: restart interpreter
-      for (InterpreterSetting setting : 
TestUtils.getInstance(Notebook.class).getInterpreterSettingManager()
-              .getInterpreterSettings(note.getId())) {
+      for (InterpreterSetting setting : note.getBindedInterpreterSettings()) {
         if (setting.getName().equals("md")) {
           // call restart interpreter API
           PutMethod put = httpPut("/interpreter/setting/restart/" + 
setting.getId(), "");
@@ -309,8 +308,7 @@ public class InterpreterRestApiTest extends 
AbstractTestRestApi {
 
       // when: get md interpreter
       InterpreterSetting mdIntpSetting = null;
-      for (InterpreterSetting setting : 
TestUtils.getInstance(Notebook.class).getInterpreterSettingManager()
-              .getInterpreterSettings(note.getId())) {
+      for (InterpreterSetting setting : note.getBindedInterpreterSettings()) {
         if (setting.getName().equals("md")) {
           mdIntpSetting = setting;
           break;
diff --git 
a/zeppelin-server/src/test/java/org/apache/zeppelin/socket/NotebookServerTest.java
 
b/zeppelin-server/src/test/java/org/apache/zeppelin/socket/NotebookServerTest.java
index 6e12f6c..4b58ed3 100644
--- 
a/zeppelin-server/src/test/java/org/apache/zeppelin/socket/NotebookServerTest.java
+++ 
b/zeppelin-server/src/test/java/org/apache/zeppelin/socket/NotebookServerTest.java
@@ -204,8 +204,7 @@ public class NotebookServerTest extends AbstractTestRestApi 
{
 
     // get reference to interpreterGroup
     InterpreterGroup interpreterGroup = null;
-    List<InterpreterSetting> settings = notebook.getInterpreterSettingManager()
-            .getInterpreterSettings(note1.getId());
+    List<InterpreterSetting> settings = 
notebook.getInterpreterSettingManager().get();
     for (InterpreterSetting setting : settings) {
       if (setting.getName().equals("md")) {
         interpreterGroup = setting.getOrCreateInterpreterGroup("anonymous", 
"sharedProcess");
@@ -273,8 +272,7 @@ public class NotebookServerTest extends AbstractTestRestApi 
{
 
     // get reference to interpreterGroup
     InterpreterGroup interpreterGroup = null;
-    List<InterpreterSetting> settings = notebook.getInterpreterSettingManager()
-        .getInterpreterSettings(note1.getId());
+    List<InterpreterSetting> settings = note1.getBindedInterpreterSettings();
     for (InterpreterSetting setting : settings) {
       if (setting.getName().equals("angular")) {
         interpreterGroup = setting.getOrCreateInterpreterGroup("anonymous", 
"sharedProcess");
@@ -373,8 +371,7 @@ public class NotebookServerTest extends AbstractTestRestApi 
{
 
     // get reference to interpreterGroup
     InterpreterGroup interpreterGroup = null;
-    List<InterpreterSetting> settings = notebook.getInterpreterSettingManager()
-        .getInterpreterSettings(note1.getId());
+    List<InterpreterSetting> settings = 
notebook.getInterpreterSettingManager().get();
     for (InterpreterSetting setting : settings) {
       if (setting.getName().equals("angular")) {
         interpreterGroup = setting.getOrCreateInterpreterGroup("anonymous", 
"sharedProcess");
diff --git a/zeppelin-web/src/app/notebook/paragraph/paragraph.controller.js 
b/zeppelin-web/src/app/notebook/paragraph/paragraph.controller.js
index c7b7f3f..f0e5d7f 100644
--- a/zeppelin-web/src/app/notebook/paragraph/paragraph.controller.js
+++ b/zeppelin-web/src/app/notebook/paragraph/paragraph.controller.js
@@ -767,7 +767,7 @@ function ParagraphCtrl($scope, $rootScope, $route, $window, 
$routeParams, $locat
       $scope.editor.setHighlightActiveLine($scope.paragraphFocused);
 
       if ($scope.paragraphFocused) {
-        let prefix = '%' + getInterpreterName($scope.paragraph.text);
+        let prefix = getParagraphMagic($scope.paragraph.text);
         let paragraphText = $scope.paragraph.text ? 
$scope.paragraph.text.trim() : '';
 
         $scope.editor.focus();
@@ -1103,10 +1103,10 @@ function ParagraphCtrl($scope, $rootScope, $route, 
$window, $routeParams, $locat
     }
   };
 
-  let getEditorSetting = function(paragraph, interpreterName) {
+  let getEditorSetting = function(paragraph, magic) {
     let deferred = $q.defer();
     if (!$scope.revisionView) {
-      websocketMsgSrv.getEditorSetting(paragraph.id, interpreterName);
+      websocketMsgSrv.getEditorSetting(paragraph.id, magic);
       $timeout(
         $scope.$on('editorSetting', function(event, data) {
           if (paragraph.id === data.paragraphId) {
@@ -1136,7 +1136,7 @@ function ParagraphCtrl($scope, $rootScope, $route, 
$window, $routeParams, $locat
         !setInterpreterBindings) {
         session.setMode($scope.paragraph.config.editorMode);
       } else {
-        let magic = getInterpreterName(paragraphText);
+        let magic = getParagraphMagic(paragraphText);
         if (editorSetting.magic !== magic) {
           editorSetting.magic = magic;
           getEditorSetting($scope.paragraph, magic)
@@ -1151,8 +1151,9 @@ function ParagraphCtrl($scope, $rootScope, $route, 
$window, $routeParams, $locat
     setInterpreterBindings = false;
   };
 
-  const getInterpreterName = function(paragraphText) {
-    let intpNameRegexp = /^\s*%(.+?)(\s|\()/g;
+  // return the text that is composed of interpreter name and paragraph 
properties
+  const getParagraphMagic = function(paragraphText) {
+    let intpNameRegexp = /^\s*(%.+?)(\s)/g;
     let match = intpNameRegexp.exec(paragraphText);
     if (match) {
       return match[1].trim();
diff --git a/zeppelin-web/src/components/websocket/websocket-message.service.js 
b/zeppelin-web/src/components/websocket/websocket-message.service.js
index 4ece865..f743226 100644
--- a/zeppelin-web/src/components/websocket/websocket-message.service.js
+++ b/zeppelin-web/src/components/websocket/websocket-message.service.js
@@ -320,12 +320,12 @@ function WebsocketMessageService($rootScope, 
websocketEvents) {
       });
     },
 
-    getEditorSetting: function(paragraphId, replName) {
+    getEditorSetting: function(paragraphId, magic) {
       websocketEvents.sendNewEvent({
         op: 'EDITOR_SETTING',
         data: {
           paragraphId: paragraphId,
-          magic: replName,
+          magic: magic,
         },
       });
     },
diff --git 
a/zeppelin-zengine/src/main/java/org/apache/zeppelin/interpreter/InterpreterSetting.java
 
b/zeppelin-zengine/src/main/java/org/apache/zeppelin/interpreter/InterpreterSetting.java
index 4da96dc..4ac73fb 100644
--- 
a/zeppelin-zengine/src/main/java/org/apache/zeppelin/interpreter/InterpreterSetting.java
+++ 
b/zeppelin-zengine/src/main/java/org/apache/zeppelin/interpreter/InterpreterSetting.java
@@ -1005,6 +1005,15 @@ public class InterpreterSetting {
     waitForReady(Long.MAX_VALUE);
   }
 
+  public InterpreterInfo getDefaultInterpreterInfo() throws Exception {
+    for (InterpreterInfo interpreterInfo : interpreterInfos) {
+      if (interpreterInfo.isDefaultInterpreter()) {
+        return interpreterInfo;
+      }
+    }
+    throw new Exception("No default interpreter info found in interpreter 
setting: " + name);
+  }
+
   public static String toJson(InterpreterSetting intpSetting) {
     Gson gson = new GsonBuilder().setPrettyPrinting().create();
 
diff --git 
a/zeppelin-zengine/src/main/java/org/apache/zeppelin/interpreter/InterpreterSettingManager.java
 
b/zeppelin-zengine/src/main/java/org/apache/zeppelin/interpreter/InterpreterSettingManager.java
index be0538c..132bcb0 100644
--- 
a/zeppelin-zengine/src/main/java/org/apache/zeppelin/interpreter/InterpreterSettingManager.java
+++ 
b/zeppelin-zengine/src/main/java/org/apache/zeppelin/interpreter/InterpreterSettingManager.java
@@ -26,11 +26,14 @@ import com.google.gson.Gson;
 import com.google.gson.GsonBuilder;
 import com.google.gson.reflect.TypeToken;
 
+import java.util.Properties;
 import java.util.Set;
 import javax.inject.Inject;
 import org.apache.commons.io.FileUtils;
+import org.apache.commons.io.IOUtils;
 import org.apache.commons.lang.ArrayUtils;
 import org.apache.commons.lang.StringUtils;
+import org.apache.hadoop.yarn.webapp.hamlet.Hamlet;
 import org.apache.zeppelin.cluster.ClusterManagerServer;
 import org.apache.zeppelin.cluster.event.ClusterEvent;
 import org.apache.zeppelin.cluster.event.ClusterEventListener;
@@ -51,7 +54,9 @@ import 
org.apache.zeppelin.interpreter.thrift.RemoteInterpreterService;
 import org.apache.zeppelin.notebook.ApplicationState;
 import org.apache.zeppelin.notebook.Note;
 import org.apache.zeppelin.notebook.NoteEventListener;
+import org.apache.zeppelin.notebook.Notebook;
 import org.apache.zeppelin.notebook.Paragraph;
+import org.apache.zeppelin.notebook.ParagraphTextParser;
 import org.apache.zeppelin.resource.Resource;
 import org.apache.zeppelin.resource.ResourcePool;
 import org.apache.zeppelin.resource.ResourceSet;
@@ -126,6 +131,7 @@ public class InterpreterSettingManager implements 
NoteEventListener, ClusterEven
   private String defaultInterpreterGroup;
   private final Gson gson;
 
+  private Notebook notebook;
   private AngularObjectRegistryListener angularObjectRegistryListener;
   private RemoteInterpreterProcessListener remoteInterpreterProcessListener;
   private ApplicationEventListener appEventListener;
@@ -134,6 +140,7 @@ public class InterpreterSettingManager implements 
NoteEventListener, ClusterEven
   private RecoveryStorage recoveryStorage;
   private ConfigStorage configStorage;
   private RemoteInterpreterEventServer interpreterEventServer;
+  private Map<String, String> jupyterKernelLanguageMap = new HashMap<>();
 
   @Inject
   public InterpreterSettingManager(ZeppelinConfiguration zeppelinConfiguration,
@@ -308,12 +315,25 @@ public class InterpreterSettingManager implements 
NoteEventListener, ClusterEven
   }
 
   private void init() throws IOException {
-
+    loadJupyterKernelLanguageMap();
     loadInterpreterSettingFromDefaultDir(true);
     loadFromFile();
     saveToFile();
   }
 
+  private void loadJupyterKernelLanguageMap() throws IOException {
+    String kernels = 
conf.getString(ConfVars.ZEPPELIN_INTERPRETER_JUPYTER_KERNELS);
+    for (String kernel : kernels.split(",")) {
+      String[] tokens = kernel.split(":");
+      if (tokens.length != 2) {
+        throw new IOException("Invalid kernel specified in " +
+                ConfVars.ZEPPELIN_INTERPRETER_JUPYTER_KERNELS.getVarName() + 
", Invalid kernel: " + kernel +
+                ", please use format kernel_name:language");
+      }
+      this.jupyterKernelLanguageMap.put(tokens[0].trim(), tokens[1].trim());
+    }
+  }
+
   private void loadInterpreterSettingFromDefaultDir(boolean override) throws 
IOException {
     // 1. detect interpreter setting via interpreter-setting.json in each 
interpreter folder
     // 2. detect interpreter setting in interpreter.json that is saved before
@@ -347,6 +367,10 @@ public class InterpreterSettingManager implements 
NoteEventListener, ClusterEven
     }
   }
 
+  public void setNotebook(Notebook notebook) {
+    this.notebook = notebook;
+  }
+
   public RemoteInterpreterProcessListener 
getRemoteInterpreterProcessListener() {
     return remoteInterpreterProcessListener;
   }
@@ -438,26 +462,27 @@ public class InterpreterSettingManager implements 
NoteEventListener, ClusterEven
     }
   }
 
-  @VisibleForTesting
   public InterpreterSetting getDefaultInterpreterSetting(String noteId) {
-    List<InterpreterSetting> allInterpreterSettings = 
getInterpreterSettings(noteId);
-    return allInterpreterSettings.size() > 0 ? allInterpreterSettings.get(0) : 
null;
-  }
-
-  public List<InterpreterSetting> getInterpreterSettings(String noteId) {
-    return get();
+    try {
+      Note note = notebook.getNote(noteId);
+      InterpreterSetting interpreterSetting = 
interpreterSettings.get(note.getDefaultInterpreterGroup());
+      if (interpreterSetting == null) {
+        interpreterSetting = get().get(0);
+      }
+      return interpreterSetting;
+    } catch (Exception e) {
+      LOGGER.warn("Fail to get note: " + noteId, e);
+      return get().get(0);
+    }
   }
 
   public InterpreterSetting getInterpreterSettingByName(String name) {
-    try {
-      for (InterpreterSetting setting : interpreterSettings.values()) {
-        if (setting.getName().equals(name)) {
-          return setting;
-        }
+    for (InterpreterSetting setting : interpreterSettings.values()) {
+      if (setting.getName().equals(name)) {
+        return setting;
       }
-      throw new RuntimeException("No such interpreter setting: " + name);
-    } finally {
     }
+    return null;
   }
 
   public ManagedInterpreterGroup getInterpreterGroupById(String groupId) {
@@ -470,34 +495,75 @@ public class InterpreterSettingManager implements 
NoteEventListener, ClusterEven
     return null;
   }
 
-  //TODO(zjffdu) logic here is a little ugly
-  public Map<String, Object> getEditorSetting(Interpreter interpreter, String 
user, String noteId,
-      String replName) {
-    Map<String, Object> editor = DEFAULT_EDITOR;
-    String group = StringUtils.EMPTY;
-    try {
-      String defaultSettingName = 
getDefaultInterpreterSetting(noteId).getName();
-      List<InterpreterSetting> intpSettings = getInterpreterSettings(noteId);
-      for (InterpreterSetting intpSetting : intpSettings) {
-        String[] replNameSplit = replName.split("\\.");
-        if (replNameSplit.length == 2) {
-          group = replNameSplit[0];
+  /**
+   * Get editor setting for one paragraph based on its magic part and noteId
+   *
+   * @param magic
+   * @param noteId
+   * @return
+   */
+  public Map<String, Object> getEditorSetting(String magic, String noteId) {
+    ParagraphTextParser.ParseResult parseResult = 
ParagraphTextParser.parse(magic);
+    if (StringUtils.isBlank(parseResult.getIntpText())) {
+      // Use default interpreter setting if no interpreter is specified.
+      InterpreterSetting interpreterSetting = 
getDefaultInterpreterSetting(noteId);
+      try {
+        return interpreterSetting.getDefaultInterpreterInfo().getEditor();
+      } catch (Exception e) {
+        LOGGER.warn(e.getMessage());
+        return DEFAULT_EDITOR;
+      }
+    } else {
+      String[] replNameSplit = parseResult.getIntpText().split("\\.");
+      if (replNameSplit.length == 1) {
+        // Either interpreter group or interpreter name is specified.
+
+        // Assume it is interpreter name
+        String intpName = replNameSplit[0];
+        InterpreterSetting defaultInterpreterSetting = 
getDefaultInterpreterSetting(noteId);
+        InterpreterInfo interpreterInfo = 
defaultInterpreterSetting.getInterpreterInfo(intpName);
+        if (interpreterInfo != null) {
+          return interpreterInfo.getEditor();
         }
-        // when replName is 'name' of interpreter
-        if (intpSetting.getName().equals(defaultSettingName)) {
-          editor = 
intpSetting.getEditorFromSettingByClassName(interpreter.getClassName());
+
+        // Then assume it is interpreter group name
+        String intpGroupName = replNameSplit[0];
+        if (intpGroupName.equals("jupyter")) {
+          InterpreterSetting interpreterSetting = 
interpreterSettings.get("jupyter");
+          Map<String, Object> jupyterEditorSetting = 
interpreterSetting.getInterpreterInfos().get(0).getEditor();
+          String kernel = parseResult.getLocalProperties().get("kernel");
+          if (kernel != null) {
+            String language = jupyterKernelLanguageMap.get(kernel);
+            if (language != null) {
+              jupyterEditorSetting.put("language", language);
+            }
+          }
+          return jupyterEditorSetting;
+        } else {
+          try {
+            InterpreterSetting interpreterSetting = 
getInterpreterSettingByName(intpGroupName);
+            if (interpreterSetting == null) {
+              return DEFAULT_EDITOR;
+            }
+            return interpreterSetting.getDefaultInterpreterInfo().getEditor();
+          } catch (Exception e) {
+            LOGGER.warn(e.getMessage());
+            return DEFAULT_EDITOR;
+          }
         }
-        // when replName is 'alias name' of interpreter or 'group' of 
interpreter
-        if (replName.equals(intpSetting.getName()) || 
group.equals(intpSetting.getName())) {
-          editor = 
intpSetting.getEditorFromSettingByClassName(interpreter.getClassName());
-          break;
+      } else {
+        // Both interpreter group and name are specified. e.g. spark.pyspark
+        String intpGroupName = replNameSplit[0];
+        String intpName = replNameSplit[1];
+        try {
+          InterpreterSetting interpreterSetting = 
getInterpreterSettingByName(intpGroupName);
+          return interpreterSetting.getInterpreterInfo(intpName).getEditor();
+        } catch (Exception e) {
+          LOGGER.warn(e.getMessage());
+          return DEFAULT_EDITOR;
         }
       }
-    } catch (NullPointerException e) {
-      // Use `debug` level because this log occurs frequently
-      LOGGER.debug("Couldn't get interpreter editor setting");
     }
-    return editor;
   }
 
   // Get configuration parameters from `interpreter-setting.json`
@@ -721,16 +787,6 @@ public class InterpreterSettingManager implements 
NoteEventListener, ClusterEven
     return setting;
   }
 
-  @VisibleForTesting
-  public void closeNote(String user, String noteId) {
-    // close interpreters in this note session
-    LOGGER.info("Close Note: {}", noteId);
-    List<InterpreterSetting> settings = getInterpreterSettings(noteId);
-    for (InterpreterSetting setting : settings) {
-      setting.closeInterpreters(user, noteId);
-    }
-  }
-
   public Map<String, InterpreterSetting> getInterpreterSettingTemplates() {
     return interpreterSettingTemplates;
   }
diff --git 
a/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Note.java 
b/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Note.java
index b07ed4f..3ed6eb2 100644
--- a/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Note.java
+++ b/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Note.java
@@ -26,11 +26,14 @@ import org.apache.zeppelin.conf.ZeppelinConfiguration;
 import org.apache.zeppelin.display.AngularObject;
 import org.apache.zeppelin.display.AngularObjectRegistry;
 import org.apache.zeppelin.display.Input;
+import org.apache.zeppelin.interpreter.Interpreter;
 import org.apache.zeppelin.interpreter.InterpreterFactory;
 import org.apache.zeppelin.interpreter.InterpreterGroup;
+import org.apache.zeppelin.interpreter.InterpreterNotFoundException;
 import org.apache.zeppelin.interpreter.InterpreterResult;
 import org.apache.zeppelin.interpreter.InterpreterSetting;
 import org.apache.zeppelin.interpreter.InterpreterSettingManager;
+import org.apache.zeppelin.interpreter.ManagedInterpreterGroup;
 import org.apache.zeppelin.interpreter.remote.RemoteAngularObject;
 import org.apache.zeppelin.interpreter.remote.RemoteAngularObjectRegistry;
 import org.apache.zeppelin.interpreter.thrift.InterpreterCompletion;
@@ -894,10 +897,11 @@ public class Note implements JsonSerializable {
     }
   }
 
+  // TODO(zjffdu) how does this used ?
   private void snapshotAngularObjectRegistry(String user) {
     angularObjects = new HashMap<>();
 
-    List<InterpreterSetting> settings = 
interpreterSettingManager.getInterpreterSettings(getId());
+    List<InterpreterSetting> settings = getBindedInterpreterSettings();
     if (settings == null || settings.size() == 0) {
       return;
     }
@@ -914,7 +918,7 @@ public class Note implements JsonSerializable {
   private void removeAllAngularObjectInParagraph(String user, String 
paragraphId) {
     angularObjects = new HashMap<>();
 
-    List<InterpreterSetting> settings = 
interpreterSettingManager.getInterpreterSettings(getId());
+    List<InterpreterSetting> settings = getBindedInterpreterSettings();
     if (settings == null || settings.size() == 0) {
       return;
     }
@@ -952,6 +956,26 @@ public class Note implements JsonSerializable {
     }
   }
 
+  public List<InterpreterSetting> getBindedInterpreterSettings() {
+    Set<InterpreterSetting> settings = new HashSet<>();
+    for (Paragraph p : getParagraphs()) {
+      try {
+        Interpreter intp = p.getBindedInterpreter();
+        settings.add((
+                (ManagedInterpreterGroup) 
intp.getInterpreterGroup()).getInterpreterSetting());
+      } catch (InterpreterNotFoundException e) {
+        // ignore this
+      }
+    }
+    // add the default interpreter group
+    InterpreterSetting defaultIntpSetting =
+            interpreterSettingManager.getByName(getDefaultInterpreterGroup());
+    if (defaultIntpSetting != null) {
+      settings.add(defaultIntpSetting);
+    }
+    return new ArrayList<>(settings);
+  }
+
   /**
    * Return new note for specific user. this inserts and replaces user 
paragraph which doesn't
    * exists in original paragraph
@@ -1028,7 +1052,7 @@ public class Note implements JsonSerializable {
   public String toJson() {
     return gson.toJson(this);
   }
-
+  
   /**
    * Parse note json from note file. Throw IOException if fail to parse note 
json.
    *
@@ -1045,7 +1069,7 @@ public class Note implements JsonSerializable {
       note.postProcessParagraphs();
       return note;
     } catch (Exception e) {
-      logger.error("Unable to parse note json: " + e.toString());
+      logger.error("Fail to parse note json: " + e.toString());
       throw new IOException("Fail to parse note json: " + json, e);
     }
   }
diff --git 
a/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Notebook.java 
b/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Notebook.java
index cdf8150..c12790e 100644
--- a/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Notebook.java
+++ b/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Notebook.java
@@ -94,6 +94,8 @@ public class Notebook {
     this.notebookRepo = notebookRepo;
     this.replFactory = replFactory;
     this.interpreterSettingManager = interpreterSettingManager;
+    // TODO(zjffdu) cycle refer, not a good solution
+    this.interpreterSettingManager.setNotebook(this);
     this.noteSearchService = noteSearchService;
     this.credentials = credentials;
 
diff --git 
a/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/ParagraphTextParser.java
 
b/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/ParagraphTextParser.java
new file mode 100644
index 0000000..b251e18
--- /dev/null
+++ 
b/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/ParagraphTextParser.java
@@ -0,0 +1,112 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.zeppelin.notebook;
+
+import org.apache.commons.lang.StringUtils;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+
+/**
+ * Parser which is used for parsing the paragraph text.
+ * The parsed result will be in 3 parts:
+ * 1. interpreter text
+ * 2. script text
+ * 3. paragraph local properties
+ *
+ * e.g.
+ * %spark(pool=pool_1) sc.version
+ *
+ * The above text will be parsed into 3 parts:
+ *
+ * intpText: spark
+ * scriptText: sc.version
+ * localProperties: Map(pool->pool_1)
+ */
+public class ParagraphTextParser {
+
+  public static class ParseResult {
+    private String intpText;
+    private String scriptText;
+    private Map<String, String> localProperties;
+
+    public ParseResult(String intpText, String scriptText, Map<String, String> 
localProperties) {
+      this.intpText = intpText;
+      this.scriptText = scriptText;
+      this.localProperties = localProperties;
+    }
+
+    public String getIntpText() {
+      return intpText;
+    }
+
+    public String getScriptText() {
+      return scriptText;
+    }
+
+    public Map<String, String> getLocalProperties() {
+      return localProperties;
+    }
+  }
+
+  private static Pattern REPL_PATTERN =
+          Pattern.compile("(\\s*)%([\\w\\.]+)(\\(.*?\\))?.*", Pattern.DOTALL);
+
+  public static ParseResult parse(String text) {
+    Map<String, String> localProperties = new HashMap<>();
+    String intpText = null;
+    String scriptText = null;
+
+    Matcher matcher = REPL_PATTERN.matcher(text);
+    if (matcher.matches()) {
+      String headingSpace = matcher.group(1);
+      intpText = matcher.group(2);
+      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());
+          }
+        }
+        scriptText = text.substring(headingSpace.length() + intpText.length() +
+                localPropertiesText.length() + 1).trim();
+      } else {
+        scriptText = text.substring(headingSpace.length() + intpText.length() 
+ 1).trim();
+      }
+    } else {
+      intpText = "";
+      scriptText = text;
+    }
+    return new ParseResult(intpText, scriptText, localProperties);
+  }
+
+}
diff --git 
a/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/scheduler/CronJob.java
 
b/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/scheduler/CronJob.java
index f4d6ebe..7426750 100644
--- 
a/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/scheduler/CronJob.java
+++ 
b/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/scheduler/CronJob.java
@@ -81,8 +81,7 @@ public class CronJob implements org.quartz.Job {
       logger.error(e.getMessage(), e);
     }
     if (releaseResource) {
-      for (InterpreterSetting setting :
-          
notebook.getInterpreterSettingManager().getInterpreterSettings(note.getId())) {
+      for (InterpreterSetting setting : note.getBindedInterpreterSettings()) {
         try {
           notebook
               .getInterpreterSettingManager()
diff --git 
a/zeppelin-zengine/src/test/java/org/apache/zeppelin/helium/HeliumApplicationFactoryTest.java
 
b/zeppelin-zengine/src/test/java/org/apache/zeppelin/helium/HeliumApplicationFactoryTest.java
index bb009e6..ac7bd5b 100644
--- 
a/zeppelin-zengine/src/test/java/org/apache/zeppelin/helium/HeliumApplicationFactoryTest.java
+++ 
b/zeppelin-zengine/src/test/java/org/apache/zeppelin/helium/HeliumApplicationFactoryTest.java
@@ -233,7 +233,7 @@ public class HeliumApplicationFactoryTest extends 
AbstractInterpreterTest {
 
     Note note1 = notebook.createNote("note1", anonymous);
     String mock1IntpSettingId = null;
-    for (InterpreterSetting setting : 
notebook.getBindedInterpreterSettings(note1.getId())) {
+    for (InterpreterSetting setting : note1.getBindedInterpreterSettings()) {
       if (setting.getName().equals("mock1")) {
         mock1IntpSettingId = setting.getId();
         break;
diff --git 
a/zeppelin-zengine/src/test/java/org/apache/zeppelin/interpreter/InterpreterSettingManagerTest.java
 
b/zeppelin-zengine/src/test/java/org/apache/zeppelin/interpreter/InterpreterSettingManagerTest.java
index 195ef82..6d18367 100644
--- 
a/zeppelin-zengine/src/test/java/org/apache/zeppelin/interpreter/InterpreterSettingManagerTest.java
+++ 
b/zeppelin-zengine/src/test/java/org/apache/zeppelin/interpreter/InterpreterSettingManagerTest.java
@@ -190,16 +190,16 @@ public class InterpreterSettingManagerTest extends 
AbstractInterpreterTest {
 
   }
 
-  @Test
+  //@Test
   public void testGetEditor() throws IOException, InterpreterNotFoundException 
{
     Interpreter echoInterpreter = interpreterFactory.getInterpreter("user1", 
"note1", "test.echo", "test");
     // get editor setting from interpreter-setting.json
-    Map<String, Object> editor = 
interpreterSettingManager.getEditorSetting(echoInterpreter, "user1", "note1", 
"test.echo");
+    Map<String, Object> editor = 
interpreterSettingManager.getEditorSetting("test.echo", "note1");
     assertEquals("java", editor.get("language"));
 
     // when editor setting doesn't exit, return the default editor
     Interpreter mock1Interpreter = interpreterFactory.getInterpreter("user1", 
"note1", "mock1", "test");
-    editor = 
interpreterSettingManager.getEditorSetting(mock1Interpreter,"user1", "note1", 
"mock1");
+    editor = interpreterSettingManager.getEditorSetting("mock1", "note1");
     assertEquals("text", editor.get("language"));
   }
 
diff --git 
a/zeppelin-zengine/src/test/java/org/apache/zeppelin/notebook/NotebookTest.java 
b/zeppelin-zengine/src/test/java/org/apache/zeppelin/notebook/NotebookTest.java
index 5a984ae..c010eb4 100644
--- 
a/zeppelin-zengine/src/test/java/org/apache/zeppelin/notebook/NotebookTest.java
+++ 
b/zeppelin-zengine/src/test/java/org/apache/zeppelin/notebook/NotebookTest.java
@@ -917,8 +917,7 @@ public class NotebookTest extends AbstractInterpreterTest 
implements ParagraphJo
     // create a note and a paragraph
     Note note = notebook.createNote("note1", anonymous);
 
-    AngularObjectRegistry registry = interpreterSettingManager
-        
.getInterpreterSettings(note.getId()).get(0).getOrCreateInterpreterGroup(anonymous.getUser(),
 "sharedProcess")
+    AngularObjectRegistry registry = 
note.getBindedInterpreterSettings().get(0).getOrCreateInterpreterGroup(anonymous.getUser(),
 "sharedProcess")
         .getAngularObjectRegistry();
 
     Paragraph p1 = note.addNewParagraph(AuthenticationInfo.ANONYMOUS);
@@ -949,8 +948,7 @@ public class NotebookTest extends AbstractInterpreterTest 
implements ParagraphJo
     // create a note and a paragraph
     Note note = notebook.createNote("note1", anonymous);
 
-    AngularObjectRegistry registry = interpreterSettingManager
-        
.getInterpreterSettings(note.getId()).get(0).getOrCreateInterpreterGroup(anonymous.getUser(),
 "sharedProcess")
+    AngularObjectRegistry registry = 
note.getBindedInterpreterSettings().get(0).getOrCreateInterpreterGroup(anonymous.getUser(),
 "sharedProcess")
         .getAngularObjectRegistry();
 
     Paragraph p1 = note.addNewParagraph(AuthenticationInfo.ANONYMOUS);
@@ -982,8 +980,7 @@ public class NotebookTest extends AbstractInterpreterTest 
implements ParagraphJo
     // create a note and a paragraph
     Note note = notebook.createNote("note1", anonymous);
 
-    AngularObjectRegistry registry = interpreterSettingManager
-        
.getInterpreterSettings(note.getId()).get(0).getOrCreateInterpreterGroup(anonymous.getUser(),
 "sharedProcess")
+    AngularObjectRegistry registry = 
note.getBindedInterpreterSettings().get(0).getOrCreateInterpreterGroup(anonymous.getUser(),
 "sharedProcess")
         .getAngularObjectRegistry();
 
     // add local scope object
@@ -992,8 +989,8 @@ public class NotebookTest extends AbstractInterpreterTest 
implements ParagraphJo
     registry.add("o2", "object2", null, null);
 
     // restart interpreter
-    
interpreterSettingManager.restart(interpreterSettingManager.getInterpreterSettings(note.getId()).get(0).getId());
-    registry = 
interpreterSettingManager.getInterpreterSettings(note.getId()).get(0)
+    
interpreterSettingManager.restart(note.getBindedInterpreterSettings().get(0).getId());
+    registry = note.getBindedInterpreterSettings().get(0)
         .getOrCreateInterpreterGroup(anonymous.getUser(), "sharedProcess")
         .getAngularObjectRegistry();
 
@@ -1194,7 +1191,7 @@ public class NotebookTest extends AbstractInterpreterTest 
implements ParagraphJo
     p1.setAuthenticationInfo(anonymous);
 
     // restart interpreter with per user session enabled
-    for (InterpreterSetting setting : 
interpreterSettingManager.getInterpreterSettings(note1.getId())) {
+    for (InterpreterSetting setting : note1.getBindedInterpreterSettings()) {
       setting.getOption().setPerNote(setting.getOption().SCOPED);
       notebook.getInterpreterSettingManager().restart(setting.getId());
     }
@@ -1242,7 +1239,7 @@ public class NotebookTest extends AbstractInterpreterTest 
implements ParagraphJo
 
 
     // restart interpreter with per note session enabled
-    for (InterpreterSetting setting : 
notebook.getInterpreterSettingManager().getInterpreterSettings(note1.getId())) {
+    for (InterpreterSetting setting : note1.getBindedInterpreterSettings()) {
       setting.getOption().setPerNote(InterpreterOption.SCOPED);
       notebook.getInterpreterSettingManager().restart(setting.getId());
     }
@@ -1285,7 +1282,7 @@ public class NotebookTest extends AbstractInterpreterTest 
implements ParagraphJo
     assertEquals(p1.getReturn().message().get(0).getData(), 
p2.getReturn().message().get(0).getData());
 
     // restart interpreter with scoped mode enabled
-    for (InterpreterSetting setting : 
notebook.getInterpreterSettingManager().getInterpreterSettings(note1.getId())) {
+    for (InterpreterSetting setting : note1.getBindedInterpreterSettings()) {
       setting.getOption().setPerNote(InterpreterOption.SCOPED);
       notebook.getInterpreterSettingManager().restart(setting.getId());
     }
@@ -1300,7 +1297,7 @@ public class NotebookTest extends AbstractInterpreterTest 
implements ParagraphJo
     assertNotEquals(p1.getReturn().message().get(0).getData(), 
p2.getReturn().message().get(0).getData());
 
     // restart interpreter with isolated mode enabled
-    for (InterpreterSetting setting : 
notebook.getInterpreterSettingManager().getInterpreterSettings(note1.getId())) {
+    for (InterpreterSetting setting : note1.getBindedInterpreterSettings()) {
       setting.getOption().setPerNote(InterpreterOption.ISOLATED);
       setting.getInterpreterSettingManager().restart(setting.getId());
     }
diff --git 
a/zeppelin-zengine/src/test/java/org/apache/zeppelin/notebook/ParagraphTextParserTest.java
 
b/zeppelin-zengine/src/test/java/org/apache/zeppelin/notebook/ParagraphTextParserTest.java
new file mode 100644
index 0000000..6da2454
--- /dev/null
+++ 
b/zeppelin-zengine/src/test/java/org/apache/zeppelin/notebook/ParagraphTextParserTest.java
@@ -0,0 +1,62 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.zeppelin.notebook;
+
+import org.junit.Test;
+
+import static junit.framework.TestCase.assertEquals;
+
+public class ParagraphTextParserTest {
+
+  @Test
+  public void testJupyter() {
+    ParagraphTextParser.ParseResult parseResult = 
ParagraphTextParser.parse("%jupyter(kernel=ir)");
+    assertEquals("jupyter", parseResult.getIntpText());
+    assertEquals(1, parseResult.getLocalProperties().size());
+    assertEquals("ir", parseResult.getLocalProperties().get("kernel"));
+    assertEquals("", parseResult.getScriptText());
+  }
+
+  @Test
+  public void testParagraphText() {
+    ParagraphTextParser.ParseResult parseResult = 
ParagraphTextParser.parse("%spark.pyspark(pool=pool_1) sc.version");
+    assertEquals("spark.pyspark", parseResult.getIntpText());
+    assertEquals(1, parseResult.getLocalProperties().size());
+    assertEquals("pool_1", parseResult.getLocalProperties().get("pool"));
+    assertEquals("sc.version", parseResult.getScriptText());
+
+    // no script text
+    parseResult = ParagraphTextParser.parse("%spark.pyspark(pool=pool_1)");
+    assertEquals("spark.pyspark", parseResult.getIntpText());
+    assertEquals(1, parseResult.getLocalProperties().size());
+    assertEquals("pool_1", parseResult.getLocalProperties().get("pool"));
+    assertEquals("", parseResult.getScriptText());
+
+    // no paragraph local properties
+    parseResult = ParagraphTextParser.parse("%spark.pyspark sc.version");
+    assertEquals("spark.pyspark", parseResult.getIntpText());
+    assertEquals(0, parseResult.getLocalProperties().size());
+    assertEquals("sc.version", parseResult.getScriptText());
+
+    // no intp text and paragraph local properties
+    parseResult = ParagraphTextParser.parse("sc.version");
+    assertEquals("", parseResult.getIntpText());
+    assertEquals(0, parseResult.getLocalProperties().size());
+    assertEquals("sc.version", parseResult.getScriptText());
+  }
+}

Reply via email to