Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.apache.zeppelin.socket.NotebookServer 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.socket;
import com.google.common.base.Strings;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;
import java.io.IOException;
import java.lang.reflect.Type;
import java.net.URISyntaxException;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicReference;
import javax.inject.Inject;
import javax.inject.Provider;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.apache.thrift.TException;
import org.apache.zeppelin.cluster.ClusterManagerServer;
import org.apache.zeppelin.cluster.event.ClusterEvent;
import org.apache.zeppelin.cluster.event.ClusterEventListener;
import org.apache.zeppelin.cluster.event.ClusterMessage;
import org.apache.zeppelin.conf.ZeppelinConfiguration;
import org.apache.zeppelin.display.AngularObject;
import org.apache.zeppelin.display.AngularObjectRegistry;
import org.apache.zeppelin.display.AngularObjectRegistryListener;
import org.apache.zeppelin.display.GUI;
import org.apache.zeppelin.display.Input;
import org.apache.zeppelin.helium.ApplicationEventListener;
import org.apache.zeppelin.helium.HeliumPackage;
import org.apache.zeppelin.interpreter.InterpreterGroup;
import org.apache.zeppelin.interpreter.InterpreterResult;
import org.apache.zeppelin.interpreter.InterpreterSetting;
import org.apache.zeppelin.interpreter.remote.RemoteAngularObjectRegistry;
import org.apache.zeppelin.interpreter.remote.RemoteInterpreterProcessListener;
import org.apache.zeppelin.interpreter.thrift.InterpreterCompletion;
import org.apache.zeppelin.interpreter.thrift.ParagraphInfo;
import org.apache.zeppelin.interpreter.thrift.ServiceException;
import org.apache.zeppelin.jupyter.JupyterUtil;
import org.apache.zeppelin.notebook.Note;
import org.apache.zeppelin.notebook.NoteEventListener;
import org.apache.zeppelin.notebook.NoteInfo;
import org.apache.zeppelin.notebook.Notebook;
import org.apache.zeppelin.notebook.NotebookImportDeserializer;
import org.apache.zeppelin.notebook.Paragraph;
import org.apache.zeppelin.notebook.ParagraphJobListener;
import org.apache.zeppelin.notebook.AuthorizationService;
import org.apache.zeppelin.notebook.repo.NotebookRepoWithVersionControl.Revision;
import org.apache.zeppelin.common.Message;
import org.apache.zeppelin.common.Message.OP;
import org.apache.zeppelin.rest.exception.ForbiddenException;
import org.apache.zeppelin.scheduler.Job.Status;
import org.apache.zeppelin.service.ConfigurationService;
import org.apache.zeppelin.service.JobManagerService;
import org.apache.zeppelin.service.NotebookService;
import org.apache.zeppelin.service.ServiceContext;
import org.apache.zeppelin.service.SimpleServiceCallback;
import org.apache.zeppelin.socket.ConnectionManager.UserIterator;
import org.apache.zeppelin.ticket.TicketContainer;
import org.apache.zeppelin.types.InterpreterSettingsList;
import org.apache.zeppelin.user.AuthenticationInfo;
import org.apache.zeppelin.util.IdHashes;
import org.apache.zeppelin.utils.CorsUtils;
import org.apache.zeppelin.utils.TestUtils;
import org.eclipse.jetty.util.annotation.ManagedAttribute;
import org.eclipse.jetty.util.annotation.ManagedObject;
import org.eclipse.jetty.util.annotation.ManagedOperation;
import org.eclipse.jetty.websocket.servlet.WebSocketServlet;
import org.eclipse.jetty.websocket.servlet.WebSocketServletFactory;
import org.glassfish.hk2.api.ServiceLocator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static org.apache.zeppelin.common.Message.MSG_ID_NOT_DEFINED;
/**
* Zeppelin websocket service. This class used setter injection because all servlet should have
* no-parameter constructor
*/
@ManagedObject
public class NotebookServer extends WebSocketServlet
implements NotebookSocketListener,
AngularObjectRegistryListener,
RemoteInterpreterProcessListener,
ApplicationEventListener,
ParagraphJobListener,
NoteEventListener,
ClusterEventListener {
/**
* Job manager service type.
*/
protected enum JobManagerServiceType {
JOB_MANAGER_PAGE("JOB_MANAGER_PAGE");
private String serviceTypeKey;
JobManagerServiceType(String serviceType) {
this.serviceTypeKey = serviceType;
}
String getKey() {
return this.serviceTypeKey;
}
}
private Boolean collaborativeModeEnable = ZeppelinConfiguration
.create()
.isZeppelinNotebookCollaborativeModeEnable();
private static final Logger LOG = LoggerFactory.getLogger(NotebookServer.class);
private static Gson gson = new GsonBuilder()
.setDateFormat("yyyy-MM-dd'T'HH:mm:ssZ")
.registerTypeAdapter(Date.class, new NotebookImportDeserializer())
.setPrettyPrinting()
.registerTypeAdapterFactory(Input.TypeAdapterFactory).create();
private static AtomicReference self = new AtomicReference<>();
private ExecutorService executorService = Executors.newFixedThreadPool(10);
private boolean sendParagraphStatusToFrontend = ZeppelinConfiguration.create().getBoolean(
ZeppelinConfiguration.ConfVars.ZEPPELIN_WEBSOCKET_PARAGRAPH_STATUS_PROGRESS);
private Provider notebookProvider;
private Provider notebookServiceProvider;
private Provider authorizationServiceProvider;
private Provider configurationServiceProvider;
private Provider jobManagerServiceProvider;
private Provider connectionManagerProvider;
public NotebookServer() {
NotebookServer.self.set(this);
LOG.info("NotebookServer instantiated: {}", this);
}
@Inject
public void setServiceLocator(ServiceLocator serviceLocator) {
LOG.info("Injected ServiceLocator: {}", serviceLocator);
}
@Inject
public void setNotebook(Provider notebookProvider) {
this.notebookProvider = notebookProvider;
LOG.info("Injected NotebookProvider");
}
@Inject
public void setNotebookService(
Provider notebookServiceProvider) {
this.notebookServiceProvider = notebookServiceProvider;
LOG.info("Injected NotebookServiceProvider");
}
@Inject
public void setAuthorizationServiceProvider(Provider
authorizationServiceProvider) {
this.authorizationServiceProvider = authorizationServiceProvider;
LOG.info("Injected NotebookAuthorizationServiceProvider");
}
@Inject
public void setConnectionManagerProvider(Provider connectionManagerProvider) {
this.connectionManagerProvider = connectionManagerProvider;
LOG.info("Injected ConnectionManagerProvider");
}
@Inject
public void setConfigurationService(
Provider configurationServiceProvider) {
this.configurationServiceProvider = configurationServiceProvider;
}
@Inject
public void setJobManagerService(
Provider jobManagerServiceProvider) {
this.jobManagerServiceProvider = jobManagerServiceProvider;
}
public static NotebookServer getInstance() {
return TestUtils.getInstance(NotebookServer.class);
}
public Notebook getNotebook() {
return notebookProvider.get();
}
public ConnectionManager getConnectionManager() {
return connectionManagerProvider.get();
}
public NotebookService getNotebookService() {
return notebookServiceProvider.get();
}
public ConfigurationService getConfigurationService() {
return configurationServiceProvider.get();
}
public synchronized JobManagerService getJobManagerService() {
return jobManagerServiceProvider.get();
}
public AuthorizationService getNotebookAuthorizationService() {
return authorizationServiceProvider.get();
}
@Override
public void configure(WebSocketServletFactory factory) {
factory.setCreator(new NotebookWebSocketCreator(this));
}
public boolean checkOrigin(HttpServletRequest request, String origin) {
try {
return CorsUtils.isValidOrigin(origin, ZeppelinConfiguration.create());
} catch (UnknownHostException | URISyntaxException e) {
LOG.error(e.toString(), e);
}
return false;
}
@Override
public void onOpen(NotebookSocket conn) {
LOG.info("New connection from {}", conn);
getConnectionManager().addConnection(conn);
}
@Override
public void onMessage(NotebookSocket conn, String msg) {
try {
Message messagereceived = deserializeMessage(msg);
if (messagereceived.op != OP.PING) {
LOG.debug("RECEIVE: " + messagereceived.op +
", RECEIVE PRINCIPAL: " + messagereceived.principal +
", RECEIVE TICKET: " + messagereceived.ticket +
", RECEIVE ROLES: " + messagereceived.roles +
", RECEIVE DATA: " + messagereceived.data);
}
if (LOG.isTraceEnabled()) {
LOG.trace("RECEIVE MSG = " + messagereceived);
}
String ticket = TicketContainer.instance.getTicket(messagereceived.principal);
if (ticket != null &&
(messagereceived.ticket == null || !ticket.equals(messagereceived.ticket))) {
/* not to pollute logs, log instead of exception */
if (StringUtils.isEmpty(messagereceived.ticket)) {
LOG.debug("{} message: invalid ticket {} != {}", messagereceived.op,
messagereceived.ticket, ticket);
} else {
if (!messagereceived.op.equals(OP.PING)) {
conn.send(serializeMessage(new Message(OP.SESSION_LOGOUT).put("info",
"Your ticket is invalid possibly due to server restart. "
+ "Please login again.")));
}
}
return;
}
ZeppelinConfiguration conf = ZeppelinConfiguration.create();
boolean allowAnonymous = conf.isAnonymousAllowed();
if (!allowAnonymous && messagereceived.principal.equals("anonymous")) {
LOG.warn("Anonymous access not allowed.");
return;
}
if (Message.isDisabledForRunningNotes(messagereceived.op)) {
Note note = getNotebook().getNote((String) messagereceived.get("noteId"));
if (note != null && note.isRunning()) {
throw new Exception("Note is now running sequentially. Can not be performed: " +
messagereceived.op);
}
}
if (StringUtils.isEmpty(conn.getUser())) {
getConnectionManager().addUserConnection(messagereceived.principal, conn);
}
// Lets be elegant here
switch (messagereceived.op) {
case LIST_NOTES:
listNotesInfo(conn, messagereceived);
break;
case RELOAD_NOTES_FROM_REPO:
broadcastReloadedNoteList(conn, getServiceContext(messagereceived));
break;
case GET_HOME_NOTE:
getHomeNote(conn, messagereceived);
break;
case GET_NOTE:
getNote(conn, messagereceived);
break;
case NEW_NOTE:
createNote(conn, messagereceived);
break;
case DEL_NOTE:
deleteNote(conn, messagereceived);
break;
case REMOVE_FOLDER:
removeFolder(conn, messagereceived);
break;
case MOVE_NOTE_TO_TRASH:
moveNoteToTrash(conn, messagereceived);
break;
case MOVE_FOLDER_TO_TRASH:
moveFolderToTrash(conn, messagereceived);
break;
case EMPTY_TRASH:
emptyTrash(conn, messagereceived);
break;
case RESTORE_FOLDER:
restoreFolder(conn, messagereceived);
break;
case RESTORE_NOTE:
restoreNote(conn, messagereceived);
break;
case RESTORE_ALL:
restoreAll(conn, messagereceived);
break;
case CLONE_NOTE:
cloneNote(conn, messagereceived);
break;
case IMPORT_NOTE:
importNote(conn, messagereceived);
break;
case CONVERT_NOTE_NBFORMAT:
convertNote(conn, messagereceived);
break;
case COMMIT_PARAGRAPH:
updateParagraph(conn, messagereceived);
break;
case RUN_PARAGRAPH:
runParagraph(conn, messagereceived);
break;
case PARAGRAPH_EXECUTED_BY_SPELL:
broadcastSpellExecution(conn, messagereceived);
break;
case RUN_ALL_PARAGRAPHS:
runAllParagraphs(conn, messagereceived);
break;
case CANCEL_PARAGRAPH:
cancelParagraph(conn, messagereceived);
break;
case MOVE_PARAGRAPH:
moveParagraph(conn, messagereceived);
break;
case INSERT_PARAGRAPH:
insertParagraph(conn, messagereceived);
break;
case COPY_PARAGRAPH:
copyParagraph(conn, messagereceived);
break;
case PARAGRAPH_REMOVE:
removeParagraph(conn, messagereceived);
break;
case PARAGRAPH_CLEAR_OUTPUT:
clearParagraphOutput(conn, messagereceived);
break;
case PARAGRAPH_CLEAR_ALL_OUTPUT:
clearAllParagraphOutput(conn, messagereceived);
break;
case NOTE_UPDATE:
updateNote(conn, messagereceived);
break;
case NOTE_RENAME:
renameNote(conn, messagereceived);
break;
case FOLDER_RENAME:
renameFolder(conn, messagereceived);
break;
case UPDATE_PERSONALIZED_MODE:
updatePersonalizedMode(conn, messagereceived);
break;
case COMPLETION:
completion(conn, messagereceived);
break;
case PING:
break; //do nothing
case ANGULAR_OBJECT_UPDATED:
angularObjectUpdated(conn, messagereceived);
break;
case ANGULAR_OBJECT_CLIENT_BIND:
angularObjectClientBind(conn, messagereceived);
break;
case ANGULAR_OBJECT_CLIENT_UNBIND:
angularObjectClientUnbind(conn, messagereceived);
break;
case LIST_CONFIGURATIONS:
sendAllConfigurations(conn, messagereceived);
break;
case CHECKPOINT_NOTE:
checkpointNote(conn, messagereceived);
break;
case LIST_REVISION_HISTORY:
listRevisionHistory(conn, messagereceived);
break;
case SET_NOTE_REVISION:
setNoteRevision(conn, messagereceived);
break;
case NOTE_REVISION:
getNoteByRevision(conn, messagereceived);
break;
case NOTE_REVISION_FOR_COMPARE:
getNoteByRevisionForCompare(conn, messagereceived);
break;
case LIST_NOTE_JOBS:
unicastNoteJobInfo(conn, messagereceived);
break;
case UNSUBSCRIBE_UPDATE_NOTE_JOBS:
unsubscribeNoteJobInfo(conn);
break;
case GET_INTERPRETER_BINDINGS:
getInterpreterBindings(conn, messagereceived);
break;
case SAVE_INTERPRETER_BINDINGS:
saveInterpreterBindings(conn, messagereceived);
break;
case EDITOR_SETTING:
getEditorSetting(conn, messagereceived);
break;
case GET_INTERPRETER_SETTINGS:
getInterpreterSettings(conn, messagereceived);
break;
case WATCHER:
getConnectionManager().switchConnectionToWatcher(conn);
break;
case SAVE_NOTE_FORMS:
saveNoteForms(conn, messagereceived);
break;
case REMOVE_NOTE_FORMS:
removeNoteForms(conn, messagereceived);
break;
case PATCH_PARAGRAPH:
patchParagraph(conn, messagereceived);
break;
default:
break;
}
} catch (Exception e) {
LOG.error("Can't handle message: " + msg, e);
try {
conn.send(serializeMessage(new Message(OP.ERROR_INFO).put("info", e.getMessage())));
} catch (IOException iox) {
LOG.error("Fail to send error info", iox);
}
}
}
@Override
public void onClose(NotebookSocket conn, int code, String reason) {
LOG.info("Closed connection to {} ({}) {}", conn, code, reason);
getConnectionManager().removeConnection(conn);
getConnectionManager().removeConnectionFromAllNote(conn);
getConnectionManager().removeUserConnection(conn.getUser(), conn);
}
protected Message deserializeMessage(String msg) {
return gson.fromJson(msg, Message.class);
}
protected String serializeMessage(Message m) {
return gson.toJson(m);
}
public void broadcast(Message m) {
getConnectionManager().broadcast(m);
}
public void unicastNoteJobInfo(NotebookSocket conn, Message fromMessage) throws IOException {
getConnectionManager().addNoteConnection(JobManagerServiceType.JOB_MANAGER_PAGE.getKey(), conn);
getJobManagerService().getNoteJobInfoByUnixTime(0, getServiceContext(fromMessage),
new WebSocketServiceCallback>(conn) {
@Override
public void onSuccess(List notesJobInfo,
ServiceContext context) throws IOException {
super.onSuccess(notesJobInfo, context);
Map response = new HashMap<>();
response.put("lastResponseUnixTime", System.currentTimeMillis());
response.put("jobs", notesJobInfo);
conn.send(serializeMessage(new Message(OP.LIST_NOTE_JOBS).put("noteJobs", response)));
}
@Override
public void onFailure(Exception ex, ServiceContext context) throws IOException {
LOG.warn(ex.getMessage());
}
});
}
public void broadcastUpdateNoteJobInfo(Note note, long lastUpdateUnixTime) throws IOException {
ServiceContext context = new ServiceContext(new AuthenticationInfo(),
getNotebookAuthorizationService().getOwners(note.getId()));
getJobManagerService().getNoteJobInfoByUnixTime(lastUpdateUnixTime, context,
new WebSocketServiceCallback>(null) {
@Override
public void onSuccess(List notesJobInfo,
ServiceContext context) throws IOException {
super.onSuccess(notesJobInfo, context);
Map response = new HashMap<>();
response.put("lastResponseUnixTime", System.currentTimeMillis());
response.put("jobs", notesJobInfo);
getConnectionManager().broadcast(JobManagerServiceType.JOB_MANAGER_PAGE.getKey(),
new Message(OP.LIST_UPDATE_NOTE_JOBS).put("noteRunningJobs", response));
}
@Override
public void onFailure(Exception ex, ServiceContext context) throws IOException {
LOG.warn(ex.getMessage());
}
});
}
public void unsubscribeNoteJobInfo(NotebookSocket conn) {
getConnectionManager().removeNoteConnection(JobManagerServiceType.JOB_MANAGER_PAGE.getKey(), conn);
}
public void getInterpreterBindings(NotebookSocket conn, Message fromMessage) throws IOException {
List settingList = new ArrayList<>();
ServiceContext context = getServiceContext(fromMessage);
String noteId = (String) fromMessage.data.get("noteId");
Note note = getNotebook().getNote(noteId);
if (note != null) {
List bindedSettings =
note.getBindedInterpreterSettings(new ArrayList<>(context.getUserAndRoles()));
for (InterpreterSetting setting : bindedSettings) {
settingList.add(new InterpreterSettingsList(setting.getId(), setting.getName(),
setting.getInterpreterInfos(), true));
}
}
conn.send(serializeMessage(
new Message(OP.INTERPRETER_BINDINGS).put("interpreterBindings", settingList)));
}
public void saveInterpreterBindings(NotebookSocket conn, Message fromMessage) throws IOException {
List settingList = new ArrayList<>();
String noteId = (String) fromMessage.data.get("noteId");
ServiceContext context = getServiceContext(fromMessage);
Note note = getNotebook().getNote(noteId);
if (note != null) {
List settingIdList =
gson.fromJson(String.valueOf(fromMessage.data.get("selectedSettingIds")),
new TypeToken>() {}.getType());
if (!settingIdList.isEmpty()) {
note.setDefaultInterpreterGroup(settingIdList.get(0));
getNotebook().saveNote(note,
new AuthenticationInfo(fromMessage.principal, fromMessage.roles, fromMessage.ticket));
}
List bindedSettings =
note.getBindedInterpreterSettings(new ArrayList<>(context.getUserAndRoles()));
for (InterpreterSetting setting : bindedSettings) {
settingList.add(new InterpreterSettingsList(setting.getId(), setting.getName(),
setting.getInterpreterInfos(), true));
}
}
conn.send(serializeMessage(
new Message(OP.INTERPRETER_BINDINGS).put("interpreterBindings", settingList)));
}
public void broadcastNote(Note note) {
inlineBroadcastNote(note);
broadcastClusterEvent(ClusterEvent.BROADCAST_NOTE, MSG_ID_NOT_DEFINED, note);
}
private void inlineBroadcastNote(Note note) {
Message message = new Message(OP.NOTE).put("note", note);
getConnectionManager().broadcast(note.getId(), message);
}
private void inlineBroadcastParagraph(Note note, Paragraph p, String msgId) {
broadcastNoteForms(note);
if (note.isPersonalizedMode()) {
broadcastParagraphs(p.getUserParagraphMap(), p, msgId);
} else {
Message message = new Message(OP.PARAGRAPH).withMsgId(msgId).put("paragraph", p);
getConnectionManager().broadcast(note.getId(), message);
}
}
public void broadcastParagraph(Note note, Paragraph p, String msgId) {
inlineBroadcastParagraph(note, p, msgId);
broadcastClusterEvent(ClusterEvent.BROADCAST_PARAGRAPH, msgId, note, p);
}
private void inlineBroadcastParagraphs(Map userParagraphMap,
Paragraph defaultParagraph,
String msgId) {
if (null != userParagraphMap) {
for (String user : userParagraphMap.keySet()) {
Message message = new Message(OP.PARAGRAPH).withMsgId(msgId).put("paragraph", userParagraphMap.get(user));
getConnectionManager().multicastToUser(user, message);
}
}
}
private void broadcastParagraphs(Map userParagraphMap,
Paragraph defaultParagraph,
String msgId) {
inlineBroadcastParagraphs(userParagraphMap, defaultParagraph, msgId);
broadcastClusterEvent(ClusterEvent.BROADCAST_PARAGRAPHS, msgId, userParagraphMap, defaultParagraph);
}
private void inlineBroadcastNewParagraph(Note note, Paragraph para) {
LOG.info("Broadcasting paragraph on run call instead of note.");
int paraIndex = note.getParagraphs().indexOf(para);
Message message = new Message(OP.PARAGRAPH_ADDED).put("paragraph", para).put("index", paraIndex);
getConnectionManager().broadcast(note.getId(), message);
}
private void broadcastNewParagraph(Note note, Paragraph para) {
inlineBroadcastNewParagraph(note, para);
broadcastClusterEvent(ClusterEvent.BROADCAST_NEW_PARAGRAPH, MSG_ID_NOT_DEFINED, note, para);
}
public void inlineBroadcastNoteList(AuthenticationInfo subject, Set userAndRoles) {
broadcastNoteListUpdate();
}
public void broadcastNoteListUpdate() {
AuthorizationService authorizationService = getNotebookAuthorizationService();
getConnectionManager().forAllUsers(new UserIterator() {
@Override
public void handleUser(String user, Set userAndRoles) {
List notesInfo = getNotebook().getNotesInfo(
noteId -> authorizationService.isReader(noteId, userAndRoles));
getConnectionManager().multicastToUser(user,
new Message(OP.NOTES_INFO).put("notes", notesInfo));
}
});
}
public void broadcastNoteList(AuthenticationInfo subject, Set userAndRoles) {
inlineBroadcastNoteList(subject, userAndRoles);
broadcastClusterEvent(ClusterEvent.BROADCAST_NOTE_LIST, MSG_ID_NOT_DEFINED, subject, userAndRoles);
}
// broadcast ClusterEvent
private void broadcastClusterEvent(ClusterEvent event, String msgId, Object... objects) {
ZeppelinConfiguration conf = ZeppelinConfiguration.create();
if (!conf.isClusterMode()) {
return;
}
ClusterMessage clusterMessage = new ClusterMessage(event);
clusterMessage.setMsgId(msgId);
for(Object object : objects) {
String json = "";
if (object instanceof AuthenticationInfo) {
json = ((AuthenticationInfo) object).toJson();
clusterMessage.put("AuthenticationInfo", json);
} else if (object instanceof Note) {
json = ((Note) object).toJson();
clusterMessage.put("Note", json);
} else if (object instanceof Paragraph) {
json = ((Paragraph) object).toJson();
clusterMessage.put("Paragraph", json);
} else if (object instanceof Set) {
Gson gson = new Gson();
json = gson.toJson(object);
clusterMessage.put("Set", json);
} else if (object instanceof Map) {
Gson gson = new Gson();
json = gson.toJson(object);
clusterMessage.put("Map", json);
} else {
LOG.error("Unknown object type!");
}
}
String msg = ClusterMessage.serializeMessage(clusterMessage);
ClusterManagerServer.getInstance(conf).broadcastClusterEvent(
ClusterManagerServer.CLUSTER_NOTE_EVENT_TOPIC, msg);
}
@Override
public void onClusterEvent(String msg) {
if (LOG.isDebugEnabled()) {
LOG.debug("onClusterEvent : {}", msg);
}
ClusterMessage message = ClusterMessage.deserializeMessage(msg);
Note note = null;
Paragraph paragraph = null;
Set userAndRoles = null;
Map userParagraphMap = null;
AuthenticationInfo authenticationInfo = null;
for (Map.Entry entry : message.getData().entrySet()) {
String key = entry.getKey();
String json = entry.getValue();
if (StringUtils.equals(key, "AuthenticationInfo")) {
authenticationInfo = AuthenticationInfo.fromJson(json);
} else if (StringUtils.equals(key, "Note")) {
try {
note = Note.fromJson(json);
} catch (IOException e) {
LOG.warn("Fail to parse note json", e);
}
} else if (StringUtils.equals(key, "Paragraph")) {
paragraph = Paragraph.fromJson(json);
} else if (StringUtils.equals(key, "Set")) {
Gson gson = new Gson();
userAndRoles = gson.fromJson(json, new TypeToken>() {
}.getType());
} else if (StringUtils.equals(key, "Map")) {
Gson gson = new Gson();
userParagraphMap = gson.fromJson(json, new TypeToken>() {
}.getType());
} else {
LOG.error("Unknown key:{}, json:{}!" + key, json);
}
}
switch (message.clusterEvent) {
case BROADCAST_NOTE:
inlineBroadcastNote(note);
break;
case BROADCAST_NOTE_LIST:
try {
getNotebook().reloadAllNotes(authenticationInfo);
inlineBroadcastNoteList(authenticationInfo, userAndRoles);
} catch (IOException e) {
LOG.error(e.getMessage(), e);
}
break;
case BROADCAST_PARAGRAPH:
inlineBroadcastParagraph(note, paragraph, message.getMsgId());
break;
case BROADCAST_PARAGRAPHS:
inlineBroadcastParagraphs(userParagraphMap, paragraph, message.getMsgId());
break;
case BROADCAST_NEW_PARAGRAPH:
inlineBroadcastNewParagraph(note, paragraph);
break;
default:
LOG.error("Unknown clusterEvent:{}, msg:{} ", message.clusterEvent, msg);
break;
}
}
public void listNotesInfo(NotebookSocket conn, Message message) throws IOException {
getNotebookService().listNotesInfo(false, getServiceContext(message),
new WebSocketServiceCallback>(conn) {
@Override
public void onSuccess(List notesInfo,
ServiceContext context) throws IOException {
super.onSuccess(notesInfo, context);
getConnectionManager().unicast(new Message(OP.NOTES_INFO).put("notes", notesInfo), conn);
}
});
}
public void broadcastReloadedNoteList(NotebookSocket conn, ServiceContext context)
throws IOException {
broadcastNoteListUpdate();
}
void permissionError(NotebookSocket conn, String op, String userName, Set userAndRoles,
Set allowed) throws IOException {
LOG.info("Cannot {}. Connection readers {}. Allowed readers {}", op, userAndRoles, allowed);
conn.send(serializeMessage(new Message(OP.AUTH_INFO).put("info",
"Insufficient privileges to " + op + " note.\n\n" + "Allowed users or roles: " + allowed
.toString() + "\n\n" + "But the user " + userName + " belongs to: " + userAndRoles
.toString())));
}
/**
* @return false if user doesn't have writer permission for this paragraph
*/
private boolean hasParagraphWriterPermission(NotebookSocket conn, Notebook notebook,
String noteId, Set userAndRoles,
String principal, String op)
throws IOException {
AuthorizationService authorizationService =
getNotebookAuthorizationService();
if (!authorizationService.isWriter(noteId, userAndRoles)) {
permissionError(conn, op, principal, userAndRoles,
authorizationService.getOwners(noteId));
return false;
}
return true;
}
private void getNote(NotebookSocket conn, Message fromMessage) throws IOException {
String noteId = (String) fromMessage.get("id");
if (noteId == null) {
return;
}
getNotebookService().getNote(noteId, getServiceContext(fromMessage),
new WebSocketServiceCallback(conn) {
@Override
public void onSuccess(Note note, ServiceContext context) throws IOException {
getConnectionManager().addNoteConnection(note.getId(), conn);
conn.send(serializeMessage(new Message(OP.NOTE).put("note", note)));
updateAngularObjectRegistry(conn, note);
sendAllAngularObjects(note, context.getAutheInfo().getUser(), conn);
}
});
}
/**
* Update the AngularObject object in the note to InterpreterGroup and AngularObjectRegistry.
*/
private void updateAngularObjectRegistry(NotebookSocket conn, Note note) {
for(Paragraph paragraph : note.getParagraphs()) {
InterpreterGroup interpreterGroup = null;
try {
interpreterGroup = findInterpreterGroupForParagraph(note, paragraph.getId());
} catch (Exception e) {
LOG.warn(e.getMessage(), e);
}
if (null == interpreterGroup) {
return;
}
RemoteAngularObjectRegistry registry = (RemoteAngularObjectRegistry)
interpreterGroup.getAngularObjectRegistry();
List angularObjects = note.getAngularObjects(interpreterGroup.getId());
for (AngularObject ao : angularObjects) {
if (StringUtils.equals(ao.getNoteId(), note.getId())
&& StringUtils.equals(ao.getParagraphId(), paragraph.getId())) {
pushAngularObjectToRemoteRegistry(ao.getNoteId(), ao.getParagraphId(),
ao.getName(), ao.get(), registry, interpreterGroup.getId(), conn);
}
}
}
}
private void getHomeNote(NotebookSocket conn,
Message fromMessage) throws IOException {
getNotebookService().getHomeNote(getServiceContext(fromMessage),
new WebSocketServiceCallback(conn) {
@Override
public void onSuccess(Note note, ServiceContext context) throws IOException {
super.onSuccess(note, context);
if (note != null) {
getConnectionManager().addNoteConnection(note.getId(), conn);
conn.send(serializeMessage(new Message(OP.NOTE).put("note", note)));
sendAllAngularObjects(note, context.getAutheInfo().getUser(), conn);
} else {
getConnectionManager().removeConnectionFromAllNote(conn);
conn.send(serializeMessage(new Message(OP.NOTE).put("note", null)));
}
}
});
}
private void updateNote(NotebookSocket conn,
Message fromMessage) throws IOException {
String noteId = (String) fromMessage.get("id");
String name = (String) fromMessage.get("name");
Map config = (Map) fromMessage.get("config");
if (noteId == null) {
return;
}
if (config == null) {
return;
}
getNotebookService().updateNote(noteId, name, config, getServiceContext(fromMessage),
new WebSocketServiceCallback(conn) {
@Override
public void onSuccess(Note note, ServiceContext context) throws IOException {
getConnectionManager().broadcast(note.getId(), new Message(OP.NOTE_UPDATED).put("name", name)
.put("config", config)
.put("info", note.getInfo()));
broadcastNoteList(context.getAutheInfo(), context.getUserAndRoles());
}
});
}
private void updatePersonalizedMode(NotebookSocket conn,
Message fromMessage) throws IOException {
String noteId = (String) fromMessage.get("id");
String personalized = (String) fromMessage.get("personalized");
boolean isPersonalized = personalized.equals("true") ? true : false;
getNotebookService().updatePersonalizedMode(noteId, isPersonalized,
getServiceContext(fromMessage), new WebSocketServiceCallback(conn) {
@Override
public void onSuccess(Note note, ServiceContext context) throws IOException {
super.onSuccess(note, context);
getConnectionManager().broadcastNote(note);
}
});
}
private void renameNote(NotebookSocket conn,
Message fromMessage) throws IOException {
String noteId = (String) fromMessage.get("id");
String name = (String) fromMessage.get("name");
boolean isRelativePath = false;
if (fromMessage.get("relative") != null) {
isRelativePath = (boolean) fromMessage.get("relative");
}
if (noteId == null) {
return;
}
getNotebookService().renameNote(noteId, name, isRelativePath, getServiceContext(fromMessage),
new WebSocketServiceCallback(conn) {
@Override
public void onSuccess(Note note, ServiceContext context) throws IOException {
super.onSuccess(note, context);
broadcastNote(note);
broadcastNoteList(context.getAutheInfo(), context.getUserAndRoles());
}
});
}
private void renameFolder(NotebookSocket conn,
Message fromMessage) throws IOException {
String oldFolderId = (String) fromMessage.get("id");
String newFolderId = (String) fromMessage.get("name");
getNotebookService().renameFolder(oldFolderId, newFolderId, getServiceContext(fromMessage),
new WebSocketServiceCallback>(conn) {
@Override
public void onSuccess(List result, ServiceContext context) throws IOException {
super.onSuccess(result, context);
broadcastNoteList(context.getAutheInfo(), context.getUserAndRoles());
}
});
}
private void createNote(NotebookSocket conn,
Message message) throws IOException {
String noteName = (String) message.get("name");
String defaultInterpreterGroup = (String) message.get("defaultInterpreterGroup");
getNotebookService().createNote(noteName, defaultInterpreterGroup, true, getServiceContext(message),
new WebSocketServiceCallback(conn) {
@Override
public void onSuccess(Note note, ServiceContext context) throws IOException {
super.onSuccess(note, context);
getConnectionManager().addNoteConnection(note.getId(), conn);
conn.send(serializeMessage(new Message(OP.NEW_NOTE).put("note", note)));
broadcastNoteList(context.getAutheInfo(), context.getUserAndRoles());
}
@Override
public void onFailure(Exception ex, ServiceContext context) throws IOException {
super.onFailure(ex, context);
conn.send(serializeMessage(new Message(OP.ERROR_INFO).put("info",
"Failed to create note.\n" + ExceptionUtils.getMessage(ex))));
}
});
}
private void deleteNote(NotebookSocket conn,
Message fromMessage) throws IOException {
String noteId = (String) fromMessage.get("id");
getNotebookService().removeNote(noteId, getServiceContext(fromMessage),
new WebSocketServiceCallback(conn) {
@Override
public void onSuccess(String message, ServiceContext context) throws IOException {
super.onSuccess(message, context);
getConnectionManager().removeNoteConnection(noteId);
broadcastNoteList(context.getAutheInfo(), context.getUserAndRoles());
}
});
}
private void removeFolder(NotebookSocket conn,
Message fromMessage) throws IOException {
String folderPath = (String) fromMessage.get("id");
folderPath = "/" + folderPath;
getNotebookService().removeFolder(folderPath, getServiceContext(fromMessage),
new WebSocketServiceCallback>(conn) {
@Override
public void onSuccess(List notesInfo,
ServiceContext context) throws IOException {
super.onSuccess(notesInfo, context);
for (NoteInfo noteInfo : notesInfo) {
getConnectionManager().removeNoteConnection(noteInfo.getId());
}
broadcastNoteList(context.getAutheInfo(), context.getUserAndRoles());
}
});
}
private void moveNoteToTrash(NotebookSocket conn,
Message fromMessage) throws IOException {
String noteId = (String) fromMessage.get("id");
getNotebookService().moveNoteToTrash(noteId, getServiceContext(fromMessage),
new WebSocketServiceCallback(conn) {
@Override
public void onSuccess(Note note, ServiceContext context) throws IOException {
super.onSuccess(note, context);
broadcastNote(note);
broadcastNoteList(context.getAutheInfo(), context.getUserAndRoles());
}
});
}
private void moveFolderToTrash(NotebookSocket conn,
Message fromMessage)
throws IOException {
String folderPath = (String) fromMessage.get("id");
getNotebookService().moveFolderToTrash(folderPath, getServiceContext(fromMessage),
new WebSocketServiceCallback(conn) {
@Override
public void onSuccess(Void result, ServiceContext context) throws IOException {
super.onSuccess(result, context);
broadcastNoteList(context.getAutheInfo(), context.getUserAndRoles());
}
});
}
private void restoreNote(NotebookSocket conn,
Message fromMessage) throws IOException {
String noteId = (String) fromMessage.get("id");
getNotebookService().restoreNote(noteId, getServiceContext(fromMessage),
new WebSocketServiceCallback(conn) {
@Override
public void onSuccess(Note note, ServiceContext context) throws IOException {
super.onSuccess(note, context);
broadcastNote(note);
broadcastNoteList(context.getAutheInfo(), context.getUserAndRoles());
}
});
}
private void restoreFolder(NotebookSocket conn,
Message fromMessage) throws IOException {
String folderPath = (String) fromMessage.get("id");
folderPath = "/" + folderPath;
getNotebookService().restoreFolder(folderPath, getServiceContext(fromMessage),
new WebSocketServiceCallback(conn) {
@Override
public void onSuccess(Object result, ServiceContext context) throws IOException {
super.onSuccess(result, context);
broadcastNoteList(context.getAutheInfo(), context.getUserAndRoles());
}
});
}
private void restoreAll(NotebookSocket conn,
Message fromMessage) throws IOException {
getNotebookService().restoreAll(getServiceContext(fromMessage),
new WebSocketServiceCallback(conn) {
@Override
public void onSuccess(Object result, ServiceContext context) throws IOException {
super.onSuccess(result, context);
broadcastNoteList(context.getAutheInfo(), context.getUserAndRoles());
}
});
}
private void emptyTrash(NotebookSocket conn,
Message fromMessage) throws IOException {
getNotebookService().emptyTrash(getServiceContext(fromMessage),
new WebSocketServiceCallback(conn) {
@Override
public void onSuccess(Object result, ServiceContext context) throws IOException {
super.onSuccess(result, context);
broadcastNoteList(context.getAutheInfo(), context.getUserAndRoles());
}
});
}
private void updateParagraph(NotebookSocket conn,
Message fromMessage) throws IOException {
String paragraphId = (String) fromMessage.get("id");
String noteId = getConnectionManager().getAssociatedNoteId(conn);
if (noteId == null) {
noteId = (String) fromMessage.get("noteId");
}
String title = (String) fromMessage.get("title");
String text = (String) fromMessage.get("paragraph");
Map params = (Map) fromMessage.get("params");
Map config = (Map) fromMessage.get("config");
getNotebookService().updateParagraph(noteId, paragraphId, title, text, params, config,
getServiceContext(fromMessage),
new WebSocketServiceCallback(conn) {
@Override
public void onSuccess(Paragraph p, ServiceContext context) throws IOException {
super.onSuccess(p, context);
if (p.getNote().isPersonalizedMode()) {
Map userParagraphMap =
p.getNote().getParagraph(paragraphId).getUserParagraphMap();
broadcastParagraphs(userParagraphMap, p, fromMessage.msgId);
} else {
broadcastParagraph(p.getNote(), p, fromMessage.msgId);
}
}
});
}
private void patchParagraph(NotebookSocket conn,
Message fromMessage) throws IOException {
if (!collaborativeModeEnable) {
return;
}
String paragraphId = fromMessage.getType("id", LOG);
if (paragraphId == null) {
return;
}
String noteId = getConnectionManager().getAssociatedNoteId(conn);
if (noteId == null) {
noteId = fromMessage.getType("noteId", LOG);
if (noteId == null) {
return;
}
}
final String noteId2 = noteId;
String patchText = fromMessage.getType("patch", LOG);
if (patchText == null) {
return;
}
getNotebookService().patchParagraph(noteId, paragraphId, patchText,
getServiceContext(fromMessage),
new WebSocketServiceCallback(conn) {
@Override
public void onSuccess(String result, ServiceContext context) throws IOException {
super.onSuccess(result, context);
Message message = new Message(OP.PATCH_PARAGRAPH).put("patch", result)
.put("paragraphId", paragraphId);
getConnectionManager().broadcastExcept(noteId2, message, conn);
}
});
}
private void cloneNote(NotebookSocket conn,
Message fromMessage) throws IOException {
String noteId = getConnectionManager().getAssociatedNoteId(conn);
String name = (String) fromMessage.get("name");
getNotebookService().cloneNote(noteId, name, getServiceContext(fromMessage),
new WebSocketServiceCallback(conn) {
@Override
public void onSuccess(Note newNote, ServiceContext context) throws IOException {
super.onSuccess(newNote, context);
getConnectionManager().addNoteConnection(newNote.getId(), conn);
conn.send(serializeMessage(new Message(OP.NEW_NOTE).put("note", newNote)));
broadcastNoteList(context.getAutheInfo(), context.getUserAndRoles());
}
});
}
private void clearAllParagraphOutput(NotebookSocket conn,
Message fromMessage) throws IOException {
final String noteId = (String) fromMessage.get("id");
getNotebookService().clearAllParagraphOutput(noteId, getServiceContext(fromMessage),
new WebSocketServiceCallback(conn) {
@Override
public void onSuccess(Note note, ServiceContext context) throws IOException {
super.onSuccess(note, context);
broadcastNote(note);
}
});
}
protected void convertNote(NotebookSocket conn, Message fromMessage) throws IOException {
String noteId = fromMessage.get("noteId").toString();
Note note = getNotebook().getNote(noteId);
if (note == null) {
throw new IOException("No such note: " + noteId);
} else {
Message resp = new Message(OP.CONVERTED_NOTE_NBFORMAT)
.put("nbformat", new JupyterUtil().getNbformat(note.toJson()))
.put("noteName", fromMessage.get("noteName"));
conn.send(serializeMessage(resp));
}
}
protected Note importNote(NotebookSocket conn, Message fromMessage) throws IOException {
String noteJson = null;
String noteName = (String) ((Map) fromMessage.get("note")).get("name");
// Checking whether the notebook data is from a Jupyter or a Zeppelin Notebook.
// Jupyter notebooks have paragraphs under the "cells" label.
if (((Map) fromMessage.get("note")).get("cells") == null) {
noteJson = gson.toJson(fromMessage.get("note"));
} else {
noteJson = new JupyterUtil().getJson(
gson.toJson(fromMessage.get("note")), IdHashes.generateId(), "%python", "%md");
}
Note note = getNotebookService().importNote(noteName, noteJson, getServiceContext(fromMessage),
new WebSocketServiceCallback(conn) {
@Override
public void onSuccess(Note note, ServiceContext context) throws IOException {
super.onSuccess(note, context);
try {
broadcastNote(note);
broadcastNoteList(context.getAutheInfo(), context.getUserAndRoles());
} catch (NullPointerException e) {
// TODO(zjffdu) remove this try catch. This is only for test of
// NotebookServerTest#testImportNotebook
}
}
});
return note;
}
private void removeParagraph(NotebookSocket conn,
Message fromMessage) throws IOException {
final String paragraphId = (String) fromMessage.get("id");
String noteId = getConnectionManager().getAssociatedNoteId(conn);
getNotebookService().removeParagraph(noteId, paragraphId,
getServiceContext(fromMessage), new WebSocketServiceCallback(conn) {
@Override
public void onSuccess(Paragraph p, ServiceContext context) throws IOException {
super.onSuccess(p, context);
getConnectionManager().broadcast(p.getNote().getId(), new Message(OP.PARAGRAPH_REMOVED).
put("id", p.getId()));
}
});
}
private void clearParagraphOutput(NotebookSocket conn,
Message fromMessage) throws IOException {
final String paragraphId = (String) fromMessage.get("id");
String noteId = getConnectionManager().getAssociatedNoteId(conn);
getNotebookService().clearParagraphOutput(noteId, paragraphId, getServiceContext(fromMessage),
new WebSocketServiceCallback(conn) {
@Override
public void onSuccess(Paragraph p, ServiceContext context) throws IOException {
super.onSuccess(p, context);
if (p.getNote().isPersonalizedMode()) {
getConnectionManager().unicastParagraph(p.getNote(), p, context.getAutheInfo().getUser(), fromMessage.msgId);
} else {
broadcastParagraph(p.getNote(), p, fromMessage.msgId);
}
}
});
}
private void completion(NotebookSocket conn,
Message fromMessage) throws IOException {
String noteId = getConnectionManager().getAssociatedNoteId(conn);
String paragraphId = (String) fromMessage.get("id");
String buffer = (String) fromMessage.get("buf");
int cursor = (int) Double.parseDouble(fromMessage.get("cursor").toString());
getNotebookService().completion(noteId, paragraphId, buffer, cursor,
getServiceContext(fromMessage),
new WebSocketServiceCallback>(conn) {
@Override
public void onSuccess(List completions, ServiceContext context)
throws IOException {
super.onSuccess(completions, context);
Message resp = new Message(OP.COMPLETION_LIST).put("id", paragraphId);
resp.put("completions", completions);
conn.send(serializeMessage(resp));
}
@Override
public void onFailure(Exception ex, ServiceContext context) throws IOException {
super.onFailure(ex, context);
Message resp = new Message(OP.COMPLETION_LIST).put("id", paragraphId);
resp.put("completions", new ArrayList<>());
conn.send(serializeMessage(resp));
}
});
}
/**
* 1. When angular object updated from client.
* 2. Save AngularObject to note.
*
* @param conn the web socket.
* @param fromMessage the message.
*/
private void angularObjectUpdated(NotebookSocket conn,
Message fromMessage) throws IOException {
String noteId = (String) fromMessage.get("noteId");
String paragraphId = (String) fromMessage.get("paragraphId");
String interpreterGroupId = (String) fromMessage.get("interpreterGroupId");
String varName = (String) fromMessage.get("name");
Object varValue = fromMessage.get("value");
String user = fromMessage.principal;
getNotebookService().updateAngularObject(noteId, paragraphId, interpreterGroupId,
varName, varValue, getServiceContext(fromMessage),
new WebSocketServiceCallback(conn) {
@Override
public void onSuccess(AngularObject ao, ServiceContext context) throws IOException {
super.onSuccess(ao, context);
getConnectionManager().broadcastExcept(noteId,
new Message(OP.ANGULAR_OBJECT_UPDATE).put("angularObject", ao)
.put("interpreterGroupId", interpreterGroupId).put("noteId", noteId)
.put("paragraphId", ao.getParagraphId()), conn);
Note note = getNotebook().getNote(noteId);
note.addOrUpdateAngularObject(interpreterGroupId, ao);
}
});
}
/**
* 1. Push the given Angular variable to the target interpreter angular
* registry given a noteId and a paragraph id.
* 2. Save AngularObject to note.
*/
protected void angularObjectClientBind(NotebookSocket conn,
Message fromMessage) throws Exception {
String noteId = fromMessage.getType("noteId");
String varName = fromMessage.getType("name");
Object varValue = fromMessage.get("value");
String paragraphId = fromMessage.getType("paragraphId");
Note note = getNotebook().getNote(noteId);
if (paragraphId == null) {
throw new IllegalArgumentException(
"target paragraph not specified for " + "angular value bind");
}
if (note != null) {
final InterpreterGroup interpreterGroup = findInterpreterGroupForParagraph(note, paragraphId);
final RemoteAngularObjectRegistry registry = (RemoteAngularObjectRegistry)
interpreterGroup.getAngularObjectRegistry();
AngularObject ao = pushAngularObjectToRemoteRegistry(noteId, paragraphId, varName, varValue, registry,
interpreterGroup.getId(), conn);
note.addOrUpdateAngularObject(interpreterGroup.getId(), ao);
}
}
/**
* 1. Remove the given Angular variable to the target interpreter(s) angular
* registry given a noteId and an optional list of paragraph id(s).
* 2. Delete AngularObject from note.
*/
protected void angularObjectClientUnbind(NotebookSocket conn,
Message fromMessage) throws Exception {
String noteId = fromMessage.getType("noteId");
String varName = fromMessage.getType("name");
String paragraphId = fromMessage.getType("paragraphId");
Note note = getNotebook().getNote(noteId);
if (paragraphId == null) {
throw new IllegalArgumentException(
"target paragraph not specified for " + "angular value unBind");
}
if (note != null) {
final InterpreterGroup interpreterGroup = findInterpreterGroupForParagraph(note, paragraphId);
final RemoteAngularObjectRegistry registry = (RemoteAngularObjectRegistry)
interpreterGroup.getAngularObjectRegistry();
AngularObject ao = removeAngularFromRemoteRegistry(noteId, paragraphId, varName, registry,
interpreterGroup.getId(), conn);
note.deleteAngularObject(interpreterGroup.getId(), noteId, paragraphId, varName);
}
}
private InterpreterGroup findInterpreterGroupForParagraph(Note note, String paragraphId)
throws Exception {
final Paragraph paragraph = note.getParagraph(paragraphId);
if (paragraph == null) {
throw new IllegalArgumentException("Unknown paragraph with id : " + paragraphId);
}
return paragraph.getBindedInterpreter().getInterpreterGroup();
}
private AngularObject pushAngularObjectToRemoteRegistry(String noteId, String paragraphId, String varName,
Object varValue,
RemoteAngularObjectRegistry remoteRegistry,
String interpreterGroupId,
NotebookSocket conn) {
final AngularObject ao =
remoteRegistry.addAndNotifyRemoteProcess(varName, varValue, noteId, paragraphId);
getConnectionManager().broadcastExcept(noteId, new Message(OP.ANGULAR_OBJECT_UPDATE)
.put("angularObject", ao)
.put("interpreterGroupId", interpreterGroupId).put("noteId", noteId)
.put("paragraphId", paragraphId), conn);
return ao;
}
private AngularObject removeAngularFromRemoteRegistry(String noteId, String paragraphId, String varName,
RemoteAngularObjectRegistry remoteRegistry,
String interpreterGroupId,
NotebookSocket conn) {
final AngularObject ao =
remoteRegistry.removeAndNotifyRemoteProcess(varName, noteId, paragraphId);
getConnectionManager().broadcastExcept(noteId, new Message(OP.ANGULAR_OBJECT_REMOVE)
.put("angularObject", ao)
.put("interpreterGroupId", interpreterGroupId).put("noteId", noteId)
.put("paragraphId", paragraphId), conn);
return ao;
}
private void moveParagraph(NotebookSocket conn,
Message fromMessage) throws IOException {
final String paragraphId = (String) fromMessage.get("id");
final int newIndex = (int) Double.parseDouble(fromMessage.get("index").toString());
String noteId = getConnectionManager().getAssociatedNoteId(conn);
getNotebookService().moveParagraph(noteId, paragraphId, newIndex,
getServiceContext(fromMessage),
new WebSocketServiceCallback(conn) {
@Override
public void onSuccess(Paragraph result, ServiceContext context) throws IOException {
super.onSuccess(result, context);
getConnectionManager().broadcast(result.getNote().getId(),
new Message(OP.PARAGRAPH_MOVED).put("id", paragraphId).put("index", newIndex));
}
});
}
private String insertParagraph(NotebookSocket conn,
Message fromMessage) throws IOException {
final int index = (int) Double.parseDouble(fromMessage.get("index").toString());
String noteId = getConnectionManager().getAssociatedNoteId(conn);
Map config;
if (fromMessage.get("config") != null) {
config = (Map) fromMessage.get("config");
} else {
config = new HashMap<>();
}
Paragraph newPara = getNotebookService().insertParagraph(noteId, index, config,
getServiceContext(fromMessage),
new WebSocketServiceCallback(conn) {
@Override
public void onSuccess(Paragraph p, ServiceContext context) throws IOException {
super.onSuccess(p, context);
broadcastNewParagraph(p.getNote(), p);
}
});
return newPara.getId();
}
private void copyParagraph(NotebookSocket conn,
Message fromMessage) throws IOException {
String newParaId = insertParagraph(conn, fromMessage);
if (newParaId == null) {
return;
}
fromMessage.put("id", newParaId);
updateParagraph(conn, fromMessage);
}
private void cancelParagraph(NotebookSocket conn, Message fromMessage) throws IOException {
final String paragraphId = (String) fromMessage.get("id");
String noteId = getConnectionManager().getAssociatedNoteId(conn);
getNotebookService().cancelParagraph(noteId, paragraphId, getServiceContext(fromMessage),
new WebSocketServiceCallback<>(conn));
}
private void runAllParagraphs(NotebookSocket conn,
Message fromMessage) throws IOException {
final String noteId = (String) fromMessage.get("noteId");
List> paragraphs =
gson.fromJson(String.valueOf(fromMessage.data.get("paragraphs")),
new TypeToken>>() {
}.getType());
if (!getNotebookService().runAllParagraphs(noteId, paragraphs, getServiceContext(fromMessage),
new WebSocketServiceCallback(conn))) {
// If one paragraph fails, we need to broadcast paragraph states to the client,
// or paragraphs not run will stay in PENDING state.
Note note = getNotebookService().getNote(noteId, getServiceContext(fromMessage), new SimpleServiceCallback());
if (note != null) {
for (Paragraph p : note.getParagraphs()) {
broadcastParagraph(note, p, null);
}
}
}
}
private void broadcastSpellExecution(NotebookSocket conn,
Message fromMessage) throws IOException {
String noteId = getConnectionManager().getAssociatedNoteId(conn);
getNotebookService().spell(noteId, fromMessage,
getServiceContext(fromMessage), new WebSocketServiceCallback(conn) {
@Override
public void onSuccess(Paragraph p, ServiceContext context) throws IOException {
super.onSuccess(p, context);
// broadcast to other clients only
getConnectionManager().broadcastExcept(p.getNote().getId(),
new Message(OP.RUN_PARAGRAPH_USING_SPELL).put("paragraph", p), conn);
}
});
}
private void runParagraph(NotebookSocket conn,
Message fromMessage) throws IOException {
String paragraphId = (String) fromMessage.get("id");
String noteId = getConnectionManager().getAssociatedNoteId(conn);
String text = (String) fromMessage.get("paragraph");
String title = (String) fromMessage.get("title");
Map params = (Map) fromMessage.get("params");
Map config = (Map) fromMessage.get("config");
getNotebookService().runParagraph(noteId, paragraphId, title, text, params, config, null,
false, false, getServiceContext(fromMessage),
new WebSocketServiceCallback(conn) {
@Override
public void onSuccess(Paragraph p, ServiceContext context) throws IOException {
super.onSuccess(p, context);
if (p.getNote().isPersonalizedMode()) {
Paragraph p2 = p.getNote().clearPersonalizedParagraphOutput(paragraphId,
context.getAutheInfo().getUser());
getConnectionManager().unicastParagraph(p.getNote(), p2, context.getAutheInfo().getUser(), fromMessage.msgId);
}
// if it's the last paragraph and not empty, let's add a new one
boolean isTheLastParagraph = p.getNote().isLastParagraph(paragraphId);
if (!(Strings.isNullOrEmpty(p.getText()) ||
Strings.isNullOrEmpty(p.getScriptText())) &&
isTheLastParagraph) {
Paragraph newPara = p.getNote().addNewParagraph(p.getAuthenticationInfo());
broadcastNewParagraph(p.getNote(), newPara);
}
}
});
}
private void sendAllConfigurations(NotebookSocket conn,
Message message) throws IOException {
getConfigurationService().getAllProperties(getServiceContext(message),
new WebSocketServiceCallback>(conn) {
@Override
public void onSuccess(Map properties,
ServiceContext context) throws IOException {
super.onSuccess(properties, context);
properties.put("isRevisionSupported", String.valueOf(getNotebook().isRevisionSupported()));
conn.send(serializeMessage(
new Message(OP.CONFIGURATIONS_INFO).put("configurations", properties)));
}
});
}
private void checkpointNote(NotebookSocket conn, Message fromMessage)
throws IOException {
String noteId = (String) fromMessage.get("noteId");
String commitMessage = (String) fromMessage.get("commitMessage");
getNotebookService().checkpointNote(noteId, commitMessage, getServiceContext(fromMessage),
new WebSocketServiceCallback(conn) {
@Override
public void onSuccess(Revision revision, ServiceContext context) throws IOException {
super.onSuccess(revision, context);
if (!Revision.isEmpty(revision)) {
List revisions =
getNotebook().listRevisionHistory(noteId, getNotebook().getNote(noteId).getPath(),
context.getAutheInfo());
conn.send(
serializeMessage(new Message(OP.LIST_REVISION_HISTORY).put("revisionList",
revisions)));
} else {
conn.send(serializeMessage(new Message(OP.ERROR_INFO).put("info",
"Couldn't checkpoint note revision: possibly no changes found or storage doesn't support versioning. "
+ "Please check the logs for more details.")));
}
}
});
}
private void listRevisionHistory(NotebookSocket conn, Message fromMessage)
throws IOException {
String noteId = (String) fromMessage.get("noteId");
getNotebookService().listRevisionHistory(noteId, getServiceContext(fromMessage),
new WebSocketServiceCallback>(conn) {
@Override
public void onSuccess(List revisions, ServiceContext context)
throws IOException {
super.onSuccess(revisions, context);
conn.send(serializeMessage(
new Message(OP.LIST_REVISION_HISTORY).put("revisionList", revisions)));
}
});
}
private void setNoteRevision(NotebookSocket conn,
Message fromMessage) throws IOException {
String noteId = (String) fromMessage.get("noteId");
String revisionId = (String) fromMessage.get("revisionId");
getNotebookService().setNoteRevision(noteId, revisionId, getServiceContext(fromMessage),
new WebSocketServiceCallback(conn) {
@Override
public void onSuccess(Note note, ServiceContext context) throws IOException {
super.onSuccess(note, context);
Note reloadedNote = getNotebook().loadNoteFromRepo(noteId, context.getAutheInfo());
conn.send(serializeMessage(new Message(OP.SET_NOTE_REVISION).put("status", true)));
broadcastNote(reloadedNote);
}
});
}
private void getNoteByRevision(NotebookSocket conn, Message fromMessage)
throws IOException {
String noteId = (String) fromMessage.get("noteId");
String revisionId = (String) fromMessage.get("revisionId");
getNotebookService().getNotebyRevision(noteId, revisionId, getServiceContext(fromMessage),
new WebSocketServiceCallback(conn) {
@Override
public void onSuccess(Note note, ServiceContext context) throws IOException {
super.onSuccess(note, context);
conn.send(serializeMessage(
new Message(OP.NOTE_REVISION).put("noteId", noteId).put("revisionId", revisionId)
.put("note", note)));
}
});
}
private void getNoteByRevisionForCompare(NotebookSocket conn,
Message fromMessage) throws IOException {
String noteId = (String) fromMessage.get("noteId");
String revisionId = (String) fromMessage.get("revisionId");
String position = (String) fromMessage.get("position");
getNotebookService().getNoteByRevisionForCompare(noteId, revisionId,
getServiceContext(fromMessage),
new WebSocketServiceCallback(conn) {
@Override
public void onSuccess(Note note, ServiceContext context) throws IOException {
super.onSuccess(note, context);
conn.send(serializeMessage(
new Message(OP.NOTE_REVISION_FOR_COMPARE).put("noteId", noteId)
.put("revisionId", revisionId).put("position", position).put("note", note)));
}
});
}
/**
* This callback is for the paragraph that runs on ZeppelinServer.
*
* @param output output to append
*/
@Override
public void onOutputAppend(String noteId, String paragraphId, int index, String output) {
if (!sendParagraphStatusToFrontend) {
return;
}
Message msg = new Message(OP.PARAGRAPH_APPEND_OUTPUT).put("noteId", noteId)
.put("paragraphId", paragraphId).put("index", index).put("data", output);
getConnectionManager().broadcast(noteId, msg);
}
/**
* This callback is for the paragraph that runs on ZeppelinServer.
*
* @param output output to update (replace)
*/
@Override
public void onOutputUpdated(String noteId, String paragraphId, int index,
InterpreterResult.Type type, String output) {
if (!sendParagraphStatusToFrontend) {
return;
}
Message msg = new Message(OP.PARAGRAPH_UPDATE_OUTPUT).put("noteId", noteId)
.put("paragraphId", paragraphId).put("index", index).put("type", type).put("data", output);
try {
Note note = getNotebook().getNote(noteId);
if (note == null) {
LOG.warn("Note " + noteId + " note found");
return;
}
Paragraph paragraph = note.getParagraph(paragraphId);
paragraph.updateOutputBuffer(index, type, output);
if (note.isPersonalizedMode()) {
String user = note.getParagraph(paragraphId).getUser();
if (null != user) {
getConnectionManager().multicastToUser(user, msg);
}
} else {
getConnectionManager().broadcast(noteId, msg);
}
} catch (IOException e) {
LOG.warn("Fail to call onOutputUpdated", e);
}
}
/**
* This callback is for the paragraph that runs on ZeppelinServer.
*/
@Override
public void onOutputClear(String noteId, String paragraphId) {
if (!sendParagraphStatusToFrontend) {
return;
}
try {
final Note note = getNotebook().getNote(noteId);
if (note == null) {
// It is possible the note is removed, but the job is still running
LOG.warn("Note {} doesn't existed, it maybe deleted.", noteId);
} else {
note.clearParagraphOutput(paragraphId);
Paragraph paragraph = note.getParagraph(paragraphId);
broadcastParagraph(note, paragraph, MSG_ID_NOT_DEFINED);
}
} catch (IOException e) {
LOG.warn("Fail to call onOutputClear", e);
}
}
/**
* When application append output.
*/
@Override
public void onOutputAppend(String noteId, String paragraphId, int index, String appId,
String output) {
Message msg =
new Message(OP.APP_APPEND_OUTPUT).put("noteId", noteId).put("paragraphId", paragraphId)
.put("index", index).put("appId", appId).put("data", output);
getConnectionManager().broadcast(noteId, msg);
}
/**
* When application update output.
*/
@Override
public void onOutputUpdated(String noteId, String paragraphId, int index, String appId,
InterpreterResult.Type type, String output) {
Message msg =
new Message(OP.APP_UPDATE_OUTPUT).put("noteId", noteId).put("paragraphId", paragraphId)
.put("index", index).put("type", type).put("appId", appId).put("data", output);
getConnectionManager().broadcast(noteId, msg);
}
@Override
public void onLoad(String noteId, String paragraphId, String appId, HeliumPackage pkg) {
Message msg = new Message(OP.APP_LOAD).put("noteId", noteId).put("paragraphId", paragraphId)
.put("appId", appId).put("pkg", pkg);
getConnectionManager().broadcast(noteId, msg);
}
@Override
public void onStatusChange(String noteId, String paragraphId, String appId, String status) {
Message msg =
new Message(OP.APP_STATUS_CHANGE).put("noteId", noteId).put("paragraphId", paragraphId)
.put("appId", appId).put("status", status);
getConnectionManager().broadcast(noteId, msg);
}
@Override
public void runParagraphs(String noteId,
List paragraphIndices,
List paragraphIds,
String curParagraphId) throws IOException {
final Note note = getNotebook().getNote(noteId);
final List toBeRunParagraphIds = new ArrayList<>();
if (note == null) {
throw new IOException("Not existed noteId: " + noteId);
}
if (!paragraphIds.isEmpty() && !paragraphIndices.isEmpty()) {
throw new IOException("Can not specify paragraphIds and paragraphIndices together");
}
if (paragraphIds != null && !paragraphIds.isEmpty()) {
for (String paragraphId : paragraphIds) {
if (note.getParagraph(paragraphId) == null) {
throw new IOException("Not existed paragraphId: " + paragraphId);
}
if (!paragraphId.equals(curParagraphId)) {
toBeRunParagraphIds.add(paragraphId);
}
}
}
if (paragraphIndices != null && !paragraphIndices.isEmpty()) {
for (int paragraphIndex : paragraphIndices) {
if (note.getParagraph(paragraphIndex) == null) {
throw new IOException("Not existed paragraphIndex: " + paragraphIndex);
}
if (!note.getParagraph(paragraphIndex).getId().equals(curParagraphId)) {
toBeRunParagraphIds.add(note.getParagraph(paragraphIndex).getId());
}
}
}
// run the whole note except the current paragraph
if (paragraphIds.isEmpty() && paragraphIndices.isEmpty()) {
for (Paragraph paragraph : note.getParagraphs()) {
if (!paragraph.getId().equals(curParagraphId)) {
toBeRunParagraphIds.add(paragraph.getId());
}
}
}
Runnable runThread = new Runnable() {
@Override
public void run() {
for (String paragraphId : toBeRunParagraphIds) {
note.run(paragraphId, true);
}
}
};
executorService.submit(runThread);
}
@Override
public void onParagraphRemove(Paragraph p) {
try {
ServiceContext context = new ServiceContext(new AuthenticationInfo(),
getNotebookAuthorizationService().getOwners(p.getNote().getId()));
getJobManagerService().getNoteJobInfoByUnixTime(System.currentTimeMillis() - 5000, context,
new JobManagerServiceCallback());
} catch (IOException e) {
LOG.warn("can not broadcast for job manager: " + e.getMessage(), e);
}
}
@Override
public void onNoteRemove(Note note, AuthenticationInfo subject) {
try {
broadcastUpdateNoteJobInfo(note, System.currentTimeMillis() - 5000);
} catch (IOException e) {
LOG.warn("can not broadcast for job manager: " + e.getMessage(), e);
}
try {
getJobManagerService().removeNoteJobInfo(note.getId(), null,
new JobManagerServiceCallback());
} catch (IOException e) {
LOG.warn("can not broadcast for job manager: " + e.getMessage(), e);
}
}
@Override
public void onParagraphCreate(Paragraph p) {
try {
getJobManagerService().getNoteJobInfo(p.getNote().getId(), null,
new JobManagerServiceCallback());
} catch (IOException e) {
LOG.warn("can not broadcast for job manager: " + e.getMessage(), e);
}
}
@Override
public void onParagraphUpdate(Paragraph p) throws IOException {
}
@Override
public void onNoteCreate(Note note, AuthenticationInfo subject) {
try {
getJobManagerService().getNoteJobInfo(note.getId(), null,
new JobManagerServiceCallback());
} catch (IOException e) {
LOG.warn("can not broadcast for job manager: " + e.getMessage(), e);
}
}
@Override
public void onNoteUpdate(Note note, AuthenticationInfo subject) throws IOException {
}
@Override
public void onParagraphStatusChange(Paragraph p, Status status) {
try {
getJobManagerService().getNoteJobInfo(p.getNote().getId(), null,
new JobManagerServiceCallback());
} catch (IOException e) {
LOG.warn("can not broadcast for job manager: " + e.getMessage(), e);
}
}
private class JobManagerServiceCallback
extends SimpleServiceCallback> {
@Override
public void onSuccess(List notesJobInfo,
ServiceContext context) throws IOException {
super.onSuccess(notesJobInfo, context);
Map response = new HashMap<>();
response.put("lastResponseUnixTime", System.currentTimeMillis());
response.put("jobs", notesJobInfo);
getConnectionManager().broadcast(JobManagerServiceType.JOB_MANAGER_PAGE.getKey(),
new Message(OP.LIST_UPDATE_NOTE_JOBS).put("noteRunningJobs", response));
}
}
@Override
public void onProgressUpdate(Paragraph p, int progress) {
if (!sendParagraphStatusToFrontend) {
return;
}
getConnectionManager().broadcast(p.getNote().getId(),
new Message(OP.PROGRESS).put("id", p.getId()).put("progress", progress));
}
@Override
public void onStatusChange(Paragraph p, Status before, Status after) {
if (after == Status.ERROR) {
if (p.getException() != null) {
LOG.error("Error", p.getException());
}
}
if (p.isTerminated() || after == Status.RUNNING) {
if (p.getStatus() == Status.FINISHED) {
LOG.info("Job {} is finished successfully, status: {}", p.getId(), p.getStatus());
} else if (p.isTerminated()) {
LOG.warn("Job {} is finished, status: {}, exception: {}, result: {}", p.getId(),
p.getStatus(), p.getException(), p.getReturn());
} else {
LOG.info("Job {} starts to RUNNING", p.getId());
}
try {
if (getNotebook().getNote(p.getNote().getId()) == null) {
// It is possible the note is removed, but the job is still running
LOG.warn("Note {} doesn't existed.", p.getNote().getId());
} else {
getNotebook().saveNote(p.getNote(), p.getAuthenticationInfo());
}
} catch (IOException e) {
LOG.error(e.toString(), e);
}
}
p.setStatusToUserParagraph(p.getStatus());
broadcastParagraph(p.getNote(), p, MSG_ID_NOT_DEFINED);
try {
broadcastUpdateNoteJobInfo(p.getNote(), System.currentTimeMillis() - 5000);
} catch (IOException e) {
LOG.error("can not broadcast for job manager {}", e);
}
}
@Override
public void checkpointOutput(String noteId, String paragraphId) {
try {
Note note = getNotebook().getNote(noteId);
note.getParagraph(paragraphId).checkpointOutput();
getNotebook().saveNote(note, AuthenticationInfo.ANONYMOUS);
} catch (IOException e) {
LOG.warn("Fail to save note: " + noteId , e);
}
}
@Override
public void noteRunningStatusChange(String noteId, boolean newStatus) {
getConnectionManager().broadcast(
noteId,
new Message(OP.NOTE_RUNNING_STATUS
).put("status", newStatus));
}
private void sendAllAngularObjects(Note note, String user, NotebookSocket conn)
throws IOException {
List settings =
getNotebook().getBindedInterpreterSettings(note.getId());
if (settings == null || settings.size() == 0) {
return;
}
for (InterpreterSetting intpSetting : settings) {
if (intpSetting.getInterpreterGroup(user, note.getId()) == null) {
continue;
}
AngularObjectRegistry registry =
intpSetting.getInterpreterGroup(user, note.getId()).getAngularObjectRegistry();
List objects = registry.getAllWithGlobal(note.getId());
for (AngularObject object : objects) {
conn.send(serializeMessage(
new Message(OP.ANGULAR_OBJECT_UPDATE).put("angularObject", object)
.put("interpreterGroupId",
intpSetting.getInterpreterGroup(user, note.getId()).getId())
.put("noteId", note.getId()).put("paragraphId", object.getParagraphId())));
}
}
}
@Override
public void onAddAngularObject(String interpreterGroupId, AngularObject angularObject) {
onUpdateAngularObject(interpreterGroupId, angularObject);
}
@Override
public void onUpdateAngularObject(String interpreterGroupId, AngularObject angularObject) {
if (getNotebook() == null) {
return;
}
// not global scope, so we just need to load the corresponded note.
if (angularObject.getNoteId() != null) {
try {
Note note = getNotebook().getNote(angularObject.getNoteId());
updateNoteAngularObject(note, angularObject, interpreterGroupId);
} catch (IOException e) {
LOG.error("AngularObject's note: {} is not found", angularObject.getNoteId());
}
} else {
// global scope angular object needs to load and iterate all notes, this is inefficient.
getNotebook().getNoteStream().forEach(note -> {
if (angularObject.getNoteId() != null && !note.getId().equals(angularObject.getNoteId())) {
return;
}
updateNoteAngularObject(note, angularObject, interpreterGroupId);
});
}
}
private void updateNoteAngularObject(Note note, AngularObject angularObject, String interpreterGroupId) {
List intpSettings =
note.getBindedInterpreterSettings(
new ArrayList<>(getNotebookAuthorizationService().getOwners(note.getId())));
if (intpSettings.isEmpty()) {
return;
}
getConnectionManager().broadcast(note.getId(), new Message(OP.ANGULAR_OBJECT_UPDATE)
.put("angularObject", angularObject)
.put("interpreterGroupId", interpreterGroupId).put("noteId", note.getId())
.put("paragraphId", angularObject.getParagraphId()));
}
@Override
public void onRemoveAngularObject(String interpreterGroupId, AngularObject angularObject) {
// not global scope, so we just need to load the corresponded note.
if (angularObject.getNoteId() != null) {
try {
Note note = getNotebook().getNote(angularObject.getNoteId());
removeNoteAngularObject(angularObject.getNoteId(), angularObject, interpreterGroupId);
} catch (IOException e) {
LOG.error("AngularObject's note: {} is not found", angularObject.getNoteId());
}
} else {
// global scope angular object needs to load and iterate all notes, this is inefficient.
getNotebook().getNoteStream().forEach(note -> {
if (angularObject.getNoteId() != null && !note.getId().equals(angularObject.getNoteId())) {
return;
}
removeNoteAngularObject(note.getId(), angularObject, interpreterGroupId);
});
}
}
private void removeNoteAngularObject(String noteId, AngularObject angularObject, String interpreterGroupId) {
List settingIds =
getNotebook().getInterpreterSettingManager().getSettingIds();
for (String id : settingIds) {
if (interpreterGroupId.contains(id)) {
getConnectionManager().broadcast(noteId,
new Message(OP.ANGULAR_OBJECT_REMOVE)
.put("name", angularObject.getName())
.put("noteId", angularObject.getNoteId())
.put("paragraphId", angularObject.getParagraphId()));
break;
}
}
}
private void getEditorSetting(NotebookSocket conn, Message fromMessage) throws IOException {
String paragraphId = (String) fromMessage.get("paragraphId");
String paragraphText = (String) fromMessage.get("paragraphText");
String noteId = getConnectionManager().getAssociatedNoteId(conn);
getNotebookService().getEditorSetting(noteId, paragraphText,
getServiceContext(fromMessage),
new WebSocketServiceCallback>(conn) {
@Override
public void onSuccess(Map settings,
ServiceContext context) throws IOException {
super.onSuccess(settings, context);
Message resp = new Message(OP.EDITOR_SETTING);
resp.put("paragraphId", paragraphId);
resp.put("editor", settings);
conn.send(serializeMessage(resp));
}
@Override
public void onFailure(Exception ex, ServiceContext context) throws IOException {
LOG.warn(ex.getMessage());
}
});
}
private void getInterpreterSettings(NotebookSocket conn, Message message)
throws IOException {
ServiceContext context = getServiceContext(message);
List allSettings = getNotebook().getInterpreterSettingManager().get();
List result = new ArrayList<>();
for (InterpreterSetting setting : allSettings) {
if (setting.isUserAuthorized(new ArrayList<>(context.getUserAndRoles()))) {
result.add(setting);
}
}
conn.send(serializeMessage(
new Message(OP.INTERPRETER_SETTINGS).put("interpreterSettings", result)));
}
@Override
public void onParaInfosReceived(String noteId, String paragraphId,
String interpreterSettingId, Map metaInfos) {
try {
Note note = getNotebook().getNote(noteId);
if (note != null) {
Paragraph paragraph = note.getParagraph(paragraphId);
if (paragraph != null) {
InterpreterSetting setting = getNotebook().getInterpreterSettingManager()
.get(interpreterSettingId);
String label = metaInfos.get("label");
String tooltip = metaInfos.get("tooltip");
List keysToRemove = Arrays.asList("noteId", "paraId", "label", "tooltip");
for (String removeKey : keysToRemove) {
metaInfos.remove(removeKey);
}
paragraph
.updateRuntimeInfos(label, tooltip, metaInfos, setting.getGroup(), setting.getId());
getNotebook().saveNote(note, AuthenticationInfo.ANONYMOUS);
getConnectionManager().broadcast(
note.getId(),
new Message(OP.PARAS_INFO).put("id", paragraphId).put("infos",
paragraph.getRuntimeInfos()));
}
}
} catch (IOException e) {
LOG.warn("Fail to call onParaInfosReceived", e);
}
}
@Override
public List getParagraphList(String user, String noteId)
throws TException, IOException {
Notebook notebook = getNotebook();
Note note = notebook.getNote(noteId);
if (null == note) {
throw new ServiceException("Not found this note : " + noteId);
}
// Check READER permission
Set userAndRoles = new HashSet<>();
userAndRoles.add(user);
AuthorizationService notebookAuthorization = getNotebookAuthorizationService();
boolean isAllowed = notebookAuthorization.isReader(noteId, userAndRoles);
Set allowed = notebookAuthorization.getReaders(noteId);
if (false == isAllowed) {
String errorMsg = "Insufficient privileges to READER note. " +
"Allowed users or roles: " + allowed;
throw new ServiceException(errorMsg);
}
// Convert Paragraph to ParagraphInfo
List paragraphInfos = new ArrayList();
List paragraphs = note.getParagraphs();
for (Iterator iter = paragraphs.iterator(); iter.hasNext();) {
Paragraph paragraph = iter.next();
ParagraphInfo paraInfo = new ParagraphInfo();
paraInfo.setNoteId(noteId);
paraInfo.setParagraphId(paragraph.getId());
paraInfo.setParagraphTitle(paragraph.getTitle());
paraInfo.setParagraphText(paragraph.getText());
paragraphInfos.add(paraInfo);
}
return paragraphInfos;
}
private void broadcastNoteForms(Note note) {
GUI formsSettings = new GUI();
formsSettings.setForms(note.getNoteForms());
formsSettings.setParams(note.getNoteParams());
getConnectionManager().broadcast(note.getId(),
new Message(OP.SAVE_NOTE_FORMS).put("formsData", formsSettings));
}
private void saveNoteForms(NotebookSocket conn,
Message fromMessage) throws IOException {
String noteId = (String) fromMessage.get("noteId");
Map noteParams = (Map) fromMessage.get("noteParams");
getNotebookService().saveNoteForms(noteId, noteParams, getServiceContext(fromMessage),
new WebSocketServiceCallback(conn) {
@Override
public void onSuccess(Note note, ServiceContext context) throws IOException {
broadcastNoteForms(note);
}
});
}
private void removeNoteForms(NotebookSocket conn,
Message fromMessage) throws IOException {
String noteId = (String) fromMessage.get("noteId");
String formName = (String) fromMessage.get("formName");
getNotebookService().removeNoteForms(noteId, formName, getServiceContext(fromMessage),
new WebSocketServiceCallback(conn) {
@Override
public void onSuccess(Note note, ServiceContext context) throws IOException {
broadcastNoteForms(note);
}
});
}
@ManagedAttribute
public Set getConnectedUsers() {
return getConnectionManager().getConnectedUsers();
}
@ManagedOperation
public void sendMessage(String message) {
Message m = new Message(OP.NOTICE);
m.data.put("notice", message);
getConnectionManager().broadcast(m);
}
private ServiceContext getServiceContext(Message message) {
AuthenticationInfo authInfo =
new AuthenticationInfo(message.principal, message.roles, message.ticket);
Set userAndRoles = new HashSet<>();
userAndRoles.add(message.principal);
if (message.roles != null && !message.roles.equals("")) {
HashSet roles =
gson.fromJson(message.roles, new TypeToken>() {
}.getType());
if (roles != null) {
userAndRoles.addAll(roles);
}
}
return new ServiceContext(authInfo, userAndRoles);
}
public class WebSocketServiceCallback extends SimpleServiceCallback {
private NotebookSocket conn;
WebSocketServiceCallback(NotebookSocket conn) {
this.conn = conn;
}
@Override
public void onFailure(Exception ex, ServiceContext context) throws IOException {
super.onFailure(ex, context);
if (ex instanceof ForbiddenException) {
Type type = new TypeToken>() {}.getType();
Map jsonObject =
gson.fromJson(((ForbiddenException) ex).getResponse().getEntity().toString(), type);
conn.send(serializeMessage(new Message(OP.AUTH_INFO)
.put("info", jsonObject.get("message"))));
} else {
String message = ex.getMessage();
if (ex.getCause() != null) {
message += ", cause: " + ex.getCause().getMessage();
}
conn.send(serializeMessage(new Message(OP.ERROR_INFO).put("info", message)));
}
}
}
}