From bb757e32aa16f738a9d71831a72f8d8bcab27e76 Mon Sep 17 00:00:00 2001 From: Lee moon soo Date: Sun, 28 Jun 2015 14:08:47 -0700 Subject: [PATCH 01/17] Introduce scope (global/local) for angular object --- .../zeppelin/flink/FlinkInterpreterTest.java | 2 +- .../ignite/IgniteInterpreterTest.java | 2 +- .../ignite/IgniteSqlInterpreterTest.java | 2 +- .../zeppelin/spark/ZeppelinContext.java | 248 ++++++++++++++++-- .../zeppelin/spark/DepInterpreterTest.java | 2 +- .../zeppelin/spark/SparkInterpreterTest.java | 2 +- .../spark/SparkSqlInterpreterTest.java | 2 +- .../zeppelin/display/AngularObject.java | 29 +- .../display/AngularObjectRegistry.java | 97 +++++-- .../interpreter/InterpreterContext.java | 10 +- .../remote/RemoteAngularObject.java | 6 +- .../remote/RemoteAngularObjectRegistry.java | 4 +- .../interpreter/remote/RemoteInterpreter.java | 1 + .../remote/RemoteInterpreterEventPoller.java | 11 +- .../remote/RemoteInterpreterProcess.java | 4 +- .../remote/RemoteInterpreterServer.java | 16 +- .../thrift/RemoteInterpreterContext.java | 174 +++++++++--- .../thrift/RemoteInterpreterService.java | 136 ++++++++-- .../thrift/RemoteInterpreterService.thrift | 15 +- .../display/AngularObjectRegistryTest.java | 21 +- .../zeppelin/display/AngularObjectTest.java | 4 +- .../remote/RemoteAngularObjectTest.java | 7 +- .../remote/RemoteInterpreterTest.java | 7 + .../remote/mock/MockInterpreterAngular.java | 10 +- .../scheduler/RemoteSchedulerTest.java | 1 + .../zeppelin/socket/NotebookServer.java | 72 +++-- .../org/apache/zeppelin/notebook/Note.java | 2 +- .../apache/zeppelin/notebook/Paragraph.java | 4 +- .../interpreter/InterpreterFactoryTest.java | 2 +- 29 files changed, 723 insertions(+), 170 deletions(-) diff --git a/flink/src/test/java/org/apache/zeppelin/flink/FlinkInterpreterTest.java b/flink/src/test/java/org/apache/zeppelin/flink/FlinkInterpreterTest.java index 264008adb21..4469c3ee5c8 100644 --- a/flink/src/test/java/org/apache/zeppelin/flink/FlinkInterpreterTest.java +++ b/flink/src/test/java/org/apache/zeppelin/flink/FlinkInterpreterTest.java @@ -38,7 +38,7 @@ public static void setUp() { Properties p = new Properties(); flink = new FlinkInterpreter(p); flink.open(); - context = new InterpreterContext(null, null, null, null, null, null, null); + context = new InterpreterContext(null, null, null, null, null, null, null, null); } @AfterClass diff --git a/ignite/src/test/java/org/apache/zeppelin/ignite/IgniteInterpreterTest.java b/ignite/src/test/java/org/apache/zeppelin/ignite/IgniteInterpreterTest.java index 3d3f50bdd73..ad393a7b12a 100644 --- a/ignite/src/test/java/org/apache/zeppelin/ignite/IgniteInterpreterTest.java +++ b/ignite/src/test/java/org/apache/zeppelin/ignite/IgniteInterpreterTest.java @@ -40,7 +40,7 @@ public class IgniteInterpreterTest { private static final String HOST = "127.0.0.1:47500..47509"; private static final InterpreterContext INTP_CONTEXT = - new InterpreterContext(null, null, null, null, null, null, null); + new InterpreterContext(null, null, null, null, null, null, null, null); private IgniteInterpreter intp; private Ignite ignite; diff --git a/ignite/src/test/java/org/apache/zeppelin/ignite/IgniteSqlInterpreterTest.java b/ignite/src/test/java/org/apache/zeppelin/ignite/IgniteSqlInterpreterTest.java index de1e7609cb5..b5eff965ced 100644 --- a/ignite/src/test/java/org/apache/zeppelin/ignite/IgniteSqlInterpreterTest.java +++ b/ignite/src/test/java/org/apache/zeppelin/ignite/IgniteSqlInterpreterTest.java @@ -43,7 +43,7 @@ public class IgniteSqlInterpreterTest { private static final String HOST = "127.0.0.1:47500..47509"; private static final InterpreterContext INTP_CONTEXT = - new InterpreterContext(null, null, null, null, null, null, null); + new InterpreterContext(null, null, null, null, null, null, null, null); private Ignite ignite; private IgniteSqlInterpreter intp; diff --git a/spark/src/main/java/org/apache/zeppelin/spark/ZeppelinContext.java b/spark/src/main/java/org/apache/zeppelin/spark/ZeppelinContext.java index 2c03f1cd91b..4299eebd06d 100644 --- a/spark/src/main/java/org/apache/zeppelin/spark/ZeppelinContext.java +++ b/spark/src/main/java/org/apache/zeppelin/spark/ZeppelinContext.java @@ -466,45 +466,225 @@ public List listParagraphs() { } + private AngularObject getAngularObject(String name, InterpreterContext interpreterContext) { + AngularObjectRegistry registry = interpreterContext.getAngularObjectRegistry(); + String noteId = interpreterContext.getNoteId(); + // try get local object + AngularObject ao = registry.get(name, interpreterContext.getNoteId()); + if (ao == null) { + // then global object + ao = registry.get(name, null); + } + return ao; + } + + /** + * Get angular object. Look up local registry first and then global registry + * @param name variable name + * @return value + */ public Object angular(String name) { + AngularObject ao = getAngularObject(name, interpreterContext); + if (ao == null) { + return null; + } else { + return ao.get(); + } + } + + /** + * Get angular object. Look up global registry + * @param name variable name + * @return value + */ + public Object angularGlobal(String name) { AngularObjectRegistry registry = interpreterContext.getAngularObjectRegistry(); - AngularObject ao = registry.get(name); + AngularObject ao = registry.get(name, null); if (ao == null) { return null; } else { return ao.get(); } + } + + /** + * Create angular variable in local registry and bind with front end Angular display system. + * If variable exists, it'll be overwritten. + * @param name name of the variable + * @param o value + */ + public void angularBind(String name, Object o) { + angularBind(name, o, interpreterContext.getNoteId()); + } + + /** + * Create angular variable in global registry and bind with front end Angular display system. + * If variable exists, it'll be overwritten. + * @param name name of the variable + * @param o value + */ + public void angularBindGlobal(String name, Object o) { + angularBind(name, o, (String) null); + } + + /** + * Create angular variable in local registry and bind with front end Angular display system. + * If variable exists, value will be overwritten and watcher will be added. + * @param name name of variable + * @param o value + * @param watcher watcher of the variable + */ + public void angularBind(String name, Object o, AngularObjectWatcher watcher) { + angularBind(name, o, interpreterContext.getNoteId(), watcher); + } + + /** + * Create angular variable in global registry and bind with front end Angular display system. + * If variable exists, value will be overwritten and watcher will be added. + * @param name name of variable + * @param o value + * @param watcher watcher of the variable + */ + public void angularBindGlobal(String name, Object o, AngularObjectWatcher watcher) { + angularBind(name, o, null, watcher); } - public void angularBind(String name, Object o) { + /** + * Add watcher into angular variable (local registry) + * @param name name of the variable + * @param watcher watcher + */ + public void angularWatch(String name, AngularObjectWatcher watcher) { + angularWatch(name, interpreterContext.getNoteId(), watcher); + } + + /** + * Add watcher into angular variable (global registry) + * @param name name of the variable + * @param watcher watcher + */ + public void angularWatchGlobal(String name, AngularObjectWatcher watcher) { + angularWatch(name, null, watcher); + } + + + public void angularWatch(String name, + final scala.Function2 func) { + angularWatch(name, interpreterContext.getNoteId(), func); + } + + public void angularWatchGlobal(String name, + final scala.Function2 func) { + angularWatch(name, null, func); + } + + public void angularWatch( + String name, + final scala.Function3 func) { + angularWatch(name, interpreterContext.getNoteId(), func); + } + + public void angularWatchGlobal( + String name, + final scala.Function3 func) { + angularWatch(name, null, func); + } + + /** + * Remove watcher from angular variable (local) + * @param name + * @param watcher + */ + public void angularUnwatch(String name, AngularObjectWatcher watcher) { + angularUnwatch(name, interpreterContext.getNoteId(), watcher); + } + + /** + * Remove watcher from angular variable (global) + * @param name + * @param watcher + */ + public void angularUnwatchGlobal(String name, AngularObjectWatcher watcher) { + angularUnwatch(name, null, watcher); + } + + + /** + * Remove all watchers for the angular variable (local) + * @param name + */ + public void angularUnwatch(String name) { + angularUnwatch(name, interpreterContext.getNoteId()); + } + + /** + * Remove all watchers for the angular variable (global) + * @param name + */ + public void angularUnwatchGlobal(String name) { + angularUnwatch(name, (String) null); + } + + /** + * Remove angular variable and all the watchers. + * @param name + */ + public void angularUnbind(String name) { AngularObjectRegistry registry = interpreterContext.getAngularObjectRegistry(); - if (registry.get(name) == null) { - registry.add(name, o); + String noteId = interpreterContext.getNoteId(); + registry.remove(name, noteId); + } + + /** + * Create angular variable in local registry and bind with front end Angular display system. + * If variable exists, it'll be overwritten. + * @param name name of the variable + * @param o value + */ + private void angularBind(String name, Object o, String noteId) { + AngularObjectRegistry registry = interpreterContext.getAngularObjectRegistry(); + + if (registry.get(name, noteId) == null) { + registry.add(name, o, noteId); } else { - registry.get(name).set(o); + registry.get(name, noteId).set(o); } } - - public void angularBind(String name, Object o, AngularObjectWatcher w) { + + /** + * Create angular variable in local registry and bind with front end Angular display system. + * If variable exists, value will be overwritten and watcher will be added. + * @param name name of variable + * @param o value + * @param watcher watcher of the variable + */ + private void angularBind(String name, Object o, String noteId, AngularObjectWatcher watcher) { AngularObjectRegistry registry = interpreterContext.getAngularObjectRegistry(); - if (registry.get(name) == null) { - registry.add(name, o); + + if (registry.get(name, noteId) == null) { + registry.add(name, o, noteId); } else { - registry.get(name).set(o); + registry.get(name, noteId).set(o); } - angularWatch(name, w); + angularWatch(name, watcher); } - public void angularWatch(String name, AngularObjectWatcher w) { + /** + * Add watcher into angular binding variable + * @param name name of the variable + * @param watcher watcher + */ + private void angularWatch(String name, String noteId, AngularObjectWatcher watcher) { AngularObjectRegistry registry = interpreterContext.getAngularObjectRegistry(); - if (registry.get(name) != null) { - registry.get(name).addWatcher(w); + + if (registry.get(name, noteId) != null) { + registry.get(name, noteId).addWatcher(watcher); } } - public void angularWatch(String name, + private void angularWatch(String name, String noteId, final scala.Function2 func) { AngularObjectWatcher w = new AngularObjectWatcher(getInterpreterContext()) { @Override @@ -513,11 +693,12 @@ public void watch(Object oldObject, Object newObject, func.apply(newObject, newObject); } }; - angularWatch(name, w); + angularWatch(name, noteId, w); } - public void angularWatch( + private void angularWatch( String name, + String noteId, final scala.Function3 func) { AngularObjectWatcher w = new AngularObjectWatcher(getInterpreterContext()) { @Override @@ -526,25 +707,38 @@ public void watch(Object oldObject, Object newObject, func.apply(oldObject, newObject, context); } }; - angularWatch(name, w); - } + angularWatch(name, noteId, w); + } - public void angularUnwatch(String name, AngularObjectWatcher w) { + /** + * Remove watcher + * @param name + * @param watcher + */ + private void angularUnwatch(String name, String noteId, AngularObjectWatcher watcher) { AngularObjectRegistry registry = interpreterContext.getAngularObjectRegistry(); - if (registry.get(name) != null) { - registry.get(name).removeWatcher(w); + if (registry.get(name, noteId) != null) { + registry.get(name, noteId).removeWatcher(watcher); } } - public void angularUnwatch(String name) { + /** + * Remove all watchers for the angular variable + * @param name + */ + private void angularUnwatch(String name, String noteId) { AngularObjectRegistry registry = interpreterContext.getAngularObjectRegistry(); - if (registry.get(name) != null) { - registry.get(name).clearAllWatchers(); + if (registry.get(name, noteId) != null) { + registry.get(name, noteId).clearAllWatchers(); } } - public void angularUnbind(String name) { + /** + * Remove angular variable and all the watchers. + * @param name + */ + private void angularUnbind(String name, String noteId) { AngularObjectRegistry registry = interpreterContext.getAngularObjectRegistry(); - registry.remove(name); + registry.remove(name, noteId); } } diff --git a/spark/src/test/java/org/apache/zeppelin/spark/DepInterpreterTest.java b/spark/src/test/java/org/apache/zeppelin/spark/DepInterpreterTest.java index 2f8254d198b..6adaa14f7b4 100644 --- a/spark/src/test/java/org/apache/zeppelin/spark/DepInterpreterTest.java +++ b/spark/src/test/java/org/apache/zeppelin/spark/DepInterpreterTest.java @@ -58,7 +58,7 @@ public void setUp() throws Exception { intpGroup.add(dep); dep.setInterpreterGroup(intpGroup); - context = new InterpreterContext("id", "title", "text", new HashMap(), new GUI(), + context = new InterpreterContext("note", "id", "title", "text", new HashMap(), new GUI(), new AngularObjectRegistry(intpGroup.getId(), null), new LinkedList()); } diff --git a/spark/src/test/java/org/apache/zeppelin/spark/SparkInterpreterTest.java b/spark/src/test/java/org/apache/zeppelin/spark/SparkInterpreterTest.java index c97e824f5b3..daa7eeda81d 100644 --- a/spark/src/test/java/org/apache/zeppelin/spark/SparkInterpreterTest.java +++ b/spark/src/test/java/org/apache/zeppelin/spark/SparkInterpreterTest.java @@ -75,7 +75,7 @@ public void setUp() throws Exception { } InterpreterGroup intpGroup = new InterpreterGroup(); - context = new InterpreterContext("id", "title", "text", + context = new InterpreterContext("note", "id", "title", "text", new HashMap(), new GUI(), new AngularObjectRegistry( intpGroup.getId(), null), new LinkedList()); diff --git a/spark/src/test/java/org/apache/zeppelin/spark/SparkSqlInterpreterTest.java b/spark/src/test/java/org/apache/zeppelin/spark/SparkSqlInterpreterTest.java index 30166a7848f..bb818fd2c56 100644 --- a/spark/src/test/java/org/apache/zeppelin/spark/SparkSqlInterpreterTest.java +++ b/spark/src/test/java/org/apache/zeppelin/spark/SparkSqlInterpreterTest.java @@ -63,7 +63,7 @@ public void setUp() throws Exception { sql.setInterpreterGroup(intpGroup); sql.open(); } - context = new InterpreterContext("id", "title", "text", new HashMap(), new GUI(), + context = new InterpreterContext("note", "id", "title", "text", new HashMap(), new GUI(), new AngularObjectRegistry(intpGroup.getId(), null), new LinkedList()); } diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/display/AngularObject.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/display/AngularObject.java index bbfcd1b184d..cebe4cc4911 100644 --- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/display/AngularObject.java +++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/display/AngularObject.java @@ -33,13 +33,17 @@ public class AngularObject { private String name; private T object; + private transient AngularObjectListener listener; private transient List watchers = new LinkedList(); + + private String noteId; // noteId belonging to. null for global scope - protected AngularObject(String name, T o, + protected AngularObject(String name, T o, String noteId, AngularObjectListener listener) { this.name = name; + this.noteId = noteId; this.listener = listener; object = o; } @@ -47,14 +51,29 @@ protected AngularObject(String name, T o, public String getName() { return name; } + + public void setNoteId(String noteId) { + this.noteId = noteId; + } + + public String getNoteId() { + return noteId; + } + + public boolean isGlobal() { + return noteId == null; + } @Override public boolean equals(Object o) { if (o instanceof AngularObject) { - return name.equals(((AngularObject) o).name); - } else { - return false; + AngularObject ao = (AngularObject) o; + if (noteId == null && ao.noteId == null || + (noteId != null && ao.noteId != null && noteId.equals(ao.noteId))) { + return name.equals(ao.name); + } } + return false; } public Object get() { @@ -66,7 +85,7 @@ public void emit(){ listener.updated(this); } } - + public void set(T o) { set(o, true); } diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/display/AngularObjectRegistry.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/display/AngularObjectRegistry.java index 56eca22d895..18a29f6b2d9 100644 --- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/display/AngularObjectRegistry.java +++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/display/AngularObjectRegistry.java @@ -17,19 +17,26 @@ package org.apache.zeppelin.display; +import java.util.Collection; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; /** - * - * + * AngularObjectRegistry keeps all the object that binded to Angular Display System. + * AngularObjectRegistry is created per interpreter group. + * It keeps two different set of AngularObjects : + * - globalRegistry: Shared to all notebook that uses the same interpreter group + * - localRegistry: AngularObject is valid only inside of a single notebook */ public class AngularObjectRegistry { - Map registry = new HashMap(); + Map> registry = + new HashMap>(); + private final String GLOBAL_KEY = "_GLOBAL_"; private AngularObjectRegistryListener listener; private String interpreterId; + AngularObjectListener angularObjectListener; @@ -51,15 +58,42 @@ public AngularObjectRegistryListener getListener() { return listener; } - public AngularObject add(String name, Object o) { - return add(name, o, true); + /** + * Add object into global registry + * @param name + * @param o + * @param noteId noteId belonging to. null for global object. + * @return + */ + public AngularObject add(String name, Object o, String noteId) { + return add(name, o, noteId, true); } - public AngularObject add(String name, Object o, boolean emit) { - AngularObject ao = createNewAngularObject(name, o); + private String getRegistryKey(String noteId) { + if (noteId == null) { + return GLOBAL_KEY; + } else { + return noteId; + } + } + + private Map getRegistryForKey(String noteId) { + synchronized (registry) { + String key = getRegistryKey(noteId); + if (!registry.containsKey(key)) { + registry.put(key, new HashMap()); + } + + return registry.get(key); + } + } + + public AngularObject add(String name, Object o, String noteId, boolean emit) { + AngularObject ao = createNewAngularObject(name, o, noteId); synchronized (registry) { - registry.put(name, ao); + Map noteLocalRegistry = getRegistryForKey(noteId); + noteLocalRegistry.put(name, ao); if (listener != null && emit) { listener.onAdd(interpreterId, ao); } @@ -68,17 +102,18 @@ public AngularObject add(String name, Object o, boolean emit) { return ao; } - protected AngularObject createNewAngularObject(String name, Object o) { - return new AngularObject(name, o, angularObjectListener); + protected AngularObject createNewAngularObject(String name, Object o, String noteId) { + return new AngularObject(name, o, noteId, angularObjectListener); } protected AngularObjectListener getAngularObjectListener() { return angularObjectListener; } - public AngularObject remove(String name) { + public AngularObject remove(String name, String noteId) { synchronized (registry) { - AngularObject o = registry.remove(name); + Map r = getRegistryForKey(noteId); + AngularObject o = r.remove(name); if (listener != null) { listener.onRemove(interpreterId, o);; } @@ -86,16 +121,40 @@ public AngularObject remove(String name) { } } - public AngularObject get(String name) { + public AngularObject get(String name, String noteId) { synchronized (registry) { - return registry.get(name); + Map r = getRegistryForKey(noteId); + return r.get(name); } } - public List getAll() { + public List getAll(String noteId) { List all = new LinkedList(); synchronized (registry) { - all.addAll(registry.values()); + Map r = getRegistryForKey(noteId); + if (r != null) { + all.addAll(r.values()); + } + } + return all; + } + + /** + * Get all object with global merged + * @param noteId + * @return + */ + public List getAllWithGlobal(String noteId) { + List all = new LinkedList(); + synchronized (registry) { + Map global = getRegistryForKey(null); + if (global != null) { + all.addAll(global.values()); + } + Map local = getRegistryForKey(noteId); + if (local != null) { + all.addAll(local.values()); + } } return all; } @@ -103,4 +162,10 @@ public List getAll() { public String getInterpreterGroupId() { return interpreterId; } + + public void removeAll(String noteId) { + synchronized (registry) { + registry.remove(getRegistryKey(noteId)); + } + } } diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/InterpreterContext.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/InterpreterContext.java index 2e4564e09ef..7c2f6c0d726 100644 --- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/InterpreterContext.java +++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/InterpreterContext.java @@ -27,6 +27,7 @@ * Interpreter context */ public class InterpreterContext { + private final String noteId; private final String paragraphTitle; private final String paragraphId; private final String paragraphText; @@ -35,7 +36,8 @@ public class InterpreterContext { private AngularObjectRegistry angularObjectRegistry; private List runners; - public InterpreterContext(String paragraphId, + public InterpreterContext(String noteId, + String paragraphId, String paragraphTitle, String paragraphText, Map config, @@ -43,6 +45,7 @@ public InterpreterContext(String paragraphId, AngularObjectRegistry angularObjectRegistry, List runners ) { + this.noteId = noteId; this.paragraphId = paragraphId; this.paragraphTitle = paragraphTitle; this.paragraphText = paragraphText; @@ -52,6 +55,11 @@ public InterpreterContext(String paragraphId, this.runners = runners; } + + public String getNoteId() { + return noteId; + } + public String getParagraphId() { return paragraphId; } diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/remote/RemoteAngularObject.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/remote/RemoteAngularObject.java index 3abd7644ef6..351a2bb1b4a 100644 --- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/remote/RemoteAngularObject.java +++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/remote/RemoteAngularObject.java @@ -27,10 +27,10 @@ public class RemoteAngularObject extends AngularObject { private transient RemoteInterpreterProcess remoteInterpreterProcess; - RemoteAngularObject(String name, Object o, String interpreterGroupId, + RemoteAngularObject(String name, Object o, String noteId, String interpreterGroupId, AngularObjectListener listener, RemoteInterpreterProcess remoteInterpreterProcess) { - super(name, o, listener); + super(name, o, noteId, listener); this.remoteInterpreterProcess = remoteInterpreterProcess; } @@ -44,7 +44,7 @@ public void set(Object o, boolean emitWeb, boolean emitRemoteProcess) { if (emitRemoteProcess) { // send updated value to remote interpreter - remoteInterpreterProcess.updateRemoteAngularObject(getName(), o); + remoteInterpreterProcess.updateRemoteAngularObject(getName(), getNoteId(), o); } } } diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/remote/RemoteAngularObjectRegistry.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/remote/RemoteAngularObjectRegistry.java index c711f69009f..09d4152c38a 100644 --- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/remote/RemoteAngularObjectRegistry.java +++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/remote/RemoteAngularObjectRegistry.java @@ -55,12 +55,12 @@ private RemoteInterpreterProcess getRemoteInterpreterProcess() { } @Override - protected AngularObject createNewAngularObject(String name, Object o) { + protected AngularObject createNewAngularObject(String name, Object o, String noteId) { RemoteInterpreterProcess remoteInterpreterProcess = getRemoteInterpreterProcess(); if (remoteInterpreterProcess == null) { throw new RuntimeException("Remote Interpreter process not found"); } - return new RemoteAngularObject(name, o, getInterpreterGroupId(), + return new RemoteAngularObject(name, o, noteId, getInterpreterGroupId(), getAngularObjectListener(), getRemoteInterpreterProcess()); } diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/remote/RemoteInterpreter.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/remote/RemoteInterpreter.java index 8992f5507ed..d5d92c83c01 100644 --- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/remote/RemoteInterpreter.java +++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/remote/RemoteInterpreter.java @@ -356,6 +356,7 @@ private String getInterpreterGroupKey(InterpreterGroup interpreterGroup) { private RemoteInterpreterContext convert(InterpreterContext ic) { return new RemoteInterpreterContext( + ic.getNoteId(), ic.getParagraphId(), ic.getParagraphTitle(), ic.getParagraphText(), diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/remote/RemoteInterpreterEventPoller.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/remote/RemoteInterpreterEventPoller.java index 4997b0eb10b..3a097ca17b3 100644 --- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/remote/RemoteInterpreterEventPoller.java +++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/remote/RemoteInterpreterEventPoller.java @@ -85,10 +85,13 @@ public void run() { continue; } else if (event.getType() == RemoteInterpreterEventType.ANGULAR_OBJECT_ADD) { AngularObject angularObject = gson.fromJson(event.getData(), AngularObject.class); - angularObjectRegistry.add(angularObject.getName(), angularObject.get()); + angularObjectRegistry.add(angularObject.getName(), + angularObject.get(), angularObject.getNoteId()); } else if (event.getType() == RemoteInterpreterEventType.ANGULAR_OBJECT_UPDATE) { - AngularObject angularObject = gson.fromJson(event.getData(), AngularObject.class); - AngularObject localAngularObject = angularObjectRegistry.get(angularObject.getName()); + AngularObject angularObject = gson.fromJson(event.getData(), + AngularObject.class); + AngularObject localAngularObject = angularObjectRegistry.get( + angularObject.getName(), angularObject.getNoteId()); if (localAngularObject instanceof RemoteAngularObject) { // to avoid ping-pong loop ((RemoteAngularObject) localAngularObject).set( @@ -98,7 +101,7 @@ public void run() { } } else if (event.getType() == RemoteInterpreterEventType.ANGULAR_OBJECT_REMOVE) { AngularObject angularObject = gson.fromJson(event.getData(), AngularObject.class); - angularObjectRegistry.remove(angularObject.getName()); + angularObjectRegistry.remove(angularObject.getName(), angularObject.getNoteId()); } else if (event.getType() == RemoteInterpreterEventType.RUN_INTERPRETER_CONTEXT_RUNNER) { InterpreterContextRunner runnerFromRemote = gson.fromJson( event.getData(), RemoteInterpreterContextRunner.class); diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/remote/RemoteInterpreterProcess.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/remote/RemoteInterpreterProcess.java index 91edd41d88d..534af271d2f 100644 --- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/remote/RemoteInterpreterProcess.java +++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/remote/RemoteInterpreterProcess.java @@ -236,7 +236,7 @@ public int getNumIdleClient() { * @param name * @param o */ - public void updateRemoteAngularObject(String name, Object o) { + public void updateRemoteAngularObject(String name, String noteId, Object o) { Client client = null; try { client = getClient(); @@ -249,7 +249,7 @@ public void updateRemoteAngularObject(String name, Object o) { try { Gson gson = new Gson(); - client.angularObjectUpdate(name, gson.toJson(o)); + client.angularObjectUpdate(name, noteId, gson.toJson(o)); } catch (TException e) { logger.error("Can't update angular object", e); } finally { diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/remote/RemoteInterpreterServer.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/remote/RemoteInterpreterServer.java index 33baf9ac0bd..b6a0a7df98e 100644 --- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/remote/RemoteInterpreterServer.java +++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/remote/RemoteInterpreterServer.java @@ -320,6 +320,7 @@ private InterpreterContext convert(RemoteInterpreterContext ric) { } return new InterpreterContext( + ric.getNoteId(), ric.getParagraphId(), ric.getParagraphTitle(), ric.getParagraphText(), @@ -429,17 +430,24 @@ public RemoteInterpreterEvent getEvent() throws TException { * called when object is updated in client (web) side. * @param className * @param name + * @param noteId noteId where the update issues * @param object * @throws TException */ @Override - public void angularObjectUpdate(String name, String object) + public void angularObjectUpdate(String name, String noteId, String object) throws TException { AngularObjectRegistry registry = interpreterGroup.getAngularObjectRegistry(); - AngularObject ao = registry.get(name); + // first try local objects + AngularObject ao = registry.get(name, noteId); if (ao == null) { - logger.error("Angular object {} not exists", name); - return; + // then try global objects + ao = registry.get(name, null); + + if (ao == null) { + logger.error("Angular object {} not exists", name); + return; + } } if (object == null) { diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterContext.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterContext.java index 9827a45fdb0..7a757ab4f42 100644 --- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterContext.java +++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterContext.java @@ -33,12 +33,13 @@ public class RemoteInterpreterContext implements org.apache.thrift.TBase, java.io.Serializable, Cloneable { private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("RemoteInterpreterContext"); - private static final org.apache.thrift.protocol.TField PARAGRAPH_ID_FIELD_DESC = new org.apache.thrift.protocol.TField("paragraphId", org.apache.thrift.protocol.TType.STRING, (short)1); - private static final org.apache.thrift.protocol.TField PARAGRAPH_TITLE_FIELD_DESC = new org.apache.thrift.protocol.TField("paragraphTitle", org.apache.thrift.protocol.TType.STRING, (short)2); - private static final org.apache.thrift.protocol.TField PARAGRAPH_TEXT_FIELD_DESC = new org.apache.thrift.protocol.TField("paragraphText", org.apache.thrift.protocol.TType.STRING, (short)3); - private static final org.apache.thrift.protocol.TField CONFIG_FIELD_DESC = new org.apache.thrift.protocol.TField("config", org.apache.thrift.protocol.TType.STRING, (short)4); - private static final org.apache.thrift.protocol.TField GUI_FIELD_DESC = new org.apache.thrift.protocol.TField("gui", org.apache.thrift.protocol.TType.STRING, (short)5); - private static final org.apache.thrift.protocol.TField RUNNERS_FIELD_DESC = new org.apache.thrift.protocol.TField("runners", org.apache.thrift.protocol.TType.STRING, (short)6); + private static final org.apache.thrift.protocol.TField NOTE_ID_FIELD_DESC = new org.apache.thrift.protocol.TField("noteId", org.apache.thrift.protocol.TType.STRING, (short)1); + private static final org.apache.thrift.protocol.TField PARAGRAPH_ID_FIELD_DESC = new org.apache.thrift.protocol.TField("paragraphId", org.apache.thrift.protocol.TType.STRING, (short)2); + private static final org.apache.thrift.protocol.TField PARAGRAPH_TITLE_FIELD_DESC = new org.apache.thrift.protocol.TField("paragraphTitle", org.apache.thrift.protocol.TType.STRING, (short)3); + private static final org.apache.thrift.protocol.TField PARAGRAPH_TEXT_FIELD_DESC = new org.apache.thrift.protocol.TField("paragraphText", org.apache.thrift.protocol.TType.STRING, (short)4); + private static final org.apache.thrift.protocol.TField CONFIG_FIELD_DESC = new org.apache.thrift.protocol.TField("config", org.apache.thrift.protocol.TType.STRING, (short)5); + private static final org.apache.thrift.protocol.TField GUI_FIELD_DESC = new org.apache.thrift.protocol.TField("gui", org.apache.thrift.protocol.TType.STRING, (short)6); + private static final org.apache.thrift.protocol.TField RUNNERS_FIELD_DESC = new org.apache.thrift.protocol.TField("runners", org.apache.thrift.protocol.TType.STRING, (short)7); private static final Map, SchemeFactory> schemes = new HashMap, SchemeFactory>(); static { @@ -46,6 +47,7 @@ public class RemoteInterpreterContext implements org.apache.thrift.TBase byName = new HashMap(); @@ -75,17 +78,19 @@ public enum _Fields implements org.apache.thrift.TFieldIdEnum { */ public static _Fields findByThriftId(int fieldId) { switch(fieldId) { - case 1: // PARAGRAPH_ID + case 1: // NOTE_ID + return NOTE_ID; + case 2: // PARAGRAPH_ID return PARAGRAPH_ID; - case 2: // PARAGRAPH_TITLE + case 3: // PARAGRAPH_TITLE return PARAGRAPH_TITLE; - case 3: // PARAGRAPH_TEXT + case 4: // PARAGRAPH_TEXT return PARAGRAPH_TEXT; - case 4: // CONFIG + case 5: // CONFIG return CONFIG; - case 5: // GUI + case 6: // GUI return GUI; - case 6: // RUNNERS + case 7: // RUNNERS return RUNNERS; default: return null; @@ -130,6 +135,8 @@ public String getFieldName() { public static final Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> metaDataMap; static { Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> tmpMap = new EnumMap<_Fields, org.apache.thrift.meta_data.FieldMetaData>(_Fields.class); + tmpMap.put(_Fields.NOTE_ID, new org.apache.thrift.meta_data.FieldMetaData("noteId", org.apache.thrift.TFieldRequirementType.DEFAULT, + new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRING))); tmpMap.put(_Fields.PARAGRAPH_ID, new org.apache.thrift.meta_data.FieldMetaData("paragraphId", org.apache.thrift.TFieldRequirementType.DEFAULT, new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRING))); tmpMap.put(_Fields.PARAGRAPH_TITLE, new org.apache.thrift.meta_data.FieldMetaData("paragraphTitle", org.apache.thrift.TFieldRequirementType.DEFAULT, @@ -150,6 +157,7 @@ public RemoteInterpreterContext() { } public RemoteInterpreterContext( + String noteId, String paragraphId, String paragraphTitle, String paragraphText, @@ -158,6 +166,7 @@ public RemoteInterpreterContext( String runners) { this(); + this.noteId = noteId; this.paragraphId = paragraphId; this.paragraphTitle = paragraphTitle; this.paragraphText = paragraphText; @@ -170,6 +179,9 @@ public RemoteInterpreterContext( * Performs a deep copy on other. */ public RemoteInterpreterContext(RemoteInterpreterContext other) { + if (other.isSetNoteId()) { + this.noteId = other.noteId; + } if (other.isSetParagraphId()) { this.paragraphId = other.paragraphId; } @@ -196,6 +208,7 @@ public RemoteInterpreterContext deepCopy() { @Override public void clear() { + this.noteId = null; this.paragraphId = null; this.paragraphTitle = null; this.paragraphText = null; @@ -204,6 +217,30 @@ public void clear() { this.runners = null; } + public String getNoteId() { + return this.noteId; + } + + public RemoteInterpreterContext setNoteId(String noteId) { + this.noteId = noteId; + return this; + } + + public void unsetNoteId() { + this.noteId = null; + } + + /** Returns true if field noteId is set (has been assigned a value) and false otherwise */ + public boolean isSetNoteId() { + return this.noteId != null; + } + + public void setNoteIdIsSet(boolean value) { + if (!value) { + this.noteId = null; + } + } + public String getParagraphId() { return this.paragraphId; } @@ -350,6 +387,14 @@ public void setRunnersIsSet(boolean value) { public void setFieldValue(_Fields field, Object value) { switch (field) { + case NOTE_ID: + if (value == null) { + unsetNoteId(); + } else { + setNoteId((String)value); + } + break; + case PARAGRAPH_ID: if (value == null) { unsetParagraphId(); @@ -403,6 +448,9 @@ public void setFieldValue(_Fields field, Object value) { public Object getFieldValue(_Fields field) { switch (field) { + case NOTE_ID: + return getNoteId(); + case PARAGRAPH_ID: return getParagraphId(); @@ -432,6 +480,8 @@ public boolean isSet(_Fields field) { } switch (field) { + case NOTE_ID: + return isSetNoteId(); case PARAGRAPH_ID: return isSetParagraphId(); case PARAGRAPH_TITLE: @@ -461,6 +511,15 @@ public boolean equals(RemoteInterpreterContext that) { if (that == null) return false; + boolean this_present_noteId = true && this.isSetNoteId(); + boolean that_present_noteId = true && that.isSetNoteId(); + if (this_present_noteId || that_present_noteId) { + if (!(this_present_noteId && that_present_noteId)) + return false; + if (!this.noteId.equals(that.noteId)) + return false; + } + boolean this_present_paragraphId = true && this.isSetParagraphId(); boolean that_present_paragraphId = true && that.isSetParagraphId(); if (this_present_paragraphId || that_present_paragraphId) { @@ -531,6 +590,16 @@ public int compareTo(RemoteInterpreterContext other) { int lastComparison = 0; RemoteInterpreterContext typedOther = (RemoteInterpreterContext)other; + lastComparison = Boolean.valueOf(isSetNoteId()).compareTo(typedOther.isSetNoteId()); + if (lastComparison != 0) { + return lastComparison; + } + if (isSetNoteId()) { + lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.noteId, typedOther.noteId); + if (lastComparison != 0) { + return lastComparison; + } + } lastComparison = Boolean.valueOf(isSetParagraphId()).compareTo(typedOther.isSetParagraphId()); if (lastComparison != 0) { return lastComparison; @@ -611,6 +680,14 @@ public String toString() { StringBuilder sb = new StringBuilder("RemoteInterpreterContext("); boolean first = true; + sb.append("noteId:"); + if (this.noteId == null) { + sb.append("null"); + } else { + sb.append(this.noteId); + } + first = false; + if (!first) sb.append(", "); sb.append("paragraphId:"); if (this.paragraphId == null) { sb.append("null"); @@ -701,7 +778,15 @@ public void read(org.apache.thrift.protocol.TProtocol iprot, RemoteInterpreterCo break; } switch (schemeField.id) { - case 1: // PARAGRAPH_ID + case 1: // NOTE_ID + if (schemeField.type == org.apache.thrift.protocol.TType.STRING) { + struct.noteId = iprot.readString(); + struct.setNoteIdIsSet(true); + } else { + org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type); + } + break; + case 2: // PARAGRAPH_ID if (schemeField.type == org.apache.thrift.protocol.TType.STRING) { struct.paragraphId = iprot.readString(); struct.setParagraphIdIsSet(true); @@ -709,7 +794,7 @@ public void read(org.apache.thrift.protocol.TProtocol iprot, RemoteInterpreterCo org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type); } break; - case 2: // PARAGRAPH_TITLE + case 3: // PARAGRAPH_TITLE if (schemeField.type == org.apache.thrift.protocol.TType.STRING) { struct.paragraphTitle = iprot.readString(); struct.setParagraphTitleIsSet(true); @@ -717,7 +802,7 @@ public void read(org.apache.thrift.protocol.TProtocol iprot, RemoteInterpreterCo org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type); } break; - case 3: // PARAGRAPH_TEXT + case 4: // PARAGRAPH_TEXT if (schemeField.type == org.apache.thrift.protocol.TType.STRING) { struct.paragraphText = iprot.readString(); struct.setParagraphTextIsSet(true); @@ -725,7 +810,7 @@ public void read(org.apache.thrift.protocol.TProtocol iprot, RemoteInterpreterCo org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type); } break; - case 4: // CONFIG + case 5: // CONFIG if (schemeField.type == org.apache.thrift.protocol.TType.STRING) { struct.config = iprot.readString(); struct.setConfigIsSet(true); @@ -733,7 +818,7 @@ public void read(org.apache.thrift.protocol.TProtocol iprot, RemoteInterpreterCo org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type); } break; - case 5: // GUI + case 6: // GUI if (schemeField.type == org.apache.thrift.protocol.TType.STRING) { struct.gui = iprot.readString(); struct.setGuiIsSet(true); @@ -741,7 +826,7 @@ public void read(org.apache.thrift.protocol.TProtocol iprot, RemoteInterpreterCo org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type); } break; - case 6: // RUNNERS + case 7: // RUNNERS if (schemeField.type == org.apache.thrift.protocol.TType.STRING) { struct.runners = iprot.readString(); struct.setRunnersIsSet(true); @@ -764,6 +849,11 @@ public void write(org.apache.thrift.protocol.TProtocol oprot, RemoteInterpreterC struct.validate(); oprot.writeStructBegin(STRUCT_DESC); + if (struct.noteId != null) { + oprot.writeFieldBegin(NOTE_ID_FIELD_DESC); + oprot.writeString(struct.noteId); + oprot.writeFieldEnd(); + } if (struct.paragraphId != null) { oprot.writeFieldBegin(PARAGRAPH_ID_FIELD_DESC); oprot.writeString(struct.paragraphId); @@ -812,25 +902,31 @@ private static class RemoteInterpreterContextTupleScheme extends TupleScheme resultHandler) throws org.apache.thrift.TException; - public void angularObjectUpdate(String name, String object, org.apache.thrift.async.AsyncMethodCallback resultHandler) throws org.apache.thrift.TException; + public void angularObjectUpdate(String name, String noteId, String object, org.apache.thrift.async.AsyncMethodCallback resultHandler) throws org.apache.thrift.TException; } @@ -351,16 +351,17 @@ public RemoteInterpreterEvent recv_getEvent() throws org.apache.thrift.TExceptio throw new org.apache.thrift.TApplicationException(org.apache.thrift.TApplicationException.MISSING_RESULT, "getEvent failed: unknown result"); } - public void angularObjectUpdate(String name, String object) throws org.apache.thrift.TException + public void angularObjectUpdate(String name, String noteId, String object) throws org.apache.thrift.TException { - send_angularObjectUpdate(name, object); + send_angularObjectUpdate(name, noteId, object); recv_angularObjectUpdate(); } - public void send_angularObjectUpdate(String name, String object) throws org.apache.thrift.TException + public void send_angularObjectUpdate(String name, String noteId, String object) throws org.apache.thrift.TException { angularObjectUpdate_args args = new angularObjectUpdate_args(); args.setName(name); + args.setNoteId(noteId); args.setObject(object); sendBase("angularObjectUpdate", args); } @@ -757,19 +758,21 @@ public RemoteInterpreterEvent getResult() throws org.apache.thrift.TException { } } - public void angularObjectUpdate(String name, String object, org.apache.thrift.async.AsyncMethodCallback resultHandler) throws org.apache.thrift.TException { + public void angularObjectUpdate(String name, String noteId, String object, org.apache.thrift.async.AsyncMethodCallback resultHandler) throws org.apache.thrift.TException { checkReady(); - angularObjectUpdate_call method_call = new angularObjectUpdate_call(name, object, resultHandler, this, ___protocolFactory, ___transport); + angularObjectUpdate_call method_call = new angularObjectUpdate_call(name, noteId, object, resultHandler, this, ___protocolFactory, ___transport); this.___currentMethod = method_call; ___manager.call(method_call); } public static class angularObjectUpdate_call extends org.apache.thrift.async.TAsyncMethodCall { private String name; + private String noteId; private String object; - public angularObjectUpdate_call(String name, String object, org.apache.thrift.async.AsyncMethodCallback resultHandler, org.apache.thrift.async.TAsyncClient client, org.apache.thrift.protocol.TProtocolFactory protocolFactory, org.apache.thrift.transport.TNonblockingTransport transport) throws org.apache.thrift.TException { + public angularObjectUpdate_call(String name, String noteId, String object, org.apache.thrift.async.AsyncMethodCallback resultHandler, org.apache.thrift.async.TAsyncClient client, org.apache.thrift.protocol.TProtocolFactory protocolFactory, org.apache.thrift.transport.TNonblockingTransport transport) throws org.apache.thrift.TException { super(client, protocolFactory, transport, resultHandler, false); this.name = name; + this.noteId = noteId; this.object = object; } @@ -777,6 +780,7 @@ public void write_args(org.apache.thrift.protocol.TProtocol prot) throws org.apa prot.writeMessageBegin(new org.apache.thrift.protocol.TMessage("angularObjectUpdate", org.apache.thrift.protocol.TMessageType.CALL, 0)); angularObjectUpdate_args args = new angularObjectUpdate_args(); args.setName(name); + args.setNoteId(noteId); args.setObject(object); args.write(prot); prot.writeMessageEnd(); @@ -1056,7 +1060,7 @@ protected boolean isOneway() { public angularObjectUpdate_result getResult(I iface, angularObjectUpdate_args args) throws org.apache.thrift.TException { angularObjectUpdate_result result = new angularObjectUpdate_result(); - iface.angularObjectUpdate(args.name, args.object); + iface.angularObjectUpdate(args.name, args.noteId, args.object); return result; } } @@ -8937,7 +8941,8 @@ public static class angularObjectUpdate_args implements org.apache.thrift.TBase< private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("angularObjectUpdate_args"); private static final org.apache.thrift.protocol.TField NAME_FIELD_DESC = new org.apache.thrift.protocol.TField("name", org.apache.thrift.protocol.TType.STRING, (short)1); - private static final org.apache.thrift.protocol.TField OBJECT_FIELD_DESC = new org.apache.thrift.protocol.TField("object", org.apache.thrift.protocol.TType.STRING, (short)2); + private static final org.apache.thrift.protocol.TField NOTE_ID_FIELD_DESC = new org.apache.thrift.protocol.TField("noteId", org.apache.thrift.protocol.TType.STRING, (short)2); + private static final org.apache.thrift.protocol.TField OBJECT_FIELD_DESC = new org.apache.thrift.protocol.TField("object", org.apache.thrift.protocol.TType.STRING, (short)3); private static final Map, SchemeFactory> schemes = new HashMap, SchemeFactory>(); static { @@ -8946,12 +8951,14 @@ public static class angularObjectUpdate_args implements org.apache.thrift.TBase< } public String name; // required + public String noteId; // required public String object; // required /** The set of fields this struct contains, along with convenience methods for finding and manipulating them. */ public enum _Fields implements org.apache.thrift.TFieldIdEnum { NAME((short)1, "name"), - OBJECT((short)2, "object"); + NOTE_ID((short)2, "noteId"), + OBJECT((short)3, "object"); private static final Map byName = new HashMap(); @@ -8968,7 +8975,9 @@ public static _Fields findByThriftId(int fieldId) { switch(fieldId) { case 1: // NAME return NAME; - case 2: // OBJECT + case 2: // NOTE_ID + return NOTE_ID; + case 3: // OBJECT return OBJECT; default: return null; @@ -9015,6 +9024,8 @@ public String getFieldName() { Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> tmpMap = new EnumMap<_Fields, org.apache.thrift.meta_data.FieldMetaData>(_Fields.class); tmpMap.put(_Fields.NAME, new org.apache.thrift.meta_data.FieldMetaData("name", org.apache.thrift.TFieldRequirementType.DEFAULT, new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRING))); + tmpMap.put(_Fields.NOTE_ID, new org.apache.thrift.meta_data.FieldMetaData("noteId", org.apache.thrift.TFieldRequirementType.DEFAULT, + new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRING))); tmpMap.put(_Fields.OBJECT, new org.apache.thrift.meta_data.FieldMetaData("object", org.apache.thrift.TFieldRequirementType.DEFAULT, new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRING))); metaDataMap = Collections.unmodifiableMap(tmpMap); @@ -9026,10 +9037,12 @@ public angularObjectUpdate_args() { public angularObjectUpdate_args( String name, + String noteId, String object) { this(); this.name = name; + this.noteId = noteId; this.object = object; } @@ -9040,6 +9053,9 @@ public angularObjectUpdate_args(angularObjectUpdate_args other) { if (other.isSetName()) { this.name = other.name; } + if (other.isSetNoteId()) { + this.noteId = other.noteId; + } if (other.isSetObject()) { this.object = other.object; } @@ -9052,6 +9068,7 @@ public angularObjectUpdate_args deepCopy() { @Override public void clear() { this.name = null; + this.noteId = null; this.object = null; } @@ -9079,6 +9096,30 @@ public void setNameIsSet(boolean value) { } } + public String getNoteId() { + return this.noteId; + } + + public angularObjectUpdate_args setNoteId(String noteId) { + this.noteId = noteId; + return this; + } + + public void unsetNoteId() { + this.noteId = null; + } + + /** Returns true if field noteId is set (has been assigned a value) and false otherwise */ + public boolean isSetNoteId() { + return this.noteId != null; + } + + public void setNoteIdIsSet(boolean value) { + if (!value) { + this.noteId = null; + } + } + public String getObject() { return this.object; } @@ -9113,6 +9154,14 @@ public void setFieldValue(_Fields field, Object value) { } break; + case NOTE_ID: + if (value == null) { + unsetNoteId(); + } else { + setNoteId((String)value); + } + break; + case OBJECT: if (value == null) { unsetObject(); @@ -9129,6 +9178,9 @@ public Object getFieldValue(_Fields field) { case NAME: return getName(); + case NOTE_ID: + return getNoteId(); + case OBJECT: return getObject(); @@ -9145,6 +9197,8 @@ public boolean isSet(_Fields field) { switch (field) { case NAME: return isSetName(); + case NOTE_ID: + return isSetNoteId(); case OBJECT: return isSetObject(); } @@ -9173,6 +9227,15 @@ public boolean equals(angularObjectUpdate_args that) { return false; } + boolean this_present_noteId = true && this.isSetNoteId(); + boolean that_present_noteId = true && that.isSetNoteId(); + if (this_present_noteId || that_present_noteId) { + if (!(this_present_noteId && that_present_noteId)) + return false; + if (!this.noteId.equals(that.noteId)) + return false; + } + boolean this_present_object = true && this.isSetObject(); boolean that_present_object = true && that.isSetObject(); if (this_present_object || that_present_object) { @@ -9208,6 +9271,16 @@ public int compareTo(angularObjectUpdate_args other) { return lastComparison; } } + lastComparison = Boolean.valueOf(isSetNoteId()).compareTo(typedOther.isSetNoteId()); + if (lastComparison != 0) { + return lastComparison; + } + if (isSetNoteId()) { + lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.noteId, typedOther.noteId); + if (lastComparison != 0) { + return lastComparison; + } + } lastComparison = Boolean.valueOf(isSetObject()).compareTo(typedOther.isSetObject()); if (lastComparison != 0) { return lastComparison; @@ -9246,6 +9319,14 @@ public String toString() { } first = false; if (!first) sb.append(", "); + sb.append("noteId:"); + if (this.noteId == null) { + sb.append("null"); + } else { + sb.append(this.noteId); + } + first = false; + if (!first) sb.append(", "); sb.append("object:"); if (this.object == null) { sb.append("null"); @@ -9304,7 +9385,15 @@ public void read(org.apache.thrift.protocol.TProtocol iprot, angularObjectUpdate org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type); } break; - case 2: // OBJECT + case 2: // NOTE_ID + if (schemeField.type == org.apache.thrift.protocol.TType.STRING) { + struct.noteId = iprot.readString(); + struct.setNoteIdIsSet(true); + } else { + org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type); + } + break; + case 3: // OBJECT if (schemeField.type == org.apache.thrift.protocol.TType.STRING) { struct.object = iprot.readString(); struct.setObjectIsSet(true); @@ -9332,6 +9421,11 @@ public void write(org.apache.thrift.protocol.TProtocol oprot, angularObjectUpdat oprot.writeString(struct.name); oprot.writeFieldEnd(); } + if (struct.noteId != null) { + oprot.writeFieldBegin(NOTE_ID_FIELD_DESC); + oprot.writeString(struct.noteId); + oprot.writeFieldEnd(); + } if (struct.object != null) { oprot.writeFieldBegin(OBJECT_FIELD_DESC); oprot.writeString(struct.object); @@ -9358,13 +9452,19 @@ public void write(org.apache.thrift.protocol.TProtocol prot, angularObjectUpdate if (struct.isSetName()) { optionals.set(0); } - if (struct.isSetObject()) { + if (struct.isSetNoteId()) { optionals.set(1); } - oprot.writeBitSet(optionals, 2); + if (struct.isSetObject()) { + optionals.set(2); + } + oprot.writeBitSet(optionals, 3); if (struct.isSetName()) { oprot.writeString(struct.name); } + if (struct.isSetNoteId()) { + oprot.writeString(struct.noteId); + } if (struct.isSetObject()) { oprot.writeString(struct.object); } @@ -9373,12 +9473,16 @@ public void write(org.apache.thrift.protocol.TProtocol prot, angularObjectUpdate @Override public void read(org.apache.thrift.protocol.TProtocol prot, angularObjectUpdate_args struct) throws org.apache.thrift.TException { TTupleProtocol iprot = (TTupleProtocol) prot; - BitSet incoming = iprot.readBitSet(2); + BitSet incoming = iprot.readBitSet(3); if (incoming.get(0)) { struct.name = iprot.readString(); struct.setNameIsSet(true); } if (incoming.get(1)) { + struct.noteId = iprot.readString(); + struct.setNoteIdIsSet(true); + } + if (incoming.get(2)) { struct.object = iprot.readString(); struct.setObjectIsSet(true); } diff --git a/zeppelin-interpreter/src/main/thrift/RemoteInterpreterService.thrift b/zeppelin-interpreter/src/main/thrift/RemoteInterpreterService.thrift index f9cd181e17e..f84e61d15ed 100644 --- a/zeppelin-interpreter/src/main/thrift/RemoteInterpreterService.thrift +++ b/zeppelin-interpreter/src/main/thrift/RemoteInterpreterService.thrift @@ -20,12 +20,13 @@ namespace java org.apache.zeppelin.interpreter.thrift struct RemoteInterpreterContext { - 1: string paragraphId, - 2: string paragraphTitle, - 3: string paragraphText, - 4: string config, // json serialized config - 5: string gui, // json serialized gui - 6: string runners // json serialized runner + 1: string noteId, + 2: string paragraphId, + 3: string paragraphTitle, + 4: string paragraphText, + 5: string config, // json serialized config + 6: string gui, // json serialized gui + 7: string runners // json serialized runner } struct RemoteInterpreterResult { @@ -64,5 +65,5 @@ service RemoteInterpreterService { string getStatus(1:string jobId); RemoteInterpreterEvent getEvent(); - void angularObjectUpdate(1: string name, 2: string object); + void angularObjectUpdate(1: string name, 2: string noteId, 3: string object); } \ No newline at end of file diff --git a/zeppelin-interpreter/src/test/java/org/apache/zeppelin/display/AngularObjectRegistryTest.java b/zeppelin-interpreter/src/test/java/org/apache/zeppelin/display/AngularObjectRegistryTest.java index b0ed45f3a94..b693e6a4f42 100644 --- a/zeppelin-interpreter/src/test/java/org/apache/zeppelin/display/AngularObjectRegistryTest.java +++ b/zeppelin-interpreter/src/test/java/org/apache/zeppelin/display/AngularObjectRegistryTest.java @@ -50,18 +50,27 @@ public void onRemove(String interpreterGroupId, AngularObject object) { } }); - registry.add("name1", "value1"); - assertEquals(1, registry.getAll().size()); + registry.add("name1", "value1", "note1"); + assertEquals(1, registry.getAll("note1").size()); assertEquals(1, onAdd.get()); assertEquals(0, onUpdate.get()); - registry.get("name1").set("newValue"); + registry.get("name1", "note1").set("newValue"); assertEquals(1, onUpdate.get()); - registry.remove("name1"); - assertEquals(0, registry.getAll().size()); + registry.remove("name1", "note1"); + assertEquals(0, registry.getAll("note1").size()); assertEquals(1, onRemove.get()); - assertEquals(null, registry.get("name1")); + assertEquals(null, registry.get("name1", "note1")); + + // namespace + registry.add("name1", "value11", "note2"); + assertEquals("value11", registry.get("name1", "note2").get()); + assertEquals(null, registry.get("name1", "note1")); + + // null namespace + registry.add("name1", "global1", null); + assertEquals("global1", registry.get("name1", null).get()); } } diff --git a/zeppelin-interpreter/src/test/java/org/apache/zeppelin/display/AngularObjectTest.java b/zeppelin-interpreter/src/test/java/org/apache/zeppelin/display/AngularObjectTest.java index 7ccc934c170..acb93d041b6 100644 --- a/zeppelin-interpreter/src/test/java/org/apache/zeppelin/display/AngularObjectTest.java +++ b/zeppelin-interpreter/src/test/java/org/apache/zeppelin/display/AngularObjectTest.java @@ -29,7 +29,7 @@ public class AngularObjectTest { @Test public void testListener() { final AtomicInteger updated = new AtomicInteger(0); - AngularObject ao = new AngularObject("name", "value", new AngularObjectListener() { + AngularObject ao = new AngularObject("name", "value", "note1", new AngularObjectListener() { @Override public void updated(AngularObject updatedObject) { @@ -55,7 +55,7 @@ public void updated(AngularObject updatedObject) { public void testWatcher() throws InterruptedException { final AtomicInteger updated = new AtomicInteger(0); final AtomicInteger onWatch = new AtomicInteger(0); - AngularObject ao = new AngularObject("name", "value", new AngularObjectListener() { + AngularObject ao = new AngularObject("name", "value", "note1", new AngularObjectListener() { @Override public void updated(AngularObject updatedObject) { updated.incrementAndGet(); diff --git a/zeppelin-interpreter/src/test/java/org/apache/zeppelin/interpreter/remote/RemoteAngularObjectTest.java b/zeppelin-interpreter/src/test/java/org/apache/zeppelin/interpreter/remote/RemoteAngularObjectTest.java index e6da1ec1df0..186b287ee34 100644 --- a/zeppelin-interpreter/src/test/java/org/apache/zeppelin/interpreter/remote/RemoteAngularObjectTest.java +++ b/zeppelin-interpreter/src/test/java/org/apache/zeppelin/interpreter/remote/RemoteAngularObjectTest.java @@ -76,6 +76,7 @@ public void setUp() throws Exception { intp.setInterpreterGroup(intpGroup); context = new InterpreterContext( + "note", "id", "title", "text", @@ -108,7 +109,7 @@ public void testAngularObjectCRUD() throws InterruptedException { result = ret.message().split(" "); assertEquals("1", result[0]); // size of registry assertEquals("0", result[1]); // num watcher called - assertEquals("v1", localRegistry.get("n1").get()); + assertEquals("v1", localRegistry.get("n1", "note").get()); // update object ret = intp.interpret("update n1 v11", context); @@ -116,7 +117,7 @@ public void testAngularObjectCRUD() throws InterruptedException { Thread.sleep(500); assertEquals("1", result[0]); // size of registry assertEquals("1", result[1]); // num watcher called - assertEquals("v11", localRegistry.get("n1").get()); + assertEquals("v11", localRegistry.get("n1", "note").get()); // remove object ret = intp.interpret("remove n1", context); @@ -124,7 +125,7 @@ public void testAngularObjectCRUD() throws InterruptedException { Thread.sleep(500); assertEquals("0", result[0]); // size of registry assertEquals("1", result[1]); // num watcher called - assertEquals(null, localRegistry.get("n1")); + assertEquals(null, localRegistry.get("n1", "note")); } @Override diff --git a/zeppelin-interpreter/src/test/java/org/apache/zeppelin/interpreter/remote/RemoteInterpreterTest.java b/zeppelin-interpreter/src/test/java/org/apache/zeppelin/interpreter/remote/RemoteInterpreterTest.java index 4338c50fdc4..4263dd8c230 100644 --- a/zeppelin-interpreter/src/test/java/org/apache/zeppelin/interpreter/remote/RemoteInterpreterTest.java +++ b/zeppelin-interpreter/src/test/java/org/apache/zeppelin/interpreter/remote/RemoteInterpreterTest.java @@ -110,6 +110,7 @@ public void testRemoteInterperterCall() throws TTransportException, IOException intpA.interpret("1", new InterpreterContext( + "note", "id", "title", "text", @@ -194,6 +195,7 @@ public void testRemoteSchedulerSharing() throws TTransportException, IOException long start = System.currentTimeMillis(); InterpreterResult ret = intpA.interpret("500", new InterpreterContext( + "note", "id", "title", "text", @@ -205,6 +207,7 @@ public void testRemoteSchedulerSharing() throws TTransportException, IOException ret = intpB.interpret("500", new InterpreterContext( + "note", "id", "title", "text", @@ -272,6 +275,7 @@ public Map info() { protected Object jobRun() throws Throwable { return intpA.interpret("500", new InterpreterContext( + "note", "jobA", "title", "text", @@ -305,6 +309,7 @@ public Map info() { protected Object jobRun() throws Throwable { return intpB.interpret("500", new InterpreterContext( + "note", "jobB", "title", "text", @@ -379,6 +384,7 @@ public Map info() { @Override protected Object jobRun() throws Throwable { InterpreterResult ret = intpA.interpret(getJobName(), new InterpreterContext( + "note", jobId, "title", "text", @@ -462,6 +468,7 @@ public Map info() { protected Object jobRun() throws Throwable { String stmt = Integer.toString(timeToSleep); InterpreterResult ret = intpA.interpret(stmt, new InterpreterContext( + "note", jobId, "title", "text", diff --git a/zeppelin-interpreter/src/test/java/org/apache/zeppelin/interpreter/remote/mock/MockInterpreterAngular.java b/zeppelin-interpreter/src/test/java/org/apache/zeppelin/interpreter/remote/mock/MockInterpreterAngular.java index ff1b8edeea0..df0afc59411 100644 --- a/zeppelin-interpreter/src/test/java/org/apache/zeppelin/interpreter/remote/mock/MockInterpreterAngular.java +++ b/zeppelin-interpreter/src/test/java/org/apache/zeppelin/interpreter/remote/mock/MockInterpreterAngular.java @@ -71,8 +71,8 @@ public InterpreterResult interpret(String st, InterpreterContext context) { AngularObjectRegistry registry = context.getAngularObjectRegistry(); if (cmd.equals("add")) { - registry.add(name, value); - registry.get(name).addWatcher(new AngularObjectWatcher(null) { + registry.add(name, context.getNoteId(), value); + registry.get(name, context.getNoteId()).addWatcher(new AngularObjectWatcher(null) { @Override public void watch(Object oldObject, Object newObject, @@ -82,9 +82,9 @@ public void watch(Object oldObject, Object newObject, }); } else if (cmd.equalsIgnoreCase("update")) { - registry.get(name).set(value); + registry.get(name, context.getNoteId()).set(value); } else if (cmd.equals("remove")) { - registry.remove(name); + registry.remove(name, context.getNoteId()); } try { @@ -92,7 +92,7 @@ public void watch(Object oldObject, Object newObject, } catch (InterruptedException e) { } - String msg = registry.getAll().size() + " " + Integer.toString(numWatch.get()); + String msg = registry.getAll(context.getNoteId()).size() + " " + Integer.toString(numWatch.get()); return new InterpreterResult(Code.SUCCESS, msg); } diff --git a/zeppelin-interpreter/src/test/java/org/apache/zeppelin/scheduler/RemoteSchedulerTest.java b/zeppelin-interpreter/src/test/java/org/apache/zeppelin/scheduler/RemoteSchedulerTest.java index 2a1075a4173..3c9a4759265 100644 --- a/zeppelin-interpreter/src/test/java/org/apache/zeppelin/scheduler/RemoteSchedulerTest.java +++ b/zeppelin-interpreter/src/test/java/org/apache/zeppelin/scheduler/RemoteSchedulerTest.java @@ -90,6 +90,7 @@ public Map info() { @Override protected Object jobRun() throws Throwable { intpA.interpret("1000", new InterpreterContext( + "note", "jobId", "title", "text", diff --git a/zeppelin-server/src/main/java/org/apache/zeppelin/socket/NotebookServer.java b/zeppelin-server/src/main/java/org/apache/zeppelin/socket/NotebookServer.java index 659d4df470f..20128627adc 100644 --- a/zeppelin-server/src/main/java/org/apache/zeppelin/socket/NotebookServer.java +++ b/zeppelin-server/src/main/java/org/apache/zeppelin/socket/NotebookServer.java @@ -422,6 +422,10 @@ private void angularObjectUpdated(WebSocket conn, Notebook notebook, String varName = (String) fromMessage.get("name"); Object varValue = fromMessage.get("value"); + AngularObject ao = null; + boolean global = false; + + // propagate change to (Remote) AngularObjectRegistry Note note = notebook.getNote(noteId); if (note != null) { @@ -434,37 +438,54 @@ private void angularObjectUpdated(WebSocket conn, Notebook notebook, if (interpreterGroupId.equals(setting.getInterpreterGroup().getId())) { AngularObjectRegistry angularObjectRegistry = setting .getInterpreterGroup().getAngularObjectRegistry(); - AngularObject ao = angularObjectRegistry.get(varName); + + // first trying to get local registry + ao = angularObjectRegistry.get(varName, noteId); if (ao == null) { - LOG.warn("Object {} is not binded", varName); + // then try global registry + ao = angularObjectRegistry.get(varName, null); + if (ao == null) { + LOG.warn("Object {} is not binded", varName); + } else { + // path from client -> server + ao.set(varValue, false); + global = true; + } } else { // path from client -> server ao.set(varValue, false); + global = false; } break; } } } - - // broadcast change to all web session that uses related interpreter. - for (Note n : notebook.getAllNotes()) { - List settings = note.getNoteReplLoader().getInterpreterSettings(); - for (InterpreterSetting setting : settings) { - if (setting.getInterpreterGroup() == null) { - continue; - } - - if (interpreterGroupId.equals(setting.getInterpreterGroup().getId())) { - AngularObjectRegistry angularObjectRegistry = setting - .getInterpreterGroup().getAngularObjectRegistry(); - AngularObject ao = angularObjectRegistry.get(varName); - this.broadcast(n.id(), new Message(OP.ANGULAR_OBJECT_UPDATE) - .put("angularObject", ao) - .put("interpreterGroupId", interpreterGroupId) - .put("noteId", n.id())); + + if (global) { // broadcast change to all web session that uses related interpreter. + for (Note n : notebook.getAllNotes()) { + List settings = note.getNoteReplLoader().getInterpreterSettings(); + for (InterpreterSetting setting : settings) { + if (setting.getInterpreterGroup() == null) { + continue; + } + + if (interpreterGroupId.equals(setting.getInterpreterGroup().getId())) { + AngularObjectRegistry angularObjectRegistry = setting + .getInterpreterGroup().getAngularObjectRegistry(); + this.broadcast(n.id(), new Message(OP.ANGULAR_OBJECT_UPDATE) + .put("angularObject", ao) + .put("interpreterGroupId", interpreterGroupId) + .put("noteId", n.id())); + } } } + } else { // broadcast to all web session for the note + this.broadcast( + note.id(), + new Message(OP.ANGULAR_OBJECT_UPDATE).put("angularObject", ao) + .put("interpreterGroupId", interpreterGroupId) + .put("noteId", note.id())); } } @@ -600,7 +621,7 @@ private void sendAllAngularObjects(Note note, WebSocket conn) { for (InterpreterSetting intpSetting : settings) { AngularObjectRegistry registry = intpSetting.getInterpreterGroup().getAngularObjectRegistry(); - List objects = registry.getAll(); + List objects = registry.getAllWithGlobal(note.id()); for (AngularObject object : objects) { conn.send(serializeMessage(new Message(OP.ANGULAR_OBJECT_UPDATE) .put("angularObject", object) @@ -621,6 +642,10 @@ public void onUpdate(String interpreterGroupId, AngularObject object) { List notes = notebook.getAllNotes(); for (Note note : notes) { + if (object.getNoteId() != null && !note.id().equals(object.getNoteId())) { + continue; + } + List intpSettings = note.getNoteReplLoader() .getInterpreterSettings(); @@ -634,14 +659,19 @@ public void onUpdate(String interpreterGroupId, AngularObject object) { .put("noteId", note.id())); } } - } + } } + @Override public void onRemove(String interpreterGroupId, AngularObject object) { Notebook notebook = notebook(); List notes = notebook.getAllNotes(); for (Note note : notes) { + if (object.getNoteId() != null && !note.id().equals(object.getNoteId())) { + continue; + } + List ids = note.getNoteReplLoader().getInterpreters(); for (String id : ids) { if (id.equals(interpreterGroupId)) { diff --git a/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Note.java b/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Note.java index 46b4c1addc5..32b00e6c5d1 100644 --- a/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Note.java +++ b/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Note.java @@ -295,7 +295,7 @@ private void snapshotAngularObjectRegistry() { for (InterpreterSetting setting : settings) { InterpreterGroup intpGroup = setting.getInterpreterGroup(); AngularObjectRegistry registry = intpGroup.getAngularObjectRegistry(); - angularObjects.put(intpGroup.getId(), registry.getAll()); + angularObjects.put(intpGroup.getId(), registry.getAll(id)); } } diff --git a/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Paragraph.java b/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Paragraph.java index 79dfc3dc079..5a431986bb5 100644 --- a/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Paragraph.java +++ b/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Paragraph.java @@ -233,7 +233,9 @@ private InterpreterContext getInterpreterContext() { runners.add(new ParagraphRunner(note, note.id(), p.getId())); } - InterpreterContext interpreterContext = new InterpreterContext(getId(), + InterpreterContext interpreterContext = new InterpreterContext( + note.id(), + getId(), this.getTitle(), this.getText(), this.getConfig(), diff --git a/zeppelin-zengine/src/test/java/org/apache/zeppelin/interpreter/InterpreterFactoryTest.java b/zeppelin-zengine/src/test/java/org/apache/zeppelin/interpreter/InterpreterFactoryTest.java index d7f4ab11d8f..585880b0110 100644 --- a/zeppelin-zengine/src/test/java/org/apache/zeppelin/interpreter/InterpreterFactoryTest.java +++ b/zeppelin-zengine/src/test/java/org/apache/zeppelin/interpreter/InterpreterFactoryTest.java @@ -55,7 +55,7 @@ public void setUp() throws Exception { System.setProperty(ConfVars.ZEPPELIN_INTERPRETERS.getVarName(), "org.apache.zeppelin.interpreter.mock.MockInterpreter1,org.apache.zeppelin.interpreter.mock.MockInterpreter2"); conf = new ZeppelinConfiguration(); factory = new InterpreterFactory(conf, new InterpreterOption(false), null); - context = new InterpreterContext("id", "title", "text", null, null, null, null); + context = new InterpreterContext("note", "id", "title", "text", null, null, null, null); } From 25cf5da68917e2d62c6251a91c97353b4a308983 Mon Sep 17 00:00:00 2001 From: Lee moon soo Date: Mon, 29 Jun 2015 11:59:58 -0700 Subject: [PATCH 02/17] Take all objects --- .../src/main/java/org/apache/zeppelin/notebook/Note.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Note.java b/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Note.java index 32b00e6c5d1..ad6197046b7 100644 --- a/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Note.java +++ b/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Note.java @@ -295,7 +295,7 @@ private void snapshotAngularObjectRegistry() { for (InterpreterSetting setting : settings) { InterpreterGroup intpGroup = setting.getInterpreterGroup(); AngularObjectRegistry registry = intpGroup.getAngularObjectRegistry(); - angularObjects.put(intpGroup.getId(), registry.getAll(id)); + angularObjects.put(intpGroup.getId(), registry.getAllWithGlobal(id)); } } From 093870cc625c2f7dcd7bc1f10b9904f4cc8203d1 Mon Sep 17 00:00:00 2001 From: Lee moon soo Date: Wed, 1 Jul 2015 10:38:21 -0700 Subject: [PATCH 03/17] save / load angular object --- .../zeppelin/socket/NotebookServer.java | 3 +++ .../org/apache/zeppelin/notebook/Note.java | 1 + .../apache/zeppelin/notebook/Notebook.java | 19 +++++++++++++++++++ 3 files changed, 23 insertions(+) diff --git a/zeppelin-server/src/main/java/org/apache/zeppelin/socket/NotebookServer.java b/zeppelin-server/src/main/java/org/apache/zeppelin/socket/NotebookServer.java index 20128627adc..d0cb516c351 100644 --- a/zeppelin-server/src/main/java/org/apache/zeppelin/socket/NotebookServer.java +++ b/zeppelin-server/src/main/java/org/apache/zeppelin/socket/NotebookServer.java @@ -639,6 +639,9 @@ public void onAdd(String interpreterGroupId, AngularObject object) { @Override public void onUpdate(String interpreterGroupId, AngularObject object) { Notebook notebook = notebook(); + if (notebook == null) { + return; + } List notes = notebook.getAllNotes(); for (Note note : notes) { diff --git a/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Note.java b/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Note.java index ad6197046b7..20cfa969c7b 100644 --- a/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Note.java +++ b/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Note.java @@ -300,6 +300,7 @@ private void snapshotAngularObjectRegistry() { } public void persist() throws IOException { + snapshotAngularObjectRegistry(); repo.save(this); } diff --git a/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Notebook.java b/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Notebook.java index 1b29509b322..da8d3b9bcd9 100644 --- a/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Notebook.java +++ b/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Notebook.java @@ -31,7 +31,9 @@ import org.apache.zeppelin.conf.ZeppelinConfiguration; import org.apache.zeppelin.conf.ZeppelinConfiguration.ConfVars; import org.apache.zeppelin.display.AngularObject; +import org.apache.zeppelin.display.AngularObjectRegistry; import org.apache.zeppelin.interpreter.InterpreterFactory; +import org.apache.zeppelin.interpreter.InterpreterGroup; import org.apache.zeppelin.interpreter.InterpreterSetting; import org.apache.zeppelin.notebook.repo.NotebookRepo; import org.apache.zeppelin.scheduler.SchedulerFactory; @@ -220,6 +222,23 @@ private Note loadNoteFromRepo(String id) { notes.put(note.id(), note); refreshCron(note.id()); } + + for (String name : angularObjectSnapshot.keySet()) { + SnapshotAngularObject snapshot = angularObjectSnapshot.get(name); + List settings = replFactory.get(); + for (InterpreterSetting setting : settings) { + InterpreterGroup intpGroup = setting.getInterpreterGroup(); + if (intpGroup.getId().equals(snapshot.getIntpGroupId())) { + AngularObjectRegistry registry = intpGroup.getAngularObjectRegistry(); + boolean localScope = snapshot.getAngularObject().getNoteId() != null; + if (localScope) { + registry.add(name, snapshot.getAngularObject().get(), note.id()); + } else { + registry.add(name, snapshot.getAngularObject().get(), null); + } + } + } + } return note; } From 3548cb5e3617f8bc1949e838d71e6384af84813d Mon Sep 17 00:00:00 2001 From: Lee moon soo Date: Fri, 3 Jul 2015 19:02:53 -0700 Subject: [PATCH 04/17] Fix test --- .../interpreter/remote/mock/MockInterpreterAngular.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zeppelin-interpreter/src/test/java/org/apache/zeppelin/interpreter/remote/mock/MockInterpreterAngular.java b/zeppelin-interpreter/src/test/java/org/apache/zeppelin/interpreter/remote/mock/MockInterpreterAngular.java index df0afc59411..3024f13b92b 100644 --- a/zeppelin-interpreter/src/test/java/org/apache/zeppelin/interpreter/remote/mock/MockInterpreterAngular.java +++ b/zeppelin-interpreter/src/test/java/org/apache/zeppelin/interpreter/remote/mock/MockInterpreterAngular.java @@ -71,7 +71,7 @@ public InterpreterResult interpret(String st, InterpreterContext context) { AngularObjectRegistry registry = context.getAngularObjectRegistry(); if (cmd.equals("add")) { - registry.add(name, context.getNoteId(), value); + registry.add(name, value, context.getNoteId()); registry.get(name, context.getNoteId()).addWatcher(new AngularObjectWatcher(null) { @Override From 378df682c3f1ea75af5119fd0aaf89eb2e311c50 Mon Sep 17 00:00:00 2001 From: Lee moon soo Date: Sat, 4 Jul 2015 15:42:31 -0700 Subject: [PATCH 05/17] Remove angularObject when notebook removal --- .../display/AngularObjectRegistry.java | 15 +++--- .../zeppelin/socket/NotebookServer.java | 1 - .../apache/zeppelin/notebook/Notebook.java | 7 +++ .../zeppelin/notebook/NotebookTest.java | 54 +++++++++++++++++++ 4 files changed, 70 insertions(+), 7 deletions(-) diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/display/AngularObjectRegistry.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/display/AngularObjectRegistry.java index 18a29f6b2d9..e3d4425f3bc 100644 --- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/display/AngularObjectRegistry.java +++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/display/AngularObjectRegistry.java @@ -121,6 +121,15 @@ public AngularObject remove(String name, String noteId) { } } + public void removeAll(String noteId) { + synchronized (registry) { + List all = getAll(noteId); + for (AngularObject ao : all) { + remove(ao.getName(), noteId); + } + } + } + public AngularObject get(String name, String noteId) { synchronized (registry) { Map r = getRegistryForKey(noteId); @@ -162,10 +171,4 @@ public List getAllWithGlobal(String noteId) { public String getInterpreterGroupId() { return interpreterId; } - - public void removeAll(String noteId) { - synchronized (registry) { - registry.remove(getRegistryKey(noteId)); - } - } } diff --git a/zeppelin-server/src/main/java/org/apache/zeppelin/socket/NotebookServer.java b/zeppelin-server/src/main/java/org/apache/zeppelin/socket/NotebookServer.java index d0cb516c351..842d1959c0e 100644 --- a/zeppelin-server/src/main/java/org/apache/zeppelin/socket/NotebookServer.java +++ b/zeppelin-server/src/main/java/org/apache/zeppelin/socket/NotebookServer.java @@ -353,7 +353,6 @@ private void removeNote(WebSocket conn, Notebook notebook, Message fromMessage) return; } Note note = notebook.getNote(noteId); - note.unpersist(); notebook.removeNote(noteId); removeNote(noteId); broadcastNoteList(); diff --git a/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Notebook.java b/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Notebook.java index da8d3b9bcd9..90bccfb9056 100644 --- a/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Notebook.java +++ b/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Notebook.java @@ -155,6 +155,13 @@ public void removeNote(String id) { synchronized (notes) { note = notes.remove(id); } + + // remove from all interpreter instance's angular object registry + for (InterpreterSetting settings : replFactory.get()) { + AngularObjectRegistry registry = settings.getInterpreterGroup().getAngularObjectRegistry(); + registry.removeAll(id); + } + try { note.unpersist(); } catch (IOException e) { diff --git a/zeppelin-zengine/src/test/java/org/apache/zeppelin/notebook/NotebookTest.java b/zeppelin-zengine/src/test/java/org/apache/zeppelin/notebook/NotebookTest.java index 0d4d1113370..08a00985594 100644 --- a/zeppelin-zengine/src/test/java/org/apache/zeppelin/notebook/NotebookTest.java +++ b/zeppelin-zengine/src/test/java/org/apache/zeppelin/notebook/NotebookTest.java @@ -28,6 +28,7 @@ import org.apache.zeppelin.conf.ZeppelinConfiguration; import org.apache.zeppelin.conf.ZeppelinConfiguration.ConfVars; +import org.apache.zeppelin.display.AngularObjectRegistry; import org.apache.zeppelin.interpreter.InterpreterFactory; import org.apache.zeppelin.interpreter.InterpreterOption; import org.apache.zeppelin.interpreter.mock.MockInterpreter1; @@ -160,6 +161,59 @@ public void testSchedule() throws InterruptedException, IOException{ assertEquals(dateFinished, p.getDateFinished()); } + @Test + public void testAngularObjectRemovalOnNotebookRemove() throws InterruptedException, + IOException { + // create a note and a paragraph + Note note = notebook.createNote(); + note.getNoteReplLoader().setInterpreters(factory.getDefaultInterpreterSettingList()); + + AngularObjectRegistry registry = note.getNoteReplLoader() + .getInterpreterSettings().get(0).getInterpreterGroup() + .getAngularObjectRegistry(); + + // add local scope object + registry.add("o1", "object1", note.id()); + // add global scope object + registry.add("o2", "object2", null); + + // remove notebook + notebook.removeNote(note.id()); + + // local object should be removed + assertNull(registry.get("o1", note.id())); + // global object sould be remained + assertNotNull(registry.get("o2", null)); + } + + @Test + public void testAngularObjectRemovalOnInterpreterRestart() throws InterruptedException, + IOException { + // create a note and a paragraph + Note note = notebook.createNote(); + note.getNoteReplLoader().setInterpreters(factory.getDefaultInterpreterSettingList()); + + AngularObjectRegistry registry = note.getNoteReplLoader() + .getInterpreterSettings().get(0).getInterpreterGroup() + .getAngularObjectRegistry(); + + // add local scope object + registry.add("o1", "object1", note.id()); + // add global scope object + registry.add("o2", "object2", null); + + // restart interpreter + factory.restart(note.getNoteReplLoader().getInterpreterSettings().get(0).id()); + registry = note.getNoteReplLoader() + .getInterpreterSettings().get(0).getInterpreterGroup() + .getAngularObjectRegistry(); + + // local and global scope object should be removed + assertNull(registry.get("o1", note.id())); + assertNull(registry.get("o2", null)); + notebook.removeNote(note.id()); + } + private void delete(File file){ if(file.isFile()) file.delete(); else if(file.isDirectory()){ From 195a8c9a62da59c8855252048a87523a2fc152e8 Mon Sep 17 00:00:00 2001 From: Lee moon soo Date: Sat, 4 Jul 2015 15:42:56 -0700 Subject: [PATCH 06/17] Add Unbind api for global scope object --- .../org/apache/zeppelin/spark/ZeppelinContext.java | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/spark/src/main/java/org/apache/zeppelin/spark/ZeppelinContext.java b/spark/src/main/java/org/apache/zeppelin/spark/ZeppelinContext.java index 4299eebd06d..6cb94d9e927 100644 --- a/spark/src/main/java/org/apache/zeppelin/spark/ZeppelinContext.java +++ b/spark/src/main/java/org/apache/zeppelin/spark/ZeppelinContext.java @@ -631,9 +631,16 @@ public void angularUnwatchGlobal(String name) { * @param name */ public void angularUnbind(String name) { - AngularObjectRegistry registry = interpreterContext.getAngularObjectRegistry(); String noteId = interpreterContext.getNoteId(); - registry.remove(name, noteId); + angularUnbind(name, noteId); + } + + /** + * Remove angular variable and all the watchers. + * @param name + */ + public void angularUnbindGlobal(String name) { + angularUnbind(name, null); } /** From 1c695c025165b0b9a9104b410e162f3f875abb52 Mon Sep 17 00:00:00 2001 From: Lee moon soo Date: Sat, 4 Jul 2015 18:17:41 -0700 Subject: [PATCH 07/17] Send angularObject add/remove event from ZeppelinServer to remote process --- .../display/AngularObjectRegistry.java | 10 +- .../AngularObjectRegistryListener.java | 2 +- .../remote/RemoteAngularObjectRegistry.java | 75 +- .../remote/RemoteInterpreterEventPoller.java | 1 + .../remote/RemoteInterpreterServer.java | 77 +- .../thrift/RemoteInterpreterService.java | 1666 +++++++++++++++++ .../thrift/RemoteInterpreterService.thrift | 2 + .../display/AngularObjectRegistryTest.java | 2 +- .../remote/RemoteAngularObjectTest.java | 49 +- .../zeppelin/socket/NotebookServer.java | 9 +- .../apache/zeppelin/notebook/Notebook.java | 20 +- 11 files changed, 1880 insertions(+), 33 deletions(-) diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/display/AngularObjectRegistry.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/display/AngularObjectRegistry.java index e3d4425f3bc..d6bab7b732c 100644 --- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/display/AngularObjectRegistry.java +++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/display/AngularObjectRegistry.java @@ -59,7 +59,7 @@ public AngularObjectRegistryListener getListener() { } /** - * Add object into global registry + * Add object into registry * @param name * @param o * @param noteId noteId belonging to. null for global object. @@ -111,11 +111,15 @@ protected AngularObjectListener getAngularObjectListener() { } public AngularObject remove(String name, String noteId) { + return remove(name, noteId, true); + } + + public AngularObject remove(String name, String noteId, boolean emit) { synchronized (registry) { Map r = getRegistryForKey(noteId); AngularObject o = r.remove(name); - if (listener != null) { - listener.onRemove(interpreterId, o);; + if (listener != null && emit) { + listener.onRemove(interpreterId, name, noteId);; } return o; } diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/display/AngularObjectRegistryListener.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/display/AngularObjectRegistryListener.java index 3f08efae4a2..3ba57d7b1af 100644 --- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/display/AngularObjectRegistryListener.java +++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/display/AngularObjectRegistryListener.java @@ -24,5 +24,5 @@ public interface AngularObjectRegistryListener { public void onAdd(String interpreterGroupId, AngularObject object); public void onUpdate(String interpreterGroupId, AngularObject object); - public void onRemove(String interpreterGroupId, AngularObject object); + public void onRemove(String interpreterGroupId, String name, String noteId); } diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/remote/RemoteAngularObjectRegistry.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/remote/RemoteAngularObjectRegistry.java index 09d4152c38a..b7ac014c2e8 100644 --- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/remote/RemoteAngularObjectRegistry.java +++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/remote/RemoteAngularObjectRegistry.java @@ -17,18 +17,25 @@ package org.apache.zeppelin.interpreter.remote; +import java.util.List; + import org.apache.zeppelin.display.AngularObject; import org.apache.zeppelin.display.AngularObjectRegistry; import org.apache.zeppelin.display.AngularObjectRegistryListener; import org.apache.zeppelin.interpreter.Interpreter; import org.apache.zeppelin.interpreter.InterpreterGroup; import org.apache.zeppelin.interpreter.WrappedInterpreter; +import org.apache.zeppelin.interpreter.thrift.RemoteInterpreterService.Client; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.gson.Gson; /** * */ public class RemoteAngularObjectRegistry extends AngularObjectRegistry { - + Logger logger = LoggerFactory.getLogger(RemoteAngularObjectRegistry.class); private InterpreterGroup interpreterGroup; public RemoteAngularObjectRegistry(String interpreterId, @@ -54,6 +61,72 @@ private RemoteInterpreterProcess getRemoteInterpreterProcess() { } } + /** + * When ZeppelinServer side code want to add angularObject to the registry, + * this method should be used instead of add() + * @param name + * @param o + * @param noteId + * @return + */ + public AngularObject addAndNotifyRemoteProcess(String name, Object o, String noteId) { + Gson gson = new Gson(); + RemoteInterpreterProcess remoteInterpreterProcess = getRemoteInterpreterProcess(); + if (!remoteInterpreterProcess.isRunning()) { + return null; + } + + Client client = null; + try { + client = remoteInterpreterProcess.getClient(); + client.angularObjectAdd(name, noteId, gson.toJson(o)); + return super.add(name, o, noteId, true); + } catch (Exception e) { + logger.error("Error", e); + } finally { + if (client != null) { + remoteInterpreterProcess.releaseClient(client); + } + } + return null; + } + + /** + * When ZeppelinServer side code want to remove angularObject from the registry, + * this method should be used instead of remove() + * @param name + * @param noteId + * @param emit + * @return + */ + public AngularObject removeAndNotifyRemoteProcess(String name, String noteId) { + RemoteInterpreterProcess remoteInterpreterProcess = getRemoteInterpreterProcess(); + if (!remoteInterpreterProcess.isRunning()) { + return null; + } + + Client client = null; + try { + client = remoteInterpreterProcess.getClient(); + client.angularObjectRemove(name, noteId); + return super.remove(name, noteId); + } catch (Exception e) { + logger.error("Error", e); + } finally { + if (client != null) { + remoteInterpreterProcess.releaseClient(client); + } + } + return null; + } + + public void removeAllAndNotifyRemoteProcess(String noteId) { + List all = getAll(noteId); + for (AngularObject ao : all) { + removeAndNotifyRemoteProcess(ao.getName(), noteId); + } + } + @Override protected AngularObject createNewAngularObject(String name, Object o, String noteId) { RemoteInterpreterProcess remoteInterpreterProcess = getRemoteInterpreterProcess(); diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/remote/RemoteInterpreterEventPoller.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/remote/RemoteInterpreterEventPoller.java index 3a097ca17b3..373efef5504 100644 --- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/remote/RemoteInterpreterEventPoller.java +++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/remote/RemoteInterpreterEventPoller.java @@ -109,6 +109,7 @@ public void run() { interpreterProcess.getInterpreterContextRunnerPool().run( runnerFromRemote.getNoteId(), runnerFromRemote.getParagraphId()); } + logger.info("I've got event from remoteproceess {}", event.getType()); } catch (Exception e) { logger.error("Can't handle event " + event, e); } diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/remote/RemoteInterpreterServer.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/remote/RemoteInterpreterServer.java index b6a0a7df98e..16b188394d0 100644 --- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/remote/RemoteInterpreterServer.java +++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/remote/RemoteInterpreterServer.java @@ -21,6 +21,7 @@ import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.net.URL; +import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; @@ -396,9 +397,13 @@ public void onUpdate(String interpreterGroupId, AngularObject object) { } @Override - public void onRemove(String interpreterGroupId, AngularObject object) { + public void onRemove(String interpreterGroupId, String name, String noteId) { + Map removeObject = new HashMap(); + removeObject.put("name", name); + removeObject.put("noteId", noteId); + sendEvent(new RemoteInterpreterEvent( - RemoteInterpreterEventType.ANGULAR_OBJECT_REMOVE, gson.toJson(object))); + RemoteInterpreterEventType.ANGULAR_OBJECT_REMOVE, gson.toJson(removeObject))); } private void sendEvent(RemoteInterpreterEvent event) { @@ -441,13 +446,8 @@ public void angularObjectUpdate(String name, String noteId, String object) // first try local objects AngularObject ao = registry.get(name, noteId); if (ao == null) { - // then try global objects - ao = registry.get(name, null); - - if (ao == null) { - logger.error("Angular object {} not exists", name); - return; - } + logger.error("Angular object {} not exists", name); + return; } if (object == null) { @@ -456,8 +456,8 @@ public void angularObjectUpdate(String name, String noteId, String object) } Object oldObject = ao.get(); + Object value = null; if (oldObject != null) { // first try with previous object's type - Object value; try { value = gson.fromJson(object, oldObject.getClass()); ao.set(value, false); @@ -468,9 +468,60 @@ public void angularObjectUpdate(String name, String noteId, String object) } // Generic java object type for json. - Map value = gson.fromJson(object, - new TypeToken>() { - }.getType()); + if (value == null) { + try { + value = gson.fromJson(object, + new TypeToken>() { + }.getType()); + } catch (Exception e) { + // no lock + } + } + + // try string object type at last + if (value == null) { + value = gson.fromJson(object, String.class); + } + ao.set(value, false); } + + /** + * When zeppelinserver initiate angular object add. + * Dont't need to emit event to zeppelin server + */ + @Override + public void angularObjectAdd(String name, String noteId, String object) + throws TException { + AngularObjectRegistry registry = interpreterGroup.getAngularObjectRegistry(); + // first try local objects + AngularObject ao = registry.get(name, noteId); + if (ao != null) { + angularObjectUpdate(name, noteId, object); + return; + } + + // Generic java object type for json. + Object value = null; + try { + value = gson.fromJson(object, + new TypeToken>() { + }.getType()); + } catch (Exception e) { + // nolock + } + + // try string object type at last + if (value == null) { + value = gson.fromJson(object, String.class); + } + + registry.add(name, value, noteId, false); + } + + @Override + public void angularObjectRemove(String name, String noteId) throws TException { + AngularObjectRegistry registry = interpreterGroup.getAngularObjectRegistry(); + registry.remove(name, noteId, false); + } } diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterService.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterService.java index 2e0f850e5d3..b9a8dae79e4 100644 --- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterService.java +++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterService.java @@ -58,6 +58,10 @@ public interface Iface { public void angularObjectUpdate(String name, String noteId, String object) throws org.apache.thrift.TException; + public void angularObjectAdd(String name, String noteId, String object) throws org.apache.thrift.TException; + + public void angularObjectRemove(String name, String noteId) throws org.apache.thrift.TException; + } public interface AsyncIface { @@ -86,6 +90,10 @@ public interface AsyncIface { public void angularObjectUpdate(String name, String noteId, String object, org.apache.thrift.async.AsyncMethodCallback resultHandler) throws org.apache.thrift.TException; + public void angularObjectAdd(String name, String noteId, String object, org.apache.thrift.async.AsyncMethodCallback resultHandler) throws org.apache.thrift.TException; + + public void angularObjectRemove(String name, String noteId, org.apache.thrift.async.AsyncMethodCallback resultHandler) throws org.apache.thrift.TException; + } public static class Client extends org.apache.thrift.TServiceClient implements Iface { @@ -373,6 +381,49 @@ public void recv_angularObjectUpdate() throws org.apache.thrift.TException return; } + public void angularObjectAdd(String name, String noteId, String object) throws org.apache.thrift.TException + { + send_angularObjectAdd(name, noteId, object); + recv_angularObjectAdd(); + } + + public void send_angularObjectAdd(String name, String noteId, String object) throws org.apache.thrift.TException + { + angularObjectAdd_args args = new angularObjectAdd_args(); + args.setName(name); + args.setNoteId(noteId); + args.setObject(object); + sendBase("angularObjectAdd", args); + } + + public void recv_angularObjectAdd() throws org.apache.thrift.TException + { + angularObjectAdd_result result = new angularObjectAdd_result(); + receiveBase(result, "angularObjectAdd"); + return; + } + + public void angularObjectRemove(String name, String noteId) throws org.apache.thrift.TException + { + send_angularObjectRemove(name, noteId); + recv_angularObjectRemove(); + } + + public void send_angularObjectRemove(String name, String noteId) throws org.apache.thrift.TException + { + angularObjectRemove_args args = new angularObjectRemove_args(); + args.setName(name); + args.setNoteId(noteId); + sendBase("angularObjectRemove", args); + } + + public void recv_angularObjectRemove() throws org.apache.thrift.TException + { + angularObjectRemove_result result = new angularObjectRemove_result(); + receiveBase(result, "angularObjectRemove"); + return; + } + } public static class AsyncClient extends org.apache.thrift.async.TAsyncClient implements AsyncIface { public static class Factory implements org.apache.thrift.async.TAsyncClientFactory { @@ -796,6 +847,79 @@ public void getResult() throws org.apache.thrift.TException { } } + public void angularObjectAdd(String name, String noteId, String object, org.apache.thrift.async.AsyncMethodCallback resultHandler) throws org.apache.thrift.TException { + checkReady(); + angularObjectAdd_call method_call = new angularObjectAdd_call(name, noteId, object, resultHandler, this, ___protocolFactory, ___transport); + this.___currentMethod = method_call; + ___manager.call(method_call); + } + + public static class angularObjectAdd_call extends org.apache.thrift.async.TAsyncMethodCall { + private String name; + private String noteId; + private String object; + public angularObjectAdd_call(String name, String noteId, String object, org.apache.thrift.async.AsyncMethodCallback resultHandler, org.apache.thrift.async.TAsyncClient client, org.apache.thrift.protocol.TProtocolFactory protocolFactory, org.apache.thrift.transport.TNonblockingTransport transport) throws org.apache.thrift.TException { + super(client, protocolFactory, transport, resultHandler, false); + this.name = name; + this.noteId = noteId; + this.object = object; + } + + public void write_args(org.apache.thrift.protocol.TProtocol prot) throws org.apache.thrift.TException { + prot.writeMessageBegin(new org.apache.thrift.protocol.TMessage("angularObjectAdd", org.apache.thrift.protocol.TMessageType.CALL, 0)); + angularObjectAdd_args args = new angularObjectAdd_args(); + args.setName(name); + args.setNoteId(noteId); + args.setObject(object); + args.write(prot); + prot.writeMessageEnd(); + } + + public void getResult() throws org.apache.thrift.TException { + if (getState() != org.apache.thrift.async.TAsyncMethodCall.State.RESPONSE_READ) { + throw new IllegalStateException("Method call not finished!"); + } + org.apache.thrift.transport.TMemoryInputTransport memoryTransport = new org.apache.thrift.transport.TMemoryInputTransport(getFrameBuffer().array()); + org.apache.thrift.protocol.TProtocol prot = client.getProtocolFactory().getProtocol(memoryTransport); + (new Client(prot)).recv_angularObjectAdd(); + } + } + + public void angularObjectRemove(String name, String noteId, org.apache.thrift.async.AsyncMethodCallback resultHandler) throws org.apache.thrift.TException { + checkReady(); + angularObjectRemove_call method_call = new angularObjectRemove_call(name, noteId, resultHandler, this, ___protocolFactory, ___transport); + this.___currentMethod = method_call; + ___manager.call(method_call); + } + + public static class angularObjectRemove_call extends org.apache.thrift.async.TAsyncMethodCall { + private String name; + private String noteId; + public angularObjectRemove_call(String name, String noteId, org.apache.thrift.async.AsyncMethodCallback resultHandler, org.apache.thrift.async.TAsyncClient client, org.apache.thrift.protocol.TProtocolFactory protocolFactory, org.apache.thrift.transport.TNonblockingTransport transport) throws org.apache.thrift.TException { + super(client, protocolFactory, transport, resultHandler, false); + this.name = name; + this.noteId = noteId; + } + + public void write_args(org.apache.thrift.protocol.TProtocol prot) throws org.apache.thrift.TException { + prot.writeMessageBegin(new org.apache.thrift.protocol.TMessage("angularObjectRemove", org.apache.thrift.protocol.TMessageType.CALL, 0)); + angularObjectRemove_args args = new angularObjectRemove_args(); + args.setName(name); + args.setNoteId(noteId); + args.write(prot); + prot.writeMessageEnd(); + } + + public void getResult() throws org.apache.thrift.TException { + if (getState() != org.apache.thrift.async.TAsyncMethodCall.State.RESPONSE_READ) { + throw new IllegalStateException("Method call not finished!"); + } + org.apache.thrift.transport.TMemoryInputTransport memoryTransport = new org.apache.thrift.transport.TMemoryInputTransport(getFrameBuffer().array()); + org.apache.thrift.protocol.TProtocol prot = client.getProtocolFactory().getProtocol(memoryTransport); + (new Client(prot)).recv_angularObjectRemove(); + } + } + } public static class Processor extends org.apache.thrift.TBaseProcessor implements org.apache.thrift.TProcessor { @@ -821,6 +945,8 @@ protected Processor(I iface, Map extends org.apache.thrift.ProcessFunction { + public angularObjectAdd() { + super("angularObjectAdd"); + } + + public angularObjectAdd_args getEmptyArgsInstance() { + return new angularObjectAdd_args(); + } + + protected boolean isOneway() { + return false; + } + + public angularObjectAdd_result getResult(I iface, angularObjectAdd_args args) throws org.apache.thrift.TException { + angularObjectAdd_result result = new angularObjectAdd_result(); + iface.angularObjectAdd(args.name, args.noteId, args.object); + return result; + } + } + + public static class angularObjectRemove extends org.apache.thrift.ProcessFunction { + public angularObjectRemove() { + super("angularObjectRemove"); + } + + public angularObjectRemove_args getEmptyArgsInstance() { + return new angularObjectRemove_args(); + } + + protected boolean isOneway() { + return false; + } + + public angularObjectRemove_result getResult(I iface, angularObjectRemove_args args) throws org.apache.thrift.TException { + angularObjectRemove_result result = new angularObjectRemove_result(); + iface.angularObjectRemove(args.name, args.noteId); + return result; + } + } + } public static class createInterpreter_args implements org.apache.thrift.TBase, java.io.Serializable, Cloneable { @@ -9737,4 +9903,1504 @@ public void read(org.apache.thrift.protocol.TProtocol prot, angularObjectUpdate_ } + public static class angularObjectAdd_args implements org.apache.thrift.TBase, java.io.Serializable, Cloneable { + private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("angularObjectAdd_args"); + + private static final org.apache.thrift.protocol.TField NAME_FIELD_DESC = new org.apache.thrift.protocol.TField("name", org.apache.thrift.protocol.TType.STRING, (short)1); + private static final org.apache.thrift.protocol.TField NOTE_ID_FIELD_DESC = new org.apache.thrift.protocol.TField("noteId", org.apache.thrift.protocol.TType.STRING, (short)2); + private static final org.apache.thrift.protocol.TField OBJECT_FIELD_DESC = new org.apache.thrift.protocol.TField("object", org.apache.thrift.protocol.TType.STRING, (short)3); + + private static final Map, SchemeFactory> schemes = new HashMap, SchemeFactory>(); + static { + schemes.put(StandardScheme.class, new angularObjectAdd_argsStandardSchemeFactory()); + schemes.put(TupleScheme.class, new angularObjectAdd_argsTupleSchemeFactory()); + } + + public String name; // required + public String noteId; // required + public String object; // required + + /** The set of fields this struct contains, along with convenience methods for finding and manipulating them. */ + public enum _Fields implements org.apache.thrift.TFieldIdEnum { + NAME((short)1, "name"), + NOTE_ID((short)2, "noteId"), + OBJECT((short)3, "object"); + + private static final Map byName = new HashMap(); + + static { + for (_Fields field : EnumSet.allOf(_Fields.class)) { + byName.put(field.getFieldName(), field); + } + } + + /** + * Find the _Fields constant that matches fieldId, or null if its not found. + */ + public static _Fields findByThriftId(int fieldId) { + switch(fieldId) { + case 1: // NAME + return NAME; + case 2: // NOTE_ID + return NOTE_ID; + case 3: // OBJECT + return OBJECT; + default: + return null; + } + } + + /** + * Find the _Fields constant that matches fieldId, throwing an exception + * if it is not found. + */ + public static _Fields findByThriftIdOrThrow(int fieldId) { + _Fields fields = findByThriftId(fieldId); + if (fields == null) throw new IllegalArgumentException("Field " + fieldId + " doesn't exist!"); + return fields; + } + + /** + * Find the _Fields constant that matches name, or null if its not found. + */ + public static _Fields findByName(String name) { + return byName.get(name); + } + + private final short _thriftId; + private final String _fieldName; + + _Fields(short thriftId, String fieldName) { + _thriftId = thriftId; + _fieldName = fieldName; + } + + public short getThriftFieldId() { + return _thriftId; + } + + public String getFieldName() { + return _fieldName; + } + } + + // isset id assignments + public static final Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> metaDataMap; + static { + Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> tmpMap = new EnumMap<_Fields, org.apache.thrift.meta_data.FieldMetaData>(_Fields.class); + tmpMap.put(_Fields.NAME, new org.apache.thrift.meta_data.FieldMetaData("name", org.apache.thrift.TFieldRequirementType.DEFAULT, + new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRING))); + tmpMap.put(_Fields.NOTE_ID, new org.apache.thrift.meta_data.FieldMetaData("noteId", org.apache.thrift.TFieldRequirementType.DEFAULT, + new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRING))); + tmpMap.put(_Fields.OBJECT, new org.apache.thrift.meta_data.FieldMetaData("object", org.apache.thrift.TFieldRequirementType.DEFAULT, + new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRING))); + metaDataMap = Collections.unmodifiableMap(tmpMap); + org.apache.thrift.meta_data.FieldMetaData.addStructMetaDataMap(angularObjectAdd_args.class, metaDataMap); + } + + public angularObjectAdd_args() { + } + + public angularObjectAdd_args( + String name, + String noteId, + String object) + { + this(); + this.name = name; + this.noteId = noteId; + this.object = object; + } + + /** + * Performs a deep copy on other. + */ + public angularObjectAdd_args(angularObjectAdd_args other) { + if (other.isSetName()) { + this.name = other.name; + } + if (other.isSetNoteId()) { + this.noteId = other.noteId; + } + if (other.isSetObject()) { + this.object = other.object; + } + } + + public angularObjectAdd_args deepCopy() { + return new angularObjectAdd_args(this); + } + + @Override + public void clear() { + this.name = null; + this.noteId = null; + this.object = null; + } + + public String getName() { + return this.name; + } + + public angularObjectAdd_args setName(String name) { + this.name = name; + return this; + } + + public void unsetName() { + this.name = null; + } + + /** Returns true if field name is set (has been assigned a value) and false otherwise */ + public boolean isSetName() { + return this.name != null; + } + + public void setNameIsSet(boolean value) { + if (!value) { + this.name = null; + } + } + + public String getNoteId() { + return this.noteId; + } + + public angularObjectAdd_args setNoteId(String noteId) { + this.noteId = noteId; + return this; + } + + public void unsetNoteId() { + this.noteId = null; + } + + /** Returns true if field noteId is set (has been assigned a value) and false otherwise */ + public boolean isSetNoteId() { + return this.noteId != null; + } + + public void setNoteIdIsSet(boolean value) { + if (!value) { + this.noteId = null; + } + } + + public String getObject() { + return this.object; + } + + public angularObjectAdd_args setObject(String object) { + this.object = object; + return this; + } + + public void unsetObject() { + this.object = null; + } + + /** Returns true if field object is set (has been assigned a value) and false otherwise */ + public boolean isSetObject() { + return this.object != null; + } + + public void setObjectIsSet(boolean value) { + if (!value) { + this.object = null; + } + } + + public void setFieldValue(_Fields field, Object value) { + switch (field) { + case NAME: + if (value == null) { + unsetName(); + } else { + setName((String)value); + } + break; + + case NOTE_ID: + if (value == null) { + unsetNoteId(); + } else { + setNoteId((String)value); + } + break; + + case OBJECT: + if (value == null) { + unsetObject(); + } else { + setObject((String)value); + } + break; + + } + } + + public Object getFieldValue(_Fields field) { + switch (field) { + case NAME: + return getName(); + + case NOTE_ID: + return getNoteId(); + + case OBJECT: + return getObject(); + + } + throw new IllegalStateException(); + } + + /** Returns true if field corresponding to fieldID is set (has been assigned a value) and false otherwise */ + public boolean isSet(_Fields field) { + if (field == null) { + throw new IllegalArgumentException(); + } + + switch (field) { + case NAME: + return isSetName(); + case NOTE_ID: + return isSetNoteId(); + case OBJECT: + return isSetObject(); + } + throw new IllegalStateException(); + } + + @Override + public boolean equals(Object that) { + if (that == null) + return false; + if (that instanceof angularObjectAdd_args) + return this.equals((angularObjectAdd_args)that); + return false; + } + + public boolean equals(angularObjectAdd_args that) { + if (that == null) + return false; + + boolean this_present_name = true && this.isSetName(); + boolean that_present_name = true && that.isSetName(); + if (this_present_name || that_present_name) { + if (!(this_present_name && that_present_name)) + return false; + if (!this.name.equals(that.name)) + return false; + } + + boolean this_present_noteId = true && this.isSetNoteId(); + boolean that_present_noteId = true && that.isSetNoteId(); + if (this_present_noteId || that_present_noteId) { + if (!(this_present_noteId && that_present_noteId)) + return false; + if (!this.noteId.equals(that.noteId)) + return false; + } + + boolean this_present_object = true && this.isSetObject(); + boolean that_present_object = true && that.isSetObject(); + if (this_present_object || that_present_object) { + if (!(this_present_object && that_present_object)) + return false; + if (!this.object.equals(that.object)) + return false; + } + + return true; + } + + @Override + public int hashCode() { + return 0; + } + + public int compareTo(angularObjectAdd_args other) { + if (!getClass().equals(other.getClass())) { + return getClass().getName().compareTo(other.getClass().getName()); + } + + int lastComparison = 0; + angularObjectAdd_args typedOther = (angularObjectAdd_args)other; + + lastComparison = Boolean.valueOf(isSetName()).compareTo(typedOther.isSetName()); + if (lastComparison != 0) { + return lastComparison; + } + if (isSetName()) { + lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.name, typedOther.name); + if (lastComparison != 0) { + return lastComparison; + } + } + lastComparison = Boolean.valueOf(isSetNoteId()).compareTo(typedOther.isSetNoteId()); + if (lastComparison != 0) { + return lastComparison; + } + if (isSetNoteId()) { + lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.noteId, typedOther.noteId); + if (lastComparison != 0) { + return lastComparison; + } + } + lastComparison = Boolean.valueOf(isSetObject()).compareTo(typedOther.isSetObject()); + if (lastComparison != 0) { + return lastComparison; + } + if (isSetObject()) { + lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.object, typedOther.object); + if (lastComparison != 0) { + return lastComparison; + } + } + return 0; + } + + public _Fields fieldForId(int fieldId) { + return _Fields.findByThriftId(fieldId); + } + + public void read(org.apache.thrift.protocol.TProtocol iprot) throws org.apache.thrift.TException { + schemes.get(iprot.getScheme()).getScheme().read(iprot, this); + } + + public void write(org.apache.thrift.protocol.TProtocol oprot) throws org.apache.thrift.TException { + schemes.get(oprot.getScheme()).getScheme().write(oprot, this); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder("angularObjectAdd_args("); + boolean first = true; + + sb.append("name:"); + if (this.name == null) { + sb.append("null"); + } else { + sb.append(this.name); + } + first = false; + if (!first) sb.append(", "); + sb.append("noteId:"); + if (this.noteId == null) { + sb.append("null"); + } else { + sb.append(this.noteId); + } + first = false; + if (!first) sb.append(", "); + sb.append("object:"); + if (this.object == null) { + sb.append("null"); + } else { + sb.append(this.object); + } + first = false; + sb.append(")"); + return sb.toString(); + } + + public void validate() throws org.apache.thrift.TException { + // check for required fields + // check for sub-struct validity + } + + private void writeObject(java.io.ObjectOutputStream out) throws java.io.IOException { + try { + write(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(out))); + } catch (org.apache.thrift.TException te) { + throw new java.io.IOException(te); + } + } + + private void readObject(java.io.ObjectInputStream in) throws java.io.IOException, ClassNotFoundException { + try { + read(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(in))); + } catch (org.apache.thrift.TException te) { + throw new java.io.IOException(te); + } + } + + private static class angularObjectAdd_argsStandardSchemeFactory implements SchemeFactory { + public angularObjectAdd_argsStandardScheme getScheme() { + return new angularObjectAdd_argsStandardScheme(); + } + } + + private static class angularObjectAdd_argsStandardScheme extends StandardScheme { + + public void read(org.apache.thrift.protocol.TProtocol iprot, angularObjectAdd_args struct) throws org.apache.thrift.TException { + org.apache.thrift.protocol.TField schemeField; + iprot.readStructBegin(); + while (true) + { + schemeField = iprot.readFieldBegin(); + if (schemeField.type == org.apache.thrift.protocol.TType.STOP) { + break; + } + switch (schemeField.id) { + case 1: // NAME + if (schemeField.type == org.apache.thrift.protocol.TType.STRING) { + struct.name = iprot.readString(); + struct.setNameIsSet(true); + } else { + org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type); + } + break; + case 2: // NOTE_ID + if (schemeField.type == org.apache.thrift.protocol.TType.STRING) { + struct.noteId = iprot.readString(); + struct.setNoteIdIsSet(true); + } else { + org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type); + } + break; + case 3: // OBJECT + if (schemeField.type == org.apache.thrift.protocol.TType.STRING) { + struct.object = iprot.readString(); + struct.setObjectIsSet(true); + } else { + org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type); + } + break; + default: + org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type); + } + iprot.readFieldEnd(); + } + iprot.readStructEnd(); + + // check for required fields of primitive type, which can't be checked in the validate method + struct.validate(); + } + + public void write(org.apache.thrift.protocol.TProtocol oprot, angularObjectAdd_args struct) throws org.apache.thrift.TException { + struct.validate(); + + oprot.writeStructBegin(STRUCT_DESC); + if (struct.name != null) { + oprot.writeFieldBegin(NAME_FIELD_DESC); + oprot.writeString(struct.name); + oprot.writeFieldEnd(); + } + if (struct.noteId != null) { + oprot.writeFieldBegin(NOTE_ID_FIELD_DESC); + oprot.writeString(struct.noteId); + oprot.writeFieldEnd(); + } + if (struct.object != null) { + oprot.writeFieldBegin(OBJECT_FIELD_DESC); + oprot.writeString(struct.object); + oprot.writeFieldEnd(); + } + oprot.writeFieldStop(); + oprot.writeStructEnd(); + } + + } + + private static class angularObjectAdd_argsTupleSchemeFactory implements SchemeFactory { + public angularObjectAdd_argsTupleScheme getScheme() { + return new angularObjectAdd_argsTupleScheme(); + } + } + + private static class angularObjectAdd_argsTupleScheme extends TupleScheme { + + @Override + public void write(org.apache.thrift.protocol.TProtocol prot, angularObjectAdd_args struct) throws org.apache.thrift.TException { + TTupleProtocol oprot = (TTupleProtocol) prot; + BitSet optionals = new BitSet(); + if (struct.isSetName()) { + optionals.set(0); + } + if (struct.isSetNoteId()) { + optionals.set(1); + } + if (struct.isSetObject()) { + optionals.set(2); + } + oprot.writeBitSet(optionals, 3); + if (struct.isSetName()) { + oprot.writeString(struct.name); + } + if (struct.isSetNoteId()) { + oprot.writeString(struct.noteId); + } + if (struct.isSetObject()) { + oprot.writeString(struct.object); + } + } + + @Override + public void read(org.apache.thrift.protocol.TProtocol prot, angularObjectAdd_args struct) throws org.apache.thrift.TException { + TTupleProtocol iprot = (TTupleProtocol) prot; + BitSet incoming = iprot.readBitSet(3); + if (incoming.get(0)) { + struct.name = iprot.readString(); + struct.setNameIsSet(true); + } + if (incoming.get(1)) { + struct.noteId = iprot.readString(); + struct.setNoteIdIsSet(true); + } + if (incoming.get(2)) { + struct.object = iprot.readString(); + struct.setObjectIsSet(true); + } + } + } + + } + + public static class angularObjectAdd_result implements org.apache.thrift.TBase, java.io.Serializable, Cloneable { + private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("angularObjectAdd_result"); + + + private static final Map, SchemeFactory> schemes = new HashMap, SchemeFactory>(); + static { + schemes.put(StandardScheme.class, new angularObjectAdd_resultStandardSchemeFactory()); + schemes.put(TupleScheme.class, new angularObjectAdd_resultTupleSchemeFactory()); + } + + + /** The set of fields this struct contains, along with convenience methods for finding and manipulating them. */ + public enum _Fields implements org.apache.thrift.TFieldIdEnum { +; + + private static final Map byName = new HashMap(); + + static { + for (_Fields field : EnumSet.allOf(_Fields.class)) { + byName.put(field.getFieldName(), field); + } + } + + /** + * Find the _Fields constant that matches fieldId, or null if its not found. + */ + public static _Fields findByThriftId(int fieldId) { + switch(fieldId) { + default: + return null; + } + } + + /** + * Find the _Fields constant that matches fieldId, throwing an exception + * if it is not found. + */ + public static _Fields findByThriftIdOrThrow(int fieldId) { + _Fields fields = findByThriftId(fieldId); + if (fields == null) throw new IllegalArgumentException("Field " + fieldId + " doesn't exist!"); + return fields; + } + + /** + * Find the _Fields constant that matches name, or null if its not found. + */ + public static _Fields findByName(String name) { + return byName.get(name); + } + + private final short _thriftId; + private final String _fieldName; + + _Fields(short thriftId, String fieldName) { + _thriftId = thriftId; + _fieldName = fieldName; + } + + public short getThriftFieldId() { + return _thriftId; + } + + public String getFieldName() { + return _fieldName; + } + } + public static final Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> metaDataMap; + static { + Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> tmpMap = new EnumMap<_Fields, org.apache.thrift.meta_data.FieldMetaData>(_Fields.class); + metaDataMap = Collections.unmodifiableMap(tmpMap); + org.apache.thrift.meta_data.FieldMetaData.addStructMetaDataMap(angularObjectAdd_result.class, metaDataMap); + } + + public angularObjectAdd_result() { + } + + /** + * Performs a deep copy on other. + */ + public angularObjectAdd_result(angularObjectAdd_result other) { + } + + public angularObjectAdd_result deepCopy() { + return new angularObjectAdd_result(this); + } + + @Override + public void clear() { + } + + public void setFieldValue(_Fields field, Object value) { + switch (field) { + } + } + + public Object getFieldValue(_Fields field) { + switch (field) { + } + throw new IllegalStateException(); + } + + /** Returns true if field corresponding to fieldID is set (has been assigned a value) and false otherwise */ + public boolean isSet(_Fields field) { + if (field == null) { + throw new IllegalArgumentException(); + } + + switch (field) { + } + throw new IllegalStateException(); + } + + @Override + public boolean equals(Object that) { + if (that == null) + return false; + if (that instanceof angularObjectAdd_result) + return this.equals((angularObjectAdd_result)that); + return false; + } + + public boolean equals(angularObjectAdd_result that) { + if (that == null) + return false; + + return true; + } + + @Override + public int hashCode() { + return 0; + } + + public int compareTo(angularObjectAdd_result other) { + if (!getClass().equals(other.getClass())) { + return getClass().getName().compareTo(other.getClass().getName()); + } + + int lastComparison = 0; + angularObjectAdd_result typedOther = (angularObjectAdd_result)other; + + return 0; + } + + public _Fields fieldForId(int fieldId) { + return _Fields.findByThriftId(fieldId); + } + + public void read(org.apache.thrift.protocol.TProtocol iprot) throws org.apache.thrift.TException { + schemes.get(iprot.getScheme()).getScheme().read(iprot, this); + } + + public void write(org.apache.thrift.protocol.TProtocol oprot) throws org.apache.thrift.TException { + schemes.get(oprot.getScheme()).getScheme().write(oprot, this); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder("angularObjectAdd_result("); + boolean first = true; + + sb.append(")"); + return sb.toString(); + } + + public void validate() throws org.apache.thrift.TException { + // check for required fields + // check for sub-struct validity + } + + private void writeObject(java.io.ObjectOutputStream out) throws java.io.IOException { + try { + write(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(out))); + } catch (org.apache.thrift.TException te) { + throw new java.io.IOException(te); + } + } + + private void readObject(java.io.ObjectInputStream in) throws java.io.IOException, ClassNotFoundException { + try { + read(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(in))); + } catch (org.apache.thrift.TException te) { + throw new java.io.IOException(te); + } + } + + private static class angularObjectAdd_resultStandardSchemeFactory implements SchemeFactory { + public angularObjectAdd_resultStandardScheme getScheme() { + return new angularObjectAdd_resultStandardScheme(); + } + } + + private static class angularObjectAdd_resultStandardScheme extends StandardScheme { + + public void read(org.apache.thrift.protocol.TProtocol iprot, angularObjectAdd_result struct) throws org.apache.thrift.TException { + org.apache.thrift.protocol.TField schemeField; + iprot.readStructBegin(); + while (true) + { + schemeField = iprot.readFieldBegin(); + if (schemeField.type == org.apache.thrift.protocol.TType.STOP) { + break; + } + switch (schemeField.id) { + default: + org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type); + } + iprot.readFieldEnd(); + } + iprot.readStructEnd(); + + // check for required fields of primitive type, which can't be checked in the validate method + struct.validate(); + } + + public void write(org.apache.thrift.protocol.TProtocol oprot, angularObjectAdd_result struct) throws org.apache.thrift.TException { + struct.validate(); + + oprot.writeStructBegin(STRUCT_DESC); + oprot.writeFieldStop(); + oprot.writeStructEnd(); + } + + } + + private static class angularObjectAdd_resultTupleSchemeFactory implements SchemeFactory { + public angularObjectAdd_resultTupleScheme getScheme() { + return new angularObjectAdd_resultTupleScheme(); + } + } + + private static class angularObjectAdd_resultTupleScheme extends TupleScheme { + + @Override + public void write(org.apache.thrift.protocol.TProtocol prot, angularObjectAdd_result struct) throws org.apache.thrift.TException { + TTupleProtocol oprot = (TTupleProtocol) prot; + } + + @Override + public void read(org.apache.thrift.protocol.TProtocol prot, angularObjectAdd_result struct) throws org.apache.thrift.TException { + TTupleProtocol iprot = (TTupleProtocol) prot; + } + } + + } + + public static class angularObjectRemove_args implements org.apache.thrift.TBase, java.io.Serializable, Cloneable { + private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("angularObjectRemove_args"); + + private static final org.apache.thrift.protocol.TField NAME_FIELD_DESC = new org.apache.thrift.protocol.TField("name", org.apache.thrift.protocol.TType.STRING, (short)1); + private static final org.apache.thrift.protocol.TField NOTE_ID_FIELD_DESC = new org.apache.thrift.protocol.TField("noteId", org.apache.thrift.protocol.TType.STRING, (short)2); + + private static final Map, SchemeFactory> schemes = new HashMap, SchemeFactory>(); + static { + schemes.put(StandardScheme.class, new angularObjectRemove_argsStandardSchemeFactory()); + schemes.put(TupleScheme.class, new angularObjectRemove_argsTupleSchemeFactory()); + } + + public String name; // required + public String noteId; // required + + /** The set of fields this struct contains, along with convenience methods for finding and manipulating them. */ + public enum _Fields implements org.apache.thrift.TFieldIdEnum { + NAME((short)1, "name"), + NOTE_ID((short)2, "noteId"); + + private static final Map byName = new HashMap(); + + static { + for (_Fields field : EnumSet.allOf(_Fields.class)) { + byName.put(field.getFieldName(), field); + } + } + + /** + * Find the _Fields constant that matches fieldId, or null if its not found. + */ + public static _Fields findByThriftId(int fieldId) { + switch(fieldId) { + case 1: // NAME + return NAME; + case 2: // NOTE_ID + return NOTE_ID; + default: + return null; + } + } + + /** + * Find the _Fields constant that matches fieldId, throwing an exception + * if it is not found. + */ + public static _Fields findByThriftIdOrThrow(int fieldId) { + _Fields fields = findByThriftId(fieldId); + if (fields == null) throw new IllegalArgumentException("Field " + fieldId + " doesn't exist!"); + return fields; + } + + /** + * Find the _Fields constant that matches name, or null if its not found. + */ + public static _Fields findByName(String name) { + return byName.get(name); + } + + private final short _thriftId; + private final String _fieldName; + + _Fields(short thriftId, String fieldName) { + _thriftId = thriftId; + _fieldName = fieldName; + } + + public short getThriftFieldId() { + return _thriftId; + } + + public String getFieldName() { + return _fieldName; + } + } + + // isset id assignments + public static final Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> metaDataMap; + static { + Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> tmpMap = new EnumMap<_Fields, org.apache.thrift.meta_data.FieldMetaData>(_Fields.class); + tmpMap.put(_Fields.NAME, new org.apache.thrift.meta_data.FieldMetaData("name", org.apache.thrift.TFieldRequirementType.DEFAULT, + new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRING))); + tmpMap.put(_Fields.NOTE_ID, new org.apache.thrift.meta_data.FieldMetaData("noteId", org.apache.thrift.TFieldRequirementType.DEFAULT, + new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRING))); + metaDataMap = Collections.unmodifiableMap(tmpMap); + org.apache.thrift.meta_data.FieldMetaData.addStructMetaDataMap(angularObjectRemove_args.class, metaDataMap); + } + + public angularObjectRemove_args() { + } + + public angularObjectRemove_args( + String name, + String noteId) + { + this(); + this.name = name; + this.noteId = noteId; + } + + /** + * Performs a deep copy on other. + */ + public angularObjectRemove_args(angularObjectRemove_args other) { + if (other.isSetName()) { + this.name = other.name; + } + if (other.isSetNoteId()) { + this.noteId = other.noteId; + } + } + + public angularObjectRemove_args deepCopy() { + return new angularObjectRemove_args(this); + } + + @Override + public void clear() { + this.name = null; + this.noteId = null; + } + + public String getName() { + return this.name; + } + + public angularObjectRemove_args setName(String name) { + this.name = name; + return this; + } + + public void unsetName() { + this.name = null; + } + + /** Returns true if field name is set (has been assigned a value) and false otherwise */ + public boolean isSetName() { + return this.name != null; + } + + public void setNameIsSet(boolean value) { + if (!value) { + this.name = null; + } + } + + public String getNoteId() { + return this.noteId; + } + + public angularObjectRemove_args setNoteId(String noteId) { + this.noteId = noteId; + return this; + } + + public void unsetNoteId() { + this.noteId = null; + } + + /** Returns true if field noteId is set (has been assigned a value) and false otherwise */ + public boolean isSetNoteId() { + return this.noteId != null; + } + + public void setNoteIdIsSet(boolean value) { + if (!value) { + this.noteId = null; + } + } + + public void setFieldValue(_Fields field, Object value) { + switch (field) { + case NAME: + if (value == null) { + unsetName(); + } else { + setName((String)value); + } + break; + + case NOTE_ID: + if (value == null) { + unsetNoteId(); + } else { + setNoteId((String)value); + } + break; + + } + } + + public Object getFieldValue(_Fields field) { + switch (field) { + case NAME: + return getName(); + + case NOTE_ID: + return getNoteId(); + + } + throw new IllegalStateException(); + } + + /** Returns true if field corresponding to fieldID is set (has been assigned a value) and false otherwise */ + public boolean isSet(_Fields field) { + if (field == null) { + throw new IllegalArgumentException(); + } + + switch (field) { + case NAME: + return isSetName(); + case NOTE_ID: + return isSetNoteId(); + } + throw new IllegalStateException(); + } + + @Override + public boolean equals(Object that) { + if (that == null) + return false; + if (that instanceof angularObjectRemove_args) + return this.equals((angularObjectRemove_args)that); + return false; + } + + public boolean equals(angularObjectRemove_args that) { + if (that == null) + return false; + + boolean this_present_name = true && this.isSetName(); + boolean that_present_name = true && that.isSetName(); + if (this_present_name || that_present_name) { + if (!(this_present_name && that_present_name)) + return false; + if (!this.name.equals(that.name)) + return false; + } + + boolean this_present_noteId = true && this.isSetNoteId(); + boolean that_present_noteId = true && that.isSetNoteId(); + if (this_present_noteId || that_present_noteId) { + if (!(this_present_noteId && that_present_noteId)) + return false; + if (!this.noteId.equals(that.noteId)) + return false; + } + + return true; + } + + @Override + public int hashCode() { + return 0; + } + + public int compareTo(angularObjectRemove_args other) { + if (!getClass().equals(other.getClass())) { + return getClass().getName().compareTo(other.getClass().getName()); + } + + int lastComparison = 0; + angularObjectRemove_args typedOther = (angularObjectRemove_args)other; + + lastComparison = Boolean.valueOf(isSetName()).compareTo(typedOther.isSetName()); + if (lastComparison != 0) { + return lastComparison; + } + if (isSetName()) { + lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.name, typedOther.name); + if (lastComparison != 0) { + return lastComparison; + } + } + lastComparison = Boolean.valueOf(isSetNoteId()).compareTo(typedOther.isSetNoteId()); + if (lastComparison != 0) { + return lastComparison; + } + if (isSetNoteId()) { + lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.noteId, typedOther.noteId); + if (lastComparison != 0) { + return lastComparison; + } + } + return 0; + } + + public _Fields fieldForId(int fieldId) { + return _Fields.findByThriftId(fieldId); + } + + public void read(org.apache.thrift.protocol.TProtocol iprot) throws org.apache.thrift.TException { + schemes.get(iprot.getScheme()).getScheme().read(iprot, this); + } + + public void write(org.apache.thrift.protocol.TProtocol oprot) throws org.apache.thrift.TException { + schemes.get(oprot.getScheme()).getScheme().write(oprot, this); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder("angularObjectRemove_args("); + boolean first = true; + + sb.append("name:"); + if (this.name == null) { + sb.append("null"); + } else { + sb.append(this.name); + } + first = false; + if (!first) sb.append(", "); + sb.append("noteId:"); + if (this.noteId == null) { + sb.append("null"); + } else { + sb.append(this.noteId); + } + first = false; + sb.append(")"); + return sb.toString(); + } + + public void validate() throws org.apache.thrift.TException { + // check for required fields + // check for sub-struct validity + } + + private void writeObject(java.io.ObjectOutputStream out) throws java.io.IOException { + try { + write(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(out))); + } catch (org.apache.thrift.TException te) { + throw new java.io.IOException(te); + } + } + + private void readObject(java.io.ObjectInputStream in) throws java.io.IOException, ClassNotFoundException { + try { + read(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(in))); + } catch (org.apache.thrift.TException te) { + throw new java.io.IOException(te); + } + } + + private static class angularObjectRemove_argsStandardSchemeFactory implements SchemeFactory { + public angularObjectRemove_argsStandardScheme getScheme() { + return new angularObjectRemove_argsStandardScheme(); + } + } + + private static class angularObjectRemove_argsStandardScheme extends StandardScheme { + + public void read(org.apache.thrift.protocol.TProtocol iprot, angularObjectRemove_args struct) throws org.apache.thrift.TException { + org.apache.thrift.protocol.TField schemeField; + iprot.readStructBegin(); + while (true) + { + schemeField = iprot.readFieldBegin(); + if (schemeField.type == org.apache.thrift.protocol.TType.STOP) { + break; + } + switch (schemeField.id) { + case 1: // NAME + if (schemeField.type == org.apache.thrift.protocol.TType.STRING) { + struct.name = iprot.readString(); + struct.setNameIsSet(true); + } else { + org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type); + } + break; + case 2: // NOTE_ID + if (schemeField.type == org.apache.thrift.protocol.TType.STRING) { + struct.noteId = iprot.readString(); + struct.setNoteIdIsSet(true); + } else { + org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type); + } + break; + default: + org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type); + } + iprot.readFieldEnd(); + } + iprot.readStructEnd(); + + // check for required fields of primitive type, which can't be checked in the validate method + struct.validate(); + } + + public void write(org.apache.thrift.protocol.TProtocol oprot, angularObjectRemove_args struct) throws org.apache.thrift.TException { + struct.validate(); + + oprot.writeStructBegin(STRUCT_DESC); + if (struct.name != null) { + oprot.writeFieldBegin(NAME_FIELD_DESC); + oprot.writeString(struct.name); + oprot.writeFieldEnd(); + } + if (struct.noteId != null) { + oprot.writeFieldBegin(NOTE_ID_FIELD_DESC); + oprot.writeString(struct.noteId); + oprot.writeFieldEnd(); + } + oprot.writeFieldStop(); + oprot.writeStructEnd(); + } + + } + + private static class angularObjectRemove_argsTupleSchemeFactory implements SchemeFactory { + public angularObjectRemove_argsTupleScheme getScheme() { + return new angularObjectRemove_argsTupleScheme(); + } + } + + private static class angularObjectRemove_argsTupleScheme extends TupleScheme { + + @Override + public void write(org.apache.thrift.protocol.TProtocol prot, angularObjectRemove_args struct) throws org.apache.thrift.TException { + TTupleProtocol oprot = (TTupleProtocol) prot; + BitSet optionals = new BitSet(); + if (struct.isSetName()) { + optionals.set(0); + } + if (struct.isSetNoteId()) { + optionals.set(1); + } + oprot.writeBitSet(optionals, 2); + if (struct.isSetName()) { + oprot.writeString(struct.name); + } + if (struct.isSetNoteId()) { + oprot.writeString(struct.noteId); + } + } + + @Override + public void read(org.apache.thrift.protocol.TProtocol prot, angularObjectRemove_args struct) throws org.apache.thrift.TException { + TTupleProtocol iprot = (TTupleProtocol) prot; + BitSet incoming = iprot.readBitSet(2); + if (incoming.get(0)) { + struct.name = iprot.readString(); + struct.setNameIsSet(true); + } + if (incoming.get(1)) { + struct.noteId = iprot.readString(); + struct.setNoteIdIsSet(true); + } + } + } + + } + + public static class angularObjectRemove_result implements org.apache.thrift.TBase, java.io.Serializable, Cloneable { + private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("angularObjectRemove_result"); + + + private static final Map, SchemeFactory> schemes = new HashMap, SchemeFactory>(); + static { + schemes.put(StandardScheme.class, new angularObjectRemove_resultStandardSchemeFactory()); + schemes.put(TupleScheme.class, new angularObjectRemove_resultTupleSchemeFactory()); + } + + + /** The set of fields this struct contains, along with convenience methods for finding and manipulating them. */ + public enum _Fields implements org.apache.thrift.TFieldIdEnum { +; + + private static final Map byName = new HashMap(); + + static { + for (_Fields field : EnumSet.allOf(_Fields.class)) { + byName.put(field.getFieldName(), field); + } + } + + /** + * Find the _Fields constant that matches fieldId, or null if its not found. + */ + public static _Fields findByThriftId(int fieldId) { + switch(fieldId) { + default: + return null; + } + } + + /** + * Find the _Fields constant that matches fieldId, throwing an exception + * if it is not found. + */ + public static _Fields findByThriftIdOrThrow(int fieldId) { + _Fields fields = findByThriftId(fieldId); + if (fields == null) throw new IllegalArgumentException("Field " + fieldId + " doesn't exist!"); + return fields; + } + + /** + * Find the _Fields constant that matches name, or null if its not found. + */ + public static _Fields findByName(String name) { + return byName.get(name); + } + + private final short _thriftId; + private final String _fieldName; + + _Fields(short thriftId, String fieldName) { + _thriftId = thriftId; + _fieldName = fieldName; + } + + public short getThriftFieldId() { + return _thriftId; + } + + public String getFieldName() { + return _fieldName; + } + } + public static final Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> metaDataMap; + static { + Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> tmpMap = new EnumMap<_Fields, org.apache.thrift.meta_data.FieldMetaData>(_Fields.class); + metaDataMap = Collections.unmodifiableMap(tmpMap); + org.apache.thrift.meta_data.FieldMetaData.addStructMetaDataMap(angularObjectRemove_result.class, metaDataMap); + } + + public angularObjectRemove_result() { + } + + /** + * Performs a deep copy on other. + */ + public angularObjectRemove_result(angularObjectRemove_result other) { + } + + public angularObjectRemove_result deepCopy() { + return new angularObjectRemove_result(this); + } + + @Override + public void clear() { + } + + public void setFieldValue(_Fields field, Object value) { + switch (field) { + } + } + + public Object getFieldValue(_Fields field) { + switch (field) { + } + throw new IllegalStateException(); + } + + /** Returns true if field corresponding to fieldID is set (has been assigned a value) and false otherwise */ + public boolean isSet(_Fields field) { + if (field == null) { + throw new IllegalArgumentException(); + } + + switch (field) { + } + throw new IllegalStateException(); + } + + @Override + public boolean equals(Object that) { + if (that == null) + return false; + if (that instanceof angularObjectRemove_result) + return this.equals((angularObjectRemove_result)that); + return false; + } + + public boolean equals(angularObjectRemove_result that) { + if (that == null) + return false; + + return true; + } + + @Override + public int hashCode() { + return 0; + } + + public int compareTo(angularObjectRemove_result other) { + if (!getClass().equals(other.getClass())) { + return getClass().getName().compareTo(other.getClass().getName()); + } + + int lastComparison = 0; + angularObjectRemove_result typedOther = (angularObjectRemove_result)other; + + return 0; + } + + public _Fields fieldForId(int fieldId) { + return _Fields.findByThriftId(fieldId); + } + + public void read(org.apache.thrift.protocol.TProtocol iprot) throws org.apache.thrift.TException { + schemes.get(iprot.getScheme()).getScheme().read(iprot, this); + } + + public void write(org.apache.thrift.protocol.TProtocol oprot) throws org.apache.thrift.TException { + schemes.get(oprot.getScheme()).getScheme().write(oprot, this); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder("angularObjectRemove_result("); + boolean first = true; + + sb.append(")"); + return sb.toString(); + } + + public void validate() throws org.apache.thrift.TException { + // check for required fields + // check for sub-struct validity + } + + private void writeObject(java.io.ObjectOutputStream out) throws java.io.IOException { + try { + write(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(out))); + } catch (org.apache.thrift.TException te) { + throw new java.io.IOException(te); + } + } + + private void readObject(java.io.ObjectInputStream in) throws java.io.IOException, ClassNotFoundException { + try { + read(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(in))); + } catch (org.apache.thrift.TException te) { + throw new java.io.IOException(te); + } + } + + private static class angularObjectRemove_resultStandardSchemeFactory implements SchemeFactory { + public angularObjectRemove_resultStandardScheme getScheme() { + return new angularObjectRemove_resultStandardScheme(); + } + } + + private static class angularObjectRemove_resultStandardScheme extends StandardScheme { + + public void read(org.apache.thrift.protocol.TProtocol iprot, angularObjectRemove_result struct) throws org.apache.thrift.TException { + org.apache.thrift.protocol.TField schemeField; + iprot.readStructBegin(); + while (true) + { + schemeField = iprot.readFieldBegin(); + if (schemeField.type == org.apache.thrift.protocol.TType.STOP) { + break; + } + switch (schemeField.id) { + default: + org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type); + } + iprot.readFieldEnd(); + } + iprot.readStructEnd(); + + // check for required fields of primitive type, which can't be checked in the validate method + struct.validate(); + } + + public void write(org.apache.thrift.protocol.TProtocol oprot, angularObjectRemove_result struct) throws org.apache.thrift.TException { + struct.validate(); + + oprot.writeStructBegin(STRUCT_DESC); + oprot.writeFieldStop(); + oprot.writeStructEnd(); + } + + } + + private static class angularObjectRemove_resultTupleSchemeFactory implements SchemeFactory { + public angularObjectRemove_resultTupleScheme getScheme() { + return new angularObjectRemove_resultTupleScheme(); + } + } + + private static class angularObjectRemove_resultTupleScheme extends TupleScheme { + + @Override + public void write(org.apache.thrift.protocol.TProtocol prot, angularObjectRemove_result struct) throws org.apache.thrift.TException { + TTupleProtocol oprot = (TTupleProtocol) prot; + } + + @Override + public void read(org.apache.thrift.protocol.TProtocol prot, angularObjectRemove_result struct) throws org.apache.thrift.TException { + TTupleProtocol iprot = (TTupleProtocol) prot; + } + } + + } + } diff --git a/zeppelin-interpreter/src/main/thrift/RemoteInterpreterService.thrift b/zeppelin-interpreter/src/main/thrift/RemoteInterpreterService.thrift index f84e61d15ed..144784c539e 100644 --- a/zeppelin-interpreter/src/main/thrift/RemoteInterpreterService.thrift +++ b/zeppelin-interpreter/src/main/thrift/RemoteInterpreterService.thrift @@ -66,4 +66,6 @@ service RemoteInterpreterService { RemoteInterpreterEvent getEvent(); void angularObjectUpdate(1: string name, 2: string noteId, 3: string object); + void angularObjectAdd(1: string name, 2: string noteId, 3: string object); + void angularObjectRemove(1: string name, 2: string noteId); } \ No newline at end of file diff --git a/zeppelin-interpreter/src/test/java/org/apache/zeppelin/display/AngularObjectRegistryTest.java b/zeppelin-interpreter/src/test/java/org/apache/zeppelin/display/AngularObjectRegistryTest.java index b693e6a4f42..43aca62c497 100644 --- a/zeppelin-interpreter/src/test/java/org/apache/zeppelin/display/AngularObjectRegistryTest.java +++ b/zeppelin-interpreter/src/test/java/org/apache/zeppelin/display/AngularObjectRegistryTest.java @@ -45,7 +45,7 @@ public void onUpdate(String interpreterGroupId, AngularObject object) { } @Override - public void onRemove(String interpreterGroupId, AngularObject object) { + public void onRemove(String interpreterGroupId, String name, String noteId) { onRemove.incrementAndGet(); } }); diff --git a/zeppelin-interpreter/src/test/java/org/apache/zeppelin/interpreter/remote/RemoteAngularObjectTest.java b/zeppelin-interpreter/src/test/java/org/apache/zeppelin/interpreter/remote/RemoteAngularObjectTest.java index 186b287ee34..29a1fb11972 100644 --- a/zeppelin-interpreter/src/test/java/org/apache/zeppelin/interpreter/remote/RemoteAngularObjectTest.java +++ b/zeppelin-interpreter/src/test/java/org/apache/zeppelin/interpreter/remote/RemoteAngularObjectTest.java @@ -96,7 +96,7 @@ public void tearDown() throws Exception { } @Test - public void testAngularObjectCRUD() throws InterruptedException { + public void testAngularObjectInterpreterSideCRUD() throws InterruptedException { InterpreterResult ret = intp.interpret("get", context); Thread.sleep(500); // waitFor eventpoller pool event String[] result = ret.message().split(" "); @@ -128,6 +128,51 @@ public void testAngularObjectCRUD() throws InterruptedException { assertEquals(null, localRegistry.get("n1", "note")); } + @Test + public void testAngularObjectRemovalOnZeppelinServerSide() throws InterruptedException { + // test if angularobject removal from server side propagate to interpreter process's registry. + // will happen when notebook is removed. + + InterpreterResult ret = intp.interpret("get", context); + Thread.sleep(500); // waitFor eventpoller pool event + String[] result = ret.message().split(" "); + assertEquals("0", result[0]); // size of registry + + // create object + ret = intp.interpret("add n1 v1", context); + Thread.sleep(500); + result = ret.message().split(" "); + assertEquals("1", result[0]); // size of registry + assertEquals("v1", localRegistry.get("n1", "note").get()); + + // remove object in local registry. + localRegistry.removeAndNotifyRemoteProcess("n1", "note"); + ret = intp.interpret("get", context); + Thread.sleep(500); // waitFor eventpoller pool event + result = ret.message().split(" "); + assertEquals("0", result[0]); // size of registry + } + + @Test + public void testAngularObjectAddOnZeppelinServerSide() throws InterruptedException { + // test if angularobject add from server side propagate to interpreter process's registry. + // will happen when zeppelin server loads notebook and restore the object into registry + + InterpreterResult ret = intp.interpret("get", context); + Thread.sleep(500); // waitFor eventpoller pool event + String[] result = ret.message().split(" "); + assertEquals("0", result[0]); // size of registry + + // create object + localRegistry.addAndNotifyRemoteProcess("n1", "v1", "note"); + + // get from remote registry + ret = intp.interpret("get", context); + Thread.sleep(500); // waitFor eventpoller pool event + result = ret.message().split(" "); + assertEquals("1", result[0]); // size of registry + } + @Override public void onAdd(String interpreterGroupId, AngularObject object) { onAdd.incrementAndGet(); @@ -139,7 +184,7 @@ public void onUpdate(String interpreterGroupId, AngularObject object) { } @Override - public void onRemove(String interpreterGroupId, AngularObject object) { + public void onRemove(String interpreterGroupId, String name, String noteId) { onRemove.incrementAndGet(); } diff --git a/zeppelin-server/src/main/java/org/apache/zeppelin/socket/NotebookServer.java b/zeppelin-server/src/main/java/org/apache/zeppelin/socket/NotebookServer.java index 842d1959c0e..3a0f806c31a 100644 --- a/zeppelin-server/src/main/java/org/apache/zeppelin/socket/NotebookServer.java +++ b/zeppelin-server/src/main/java/org/apache/zeppelin/socket/NotebookServer.java @@ -666,21 +666,20 @@ public void onUpdate(String interpreterGroupId, AngularObject object) { @Override - public void onRemove(String interpreterGroupId, AngularObject object) { + public void onRemove(String interpreterGroupId, String name, String noteId) { Notebook notebook = notebook(); List notes = notebook.getAllNotes(); for (Note note : notes) { - if (object.getNoteId() != null && !note.id().equals(object.getNoteId())) { + if (noteId != null && !note.id().equals(noteId)) { continue; } - + List ids = note.getNoteReplLoader().getInterpreters(); for (String id : ids) { if (id.equals(interpreterGroupId)) { broadcast( note.id(), - new Message(OP.ANGULAR_OBJECT_REMOVE).put("name", - object.getName())); + new Message(OP.ANGULAR_OBJECT_REMOVE).put("name", name)); } } } diff --git a/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Notebook.java b/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Notebook.java index 90bccfb9056..5383d270efb 100644 --- a/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Notebook.java +++ b/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Notebook.java @@ -35,6 +35,7 @@ import org.apache.zeppelin.interpreter.InterpreterFactory; import org.apache.zeppelin.interpreter.InterpreterGroup; import org.apache.zeppelin.interpreter.InterpreterSetting; +import org.apache.zeppelin.interpreter.remote.RemoteAngularObjectRegistry; import org.apache.zeppelin.notebook.repo.NotebookRepo; import org.apache.zeppelin.scheduler.SchedulerFactory; import org.quartz.CronScheduleBuilder; @@ -159,7 +160,11 @@ public void removeNote(String id) { // remove from all interpreter instance's angular object registry for (InterpreterSetting settings : replFactory.get()) { AngularObjectRegistry registry = settings.getInterpreterGroup().getAngularObjectRegistry(); - registry.removeAll(id); + if (registry instanceof RemoteAngularObjectRegistry) { + ((RemoteAngularObjectRegistry) registry).removeAllAndNotifyRemoteProcess(id); + } else { + registry.removeAll(id); + } } try { @@ -237,12 +242,13 @@ private Note loadNoteFromRepo(String id) { InterpreterGroup intpGroup = setting.getInterpreterGroup(); if (intpGroup.getId().equals(snapshot.getIntpGroupId())) { AngularObjectRegistry registry = intpGroup.getAngularObjectRegistry(); - boolean localScope = snapshot.getAngularObject().getNoteId() != null; - if (localScope) { - registry.add(name, snapshot.getAngularObject().get(), note.id()); - } else { - registry.add(name, snapshot.getAngularObject().get(), null); - } + String noteId = snapshot.getAngularObject().getNoteId(); + // at this point, remote interpreter process is not created. + // so does not make sense add it to the remote. + // + // therefore instead of addAndNotifyRemoteProcess(), need to use add() + // that results add angularObject only in ZeppelinServer side not remoteProcessSide + registry.add(name, snapshot.getAngularObject().get(), noteId); } } } From 699defdfc7d14a8cef77787b615d8eec7ad9ddc0 Mon Sep 17 00:00:00 2001 From: Lee moon soo Date: Sat, 4 Jul 2015 18:40:16 -0700 Subject: [PATCH 08/17] Handle ANGULAR_OBJECT_REMOVE event in front-end. --- .../apache/zeppelin/socket/NotebookServer.java | 5 ++++- .../src/app/notebook/notebook.controller.js | 15 +++++++++++++++ .../websocketEvents/websocketEvents.factory.js | 4 +++- 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/zeppelin-server/src/main/java/org/apache/zeppelin/socket/NotebookServer.java b/zeppelin-server/src/main/java/org/apache/zeppelin/socket/NotebookServer.java index 3a0f806c31a..d6bc01daca1 100644 --- a/zeppelin-server/src/main/java/org/apache/zeppelin/socket/NotebookServer.java +++ b/zeppelin-server/src/main/java/org/apache/zeppelin/socket/NotebookServer.java @@ -679,7 +679,10 @@ public void onRemove(String interpreterGroupId, String name, String noteId) { if (id.equals(interpreterGroupId)) { broadcast( note.id(), - new Message(OP.ANGULAR_OBJECT_REMOVE).put("name", name)); + new Message(OP.ANGULAR_OBJECT_REMOVE) + .put("name", name) + .put("noteId", noteId) + ); } } } diff --git a/zeppelin-web/src/app/notebook/notebook.controller.js b/zeppelin-web/src/app/notebook/notebook.controller.js index 0d01c370ab3..1901d8c972e 100644 --- a/zeppelin-web/src/app/notebook/notebook.controller.js +++ b/zeppelin-web/src/app/notebook/notebook.controller.js @@ -465,6 +465,21 @@ angular.module('zeppelinWebApp').controller('NotebookCtrl', function($scope, $ro }); + $scope.$on('angularObjectRemove', function(event, data) { + if (!data.noteId || data.noteId === $scope.note.id) { + var scope = $rootScope.compiledScope; + var varName = data.name; + + // clear watcher + if (angularObjectRegistry[varName]) { + angularObjectRegistry[varName].clearWatcher(); + } + + // remove scope variable + scope[varName] = undefined; + } + }); + var isFunction = function(functionToCheck) { var getType = {}; return functionToCheck && getType.toString.call(functionToCheck) === '[object Function]'; diff --git a/zeppelin-web/src/components/websocketEvents/websocketEvents.factory.js b/zeppelin-web/src/components/websocketEvents/websocketEvents.factory.js index 0757d0aaea3..731266f8071 100644 --- a/zeppelin-web/src/components/websocketEvents/websocketEvents.factory.js +++ b/zeppelin-web/src/components/websocketEvents/websocketEvents.factory.js @@ -51,6 +51,8 @@ angular.module('zeppelinWebApp').factory('websocketEvents', function($rootScope, $rootScope.$broadcast('completionList', data); } else if (op === 'ANGULAR_OBJECT_UPDATE') { $rootScope.$broadcast('angularObjectUpdate', data); + } else if (op === 'ANGULAR_OBJECT_REMOVE') { + $rootScope.$broadcast('angularObjectRemove', data); } }); @@ -65,4 +67,4 @@ angular.module('zeppelinWebApp').factory('websocketEvents', function($rootScope, }); return websocketCalls; -}); \ No newline at end of file +}); From 12bb15a36b35f6af6ca3143d353019b236e8c10f Mon Sep 17 00:00:00 2001 From: Lee moon soo Date: Sat, 4 Jul 2015 18:49:57 -0700 Subject: [PATCH 09/17] Fix style --- .../java/org/apache/zeppelin/socket/NotebookServer.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/zeppelin-server/src/main/java/org/apache/zeppelin/socket/NotebookServer.java b/zeppelin-server/src/main/java/org/apache/zeppelin/socket/NotebookServer.java index d6bc01daca1..3e051f3ef5a 100644 --- a/zeppelin-server/src/main/java/org/apache/zeppelin/socket/NotebookServer.java +++ b/zeppelin-server/src/main/java/org/apache/zeppelin/socket/NotebookServer.java @@ -679,10 +679,8 @@ public void onRemove(String interpreterGroupId, String name, String noteId) { if (id.equals(interpreterGroupId)) { broadcast( note.id(), - new Message(OP.ANGULAR_OBJECT_REMOVE) - .put("name", name) - .put("noteId", noteId) - ); + new Message(OP.ANGULAR_OBJECT_REMOVE).put("name", name).put( + "noteId", noteId)); } } } From bcb60f8c2ca67e5e5bad8b08e3a84809c10fc622 Mon Sep 17 00:00:00 2001 From: Lee moon soo Date: Sat, 4 Jul 2015 19:29:44 -0700 Subject: [PATCH 10/17] Clear object correctly --- zeppelin-web/src/app/notebook/notebook.controller.js | 1 + 1 file changed, 1 insertion(+) diff --git a/zeppelin-web/src/app/notebook/notebook.controller.js b/zeppelin-web/src/app/notebook/notebook.controller.js index 1901d8c972e..6286da63d25 100644 --- a/zeppelin-web/src/app/notebook/notebook.controller.js +++ b/zeppelin-web/src/app/notebook/notebook.controller.js @@ -473,6 +473,7 @@ angular.module('zeppelinWebApp').controller('NotebookCtrl', function($scope, $ro // clear watcher if (angularObjectRegistry[varName]) { angularObjectRegistry[varName].clearWatcher(); + angularObjectRegistry[varName] = undefined; } // remove scope variable From b817bd9c1dfe60f2a5c33d075ef1cf13e4c4a4ce Mon Sep 17 00:00:00 2001 From: Lee moon soo Date: Sat, 4 Jul 2015 20:50:54 -0700 Subject: [PATCH 11/17] Cleanup the message --- .../interpreter/remote/RemoteInterpreterEventPoller.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/remote/RemoteInterpreterEventPoller.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/remote/RemoteInterpreterEventPoller.java index 373efef5504..f39f6a6aa10 100644 --- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/remote/RemoteInterpreterEventPoller.java +++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/remote/RemoteInterpreterEventPoller.java @@ -109,7 +109,7 @@ public void run() { interpreterProcess.getInterpreterContextRunnerPool().run( runnerFromRemote.getNoteId(), runnerFromRemote.getParagraphId()); } - logger.info("I've got event from remoteproceess {}", event.getType()); + logger.debug("Event from remoteproceess {}", event.getType()); } catch (Exception e) { logger.error("Can't handle event " + event, e); } From d74820fdfb9d90f8d581df6019aa18d714d66623 Mon Sep 17 00:00:00 2001 From: Lee moon soo Date: Sat, 4 Jul 2015 22:19:21 -0700 Subject: [PATCH 12/17] Enabling selenium test --- .../java/org/apache/zeppelin/ZeppelinIT.java | 141 +++++++++++++++--- 1 file changed, 122 insertions(+), 19 deletions(-) diff --git a/zeppelin-server/src/test/java/org/apache/zeppelin/ZeppelinIT.java b/zeppelin-server/src/test/java/org/apache/zeppelin/ZeppelinIT.java index 08d3238f400..5b38f13f1c6 100644 --- a/zeppelin-server/src/test/java/org/apache/zeppelin/ZeppelinIT.java +++ b/zeppelin-server/src/test/java/org/apache/zeppelin/ZeppelinIT.java @@ -17,12 +17,20 @@ package org.apache.zeppelin; -import static org.junit.Assert.fail; +import static org.junit.Assert.*; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; + +import org.junit.After; +import org.junit.Before; import org.junit.Test; import org.openqa.selenium.By; +import org.openqa.selenium.Keys; import org.openqa.selenium.TimeoutException; import org.openqa.selenium.WebDriver; +import org.openqa.selenium.WebElement; import org.openqa.selenium.chrome.ChromeDriver; import org.openqa.selenium.firefox.FirefoxBinary; import org.openqa.selenium.firefox.FirefoxDriver; @@ -31,8 +39,17 @@ import org.openqa.selenium.support.ui.ExpectedCondition; import org.openqa.selenium.support.ui.WebDriverWait; +/** + * Test Zeppelin with web brower. + * + * To test, ZeppelinServer should be running on port 8080 + * On OSX, you'll need firefox 31.0 installed. + * + */ public class ZeppelinIT { - private WebDriver getWebDriver(){ + private WebDriver driver; + + private WebDriver getWebDriver(){ WebDriver driver = null; if (driver==null){ @@ -72,21 +89,22 @@ private WebDriver getWebDriver(){ boolean loaded = false; driver.get(url); - while (System.currentTimeMillis() - start < 60*1000) { - // wait for page load - try { - (new WebDriverWait(driver, 5)).until(new ExpectedCondition() { - @Override - public Boolean apply(WebDriver d) { - return d.findElement(By.partialLinkText("Start")).isDisplayed(); - } - }); - loaded = true; - break; - } catch (TimeoutException e){ - driver.navigate().to(url); - } - } + while (System.currentTimeMillis() - start < 60 * 1000) { + // wait for page load + try { + (new WebDriverWait(driver, 5)).until(new ExpectedCondition() { + @Override + public Boolean apply(WebDriver d) { + return d.findElement(By.partialLinkText("Create new note")) + .isDisplayed(); + } + }); + loaded = true; + break; + } catch (TimeoutException e) { + driver.navigate().to(url); + } + } if (loaded==false) { fail(); @@ -95,9 +113,94 @@ public Boolean apply(WebDriver d) { return driver; } + @Before + public void startUp() { + driver = getWebDriver(); + } + + @After + public void tearDown() { + driver.quit(); + } + @Test - public void testDisableIT(){ - // + public void testCreateNotebook() throws InterruptedException{ + String noteName = createNewNoteAndGetName(); + driver.findElement(By.partialLinkText(noteName)).click(); + + final WebElement p1 = driver.findElement(By + .xpath("//div[@ng-controller=\"ParagraphCtrl\"][1]")); + + // wait for first paragraph's " READY " status text + (new WebDriverWait(driver, 10)).until(new ExpectedCondition() { + public Boolean apply(WebDriver d) { + return p1.findElement(By.xpath("//div[@class=\"control\"]//span[1][text()=\" READY \"]")) + .isDisplayed(); + } + }); + //div[@class="control"]/span[1] + // type some query + + p1.findElement(By.xpath("//textarea")).sendKeys("println" + Keys.chord(Keys.SHIFT, "9") + "\"" + + Keys.chord(Keys.SHIFT, "5") + "angular BindingTest_{{myVar}}_\")"); + p1.findElement(By.xpath("//textarea")).sendKeys(Keys.chord(Keys.SHIFT, Keys.ENTER)); + + // wait for text displayed + (new WebDriverWait(driver, 60)).until(new ExpectedCondition() { + public Boolean apply(WebDriver d) { + return p1.findElement(By.xpath("//div[@class=\"control\"]//span[1][text()=\" FINISHED \"]")) + .isDisplayed(); + } + }); + /* + // bind value + final WebElement p2 = driver.findElement(By + .xpath("//div[@ng-controller=\"ParagraphCtrl\"][2]")); + p2.findElement(By.xpath("//textarea")).sendKeys("z.angularBind" + Keys.chord(Keys.SHIFT, "9") + + "\"myVar\", 1)"); + p2.sendKeys(Keys.chord(Keys.SHIFT, Keys.ENTER)); + + // wait for text displayed + (new WebDriverWait(driver, 60)).until(new ExpectedCondition() { + public Boolean apply(WebDriver d) { + return p2.findElement(By.xpath("//div[@class=\"ng-scope\"]/span")).isDisplayed(); + } + }); + + Thread.sleep(60*1000); + */ + } + + private String createNewNoteAndGetName() { + List notebookLinks = driver.findElements(By + .xpath("//div[contains(@class, \"col-md-4\")]/div/ul/li")); + List notebookTitles = new LinkedList(); + for (WebElement el : notebookLinks) { + notebookTitles.add(el.getText()); + } + + WebElement createNoteLink = driver.findElement(By.partialLinkText("Create new note")); + createNoteLink.click(); + + try { + Thread.sleep(500); // wait for notebook list updated + } catch (InterruptedException e) { + } + + List notebookLinksAfterCreate = driver.findElements(By + .xpath("//div[contains(@class, \"col-md-4\")]/div/ul/li")); + + Iterator it = notebookLinksAfterCreate.iterator(); + while (it.hasNext()) { + WebElement newEl = it.next(); + if (notebookTitles.contains(newEl.getText())) { + + it.remove(); + } + } + + assertEquals(1, notebookLinksAfterCreate.size()); + return notebookLinksAfterCreate.get(0).getText(); } /* From c7c63d175469c3e9eea04fe44ac2dbc72605083e Mon Sep 17 00:00:00 2001 From: Lee moon soo Date: Sun, 5 Jul 2015 09:09:38 -0700 Subject: [PATCH 13/17] make sure test is executed --- .../src/test/java/org/apache/zeppelin/ZeppelinIT.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/zeppelin-server/src/test/java/org/apache/zeppelin/ZeppelinIT.java b/zeppelin-server/src/test/java/org/apache/zeppelin/ZeppelinIT.java index 5b38f13f1c6..00a2f1dcf7c 100644 --- a/zeppelin-server/src/test/java/org/apache/zeppelin/ZeppelinIT.java +++ b/zeppelin-server/src/test/java/org/apache/zeppelin/ZeppelinIT.java @@ -152,6 +152,9 @@ public Boolean apply(WebDriver d) { .isDisplayed(); } }); + + + System.out.println("testCreateNotebook Test executed"); /* // bind value final WebElement p2 = driver.findElement(By From ead4f70aed683b00901756904826926d4f977079 Mon Sep 17 00:00:00 2001 From: Lee moon soo Date: Sun, 5 Jul 2015 13:19:17 -0700 Subject: [PATCH 14/17] Front end interaction test with angularBind, angularUnbind, angularWatch --- .../java/org/apache/zeppelin/ZeppelinIT.java | 423 ++++++------------ 1 file changed, 145 insertions(+), 278 deletions(-) diff --git a/zeppelin-server/src/test/java/org/apache/zeppelin/ZeppelinIT.java b/zeppelin-server/src/test/java/org/apache/zeppelin/ZeppelinIT.java index 00a2f1dcf7c..cf0f7424065 100644 --- a/zeppelin-server/src/test/java/org/apache/zeppelin/ZeppelinIT.java +++ b/zeppelin-server/src/test/java/org/apache/zeppelin/ZeppelinIT.java @@ -115,63 +115,166 @@ public Boolean apply(WebDriver d) { @Before public void startUp() { + if (!endToEndTestEnabled()) { + return; + } + driver = getWebDriver(); } @After public void tearDown() { + if (!endToEndTestEnabled()) { + return; + } + driver.quit(); } - @Test - public void testCreateNotebook() throws InterruptedException{ - String noteName = createNewNoteAndGetName(); - driver.findElement(By.partialLinkText(noteName)).click(); - - final WebElement p1 = driver.findElement(By - .xpath("//div[@ng-controller=\"ParagraphCtrl\"][1]")); - - // wait for first paragraph's " READY " status text + String getParagraphXPath(int paragraphNo) { + return "//div[@ng-controller=\"ParagraphCtrl\"][" + paragraphNo +"]"; + } + + void waitForParagraph(final int paragraphNo, final String state) { (new WebDriverWait(driver, 10)).until(new ExpectedCondition() { public Boolean apply(WebDriver d) { - return p1.findElement(By.xpath("//div[@class=\"control\"]//span[1][text()=\" READY \"]")) + return driver.findElement(By.xpath(getParagraphXPath(paragraphNo) + + "//div[@class=\"control\"]//span[1][text()=\" " + state + " \"]")) .isDisplayed(); - } + }; }); - //div[@class="control"]/span[1] - // type some query + } - p1.findElement(By.xpath("//textarea")).sendKeys("println" + Keys.chord(Keys.SHIFT, "9") + "\"" - + Keys.chord(Keys.SHIFT, "5") + "angular BindingTest_{{myVar}}_\")"); - p1.findElement(By.xpath("//textarea")).sendKeys(Keys.chord(Keys.SHIFT, Keys.ENTER)); + boolean endToEndTestEnabled() { + return null != System.getenv("CI"); + } + + @Test + public void testAngularDisplay() throws InterruptedException{ + if (!endToEndTestEnabled()) { + return; + } + + String noteName = createNewNoteAndGetName(); + driver.findElement(By.partialLinkText(noteName)).click(); + + // wait for first paragraph's " READY " status text + waitForParagraph(1, "READY"); - // wait for text displayed - (new WebDriverWait(driver, 60)).until(new ExpectedCondition() { - public Boolean apply(WebDriver d) { - return p1.findElement(By.xpath("//div[@class=\"control\"]//span[1][text()=\" FINISHED \"]")) - .isDisplayed(); - } - }); - - - System.out.println("testCreateNotebook Test executed"); /* - // bind value - final WebElement p2 = driver.findElement(By - .xpath("//div[@ng-controller=\"ParagraphCtrl\"][2]")); - p2.findElement(By.xpath("//textarea")).sendKeys("z.angularBind" + Keys.chord(Keys.SHIFT, "9") - + "\"myVar\", 1)"); - p2.sendKeys(Keys.chord(Keys.SHIFT, Keys.ENTER)); - - // wait for text displayed - (new WebDriverWait(driver, 60)).until(new ExpectedCondition() { - public Boolean apply(WebDriver d) { - return p2.findElement(By.xpath("//div[@class=\"ng-scope\"]/span")).isDisplayed(); - } - }); - - Thread.sleep(60*1000); - */ + * print angular template + * %angular
BindingTest_{{myVar}}_
+ */ + WebElement paragraph1Editor = driver.findElement(By.xpath(getParagraphXPath(1) + "//textarea")); + paragraph1Editor.sendKeys("println" + Keys.chord(Keys.SHIFT, "9") + "\"" + + Keys.chord(Keys.SHIFT, "5") + + "angular
" + + "BindingTest_{{myVar}}_
\")"); + paragraph1Editor.sendKeys(Keys.chord(Keys.SHIFT, Keys.ENTER)); + waitForParagraph(1, "FINISHED"); + + // check expected text + assertEquals("BindingTest__", driver.findElement(By.xpath( + getParagraphXPath(1) + "//div[@id=\"angularTestButton\"]")).getText()); + + /* + * Bind variable + * z.angularBind("myVar", 1) + */ + assertEquals(1, driver.findElements(By.xpath(getParagraphXPath(2) + "//textarea")).size()); + WebElement paragraph2Editor = driver.findElement(By.xpath(getParagraphXPath(2) + "//textarea")); + paragraph2Editor.sendKeys("z.angularBind" + Keys.chord(Keys.SHIFT, "9") + "\"myVar\", 1)"); + paragraph2Editor.sendKeys(Keys.chord(Keys.SHIFT, Keys.ENTER)); + waitForParagraph(2, "FINISHED"); + + // check expected text + assertEquals("BindingTest_1_", driver.findElement(By.xpath( + getParagraphXPath(1) + "//div[@id=\"angularTestButton\"]")).getText()); + + + /* + * print variable + * print("myVar="+z.angular("myVar")) + */ + WebElement paragraph3Editor = driver.findElement(By.xpath(getParagraphXPath(3) + "//textarea")); + paragraph3Editor.sendKeys( + "print" + Keys.chord(Keys.SHIFT, "9") + "\"myVar=\"" + Keys.chord(Keys.ADD) + + "z.angular" + Keys.chord(Keys.SHIFT, "9") + "\"myVar\"))"); + paragraph3Editor.sendKeys(Keys.chord(Keys.SHIFT, Keys.ENTER)); + waitForParagraph(3, "FINISHED"); + + // check expected text + assertEquals("myVar=1", driver.findElement(By.xpath( + getParagraphXPath(3) + "//div[@ng-bind=\"paragraph.result.msg\"]")).getText()); + + /* + * Click element + */ + driver.findElement(By.xpath( + getParagraphXPath(1) + "//div[@id=\"angularTestButton\"]")).click(); + + // check expected text + assertEquals("BindingTest_2_", driver.findElement(By.xpath( + getParagraphXPath(1) + "//div[@id=\"angularTestButton\"]")).getText()); + + /* + * Register watcher + * z.angularWatch("myVar", (before:Object, after:Object, context:org.apache.zeppelin.interpreter.InterpreterContext) => { + * z.run(2, context) + * } + */ + WebElement paragraph4Editor = driver.findElement(By.xpath(getParagraphXPath(4) + "//textarea")); + paragraph4Editor.sendKeys( + "z.angularWatch" + Keys.chord(Keys.SHIFT, "9") + "\"myVar\", " + + Keys.chord(Keys.SHIFT, "9") + + "before:Object, after:Object, context:org.apache.zeppelin.interpreter.InterpreterContext)" + + Keys.EQUALS + ">{ z.run" +Keys.chord(Keys.SHIFT, "9") + "2, context)}"); + paragraph4Editor.sendKeys(Keys.chord(Keys.SHIFT, Keys.ENTER)); + waitForParagraph(4, "FINISHED"); + + + /* + * Click element, again and see watcher works + */ + driver.findElement(By.xpath( + getParagraphXPath(1) + "//div[@id=\"angularTestButton\"]")).click(); + + // check expected text + assertEquals("BindingTest_3_", driver.findElement(By.xpath( + getParagraphXPath(1) + "//div[@id=\"angularTestButton\"]")).getText()); + waitForParagraph(3, "FINISHED"); + + // check expected text by watcher + assertEquals("myVar=3", driver.findElement(By.xpath( + getParagraphXPath(3) + "//div[@ng-bind=\"paragraph.result.msg\"]")).getText()); + + /* + * Unbind + * z.angularUnbind("myVar") + */ + WebElement paragraph5Editor = driver.findElement(By.xpath(getParagraphXPath(5) + "//textarea")); + paragraph5Editor.sendKeys( + "z.angularUnbind" + Keys.chord(Keys.SHIFT, "9") + "\"myVar\")"); + paragraph5Editor.sendKeys(Keys.chord(Keys.SHIFT, Keys.ENTER)); + waitForParagraph(5, "FINISHED"); + + // check expected text + assertEquals("BindingTest__", driver.findElement(By.xpath( + getParagraphXPath(1) + "//div[@id=\"angularTestButton\"]")).getText()); + + /* + * Bind again and see rebind works. + */ + paragraph2Editor = driver.findElement(By.xpath(getParagraphXPath(2) + "//textarea")); + paragraph2Editor.sendKeys(Keys.chord(Keys.SHIFT, Keys.ENTER)); + waitForParagraph(2, "FINISHED"); + + // check expected text + assertEquals("BindingTest_1_", driver.findElement(By.xpath( + getParagraphXPath(1) + "//div[@id=\"angularTestButton\"]")).getText()); + + System.out.println("testCreateNotebook Test executed"); } private String createNewNoteAndGetName() { @@ -205,240 +308,4 @@ private String createNewNoteAndGetName() { assertEquals(1, notebookLinksAfterCreate.size()); return notebookLinksAfterCreate.get(0).getText(); } - - /* - @Test - public void testRunSimpleQueryInNewSession() { - // Notice that the remainder of the code relies on the interface, - // not the implementation. - WebDriver driver = getWebDriver(); - - try { - // click start - WebElement start = driver.findElement(By.partialLinkText("Start")); - start.click(); - - // Wait for the page to load, timeout after 10 seconds - (new WebDriverWait(driver, 10)).until(new ExpectedCondition() { - public Boolean apply(WebDriver d) { - return d.findElement(By.linkText("Create new Job")).isDisplayed(); - } - }); - - // click new - driver.findElement(By.linkText("Create new Job")).click(); - - // wait for run button appears - (new WebDriverWait(driver, 10)).until(new ExpectedCondition() { - public Boolean apply(WebDriver d) { - return d.findElement(By.linkText("Run")).isDisplayed(); - } - }); - - // type some query - driver.findElement(By.xpath("//div[@id='zqlEditor']//textarea")).sendKeys("create table if not exists test "+Keys.chord(Keys.SHIFT, "9")+"id STRING);\n"); - driver.findElement(By.xpath("//div[@id='zqlEditor']//textarea")).sendKeys("\nshow tables;"); - - // press run button - driver.findElement(By.linkText("Run")).click(); - - // wait for button becomes Running ... - (new WebDriverWait(driver, 10)).until(new ExpectedCondition() { - public Boolean apply(WebDriver d) { - return d.findElement(By.xpath("//div//a[text()='Running ...']")).isDisplayed(); - } - }); - - // wait for button becomes Run - (new WebDriverWait(driver, 60)).until(new ExpectedCondition() { - public Boolean apply(WebDriver d) { - return d.findElement(By.xpath("//div//a[text()='Run']")).isDisplayed(); - } - }); - - WebElement msg = driver.findElement(By.id("msgBox")); - if (msg!=null) { - System.out.println("msgBox="+msg.getText()); - } - - // wait for visualization - (new WebDriverWait(driver, 20)).until(new ExpectedCondition() { - public Boolean apply(WebDriver d) { - return d.findElement(By.xpath("//div[@id='visualizationContainer']//iframe")).isDisplayed(); - } - }); - - WebDriver iframe = driver.switchTo().frame(driver.findElement(By.xpath("//div[@id='visualizationContainer']//iframe"))); - - // wait for result displayed - (new WebDriverWait(iframe, 20)).until(new ExpectedCondition() { - public Boolean apply(WebDriver d) { - return d.findElement(By.xpath("//table//td[text()='test']")).isDisplayed(); - } - }); - } catch (WebDriverException e){ - File scrFile = ((TakesScreenshot)driver).getScreenshotAs(OutputType.FILE); - System.out.println("Screenshot in: " + scrFile.getAbsolutePath()); - throw e; - } finally { - // Close the browser - driver.quit(); - } - } - -*/ - - /** - * Get the url of Zeppelin - * - * @param path to add to the url ex: HOST/myPath - * @return Zeppelin url HOST:PORT{/PATH} - */ - private String getUrl(String path) { - String url; - if (System.getProperty("url") != null) { - url = System.getProperty("url"); - } else { - url = "http://localhost:8080"; - } - if (path != null) - url += path; - return url; - } - -/* - @Test - public void testZAN() { - WebDriver driver = getWebDriver(); - - try { - // goto ZAN menu - driver.findElement(By.xpath("//ul//a[text()='ZAN']")).click(); - - // wait for ZAN page loaded - (new WebDriverWait(driver, 20)).until(new ExpectedCondition() { - public Boolean apply(WebDriver d) { - return d.findElement(By.xpath("//div//a[text()='Update Catalog']")).isDisplayed(); - } - }); - } catch (WebDriverException e) { - File scrFile = ((TakesScreenshot) driver) - .getScreenshotAs(OutputType.FILE); - System.out.println("Screenshot in: " + scrFile.getAbsolutePath()); - throw e; - } finally { - // Close the browser - driver.quit(); - } - } -*/ - - - /** - * Test is swagger-ui is started - */ - /* - @Test - public void testSwaggerDocumentation() { - WebDriver driver = getWebDriver(); - try { - - driver.get(getUrl("/docs")); - // wait for Swagger page loaded - (new WebDriverWait(driver, 20)).until(new ExpectedCondition() { - public Boolean apply(WebDriver d) { - return d.findElement(By.xpath("//div//input[@id='input_apiKey']")).isDisplayed(); - } - }); - - } catch (WebDriverException ex) { - File scrFile = ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE); - System.out.println("Screenshot in: " + scrFile.getAbsolutePath()); - throw ex; - } finally { - driver.close(); - } - } - - @Test - public void testAnnotationStmt() { - // Notice that the remainder of the code relies on the interface, - // not the implementation. - WebDriver driver = getWebDriver(); - - try { - // click start - WebElement start = driver.findElement(By.partialLinkText("Start")); - start.click(); - - // Wait for the page to load, timeout after 10 seconds - (new WebDriverWait(driver, 10)).until(new ExpectedCondition() { - public Boolean apply(WebDriver d) { - return d.findElement(By.linkText("Create new Job")).isDisplayed(); - } - }); - - // click new - driver.findElement(By.linkText("Create new Job")).click(); - - // wait for run button appears - (new WebDriverWait(driver, 10)).until(new ExpectedCondition() { - public Boolean apply(WebDriver d) { - return d.findElement(By.linkText("Run")).isDisplayed(); - } - }); - - // type some query with default driver - driver.findElement(By.xpath("//div[@id='zqlEditor']//textarea")).sendKeys("@driver set exec;"); - driver.findElement(By.xpath("//div[@id='zqlEditor']//textarea")).sendKeys("\necho 'hello world';"); - - // press run button - driver.findElement(By.xpath("//div[@id='zqlEditor']//textarea")).sendKeys(Keys.chord(Keys.COMMAND, Keys.ENTER)); - driver.findElement(By.xpath("//div[@id='zqlEditor']//textarea")).sendKeys(Keys.chord(Keys.CONTROL, Keys.ENTER)); - driver.findElement(By.linkText("Run")).click(); - - // wait for button becomes Running ... - (new WebDriverWait(driver, 10)).until(new ExpectedCondition() { - public Boolean apply(WebDriver d) { - return d.findElement(By.xpath("//div//a[text()='Running ...']")).isDisplayed(); - } - }); - - // wait for button becomes Run - (new WebDriverWait(driver, 60)).until(new ExpectedCondition() { - public Boolean apply(WebDriver d) { - return d.findElement(By.xpath("//div//a[text()='Run']")).isDisplayed(); - } - }); - - WebElement msg = driver.findElement(By.id("msgBox")); - if (msg!=null) { - System.out.println("msgBox="+msg.getText()); - } - - // wait for visualization - (new WebDriverWait(driver, 20)).until(new ExpectedCondition() { - public Boolean apply(WebDriver d) { - return d.findElement(By.xpath("//div[@id='visualizationContainer']//iframe")).isDisplayed(); - } - }); - - WebDriver iframe = driver.switchTo().frame(driver.findElement(By.xpath("//div[@id='visualizationContainer']//iframe"))); - - // wait for result displayed - (new WebDriverWait(iframe, 20)).until(new ExpectedCondition() { - public Boolean apply(WebDriver d) { - return d.findElement(By.xpath("//table//td[text()='hello world']")).isDisplayed(); - } - }); - } catch (WebDriverException e){ - File scrFile = ((TakesScreenshot)driver).getScreenshotAs(OutputType.FILE); - System.out.println("Screenshot in: " + scrFile.getAbsolutePath()); - throw e; - } finally { - // Close the browser - driver.quit(); - } - } -*/ } From 80ff3d41ad31c23f7b0aad441748399f8df38192 Mon Sep 17 00:00:00 2001 From: Lee moon soo Date: Sun, 5 Jul 2015 13:30:00 -0700 Subject: [PATCH 15/17] Fix style --- .../java/org/apache/zeppelin/ZeppelinIT.java | 105 +++++++++--------- 1 file changed, 53 insertions(+), 52 deletions(-) diff --git a/zeppelin-server/src/test/java/org/apache/zeppelin/ZeppelinIT.java b/zeppelin-server/src/test/java/org/apache/zeppelin/ZeppelinIT.java index cf0f7424065..b3206096224 100644 --- a/zeppelin-server/src/test/java/org/apache/zeppelin/ZeppelinIT.java +++ b/zeppelin-server/src/test/java/org/apache/zeppelin/ZeppelinIT.java @@ -47,47 +47,48 @@ * */ public class ZeppelinIT { - private WebDriver driver; - - private WebDriver getWebDriver(){ - WebDriver driver = null; - - if (driver==null){ - try { - FirefoxBinary ffox = new FirefoxBinary(); - if ("true".equals(System.getenv("TRAVIS"))) { - ffox.setEnvironmentProperty("DISPLAY", ":99"); // xvfb is supposed to run with DISPLAY 99 - } - FirefoxProfile profile = new FirefoxProfile(); - driver = new FirefoxDriver(ffox, profile); - } catch (Exception e){ - } - } - - if (driver==null){ - try { - driver = new ChromeDriver(); - } catch (Exception e){ - } - } - - if (driver==null){ - try { - driver = new SafariDriver(); - } catch (Exception e){ - } - } - - String url; - if (System.getProperty("url")!=null) { - url = System.getProperty("url"); - } else { - url = "http://localhost:8080"; - } - - long start = System.currentTimeMillis(); - boolean loaded = false; - driver.get(url); + private WebDriver driver; + + private WebDriver getWebDriver() { + WebDriver driver = null; + + if (driver == null) { + try { + FirefoxBinary ffox = new FirefoxBinary(); + if ("true".equals(System.getenv("TRAVIS"))) { + ffox.setEnvironmentProperty("DISPLAY", ":99"); // xvfb is supposed to + // run with DISPLAY 99 + } + FirefoxProfile profile = new FirefoxProfile(); + driver = new FirefoxDriver(ffox, profile); + } catch (Exception e) { + } + } + + if (driver == null) { + try { + driver = new ChromeDriver(); + } catch (Exception e) { + } + } + + if (driver == null) { + try { + driver = new SafariDriver(); + } catch (Exception e) { + } + } + + String url; + if (System.getProperty("url") != null) { + url = System.getProperty("url"); + } else { + url = "http://localhost:8080"; + } + + long start = System.currentTimeMillis(); + boolean loaded = false; + driver.get(url); while (System.currentTimeMillis() - start < 60 * 1000) { // wait for page load @@ -106,12 +107,12 @@ public Boolean apply(WebDriver d) { } } - if (loaded==false) { - fail(); - } + if (loaded == false) { + fail(); + } - return driver; - } + return driver; + } @Before public void startUp() { @@ -150,7 +151,7 @@ boolean endToEndTestEnabled() { } @Test - public void testAngularDisplay() throws InterruptedException{ + public void testAngularDisplay() throws InterruptedException{ if (!endToEndTestEnabled()) { return; } @@ -275,9 +276,9 @@ public void testAngularDisplay() throws InterruptedException{ getParagraphXPath(1) + "//div[@id=\"angularTestButton\"]")).getText()); System.out.println("testCreateNotebook Test executed"); - } - - private String createNewNoteAndGetName() { + } + + private String createNewNoteAndGetName() { List notebookLinks = driver.findElements(By .xpath("//div[contains(@class, \"col-md-4\")]/div/ul/li")); List notebookTitles = new LinkedList(); @@ -292,7 +293,7 @@ private String createNewNoteAndGetName() { Thread.sleep(500); // wait for notebook list updated } catch (InterruptedException e) { } - + List notebookLinksAfterCreate = driver.findElements(By .xpath("//div[contains(@class, \"col-md-4\")]/div/ul/li")); @@ -307,5 +308,5 @@ private String createNewNoteAndGetName() { assertEquals(1, notebookLinksAfterCreate.size()); return notebookLinksAfterCreate.get(0).getText(); - } + } } From e00a9af12da48c7f72e5034d3fe00f7d56c2817d Mon Sep 17 00:00:00 2001 From: Lee moon soo Date: Sun, 5 Jul 2015 13:42:34 -0700 Subject: [PATCH 16/17] Fix test --- .../zeppelin/interpreter/remote/RemoteInterpreterTest.java | 1 + 1 file changed, 1 insertion(+) diff --git a/zeppelin-interpreter/src/test/java/org/apache/zeppelin/interpreter/remote/RemoteInterpreterTest.java b/zeppelin-interpreter/src/test/java/org/apache/zeppelin/interpreter/remote/RemoteInterpreterTest.java index 4263dd8c230..0c74cea54d4 100644 --- a/zeppelin-interpreter/src/test/java/org/apache/zeppelin/interpreter/remote/RemoteInterpreterTest.java +++ b/zeppelin-interpreter/src/test/java/org/apache/zeppelin/interpreter/remote/RemoteInterpreterTest.java @@ -150,6 +150,7 @@ public void testRemoteInterperterErrorStatus() throws TTransportException, IOExc intpA.open(); InterpreterResult ret = intpA.interpret("non numeric value", new InterpreterContext( + "noteId", "id", "title", "text", From 51340d22859128ef9d019e7a71064e24e0ee3666 Mon Sep 17 00:00:00 2001 From: Lee moon soo Date: Sun, 5 Jul 2015 14:26:41 -0700 Subject: [PATCH 17/17] Increase paragraph run timeout --- .../src/test/java/org/apache/zeppelin/ZeppelinIT.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zeppelin-server/src/test/java/org/apache/zeppelin/ZeppelinIT.java b/zeppelin-server/src/test/java/org/apache/zeppelin/ZeppelinIT.java index b3206096224..779396cb917 100644 --- a/zeppelin-server/src/test/java/org/apache/zeppelin/ZeppelinIT.java +++ b/zeppelin-server/src/test/java/org/apache/zeppelin/ZeppelinIT.java @@ -137,7 +137,7 @@ String getParagraphXPath(int paragraphNo) { } void waitForParagraph(final int paragraphNo, final String state) { - (new WebDriverWait(driver, 10)).until(new ExpectedCondition() { + (new WebDriverWait(driver, 60)).until(new ExpectedCondition() { public Boolean apply(WebDriver d) { return driver.findElement(By.xpath(getParagraphXPath(paragraphNo) + "//div[@class=\"control\"]//span[1][text()=\" " + state + " \"]"))