org.apache.zeppelin.notebook.repo.VFSNotebookRepo Maven / Gradle / Ivy
/*
* 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.repo;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.LinkedList;
import java.util.List;
import org.apache.commons.io.IOUtils;
import org.apache.commons.vfs2.FileContent;
import org.apache.commons.vfs2.FileObject;
import org.apache.commons.vfs2.FileSystemManager;
import org.apache.commons.vfs2.FileType;
import org.apache.commons.vfs2.NameScope;
import org.apache.commons.vfs2.Selectors;
import org.apache.commons.vfs2.VFS;
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.Paragraph;
import org.apache.zeppelin.scheduler.Job.Status;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
/**
*
*/
public class VFSNotebookRepo implements NotebookRepo {
Logger logger = LoggerFactory.getLogger(VFSNotebookRepo.class);
private FileSystemManager fsManager;
private URI filesystemRoot;
private ZeppelinConfiguration conf;
public VFSNotebookRepo(ZeppelinConfiguration conf) throws IOException {
this.conf = conf;
try {
filesystemRoot = new URI(conf.getNotebookDir());
} catch (URISyntaxException e1) {
throw new IOException(e1);
}
if (filesystemRoot.getScheme() == null) { // it is local path
try {
this.filesystemRoot = new URI(new File(
conf.getRelativeDir(filesystemRoot.getPath())).getAbsolutePath());
} catch (URISyntaxException e) {
throw new IOException(e);
}
} else {
this.filesystemRoot = filesystemRoot;
}
fsManager = VFS.getManager();
}
private String getPath(String path) {
if (path == null || path.trim().length() == 0) {
return filesystemRoot.toString();
}
if (path.startsWith("/")) {
return filesystemRoot.toString() + path;
} else {
return filesystemRoot.toString() + "/" + path;
}
}
private boolean isDirectory(FileObject fo) throws IOException {
if (fo == null) return false;
if (fo.getType() == FileType.FOLDER) {
return true;
} else {
return false;
}
}
@Override
public List list() throws IOException {
FileObject rootDir = getRootDir();
FileObject[] children = rootDir.getChildren();
List infos = new LinkedList();
for (FileObject f : children) {
String fileName = f.getName().getBaseName();
if (f.isHidden()
|| fileName.startsWith(".")
|| fileName.startsWith("#")
|| fileName.startsWith("~")) {
// skip hidden, temporary files
continue;
}
if (!isDirectory(f)) {
// currently single note is saved like, [NOTE_ID]/note.json.
// so it must be a directory
continue;
}
NoteInfo info = null;
try {
info = getNoteInfo(f);
if (info != null) {
infos.add(info);
}
} catch (IOException e) {
logger.error("Can't read note " + f.getName().toString(), e);
}
}
return infos;
}
private Note getNote(FileObject noteDir) throws IOException {
if (!isDirectory(noteDir)) {
throw new IOException(noteDir.getName().toString() + " is not a directory");
}
FileObject noteJson = noteDir.resolveFile("note.json", NameScope.CHILD);
if (!noteJson.exists()) {
throw new IOException(noteJson.getName().toString() + " not found");
}
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.setPrettyPrinting();
Gson gson = gsonBuilder.create();
FileContent content = noteJson.getContent();
InputStream ins = content.getInputStream();
String json = IOUtils.toString(ins, conf.getString(ConfVars.ZEPPELIN_ENCODING));
ins.close();
Note note = gson.fromJson(json, Note.class);
// note.setReplLoader(replLoader);
// note.jobListenerFactory = jobListenerFactory;
for (Paragraph p : note.getParagraphs()) {
if (p.getStatus() == Status.PENDING || p.getStatus() == Status.RUNNING) {
p.setStatus(Status.ABORT);
}
}
return note;
}
private NoteInfo getNoteInfo(FileObject noteDir) throws IOException {
Note note = getNote(noteDir);
return new NoteInfo(note);
}
@Override
public Note get(String noteId) throws IOException {
FileObject rootDir = fsManager.resolveFile(getPath("/"));
FileObject noteDir = rootDir.resolveFile(noteId, NameScope.CHILD);
return getNote(noteDir);
}
private FileObject getRootDir() throws IOException {
FileObject rootDir = fsManager.resolveFile(getPath("/"));
if (!rootDir.exists()) {
throw new IOException("Root path does not exists");
}
if (!isDirectory(rootDir)) {
throw new IOException("Root path is not a directory");
}
return rootDir;
}
@Override
public void save(Note note) throws IOException {
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.setPrettyPrinting();
Gson gson = gsonBuilder.create();
String json = gson.toJson(note);
FileObject rootDir = getRootDir();
FileObject noteDir = rootDir.resolveFile(note.id(), NameScope.CHILD);
if (!noteDir.exists()) {
noteDir.createFolder();
}
if (!isDirectory(noteDir)) {
throw new IOException(noteDir.getName().toString() + " is not a directory");
}
FileObject noteJson = noteDir.resolveFile("note.json", NameScope.CHILD);
// false means not appending. creates file if not exists
OutputStream out = noteJson.getContent().getOutputStream(false);
out.write(json.getBytes(conf.getString(ConfVars.ZEPPELIN_ENCODING)));
out.close();
}
@Override
public void remove(String noteId) throws IOException {
FileObject rootDir = fsManager.resolveFile(getPath("/"));
FileObject noteDir = rootDir.resolveFile(noteId, NameScope.CHILD);
if (!noteDir.exists()) {
// nothing to do
return;
}
if (!isDirectory(noteDir)) {
// it is not look like zeppelin note savings
throw new IOException("Can not remove " + noteDir.getName().toString());
}
noteDir.delete(Selectors.SELECT_SELF_AND_CHILDREN);
}
}