From 87b484a1d0587b136a9bd1253a27903fb056c200 Mon Sep 17 00:00:00 2001 From: 1000TurquoisePogs Date: Thu, 7 Feb 2019 14:44:10 -0500 Subject: [PATCH] Making dispatcher into an anonymous object to make its recognizers and action arrays private Signed-off-by: 1000TurquoisePogs --- base/src/dispatcher/dispatcher.ts | 739 +++++++++++++++--------------- 1 file changed, 381 insertions(+), 358 deletions(-) diff --git a/base/src/dispatcher/dispatcher.ts b/base/src/dispatcher/dispatcher.ts index 696bd8d..1fad1bd 100644 --- a/base/src/dispatcher/dispatcher.ts +++ b/base/src/dispatcher/dispatcher.ts @@ -53,172 +53,32 @@ export class DispatcherConstants implements ZLUX.DispatcherConstants { readonly ActionType = ActionType; } -export class Dispatcher implements ZLUX.Dispatcher { - private instancesForTypes : Map = new Map(); - recognizers:RecognitionRule[] = []; - actionsByID :Map = new Map(); - indexedRecognizers :Map = new Map(); - launchCallback: any = null; - private pluginWatchers: Map> = new Map(); - postMessageCallback: any = null; - public readonly constants:DispatcherConstants = new DispatcherConstants(); - private log:ZLUX.ComponentLogger; - - constructor(logger: ZLUX.Logger){ - /* dispatcher created early on - refering to logger from window object as a result */ - this.log = logger.makeComponentLogger("ZLUX.Dispatcher"); - this.runHeartbeat(); - } - - - registerApplicationCallbacks(plugin:ZLUX.Plugin, applicationInstanceId: any, callbacks:ZLUX.ApplicationCallbacks): void { - let wrapper = this.getAppInstanceWrapper(plugin,applicationInstanceId); - if (wrapper) { - wrapper.callbacks = callbacks; - } - } - - static dispatcherHeartbeatInterval:number = 60000; /* one minute */ - - runHeartbeat():void { - let dispatcherHeartbeatFunction = () => { - this.log.debug("dispatcher heart beat"); - this.log.debug("instances for Types = "+this.instancesForTypes.toString()); - let keyIterator:Iterator = this.instancesForTypes.keys(); - while (true){ - let iterationValue = keyIterator.next(); - if (iterationValue.done) break; - let key = iterationValue.value; - let wrappers:ApplicationInstanceWrapper[]|undefined = this.instancesForTypes.get(key); - this.log.debug("disp.heartbeat: key "+JSON.stringify(key)+" val="+wrappers); - if (wrappers){ - for (let wrapper of (wrappers as ApplicationInstanceWrapper[])){ - this.log.debug("wrapper="+wrapper); - this.postMessageCallback(wrapper.applicationInstanceId, - { dispatchType: "echo", - dispatchData: { a: 1 } - }); - } - } - - } - - window.setTimeout(dispatcherHeartbeatFunction,Dispatcher.dispatcherHeartbeatInterval); - }; - window.setTimeout(dispatcherHeartbeatFunction,Dispatcher.dispatcherHeartbeatInterval); - } - - deregisterPluginInstance(plugin: ZLUX.Plugin, applicationInstanceId: MVDHosting.InstanceId):void { - this.log.info(`Dispatcher requested to deregister plugin ${plugin} with id ${applicationInstanceId}`); - let key = plugin.getKey(); - let instancesArray = this.instancesForTypes.get(key); - if (!instancesArray) { - this.log.warn("Couldn't deregister instance for plugin ${plugin} because no instances were found"); - } else { - for (let i = 0; i < instancesArray.length; i++) { - if (instancesArray[i].applicationInstanceId === applicationInstanceId) { - instancesArray.splice(i,1); - this.log.debug(`Deregistered application instance with id ${applicationInstanceId} from plugin ${plugin} successfully`); - let watchers = this.pluginWatchers.get(key); - if (watchers) { - for (let j = 0; j < watchers.length; j++) { - watchers[j].instanceRemoved(applicationInstanceId); - } - } - return; - } - } - this.log.warn(`Could not find application instance with id ${applicationInstanceId} in plugins list. Already deregistered?`); - } - } - - registerPluginInstance(plugin: ZLUX.Plugin, applicationInstanceId: MVDHosting.InstanceId, isIframe:boolean, isEmbedded?:boolean): void { - this.log.info("Registering plugin="+plugin+" id="+applicationInstanceId); - let instanceWrapper = new ApplicationInstanceWrapper(applicationInstanceId,isIframe); - let key = plugin.getKey(); - if (!this.instancesForTypes.get(key)){ - this.instancesForTypes.set(key,[instanceWrapper]); - } else { - let ids:any[] = (this.instancesForTypes.get(key) as any[]); - ids.push(instanceWrapper); - } - let watchers = this.pluginWatchers.get(key); - if (watchers) { - for (let i = 0; i < watchers.length; i++) { - watchers[i].instanceAdded(applicationInstanceId, isEmbedded); - } - } - // Michael - how to get window manager, IE, how to get interface to look up plugins, - // or be called on plugin instance lifecycle stuff. - } +export class DispatcherFactory { + public makeDispatcher(logger:ZLUX.Logger):ZLUX.Dispatcher{return Dispatcher(logger)}; +} - setLaunchHandler(launchCallback: any): void { - this.launchCallback = launchCallback; - } +function Dispatcher(logger: ZLUX.Logger): ZLUX.Dispatcher { - setPostMessageHandler( postMessageCallback: any):void{ - this.postMessageCallback = postMessageCallback; - } - - matchInList(recognizersForIndex: any[], - propertyValue: any, - shouldCreate: boolean): any { - for (let recognizersForValue of recognizersForIndex){ - if (recognizersForValue.propertyValue == propertyValue){ - return recognizersForValue; - } - }; - if (shouldCreate){ - let recognizersForValue = { propertyValue: propertyValue, recognizerList: [] }; - recognizersForIndex.push(recognizersForValue); - return recognizersForValue; - } else { - return null; - } - } - - getRecognizers(tuple:any):RecognitionRule[] { - let matchedRecognizers:any[] = []; - // we can get the set of recognizers that match on this property at top clause - // and those that don't, too. - // PropertyRecognizers table of propName-> ( tableOfRecognizersPerValue, otherRecognizers) - // if tuple has a prop - // prop indexed - // get recognizers per value, or none - // prop not indexed - // use all recognizer list - // need iteration on propertyNames for tuple - // - this.log.debug("getRecognizers"+JSON.stringify(tuple)); - for (let propertyName in tuple){ - let recognizerIndex:RecognizerIndex|undefined = this.indexedRecognizers.get(propertyName); - this.log.debug("recognizerIndex="+recognizerIndex); - if (recognizerIndex){ - let ruleArray:RecognitionRule[]|undefined = recognizerIndex.valueMap.get(tuple[propertyName]); - this.log.debug("ruleArray="+ruleArray); - if (ruleArray){ - for (let rule of ruleArray){ - if (rule.predicate.match(tuple)){ - matchedRecognizers.push(rule); - } - } - } - return matchedRecognizers; // since we had an index, good enough - } - } - this.recognizers.forEach( (recognizer:RecognitionRule) => { - if (recognizer.predicate.match(tuple)){ - matchedRecognizers.push(recognizer); - } - }); - return matchedRecognizers; - } + //private + let instancesForTypes : Map = new Map(); + let recognizers:RecognitionRule[] = []; + let actionsByID :Map = new Map(); + let indexedRecognizers :Map = new Map(); + let pluginWatchers: Map> = new Map(); + let log:ZLUX.ComponentLogger = logger.makeComponentLogger("ZLUX.Dispatcher"); + - addRecognizerFromObject(predicateObject:ZLUX.RecognitionObjectPropClause | ZLUX.RecognitionObjectOpClause, actionID:string):void{ - this.addRecognizer(this.addRecognizerFromObjectInner(predicateObject), actionID); + //static + let dispatcherHeartbeatInterval:number = 60000; /* one minute */ + let isAtomicType = function(specType:string):boolean{ + return ((specType === "boolean") || + (specType === "number") || + (specType === "string") || + (specType === "symbol") || + (specType === "function")); } - - private addRecognizerFromObjectInner(predicateObject:ZLUX.RecognitionObjectPropClause | ZLUX.RecognitionObjectOpClause):RecognitionClause{ + + let addRecognizerFromObjectInner = function(predicateObject:ZLUX.RecognitionObjectPropClause | ZLUX.RecognitionObjectOpClause):RecognitionClause{ // type checking as illustrated in "Type Guards and Differentiating Types" of https://www.typescriptlang.org/docs/handbook/advanced-types.html if ((predicateObject).op) { const predicateOp: ZLUX.RecognitionObjectOpClause = predicateObject @@ -228,7 +88,7 @@ export class Dispatcher implements ZLUX.Dispatcher { if (predicateOp.args) { let args:any = []; predicateOp.args.forEach((arg:any)=> { - args.push(this.addRecognizerFromObjectInner(arg)); + args.push(addRecognizerFromObjectInner(arg)); }); if (predicateOp.op === 'AND') { return new RecognizerAnd(...args); @@ -249,47 +109,211 @@ export class Dispatcher implements ZLUX.Dispatcher { } } - addRecognizer(predicate:RecognitionClause, actionID:string):void{ - let recognitionRule:RecognitionRule = new RecognitionRule(predicate,actionID); - this.recognizers.push(recognitionRule); - if (predicate.operation == RecognitionOp.AND){ - for (let subClause of predicate.subClauses){ - if ((subClause as RecognitionClause).operation == RecognitionOp.PROPERTY_EQ){ - let propertyClause:RecognitionClause = subClause as RecognitionClause; - let propertyName:string = propertyClause.subClauses[0] as string; - let propertyValue:string|number = propertyClause.subClauses[1] as string|number; - let recognizerIndex = this.indexedRecognizers.get(propertyName); - this.log.debug("addRecognizer recognizersForIndex="+recognizerIndex); - // here - fix me - // test server/client - // filter crap - are the screen ID's broken?? - should be no screen ID in tuple on first page - // why not getting 5 things? - if (recognizerIndex){ - let ruleArray:RecognitionRule[]|undefined = recognizerIndex.valueMap.get(propertyValue); - if (!ruleArray){ - ruleArray = []; - recognizerIndex.valueMap.set(propertyValue,ruleArray); - } - ruleArray.push(recognitionRule); - } - } - } - } - } + let getAppInstanceWrapper = function(plugin:ZLUX.Plugin, id:MVDHosting.InstanceId) :ApplicationInstanceWrapper|null{ + let wrappers:ApplicationInstanceWrapper[]|undefined = instancesForTypes.get(plugin.getKey()); + log.debug("found some wrappers "+wrappers); + if (wrappers){ + for (let wrapper of (wrappers as ApplicationInstanceWrapper[])){ + if (wrapper.applicationInstanceId === id){ + return wrapper; + } + } + } + return null; + } + + //public + let launchCallback: any = null; + let postMessageCallback: any = null; + let constants:DispatcherConstants= new DispatcherConstants(); + let registerApplicationCallbacks = function(plugin:ZLUX.Plugin, applicationInstanceId: any, callbacks:ZLUX.ApplicationCallbacks): void { + let wrapper = getAppInstanceWrapper(plugin,applicationInstanceId); + if (wrapper) { + wrapper.callbacks = callbacks; + } + }; + + let runHeartbeat = function():void { + let dispatcherHeartbeatFunction = () => { + log.debug("dispatcher heart beat"); + log.debug("instances for Types = "+instancesForTypes.toString()); + let keyIterator:Iterator = instancesForTypes.keys(); + while (true){ + let iterationValue = keyIterator.next(); + if (iterationValue.done) break; + let key = iterationValue.value; + let wrappers:ApplicationInstanceWrapper[]|undefined = instancesForTypes.get(key); + log.debug("disp.heartbeat: key "+JSON.stringify(key)+" val="+wrappers); + if (wrappers){ + for (let wrapper of (wrappers as ApplicationInstanceWrapper[])){ + log.debug("wrapper="+wrapper); + postMessageCallback(wrapper.applicationInstanceId, + { dispatchType: "echo", + dispatchData: { a: 1 } + }); + } + } + + } + + window.setTimeout(dispatcherHeartbeatFunction,dispatcherHeartbeatInterval); + }; + window.setTimeout(dispatcherHeartbeatFunction,dispatcherHeartbeatInterval); + }; + + let deregisterPluginInstance = function(plugin: ZLUX.Plugin, applicationInstanceId: MVDHosting.InstanceId):void { + log.info(`Dispatcher requested to deregister plugin ${plugin} with id ${applicationInstanceId}`); + let key = plugin.getKey(); + let instancesArray = instancesForTypes.get(key); + if (!instancesArray) { + log.warn("Couldn't deregister instance for plugin ${plugin} because no instances were found"); + } else { + for (let i = 0; i < instancesArray.length; i++) { + if (instancesArray[i].applicationInstanceId === applicationInstanceId) { + instancesArray.splice(i,1); + log.debug(`Deregistered application instance with id ${applicationInstanceId} from plugin ${plugin} successfully`); + let watchers = pluginWatchers.get(key); + if (watchers) { + for (let j = 0; j < watchers.length; j++) { + watchers[j].instanceRemoved(applicationInstanceId); + } + } + return; + } + } + log.warn(`Could not find application instance with id ${applicationInstanceId} in plugins list. Already deregistered?`); + } + }; - registerPluginWatcher(plugin:ZLUX.Plugin, watcher: ZLUX.PluginWatcher) { + let registerPluginInstance = function(plugin: ZLUX.Plugin, applicationInstanceId: MVDHosting.InstanceId, isIframe:boolean, isEmbedded?:boolean): void { + log.info("Registering plugin="+plugin+" id="+applicationInstanceId); + let instanceWrapper = new ApplicationInstanceWrapper(applicationInstanceId,isIframe); let key = plugin.getKey(); - let watchers = this.pluginWatchers.get(key); + if (!instancesForTypes.get(key)){ + instancesForTypes.set(key,[instanceWrapper]); + } else { + let ids:any[] = (instancesForTypes.get(key) as any[]); + ids.push(instanceWrapper); + } + let watchers = pluginWatchers.get(key); + if (watchers) { + for (let i = 0; i < watchers.length; i++) { + watchers[i].instanceAdded(applicationInstanceId, isEmbedded); + } + } + // Michael - how to get window manager, IE, how to get interface to look up plugins, + // or be called on plugin instance lifecycle stuff. + }; + + let setLaunchHandler = function(newLaunchCallback: any): void { + launchCallback = newLaunchCallback; + }; + + let setPostMessageHandler = function(newPostMessageCallback: any):void{ + postMessageCallback = newPostMessageCallback; + }; + +/* unused, typescript complained + let matchInList = function(recognizersForIndex: any[], + propertyValue: any, + shouldCreate: boolean): any { + for (let recognizersForValue of recognizersForIndex){ + if (recognizersForValue.propertyValue == propertyValue){ + return recognizersForValue; + } + }; + if (shouldCreate){ + let recognizersForValue = { propertyValue: propertyValue, recognizerList: [] }; + recognizersForIndex.push(recognizersForValue); + return recognizersForValue; + } else { + return null; + } + }; +*/ + + let getRecognizers = function(tuple:any):RecognitionRule[] { + let matchedRecognizers:any[] = []; + // we can get the set of recognizers that match on this property at top clause + // and those that don't, too. + // PropertyRecognizers table of propName-> ( tableOfRecognizersPerValue, otherRecognizers) + // if tuple has a prop + // prop indexed + // get recognizers per value, or none + // prop not indexed + // use all recognizer list + // need iteration on propertyNames for tuple + // + log.debug("getRecognizers"+JSON.stringify(tuple)); + for (let propertyName in tuple){ + let recognizerIndex:RecognizerIndex|undefined = indexedRecognizers.get(propertyName); + log.debug("recognizerIndex="+recognizerIndex); + if (recognizerIndex){ + let ruleArray:RecognitionRule[]|undefined = recognizerIndex.valueMap.get(tuple[propertyName]); + log.debug("ruleArray="+ruleArray); + if (ruleArray){ + for (let rule of ruleArray){ + if (rule.predicate.match(tuple)){ + matchedRecognizers.push(rule); + } + } + } + return matchedRecognizers; // since we had an index, good enough + } + } + recognizers.forEach( (recognizer:RecognitionRule) => { + if (recognizer.predicate.match(tuple)){ + matchedRecognizers.push(recognizer); + } + }); + return matchedRecognizers; + }; + + let addRecognizerFromObject = function(predicateObject:ZLUX.RecognitionObjectPropClause | ZLUX.RecognitionObjectOpClause, actionID:string):void{ + addRecognizer(addRecognizerFromObjectInner(predicateObject), actionID); + }; + + let addRecognizer = function(predicate:RecognitionClause, actionID:string):void{ + let recognitionRule:RecognitionRule = new RecognitionRule(predicate,actionID); + recognizers.push(recognitionRule); + if (predicate.operation == RecognitionOp.AND){ + for (let subClause of predicate.subClauses){ + if ((subClause as RecognitionClause).operation == RecognitionOp.PROPERTY_EQ){ + let propertyClause:RecognitionClause = subClause as RecognitionClause; + let propertyName:string = propertyClause.subClauses[0] as string; + let propertyValue:string|number = propertyClause.subClauses[1] as string|number; + let recognizerIndex = indexedRecognizers.get(propertyName); + log.debug("addRecognizer recognizersForIndex="+recognizerIndex); + // here - fix me + // test server/client + // filter crap - are the screen ID's broken?? - should be no screen ID in tuple on first page + // why not getting 5 things? + if (recognizerIndex){ + let ruleArray:RecognitionRule[]|undefined = recognizerIndex.valueMap.get(propertyValue); + if (!ruleArray){ + ruleArray = []; + recognizerIndex.valueMap.set(propertyValue,ruleArray); + } + ruleArray.push(recognitionRule); + } + } + } + } + }; + + let registerPluginWatcher = function(plugin:ZLUX.Plugin, watcher: ZLUX.PluginWatcher) { + let key = plugin.getKey(); + let watchers = pluginWatchers.get(key); if (!watchers) { watchers = new Array(); - this.pluginWatchers.set(key,watchers); + pluginWatchers.set(key,watchers); } watchers.push(watcher); - } + }; - deregisterPluginWatcher(plugin:ZLUX.Plugin, watcher: ZLUX.PluginWatcher): boolean { + let deregisterPluginWatcher = function(plugin:ZLUX.Plugin, watcher: ZLUX.PluginWatcher): boolean { let key = plugin.getKey(); - let watchers = this.pluginWatchers.get(key); + let watchers = pluginWatchers.get(key); if (!watchers) { return false; } @@ -302,214 +326,213 @@ export class Dispatcher implements ZLUX.Dispatcher { } return false; } - } - - -/* what will callback be called with */ - registerAction(action: Action):void { - this.actionsByID.set(action.id,action); - } - - - getAction(recognizer:any):Action|undefined { - this.log.debug("actionName "+JSON.stringify(recognizer)+" in "+JSON.stringify(this.actionsByID)); - return this.actionsByID.get(recognizer.actionID); - } - - static isAtomicType(specType:string):boolean{ - return ((specType === "boolean") || - (specType === "number") || - (specType === "string") || - (specType === "symbol") || - (specType === "function")); - } - - evaluateTemplateOp(operation:any, - eventContext:any, - localContext:any):any{ - let opName:string = operation.op as string; - let dispatcher:Dispatcher = this; - if (opName == "deref"){ - let derefSource:any = null; - if (operation.source == "event"){ - derefSource = eventContext; - } else if (operation.source == "deref"){ - derefSource = localContext; - } else { - throw "unknown deref source: "+operation.source; - } - if (!Array.isArray(operation.path)){ - throw "no path spec for deref: "+JSON.stringify(operation); - } - var path = operation.path; - path.forEach((pathElement:any) => { - if ((typeof pathElement) === "object"){ - if ((typeof pathElement.op) === "string"){ - pathElement = this.evaluateTemplateOp(pathElement,eventContext,derefSource); - } else { - this.log.debug("path element replacement before: "+pathElement); - pathElement = dispatcher.buildObjectFromTemplate(pathElement,eventContext); - this.log.debug("path element replacement after: "+pathElement); - } - } - let pathElementType:string = (typeof pathElement); - if ((pathElementType === "string") || - (pathElementType === "number")){ - derefSource = derefSource[pathElement]; - if ((typeof derefSource) === "undefined"){ - throw "dereference to unbound element from "+pathElement; - } - } else { - throw "cannot dereference by "+JSON.stringify(pathElement); - } - }); - return derefSource; - } else if (opName == "concat"){ - if (!Array.isArray(operation.parts)){ - throw "concat op must have array of parts "+JSON.stringify(operation); - } - let concatenatedString:string = ""; - operation.parts.forEach( (part:any) => { - if ((typeof part) === "object"){ - if ((typeof part.op) === "string"){ - part = dispatcher.evaluateTemplateOp(part,eventContext,{}); - } else { - part = dispatcher.buildObjectFromTemplate(part,eventContext); - } - } else if (Dispatcher.isAtomicType((typeof part))){ - // do nothing - } else { - part = JSON.stringify(part); - } - concatenatedString += part; - }); - return concatenatedString; - } else if (opName == "localeDate"){ - return (new Date()).toLocaleTimeString(); - } else { - throw "unknown substitution op: "+opName; - } - } + }; + - buildObjectFromTemplate(template:any, eventContext:any):any{ - let outputObject:any = Array.isArray(template) ? [] : {}; - let dispatcher:Dispatcher = this; - for (let propName in template){ - if (template.hasOwnProperty(propName)){ - let substitutionSpec:any = template[propName]; - let specType:string = (typeof substitutionSpec); - if (substitutionSpec === null){ - outputObject[propName] = null; - } else if (Dispatcher.isAtomicType(specType)){ - outputObject[propName] = substitutionSpec; - } else if (specType === "object"){ - if ((typeof substitutionSpec.op) === "string"){ - outputObject[propName] = dispatcher.evaluateTemplateOp(substitutionSpec, eventContext, {}); - } else { - outputObject[propName] = dispatcher.buildObjectFromTemplate(substitutionSpec, eventContext); - } + /* what will callback be called with */ + let registerAction = function(action: Action):void { + actionsByID.set(action.id,action); + }; + + + let getAction = function(recognizer:any):Action|undefined { + log.debug("actionName "+JSON.stringify(recognizer)+" in "+JSON.stringify(actionsByID)); + return actionsByID.get(recognizer.actionID); + }; + + let evaluateTemplateOp = function(operation:any, + eventContext:any, + localContext:any):any{ + let opName:string = operation.op as string; + if (opName == "deref"){ + let derefSource:any = null; + if (operation.source == "event"){ + derefSource = eventContext; + } else if (operation.source == "deref"){ + derefSource = localContext; + } else { + throw "unknown deref source: "+operation.source; + } + if (!Array.isArray(operation.path)){ + throw "no path spec for deref: "+JSON.stringify(operation); + } + var path = operation.path; + path.forEach((pathElement:any) => { + if ((typeof pathElement) === "object"){ + if ((typeof pathElement.op) === "string"){ + pathElement = evaluateTemplateOp(pathElement,eventContext,derefSource); } else { - throw "no known substitution for type "+specType+": "+substitutionSpec; + log.debug("path element replacement before: "+pathElement); + pathElement = buildObjectFromTemplate(pathElement,eventContext); + log.debug("path element replacement after: "+pathElement); } } + let pathElementType:string = (typeof pathElement); + if ((pathElementType === "string") || + (pathElementType === "number")){ + derefSource = derefSource[pathElement]; + if ((typeof derefSource) === "undefined"){ + throw "dereference to unbound element from "+pathElement; + } + } else { + throw "cannot dereference by "+JSON.stringify(pathElement); + } + }); + return derefSource; + } else if (opName == "concat"){ + if (!Array.isArray(operation.parts)){ + throw "concat op must have array of parts "+JSON.stringify(operation); } - return outputObject; - } - - makeAction(id: string, defaultName: string, targetMode: ActionTargetMode, type: ActionType, targetPluginID: string, primaryArgument: any):Action{ - return new Action(id,defaultName,targetMode,type,targetPluginID,primaryArgument); - } - - private getAppInstanceWrapper(plugin:ZLUX.Plugin, id:MVDHosting.InstanceId) :ApplicationInstanceWrapper|null{ - let wrappers:ApplicationInstanceWrapper[]|undefined = this.instancesForTypes.get(plugin.getKey()); - this.log.debug("found some wrappers "+wrappers); - if (wrappers){ - for (let wrapper of (wrappers as ApplicationInstanceWrapper[])){ - if (wrapper.applicationInstanceId === id){ - return wrapper; + let concatenatedString:string = ""; + operation.parts.forEach( (part:any) => { + if ((typeof part) === "object"){ + if ((typeof part.op) === "string"){ + part = evaluateTemplateOp(part,eventContext,{}); + } else { + part = buildObjectFromTemplate(part,eventContext); + } + } else if (isAtomicType((typeof part))){ + // do nothing + } else { + part = JSON.stringify(part); + } + concatenatedString += part; + }); + return concatenatedString; + } else if (opName == "localeDate"){ + return (new Date()).toLocaleTimeString(); + } else { + throw "unknown substitution op: "+opName; + } + }; + + let buildObjectFromTemplate = function(template:any, eventContext:any):any{ + let outputObject:any = Array.isArray(template) ? [] : {}; + for (let propName in template){ + if (template.hasOwnProperty(propName)){ + let substitutionSpec:any = template[propName]; + let specType:string = (typeof substitutionSpec); + if (substitutionSpec === null){ + outputObject[propName] = null; + } else if (isAtomicType(specType)){ + outputObject[propName] = substitutionSpec; + } else if (specType === "object"){ + if ((typeof substitutionSpec.op) === "string"){ + outputObject[propName] = evaluateTemplateOp(substitutionSpec, eventContext, {}); + } else { + outputObject[propName] = buildObjectFromTemplate(substitutionSpec, eventContext); + } + } else { + throw "no known substitution for type "+specType+": "+substitutionSpec; } } } - return null; - } + return outputObject; + }; - createAsync(plugin:ZLUX.Plugin, action:Action, eventContext: any):Promise{ + let makeAction = function(id: string, defaultName: string, targetMode: ActionTargetMode, type: ActionType, targetPluginID: string, primaryArgument: any):Action{ + return new Action(id,defaultName,targetMode,type,targetPluginID,primaryArgument); + }; + + + let createAsync = function(plugin:ZLUX.Plugin, action:Action, eventContext: any):Promise{ //let appPromise:Promise - if (!this.launchCallback){ + if (!launchCallback){ return Promise.reject("no launch callback established"); } - let launchMetadata = this.buildObjectFromTemplate(action.primaryArgument, eventContext); + let launchMetadata = buildObjectFromTemplate(action.primaryArgument, eventContext); let appPromise = - this.launchCallback(plugin, launchMetadata).then( (newAppID:MVDHosting.InstanceId) => { - let wrapper = this.getAppInstanceWrapper(plugin,newAppID); + launchCallback(plugin, launchMetadata).then( (newAppID:MVDHosting.InstanceId) => { + let wrapper = getAppInstanceWrapper(plugin,newAppID); if (wrapper){ return wrapper; } else { return Promise.reject("could not find wrapper after launch/create for "+plugin.getIdentifier()); } }).catch((error:any) => { - this.log.warn("Caught error from launchcallback, e="+error); + log.warn("Caught error from launchcallback, e="+error); }); return appPromise; - } + }; - getActionTarget(action:Action, eventContext: any):Promise{ + let getActionTarget= function(action:Action, eventContext: any):Promise{ let plugin:ZLUX.Plugin|undefined = ZoweZLUX.pluginManager.getPlugin(action.targetPluginID); let applicationInstanceId:MVDHosting.InstanceId|undefined = eventContext.applicationInstanceId; if (plugin){ - this.log.debug(" ectxt="+eventContext); + log.debug(" ectxt="+eventContext); switch (action.targetMode){ - case ActionTargetMode.PluginCreate: - return this.createAsync(plugin,action, eventContext); - case ActionTargetMode.PluginFindAnyOrCreate: - let wrappers:ApplicationInstanceWrapper[]|undefined = this.instancesForTypes.get(plugin.getKey()); - if (wrappers && wrappers.length > 0) { - return Promise.resolve(wrappers[0]); - } else { - return this.createAsync(plugin,action,eventContext); - } - case ActionTargetMode.PluginFindUniqueOrCreate: - let existingWrapper = null; - if (applicationInstanceId) { - existingWrapper = this.getAppInstanceWrapper(plugin,applicationInstanceId); - } - if (existingWrapper){ - return Promise.resolve(existingWrapper); - } else { - return this.createAsync(plugin, action, eventContext); - } - case ActionTargetMode.System: - return Promise.reject("not yet implemented"); - default: - return Promise.reject("unknown target mode"); + case ActionTargetMode.PluginCreate: + return createAsync(plugin,action, eventContext); + case ActionTargetMode.PluginFindAnyOrCreate: + let wrappers:ApplicationInstanceWrapper[]|undefined = instancesForTypes.get(plugin.getKey()); + if (wrappers && wrappers.length > 0) { + return Promise.resolve(wrappers[0]); + } else { + return createAsync(plugin,action,eventContext); + } + case ActionTargetMode.PluginFindUniqueOrCreate: + let existingWrapper = null; + if (applicationInstanceId) { + existingWrapper = getAppInstanceWrapper(plugin,applicationInstanceId); + } + if (existingWrapper){ + return Promise.resolve(existingWrapper); + } else { + return createAsync(plugin, action, eventContext); + } + case ActionTargetMode.System: + return Promise.reject("not yet implemented"); + default: + return Promise.reject("unknown target mode"); } } else { return Promise.reject("no plugin"); } - } + }; - invokeAction(action:Action, eventContext: any):any{ - this.log.info("dispatcher.invokeAction on context "+JSON.stringify(eventContext)); - this.getActionTarget(action,eventContext).then( (wrapper:ApplicationInstanceWrapper) => { + let invokeAction = function(action:Action, eventContext: any):any{ + log.info("invokeAction on context "+JSON.stringify(eventContext)); + getActionTarget(action,eventContext).then( (wrapper:ApplicationInstanceWrapper) => { switch (action.type) { case ActionType.Launch: - this.log.debug("invoke Launch, which means do nothing if wrapper found: "+wrapper); + log.debug("invoke Launch, which means do nothing if wrapper found: "+wrapper); break; case ActionType.Message: - this.log.debug('Invoking message type Action'); + log.debug('Invoking message type Action'); if (wrapper.callbacks && wrapper.callbacks.onMessage) { wrapper.callbacks.onMessage(eventContext); } break; case ActionType.Minimize: case ActionType.Maximize: - this.log.warn('Max/Min not supported at this time. Concern if apps should be able to control other apps visibility.'); + log.warn('Max/Min not supported at this time. Concern if apps should be able to control other apps visibility.'); default: - this.log.warn("Unhandled action type = "+action.type); + log.warn("Unhandled action type = "+action.type); }; }); } + //constructor + runHeartbeat(); + + + return { + constants: constants, + makeAction: makeAction, + getAction: getAction, + registerAction: registerAction, + deregisterPluginWatcher: deregisterPluginWatcher, + registerPluginWatcher: registerPluginWatcher, + addRecognizer: addRecognizer, + addRecognizerFromObject: addRecognizerFromObject, + getRecognizers: getRecognizers, + setPostMessageHandler: setPostMessageHandler, + setLaunchHandler: setLaunchHandler, + registerPluginInstance: registerPluginInstance, + deregisterPluginInstance: deregisterPluginInstance, + registerApplicationCallbacks: registerApplicationCallbacks, + invokeAction:invokeAction + }; } export class RecognitionRule {