/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.zeppelin.notebook; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.LinkedHashMap; import java.util.Map; /** * Folder view of notes of Notebook. * FolderView allows you to see notes from perspective of folders. */ public class FolderView implements NoteNameListener, FolderListener { // key: folderId private final Map<String, Folder> folders = new LinkedHashMap<>(); // key: a note, value: a folder where the note belongs to private final Map<Note, Folder> index = new LinkedHashMap<>(); private static final Logger logger = LoggerFactory.getLogger(FolderView.class); public Folder getFolder(String folderId) { String normalizedFolderId = Folder.normalizeFolderId(folderId); return folders.get(normalizedFolderId); } /** * Rename folder of which id is folderId to newFolderId * * @param oldFolderId folderId to rename * @param newFolderId newFolderId * @return `null` if folder not exists, else old Folder * in order to know which notes and child folders are renamed */ public Folder renameFolder(String oldFolderId, String newFolderId) { String normOldFolderId = Folder.normalizeFolderId(oldFolderId); String normNewFolderId = Folder.normalizeFolderId(newFolderId); if (!hasFolder(normOldFolderId)) return null; if (oldFolderId.equals(Folder.ROOT_FOLDER_ID)) // cannot rename the root folder return null; // check whether oldFolderId and newFolderId are same or not if (normOldFolderId.equals(normNewFolderId)) return getFolder(normOldFolderId); logger.info("Rename {} to {}", normOldFolderId, normNewFolderId); Folder oldFolder = getFolder(normOldFolderId); removeFolder(oldFolderId); oldFolder.rename(normNewFolderId); return oldFolder; } public Folder getFolderOf(Note note) { return index.get(note); } public void putNote(Note note) { if (note.isNameEmpty()) { return; } String folderId = note.getFolderId(); Folder folder = getOrCreateFolder(folderId); folder.addNote(note); synchronized (index) { index.put(note, folder); } } private Folder getOrCreateFolder(String folderId) { if (folders.containsKey(folderId)) return folders.get(folderId); return createFolder(folderId); } private Folder createFolder(String folderId) { folderId = Folder.normalizeFolderId(folderId); Folder newFolder = new Folder(folderId); newFolder.addFolderListener(this); logger.info("Create folder {}", folderId); synchronized (folders) { folders.put(folderId, newFolder); } Folder parentFolder = getOrCreateFolder(newFolder.getParentFolderId()); newFolder.setParent(parentFolder); parentFolder.addChild(newFolder); return newFolder; } private void removeFolder(String folderId) { Folder removedFolder; synchronized (folders) { removedFolder = folders.remove(folderId); } if (removedFolder != null) { logger.info("Remove folder {}", folderId); Folder parent = removedFolder.getParent(); parent.removeChild(folderId); removeFolderIfEmpty(parent.getId()); } } private void removeFolderIfEmpty(String folderId) { if (!hasFolder(folderId)) return; Folder folder = getFolder(folderId); if (folder.countNotes() == 0 && !folder.hasChild()) { logger.info("Folder {} is empty", folder.getId()); removeFolder(folderId); } } public void removeNote(Note note) { if (!index.containsKey(note)) { return; } Folder folder = index.get(note); folder.removeNote(note); removeFolderIfEmpty(folder.getId()); synchronized (index) { index.remove(note); } } public void clear() { synchronized (folders) { folders.clear(); } synchronized (index) { index.clear(); } } public boolean hasFolder(String folderId) { return getFolder(folderId) != null; } public boolean hasNote(Note note) { return index.containsKey(note); } public int countFolders() { return folders.size(); } public int countNotes() { int count = 0; for (Folder folder : folders.values()) { count += folder.countNotes(); } return count; } /** * Fired after a note's setName() run. * When the note's name changed, FolderView should check if the note is in the right folder. * * @param note * @param oldName */ @Override public void onNoteNameChanged(Note note, String oldName) { if (note.isNameEmpty()) { return; } logger.info("Note name changed: {} -> {}", oldName, note.getName()); // New note if (!index.containsKey(note)) { putNote(note); } // Existing note else { // If the note is in the right place, just return Folder folder = index.get(note); if (folder.getId().equals(note.getFolderId())) { return; } // The note's folder is changed! removeNote(note); putNote(note); } } @Override public void onFolderRenamed(Folder folder, String oldFolderId) { if (getFolder(folder.getId()) == folder) // the folder is at the right place return; logger.info("folder renamed: {} -> {}", oldFolderId, folder.getId()); if (getFolder(oldFolderId) == folder) folders.remove(oldFolderId); Folder newFolder = getOrCreateFolder(folder.getId()); newFolder.merge(folder); for (Note note : folder.getNotes()) { index.put(note, newFolder); } } }