first draft

This commit is contained in:
Khalid Huseynov 2016-09-01 16:29:57 +09:00
parent 1e8559e651
commit 17e2d4c0c5
4 changed files with 141 additions and 19 deletions

View file

@ -168,7 +168,8 @@ public class NotebookServer extends WebSocketServlet implements
unicastNoteList(conn, subject);
break;
case RELOAD_NOTES_FROM_REPO:
broadcastReloadedNoteList(subject);
//broadcastReloadedNoteList(subject);
unicastNoteList(conn, subject);
break;
case GET_HOME_NOTE:
sendHomeNote(conn, userAndRoles, notebook, messagereceived);
@ -331,7 +332,9 @@ public class NotebookServer extends WebSocketServlet implements
private void broadcastToNoteBindedInterpreter(String interpreterGroupId,
Message m) {
Notebook notebook = notebook();
List<Note> notes = notebook.getAllNotes();
//TODO(khalid): anonymous or specific user notes?
AuthenticationInfo subject = new AuthenticationInfo("anonymous");
List<Note> notes = notebook.getAllNotes(subject);
for (Note note : notes) {
List<String> ids = notebook.getInterpreterFactory().getInterpreters(note.getId());
for (String id : ids) {
@ -472,6 +475,7 @@ public class NotebookServer extends WebSocketServlet implements
LOG.error("Fail to reload notes from repository", e);
}
}
List<Note> notes = notebook.getAllNotes(subject);
List<Map<String, String>> notesInfo = new LinkedList<>();
for (Note note : notes) {
@ -855,7 +859,9 @@ public class NotebookServer extends WebSocketServlet implements
if (global) { // broadcast change to all web session that uses related
// interpreter.
for (Note n : notebook.getAllNotes()) {
//TODO(khalid): anonymous or specific user notes?
AuthenticationInfo subject = new AuthenticationInfo("anonymous");
for (Note n : notebook.getAllNotes(subject)) {
List<InterpreterSetting> settings = notebook.getInterpreterFactory()
.getInterpreterSettings(note.getId());
for (InterpreterSetting setting : settings) {
@ -1533,7 +1539,9 @@ public class NotebookServer extends WebSocketServlet implements
return;
}
List<Note> notes = notebook.getAllNotes();
//TODO(khalid): anonymous or specific user notes?
AuthenticationInfo subject = new AuthenticationInfo("anonymous");
List<Note> notes = notebook.getAllNotes(subject );
for (Note note : notes) {
if (object.getNoteId() != null && !note.getId().equals(object.getNoteId())) {
continue;
@ -1558,7 +1566,9 @@ public class NotebookServer extends WebSocketServlet implements
@Override
public void onRemove(String interpreterGroupId, String name, String noteId, String paragraphId) {
Notebook notebook = notebook();
List<Note> notes = notebook.getAllNotes();
//TODO(khalid): anonymous or specific user notes?
AuthenticationInfo subject = new AuthenticationInfo("anonymous");
List<Note> notes = notebook.getAllNotes(subject);
for (Note note : notes) {
if (noteId != null && !note.getId().equals(noteId)) {
continue;

View file

@ -32,6 +32,7 @@ import org.apache.zeppelin.notebook.Note;
import org.apache.zeppelin.notebook.Paragraph;
import org.apache.zeppelin.scheduler.Job.Status;
import org.apache.zeppelin.server.ZeppelinServer;
import org.apache.zeppelin.user.AuthenticationInfo;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.FixMethodOrder;
@ -341,7 +342,9 @@ public class ZeppelinRestApiTest extends AbstractTestRestApi {
Map<String, Object> resp = gson.fromJson(get.getResponseBodyAsString(), new TypeToken<Map<String, Object>>() {
}.getType());
List<Map<String, String>> body = (List<Map<String, String>>) resp.get("body");
assertEquals("List notebooks are equal", ZeppelinServer.notebook.getAllNotes().size(), body.size());
//TODO(khalid): anonymous or specific user notes?
AuthenticationInfo subject = new AuthenticationInfo("anonymous");
assertEquals("List notebooks are equal", ZeppelinServer.notebook.getAllNotes(subject).size(), body.size());
get.releaseConnection();
}

View file

@ -20,6 +20,7 @@ package org.apache.zeppelin.notebook;
import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
@ -31,9 +32,9 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import com.google.common.base.Predicate;
import com.google.common.collect.FluentIterable;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
@ -484,11 +485,74 @@ public class Notebook implements NoteEventListener {
}
List<NoteInfo> noteInfos = notebookRepo.list(subject);
noteInfos = getAuthorizedNoteInfos(noteInfos, subject);
for (NoteInfo info : noteInfos) {
loadNoteFromRepo(info.getId(), subject);
}
}
private List<NoteInfo> getAuthorizedNoteInfos(List<NoteInfo> notes, AuthenticationInfo subject) {
Set<String> allIds = Sets.newHashSet();
if (subject == null) {
logger.warn("Subject for retrieving notes is null");
return notes;
}
if ("anonymous".equals(subject.getUser())) {
return notes;
}
for (NoteInfo note: notes) {
allIds.add(note.getId());
}
Set<String> filteredIds = applyAuthorizationFilter(allIds, subject.getUser());
List<NoteInfo> filteredNotes = Lists.newArrayList();
for (NoteInfo note: notes) {
if (filteredIds.contains(note.getId())){
filteredNotes.add(note);
}
}
return filteredNotes;
}
//TODO(khalid): to change from processing everytime to keeping in memory view of each user
public List<Note> getAuthorizedNotes(AuthenticationInfo subject) {
List<Note> allNotes = new ArrayList<>(notes.values());
Set<String> allIds = Sets.newHashSet();
if (subject == null) {
logger.warn("Subject for retrieving notes is null");
return allNotes;
}
if ("anonymous".equals(subject.getUser())) {
return allNotes;
}
for (Note note: allNotes) {
allIds.add(note.getId());
}
Set<String> filteredIds = applyAuthorizationFilter(allIds, subject.getUser());
List<Note> filteredNotes = Lists.newArrayList();
for (Note note: allNotes) {
if (filteredIds.contains(note.getId())){
filteredNotes.add(note);
}
}
return filteredNotes;
}
public Set<String> applyAuthorizationFilter(Set<String> ids, String user) {
logger.info("applying filter for {}", user);
Set<String> filteredIds = Sets.newHashSet();
Set<String> userEntity = Sets.newHashSet((Arrays.asList(user)));
NotebookAuthorization auth = getNotebookAuthorization();
for (String id: ids) {
if (auth.isOwner(id, userEntity) || auth.isReader(id, userEntity)
|| auth.isWriter(id, userEntity)) {
filteredIds.add(id);
}
}
return filteredIds;
}
private class SnapshotAngularObject {
String intpGroupId;
AngularObject angularObject;
@ -514,9 +578,9 @@ public class Notebook implements NoteEventListener {
}
}
public List<Note> getAllNotes() {
public List<Note> getAllNotes(AuthenticationInfo subject) {
synchronized (notes) {
List<Note> noteList = new ArrayList<>(notes.values());
List<Note> noteList = getAuthorizedNotes(subject);
Collections.sort(noteList, new Comparator<Note>() {
@Override
public int compare(Note note1, Note note2) {
@ -534,7 +598,7 @@ public class Notebook implements NoteEventListener {
return noteList;
}
}
/*
public List<Note> getAllNotes(AuthenticationInfo subject) {
final Set<String> entities = Sets.newHashSet();
if (subject != null) {
@ -563,7 +627,7 @@ public class Notebook implements NoteEventListener {
});
}
}
*/
private Map<String, Object> getParagraphForJobManagerItem(Paragraph paragraph) {
Map<String, Object> paragraphItem = new HashMap<>();
@ -696,7 +760,7 @@ public class Notebook implements NoteEventListener {
}
}
List<Note> notes = getAllNotes();
List<Note> notes = getAllNotes(subject);
List<Map<String, Object>> notesInfo = new LinkedList<>();
for (Note note : notes) {
boolean isNotebookRunning = false;

View file

@ -135,12 +135,15 @@ public class NotebookTest implements JobListenerFactory{
File destDir = new File(notebookDir.getAbsolutePath() + "/2A94M5J1Z");
FileUtils.copyDirectory(srcDir, destDir);
//TODO(khalid): anonymous or specific user notes?
AuthenticationInfo subject = new AuthenticationInfo("anonymous");
// when load
notebook.reloadAllNotes(null);
assertEquals(1, notebook.getAllNotes().size());
assertEquals(1, notebook.getAllNotes(subject).size());
// then interpreter factory should be injected into all the paragraphs
Note note = notebook.getAllNotes().get(0);
Note note = notebook.getAllNotes(subject).get(0);
assertNull(note.getParagraphs().get(0).getRepl(null));
}
@ -163,14 +166,17 @@ public class NotebookTest implements JobListenerFactory{
logger.error(e.toString(), e);
}
//TODO(khalid): anonymous or specific user notes?
AuthenticationInfo subject = new AuthenticationInfo("anonymous");
// doesn't have copied notebook in memory before reloading
List<Note> notes = notebook.getAllNotes();
List<Note> notes = notebook.getAllNotes(subject);
assertEquals(notes.size(), 0);
// load copied notebook on memory when reloadAllNotes() is called
Note copiedNote = notebookRepo.get("2A94M5J1Z", null);
notebook.reloadAllNotes(null);
notes = notebook.getAllNotes();
notes = notebook.getAllNotes(subject);
assertEquals(notes.size(), 2);
assertEquals(notes.get(1).getId(), copiedNote.getId());
assertEquals(notes.get(1).getName(), copiedNote.getName());
@ -183,15 +189,52 @@ public class NotebookTest implements JobListenerFactory{
}
// keep notebook in memory before reloading
notes = notebook.getAllNotes();
notes = notebook.getAllNotes(subject);
assertEquals(notes.size(), 2);
// delete notebook from notebook list when reloadAllNotes() is called
notebook.reloadAllNotes(null);
notes = notebook.getAllNotes();
notes = notebook.getAllNotes(subject);
assertEquals(notes.size(), 0);
}
@Test
public void testReloadAuthorizedNotes() throws IOException {
AuthenticationInfo user1 = new AuthenticationInfo("user1");
AuthenticationInfo user2 = new AuthenticationInfo("user2");
notebook.reloadAllNotes(user1);
List<Note> notes1 = notebook.getAllNotes(user1);
notebook.reloadAllNotes(user2);
List<Note> notes2 = notebook.getAllNotes(user2);
assertEquals(notes1.size(), 0);
assertEquals(notes2.size(), 0);
logger.info("Loaded {} notes", notes1.size());
Note note = notebook.createNote(user1);
setNotePermissions(note.id(), user1.getUser(), true, true, true);
notebook.reloadAllNotes(user1);
notes1 = notebook.getAllNotes(user1);
notebook.reloadAllNotes(user2);
notes2 = notebook.getAllNotes(user2);
assertEquals(notes1.size(), 1);
assertEquals(notes2.size(), 0);
}
//fails if all failed, otherwise true
private boolean setNotePermissions(String noteId, String user, boolean isOwner, boolean isReader, boolean isWriter) {
NotebookAuthorization notebookAuthorization = notebook.getNotebookAuthorization();
Set<String> owners = notebookAuthorization.getOwners(noteId);
Set<String> readers = notebookAuthorization.getReaders(noteId);
Set<String> writers = notebookAuthorization.getWriters(noteId);
boolean ownerSet = isOwner ? owners.add(user) : owners.remove(user);
boolean readerSet = isReader ? readers.add(user) : readers.remove(user);
boolean writerSet = isWriter ? writers.add(user) : writers.remove(user);
notebookAuthorization.setOwners(noteId, owners);
notebookAuthorization.setReaders(noteId, readers);
notebookAuthorization.setWriters(noteId, writers);
return ownerSet || readerSet || writerSet;
}
@Test
public void testPersist() throws IOException, SchedulerException, RepositoryException {
Note note = notebook.createNote(null);
@ -207,7 +250,9 @@ public class NotebookTest implements JobListenerFactory{
Notebook notebook2 = new Notebook(
conf, notebookRepo, schedulerFactory,
new InterpreterFactory(conf, null, null, null, depResolver), this, null, null, null);
assertEquals(1, notebook2.getAllNotes().size());
//TODO(khalid): anonymous or specific user notes?
AuthenticationInfo subject = new AuthenticationInfo("anonymous");
assertEquals(1, notebook2.getAllNotes(subject).size());
}
@Test