You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@zeppelin.apache.org by zj...@apache.org on 2021/07/21 03:02:37 UTC

[zeppelin] branch master updated: [ZEPPELIN-5398] fix ZEPPELIN-5398, make corrupted notes deletable

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 bb5e7e1  [ZEPPELIN-5398] fix ZEPPELIN-5398, make corrupted notes deletable
bb5e7e1 is described below

commit bb5e7e1c136b927ceecef0b3cde680fb2d58695f
Author: EricGao888 <er...@gmail.com>
AuthorDate: Wed Jul 14 15:40:16 2021 +0800

    [ZEPPELIN-5398] fix ZEPPELIN-5398, make corrupted notes deletable
    
    ### What is this PR for?
    * fix ZEPPELIN-5398, make corrupted notes deletable
    
    ### What type of PR is it?
    * Bug Fix
    
    ### Todos
    * None
    
    ### What is the Jira issue?
    * https://issues.apache.org/jira/browse/ZEPPELIN-5398
    
    ### How should this be tested?
    1. Create a new note.
    2. Corrupt it in the backend (e.g. mess up the json format).
    3. Restart zeppelin server.
    4. Delete the corrupted note and refresh page.
    5. The corrupted note will be gone.
    
    ### Screenshots (if appropriate)
    * None
    
    ### Questions:
    * None
    
    Author: EricGao888 <er...@gmail.com>
    
    Closes #4134 from EricGao888/chufeng-fix-ZEPPELIN-5398 and squashes the following commits:
    
    4497442524 [EricGao888] improve coding style
    8836b98640 [EricGao888] improve coding style
    1fb0e8a3da [EricGao888] improve removeCorruptedNote test logic
    d3a7fa6f3c [EricGao888] resolve conflict
    aa4a542cbd [EricGao888] add noteId param for fromJson method
    4764b6f881 [EricGao888] remove duplicate code
    91243f37e0 [EricGao888] improve coding style
    e1757a910e [EricGao888] add method to remove corrupted notes from trash, add test cases, fix minor issues in previous commits
    f290cb3900 [EricGao888] add unit test for moving corrupted note to trash
    2d9b93f2d0 [EricGao888] remove unused import, remove useless blank line
    99b9189ea8 [EricGao888] fix ZEPPELIN-5398, make corrupted notes deletable
---
 .../zeppelin/notebook/repo/AzureNotebookRepo.java  |  2 +-
 .../notebook/repo/OldAzureNotebookRepo.java        |  2 +-
 .../notebook/repo/FileSystemNotebookRepo.java      |  2 +-
 .../notebook/repo/OldFileSystemNotebookRepo.java   |  2 +-
 .../zeppelin/notebook/repo/GCSNotebookRepo.java    |  2 +-
 .../zeppelin/notebook/repo/OldGCSNotebookRepo.java |  2 +-
 .../zeppelin/notebook/repo/MongoNotebookRepo.java  |  6 +--
 .../notebook/repo/OldMongoNotebookRepo.java        |  8 ++--
 .../zeppelin/notebook/repo/OSSNotebookRepo.java    |  2 +-
 .../zeppelin/notebook/repo/OldS3NotebookRepo.java  |  2 +-
 .../zeppelin/notebook/repo/S3NotebookRepo.java     |  2 +-
 .../repo/zeppelinhub/OldZeppelinHubRepo.java       |  4 +-
 .../notebook/repo/zeppelinhub/ZeppelinHubRepo.java |  4 +-
 .../apache/zeppelin/service/NotebookService.java   | 43 ++++++++++++++++------
 .../org/apache/zeppelin/socket/NotebookServer.java |  2 +-
 .../cluster/ClusterNoteEventListenerTest.java      |  2 +-
 .../zeppelin/service/NotebookServiceTest.java      | 15 ++++++++
 .../java/org/apache/zeppelin/notebook/Note.java    |  5 ++-
 .../org/apache/zeppelin/notebook/Notebook.java     |  8 +++-
 .../notebook/exception/CorruptedNoteException.java | 26 +++++++++++++
 .../zeppelin/notebook/repo/OldVFSNotebookRepo.java |  2 +-
 .../zeppelin/notebook/repo/VFSNotebookRepo.java    |  2 +-
 .../org/apache/zeppelin/notebook/NoteTest.java     |  2 +-
 .../org/apache/zeppelin/notebook/NotebookTest.java | 18 +++++++++
 24 files changed, 125 insertions(+), 40 deletions(-)

diff --git a/zeppelin-plugins/notebookrepo/azure/src/main/java/org/apache/zeppelin/notebook/repo/AzureNotebookRepo.java b/zeppelin-plugins/notebookrepo/azure/src/main/java/org/apache/zeppelin/notebook/repo/AzureNotebookRepo.java
index 5ad9407..490f818 100644
--- a/zeppelin-plugins/notebookrepo/azure/src/main/java/org/apache/zeppelin/notebook/repo/AzureNotebookRepo.java
+++ b/zeppelin-plugins/notebookrepo/azure/src/main/java/org/apache/zeppelin/notebook/repo/AzureNotebookRepo.java
@@ -125,7 +125,7 @@ public class AzureNotebookRepo implements NotebookRepo {
     String json = IOUtils.toString(ins,
         conf.getString(ZeppelinConfiguration.ConfVars.ZEPPELIN_ENCODING));
     ins.close();
-    return Note.fromJson(json);
+    return Note.fromJson(noteId, json);
   }
 
   @Override
diff --git a/zeppelin-plugins/notebookrepo/azure/src/main/java/org/apache/zeppelin/notebook/repo/OldAzureNotebookRepo.java b/zeppelin-plugins/notebookrepo/azure/src/main/java/org/apache/zeppelin/notebook/repo/OldAzureNotebookRepo.java
index 27e31c6..26f6631 100644
--- a/zeppelin-plugins/notebookrepo/azure/src/main/java/org/apache/zeppelin/notebook/repo/OldAzureNotebookRepo.java
+++ b/zeppelin-plugins/notebookrepo/azure/src/main/java/org/apache/zeppelin/notebook/repo/OldAzureNotebookRepo.java
@@ -132,7 +132,7 @@ public class OldAzureNotebookRepo implements OldNotebookRepo {
     String json = IOUtils.toString(ins,
         conf.getString(ZeppelinConfiguration.ConfVars.ZEPPELIN_ENCODING));
     ins.close();
-    return Note.fromJson(json);
+    return Note.fromJson(noteId, json);
   }
 
   @Override
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 70e71c6..b200364 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
@@ -74,7 +74,7 @@ public class FileSystemNotebookRepo implements NotebookRepo {
   public Note get(String noteId, String notePath, AuthenticationInfo subject) throws IOException {
     String content = this.fs.readFile(
         new Path(notebookDir, buildNoteFileName(noteId, notePath)));
-    return Note.fromJson(content);
+    return Note.fromJson(noteId, content);
   }
 
   @Override
diff --git a/zeppelin-plugins/notebookrepo/filesystem/src/main/java/org/apache/zeppelin/notebook/repo/OldFileSystemNotebookRepo.java b/zeppelin-plugins/notebookrepo/filesystem/src/main/java/org/apache/zeppelin/notebook/repo/OldFileSystemNotebookRepo.java
index f49e7c5..378bdc7 100644
--- a/zeppelin-plugins/notebookrepo/filesystem/src/main/java/org/apache/zeppelin/notebook/repo/OldFileSystemNotebookRepo.java
+++ b/zeppelin-plugins/notebookrepo/filesystem/src/main/java/org/apache/zeppelin/notebook/repo/OldFileSystemNotebookRepo.java
@@ -58,7 +58,7 @@ public class OldFileSystemNotebookRepo implements OldNotebookRepo {
   public Note get(final String noteId, AuthenticationInfo subject) throws IOException {
     String content = this.fs.readFile(
         new Path(notebookDir.toString() + "/" + noteId + "/note.json"));
-    return Note.fromJson(content);
+    return Note.fromJson(noteId, content);
   }
 
   @Override
diff --git a/zeppelin-plugins/notebookrepo/gcs/src/main/java/org/apache/zeppelin/notebook/repo/GCSNotebookRepo.java b/zeppelin-plugins/notebookrepo/gcs/src/main/java/org/apache/zeppelin/notebook/repo/GCSNotebookRepo.java
index a658c57..606a33a 100644
--- a/zeppelin-plugins/notebookrepo/gcs/src/main/java/org/apache/zeppelin/notebook/repo/GCSNotebookRepo.java
+++ b/zeppelin-plugins/notebookrepo/gcs/src/main/java/org/apache/zeppelin/notebook/repo/GCSNotebookRepo.java
@@ -181,7 +181,7 @@ public class GCSNotebookRepo implements NotebookRepo {
     }
 
     try {
-      return Note.fromJson(new String(contents, encoding));
+      return Note.fromJson(noteId, new String(contents, encoding));
     } catch (JsonParseException jpe) {
       throw new IOException(
           "Could note parse as json " + blobId.toString() + jpe.getMessage(), jpe);
diff --git a/zeppelin-plugins/notebookrepo/gcs/src/main/java/org/apache/zeppelin/notebook/repo/OldGCSNotebookRepo.java b/zeppelin-plugins/notebookrepo/gcs/src/main/java/org/apache/zeppelin/notebook/repo/OldGCSNotebookRepo.java
index 15135c3..765cfa1 100644
--- a/zeppelin-plugins/notebookrepo/gcs/src/main/java/org/apache/zeppelin/notebook/repo/OldGCSNotebookRepo.java
+++ b/zeppelin-plugins/notebookrepo/gcs/src/main/java/org/apache/zeppelin/notebook/repo/OldGCSNotebookRepo.java
@@ -175,7 +175,7 @@ public class OldGCSNotebookRepo implements OldNotebookRepo {
     }
 
     try {
-      return Note.fromJson(new String(contents, encoding));
+      return Note.fromJson(noteId, new String(contents, encoding));
     } catch (JsonParseException jpe) {
       throw new IOException(
           "Could note parse as json " + blobId.toString() + jpe.getMessage(), jpe);
diff --git a/zeppelin-plugins/notebookrepo/mongo/src/main/java/org/apache/zeppelin/notebook/repo/MongoNotebookRepo.java b/zeppelin-plugins/notebookrepo/mongo/src/main/java/org/apache/zeppelin/notebook/repo/MongoNotebookRepo.java
index 568de20..475b884 100644
--- a/zeppelin-plugins/notebookrepo/mongo/src/main/java/org/apache/zeppelin/notebook/repo/MongoNotebookRepo.java
+++ b/zeppelin-plugins/notebookrepo/mongo/src/main/java/org/apache/zeppelin/notebook/repo/MongoNotebookRepo.java
@@ -158,7 +158,7 @@ public class MongoNotebookRepo implements NotebookRepo {
       throw new IOException("Note '" + noteId + "' in path '" + notePath + "'not found");
     }
 
-    return documentToNote(doc);
+    return documentToNote(noteId, doc);
   }
 
   @Override
@@ -434,11 +434,11 @@ public class MongoNotebookRepo implements NotebookRepo {
   /**
    * Convert document to note.
    */
-  private Note documentToNote(Document doc) throws IOException {
+  private Note documentToNote(String noteId, Document doc) throws IOException {
     // document to JSON
     String json = doc.toJson();
     // JSON to note
-    return Note.fromJson(json);
+    return Note.fromJson(noteId, json);
   }
 
   /**
diff --git a/zeppelin-plugins/notebookrepo/mongo/src/main/java/org/apache/zeppelin/notebook/repo/OldMongoNotebookRepo.java b/zeppelin-plugins/notebookrepo/mongo/src/main/java/org/apache/zeppelin/notebook/repo/OldMongoNotebookRepo.java
index e637f3a..dbeac44 100644
--- a/zeppelin-plugins/notebookrepo/mongo/src/main/java/org/apache/zeppelin/notebook/repo/OldMongoNotebookRepo.java
+++ b/zeppelin-plugins/notebookrepo/mongo/src/main/java/org/apache/zeppelin/notebook/repo/OldMongoNotebookRepo.java
@@ -129,7 +129,7 @@ public class OldMongoNotebookRepo implements OldNotebookRepo {
 
     while (cursor.hasNext()) {
       Document doc = cursor.next();
-      Note note = documentToNote(doc);
+      Note note = documentToNote(null, doc);
       OldNoteInfo info = new OldNoteInfo(note);
       infos.add(info);
     }
@@ -174,11 +174,11 @@ public class OldMongoNotebookRepo implements OldNotebookRepo {
   /**
    * Convert document to note
    */
-  private Note documentToNote(Document doc) throws IOException {
+  private Note documentToNote(String noteId, Document doc) throws IOException {
     // document to JSON
     String json = doc.toJson();
     // JSON to note
-    return Note.fromJson(json);
+    return Note.fromJson(noteId, json);
   }
 
   /**
@@ -202,7 +202,7 @@ public class OldMongoNotebookRepo implements OldNotebookRepo {
       throw new IOException("Note " + noteId + "not found");
     }
 
-    return documentToNote(doc);
+    return documentToNote(noteId, doc);
   }
 
   @Override
diff --git a/zeppelin-plugins/notebookrepo/oss/src/main/java/org/apache/zeppelin/notebook/repo/OSSNotebookRepo.java b/zeppelin-plugins/notebookrepo/oss/src/main/java/org/apache/zeppelin/notebook/repo/OSSNotebookRepo.java
index 72994f1..81096db 100644
--- a/zeppelin-plugins/notebookrepo/oss/src/main/java/org/apache/zeppelin/notebook/repo/OSSNotebookRepo.java
+++ b/zeppelin-plugins/notebookrepo/oss/src/main/java/org/apache/zeppelin/notebook/repo/OSSNotebookRepo.java
@@ -111,7 +111,7 @@ public class OSSNotebookRepo implements NotebookRepo {
     InputStream in = null;
     try {
       in = ossObject.getObjectContent();
-      return Note.fromJson(IOUtils.toString(in, StandardCharsets.UTF_8));
+      return Note.fromJson(noteId, IOUtils.toString(in, StandardCharsets.UTF_8));
     } finally {
       if (in != null) {
         in.close();
diff --git a/zeppelin-plugins/notebookrepo/s3/src/main/java/org/apache/zeppelin/notebook/repo/OldS3NotebookRepo.java b/zeppelin-plugins/notebookrepo/s3/src/main/java/org/apache/zeppelin/notebook/repo/OldS3NotebookRepo.java
index 42bcc6e..cae6d0b 100644
--- a/zeppelin-plugins/notebookrepo/s3/src/main/java/org/apache/zeppelin/notebook/repo/OldS3NotebookRepo.java
+++ b/zeppelin-plugins/notebookrepo/s3/src/main/java/org/apache/zeppelin/notebook/repo/OldS3NotebookRepo.java
@@ -216,7 +216,7 @@ public class OldS3NotebookRepo implements OldNotebookRepo {
 
     try (InputStream ins = s3object.getObjectContent()) {
       String json = IOUtils.toString(ins, conf.getString(ConfVars.ZEPPELIN_ENCODING));
-      return Note.fromJson(json);
+      return Note.fromJson(null, json);
     }
   }
 
diff --git a/zeppelin-plugins/notebookrepo/s3/src/main/java/org/apache/zeppelin/notebook/repo/S3NotebookRepo.java b/zeppelin-plugins/notebookrepo/s3/src/main/java/org/apache/zeppelin/notebook/repo/S3NotebookRepo.java
index c4905d7..497203c 100644
--- a/zeppelin-plugins/notebookrepo/s3/src/main/java/org/apache/zeppelin/notebook/repo/S3NotebookRepo.java
+++ b/zeppelin-plugins/notebookrepo/s3/src/main/java/org/apache/zeppelin/notebook/repo/S3NotebookRepo.java
@@ -224,7 +224,7 @@ public class S3NotebookRepo implements NotebookRepo {
     }
     try (InputStream ins = s3object.getObjectContent()) {
       String json = IOUtils.toString(ins, conf.getString(ConfVars.ZEPPELIN_ENCODING));
-      return Note.fromJson(json);
+      return Note.fromJson(noteId, json);
     }
   }
 
diff --git a/zeppelin-plugins/notebookrepo/zeppelin-hub/src/main/java/org/apache/zeppelin/notebook/repo/zeppelinhub/OldZeppelinHubRepo.java b/zeppelin-plugins/notebookrepo/zeppelin-hub/src/main/java/org/apache/zeppelin/notebook/repo/zeppelinhub/OldZeppelinHubRepo.java
index 9af3c1e..d1134ec 100644
--- a/zeppelin-plugins/notebookrepo/zeppelin-hub/src/main/java/org/apache/zeppelin/notebook/repo/zeppelinhub/OldZeppelinHubRepo.java
+++ b/zeppelin-plugins/notebookrepo/zeppelin-hub/src/main/java/org/apache/zeppelin/notebook/repo/zeppelinhub/OldZeppelinHubRepo.java
@@ -195,7 +195,7 @@ public class OldZeppelinHubRepo implements OldNotebookRepoWithVersionControl {
     }
     String token = getUserToken(subject.getUser());
     String response = restApiClient.get(token, noteId);
-    Note note = Note.fromJson(response);
+    Note note = Note.fromJson(noteId, response);
     if (note == null) {
       return EMPTY_NOTE;
     }
@@ -254,7 +254,7 @@ public class OldZeppelinHubRepo implements OldNotebookRepoWithVersionControl {
     String token = getUserToken(subject.getUser());
     String response = restApiClient.get(token, endpoint);
 
-    Note note = Note.fromJson(response);
+    Note note = Note.fromJson(noteId, response);
     if (note == null) {
       return EMPTY_NOTE;
     }
diff --git a/zeppelin-plugins/notebookrepo/zeppelin-hub/src/main/java/org/apache/zeppelin/notebook/repo/zeppelinhub/ZeppelinHubRepo.java b/zeppelin-plugins/notebookrepo/zeppelin-hub/src/main/java/org/apache/zeppelin/notebook/repo/zeppelinhub/ZeppelinHubRepo.java
index 8c2b028..1523d09 100644
--- a/zeppelin-plugins/notebookrepo/zeppelin-hub/src/main/java/org/apache/zeppelin/notebook/repo/zeppelinhub/ZeppelinHubRepo.java
+++ b/zeppelin-plugins/notebookrepo/zeppelin-hub/src/main/java/org/apache/zeppelin/notebook/repo/zeppelinhub/ZeppelinHubRepo.java
@@ -201,7 +201,7 @@ public class ZeppelinHubRepo implements NotebookRepoWithVersionControl {
     }
     String token = getUserToken(subject.getUser());
     String response = restApiClient.get(token, noteId);
-    Note note = Note.fromJson(response);
+    Note note = Note.fromJson(noteId, response);
     if (note == null) {
       return EMPTY_NOTE;
     }
@@ -275,7 +275,7 @@ public class ZeppelinHubRepo implements NotebookRepoWithVersionControl {
     String token = getUserToken(subject.getUser());
     String response = restApiClient.get(token, endpoint);
 
-    Note note = Note.fromJson(response);
+    Note note = Note.fromJson(noteId, response);
     if (note == null) {
       return EMPTY_NOTE;
     }
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 946886c..da498e0 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
@@ -50,6 +50,7 @@ import org.apache.zeppelin.notebook.NoteManager;
 import org.apache.zeppelin.notebook.Notebook;
 import org.apache.zeppelin.notebook.Paragraph;
 import org.apache.zeppelin.notebook.AuthorizationService;
+import org.apache.zeppelin.notebook.exception.CorruptedNoteException;
 import org.apache.zeppelin.notebook.exception.NotePathAlreadyExistsException;
 import org.apache.zeppelin.notebook.repo.NotebookRepoWithVersionControl;
 import org.apache.zeppelin.notebook.scheduler.SchedulerService;
@@ -209,11 +210,20 @@ public class NotebookService {
   public void removeNote(String noteId,
                          ServiceContext context,
                          ServiceCallback<String> callback) throws IOException {
-    Note note = notebook.getNote(noteId);
+    if (!checkPermission(noteId, Permission.OWNER, Message.OP.DEL_NOTE, context, callback)) {
+      return;
+    }
+
+    Note note = null;
+    try {
+      note = notebook.getNote(noteId);
+    } catch (CorruptedNoteException e) {
+      notebook.removeCorruptedNote(noteId, context.getAutheInfo());
+      callback.onSuccess("Delete note successfully", context);
+      return;
+    }
+
     if (note != null) {
-      if (!checkPermission(note.getId(), Permission.OWNER, Message.OP.DEL_NOTE, context, callback)) {
-        return;
-      }
       notebook.removeNote(note, context.getAutheInfo());
       callback.onSuccess("Delete note successfully", context);
     } else {
@@ -1007,20 +1017,29 @@ public class NotebookService {
   public void moveNoteToTrash(String noteId,
                               ServiceContext context,
                               ServiceCallback<Note> callback) throws IOException {
-    Note note = notebook.getNote(noteId);
-    if (note == null) {
-      callback.onFailure(new NoteNotFoundException(noteId), context);
+    if (!checkPermission(noteId, Permission.OWNER, Message.OP.MOVE_NOTE_TO_TRASH, context, callback)) {
       return;
     }
 
-    if (!checkPermission(noteId, Permission.OWNER, Message.OP.MOVE_NOTE_TO_TRASH, context,
-        callback)) {
-      return;
-    }
-    String destNotePath = "/" + NoteManager.TRASH_FOLDER + note.getPath();
+    String destNotePath = "/" + NoteManager.TRASH_FOLDER + notebook.getNoteManager().getNotesInfo().get(noteId);
     if (notebook.containsNote(destNotePath)) {
       destNotePath = destNotePath + " " + TRASH_CONFLICT_TIMESTAMP_FORMATTER.format(Instant.now());
     }
+
+    Note note = null;
+    try {
+       note = notebook.getNote(noteId);
+    } catch (CorruptedNoteException e) {
+        LOGGER.info("Move corrupted note to trash");
+        notebook.moveNote(noteId, destNotePath, context.getAutheInfo());
+        return;
+    }
+
+    if (note == null) {
+      callback.onFailure(new NoteNotFoundException(noteId), context);
+      return;
+    }
+
     notebook.moveNote(noteId, destNotePath, context.getAutheInfo());
     callback.onSuccess(note, context);
   }
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 34b8244..677b1b3 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
@@ -720,7 +720,7 @@ public class NotebookServer extends WebSocketServlet
         authenticationInfo = AuthenticationInfo.fromJson(json);
       } else if (StringUtils.equals(key, "Note")) {
         try {
-          note = Note.fromJson(json);
+          note = Note.fromJson(null, json);
         } catch (IOException e) {
           LOG.warn("Fail to parse note json", e);
         }
diff --git a/zeppelin-server/src/test/java/org/apache/zeppelin/cluster/ClusterNoteEventListenerTest.java b/zeppelin-server/src/test/java/org/apache/zeppelin/cluster/ClusterNoteEventListenerTest.java
index 24a225f..0685cf9 100644
--- a/zeppelin-server/src/test/java/org/apache/zeppelin/cluster/ClusterNoteEventListenerTest.java
+++ b/zeppelin-server/src/test/java/org/apache/zeppelin/cluster/ClusterNoteEventListenerTest.java
@@ -57,7 +57,7 @@ public class ClusterNoteEventListenerTest implements ClusterEventListener {
         LOGGER.debug(authenticationInfo.toJson());
       } else if (key.equals("Note")) {
         try {
-          note = Note.fromJson(json);
+          note = Note.fromJson(null, json);
         } catch (IOException e) {
           LOGGER.warn("Fail to parse note json", e);
         }
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 4700211..d847367 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
@@ -35,6 +35,7 @@ import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import java.io.File;
+import java.io.FileWriter;
 import java.io.IOException;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -263,6 +264,20 @@ public class NotebookServiceTest {
     assertEquals(2, notesInfo.size());
     verify(callback).onSuccess(notesInfo, context);
 
+    // test moving corrupted note to trash
+    Note corruptedNote = notebookService.createNote("/folder_1/corruptedNote", "test", true, context, callback);
+    String corruptedNotePath = notebookDir.getAbsolutePath() + corruptedNote.getPath() + "_" + corruptedNote.getId() + ".zpln";
+    // corrupt note
+    FileWriter myWriter = new FileWriter(corruptedNotePath);
+    myWriter.write("{{{I'm corrupted;;;");
+    myWriter.close();
+    notebookService.moveNoteToTrash(corruptedNote.getId(), context, callback);
+    reset(callback);
+    notesInfo = notebookService.listNotesInfo(false, context, callback);
+    assertEquals(3, notesInfo.size());
+    verify(callback).onSuccess(notesInfo, context);
+    notebookService.removeNote(corruptedNote.getId(), context, callback);
+
     // move note to Trash
     notebookService.moveNoteToTrash(importedNote.getId(), context, callback);
 
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 22419cd..fca7dde 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
@@ -41,6 +41,7 @@ import org.apache.zeppelin.interpreter.ManagedInterpreterGroup;
 import org.apache.zeppelin.interpreter.remote.RemoteAngularObject;
 import org.apache.zeppelin.interpreter.remote.RemoteAngularObjectRegistry;
 import org.apache.zeppelin.interpreter.thrift.InterpreterCompletion;
+import org.apache.zeppelin.notebook.exception.CorruptedNoteException;
 import org.apache.zeppelin.notebook.utility.IdHashes;
 import org.apache.zeppelin.scheduler.ExecutorFactory;
 import org.apache.zeppelin.scheduler.Job.Status;
@@ -1132,7 +1133,7 @@ public class Note implements JsonSerializable {
    * @return Note
    * @throws IOException if fail to parse note json (note file may be corrupted)
    */
-  public static Note fromJson(String json) throws IOException {
+  public static Note fromJson(String noteId, String json) throws IOException {
     try {
       Note note = GSON.fromJson(json, Note.class);
       convertOldInput(note);
@@ -1141,7 +1142,7 @@ public class Note implements JsonSerializable {
       return note;
     } catch (Exception e) {
       LOGGER.error("Fail to parse note json: {}", e.toString());
-      throw new IOException("Fail to parse note json: " + json, e);
+      throw new CorruptedNoteException(noteId, "Fail to parse note json: " + json, e);
     }
   }
 
diff --git a/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Notebook.java b/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Notebook.java
index 01c43ea..8bf1bb3 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
@@ -292,7 +292,7 @@ public class Notebook {
    */
   public Note importNote(String sourceJson, String notePath, AuthenticationInfo subject)
       throws IOException {
-    Note oldNote = Note.fromJson(sourceJson);
+    Note oldNote = Note.fromJson(null, sourceJson);
     if (notePath == null) {
       notePath = oldNote.getName();
     }
@@ -346,6 +346,12 @@ public class Notebook {
     fireNoteRemoveEvent(note, subject);
   }
 
+  public void removeCorruptedNote(String noteId, AuthenticationInfo subject) throws IOException {
+    LOGGER.info("Remove corrupted note: {}", noteId);
+    noteManager.removeNote(noteId, subject);
+    authorizationService.removeNoteAuth(noteId);
+  }
+
   public void removeNote(String noteId, AuthenticationInfo subject) throws IOException {
     Note note = getNote(noteId);
     removeNote(note, subject);
diff --git a/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/exception/CorruptedNoteException.java b/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/exception/CorruptedNoteException.java
new file mode 100644
index 0000000..5307633
--- /dev/null
+++ b/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/exception/CorruptedNoteException.java
@@ -0,0 +1,26 @@
+/*
+ * 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.exception;
+
+import java.io.IOException;
+
+public class CorruptedNoteException extends IOException {
+    public CorruptedNoteException(final String noteId, final String message, Exception e) {
+        super(String.format("noteId: %s - %s", noteId, message), e);
+    }
+}
diff --git a/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/repo/OldVFSNotebookRepo.java b/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/repo/OldVFSNotebookRepo.java
index dfabd96..aefe2d2 100644
--- a/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/repo/OldVFSNotebookRepo.java
+++ b/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/repo/OldVFSNotebookRepo.java
@@ -162,7 +162,7 @@ public class OldVFSNotebookRepo implements OldNotebookRepo {
     String json = IOUtils.toString(ins, conf.getString(ConfVars.ZEPPELIN_ENCODING));
     ins.close();
 
-    return Note.fromJson(json);
+    return Note.fromJson(null, json);
   }
 
   private OldNoteInfo getNoteInfo(FileObject noteDir) throws IOException {
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 e5c1366..7ed73f4 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
@@ -133,7 +133,7 @@ public class VFSNotebookRepo implements NotebookRepo {
         NameScope.DESCENDENT);
     String json = IOUtils.toString(noteFile.getContent().getInputStream(),
         conf.getString(ConfVars.ZEPPELIN_ENCODING));
-    Note note = Note.fromJson(json);
+    Note note = Note.fromJson(noteId, json);
     // setPath here just for testing, because actually NoteManager will setPath
     note.setPath(notePath);
     return note;
diff --git a/zeppelin-zengine/src/test/java/org/apache/zeppelin/notebook/NoteTest.java b/zeppelin-zengine/src/test/java/org/apache/zeppelin/notebook/NoteTest.java
index 5ef6d1f..c89b03f 100644
--- a/zeppelin-zengine/src/test/java/org/apache/zeppelin/notebook/NoteTest.java
+++ b/zeppelin-zengine/src/test/java/org/apache/zeppelin/notebook/NoteTest.java
@@ -205,7 +205,7 @@ public class NoteTest {
     assertEquals(p2, p);
 
     // test Note Json
-    Note note2 = Note.fromJson(note.toJson());
+    Note note2 = Note.fromJson(null, note.toJson());
     assertEquals(note2, note);
   }
 }
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 c37b2e4..d2cf1b8 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
@@ -50,6 +50,7 @@ import org.slf4j.LoggerFactory;
 import org.eclipse.aether.RepositoryException;
 
 import java.io.File;
+import java.io.FileWriter;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -471,6 +472,23 @@ public class NotebookTest extends AbstractInterpreterTest implements ParagraphJo
   }
 
   @Test
+  public void testRemoveCorruptedNote() throws IOException{
+      LOGGER.info("--------------- Test testRemoveCorruptedNote ---------------");
+      // create a note and a paragraph
+      Note corruptedNote = notebook.createNote("note1", anonymous);
+      String corruptedNotePath = notebookDir.getAbsolutePath() + corruptedNote.getPath() + "_" + corruptedNote.getId() + ".zpln";
+      // corrupt note
+      FileWriter myWriter = new FileWriter(corruptedNotePath);
+      myWriter.write("{{{I'm corrupted;;;");
+      myWriter.close();
+      LOGGER.info("--------------- Finish Test testRemoveCorruptedNote ---------------");
+      int numberOfNotes = notebook.getAllNotes().size();
+      notebook.removeNote(corruptedNote, anonymous);
+      assertEquals(numberOfNotes - 1, notebook.getAllNotes().size());
+      LOGGER.info("--------------- Finish Test testRemoveCorruptedNote ---------------");
+  }
+
+  @Test
   public void testInvalidInterpreter() throws IOException, InterruptedException {
     Note note = notebook.createNote("note1", anonymous);
     Paragraph p1 = note.addNewParagraph(AuthenticationInfo.ANONYMOUS);