@POST
  @Path("{noteId}")
  @ZeppelinApi
  public Response cloneNote(@PathParam("noteId") String noteId, String message)
      throws IOException, IllegalArgumentException {

    LOGGER.info("Clone note by JSON {}", message);
    checkIfUserCanWrite(noteId, "Insufficient privileges you cannot clone this note");
    NewNoteRequest request = GSON.fromJson(message, NewNoteRequest.class);
    String newNoteName = null;
    String revisionId = null;
    if (request != null) {
      newNoteName = request.getName();
      revisionId = request.getRevisionId();
    }
    AuthenticationInfo subject = new AuthenticationInfo(authenticationService.getPrincipal());
    String newNoteId = notebookService.cloneNote(noteId, revisionId, newNoteName, getServiceContext(),
            new RestServiceCallback<Note>() {
              @Override
              public void onSuccess(Note newNote, ServiceContext context) throws IOException {
                notebookServer.broadcastNote(newNote);
                notebookServer.broadcastNoteList(subject, context.getUserAndRoles());
              }
            });
    return new JsonResponse<>(Status.OK, "", newNoteId).build();
  }
@Test
  void testCloneNote() throws IOException {
    LOG.info("Running testCloneNote");
    String note1Id = null;
    List<String> clonedNoteIds = new ArrayList<>();
    String text1 = "%text clone note";
    String text2 = "%text clone revision of note";
    try {
      note1Id = notebook.createNote("note1", anonymous);

      // add text and commit note
      NotebookRepoWithVersionControl.Revision first_commit =
              notebook.processNote(note1Id, note -> {
                Paragraph p1 = note.addNewParagraph(anonymous);
                p1.setText(text2);
                notebook.saveNote(note, AuthenticationInfo.ANONYMOUS);
                return notebook.checkpointNote(note.getId(), note.getPath(), "first commit", anonymous);
              });

      // change the text of note
      notebook.processNote(note1Id, note -> {
        note.getParagraph(0).setText(text1);
        return null;
      });

      // Clone a note
      CloseableHttpResponse post1 = httpPost("/notebook/" + note1Id, "");
      // Clone a revision of note
      CloseableHttpResponse post2 =
              httpPost("/notebook/" + note1Id, "{ revisionId: " + first_commit.id + "}");

      // Verify the responses
      for (int i = 0; i < 2; i++) {
        CloseableHttpResponse post = Arrays.asList(post1, post2).get(i);
        String text = Arrays.asList(text1, text2).get(i);

        String postResponse = EntityUtils.toString(post.getEntity(), StandardCharsets.UTF_8);
        LOG.info("testCloneNote response: {}", postResponse);
        assertThat(post, isAllowed());
        Map<String, Object> resp = gson.fromJson(postResponse,
                new TypeToken<Map<String, Object>>() {
                }.getType());
        clonedNoteIds.add((String) resp.get("body"));
        post.close();

        CloseableHttpResponse get = httpGet("/notebook/" + clonedNoteIds.get(clonedNoteIds.size() - 1));
        assertThat(get, isAllowed());
        Map<String, Object> resp2 = gson.fromJson(EntityUtils.toString(get.getEntity(), StandardCharsets.UTF_8),
                new TypeToken<Map<String, Object>>() {
                }.getType());
        Map<String, Object> resp2Body = (Map<String, Object>) resp2.get("body");
        List<Map<String, String>> paragraphs = (List<Map<String, String>>) resp2Body.get("paragraphs");
        // Verify that the original and copied text are consistent
        assertEquals(text, paragraphs.get(0).get("text"));
        //    assertEquals(resp2Body.get("name"), "Note " + clonedNoteId);
        get.close();
      }
    } finally {
      // cleanup
      if (null != note1Id) {
        notebook.removeNote(note1Id, anonymous);
      }
      if (null != clonedNoteIds) {
        for (String clonedNoteId : clonedNoteIds) {
          notebook.removeNote(clonedNoteId, anonymous);
        }
      }
    }
  }