Angular object update for helium app

This commit is contained in:
Lee moon soo 2016-04-12 13:53:34 +09:00
parent 6223cd44d9
commit 16f68871da
7 changed files with 175 additions and 25 deletions

View file

@ -16,6 +16,7 @@
*/
package org.apache.zeppelin.helium;
import org.apache.zeppelin.display.AngularObjectRegistry;
import org.apache.zeppelin.interpreter.InterpreterOutput;
/**
@ -24,11 +25,16 @@ import org.apache.zeppelin.interpreter.InterpreterOutput;
public class ApplicationContext {
private final String noteId;
private final String paragraphId;
private final HeliumAppAngularObjectRegistry angularObjectRegistry;
public final InterpreterOutput out;
public ApplicationContext(String noteId, String paragraphId, InterpreterOutput out) {
public ApplicationContext(String noteId,
String paragraphId,
HeliumAppAngularObjectRegistry angularObjectRegistry,
InterpreterOutput out) {
this.noteId = noteId;
this.paragraphId = paragraphId;
this.angularObjectRegistry = angularObjectRegistry;
this.out = out;
}
@ -39,4 +45,8 @@ public class ApplicationContext {
public String getParagraphId() {
return paragraphId;
}
public HeliumAppAngularObjectRegistry getAngularObjectRegistry() {
return angularObjectRegistry;
}
}

View file

@ -0,0 +1,55 @@
/*
* 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.helium;
import org.apache.zeppelin.display.AngularObject;
import org.apache.zeppelin.display.AngularObjectRegistry;
import java.util.List;
/**
* Angular Registry for helium app
*/
public class HeliumAppAngularObjectRegistry {
private final String noteId;
private final String appId;
private final AngularObjectRegistry angularObjectRegistry;
public HeliumAppAngularObjectRegistry(AngularObjectRegistry angularObjectRegistry,
String noteId,
String appId) {
this.angularObjectRegistry = angularObjectRegistry;
this.noteId = noteId;
this.appId = appId;
}
public AngularObject add(String name, Object o) {
return angularObjectRegistry.add(name, o, noteId, appId);
}
public AngularObject remove(String name) {
return angularObjectRegistry.remove(name, noteId, appId);
}
public AngularObject get(String name) {
return angularObjectRegistry.get(name, noteId, appId);
}
public List<AngularObject> getAll() {
return angularObjectRegistry.getAll(noteId, appId);
}
}

View file

@ -725,7 +725,11 @@ public class RemoteInterpreterServer
private ApplicationContext getApplicationContext(
HeliumPackage packageInfo, String noteId, String paragraphId, String applicationInstanceId) {
InterpreterOutput out = createAppOutput(noteId, paragraphId, applicationInstanceId);
return new ApplicationContext(noteId, paragraphId, out);
return new ApplicationContext(
noteId,
paragraphId,
new HeliumAppAngularObjectRegistry(angularObjectRegistry, noteId, applicationInstanceId),
out);
}
@Override

View file

@ -86,6 +86,7 @@ public class ApplicationLoaderTest {
ApplicationContext context1 = new ApplicationContext(
noteId,
paragraphId,
null,
new InterpreterOutput(new InterpreterOutputListener() {
@Override
public void onAppend(InterpreterOutput out, byte[] line) {

View file

@ -172,8 +172,23 @@ angular.module('zeppelinWebApp')
$scope.$on('angularObjectUpdate', function(event, data) {
var noteId = $route.current.pathParams.noteId;
if (!data.noteId || (data.noteId === noteId && (!data.paragraphId || data.paragraphId === $scope.paragraph.id))) {
var scope = paragraphScope;
if (!data.noteId || data.noteId === noteId) {
var scope;
var registry;
if (!data.paragraphId || data.paragraphId === $scope.paragraph.id) {
scope = paragraphScope;
registry = angularObjectRegistry;
} else {
var app = _.find($scope.apps, { id: data.paragraphId})
if (app) {
scope = getAppScope(app);
registry = getAppRegistry(app);
} else {
// no matching app in this paragraph
return;
}
}
var varName = data.angularObject.name;
if (angular.equals(data.angularObject.object, scope[varName])) {
@ -181,32 +196,32 @@ angular.module('zeppelinWebApp')
return;
}
if (!angularObjectRegistry[varName]) {
angularObjectRegistry[varName] = {
if (!registry[varName]) {
registry[varName] = {
interpreterGroupId : data.interpreterGroupId,
noteId : data.noteId,
paragraphId : data.paragraphId
};
} else {
angularObjectRegistry[varName].noteId = angularObjectRegistry[varName].noteId || data.noteId;
angularObjectRegistry[varName].paragraphId = angularObjectRegistry[varName].paragraphId || data.paragraphId;
registry[varName].noteId = registry[varName].noteId || data.noteId;
registry[varName].paragraphId = registry[varName].paragraphId || data.paragraphId;
}
angularObjectRegistry[varName].skipEmit = true;
registry[varName].skipEmit = true;
if (!angularObjectRegistry[varName].clearWatcher) {
angularObjectRegistry[varName].clearWatcher = scope.$watch(varName, function(newValue, oldValue) {
console.log('angular object (paragraph) updated %o %o', varName, angularObjectRegistry[varName]);
if (angularObjectRegistry[varName].skipEmit) {
angularObjectRegistry[varName].skipEmit = false;
if (!registry[varName].clearWatcher) {
registry[varName].clearWatcher = scope.$watch(varName, function(newValue, oldValue) {
console.log('angular object (paragraph) updated %o %o', varName, registry[varName]);
if (registry[varName].skipEmit) {
registry[varName].skipEmit = false;
return;
}
websocketMsgSrv.updateAngularObject(
angularObjectRegistry[varName].noteId,
angularObjectRegistry[varName].paragraphId,
registry[varName].noteId,
registry[varName].paragraphId,
varName,
newValue,
angularObjectRegistry[varName].interpreterGroupId);
registry[varName].interpreterGroupId);
});
}
console.log('angular object (paragraph) created %o', varName);
@ -228,14 +243,30 @@ angular.module('zeppelinWebApp')
$scope.$on('angularObjectRemove', function(event, data) {
var noteId = $route.current.pathParams.noteId;
if (!data.noteId || (data.noteId === noteId && (!data.paragraphId || data.paragraphId === $scope.paragraph.id))) {
var scope = paragraphScope;
if (!data.noteId || data.noteId === noteId) {
var scope;
var registry;
if (!data.paragraphId || data.paragraphId === $scope.paragraph.id) {
scope = paragraphScope;
registry = angularObjectRegistry;
} else {
var app = _.find($scope.apps, { id: data.paragraphId})
if (app) {
scope = getAppScope(app);
registry = getAppRegistry(app);
} else {
// no matching app in this paragraph
return;
}
}
var varName = data.name;
// clear watcher
if (angularObjectRegistry[varName]) {
angularObjectRegistry[varName].clearWatcher();
angularObjectRegistry[varName] = undefined;
if (registry[varName]) {
registry[varName].clearWatcher();
registry[varName] = undefined;
}
// remove scope variable
@ -2254,6 +2285,21 @@ angular.module('zeppelinWebApp')
});
};
var getAppScope = function(appState) {
if (!appState.scope) {
appState.scope = $rootScope.$new(true, $rootScope);
}
return appState.scope;
};
var getAppRegistry = function(appState) {
if (!appState.registry) {
appState.registry = {};
}
return appState.registry;
};
var renderApp = function(appState) {
var retryRenderer = function() {
@ -2263,7 +2309,7 @@ angular.module('zeppelinWebApp')
try {
console.log('renderApp %o', appState);
targetEl.html(appState.output);
$compile(targetEl.contents())(paragraphScope);
$compile(targetEl.contents())(getAppScope(appState));
} catch(err) {
console.log('App rendering error %o', err);
}
@ -2285,7 +2331,7 @@ angular.module('zeppelinWebApp')
var targetEl = angular.element(document.getElementById('p' + app.id));
targetEl.html(app.output);
$compile(targetEl.contents())(paragraphScope);
$compile(targetEl.contents())(getAppScope(app));
console.log('append app output %o', $scope.apps);
}
}
@ -2302,7 +2348,7 @@ angular.module('zeppelinWebApp')
var targetEl = angular.element(document.getElementById('p' + app.id));
targetEl.html(app.output);
$compile(targetEl.contents())(paragraphScope);
$compile(targetEl.contents())(getAppScope(app));
console.log('append app output');
}
}

View file

@ -438,8 +438,25 @@ public class Note implements Serializable, ParagraphJobListener {
if (registry instanceof RemoteAngularObjectRegistry) {
// remove paragraph scope object
((RemoteAngularObjectRegistry) registry).removeAllAndNotifyRemoteProcess(id, paragraphId);
// remove app scope object
List<ApplicationState> appStates = getParagraph(paragraphId).getAllApplicationStates();
if (appStates != null) {
for (ApplicationState app : appStates) {
((RemoteAngularObjectRegistry) registry).removeAllAndNotifyRemoteProcess(
id, app.getId());
}
}
} else {
registry.removeAll(id, paragraphId);
// remove app scope object
List<ApplicationState> appStates = getParagraph(paragraphId).getAllApplicationStates();
if (appStates != null) {
for (ApplicationState app : appStates) {
registry.removeAll(id, app.getId());
}
}
}
}
}

View file

@ -306,6 +306,15 @@ public class Notebook implements NoteEventListener {
// remove paragraph scope object
for (Paragraph p : note.getParagraphs()) {
((RemoteAngularObjectRegistry) registry).removeAllAndNotifyRemoteProcess(id, p.getId());
// remove app scope object
List<ApplicationState> appStates = p.getAllApplicationStates();
if (appStates != null) {
for (ApplicationState app : appStates) {
((RemoteAngularObjectRegistry) registry).removeAllAndNotifyRemoteProcess(
id, app.getId());
}
}
}
// remove notebook scope object
((RemoteAngularObjectRegistry) registry).removeAllAndNotifyRemoteProcess(id, null);
@ -313,6 +322,14 @@ public class Notebook implements NoteEventListener {
// remove paragraph scope object
for (Paragraph p : note.getParagraphs()) {
registry.removeAll(id, p.getId());
// remove app scope object
List<ApplicationState> appStates = p.getAllApplicationStates();
if (appStates != null) {
for (ApplicationState app : appStates) {
registry.removeAll(id, app.getId());
}
}
}
// remove notebook scope object
registry.removeAll(id, null);