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 b6c6124  [ZEPPELIN-4635]. Save note permission info into 
notebook-authorization.json
b6c6124 is described below

commit b6c6124d44c096a924f4efbcc9a785b8cd54e253
Author: Jeff Zhang <zjf...@apache.org>
AuthorDate: Mon Feb 24 13:19:18 2020 +0800

    [ZEPPELIN-4635]. Save note permission info into notebook-authorization.json
    
    ### What is this PR for?
    
    This PR is to revert the changes of ZEPPELIN-3985. Because it would cause 
the issue of ZEPPELIN-4612. In this PR I will make Zeppelin still save note 
permission info into `notebook-authorization.json`. But I also do some code 
refactoring, and we could store the permission info into other storage such as 
database in future. Because storing them into one file also has potential 
issue. such as scale issue, now each time we have to write all notes' 
permission info into file instead of in  [...]
    
    ### What type of PR is it?
    [Bug Fix | Refactoring]
    
    ### Todos
    * [ ] - Task
    
    ### What is the Jira issue?
    * https://issues.apache.org/jira/browse/ZEPPELIN-4635
    
    ### 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 #3668 from zjffdu/ZEPPELIN-4635 and squashes the following commits:
    
    01bd6453b [Jeff Zhang] [ZEPPELIN-4635]. Save note permission info into 
notebook-authorization.json
---
 .../zeppelin/cluster/event/ClusterEvent.java       |   1 +
 .../zeppelin/conf/ZeppelinConfiguration.java       |   2 +-
 .../notebook/repo/FileSystemNotebookRepo.java      |   7 +-
 .../org/apache/zeppelin/rest/NotebookRestApi.java  |   2 +-
 .../org/apache/zeppelin/server/ZeppelinServer.java |   2 +
 .../apache/zeppelin/service/NotebookService.java   |   9 +-
 .../apache/zeppelin/socket/ConnectionManager.java  |   1 -
 .../org/apache/zeppelin/socket/NotebookServer.java |   6 +-
 .../zeppelin/service/NotebookServiceTest.java      |  24 +-
 .../zeppelin/notebook/AuthorizationService.java    | 331 +++++++--------
 .../java/org/apache/zeppelin/notebook/Note.java    | 102 +----
 .../org/apache/zeppelin/notebook/NoteAuth.java     | 154 +++++++
 .../org/apache/zeppelin/notebook/NoteManager.java  |   7 +-
 .../org/apache/zeppelin/notebook/Notebook.java     |  65 ++-
 .../zeppelin/notebook/NotebookAuthorization.java   | 444 ---------------------
 .../notebook/NotebookAuthorizationInfoSaving.java  |  11 +-
 .../zeppelin/notebook/repo/NotebookRepo.java       |   8 +-
 .../zeppelin/notebook/repo/NotebookRepoSync.java   |  36 +-
 .../notebook/repo/UpgradeNoteFileTool.java         |   1 -
 .../zeppelin/notebook/repo/VFSNotebookRepo.java    |  12 +-
 .../zeppelin/conf/ZeppelinConfigurationTest.java   |   3 +-
 .../helium/HeliumApplicationFactoryTest.java       |   5 +
 .../org/apache/zeppelin/notebook/NotebookTest.java |  26 +-
 .../notebook/repo/NotebookRepoSyncTest.java        |  32 +-
 .../apache/zeppelin/search/LuceneSearchTest.java   |   4 +-
 25 files changed, 497 insertions(+), 798 deletions(-)

diff --git 
a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/cluster/event/ClusterEvent.java
 
b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/cluster/event/ClusterEvent.java
index 9772b54..559894a 100644
--- 
a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/cluster/event/ClusterEvent.java
+++ 
b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/cluster/event/ClusterEvent.java
@@ -31,6 +31,7 @@ public enum ClusterEvent {
   UPDATE_NOTE_PERMISSIONS,
   // CLUSTER_AUTH_EVENT_TOPIC
   SET_ROLES,
+  // (TODO) Consolidate the permission related events into one event
   SET_READERS_PERMISSIONS,
   SET_RUNNERS_PERMISSIONS,
   SET_WRITERS_PERMISSIONS,
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 2319606..dbdb614 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
@@ -394,7 +394,7 @@ public class ZeppelinConfiguration extends XMLConfiguration 
{
   }
 
   public String getNotebookDir() {
-    return getString(ConfVars.ZEPPELIN_NOTEBOOK_DIR);
+    return getRelativeDir(ConfVars.ZEPPELIN_NOTEBOOK_DIR);
   }
 
   public String getNotebookRunId() {
diff --git 
a/zeppelin-plugins/notebookrepo/filesystem/src/main/java/org/apache/zeppelin/notebook/repo/FileSystemNotebookRepo.java
 
b/zeppelin-plugins/notebookrepo/filesystem/src/main/java/org/apache/zeppelin/notebook/repo/FileSystemNotebookRepo.java
index f486451..d2c5cdd 100644
--- 
a/zeppelin-plugins/notebookrepo/filesystem/src/main/java/org/apache/zeppelin/notebook/repo/FileSystemNotebookRepo.java
+++ 
b/zeppelin-plugins/notebookrepo/filesystem/src/main/java/org/apache/zeppelin/notebook/repo/FileSystemNotebookRepo.java
@@ -69,7 +69,6 @@ public class FileSystemNotebookRepo implements NotebookRepo {
     return noteInfos;
   }
 
-
   @Override
   public Note get(String noteId, String notePath, AuthenticationInfo subject) 
throws IOException {
     String content = this.fs.readFile(
@@ -122,18 +121,18 @@ public class FileSystemNotebookRepo implements 
NotebookRepo {
 
   @Override
   public void close() {
-    LOGGER.warn("close is not implemented for HdfsNotebookRepo");
+    LOGGER.warn("close is not implemented for FileSystemNotebookRepo");
   }
 
   @Override
   public List<NotebookRepoSettingsInfo> getSettings(AuthenticationInfo 
subject) {
-    LOGGER.warn("getSettings is not implemented for HdfsNotebookRepo");
+    LOGGER.warn("getSettings is not implemented for FileSystemNotebookRepo");
     return null;
   }
 
   @Override
   public void updateSettings(Map<String, String> settings, AuthenticationInfo 
subject) {
-    LOGGER.warn("updateSettings is not implemented for HdfsNotebookRepo");
+    LOGGER.warn("updateSettings is not implemented for 
FileSystemNotebookRepo");
   }
 
 }
diff --git 
a/zeppelin-server/src/main/java/org/apache/zeppelin/rest/NotebookRestApi.java 
b/zeppelin-server/src/main/java/org/apache/zeppelin/rest/NotebookRestApi.java
index d0d7cb3..ab72ec4 100644
--- 
a/zeppelin-server/src/main/java/org/apache/zeppelin/rest/NotebookRestApi.java
+++ 
b/zeppelin-server/src/main/java/org/apache/zeppelin/rest/NotebookRestApi.java
@@ -295,7 +295,7 @@ public class NotebookRestApi extends AbstractRestApi {
             authorizationService.getReaders(noteId), 
authorizationService.getRunners(noteId),
             authorizationService.getWriters(noteId));
     AuthenticationInfo subject = new 
AuthenticationInfo(authenticationService.getPrincipal());
-    notebook.saveNote(note, subject);
+    authorizationService.saveNoteAuth(noteId, subject);
     notebookServer.broadcastNote(note);
     notebookServer.broadcastNoteList(subject, userAndRoles);
     return new JsonResponse<>(Status.OK).build();
diff --git 
a/zeppelin-server/src/main/java/org/apache/zeppelin/server/ZeppelinServer.java 
b/zeppelin-server/src/main/java/org/apache/zeppelin/server/ZeppelinServer.java
index 0c9b1cf..b231fd4 100644
--- 
a/zeppelin-server/src/main/java/org/apache/zeppelin/server/ZeppelinServer.java
+++ 
b/zeppelin-server/src/main/java/org/apache/zeppelin/server/ZeppelinServer.java
@@ -51,6 +51,7 @@ import 
org.apache.zeppelin.interpreter.InterpreterSettingManager;
 import org.apache.zeppelin.interpreter.recovery.RecoveryStorage;
 import org.apache.zeppelin.interpreter.remote.RemoteInterpreterProcessListener;
 import org.apache.zeppelin.notebook.NoteEventListener;
+import org.apache.zeppelin.notebook.NoteManager;
 import org.apache.zeppelin.notebook.Notebook;
 import org.apache.zeppelin.notebook.AuthorizationService;
 import org.apache.zeppelin.notebook.Paragraph;
@@ -164,6 +165,7 @@ public class ZeppelinServer extends ResourceConfig {
             bindAsContract(AdminService.class).in(Singleton.class);
             bindAsContract(AuthorizationService.class).in(Singleton.class);
             bindAsContract(ConnectionManager.class).in(Singleton.class);
+            bindAsContract(NoteManager.class).in(Singleton.class);
             // TODO(jl): Will make it more beautiful
             if (!StringUtils.isBlank(conf.getShiroPath())) {
               
bind(ShiroAuthenticationService.class).to(AuthenticationService.class).in(Singleton.class);
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 b6dda71..e6a7cab 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
@@ -39,8 +39,6 @@ import org.apache.commons.lang.StringUtils;
 import org.apache.zeppelin.conf.ZeppelinConfiguration;
 import org.apache.zeppelin.display.AngularObject;
 import org.apache.zeppelin.display.AngularObjectRegistry;
-import org.apache.zeppelin.interpreter.Interpreter;
-import org.apache.zeppelin.interpreter.InterpreterNotFoundException;
 import org.apache.zeppelin.interpreter.InterpreterResult;
 import org.apache.zeppelin.interpreter.InterpreterSetting;
 import org.apache.zeppelin.interpreter.thrift.InterpreterCompletion;
@@ -50,7 +48,6 @@ 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;
@@ -150,7 +147,7 @@ public class NotebookService {
 
     try {
       Note note = notebook.createNote(normalizeNotePath(notePath), 
defaultInterpreterGroup,
-          context.getAutheInfo());
+          context.getAutheInfo(), false);
       // it's an empty note. so add one paragraph
       note.addNewParagraph(context.getAutheInfo());
       notebook.saveNote(note, context.getAutheInfo());
@@ -928,8 +925,8 @@ public class NotebookService {
   }
 
   public void moveNoteToTrash(String noteId,
-                                 ServiceContext context,
-                                 ServiceCallback<Note> callback) throws 
IOException {
+                              ServiceContext context,
+                              ServiceCallback<Note> callback) throws 
IOException {
     Note note = notebook.getNote(noteId);
     if (note == null) {
       callback.onFailure(new NoteNotFoundException(noteId), context);
diff --git 
a/zeppelin-server/src/main/java/org/apache/zeppelin/socket/ConnectionManager.java
 
b/zeppelin-server/src/main/java/org/apache/zeppelin/socket/ConnectionManager.java
index 489a59f..906ee0f 100644
--- 
a/zeppelin-server/src/main/java/org/apache/zeppelin/socket/ConnectionManager.java
+++ 
b/zeppelin-server/src/main/java/org/apache/zeppelin/socket/ConnectionManager.java
@@ -28,7 +28,6 @@ import org.apache.zeppelin.display.GUI;
 import org.apache.zeppelin.display.Input;
 import org.apache.zeppelin.notebook.Note;
 import org.apache.zeppelin.notebook.NoteInfo;
-import org.apache.zeppelin.notebook.NotebookAuthorization;
 import org.apache.zeppelin.notebook.NotebookImportDeserializer;
 import org.apache.zeppelin.notebook.Paragraph;
 import org.apache.zeppelin.notebook.AuthorizationService;
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 b177f64..c0c6bd6 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
@@ -635,8 +635,9 @@ public class NotebookServer extends WebSocketServlet
       subject = new AuthenticationInfo(StringUtils.EMPTY);
     }
     //send first to requesting user
+    AuthorizationService authorizationService = 
getNotebookAuthorizationService();
     List<NoteInfo> notesInfo = getNotebook().getNotesInfo(
-        noteId -> getNotebookAuthorizationService().isReader(noteId, 
userAndRoles));
+        noteId -> authorizationService.isReader(noteId, userAndRoles));
     Message message = new Message(OP.NOTES_INFO).put("notes", notesInfo);
     getConnectionManager().multicastToUser(subject.getUser(), message);
     //to others afterwards
@@ -1983,7 +1984,8 @@ public class NotebookServer extends WebSocketServlet
       }
 
       List<InterpreterSetting> intpSettings =
-              note.getBindedInterpreterSettings(new 
ArrayList<>(note.getOwners()));
+              note.getBindedInterpreterSettings(
+                      new 
ArrayList<>(getNotebookAuthorizationService().getOwners(note.getId())));
       if (intpSettings.isEmpty()) {
         continue;
       }
diff --git 
a/zeppelin-server/src/test/java/org/apache/zeppelin/service/NotebookServiceTest.java
 
b/zeppelin-server/src/test/java/org/apache/zeppelin/service/NotebookServiceTest.java
index 9fefd57..1d0b773 100644
--- 
a/zeppelin-server/src/test/java/org/apache/zeppelin/service/NotebookServiceTest.java
+++ 
b/zeppelin-server/src/test/java/org/apache/zeppelin/service/NotebookServiceTest.java
@@ -33,6 +33,7 @@ import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import java.io.File;
 import java.io.IOException;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -40,6 +41,7 @@ import java.util.List;
 import java.util.stream.Collectors;
 import java.util.stream.IntStream;
 
+import com.google.common.io.Files;
 import org.apache.commons.lang.StringUtils;
 import org.apache.zeppelin.conf.ZeppelinConfiguration;
 import org.apache.zeppelin.interpreter.Interpreter;
@@ -53,16 +55,19 @@ import 
org.apache.zeppelin.interpreter.ManagedInterpreterGroup;
 import org.apache.zeppelin.notebook.AuthorizationService;
 import org.apache.zeppelin.notebook.Note;
 import org.apache.zeppelin.notebook.NoteInfo;
+import org.apache.zeppelin.notebook.NoteManager;
 import org.apache.zeppelin.notebook.Notebook;
 import org.apache.zeppelin.notebook.Paragraph;
 import org.apache.zeppelin.notebook.repo.InMemoryNotebookRepo;
 import org.apache.zeppelin.notebook.repo.NotebookRepo;
+import org.apache.zeppelin.notebook.repo.VFSNotebookRepo;
 import org.apache.zeppelin.notebook.scheduler.QuartzSchedulerService;
 import org.apache.zeppelin.notebook.scheduler.SchedulerService;
 import org.apache.zeppelin.search.LuceneSearch;
 import org.apache.zeppelin.search.SearchService;
 import org.apache.zeppelin.user.AuthenticationInfo;
 import org.apache.zeppelin.user.Credentials;
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.mockito.ArgumentCaptor;
@@ -74,6 +79,7 @@ public class NotebookServiceTest {
 
   private static NotebookService notebookService;
 
+  private File notebookDir;
   private ServiceContext context =
       new ServiceContext(AuthenticationInfo.ANONYMOUS, new HashSet<>());
 
@@ -84,8 +90,12 @@ public class NotebookServiceTest {
 
   @Before
   public void setUp() throws Exception {
+    notebookDir = Files.createTempDir().getAbsoluteFile();
+    
System.setProperty(ZeppelinConfiguration.ConfVars.ZEPPELIN_NOTEBOOK_DIR.getVarName(),
+            notebookDir.getAbsolutePath());
     ZeppelinConfiguration zeppelinConfiguration = 
ZeppelinConfiguration.create();
-    NotebookRepo notebookRepo = new InMemoryNotebookRepo();
+    NotebookRepo notebookRepo = new VFSNotebookRepo();
+    notebookRepo.init(zeppelinConfiguration);
 
     InterpreterSettingManager mockInterpreterSettingManager = 
mock(InterpreterSettingManager.class);
     InterpreterFactory mockInterpreterFactory = mock(InterpreterFactory.class);
@@ -106,17 +116,20 @@ public class NotebookServiceTest {
     
when(mockInterpreterSetting.getStatus()).thenReturn(InterpreterSetting.Status.READY);
     SearchService searchService = new LuceneSearch(zeppelinConfiguration);
     Credentials credentials = new Credentials(false, null, null);
+    NoteManager noteManager = new NoteManager(notebookRepo);
+    AuthorizationService authorizationService = new 
AuthorizationService(zeppelinConfiguration);
     Notebook notebook =
         new Notebook(
             zeppelinConfiguration,
+            authorizationService,
             notebookRepo,
+            noteManager,
             mockInterpreterFactory,
             mockInterpreterSettingManager,
             searchService,
             credentials,
             null);
-    AuthorizationService authorizationService =
-        new AuthorizationService(notebook, notebook.getConf());
+
     SchedulerService schedulerService = new 
QuartzSchedulerService(zeppelinConfiguration, notebook);
     notebookService =
         new NotebookService(
@@ -128,6 +141,11 @@ public class NotebookServiceTest {
         .thenReturn(mockInterpreterSetting);
   }
 
+  @After
+  public void tearDown() {
+    notebookDir.delete();
+  }
+
   @Test
   public void testNoteOperations() throws IOException {
     // get home note
diff --git 
a/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/AuthorizationService.java
 
b/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/AuthorizationService.java
index 75c3a0b..9235828 100644
--- 
a/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/AuthorizationService.java
+++ 
b/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/AuthorizationService.java
@@ -17,8 +17,6 @@
 
 package org.apache.zeppelin.notebook;
 
-import com.google.common.base.Predicate;
-import com.google.common.collect.FluentIterable;
 import com.google.common.collect.Sets;
 import com.google.gson.Gson;
 import com.google.gson.reflect.TypeToken;
@@ -28,6 +26,7 @@ import org.apache.zeppelin.cluster.event.ClusterEvent;
 import org.apache.zeppelin.cluster.event.ClusterEventListener;
 import org.apache.zeppelin.cluster.event.ClusterMessage;
 import org.apache.zeppelin.conf.ZeppelinConfiguration;
+import org.apache.zeppelin.storage.ConfigStorage;
 import org.apache.zeppelin.user.AuthenticationInfo;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -36,7 +35,6 @@ import javax.inject.Inject;
 import java.io.IOException;
 import java.util.HashMap;
 import java.util.HashSet;
-import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
@@ -50,17 +48,63 @@ public class AuthorizationService implements 
ClusterEventListener {
   private static final Set<String> EMPTY_SET = new HashSet<>();
 
   private ZeppelinConfiguration conf;
-  private Notebook notebook;
+  private ConfigStorage configStorage;
+
   // contains roles for each user (username --> roles)
   private Map<String, Set<String>> userRoles = new HashMap<>();
 
+  // cached note permission info. (noteId --> NoteAuth)
+  private Map<String, NoteAuth> notesAuth = new HashMap<>();
+
   @Inject
-  public AuthorizationService(Notebook notebook, ZeppelinConfiguration conf) {
-    this.notebook = notebook;
+  public AuthorizationService(ZeppelinConfiguration conf) {
     this.conf = conf;
+    try {
+      this.configStorage = ConfigStorage.getInstance(conf);
+      // init notesAuth by reading notebook-authorization.json
+      NotebookAuthorizationInfoSaving authorizationInfoSaving = 
configStorage.loadNotebookAuthorization();
+      if (authorizationInfoSaving != null) {
+        for (Map.Entry<String, Map<String, Set<String>>> entry : 
authorizationInfoSaving.authInfo.entrySet()) {
+          String noteId = entry.getKey();
+          Map<String, Set<String>> permissions = entry.getValue();
+          notesAuth.put(noteId, new NoteAuth(noteId, permissions));
+        }
+      }
+    } catch (IOException e) {
+      throw new RuntimeException("Fail to create ConfigStorage", e);
+    }
   }
 
-  private Set<String> validateUser(Set<String> users) {
+  /**
+   * Create NoteAuth, this method only create NoteAuth in memory, you need to 
call method
+   * saveNoteAuth to persistent it to storage.
+   * @param noteId
+   * @param subject
+   * @throws IOException
+   */
+  public void createNoteAuth(String noteId, AuthenticationInfo subject) throws 
IOException {
+    NoteAuth noteAuth =  new NoteAuth(noteId, subject);
+    this.notesAuth.put(noteId, noteAuth);
+  }
+
+  public void cloneNoteMeta(String noteId, String sourceNoteId, 
AuthenticationInfo subject) throws IOException {
+    NoteAuth noteAuth =  new NoteAuth(noteId, subject);
+    this.notesAuth.put(noteId, noteAuth);
+  }
+
+  /**
+   * Persistent NoteAuth
+   *
+   * @param noteId
+   * @param subject
+   * @throws IOException
+   */
+  public void saveNoteAuth(String noteId, AuthenticationInfo subject) throws 
IOException {
+    configStorage.save(new NotebookAuthorizationInfoSaving(this.notesAuth));
+  }
+
+  // skip empty user and remove the white space around user name.
+  private Set<String> normalizeUsers(Set<String> users) {
     Set<String> returnUser = new HashSet<>();
     for (String user : users) {
       if (!user.trim().isEmpty()) {
@@ -71,164 +115,167 @@ public class AuthorizationService implements 
ClusterEventListener {
   }
 
   public void setOwners(String noteId, Set<String> entities) throws 
IOException {
-    inlineSetOwners(noteId, entities);
-    broadcastClusterEvent(ClusterEvent.SET_OWNERS_PERMISSIONS, noteId, null, 
entities);
-  }
-
-  private void inlineSetOwners(String noteId, Set<String> entities) throws 
IOException {
-    entities = validateUser(entities);
-    notebook.getNote(noteId).setOwners(entities);
+    setOwners(noteId, entities, true);
   }
 
   public void setReaders(String noteId, Set<String> entities) throws 
IOException {
-    inlineSetReaders(noteId, entities);
-    broadcastClusterEvent(ClusterEvent.SET_READERS_PERMISSIONS, noteId, null, 
entities);
+    setReaders(noteId, entities, true);
   }
 
-  private void inlineSetReaders(String noteId, Set<String> entities) throws 
IOException {
-    entities = validateUser(entities);
-    notebook.getNote(noteId).setReaders(entities);
+  public void setWriters(String noteId, Set<String> entities) throws 
IOException {
+    setWriters(noteId, entities, true);
   }
 
   public void setRunners(String noteId, Set<String> entities) throws 
IOException {
-    inlineSetRunners(noteId, entities);
-    broadcastClusterEvent(ClusterEvent.SET_RUNNERS_PERMISSIONS, noteId, null, 
entities);
+    setRunners(noteId, entities, true);
   }
 
-  private void inlineSetRunners(String noteId, Set<String> entities) throws 
IOException {
-    entities = validateUser(entities);
-    notebook.getNote(noteId).setRunners(entities);
+  public void setRoles(String user, Set<String> roles) {
+    setRoles(user, roles, true);
   }
 
-  public void setWriters(String noteId, Set<String> entities) throws 
IOException {
-    inlineSetWriters(noteId, entities);
-    broadcastClusterEvent(ClusterEvent.SET_WRITERS_PERMISSIONS, noteId, null, 
entities);
+  public void clearPermission(String noteId) throws IOException {
+    clearPermission(noteId, true);
+  }
+
+  public void setOwners(String noteId, Set<String> entities, boolean 
broadcast) throws IOException {
+    entities = normalizeUsers(entities);
+    NoteAuth noteAuth = notesAuth.get(noteId);
+    if (noteAuth == null) {
+      throw new IOException("No note found for noteId: " + noteId);
+    }
+    noteAuth.setOwners(entities);
+    if (broadcast) {
+      broadcastClusterEvent(ClusterEvent.SET_OWNERS_PERMISSIONS, noteId, null, 
entities);
+    }
+  }
+
+  public void setReaders(String noteId, Set<String> entities, boolean 
broadcast) throws IOException {
+    entities = normalizeUsers(entities);
+    NoteAuth noteAuth = notesAuth.get(noteId);
+    if (noteAuth == null) {
+      throw new IOException("No note found for noteId: " + noteId);
+    }
+    noteAuth.setReaders(entities);
+    if (broadcast) {
+      broadcastClusterEvent(ClusterEvent.SET_READERS_PERMISSIONS, noteId, 
null, entities);
+    }
   }
 
-  private void inlineSetWriters(String noteId, Set<String> entities) throws 
IOException {
-    entities = validateUser(entities);
-    notebook.getNote(noteId).setWriters(entities);
+  public void setRunners(String noteId, Set<String> entities, boolean 
broadcast) throws IOException {
+    entities = normalizeUsers(entities);
+    NoteAuth noteAuth = notesAuth.get(noteId);
+    if (noteAuth == null) {
+      throw new IOException("No note found for noteId: " + noteId);
+    }
+    noteAuth.setRunners(entities);
+    if (broadcast) {
+      broadcastClusterEvent(ClusterEvent.SET_RUNNERS_PERMISSIONS, noteId, 
null, entities);
+    }
+  }
+
+  public void setWriters(String noteId, Set<String> entities, boolean 
broadcast) throws IOException {
+    entities = normalizeUsers(entities);
+    NoteAuth noteAuth = notesAuth.get(noteId);
+    if (noteAuth == null) {
+      throw new IOException("No note found for noteId: " + noteId);
+    }
+    noteAuth.setWriters(entities);
+    if (broadcast) {
+      broadcastClusterEvent(ClusterEvent.SET_WRITERS_PERMISSIONS, noteId, 
null, entities);
+    }
+  }
+
+  public void setRoles(String user, Set<String> roles, boolean broadcast) {
+    if (StringUtils.isBlank(user)) {
+      LOGGER.warn("Setting roles for empty user");
+      return;
+    }
+    roles = normalizeUsers(roles);
+    userRoles.put(user, roles);
+    if (broadcast) {
+      broadcastClusterEvent(ClusterEvent.SET_ROLES, null, user, roles);
+    }
+  }
+
+  public void clearPermission(String noteId, boolean broadcast) throws 
IOException {
+    NoteAuth noteAuth = notesAuth.get(noteId);
+    if (noteAuth == null) {
+      throw new IOException("No note found for noteId: " + noteId);
+    }
+    noteAuth.setReaders(Sets.newHashSet());
+    noteAuth.setRunners(Sets.newHashSet());
+    noteAuth.setWriters(Sets.newHashSet());
+    noteAuth.setOwners(Sets.newHashSet());
+
+    if (broadcast) {
+      broadcastClusterEvent(ClusterEvent.CLEAR_PERMISSION, noteId, null, null);
+    }
   }
 
   public Set<String> getOwners(String noteId) {
-    try {
-      Note note = notebook.getNote(noteId);
-      if (note == null) {
-        LOGGER.warn("Note " + noteId + " not found");
-        return EMPTY_SET;
-      }
-      return note.getOwners();
-    } catch (IOException e) {
-      LOGGER.warn("Fail to getOwner for note: " + noteId, e);
+    NoteAuth noteAuth = notesAuth.get(noteId);
+    if (noteAuth == null) {
+      LOGGER.warn("No note found for noteId: " + noteId);
       return EMPTY_SET;
     }
+    return noteAuth.getOwners();
   }
 
   public Set<String> getReaders(String noteId) {
-    try {
-      Note note = notebook.getNote(noteId);
-      if (note == null) {
-        LOGGER.warn("Note " + noteId + " not found");
-        return EMPTY_SET;
-      }
-      return note.getReaders();
-    } catch (IOException e) {
-      LOGGER.warn("Fail to getReaders for note: " + noteId, e);
+    NoteAuth noteAuth = notesAuth.get(noteId);
+    if (noteAuth == null) {
+      LOGGER.warn("No note found for noteId: " + noteId);
       return EMPTY_SET;
     }
+    return noteAuth.getReaders();
   }
 
   public Set<String> getRunners(String noteId) {
-    try {
-      Note note = notebook.getNote(noteId);
-      if (note == null) {
-        LOGGER.warn("Note " + noteId + " not found");
-        return EMPTY_SET;
-      }
-      return note.getRunners();
-    } catch (IOException e) {
-      LOGGER.warn("Fail to getRunners for note: " + noteId, e);
+    NoteAuth noteAuth = notesAuth.get(noteId);
+    if (noteAuth == null) {
+      LOGGER.warn("No note found for noteId: " + noteId);
       return EMPTY_SET;
     }
+    return noteAuth.getRunners();
   }
 
   public Set<String> getWriters(String noteId) {
-    try {
-      Note note = notebook.getNote(noteId);
-      if (note == null) {
-        LOGGER.warn("Note " + noteId + " not found");
-        return EMPTY_SET;
-      }
-      return note.getWriters();
-    } catch (IOException e) {
-      LOGGER.warn("Fail to getWriters for note: " + noteId, e);
+    NoteAuth noteAuth = notesAuth.get(noteId);
+    if (noteAuth == null) {
+      LOGGER.warn("No note found for noteId: " + noteId);
       return EMPTY_SET;
     }
+    return noteAuth.getWriters();
+  }
+
+  public Set<String> getRoles(String user) {
+    return userRoles.getOrDefault(user, Sets.newHashSet());
   }
 
   public boolean isOwner(String noteId, Set<String> entities) {
-    try {
-      Note note = notebook.getNote(noteId);
-      if (note == null) {
-        LOGGER.warn("Note " + noteId + " not found");
-        return false;
-      }
-      return isMember(entities, note.getOwners()) || isAdmin(entities);
-    } catch (IOException e) {
-      LOGGER.warn("Fail to check isOwner for note: " + noteId, e);
-      return false;
-    }
+    return isMember(entities, getOwners(noteId)) || isAdmin(entities);
   }
 
   public boolean isWriter(String noteId, Set<String> entities) {
-    try {
-      Note note = notebook.getNote(noteId);
-      if (note == null) {
-        LOGGER.warn("Note " + noteId + " not found");
-        return false;
-      }
-      return isMember(entities, note.getWriters()) ||
-              isMember(entities, note.getOwners()) ||
-              isAdmin(entities);
-    } catch (IOException e) {
-      LOGGER.warn("Fail to check isWriter for note: " + noteId, e);
-      return false;
-    }
+    return isMember(entities, getWriters(noteId)) ||
+            isMember(entities, getOwners(noteId)) ||
+            isAdmin(entities);
   }
 
   public boolean isReader(String noteId, Set<String> entities) {
-    try {
-      Note note = notebook.getNote(noteId);
-      if (note == null) {
-        LOGGER.warn("Note " + noteId + " not found");
-        return false;
-      }
-      return isMember(entities, note.getReaders()) ||
-              isMember(entities, note.getOwners()) ||
-              isMember(entities, note.getWriters()) ||
-              isMember(entities, note.getRunners()) ||
-              isAdmin(entities);
-    } catch (IOException e) {
-      LOGGER.warn("Fail to check isReader for note: " + noteId, e);
-      return false;
-    }
+    return isMember(entities, getReaders(noteId)) ||
+            isMember(entities, getOwners(noteId)) ||
+            isMember(entities, getWriters(noteId)) ||
+            isMember(entities, getRunners(noteId)) ||
+            isAdmin(entities);
   }
 
   public boolean isRunner(String noteId, Set<String> entities) {
-    try {
-      Note note = notebook.getNote(noteId);
-      if (note == null) {
-        LOGGER.warn("Note " + noteId + " not found");
-        return false;
-      }
-      return isMember(entities, note.getRunners()) ||
-              isMember(entities, note.getWriters()) ||
-              isMember(entities, note.getOwners()) ||
-              isAdmin(entities);
-    } catch (IOException e) {
-      LOGGER.warn("Fail to check isRunner for note: " + noteId, e);
-      return false;
-    }
+    return isMember(entities, getRunners(noteId)) ||
+            isMember(entities, getWriters(noteId)) ||
+            isMember(entities, getOwners(noteId)) ||
+            isAdmin(entities);
   }
 
   private boolean isAdmin(Set<String> entities) {
@@ -295,40 +342,6 @@ public class AuthorizationService implements 
ClusterEventListener {
     return conf.isNotebookPublic();
   }
 
-  public void setRoles(String user, Set<String> roles) {
-    inlineSetRoles(user, roles);
-    broadcastClusterEvent(ClusterEvent.SET_ROLES, null, user, roles);
-  }
-
-  private void inlineSetRoles(String user, Set<String> roles) {
-    if (StringUtils.isBlank(user)) {
-      LOGGER.warn("Setting roles for empty user");
-      return;
-    }
-    roles = validateUser(roles);
-    userRoles.put(user, roles);
-  }
-
-  public Set<String> getRoles(String user) {
-    Set<String> roles = Sets.newHashSet();
-    if (userRoles.containsKey(user)) {
-      roles.addAll(userRoles.get(user));
-    }
-    return roles;
-  }
-
-  public void clearPermission(String noteId) throws IOException {
-    inlineClearPermission(noteId);
-    broadcastClusterEvent(ClusterEvent.CLEAR_PERMISSION, noteId, null, null);
-  }
-
-  public void inlineClearPermission(String noteId) throws IOException {
-    notebook.getNote(noteId).setReaders(Sets.newHashSet());
-    notebook.getNote(noteId).setRunners(Sets.newHashSet());
-    notebook.getNote(noteId).setWriters(Sets.newHashSet());
-    notebook.getNote(noteId).setOwners(Sets.newHashSet());
-  }
-
   @Override
   public void onClusterEvent(String msg) {
     if (LOGGER.isDebugEnabled()) {
@@ -347,22 +360,22 @@ public class AuthorizationService implements 
ClusterEventListener {
     try {
       switch (message.clusterEvent) {
         case SET_READERS_PERMISSIONS:
-          inlineSetReaders(noteId, set);
+          setReaders(noteId, set, false);
           break;
         case SET_WRITERS_PERMISSIONS:
-          inlineSetWriters(noteId, set);
+          setWriters(noteId, set, false);
           break;
         case SET_OWNERS_PERMISSIONS:
-          inlineSetOwners(noteId, set);
+          setOwners(noteId, set, false);
           break;
         case SET_RUNNERS_PERMISSIONS:
-          inlineSetRunners(noteId, set);
+          setRunners(noteId, set, false);
           break;
         case SET_ROLES:
-          inlineSetRoles(user, set);
+          setRoles(user, set, false);
           break;
         case CLEAR_PERMISSION:
-          inlineClearPermission(noteId);
+          clearPermission(noteId, false);
           break;
         default:
           LOGGER.error("Unknown clusterEvent:{}, msg:{} ", 
message.clusterEvent, msg);
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 ab7016a..777b47d 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
@@ -95,9 +95,7 @@ public class Note implements JsonSerializable {
   private String id;
   private String defaultInterpreterGroup;
   private String version;
-  // permissions -> users
-  // e.g. "owners" -> {"u1"}, "readers" -> {"u1", "u2"}
-  private Map<String, Set<String>> permissions = new HashMap<>();
+
   private Map<String, Object> noteParams = new LinkedHashMap<>();
   private Map<String, Input> noteForms = new LinkedHashMap<>();
   private Map<String, List<AngularObject>> angularObjects = new HashMap<>();
@@ -244,103 +242,6 @@ public class Note implements JsonSerializable {
     this.defaultInterpreterGroup = defaultInterpreterGroup;
   }
 
-  // used when creating new note
-  public void initPermissions(AuthenticationInfo subject) {
-    if (!AuthenticationInfo.isAnonymous(subject)) {
-      if (ZeppelinConfiguration.create().isNotebookPublic()) {
-        // add current user to owners - can be public
-        Set<String> owners = getOwners();
-        owners.add(subject.getUser());
-        setOwners(owners);
-      } else {
-        // add current user to owners, readers, runners, writers - private note
-        Set<String> entities = getOwners();
-        entities.add(subject.getUser());
-        setOwners(entities);
-        entities = getReaders();
-        entities.add(subject.getUser());
-        setReaders(entities);
-        entities = getRunners();
-        entities.add(subject.getUser());
-        setRunners(entities);
-        entities = getWriters();
-        entities.add(subject.getUser());
-        setWriters(entities);
-      }
-    }
-  }
-
-  public void setOwners(Set<String> entities) {
-    permissions.put("owners", entities);
-  }
-
-  public Set<String> getOwners() {
-    Set<String> owners = permissions.get("owners");
-    if (owners == null) {
-      owners = new HashSet<>();
-    } else {
-      owners = checkCaseAndConvert(owners);
-    }
-    return owners;
-  }
-
-  public Set<String> getReaders() {
-    Set<String> readers = permissions.get("readers");
-    if (readers == null) {
-      readers = new HashSet<>();
-    } else {
-      readers = checkCaseAndConvert(readers);
-    }
-    return readers;
-  }
-
-  public void setReaders(Set<String> entities) {
-    permissions.put("readers", entities);
-  }
-
-  public Set<String> getRunners() {
-    Set<String> runners = permissions.get("runners");
-    if (runners == null) {
-      runners = new HashSet<>();
-    } else {
-      runners = checkCaseAndConvert(runners);
-    }
-    return runners;
-  }
-
-  public void setRunners(Set<String> entities) {
-    permissions.put("runners", entities);
-  }
-
-  public Set<String> getWriters() {
-    Set<String> writers = permissions.get("writers");
-    if (writers == null) {
-      writers = new HashSet<>();
-    } else {
-      writers = checkCaseAndConvert(writers);
-    }
-    return writers;
-  }
-
-  public void setWriters(Set<String> entities) {
-    permissions.put("writers", entities);
-  }
-
-  /*
-   * If case conversion is enforced, then change entity names to lower case
-   */
-  private Set<String> checkCaseAndConvert(Set<String> entities) {
-    if (ZeppelinConfiguration.create().isUsernameForceLowerCase()) {
-      Set<String> set2 = new HashSet<String>();
-      for (String name : entities) {
-        set2.add(name.toLowerCase());
-      }
-      return set2;
-    } else {
-      return entities;
-    }
-  }
-
   public Map<String, Object> getNoteParams() {
     return noteParams;
   }
@@ -359,6 +260,7 @@ public class Note implements JsonSerializable {
 
   public void setName(String name) {
     this.name = name;
+    // for the notes before 0.9, get path from name.
     if (this.path == null) {
       if (name.startsWith("/")) {
         this.path = name;
diff --git 
a/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/NoteAuth.java 
b/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/NoteAuth.java
new file mode 100644
index 0000000..7f6c84b
--- /dev/null
+++ b/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/NoteAuth.java
@@ -0,0 +1,154 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.zeppelin.notebook;
+
+import com.google.common.collect.Sets;
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import org.apache.zeppelin.conf.ZeppelinConfiguration;
+import org.apache.zeppelin.user.AuthenticationInfo;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Represent note authorization info, including (readers, writers, runners, 
owners)
+ *
+ */
+public class NoteAuth {
+
+  private static Gson gson = new GsonBuilder().setPrettyPrinting().create();
+
+  private String noteId;
+  private Set<String> readers = new HashSet<>();
+  private Set<String> writers = new HashSet<>();
+  private Set<String> runners = new HashSet<>();
+  private Set<String> owners = new HashSet<>();
+
+  public NoteAuth(String noteId) {
+    this(noteId, AuthenticationInfo.ANONYMOUS);
+  }
+
+  public NoteAuth(String noteId, AuthenticationInfo subject) {
+    this.noteId = noteId;
+    initPermissions(subject);
+  }
+
+  public NoteAuth(String noteId, Map<String, Set<String>> permissions) {
+    this.noteId = noteId;
+    this.readers = permissions.getOrDefault("readers", Sets.newHashSet());
+    this.writers = permissions.getOrDefault("writers", Sets.newHashSet());
+    this.runners = permissions.getOrDefault("runners", Sets.newHashSet());
+    this.owners = permissions.getOrDefault("owners", Sets.newHashSet());
+  }
+
+  // used when creating new note
+  public void initPermissions(AuthenticationInfo subject) {
+    if (!AuthenticationInfo.isAnonymous(subject)) {
+      if (ZeppelinConfiguration.create().isNotebookPublic()) {
+        // add current user to owners - can be public
+        this.owners.add(checkCaseAndConvert(subject.getUser()));
+      } else {
+        // add current user to owners, readers, runners, writers - private note
+        this.owners.add(checkCaseAndConvert(subject.getUser()));
+        this.readers.add(checkCaseAndConvert(subject.getUser()));
+        this.writers.add(checkCaseAndConvert(subject.getUser()));
+        this.runners.add(checkCaseAndConvert(subject.getUser()));
+      }
+    }
+  }
+
+  public String getNoteId() {
+    return noteId;
+  }
+
+  public void setOwners(Set<String> entities) {
+    this.owners = checkCaseAndConvert(entities);
+  }
+
+  public void setReaders(Set<String> entities) {
+    this.readers = checkCaseAndConvert(entities);
+  }
+
+  public void setWriters(Set<String> entities) {
+    this.writers = checkCaseAndConvert(entities);
+  }
+
+  public void setRunners(Set<String> entities) {
+    this.runners = checkCaseAndConvert(entities);
+  }
+
+  public Set<String> getOwners() {
+    return this.owners;
+  }
+
+  public Set<String> getReaders() {
+    return this.readers;
+  }
+
+  public Set<String> getWriters() {
+    return this.writers;
+  }
+
+  public Set<String> getRunners() {
+    return this.runners;
+  }
+
+  /*
+   * If case conversion is enforced, then change entity names to lower case
+   */
+  private Set<String> checkCaseAndConvert(Set<String> entities) {
+    if (ZeppelinConfiguration.create().isUsernameForceLowerCase()) {
+      Set<String> set2 = new HashSet<String>();
+      for (String name : entities) {
+        set2.add(name.toLowerCase());
+      }
+      return set2;
+    } else {
+      return entities;
+    }
+  }
+
+  private String checkCaseAndConvert(String entity) {
+    if (ZeppelinConfiguration.create().isUsernameForceLowerCase()) {
+      return entity.toLowerCase();
+    } else {
+      return entity;
+    }
+  }
+
+  public Map<String, Set<String>> toMap() {
+    Map<String, Set<String>> map = new HashMap<>();
+    map.put("readers", readers);
+    map.put("writers", writers);
+    map.put("runners", runners);
+    map.put("owners", owners);
+    return map;
+  }
+
+  public String toJson() {
+    return gson.toJson(this);
+  }
+
+  public static NoteAuth fromJson(String json) {
+    return gson.fromJson(json, NoteAuth.class);
+  }
+
+}
diff --git 
a/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/NoteManager.java 
b/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/NoteManager.java
index 9e06750..c260208 100644
--- 
a/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/NoteManager.java
+++ 
b/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/NoteManager.java
@@ -21,11 +21,12 @@ package org.apache.zeppelin.notebook;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.zeppelin.conf.ZeppelinConfiguration;
 import org.apache.zeppelin.notebook.repo.NotebookRepo;
-import org.apache.zeppelin.scheduler.Job;
 import org.apache.zeppelin.user.AuthenticationInfo;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import javax.inject.Inject;
+import javax.inject.Singleton;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -47,6 +48,7 @@ import java.util.stream.Collectors;
  * TODO(zjffdu) implement the lifecycle manager of Note
  * (release memory if note is not used for some period)
  */
+@Singleton
 public class NoteManager {
   private static final Logger LOGGER = 
LoggerFactory.getLogger(NoteManager.class);
   public static String TRASH_FOLDER = "~Trash";
@@ -57,6 +59,7 @@ public class NoteManager {
   // noteId -> notePath
   private Map<String, String> notesInfo;
 
+  @Inject
   public NoteManager(NotebookRepo notebookRepo) throws IOException {
     this.notebookRepo = notebookRepo;
     this.root = new Folder("/", notebookRepo);
@@ -171,7 +174,6 @@ public class NoteManager {
 
   public void addNote(Note note, AuthenticationInfo subject) throws 
IOException {
     addOrUpdateNoteNode(note, true);
-    this.notebookRepo.save(note, subject);
     note.setLoaded(true);
   }
 
@@ -222,7 +224,6 @@ public class NoteManager {
     this.notebookRepo.move(noteId, notePath, newNotePath, subject);
   }
 
-
   public void moveFolder(String folderPath,
                          String newFolderPath,
                          AuthenticationInfo subject) throws IOException {
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 c12790e..3e478d5 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
@@ -24,7 +24,6 @@ import java.util.Comparator;
 import java.util.Date;
 import java.util.HashMap;
 import java.util.HashSet;
-import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -64,8 +63,8 @@ import org.slf4j.LoggerFactory;
 public class Notebook {
   private static final Logger LOGGER = LoggerFactory.getLogger(Notebook.class);
 
+  private AuthorizationService authorizationService;
   private NoteManager noteManager;
-
   private InterpreterFactory replFactory;
   private InterpreterSettingManager interpreterSettingManager;
   private ZeppelinConfiguration conf;
@@ -83,14 +82,17 @@ public class Notebook {
    */
   public Notebook(
       ZeppelinConfiguration conf,
+      AuthorizationService authorizationService,
       NotebookRepo notebookRepo,
+      NoteManager noteManager,
       InterpreterFactory replFactory,
       InterpreterSettingManager interpreterSettingManager,
       SearchService noteSearchService,
       Credentials credentials)
       throws IOException {
-    this.noteManager = new NoteManager(notebookRepo);
     this.conf = conf;
+    this.authorizationService = authorizationService;
+    this.noteManager = noteManager;
     this.notebookRepo = notebookRepo;
     this.replFactory = replFactory;
     this.interpreterSettingManager = interpreterSettingManager;
@@ -106,7 +108,9 @@ public class Notebook {
   @Inject
   public Notebook(
       ZeppelinConfiguration conf,
+      AuthorizationService authorizationService,
       NotebookRepo notebookRepo,
+      NoteManager noteManager,
       InterpreterFactory replFactory,
       InterpreterSettingManager interpreterSettingManager,
       SearchService noteSearchService,
@@ -115,7 +119,9 @@ public class Notebook {
       throws IOException {
     this(
         conf,
+        authorizationService,
         notebookRepo,
+        noteManager,
         replFactory,
         interpreterSettingManager,
         noteSearchService,
@@ -126,6 +132,10 @@ public class Notebook {
     this.paragraphJobListener = (ParagraphJobListener) noteEventListener;
   }
 
+  public NoteManager getNoteManager() {
+    return noteManager;
+  }
+
   /**
    * This method will be called only NotebookService to register {@link *
    * org.apache.zeppelin.notebook.ParagraphJobListener}.
@@ -150,6 +160,23 @@ public class Notebook {
   }
 
   /**
+   * Creating new note. defaultInterpreterGroup is not provided, so the global
+   * defaultInterpreterGroup (zeppelin.interpreter.group.default) is used
+   *
+   * @param notePath
+   * @param subject
+   * @param save
+   * @return
+   * @throws IOException
+   */
+  public Note createNote(String notePath,
+                         AuthenticationInfo subject,
+                         boolean save) throws IOException {
+    return createNote(notePath, 
interpreterSettingManager.getDefaultInterpreterSetting().getName(),
+            subject, save);
+  }
+
+  /**
    * Creating new note.
    *
    * @param notePath
@@ -161,11 +188,32 @@ public class Notebook {
   public Note createNote(String notePath,
                          String defaultInterpreterGroup,
                          AuthenticationInfo subject) throws IOException {
+    return createNote(notePath, defaultInterpreterGroup, subject, true);
+  }
+
+  /**
+   * Creating new note.
+   *
+   * @param notePath
+   * @param defaultInterpreterGroup
+   * @param subject
+   * @return
+   * @throws IOException
+   */
+  public Note createNote(String notePath,
+                         String defaultInterpreterGroup,
+                         AuthenticationInfo subject,
+                         boolean save) throws IOException {
     Note note =
-        new Note(notePath, defaultInterpreterGroup, replFactory, 
interpreterSettingManager,
-            paragraphJobListener, credentials, noteEventListeners);
-    note.initPermissions(subject);
+            new Note(notePath, defaultInterpreterGroup, replFactory, 
interpreterSettingManager,
+                    paragraphJobListener, credentials, noteEventListeners);
     noteManager.addNote(note, subject);
+    // init noteMeta
+    authorizationService.createNoteAuth(note.getId(), subject);
+    authorizationService.saveNoteAuth(note.getId(), subject);
+    if (save) {
+      noteManager.saveNote(note, subject);
+    }
     fireNoteCreateEvent(note, subject);
     return note;
   }
@@ -225,12 +273,13 @@ public class Notebook {
     if (sourceNote == null) {
       throw new IOException("Source note: " + sourceNoteId + " not found");
     }
-    Note newNote = createNote(newNotePath, subject);
+    Note newNote = createNote(newNotePath, subject, false);
     List<Paragraph> paragraphs = sourceNote.getParagraphs();
     for (Paragraph p : paragraphs) {
       newNote.addCloneParagraph(p, subject);
     }
     saveNote(newNote, subject);
+    authorizationService.cloneNoteMeta(newNote.getId(), sourceNoteId, subject);
     return newNote;
   }
 
@@ -502,6 +551,7 @@ public class Notebook {
   }
 
   public List<NoteInfo> getNotesInfo(Function<String, Boolean> func) {
+    LOGGER.info("Start getNoteList");
     String homescreenNoteId = 
conf.getString(ConfVars.ZEPPELIN_NOTEBOOK_HOMESCREEN);
     boolean hideHomeScreenNotebookFromList =
         conf.getBoolean(ConfVars.ZEPPELIN_NOTEBOOK_HOMESCREEN_HIDE);
@@ -525,6 +575,7 @@ public class Notebook {
             }
             return name1.compareTo(name2);
           });
+      LOGGER.info("Finish getNoteList");
       return notesInfo;
     }
   }
diff --git 
a/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/NotebookAuthorization.java
 
b/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/NotebookAuthorization.java
deleted file mode 100644
index d52dc77..0000000
--- 
a/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/NotebookAuthorization.java
+++ /dev/null
@@ -1,444 +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.notebook;
-
-import java.io.IOException;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.LinkedHashMap;
-import java.util.LinkedHashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import org.apache.commons.lang.StringUtils;
-import org.apache.zeppelin.conf.ZeppelinConfiguration;
-import org.apache.zeppelin.conf.ZeppelinConfiguration.ConfVars;
-import org.apache.zeppelin.scheduler.Job;
-import org.apache.zeppelin.storage.ConfigStorage;
-import org.apache.zeppelin.user.AuthenticationInfo;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.common.base.Predicate;
-import com.google.common.collect.FluentIterable;
-import com.google.common.collect.Sets;
-
-/**
- * Contains authorization information for notes
- */
-public class NotebookAuthorization implements NoteEventListener {
-  private static final Logger LOG = 
LoggerFactory.getLogger(NotebookAuthorization.class);
-  private static NotebookAuthorization instance = null;
-  /*
-   * { "note1": { "owners": ["u1"], "readers": ["u1", "u2"], "runners": ["u2"],
-   * "writers": ["u1"] },  "note2": ... } }
-   */
-  private static Map<String, Map<String, Set<String>>> authInfo = new 
HashMap<>();
-  /*
-   * contains roles for each user
-   */
-  private static Map<String, Set<String>> userRoles = new HashMap<>();
-  private static ZeppelinConfiguration conf;
-
-  private static ConfigStorage configStorage;
-
-  private NotebookAuthorization() {}
-
-  public static NotebookAuthorization init(ZeppelinConfiguration config) {
-    if (instance == null) {
-      instance = new NotebookAuthorization();
-      conf = config;
-      try {
-        configStorage = ConfigStorage.getInstance(config);
-        loadFromFile();
-      } catch (IOException e) {
-        LOG.error("Error loading NotebookAuthorization", e);
-      }
-    }
-    return instance;
-  }
-
-  public static NotebookAuthorization getInstance() {
-    if (instance == null) {
-      LOG.warn("Notebook authorization module was called without 
initialization,"
-          + " initializing with default configuration");
-      init(ZeppelinConfiguration.create());
-    }
-    return instance;
-  }
-
-  private static void loadFromFile() throws IOException {
-    NotebookAuthorizationInfoSaving info = 
configStorage.loadNotebookAuthorization();
-    if (info != null) {
-      authInfo = info.authInfo;
-    }
-  }
-  
-  public void setRoles(String user, Set<String> roles) {
-    if (StringUtils.isBlank(user)) {
-      LOG.warn("Setting roles for empty user");
-      return;
-    }
-    roles = validateUser(roles);
-    userRoles.put(user, roles);
-  }
-  
-  public Set<String> getRoles(String user) {
-    Set<String> roles = Sets.newHashSet();
-    if (userRoles.containsKey(user)) {
-      roles.addAll(userRoles.get(user));
-    }
-    return roles;
-  }
-  
-  private void saveToFile() {
-    synchronized (authInfo) {
-      NotebookAuthorizationInfoSaving info = new 
NotebookAuthorizationInfoSaving();
-      info.authInfo = authInfo;
-      try {
-        configStorage.save(info);
-      } catch (IOException e) {
-        LOG.error("Error saving notebook authorization file", e);
-      }
-    }
-  }
-  
-  public boolean isPublic() {
-    return conf.isNotebookPublic();
-  }
-
-  private Set<String> validateUser(Set<String> users) {
-    Set<String> returnUser = new HashSet<>();
-    for (String user : users) {
-      if (!user.trim().isEmpty()) {
-        returnUser.add(user.trim());
-      }
-    }
-    return returnUser;
-  }
-
-  public void setOwners(String noteId, Set<String> entities) {
-    Map<String, Set<String>> noteAuthInfo = authInfo.get(noteId);
-    entities = validateUser(entities);
-    if (noteAuthInfo == null) {
-      noteAuthInfo = new LinkedHashMap();
-      noteAuthInfo.put("owners", new LinkedHashSet(entities));
-      noteAuthInfo.put("readers", new LinkedHashSet());
-      noteAuthInfo.put("runners", new LinkedHashSet());
-      noteAuthInfo.put("writers", new LinkedHashSet());
-    } else {
-      noteAuthInfo.put("owners", new LinkedHashSet(entities));
-    }
-    authInfo.put(noteId, noteAuthInfo);
-    saveToFile();
-  }
-
-  public void setReaders(String noteId, Set<String> entities) {
-    Map<String, Set<String>> noteAuthInfo = authInfo.get(noteId);
-    entities = validateUser(entities);
-    if (noteAuthInfo == null) {
-      noteAuthInfo = new LinkedHashMap();
-      noteAuthInfo.put("owners", new LinkedHashSet());
-      noteAuthInfo.put("readers", new LinkedHashSet(entities));
-      noteAuthInfo.put("runners", new LinkedHashSet());
-      noteAuthInfo.put("writers", new LinkedHashSet());
-    } else {
-      noteAuthInfo.put("readers", new LinkedHashSet(entities));
-    }
-    authInfo.put(noteId, noteAuthInfo);
-    saveToFile();
-  }
-
-  public void setRunners(String noteId, Set<String> entities) {
-    Map<String, Set<String>> noteAuthInfo = authInfo.get(noteId);
-    entities = validateUser(entities);
-    if (noteAuthInfo == null) {
-      noteAuthInfo = new LinkedHashMap();
-      noteAuthInfo.put("owners", new LinkedHashSet());
-      noteAuthInfo.put("readers", new LinkedHashSet());
-      noteAuthInfo.put("runners", new LinkedHashSet(entities));
-      noteAuthInfo.put("writers", new LinkedHashSet());
-    } else {
-      noteAuthInfo.put("runners", new LinkedHashSet(entities));
-    }
-    authInfo.put(noteId, noteAuthInfo);
-    saveToFile();
-  }
-
-
-  public void setWriters(String noteId, Set<String> entities) {
-    Map<String, Set<String>> noteAuthInfo = authInfo.get(noteId);
-    entities = validateUser(entities);
-    if (noteAuthInfo == null) {
-      noteAuthInfo = new LinkedHashMap();
-      noteAuthInfo.put("owners", new LinkedHashSet());
-      noteAuthInfo.put("readers", new LinkedHashSet());
-      noteAuthInfo.put("runners", new LinkedHashSet());
-      noteAuthInfo.put("writers", new LinkedHashSet(entities));
-    } else {
-      noteAuthInfo.put("writers", new LinkedHashSet(entities));
-    }
-    authInfo.put(noteId, noteAuthInfo);
-    saveToFile();
-  }
-
-  /*
-  * If case conversion is enforced, then change entity names to lower case
-  */
-  private Set<String> checkCaseAndConvert(Set<String> entities) {
-    if (conf.isUsernameForceLowerCase()) {
-      Set<String> set2 = new HashSet<String>();
-      for (String name : entities) {
-        set2.add(name.toLowerCase());
-      }
-      return set2;
-    } else {
-      return entities;
-    }
-  }
-
-  public Set<String> getOwners(String noteId) {
-    Map<String, Set<String>> noteAuthInfo = authInfo.get(noteId);
-    Set<String> entities = null;
-    if (noteAuthInfo == null) {
-      entities = new HashSet<>();
-    } else {
-      entities = noteAuthInfo.get("owners");
-      if (entities == null) {
-        entities = new HashSet<>();
-      } else {
-        entities = checkCaseAndConvert(entities);
-      }
-    }
-    return entities;
-  }
-
-  public Set<String> getReaders(String noteId) {
-    Map<String, Set<String>> noteAuthInfo = authInfo.get(noteId);
-    Set<String> entities = null;
-    if (noteAuthInfo == null) {
-      entities = new HashSet<>();
-    } else {
-      entities = noteAuthInfo.get("readers");
-      if (entities == null) {
-        entities = new HashSet<>();
-      } else {
-        entities = checkCaseAndConvert(entities);
-      }
-    }
-    return entities;
-  }
-
-  public Set<String> getRunners(String noteId) {
-    Map<String, Set<String>> noteAuthInfo = authInfo.get(noteId);
-    Set<String> entities = null;
-    if (noteAuthInfo == null) {
-      entities = new HashSet<>();
-    } else {
-      entities = noteAuthInfo.get("runners");
-      if (entities == null) {
-        entities = new HashSet<>();
-      } else {
-        entities = checkCaseAndConvert(entities);
-      }
-    }
-    return entities;
-  }
-
-  public Set<String> getWriters(String noteId) {
-    Map<String, Set<String>> noteAuthInfo = authInfo.get(noteId);
-    Set<String> entities = null;
-    if (noteAuthInfo == null) {
-      entities = new HashSet<>();
-    } else {
-      entities = noteAuthInfo.get("writers");
-      if (entities == null) {
-        entities = new HashSet<>();
-      } else {
-        entities = checkCaseAndConvert(entities);
-      }
-    }
-    return entities;
-  }
-
-  public boolean isOwner(String noteId, Set<String> entities) {
-    return isMember(entities, getOwners(noteId)) || isAdmin(entities);
-  }
-
-  public boolean isWriter(String noteId, Set<String> entities) {
-    return isMember(entities, getWriters(noteId)) ||
-           isMember(entities, getOwners(noteId)) ||
-           isAdmin(entities);
-  }
-
-  public boolean isReader(String noteId, Set<String> entities) {
-    return isMember(entities, getReaders(noteId)) ||
-           isMember(entities, getOwners(noteId)) ||
-           isMember(entities, getWriters(noteId)) ||
-           isMember(entities, getRunners(noteId)) ||
-           isAdmin(entities);
-  }
-
-  public boolean isRunner(String noteId, Set<String> entities) {
-    return isMember(entities, getRunners(noteId)) ||
-           isMember(entities, getWriters(noteId)) ||
-           isMember(entities, getOwners(noteId)) ||
-           isAdmin(entities);
-  }
-
-  private boolean isAdmin(Set<String> entities) {
-    String adminRole = conf.getString(ConfVars.ZEPPELIN_OWNER_ROLE);
-    if (StringUtils.isBlank(adminRole)) {
-      return false;
-    }
-    return entities.contains(adminRole);
-  }
-
-  // return true if b is empty or if (a intersection b) is non-empty
-  private boolean isMember(Set<String> a, Set<String> b) {
-    Set<String> intersection = new HashSet<>(b);
-    intersection.retainAll(a);
-    return (b.isEmpty() || (intersection.size() > 0));
-  }
-
-  public boolean isOwner(Set<String> userAndRoles, String noteId) {
-    if (conf.isAnonymousAllowed()) {
-      LOG.debug("Zeppelin runs in anonymous mode, everybody is owner");
-      return true;
-    }
-    if (userAndRoles == null) {
-      return false;
-    }
-    return isOwner(noteId, userAndRoles);
-  }
-  
-  public boolean hasWriteAuthorization(Set<String> userAndRoles, String 
noteId) {
-    if (conf.isAnonymousAllowed()) {
-      LOG.debug("Zeppelin runs in anonymous mode, everybody is writer");
-      return true;
-    }
-    if (userAndRoles == null) {
-      return false;
-    }
-    return isWriter(noteId, userAndRoles);
-  }
-  
-  public boolean hasReadAuthorization(Set<String> userAndRoles, String noteId) 
{
-    if (conf.isAnonymousAllowed()) {
-      LOG.debug("Zeppelin runs in anonymous mode, everybody is reader");
-      return true;
-    }
-    if (userAndRoles == null) {
-      return false;
-    }
-    return isReader(noteId, userAndRoles);
-  }
-
-  public boolean hasRunAuthorization(Set<String> userAndRoles, String noteId) {
-    if (conf.isAnonymousAllowed()) {
-      LOG.debug("Zeppelin runs in anonymous mode, everybody is runner");
-      return true;
-    }
-    if (userAndRoles == null) {
-      return false;
-    }
-    return isRunner(noteId, userAndRoles);
-  }
-
-  public void removeNote(String noteId) {
-    authInfo.remove(noteId);
-    saveToFile();
-  }
-
-  public List<NoteInfo> filterByUser(List<NoteInfo> notes, AuthenticationInfo 
subject) {
-    final Set<String> entities = Sets.newHashSet();
-    if (subject != null) {
-      entities.add(subject.getUser());
-    }
-    return FluentIterable.from(notes).filter(new Predicate<NoteInfo>() {
-      @Override
-      public boolean apply(NoteInfo input) {
-        return input != null && isReader(input.getId(), entities);
-      }
-    }).toList();
-  }
-
-  public void setNewNotePermissions(String noteId, AuthenticationInfo subject) 
{
-    if (!AuthenticationInfo.isAnonymous(subject)) {
-      if (isPublic()) {
-        // add current user to owners - can be public
-        Set<String> owners = getOwners(noteId);
-        owners.add(subject.getUser());
-        setOwners(noteId, owners);
-      } else {
-        // add current user to owners, readers, runners, writers - private note
-        Set<String> entities = getOwners(noteId);
-        entities.add(subject.getUser());
-        setOwners(noteId, entities);
-
-        entities = getReaders(noteId);
-        entities.add(subject.getUser());
-        setReaders(noteId, entities);
-
-        entities = getRunners(noteId);
-        entities.add(subject.getUser());
-        setRunners(noteId, entities);
-
-        entities = getWriters(noteId);
-        entities.add(subject.getUser());
-        setWriters(noteId, entities);
-      }
-    }
-  }
-
-  @Override
-  public void onNoteCreate(Note note, AuthenticationInfo subject) {
-    setNewNotePermissions(note.getId(), subject);
-  }
-
-  @Override
-  public void onNoteRemove(Note note, AuthenticationInfo subject) {
-    removeNote(note.getId());
-  }
-
-  @Override
-  public void onNoteUpdate(Note note, AuthenticationInfo subject) {
-
-  }
-
-  @Override
-  public void onParagraphRemove(Paragraph p) {
-
-  }
-
-  @Override
-  public void onParagraphCreate(Paragraph p) {
-
-  }
-
-  @Override
-  public void onParagraphUpdate(Paragraph p) throws IOException {
-
-  }
-
-  @Override
-  public void onParagraphStatusChange(Paragraph p, Job.Status status) {
-
-  }
-}
diff --git 
a/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/NotebookAuthorizationInfoSaving.java
 
b/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/NotebookAuthorizationInfoSaving.java
index 629e400..338a0f2 100644
--- 
a/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/NotebookAuthorizationInfoSaving.java
+++ 
b/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/NotebookAuthorizationInfoSaving.java
@@ -18,8 +18,10 @@
 package org.apache.zeppelin.notebook;
 
 import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
 import org.apache.zeppelin.common.JsonSerializable;
 
+import java.util.HashMap;
 import java.util.Map;
 import java.util.Set;
 
@@ -28,10 +30,17 @@ import java.util.Set;
  */
 public class NotebookAuthorizationInfoSaving implements JsonSerializable {
 
-  private static final Gson gson = new Gson();
+  private static final Gson gson = new 
GsonBuilder().setPrettyPrinting().create();
 
   public Map<String, Map<String, Set<String>>> authInfo;
 
+  public NotebookAuthorizationInfoSaving(Map<String, NoteAuth> notesAuth) {
+    this.authInfo = new HashMap<>();
+    for (Map.Entry<String, NoteAuth> entry : notesAuth.entrySet()) {
+      this.authInfo.put(entry.getKey(), entry.getValue().toMap());
+    }
+  }
+
   public String toJson() {
     return gson.toJson(this);
   }
diff --git 
a/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/repo/NotebookRepo.java
 
b/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/repo/NotebookRepo.java
index c7956e3..bae5cba 100644
--- 
a/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/repo/NotebookRepo.java
+++ 
b/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/repo/NotebookRepo.java
@@ -28,7 +28,7 @@ import java.util.List;
 import java.util.Map;
 
 /**
- * Notebook repository (persistence layer) abstraction
+ * Notebook repository (persistence layer) abstraction.
  */
 public interface NotebookRepo {
 
@@ -36,17 +36,17 @@ public interface NotebookRepo {
 
   /**
    * Lists notebook information about all notebooks in storage. This method 
should only read
-   * the metadata of note, rather than reading all notes which usually takes 
long time.
+   * the note file name, rather than reading all note content which usually 
takes long time.
    *
    * @param subject contains user information.
-   * @return
+   * @return Map of noteId -> NoteInfo
    * @throws IOException
    */
   @ZeppelinApi
   Map<String, NoteInfo> list(AuthenticationInfo subject) throws IOException;
 
   /**
-   * Get the notebook with the given id and given notePath.
+   * Get the notebook with the given noteId and given notePath.
    *
    * @param noteId   is note id.
    * @param notePath is note path
diff --git 
a/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/repo/NotebookRepoSync.java
 
b/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/repo/NotebookRepoSync.java
index 3b69c3e..d679c84 100644
--- 
a/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/repo/NotebookRepoSync.java
+++ 
b/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/repo/NotebookRepoSync.java
@@ -18,12 +18,11 @@
 package org.apache.zeppelin.notebook.repo;
 
 import com.google.common.collect.Lists;
-import javax.inject.Inject;
 import org.apache.zeppelin.conf.ZeppelinConfiguration;
 import org.apache.zeppelin.conf.ZeppelinConfiguration.ConfVars;
 import org.apache.zeppelin.notebook.Note;
+import org.apache.zeppelin.notebook.NoteAuth;
 import org.apache.zeppelin.notebook.NoteInfo;
-import org.apache.zeppelin.notebook.NotebookAuthorization;
 import org.apache.zeppelin.notebook.OldNoteInfo;
 import org.apache.zeppelin.notebook.Paragraph;
 import org.apache.zeppelin.plugin.PluginManager;
@@ -32,8 +31,14 @@ import org.apache.zeppelin.util.Util;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import javax.inject.Inject;
 import java.io.IOException;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
 
 /**
  * Notebook repository sync with remote storage
@@ -143,23 +148,6 @@ public class NotebookRepoSync implements 
NotebookRepoWithVersionControl {
     }
   }
 
-  public void mergeAuthorizationInfo() throws IOException {
-    LOGGER.info("Merge AuthorizationInfo into note file");
-    NotebookAuthorization notebookAuthorization = 
NotebookAuthorization.getInstance();
-    for (int i = 0; i < repos.size(); ++i) {
-      NotebookRepo notebookRepo = repos.get(i);
-      Map<String, NoteInfo> notesInfo = 
notebookRepo.list(AuthenticationInfo.ANONYMOUS);
-      for (NoteInfo noteInfo : notesInfo.values()) {
-        Note note = notebookRepo.get(noteInfo.getId(), noteInfo.getPath(), 
AuthenticationInfo.ANONYMOUS);
-        note.setOwners(notebookAuthorization.getOwners(noteInfo.getId()));
-        note.setRunners(notebookAuthorization.getRunners(noteInfo.getId()));
-        note.setReaders(notebookAuthorization.getReaders(noteInfo.getId()));
-        note.setWriters(notebookAuthorization.getWriters(noteInfo.getId()));
-        notebookRepo.save(note, AuthenticationInfo.ANONYMOUS);
-      }
-    }
-  }
-
   public List<NotebookRepoWithSettings> getNotebookRepos(AuthenticationInfo 
subject) {
     List<NotebookRepoWithSettings> reposSetting = Lists.newArrayList();
 
@@ -201,26 +189,26 @@ public class NotebookRepoSync implements 
NotebookRepoWithVersionControl {
     return getRepo(0).list(subject);
   }
 
-  /* list from specific repo (for tests) */
+  /* List NoteInfo from specific repo (for tests) */
   List<NoteInfo> list(int repoIndex, AuthenticationInfo subject) throws 
IOException {
     return new ArrayList<>(getRepo(repoIndex).list(subject).values());
   }
 
   /**
-   *  Returns from Notebook from the first repository
+   * Get Note from the first repository
    */
   @Override
   public Note get(String noteId, String notePath, AuthenticationInfo subject) 
throws IOException {
     return getRepo(0).get(noteId, notePath, subject);
   }
 
-  /* get note from specific repo (for tests) */
+  /* Get Note from specific repo (for tests) */
   Note get(int repoIndex, String noteId, String noteName, AuthenticationInfo 
subject) throws IOException {
     return getRepo(repoIndex).get(noteId, noteName, subject);
   }
 
   /**
-   *  Saves to all repositories
+   *  Saves note to all repositories
    */
   @Override
   public void save(Note note, AuthenticationInfo subject) throws IOException {
diff --git 
a/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/repo/UpgradeNoteFileTool.java
 
b/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/repo/UpgradeNoteFileTool.java
index 6429e74..c39b116 100644
--- 
a/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/repo/UpgradeNoteFileTool.java
+++ 
b/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/repo/UpgradeNoteFileTool.java
@@ -40,6 +40,5 @@ public class UpgradeNoteFileTool {
     ZeppelinConfiguration conf = ZeppelinConfiguration.create();
     NotebookRepoSync notebookRepoSync = new NotebookRepoSync(conf);
     notebookRepoSync.convertNoteFiles(conf, cmd.hasOption("d"));
-    notebookRepoSync.mergeAuthorizationInfo();
   }
 }
diff --git 
a/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/repo/VFSNotebookRepo.java
 
b/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/repo/VFSNotebookRepo.java
index e452235..50fffaf 100644
--- 
a/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/repo/VFSNotebookRepo.java
+++ 
b/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/repo/VFSNotebookRepo.java
@@ -30,7 +30,6 @@ import java.util.Map;
 import org.apache.commons.io.IOUtils;
 import org.apache.commons.lang.StringUtils;
 import org.apache.commons.vfs2.FileObject;
-import org.apache.commons.vfs2.FileSystemException;
 import org.apache.commons.vfs2.FileSystemManager;
 import org.apache.commons.vfs2.NameScope;
 import org.apache.commons.vfs2.Selectors;
@@ -39,6 +38,7 @@ import org.apache.zeppelin.conf.ZeppelinConfiguration;
 import org.apache.zeppelin.conf.ZeppelinConfiguration.ConfVars;
 import org.apache.zeppelin.notebook.Note;
 import org.apache.zeppelin.notebook.NoteInfo;
+import org.apache.zeppelin.notebook.NoteAuth;
 import org.apache.zeppelin.user.AuthenticationInfo;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -61,7 +61,7 @@ public class VFSNotebookRepo implements NotebookRepo {
   @Override
   public void init(ZeppelinConfiguration conf) throws IOException {
     this.conf = conf;
-    setNotebookDirectory(conf.getRelativeDir(conf.getNotebookDir()));
+    setNotebookDirectory(conf.getNotebookDir());
   }
 
   protected void setNotebookDirectory(String notebookDirPath) throws 
IOException {
@@ -123,9 +123,6 @@ public class VFSNotebookRepo implements NotebookRepo {
         } catch (IOException e) {
           LOGGER.warn(e.getMessage());
         }
-
-      } else {
-        LOGGER.debug("Unrecognized note file: " + noteFileName);
       }
     }
     return noteInfos;
@@ -163,7 +160,9 @@ public class VFSNotebookRepo implements NotebookRepo {
   }
 
   @Override
-  public void move(String noteId, String notePath, String newNotePath,
+  public void move(String noteId,
+                   String notePath,
+                   String newNotePath,
                    AuthenticationInfo subject) throws IOException {
     LOGGER.info("Move note " + noteId + " from " + notePath + " to " + 
newNotePath);
     FileObject fileObject = rootNotebookFileObject.resolveFile(
@@ -246,6 +245,5 @@ public class VFSNotebookRepo implements NotebookRepo {
       LOGGER.error("Cannot update notebook directory", e);
     }
   }
-
 }
 
diff --git 
a/zeppelin-zengine/src/test/java/org/apache/zeppelin/conf/ZeppelinConfigurationTest.java
 
b/zeppelin-zengine/src/test/java/org/apache/zeppelin/conf/ZeppelinConfigurationTest.java
index 1771fd3..c730e5f 100644
--- 
a/zeppelin-zengine/src/test/java/org/apache/zeppelin/conf/ZeppelinConfigurationTest.java
+++ 
b/zeppelin-zengine/src/test/java/org/apache/zeppelin/conf/ZeppelinConfigurationTest.java
@@ -80,10 +80,9 @@ public class ZeppelinConfigurationTest {
 
   @Test
   public void getNotebookDirTest() throws ConfigurationException {
-
     ZeppelinConfiguration conf = new 
ZeppelinConfiguration(this.getClass().getResource("/zeppelin-site.xml"));
     String notebookLocation = conf.getNotebookDir();
-    Assert.assertEquals("notebook", notebookLocation);
+    assertTrue(notebookLocation.endsWith("notebook"));
   }
 
   @Test
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 a39c83e..1cafc23 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
@@ -29,7 +29,9 @@ import org.apache.zeppelin.interpreter.InterpreterException;
 import org.apache.zeppelin.interpreter.InterpreterNotFoundException;
 import org.apache.zeppelin.interpreter.InterpreterSetting;
 import org.apache.zeppelin.notebook.ApplicationState;
+import org.apache.zeppelin.notebook.AuthorizationService;
 import org.apache.zeppelin.notebook.Note;
+import org.apache.zeppelin.notebook.NoteManager;
 import org.apache.zeppelin.notebook.Notebook;
 import org.apache.zeppelin.notebook.Paragraph;
 import org.apache.zeppelin.notebook.repo.NotebookRepo;
@@ -57,11 +59,14 @@ public class HeliumApplicationFactoryTest extends 
AbstractInterpreterTest {
     }
 
     SearchService search = mock(SearchService.class);
+    AuthorizationService authorizationService = 
mock(AuthorizationService.class);
     notebookRepo = mock(NotebookRepo.class);
     notebook =
         new Notebook(
             conf,
+            authorizationService,
             notebookRepo,
+            new NoteManager(notebookRepo),
             interpreterFactory,
             interpreterSettingManager,
             search,
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 17d8c85..bc47de1 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
@@ -27,13 +27,12 @@ import org.apache.zeppelin.interpreter.InterpreterGroup;
 import org.apache.zeppelin.interpreter.InterpreterNotFoundException;
 import org.apache.zeppelin.interpreter.InterpreterOption;
 import org.apache.zeppelin.interpreter.InterpreterResult;
-import org.apache.zeppelin.interpreter.InterpreterResultMessage;
 import org.apache.zeppelin.interpreter.InterpreterSetting;
 import org.apache.zeppelin.interpreter.remote.RemoteInterpreter;
-import org.apache.zeppelin.notebook.repo.InMemoryNotebookRepo;
 import org.apache.zeppelin.notebook.repo.NotebookRepo;
 import org.apache.zeppelin.notebook.repo.NotebookRepoSettingsInfo;
 import org.apache.zeppelin.notebook.repo.NotebookRepoWithVersionControl;
+import org.apache.zeppelin.notebook.repo.VFSNotebookRepo;
 import org.apache.zeppelin.notebook.scheduler.QuartzSchedulerService;
 import org.apache.zeppelin.notebook.scheduler.SchedulerService;
 import org.apache.zeppelin.resource.LocalResourcePool;
@@ -78,6 +77,7 @@ public class NotebookTest extends AbstractInterpreterTest 
implements ParagraphJo
   private static final Logger logger = 
LoggerFactory.getLogger(NotebookTest.class);
 
   private Notebook notebook;
+  private NoteManager noteManager;
   private NotebookRepo notebookRepo;
   private AuthorizationService authorizationService;
   private Credentials credentials;
@@ -92,20 +92,23 @@ public class NotebookTest extends AbstractInterpreterTest 
implements ParagraphJo
     super.setUp();
 
     SearchService search = mock(SearchService.class);
-    notebookRepo = new InMemoryNotebookRepo();
+    notebookRepo = new VFSNotebookRepo();
+    notebookRepo.init(conf);
+    noteManager = new NoteManager(notebookRepo);
+    authorizationService = new AuthorizationService(conf);
 
     credentials = new Credentials(conf.credentialsPersist(), 
conf.getCredentialsPath(), null);
-    notebook = new Notebook(conf, notebookRepo, interpreterFactory, 
interpreterSettingManager, search,
+    notebook = new Notebook(conf, authorizationService, notebookRepo, 
noteManager, interpreterFactory, interpreterSettingManager, search,
             credentials, null);
-    authorizationService = new AuthorizationService(notebook, 
notebook.getConf());
     notebook.setParagraphJobListener(this);
     schedulerService = new QuartzSchedulerService(conf, notebook);
-
   }
 
   @After
   public void tearDown() throws Exception {
     super.tearDown();
+    System.clearProperty(ConfVars.ZEPPELIN_NOTEBOOK_PUBLIC.getVarName());
+    System.clearProperty(ConfVars.ZEPPELIN_NOTEBOOK_CRON_ENABLE.getVarName());
   }
 
   @Test
@@ -114,13 +117,13 @@ public class NotebookTest extends AbstractInterpreterTest 
implements ParagraphJo
     Notebook notebook;
 
     notebookRepo = new DummyNotebookRepo();
-    notebook = new Notebook(conf, notebookRepo, interpreterFactory,
+    notebook = new Notebook(conf, mock(AuthorizationService.class), 
notebookRepo, new NoteManager(notebookRepo), interpreterFactory,
         interpreterSettingManager, null,
         credentials, null);
     assertFalse("Revision is not supported in DummyNotebookRepo", 
notebook.isRevisionSupported());
 
     notebookRepo = new DummyNotebookRepoWithVersionControl();
-    notebook = new Notebook(conf, notebookRepo, interpreterFactory,
+    notebook = new Notebook(conf, mock(AuthorizationService.class), 
notebookRepo, new NoteManager(notebookRepo), interpreterFactory,
         interpreterSettingManager, null,
         credentials, null);
     assertTrue("Revision is supported in DummyNotebookRepoWithVersionControl",
@@ -139,7 +142,6 @@ public class NotebookTest extends AbstractInterpreterTest 
implements ParagraphJo
       return new HashMap<>();
     }
 
-
     @Override
     public Note get(String noteId, String notePath, AuthenticationInfo 
subject) throws IOException {
       return null;
@@ -297,13 +299,14 @@ public class NotebookTest extends AbstractInterpreterTest 
implements ParagraphJo
     Note note = notebook.createNote("note1", AuthenticationInfo.ANONYMOUS);
     Paragraph p1 = note.insertNewParagraph(0, AuthenticationInfo.ANONYMOUS);
     p1.setText("%md hello world");
+    notebook.saveNote(note, AuthenticationInfo.ANONYMOUS);
 
     // when load
     notebook.reloadAllNotes(anonymous);
     assertEquals(1, notebook.getAllNotes().size());
 
     // then interpreter factory should be injected into all the paragraphs
-    note = notebook.getAllNotes().get(0);
+    note = notebook.getNote(note.getId());
     try {
       note.getParagraphs().get(0).getBindedInterpreter();
       fail("Should throw InterpreterNotFoundException");
@@ -339,10 +342,9 @@ public class NotebookTest extends AbstractInterpreterTest 
implements ParagraphJo
 
 
     // delete notebook from notebook list when reloadAllNotes() is called
-    ((InMemoryNotebookRepo) notebookRepo).reset();
     notebook.reloadAllNotes(anonymous);
     notes = notebook.getAllNotes();
-    assertEquals(notes.size(), 0);
+    assertEquals(notes.size(), 2);
   }
 
   @Test
diff --git 
a/zeppelin-zengine/src/test/java/org/apache/zeppelin/notebook/repo/NotebookRepoSyncTest.java
 
b/zeppelin-zengine/src/test/java/org/apache/zeppelin/notebook/repo/NotebookRepoSyncTest.java
index 726fb93..7a3b4c8 100644
--- 
a/zeppelin-zengine/src/test/java/org/apache/zeppelin/notebook/repo/NotebookRepoSyncTest.java
+++ 
b/zeppelin-zengine/src/test/java/org/apache/zeppelin/notebook/repo/NotebookRepoSyncTest.java
@@ -39,6 +39,7 @@ import 
org.apache.zeppelin.interpreter.remote.RemoteInterpreterProcessListener;
 import org.apache.zeppelin.notebook.AuthorizationService;
 import org.apache.zeppelin.notebook.Note;
 import org.apache.zeppelin.notebook.NoteInfo;
+import org.apache.zeppelin.notebook.NoteManager;
 import org.apache.zeppelin.notebook.Notebook;
 import org.apache.zeppelin.notebook.Paragraph;
 import org.apache.zeppelin.search.SearchService;
@@ -52,20 +53,20 @@ import org.quartz.SchedulerException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-// TODO(zjffdu) move it to zeppelin-zengine
 public class NotebookRepoSyncTest {
 
   private File ZEPPELIN_HOME;
   private ZeppelinConfiguration conf;
   private File mainNotebookDir;
   private File secNotebookDir;
-  private Notebook notebookSync;
+  private Notebook notebook;
   private NotebookRepoSync notebookRepoSync;
   private InterpreterFactory factory;
   private InterpreterSettingManager interpreterSettingManager;
   private SearchService search;
   private Credentials credentials;
   private AuthenticationInfo anonymous;
+  private NoteManager noteManager;
   private AuthorizationService authorizationService;
   private static final Logger LOG = 
LoggerFactory.getLogger(NotebookRepoSyncTest.class);
 
@@ -99,10 +100,11 @@ public class NotebookRepoSyncTest {
 
     search = mock(SearchService.class);
     notebookRepoSync = new NotebookRepoSync(conf);
+    noteManager = new NoteManager(notebookRepoSync);
+    authorizationService = new AuthorizationService(conf);
     credentials = new Credentials(conf.credentialsPersist(), 
conf.getCredentialsPath(), null);
-    notebookSync = new Notebook(conf, notebookRepoSync, factory, 
interpreterSettingManager, search, credentials, null);
+    notebook = new Notebook(conf, authorizationService, notebookRepoSync, 
noteManager, factory, interpreterSettingManager, search, credentials, null);
     anonymous = new AuthenticationInfo("anonymous");
-    authorizationService = new AuthorizationService(notebookSync, conf);
   }
 
   @After
@@ -123,14 +125,14 @@ public class NotebookRepoSyncTest {
     assertEquals(0, notebookRepoSync.list(1, anonymous).size());
 
     /* create note */
-    Note note = notebookSync.createNote("test", "", anonymous);
+    Note note = notebook.createNote("test", "", anonymous);
 
     // check that automatically saved on both storages
     assertEquals(1, notebookRepoSync.list(0, anonymous).size());
     assertEquals(1, notebookRepoSync.list(1, anonymous).size());
     assertEquals(notebookRepoSync.list(0, anonymous).get(0).getId(), 
notebookRepoSync.list(1, anonymous).get(0).getId());
 
-    notebookSync.removeNote(notebookRepoSync.list(0, null).get(0).getId(), 
anonymous);
+    notebook.removeNote(notebookRepoSync.list(0, null).get(0).getId(), 
anonymous);
   }
 
   @Test
@@ -140,7 +142,7 @@ public class NotebookRepoSyncTest {
     assertEquals(0, notebookRepoSync.list(0, anonymous).size());
     assertEquals(0, notebookRepoSync.list(1, anonymous).size());
 
-    Note note = notebookSync.createNote("test", "", anonymous);
+    Note note = notebook.createNote("test", "", anonymous);
 
     /* check that created in both storage systems */
     assertEquals(1, notebookRepoSync.list(0, anonymous).size());
@@ -148,7 +150,7 @@ public class NotebookRepoSyncTest {
     assertEquals(notebookRepoSync.list(0, anonymous).get(0).getId(), 
notebookRepoSync.list(1, anonymous).get(0).getId());
 
     /* remove Note */
-    notebookSync.removeNote(notebookRepoSync.list(0, 
anonymous).get(0).getId(), anonymous);
+    notebook.removeNote(notebookRepoSync.list(0, anonymous).get(0).getId(), 
anonymous);
 
     /* check that deleted in both storages */
     assertEquals(0, notebookRepoSync.list(0, anonymous).size());
@@ -160,7 +162,7 @@ public class NotebookRepoSyncTest {
   public void testSyncUpdateMain() throws IOException {
 
     /* create note */
-    Note note = notebookSync.createNote("/test", "test", anonymous);
+    Note note = notebook.createNote("/test", "test", anonymous);
     note.setInterpreterFactory(mock(InterpreterFactory.class));
     Paragraph p1 = note.addNewParagraph(AuthenticationInfo.ANONYMOUS);
     Map config = p1.getConfig();
@@ -229,7 +231,7 @@ public class NotebookRepoSyncTest {
     assertEquals(2, notebookRepoSync.list(1, anonymous).size());
 
     // After reloading notebooks repos should be synchronized
-    notebookSync.reloadAllNotes(anonymous);
+    notebook.reloadAllNotes(anonymous);
     assertEquals(2, notebookRepoSync.list(0, anonymous).size());
     assertEquals(2, notebookRepoSync.list(1, anonymous).size());
   }
@@ -240,7 +242,7 @@ public class NotebookRepoSyncTest {
     System.setProperty(ConfVars.ZEPPELIN_NOTEBOOK_ONE_WAY_SYNC.getVarName(), 
"true");
     conf = ZeppelinConfiguration.create();
     notebookRepoSync = new NotebookRepoSync(conf);
-    notebookSync = new Notebook(conf, notebookRepoSync, factory, 
interpreterSettingManager, search, credentials, null);
+    notebook = new Notebook(conf, mock(AuthorizationService.class), 
notebookRepoSync, new NoteManager(notebookRepoSync), factory, 
interpreterSettingManager, search, credentials, null);
 
     // check that both storage repos are empty
     assertTrue(notebookRepoSync.getRepoCount() > 1);
@@ -260,7 +262,7 @@ public class NotebookRepoSyncTest {
     assertEquals(2, notebookRepoSync.list(1, null).size());
 
     // after reloading the notebook should be wiped from secondary storage
-    notebookSync.reloadAllNotes(null);
+    notebook.reloadAllNotes(null);
     assertEquals(0, notebookRepoSync.list(0, null).size());
     assertEquals(0, notebookRepoSync.list(1, null).size());
 
@@ -276,7 +278,7 @@ public class NotebookRepoSyncTest {
     assertEquals(0, notebookRepoSync.list(1, null).size());
 
     // after reloading notebooks repos should be synchronized
-    notebookSync.reloadAllNotes(null);
+    notebook.reloadAllNotes(null);
     assertEquals(2, notebookRepoSync.list(0, null).size());
     assertEquals(2, notebookRepoSync.list(1, null).size());
   }
@@ -287,7 +289,7 @@ public class NotebookRepoSyncTest {
     ZeppelinConfiguration vConf = ZeppelinConfiguration.create();
 
     NotebookRepoSync vRepoSync = new NotebookRepoSync(vConf);
-    Notebook vNotebookSync = new Notebook(vConf, vRepoSync, factory, 
interpreterSettingManager, search, credentials, null);
+    Notebook vNotebookSync = new Notebook(vConf, 
mock(AuthorizationService.class), vRepoSync, new NoteManager(vRepoSync), 
factory, interpreterSettingManager, search, credentials, null);
 
     // one git versioned storage initialized
     assertThat(vRepoSync.getRepoCount()).isEqualTo(1);
@@ -327,7 +329,7 @@ public class NotebookRepoSyncTest {
   public void testSyncWithAcl() throws IOException {
     /* scenario 1 - note exists with acl on main storage */
     AuthenticationInfo user1 = new AuthenticationInfo("user1");
-    Note note = notebookSync.createNote("/test", "test", user1);
+    Note note = notebook.createNote("/test", "test", user1);
     assertEquals(0, note.getParagraphs().size());
 
     // saved on both storages
diff --git 
a/zeppelin-zengine/src/test/java/org/apache/zeppelin/search/LuceneSearchTest.java
 
b/zeppelin-zengine/src/test/java/org/apache/zeppelin/search/LuceneSearchTest.java
index 52178dc..1e65115 100644
--- 
a/zeppelin-zengine/src/test/java/org/apache/zeppelin/search/LuceneSearchTest.java
+++ 
b/zeppelin-zengine/src/test/java/org/apache/zeppelin/search/LuceneSearchTest.java
@@ -29,7 +29,9 @@ import org.apache.zeppelin.conf.ZeppelinConfiguration;
 import org.apache.zeppelin.interpreter.InterpreterFactory;
 import org.apache.zeppelin.interpreter.InterpreterSetting;
 import org.apache.zeppelin.interpreter.InterpreterSettingManager;
+import org.apache.zeppelin.notebook.AuthorizationService;
 import org.apache.zeppelin.notebook.Note;
+import org.apache.zeppelin.notebook.NoteManager;
 import org.apache.zeppelin.notebook.Notebook;
 import org.apache.zeppelin.notebook.Paragraph;
 import org.apache.zeppelin.notebook.repo.NotebookRepo;
@@ -54,7 +56,7 @@ public class LuceneSearchTest {
     InterpreterSetting defaultInterpreterSetting = 
mock(InterpreterSetting.class);
     when(defaultInterpreterSetting.getName()).thenReturn("test");
     
when(interpreterSettingManager.getDefaultInterpreterSetting()).thenReturn(defaultInterpreterSetting);
-    notebook = new Notebook(ZeppelinConfiguration.create(), 
mock(NotebookRepo.class),
+    notebook = new Notebook(ZeppelinConfiguration.create(), 
mock(AuthorizationService.class), mock(NotebookRepo.class), 
mock(NoteManager.class),
         mock(InterpreterFactory.class), interpreterSettingManager,
         noteSearchService,
         mock(Credentials.class), null);

Reply via email to