diff --git a/README.md b/README.md index 93fdc12..3afa60d 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ Based on the theme you choose the EPL code will be highlighted and easier to rea ## Settings -There are various settings available for the extension now. All the Apama configuration entries are prefixed 'SoftwareAG.Apama', and searching for 'Apama' will show all of them. +There are various settings available for the extension now. All the Apama configuration entries are prefixed 'Apama', and searching for 'Apama' will show all of them. * ApamaHome contains the path to the installation directory of the version you wish to use. * DebugHost is the default host for a correlator started for debug (allowing remote instance). @@ -42,8 +42,6 @@ There are various settings available for the extension now. All the Apama config * Langserver.Port is the port the Langserver is running on. * Langserver.MaxErrors is the maximum number of diagnostics that should be returned by the LSP (INACTIVE) -There are also some placeholders for using EPL with [Cumulocity IoT](https://www.softwareag.cloud/site/product/cumulocity-iot.html). these will become active in a later release (>v1.0). - ![settings](images/settings.png) ## Diagnostics @@ -80,7 +78,7 @@ The animation below shows how to create a non-default tasks (allowing multiple c ## Create Project -The apama_project tool can be used to create projects which are compatible with the eclipse-based 'Software Ag Designer' IDE, and will also allow you to edit Designer created projects in vscode. +The apama_project tool can be used to create projects which are compatible with the eclipse-based IDE, and will also allow you to edit Designer created projects in vscode. ![project support](images/4-project-create.gif) @@ -125,6 +123,7 @@ To use the diagnostics capability you must have version 10.5.3 or later of Apama ## v2.0.0 * Stops the extension startup from stealing application focus. +* Changes all extension preferences: the "softwareag" prefixed has been removed. No migration path is provided. ## v1.2.1 diff --git a/package.json b/package.json index 4643c9d..f14bce4 100644 --- a/package.json +++ b/package.json @@ -24,22 +24,22 @@ "configuration": { "title": "Apama", "properties": { - "softwareag.apama.apamahome": { + "apama.apamahome": { "type": "string", - "default": "c:\\softwareag\\apama", + "default": "c:\\apama", "description": "Home directory for the Apama installation." }, - "softwareag.apama.debugport": { + "apama.debugport": { "type": "integer", "default": "15904", "description": "Default port for correlator debugging." }, - "softwareag.apama.debughost": { + "apama.debughost": { "type": "string", "default": "127.0.0.1", "description": "Default host for correlator debugging." }, - "softwareag.apama.langserver.type": { + "apama.langserver.type": { "type": "string", "enum": [ "local", @@ -49,37 +49,37 @@ "default": "local", "description": "Whether vscode should start the language server locally." }, - "softwareag.apama.langserver.port": { + "apama.langserver.port": { "type": "integer", "default": "30030", "description": "The Apama language server port." }, - "softwareag.apama.langserver.host": { + "apama.langserver.host": { "type": "string", "default": "127.0.0.1", "description": "Default host the Apama langserver will listen for connections on." }, - "softwareag.apama.langserver.maxErrors": { + "apama.langserver.maxErrors": { "type": "integer", "default": "100", "description": "The maximum number of diagnostics that the Apama language server will return." }, - "softwareag.c8y.url": { + "apama.c8y.url": { "type": "string", "default": "https://demos.cumulocity.com/", "description": "Url of the cumulocity instance." }, - "softwareag.c8y.tenant": { + "apama.c8y.tenant": { "type": "string", "default": "demos", "description": "Tenant Id: click on user at the top right of the cumulocity application." }, - "softwareag.c8y.user": { + "apama.c8y.user": { "type": "string", "default": "user", "description": "User name you log in as." }, - "softwareag.c8y.password": { + "apama.c8y.password": { "type": "string", "default": "pw", "description": "password for cumulocity." diff --git a/src/apama_debug/apamadebugconfig.ts b/src/apama_debug/apamadebugconfig.ts index da3a1b9..91fc0ce 100644 --- a/src/apama_debug/apamadebugconfig.ts +++ b/src/apama_debug/apamadebugconfig.ts @@ -18,7 +18,7 @@ export class ApamaDebugConfigurationProvider implements DebugConfigurationProvid * Return an initial debug configuration */ provideDebugConfigurations(folder: WorkspaceFolder | undefined, token?: CancellationToken): ProviderResult { - const config = workspace.getConfiguration("softwareag.apama"); + const config = workspace.getConfiguration("apama"); return [ { type: "apama", name: "Debug Apama Application", @@ -59,7 +59,7 @@ export class ApamaDebugConfigurationProvider implements DebugConfigurationProvid config.injectionList = getInjectionList(this.apamaEnv, folder.uri.fsPath); config.correlator = {}; config.correlator.host = "127.0.0.1"; - config.correlator.port = workspace.getConfiguration("softwareag.apama").get("debugport"); + config.correlator.port = workspace.getConfiguration("apama").get("debugport"); config.correlator.args = ["-g"]; } diff --git a/src/apama_util/apamaenvironment.ts b/src/apama_util/apamaenvironment.ts index 4c48bca..74b30b4 100644 --- a/src/apama_util/apamaenvironment.ts +++ b/src/apama_util/apamaenvironment.ts @@ -4,7 +4,7 @@ import { join } from 'path'; -const confignode = 'softwareag.apama'; +const confignode = 'apama'; const default_linux_correlator = 'correlator'; const default_windows_correlator = 'correlator.exe'; const default_linux_deploy = 'engine_deploy'; diff --git a/src/apama_util/commands.ts b/src/apama_util/commands.ts index 129139e..3e117c6 100644 --- a/src/apama_util/commands.ts +++ b/src/apama_util/commands.ts @@ -24,7 +24,7 @@ export class ApamaCommandProvider { registerCommands(): void { if (this.context !== undefined) { - const port: any = workspace.getConfiguration("softwareag.apama").get("debugport"); + const port: any = workspace.getConfiguration("apama").get("debugport"); this.context.subscriptions.push.apply(this.context.subscriptions, [ // diff --git a/src/c8y/cumulocityView.ts b/src/c8y/cumulocityView.ts index 9471eec..b5095e2 100644 --- a/src/c8y/cumulocityView.ts +++ b/src/c8y/cumulocityView.ts @@ -68,7 +68,7 @@ export class CumulocityView implements vscode.TreeDataProvider { // inventory using sdk // vscode.commands.registerCommand('extension.c8y.login', async () => { - const config: vscode.WorkspaceConfiguration = vscode.workspace.getConfiguration('softwareag.c8y'); + const config: vscode.WorkspaceConfiguration = vscode.workspace.getConfiguration('apama.c8y'); if( config ) { const tenant:string = config.get('tenant',""); @@ -107,7 +107,7 @@ export class CumulocityView implements vscode.TreeDataProvider { appname = appname.slice(0, -4); } - const config: vscode.WorkspaceConfiguration = vscode.workspace.getConfiguration('softwareag.c8y'); + const config: vscode.WorkspaceConfiguration = vscode.workspace.getConfiguration('apama.c8y'); let url: string = config.get('url',""); // C8Y host if (!url.endsWith("/")) { url += "/"; @@ -172,7 +172,7 @@ export class CumulocityView implements vscode.TreeDataProvider { async refresh(): Promise { this.filelist = []; try { - const config: vscode.WorkspaceConfiguration = vscode.workspace.getConfiguration('softwareag.c8y'); + const config: vscode.WorkspaceConfiguration = vscode.workspace.getConfiguration('apama.c8y'); const url: string = config.get('url',"") + "service/cep/eplfiles?contents=true"; const options: AxiosRequestConfig = { auth: { diff --git a/src/extension.ts b/src/extension.ts index 25d16f9..8ba1b16 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -75,7 +75,7 @@ export async function activate(context: ExtensionContext): Promise { logger.appendLine(`Version: ${corrVersion} doesn't support the Apama Language Server - Skipping`); } else { - const config = workspace.getConfiguration("softwareag.apama.langserver"); + const config = workspace.getConfiguration("apama.langserver"); createLangServerTCP(apamaEnv, config, logger); } }) diff --git a/test-files/ImportPython.mon b/test-files/ImportPython.mon deleted file mode 100644 index b84226b..0000000 --- a/test-files/ImportPython.mon +++ /dev/null @@ -1,30 +0,0 @@ - -package apama.test; - -event myevent {} - -monitor ImportPython { - - import "myPlugin" as pyplugin; - - integer a := 20; - integer ret; - - action onload() { - ret := pyplugin.echo(a); - log ret.toString(); - - //keep the monitor alive so it can be deleted. - on all myevent() {} - - } - - /** - * Description of actionName - * @param paramName Description of this param - * @returns Description of the return value - */ - action actionName(string param) returns string { - throw com.apama.exceptions.Exception("Not yet implemented", "NotImplemented"); - } -} diff --git a/test-files/anothertest.mon b/test-files/anothertest.mon deleted file mode 100644 index 87435cf..0000000 --- a/test-files/anothertest.mon +++ /dev/null @@ -1,233 +0,0 @@ -event NestedEvent -{ - any a; -} - -event MyEvent -{ - integer i; - float f; - boolean b; - string s; - dictionary d; - sequence q; - NestedEvent n; -} - - -//Event to trigger batch of processing -// -// shouldLog is obvious -// bareException determines whether the exception thrown -// is one with or without a value - -event DoSetup { - integer numRecvContexts; - integer numSendContexts; - integer numOfIterations; -} - -event SetupDone { -} - -event ContextDone { -} - -event DoBatch { - integer numOfIterationsRemaining; -} - -//I've seen things you people wouldn't believe -event TearsInTheRain{ -} - - - - - -monitor m -{ - import "myPlugin" as plugin; - - sequence recCtxs := []; - sequence sendCtxs := []; - integer evtReceived := 0; - integer eventsPerIter := 10000; - integer numSendContexts := 0; - integer numRecvContexts := 0; - integer iterations := 0; - integer finishedContexts := 0; - - MyEvent me; - any a := me; - dictionary d := new dictionary; - - //onload await external prompting. - //use the batch channel - action onload(){ - monitor.subscribe("batch"); - - me := MyEvent(42, 3.14, true, "hello", {"key":"value"}, [1,2,3,4], NestedEvent(678)); - - sequence fields := me.getFieldNames(); - string s; - for s in fields { - d[s] := a.getField(s); - } - - on all DoSetup() as details { - doSetup( details ); - } - - on all SetupDone() { - setupDone(); - } - - on all ContextDone() { - contextDone(); - } - - on all TearsInTheRain() { - timeToDie(); - } - } - - action contextDone(){ - finishedContexts := finishedContexts +1; - if( finishedContexts = numRecvContexts ){ - enqueue TearsInTheRain() to context.current(); - } - - } - - //Termination action - action timeToDie(){ - log "Test Finished" at INFO; - } - - //Handle a batch, process a subset of the iterations required - //and then if not finished send a DoBatch event for the remainder - action doSetup( DoSetup details ){ - - integer i := 0; - recCtxs := []; //clear it - sendCtxs := []; //clear it - numRecvContexts := details.numRecvContexts; - numSendContexts := details.numSendContexts; - iterations := details.numOfIterations; - - //Setup the recieve contexts - while(i < numRecvContexts) { - context c := context("Recv"+i.toString()); - recCtxs.append(c); - log "created receiveEvents to context " + c.toString() at INFO; - i := i + 1; - } - - //Set up the send contexts - i := 0; - while(i < numSendContexts) { - context c := context("Send"+i.toString()); - sendCtxs.append(c); - log "created sendEvents to context " + c.toString()at INFO; - i := i + 1; - } - - send SetupDone() to "batch"; - - } - - //We have setup the contexts to rec/send on - action setupDone(){ - integer i := 0; - context c; - //Setup the recieve handlers - for c in recCtxs { - log "spawned receiveEvents to context " + c.toString() at INFO; - spawn receiveEvents(context.current()) to c; - i := i + 1; - } - - //Setup the recieve handlers - for c in sendCtxs { - log "spawned sendEvents to context " + c.toString() at INFO; - spawn sendEvents() to c; - send DoBatch(iterations) to c; - i := i + 1; - } - - //This will trigger sending in the test run.py - log "Setup Finished" at INFO; - } - - - //Do the work of receiving - action receiveEvents(context main) - { - monitor.subscribe("channame"); - - - on all MyEvent() as re { - //log "Received Event" + re.toString() at INFO; - //when received all expected events - evtReceived := evtReceived + 1; - if evtReceived % eventsPerIter = 0 { - log (iterations-evtReceived).toString()+" events remaining on context " + context.current().getName() at INFO; - } - if (evtReceived >= iterations) - { - log "Context COMPLETE " + context.current().toString() + " received " + evtReceived.toString() + " events" at INFO; - enqueue ContextDone() to main; - die; - } - } - } - - - action sendEvents() - { - - on all DoBatch() as details { - doBatch( details ); - } - } - - //Handle a batch, process a subset of the iterations required - //and then if not finished send a DoBatch event for the remainder - action doBatch( DoBatch details ){ - log "doBatch " + details.toString() at INFO; - - //Do a batch - integer i := eventsPerIter; - boolean last := false; - - //test for less than a batch and trigger final processing - //if we are on the remaining < 1k iterations - if( details.numOfIterationsRemaining < eventsPerIter ){ - log "less than 1k iterations" at INFO; - i := details.numOfIterationsRemaining; - last := true; - } - //next batch -1k or remainder - integer nextIterations := details.numOfIterationsRemaining - i; - - while(i> 0) { - plugin.sendEventChannelDict("channame", "MyEvent", d); - i := i-1; - } - - //If we have finished issue the trigger for the test - if( last = true ){ - string message; - message := "Batch Finished on " + context.current().toString() ; - log message at INFO; - //done - return; - } - - //Send the next batch - DoBatch nextBatch := DoBatch(nextIterations); - send nextBatch to context.current(); - } - -} diff --git a/test-files/event-test.mon b/test-files/event-test.mon deleted file mode 100644 index befc3b6..0000000 --- a/test-files/event-test.mon +++ /dev/null @@ -1,76 +0,0 @@ -//basic event 1 -event test1{} - -event test2 {} -event test3 { -} - -event test4 { - //test comment -} - -event test5 -{} - -event test6 -{ - -} - -event test7 -//extra comment -{ - -} - -//now test with included members -event member1{ - integer a; - string b; - boolean c; - float d; -} - -event member2 {integer a;string b; boolean c;float d;} -event member3 { - integer a; - string b; - boolean c; - float d; -} - -event member4 { - //test comment - any _a = f; - integer i := 1; - integer i2:= 1; - integer _test := 3; - float f := 1.0; - boolean b := true; - string s := "the rain in spain"; - dictionary d := new dictionary; - any _a = new dictionary; - sequence q := [1,_b,test_identifier]; -} - -event member5 -{integer a;string b; boolean c;float d;} - -event member6 -{ - integer a; - string b; - boolean c; - float d; - test1 x; -} - -event member7 -//extra comment -{ - integer a; - string b; - boolean c; - float d; -} - diff --git a/test-files/iro_test.mon b/test-files/iro_test.mon deleted file mode 100644 index 8f32f49..0000000 --- a/test-files/iro_test.mon +++ /dev/null @@ -1,279 +0,0 @@ -/* test integer */ - -/* -test -*/ - -// test -// -any _a ; - -integer i; -integer i2 ; -integer _test; -float f; -boolean b; -string s; -dictionary d; -sequence q; - - -any _a := f; -integer i := 1; -integer i2:= 1; -integer _test := 3; -float f := 1.0; -boolean b := true; -string s := "the rain in spain"; -dictionary d := new dictionary; -any _a = new dictionary; -sequence q := [1,_b,test_identifier]; - - - -event NestedEvent -{ - any a; -} - -event MyEvent -{ - integer i; - float f; - boolean b; - string s; - dictionary d; - sequence q; - NestedEvent n; -} - - -//Event to trigger batch of processing -// -// shouldLog is obvious -// bareException determines whether the exception thrown -// is one with or without a value - -event DoSetup { - integer numRecvContexts; - integer numSendContexts; - integer numOfIterations; - - action init(integer a) { - return something; - } -} - -event SetupDone { -} - -event ContextDone { -} - -event DoBatch { - integer numOfIterationsRemaining; -} - -//I've seen things you people wouldn't believe -event TearsInTheRain{ -} - - - - - -monitor m -{ - import "myPlugin" as plugin; - - sequence recCtxs := []; - sequence sendCtxs := []; - integer evtReceived := 0; - integer eventsPerIter := 10000; - integer numSendContexts := 0; - integer numRecvContexts := 0; - integer iterations := 0; - integer finishedContexts := 0; - - MyEvent me; - any a := me; - dictionary d := new dictionary; - - //onload await external prompting. - //use the batch channel - action onload(){ - monitor.subscribe("batch"); - - me := MyEvent(42, 3.14, true, "hello", {"key":"value"}, [1,2,3,4], NestedEvent(678)); - - sequence fields := me.getFieldNames(); - string s; - for s in fields { - d[s] := a.getField(s); - } - - on all DoSetup() as details { - doSetup( details ); - } - - on StockTick(*,*) processTick(); - - on StockTick(*,*):newTick processTick(); - - on StockTick(*,*) as newTick { - processTick(newTick); - } - - listener l := on StockTick(*,*) as newTick processTick(); - - on SetupDone() { - setupDone(); - } - - on all ContextDone() { - contextDone(); - } - - on all TearsInTheRain() { - timeToDie(); - } - } - action contextDone(){ - finishedContexts := finishedContexts +1; - if( finishedContexts = numRecvContexts ){ - enqueue TearsInTheRain() to context.current(); - } - - } - - //Termination action - action timeToDie(){ - log "Test Finished" at INFO; - } - - //Handle a batch, process a subset of the iterations required - //and then if not finished send a DoBatch event for the remainder - action doSetup( DoSetup details ){ - - integer i := 0; - recCtxs := []; //clear it - sendCtxs := []; //clear it - numRecvContexts := details.numRecvContexts; - numSendContexts := details.numSendContexts; - iterations := details.numOfIterations; - - //Setup the recieve contexts - while(i < numRecvContexts) { - context c := context("Recv"+i.toString()); - recCtxs.append(c); - log "created receiveEvents to context " + c.toString() at INFO; - i := i + 1; - } - - //Set up the send contexts - i := 0; - while(i < numSendContexts) { - context c := context("Send"+i.toString()); - sendCtxs.append(c); - log "created sendEvents to context " + c.toString()at INFO; - i := i + 1; - } - - send SetupDone() to "batch"; - - } - - //We have setup the contexts to rec/send on - action setupDone(){ - integer i := 0; - context c; - //Setup the recieve handlers - for c in recCtxs { - log "spawned receiveEvents to context " + c.toString() at INFO; - spawn receiveEvents(context.current()) to c; - i := i + 1; - } - - //Setup the recieve handlers - for c in sendCtxs { - log "spawned sendEvents to context " + c.toString() at INFO; - spawn sendEvents() to c; - send DoBatch(iterations) to c; - i := i + 1; - } - - //This will trigger sending in the test run.py - log "Setup Finished" at INFO; - } - - - //Do the work of receiving - action receiveEvents(context main) - { - monitor.subscribe("channame"); - - - on all MyEvent() as re { - //log "Received Event" + re.toString() at INFO; - //when received all expected events - evtReceived := evtReceived + 1; - if evtReceived % eventsPerIter = 0 { - log (iterations-evtReceived).toString()+" events remaining on context " + context.current().getName() at INFO; - } - if (evtReceived >= iterations) - { - log "Context COMPLETE " + context.current().toString() + " received " + evtReceived.toString() + " events" at INFO; - enqueue ContextDone() to main; - die; - } - } - } - - - action sendEvents() - { - - on all DoBatch() as details { - doBatch( details ); - } - } - - //Handle a batch, process a subset of the iterations required - //and then if not finished send a DoBatch event for the remainder - action doBatch( DoBatch details ){ - log "doBatch " + details.toString() at INFO; - - //Do a batch - integer i := eventsPerIter; - boolean last := false; - - //test for less than a batch and trigger final processing - //if we are on the remaining < 1k iterations - if( details.numOfIterationsRemaining < eventsPerIter ){ - log "less than 1k iterations" at INFO; - i := details.numOfIterationsRemaining; - last := true; - } - //next batch -1k or remainder - integer nextIterations := details.numOfIterationsRemaining - i; - - while(i> 0) { - plugin.sendEventChannelDict("channame", "MyEvent", d); - i := i-1; - } - - //If we have finished issue the trigger for the test - if( last = true ){ - string message; - message := "Batch Finished on " + context.current().toString() ; - log message at INFO; - //done - return; - } - - //Send the next batch - DoBatch nextBatch := DoBatch(nextIterations); - send nextBatch to context.current(); - } - -} diff --git a/test-files/statements-test.mon b/test-files/statements-test.mon deleted file mode 100644 index 6bb0c6f..0000000 --- a/test-files/statements-test.mon +++ /dev/null @@ -1,27 +0,0 @@ - - -monitor x{ - a < b; - a > b; - a = b; - a := b; - fields := me.getFieldNames(); - plugin.sendEventChannelDict("channame", "MyEvent", d); - log "less than 1k iterations" at INFO; - - a.b.c.test() - - //Send the next batch - DoBatch nextBatch := DoBatch(nextIterations); - send nextBatch to context.current(); - - - /** - * Description of actionName - * @param paramName Description of this param - * @returns Description of the return value - */ - action actionName(string param) returns string { - throw com.apama.exceptions.Exception("Not yet implemented", "NotImplemented"); - } -} diff --git a/test-files/streams-having.mon b/test-files/streams-having.mon deleted file mode 100644 index d351b98..0000000 --- a/test-files/streams-having.mon +++ /dev/null @@ -1,73 +0,0 @@ -/** - * Demonstrate the use of 'having' in streams - * - * This example achieves the same as the 'streams' sample -- it even - * accepts the same input and produces the same output -- but it uses - * a 'having' clause instead of creating a separate stream for each - * symbol. - * - * $Copyright (c) 2012 Progress Software Corporation. All Rights Reserved.$ - * $Copyright (c) 2013-2016 Software AG, Darmstadt, Germany and/or Software AG USA Inc., Reston, VA, USA, and/or its subsidiaries and/or its affiliates and/or their licensors.$ - * Use, reproduction, transfer, publication or disclosure is prohibited except as specifically provided for in your License Agreement with Software AG - */ - -/** - * Bring the mean aggregate into our namespace - */ -using com.apama.aggregates.mean; -using com.apama.aggregates.first; -using com.apama.aggregates.last; - -/** - * The event type (global) that we will use - */ -event Tick -{ - string symbol; - float price; -} - -/** - * The monitor itself - */ -monitor Streams -{ - // Threshold price change to look for - constant float THRESHOLD := 1.0; - - action onload() { - // Take the original stream of ticks and produce a derived - // stream of ticks that denotes, for each symbol, the mean of - // the most recent ten prices. - stream means := - from t in all Tick() - partition by t.symbol - retain 10 - group by t.symbol - select Tick(t.symbol, mean(t.price)); - - // Then take this stream of means and retain two values per - // symbol. - // - // Use a 'having' clause to find occasions when the current - // mean differs from the previous one by more than the - // threshold. In those cases (but not otherwise) output an - // 'alert' tick giving the symbol and the difference in - // average price. - stream alerts := - from t in means - partition by t.symbol - retain 2 - group by t.symbol - having last(t.price) > first(t.price)+THRESHOLD - or last(t.price) < first(t.price)-THRESHOLD - select Tick(t.symbol, last(t.price)-first(t.price)); - - // Note that if performance was valued over clarity, the - // having clause above could be re-written as: - // having (last(t.price)-first(t.price)).abs() > THRESHOLD - - // Send the alert ticks - from alerts as t send t to "output"; - } -} diff --git a/test-files/streams.mon b/test-files/streams.mon deleted file mode 100644 index 486ef0f..0000000 --- a/test-files/streams.mon +++ /dev/null @@ -1,100 +0,0 @@ -/** - * A simple example of Streaming extensions to monitorscript - * - * This application receives a stream of Tick events and calculates the - * average price over the last 10 events. If this average changes more than a - * threshold then it sends an event containing the price difference - * - * $Copyright (c) 2010,2012 Progress Software Corporation. All Rights Reserved.$ - * $Copyright (c) 2013-2016 Software AG, Darmstadt, Germany and/or Software AG USA Inc., Reston, VA, USA, and/or its subsidiaries and/or its affiliates and/or their licensors.$ - * Use, reproduction, transfer, publication or disclosure is prohibited except as specifically provided for in your License Agreement with Software AG - */ - -/** - * Bring the mean aggregate into our namespace - */ -using com.apama.aggregates.mean; - -/** - * The event type (global) that we will use - */ -event Tick -{ - string symbol; - decimal price; -} - -/** - * The monitor itself - */ -monitor Streams -{ - // Threshold price change to look for - constant decimal THRESHOLD := 1.0d; - - action onload() - { - // Setup listeners for two different stocks. - // They are independent, so can be in different - // instances of the monitor. - spawn watchForStock("ibm"); - spawn watchForStock("msft"); - } - - action watchForStock(string symbol) - { - // Create a stream from incoming events, filtered on symbol. This will - // output a Tick to any stream connected to it whenever a Tick with that - // symbol is received by the correlator. - stream ticks := all Tick(symbol=symbol); - - sequence test = new sequence(); - - // Create a stream of decimals representing the average of the last 10 - // ticks in the ticks stream. - // - // This takes the output from the previous stream, using the symbol 't' - // to represent each event from that stream. The retain clause creates a - // sliding window of size 10 and the aggregate mean operator takes one of - // the fields of the event and calculates the aggregate over the contents - // of the window. - // - // The result of the aggregate is a decimal so the whole expression returns - // a stream of decimals. There will be an item in the stream every time the - // contents of the window changes. - stream averages := from t in ticks retain 10 select mean(t.price); - - // Create a stream delaying averages by one event. - // - // Similarly, this is using the output of the averages stream and using - // the symbol 'a' to represent the values in the input stream. The window - // is size 1 and the rstream operator outputs items _leaving_ the window, - // hence the output is the input delayed by one item. - stream previous := from a in averages retain 1 select rstream a; - - // Join together the averages and previous streams performing an action - // when the difference is outside the threshold. - // - // Averages is used in both the previous expression and this one, - // creating a split in the flow of items, which is recombined in this - // query. This means that items will always arrive on both sides of the - // join simultaneously and there is no need to specify windows, although - // both sides of the join could be windowed. - // - // The join is a full cross-join of all the events on one side of the - // join with all the events on the other, which is then filtered by the - // where clause. Where clauses and select clauses can have any - // monitorscript expressions in them. - // - // Rather than putting the result of the join into a stream as above, we - // are coassigning the results to a block of monitorscript code in the - // same way that listeners work in traditional monitorscript. The block - // of procedural code will be called once for each item that is output - // from the join and where clauses. - - from a in averages from p in previous where a > p+THRESHOLD or a < p-THRESHOLD select a-p as alertPrice - { - send Tick(symbol, alertPrice) to "output"; - } - } -} diff --git a/test-files/timed.mon b/test-files/timed.mon deleted file mode 100644 index 1a2db96..0000000 --- a/test-files/timed.mon +++ /dev/null @@ -1,99 +0,0 @@ -/** - * Timed windows in MonitorScript - * - * This sample tracks the total value of shares traded for a particular symbol - * in a given period of time and sends alerts if that exceeds a given - * threshold. After the first alert for a given stock the threshold is - * increased before another alert is given. - * - * $Copyright (c) 2010 Progress Software Corporation. All Rights Reserved.$ - * $Copyright (c) 2013-2016 Software AG, Darmstadt, Germany and/or Software AG USA Inc., Reston, VA, USA, and/or its subsidiaries and/or its affiliates and/or their licensors.$ - * Use, reproduction, transfer, publication or disclosure is prohibited except as specifically provided for in your License Agreement with Software AG - */ - -/** - * Bring the sum aggregate into our namespace - */ -using com.apama.aggregates.sum; - -/** - * The event type of input events - */ -event Order -{ - string symbol; - float price; - integer volume; -} - -/** - * the event type of output events - */ -event Alert -{ - string symbol; - float traded; -} - -/** - * The monitor itself - */ -monitor Streams -{ - - // The number of seconds to window over - constant float WINDOWSIZE := 6.0; - - // Initial threshold total traded to alert on (modified for subsequent - // alerts) - float threshold := 10000.0; - - action onload() - { - // Setup listeners for two different stocks. These are spawned to two - // monitor instances so that the threshold variable can be updated - // independently for each symbol. - spawn watchForStock("ibm"); - spawn watchForStock("msft"); - } - - action watchForStock(string symbol) - { - // Create a stream from incoming events, filtered on symbol. This will - // output an Order to any stream connected to it whenever an Order with - // that symbol is received by the correlator. - stream orders := all Order(symbol=symbol); - - // Sliding window containing the total value of all the trades in the - // last six seconds. - // - // This takes the output from the previous stream, using the symbol 't' - // to represent each event from that stream. The within clause creates a - // sliding window containing any event received in the last WINDOWSIZE - // seconds (in this case 6). The sum aggregate is used to calculate the - // sum of the value of all the trades within the window. The arguments to - // the aggregate can be any function of the input events. - // - // This stream outputs a value any time the contents of the window - // change, that is, any time an item arrives in the window and WINDOWSIZE - // seconds after an item arrived in the window (when it leaves the - // window). - stream tradeTotals := from t in orders within WINDOWSIZE select sum(t.volume.toFloat()*t.price); - - // Send an alert when the total volume traded in the stock exceeds the - // threshold in the window period. - // - // The result of this filter is coassigned to a block of monitorscript - // which is executed once for each value exceeding the threshold. - // - // All the expressions in the streaming extensions are evaluated - // dynamically, so the monitorscript output block updates the threshold - // variable and the new value is used in subsequent comparisons. - - from a in tradeTotals where a > threshold select a as alertPrice - { - threshold := alertPrice + 10000.0; - send Alert(symbol, alertPrice) to "output"; - } - } -} diff --git a/test-files/variable-test.mon b/test-files/variable-test.mon deleted file mode 100644 index 05cf7da..0000000 --- a/test-files/variable-test.mon +++ /dev/null @@ -1,30 +0,0 @@ -/* test */ - -/* -test -*/ - -// test -// -any _a ; - -integer i; -integer i2 ; -integer _test; -float f; -boolean b; -string s; -dictionary d; -sequence q; - - -any _a := f; -integer i := 1; -integer i2:= 1; -integer _test := 3; -float f := 1.0; -boolean b := true; -string s := "the rain in spain"; -dictionary d := new dictionary; -any _a = new dictionary; -sequence q := [1,_b,test_identifier]; diff --git a/test-files/weather.mon b/test-files/weather.mon deleted file mode 100644 index 7ab70ad..0000000 --- a/test-files/weather.mon +++ /dev/null @@ -1,157 +0,0 @@ -package com.apamademo.weather; - -/* - * Apama DataView sample. Demonstrates the usage of the Apama DataView API - * for creating and maintaing data tables that can be show in an Apama - * Dashboard Studio dashboard. - * - * $Copyright (c) 2008-2009 Progress Software Corporation. All Rights Reserved.$ - * $Copyright (c) 2013,2015-2016 Software AG, Darmstadt, Germany and/or Software AG USA Inc., Reston, VA, USA, and/or its subsidiaries and/or its affiliates and/or their licensors.$ - * Use, reproduction, transfer, publication or disclosure is prohibited except as specifically provided for in your License Agreement with Software AG - */ - - -event AddLocation { - string location; - sequence ids; -} - -event DeleteLocation { - string location; - dictionary deletedIds; -} - -monitor Weather { - sequence locations := ["London","New York","Tokyo","Sydney"]; - string location; - - action onload() { - // Create the weather view - com.apama.dataview.DataViewAddDefinition add := new com.apama.dataview.DataViewAddDefinition; - add.dvName := "Weather"; - add.dvDisplayName := "Weather"; - add.fieldNames := ["location","temperature","humidity","visibility"]; - add.fieldTypes := ["string","integer","integer","integer"]; - add.keyFields := ["location"]; - route add; - - // clear any existing data items (we may be reloading this monitor, but the view existed previously - com.apama.dataview.DataViewDeleteAllItems deleteAll := new com.apama.dataview.DataViewDeleteAllItems; - deleteAll.dvName := "Weather"; - route deleteAll; - - - // Add the set of initial locations - string s; - for s in locations { - location := s; - spawn locationHandler(); - } - - // Add exception handlers - just log errors in this sample - on all com.apama.dataview.DataViewException() as dvException { - log "*** Weather monitor error: "+dvException.toString() at ERROR; - } - - on all com.apama.dataview.DataViewItemException() as dvItemException { - log "*** Weather monitor error: "+dvItemException.toString() at ERROR; - } - - // Listen for AddLocation events from dashboard and add if not in locations - on all AddLocation() as addLocation { - if locations.indexOf(addLocation.location) = -1 { - location := addLocation.location; - locations.append(location); - spawn locationHandler(); - } - } - - // Listen for DeleteLocation events from dashboard and remove if not in locations - on all DeleteLocation() as deleteLocation { - integer index := locations.indexOf(deleteLocation.location); - if index != -1 { - locations.remove(index); - } - } - } - - // - // Spawn point for new locations. Adds the location to the DataView and begins - // generating random updates for it. - // - action locationHandler() { - integer temp; - integer humidity; - integer visibility; - - // Set initial weather values for location - integer random; - random := 30; - temp := 50 + random.rand(); - random := 30; - humidity := 40 + random.rand(); - random := 10; - visibility := 1 + random.rand(); - - // Add the location to the "Weather" DataView - com.apama.dataview.DataViewAddItem item := new com.apama.dataview.DataViewAddItem; - item.dvName := "Weather"; - item.owner := "*"; - item.timeStamp := -1.0; - item.fieldValues := [location,temp.toString(),humidity.toString(),visibility.toString()]; - route item; - - // Log that the location was added - on com.apama.dataview.DataViewItem (dvName="Weather") as added { - log("Weather monitor - DataViewItem added: "+added.dvItemId.toString()); - } - - // Listen for DeleteLocation events for this location - on DeleteLocation(location = location) { - com.apama.dataview.DataViewDeleteItem delete := new com.apama.dataview.DataViewDeleteItem; - delete.dvName := "Weather"; - delete.dvItemId := -1; // Set the ID to -1 when using keyFields. Without this you would see DataViewItemExceptions - delete.keyFields := [location]; - route delete; - die; - } - - // Log that the location was deleted - on com.apama.dataview.DataViewItemDeleted (dvName="Weather") as deleted { - log("Weather monitor - DataViewItemDeleted: "+deleted.dvItemId.toString()); - } - - // Randomly fluctuate weather values for location every 5 seconds - on all wait (5.0) { - random := 5; - - temp := (temp - 2) + random.rand(); - humidity := (humidity - 2) + random.rand(); - visibility := (visibility - 2) + random.rand(); - - if (temp < 0) {temp := 0;} - if (humidity < 0) {humidity := 0;} - if (visibility < 0) {visibility := 0;} - - if (temp > 99) {temp := 99;} - if (humidity > 99) {humidity := 99;} - if (visibility > 99) {visibility := 99;} - -// Using Deltas -// com.apama.dataview.DataViewUpdateItemDelta update := new com.apama.dataview.DataViewUpdateItemDelta; -// update.dvName := "Weather"; -// update.dvItemId := -1; // Set the ID to -1 when using keyFields. Without this you would see DataViewItemExceptions -// update.timeStamp := -1.0; // so current time will be used for update events -// update.fieldValues := {0:location,1:temp.toString(),2:humidity.toString(),3:visibility.toString()}; -// route update; - -// OR, using full updates - com.apama.dataview.DataViewUpdateItem update := new com.apama.dataview.DataViewUpdateItem; - update.dvName := "Weather"; - update.dvItemId := -1; // Set the ID to -1 when using keyFields - update.timeStamp := -1.0; // so current time will be used for update events - update.fieldValues := [location,temp.toString(),humidity.toString(),visibility.toString()]; - route update; - } - } -} \ No newline at end of file