/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.zeppelin.interpreter;
import org.apache.zeppelin.annotation.Experimental;
import org.apache.zeppelin.annotation.ZeppelinApi;
import org.apache.zeppelin.display.AngularObject;
import org.apache.zeppelin.display.AngularObjectRegistry;
import org.apache.zeppelin.display.AngularObjectWatcher;
import org.apache.zeppelin.display.GUI;
import org.apache.zeppelin.display.ui.OptionInput.ParamOption;
import org.apache.zeppelin.interpreter.remote.RemoteEventClientWrapper;
import org.apache.zeppelin.resource.Resource;
import org.apache.zeppelin.resource.ResourcePool;
import org.apache.zeppelin.resource.ResourceSet;
import java.io.IOException;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
/**
* Base class for ZeppelinContext
*/
public abstract class BaseZeppelinContext {
protected InterpreterContext interpreterContext;
protected int maxResult;
protected InterpreterHookRegistry hooks;
protected GUI gui;
private static RemoteEventClientWrapper eventClient;
public BaseZeppelinContext(InterpreterHookRegistry hooks, int maxResult) {
this.hooks = hooks;
this.maxResult = maxResult;
}
// Map interpreter class name (to be used by hook registry) from
// given replName in parapgraph
public abstract Map<String, String> getInterpreterClassMap();
public abstract List<Class> getSupportedClasses();
public int getMaxResult() {
return this.maxResult;
}
/**
* subclasses should implement this method to display specific data type
* @param obj
* @return
*/
protected abstract String showData(Object obj);
/**
* @deprecated use z.textbox instead
*
*/
@Deprecated
@ZeppelinApi
public Object input(String name) {
return textbox(name);
}
/**
* @deprecated use z.textbox instead
*/
@Deprecated
@ZeppelinApi
public Object input(String name, Object defaultValue) {
return textbox(name, defaultValue.toString());
}
@ZeppelinApi
public Object textbox(String name) {
return textbox(name, "");
}
@ZeppelinApi
public Object textbox(String name, String defaultValue) {
return gui.textbox(name, defaultValue);
}
public Object select(String name, Object defaultValue, ParamOption[] paramOptions) {
return gui.select(name, defaultValue, paramOptions);
}
@ZeppelinApi
public Collection<Object> checkbox(String name, ParamOption[] options) {
List<Object> defaultValues = new LinkedList<>();
for (ParamOption option : options) {
defaultValues.add(option.getValue());
}
return checkbox(name, defaultValues, options);
}
@ZeppelinApi
public Collection<Object> checkbox(String name,
List<Object> defaultValues,
ParamOption[] options) {
return gui.checkbox(name, defaultValues, options);
}
public void setGui(GUI o) {
this.gui = o;
}
private void restartInterpreter() {
}
public InterpreterContext getInterpreterContext() {
return interpreterContext;
}
public void setInterpreterContext(InterpreterContext interpreterContext) {
this.interpreterContext = interpreterContext;
}
public void setMaxResult(int maxResult) {
this.maxResult = maxResult;
}
/**
* display special types of objects for interpreter.
* Each interpreter can has its own supported classes.
* @param o object
*/
@ZeppelinApi
public void show(Object o) {
show(o, maxResult);
}
/**
* display special types of objects for interpreter.
* Each interpreter can has its own supported classes.
* @param o object
* @param maxResult maximum number of rows to display
*/
@ZeppelinApi
public void show(Object o, int maxResult) {
try {
if (isSupportedObject(o)) {
interpreterContext.out.write(showData(o));
} else {
interpreterContext.out.write(o.toString());
}
} catch (IOException e) {
throw new InterpreterException(e);
}
}
private boolean isSupportedObject(Object obj) {
for (Class supportedClass : getSupportedClasses()) {
if (supportedClass.isInstance(obj)) {
return true;
}
}
return false;
}
/**
* Run paragraph by id
* @param noteId
* @param paragraphId
*/
@ZeppelinApi
public void run(String noteId, String paragraphId) {
run(noteId, paragraphId, interpreterContext, true);
}
/**
* Run paragraph by id
* @param paragraphId
*/
@ZeppelinApi
public void run(String paragraphId) {
run(paragraphId, true);
}
/**
* Run paragraph by id
* @param paragraphId
* @param checkCurrentParagraph
*/
@ZeppelinApi
public void run(String paragraphId, boolean checkCurrentParagraph) {
String noteId = interpreterContext.getNoteId();
run(noteId, paragraphId, interpreterContext, checkCurrentParagraph);
}
/**
* Run paragraph by id
* @param noteId
*/
@ZeppelinApi
public void run(String noteId, String paragraphId, InterpreterContext context) {
run(noteId, paragraphId, context, true);
}
/**
* Run paragraph by id
* @param noteId
* @param context
*/
@ZeppelinApi
public void run(String noteId, String paragraphId, InterpreterContext context,
boolean checkCurrentParagraph) {
if (paragraphId.equals(context.getParagraphId()) && checkCurrentParagraph) {
throw new InterpreterException("Can not run current Paragraph");
}
List<InterpreterContextRunner> runners =
getInterpreterContextRunner(noteId, paragraphId, context);
if (runners.size() <= 0) {
throw new InterpreterException("Paragraph " + paragraphId + " not found " + runners.size());
}
for (InterpreterContextRunner r : runners) {
r.run();
}
}
public void runNote(String noteId) {
runNote(noteId, interpreterContext);
}
public void runNote(String noteId, InterpreterContext context) {
String runningNoteId = context.getNoteId();
String runningParagraphId = context.getParagraphId();
List<InterpreterContextRunner> runners = getInterpreterContextRunner(noteId, context);
if (runners.size() <= 0) {
throw new InterpreterException("Note " + noteId + " not found " + runners.size());
}
for (InterpreterContextRunner r : runners) {
if (r.getNoteId().equals(runningNoteId) && r.getParagraphId().equals(runningParagraphId)) {
continue;
}
r.run();
}
}
/**
* get Zeppelin Paragraph Runner from zeppelin server
* @param noteId
*/
@ZeppelinApi
public List<InterpreterContextRunner> getInterpreterContextRunner(
String noteId, InterpreterContext interpreterContext) {
List<InterpreterContextRunner> runners = new LinkedList<>();
RemoteWorksController remoteWorksController = interpreterContext.getRemoteWorksController();
if (remoteWorksController != null) {
runners = remoteWorksController.getRemoteContextRunner(noteId);
}
return runners;
}
/**
* get Zeppelin Paragraph Runner from zeppelin server
* @param noteId
* @param paragraphId
*/
@ZeppelinApi
public List<InterpreterContextRunner> getInterpreterContextRunner(
String noteId, String paragraphId, InterpreterContext interpreterContext) {
List<InterpreterContextRunner> runners = new LinkedList<>();
RemoteWorksController remoteWorksController = interpreterContext.getRemoteWorksController();
if (remoteWorksController != null) {
runners = remoteWorksController.getRemoteContextRunner(noteId, paragraphId);
}
return runners;
}
/**
* Run paragraph at idx
* @param idx
*/
@ZeppelinApi
public void run(int idx) {
run(idx, true);
}
/**
*
* @param idx paragraph index
* @param checkCurrentParagraph check whether you call this run method in the current paragraph.
* Set it to false only when you are sure you are not invoking this method to run current
* paragraph. Otherwise you would run current paragraph in infinite loop.
*/
public void run(int idx, boolean checkCurrentParagraph) {
String noteId = interpreterContext.getNoteId();
run(noteId, idx, interpreterContext, checkCurrentParagraph);
}
/**
* Run paragraph at index
* @param noteId
* @param idx index starting from 0
* @param context interpreter context
*/
public void run(String noteId, int idx, InterpreterContext context) {
run(noteId, idx, context, true);
}
/**
*
* @param noteId
* @param idx paragraph index
* @param context interpreter context
* @param checkCurrentParagraph check whether you call this run method in the current paragraph.
* Set it to false only when you are sure you are not invoking this method to run current
* paragraph. Otherwise you would run current paragraph in infinite loop.
*/
public void run(String noteId, int idx, InterpreterContext context,
boolean checkCurrentParagraph) {
List<InterpreterContextRunner> runners = getInterpreterContextRunner(noteId, context);
if (idx >= runners.size()) {
throw new InterpreterException("Index out of bound");
}
InterpreterContextRunner runner = runners.get(idx);
if (runner.getParagraphId().equals(context.getParagraphId()) && checkCurrentParagraph) {
throw new InterpreterException("Can not run current Paragraph: " + runner.getParagraphId());
}
runner.run();
}
@ZeppelinApi
public void run(List<Object> paragraphIdOrIdx) {
run(paragraphIdOrIdx, interpreterContext);
}
/**
* Run paragraphs
* @param paragraphIdOrIdx list of paragraph id or idx
*/
@ZeppelinApi
public void run(List<Object> paragraphIdOrIdx, InterpreterContext context) {
String noteId = context.getNoteId();
for (Object idOrIdx : paragraphIdOrIdx) {
if (idOrIdx instanceof String) {
String paragraphId = (String) idOrIdx;
run(noteId, paragraphId, context);
} else if (idOrIdx instanceof Integer) {
Integer idx = (Integer) idOrIdx;
run(noteId, idx, context);
} else {
throw new InterpreterException("Paragraph " + idOrIdx + " not found");
}
}
}
@ZeppelinApi
public void runAll() {
runAll(interpreterContext);
}
/**
* Run all paragraphs. except this.
*/
@ZeppelinApi
public void runAll(InterpreterContext context) {
runNote(context.getNoteId());
}
@ZeppelinApi
public List<String> listParagraphs() {
List<String> paragraphs = new LinkedList<>();
for (InterpreterContextRunner r : interpreterContext.getRunners()) {
paragraphs.add(r.getParagraphId());
}
return paragraphs;
}
private AngularObject getAngularObject(String name, InterpreterContext interpreterContext) {
AngularObjectRegistry registry = interpreterContext.getAngularObjectRegistry();
String noteId = interpreterContext.getNoteId();
// try get local object
AngularObject paragraphAo = registry.get(name, noteId, interpreterContext.getParagraphId());
AngularObject noteAo = registry.get(name, noteId, null);
AngularObject ao = paragraphAo != null ? paragraphAo : noteAo;
if (ao == null) {
// then global object
ao = registry.get(name, null, null);
}
return ao;
}
/**
* Get angular object. Look up notebook scope first and then global scope
* @param name variable name
* @return value
*/
@ZeppelinApi
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 scope
* @param name variable name
* @return value
*/
@Deprecated
public Object angularGlobal(String name) {
AngularObjectRegistry registry = interpreterContext.getAngularObjectRegistry();
AngularObject ao = registry.get(name, null, null);
if (ao == null) {
return null;
} else {
return ao.get();
}
}
/**
* Create angular variable in notebook scope and bind with front end Angular display system.
* If variable exists, it'll be overwritten.
* @param name name of the variable
* @param o value
*/
@ZeppelinApi
public void angularBind(String name, Object o) {
angularBind(name, o, interpreterContext.getNoteId());
}
/**
* Create angular variable in global scope and bind with front end Angular display system.
* If variable exists, it'll be overwritten.
* @param name name of the variable
* @param o value
*/
@Deprecated
public void angularBindGlobal(String name, Object o) {
angularBind(name, o, (String) null);
}
/**
* Create angular variable in local scope 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
*/
@ZeppelinApi
public void angularBind(String name, Object o, AngularObjectWatcher watcher) {
angularBind(name, o, interpreterContext.getNoteId(), watcher);
}
/**
* Create angular variable in global scope 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
*/
@Deprecated
public void angularBindGlobal(String name, Object o, AngularObjectWatcher watcher) {
angularBind(name, o, null, watcher);
}
/**
* Add watcher into angular variable (local scope)
* @param name name of the variable
* @param watcher watcher
*/
@ZeppelinApi
public void angularWatch(String name, AngularObjectWatcher watcher) {
angularWatch(name, interpreterContext.getNoteId(), watcher);
}
/**
* Add watcher into angular variable (global scope)
* @param name name of the variable
* @param watcher watcher
*/
@Deprecated
public void angularWatchGlobal(String name, AngularObjectWatcher watcher) {
angularWatch(name, null, watcher);
}
/**
* Remove watcher from angular variable (local)
* @param name
* @param watcher
*/
@ZeppelinApi
public void angularUnwatch(String name, AngularObjectWatcher watcher) {
angularUnwatch(name, interpreterContext.getNoteId(), watcher);
}
/**
* Remove watcher from angular variable (global)
* @param name
* @param watcher
*/
@Deprecated
public void angularUnwatchGlobal(String name, AngularObjectWatcher watcher) {
angularUnwatch(name, null, watcher);
}
/**
* Remove all watchers for the angular variable (local)
* @param name
*/
@ZeppelinApi
public void angularUnwatch(String name) {
angularUnwatch(name, interpreterContext.getNoteId());
}
/**
* Remove all watchers for the angular variable (global)
* @param name
*/
@Deprecated
public void angularUnwatchGlobal(String name) {
angularUnwatch(name, (String) null);
}
/**
* Remove angular variable and all the watchers.
* @param name
*/
@ZeppelinApi
public void angularUnbind(String name) {
String noteId = interpreterContext.getNoteId();
angularUnbind(name, noteId);
}
/**
* Remove angular variable and all the watchers.
* @param name
*/
@Deprecated
public void angularUnbindGlobal(String name) {
angularUnbind(name, null);
}
/**
* Create angular variable in notebook scope 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) == null) {
registry.add(name, o, noteId, null);
} else {
registry.get(name, noteId, null).set(o);
}
}
/**
* Create angular variable in notebook scope 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, noteId, null) == null) {
registry.add(name, o, noteId, null);
} else {
registry.get(name, noteId, null).set(o);
}
angularWatch(name, watcher);
}
/**
* Add watcher into angular binding variable
* @param name name of the variable
* @param watcher watcher
*/
public void angularWatch(String name, String noteId, AngularObjectWatcher watcher) {
AngularObjectRegistry registry = interpreterContext.getAngularObjectRegistry();
if (registry.get(name, noteId, null) != null) {
registry.get(name, noteId, null).addWatcher(watcher);
}
}
/**
* Remove watcher
* @param name
* @param watcher
*/
private void angularUnwatch(String name, String noteId, AngularObjectWatcher watcher) {
AngularObjectRegistry registry = interpreterContext.getAngularObjectRegistry();
if (registry.get(name, noteId, null) != null) {
registry.get(name, noteId, null).removeWatcher(watcher);
}
}
/**
* Remove all watchers for the angular variable
* @param name
*/
private void angularUnwatch(String name, String noteId) {
AngularObjectRegistry registry = interpreterContext.getAngularObjectRegistry();
if (registry.get(name, noteId, null) != null) {
registry.get(name, noteId, null).clearAllWatchers();
}
}
/**
* Remove angular variable and all the watchers.
* @param name
*/
private void angularUnbind(String name, String noteId) {
AngularObjectRegistry registry = interpreterContext.getAngularObjectRegistry();
registry.remove(name, noteId, null);
}
/**
* Get the interpreter class name from name entered in paragraph
* @param replName if replName is a valid className, return that instead.
*/
public String getClassNameFromReplName(String replName) {
for (String name : getInterpreterClassMap().keySet()) {
if (replName.equals(name)) {
return replName;
}
}
if (replName.contains("spark.")) {
replName = replName.replace("spark.", "");
}
return getInterpreterClassMap().get(replName);
}
/**
* General function to register hook event
* @param event The type of event to hook to (pre_exec, post_exec)
* @param cmd The code to be executed by the interpreter on given event
* @param replName Name of the interpreter
*/
@Experimental
public void registerHook(String event, String cmd, String replName) {
String noteId = interpreterContext.getNoteId();
String className = getClassNameFromReplName(replName);
hooks.register(noteId, className, event, cmd);
}
/**
* registerHook() wrapper for current repl
* @param event The type of event to hook to (pre_exec, post_exec)
* @param cmd The code to be executed by the interpreter on given event
*/
@Experimental
public void registerHook(String event, String cmd) {
String className = interpreterContext.getClassName();
registerHook(event, cmd, className);
}
/**
* Get the hook code
* @param event The type of event to hook to (pre_exec, post_exec)
* @param replName Name of the interpreter
*/
@Experimental
public String getHook(String event, String replName) {
String noteId = interpreterContext.getNoteId();
String className = getClassNameFromReplName(replName);
return hooks.get(noteId, className, event);
}
/**
* getHook() wrapper for current repl
* @param event The type of event to hook to (pre_exec, post_exec)
*/
@Experimental
public String getHook(String event) {
String className = interpreterContext.getClassName();
return getHook(event, className);
}
/**
* Unbind code from given hook event
* @param event The type of event to hook to (pre_exec, post_exec)
* @param replName Name of the interpreter
*/
@Experimental
public void unregisterHook(String event, String replName) {
String noteId = interpreterContext.getNoteId();
String className = getClassNameFromReplName(replName);
hooks.unregister(noteId, className, event);
}
/**
* unregisterHook() wrapper for current repl
* @param event The type of event to hook to (pre_exec, post_exec)
*/
@Experimental
public void unregisterHook(String event) {
String className = interpreterContext.getClassName();
unregisterHook(event, className);
}
/**
* Add object into resource pool
* @param name
* @param value
*/
@ZeppelinApi
public void put(String name, Object value) {
ResourcePool resourcePool = interpreterContext.getResourcePool();
resourcePool.put(name, value);
}
/**
* Get object from resource pool
* Search local process first and then the other processes
* @param name
* @return null if resource not found
*/
@ZeppelinApi
public Object get(String name) {
ResourcePool resourcePool = interpreterContext.getResourcePool();
Resource resource = resourcePool.get(name);
if (resource != null) {
return resource.get();
} else {
return null;
}
}
/**
* Remove object from resourcePool
* @param name
*/
@ZeppelinApi
public void remove(String name) {
ResourcePool resourcePool = interpreterContext.getResourcePool();
resourcePool.remove(name);
}
/**
* Check if resource pool has the object
* @param name
* @return
*/
@ZeppelinApi
public boolean containsKey(String name) {
ResourcePool resourcePool = interpreterContext.getResourcePool();
Resource resource = resourcePool.get(name);
return resource != null;
}
/**
* Get all resources
*/
@ZeppelinApi
public ResourceSet getAll() {
ResourcePool resourcePool = interpreterContext.getResourcePool();
return resourcePool.getAll();
}
/**
* Get the event client
*/
@ZeppelinApi
public static RemoteEventClientWrapper getEventClient() {
return eventClient;
}
/**
* Set event client
*/
@ZeppelinApi
public void setEventClient(RemoteEventClientWrapper eventClient) {
if (BaseZeppelinContext.eventClient == null) {
BaseZeppelinContext.eventClient = eventClient;
}
}
}