Difference between revisions of "AMI Script"
m (Remove instance of) |
|||
(73 intermediate revisions by 6 users not shown) | |||
Line 56: | Line 56: | ||
* '''Injection Protection''' - Properly escaping control characters, quotes, etc. | * '''Injection Protection''' - Properly escaping control characters, quotes, etc. | ||
* '''Conditional Templating''' - Ability to do conditional & loop based template construction | * '''Conditional Templating''' - Ability to do conditional & loop based template construction | ||
+ | |||
+ | = AMI Script - A java syntax with embedded SQL and String Templates = | ||
+ | |||
+ | ==Syntax== | ||
+ | Same support as java for loops, if/else statements, white space, comments and expressions: | ||
+ | <syntaxhighlight lang="amiscript" line="1"> | ||
+ | double n=0; | ||
+ | for(int i=0;i<10;i++){ | ||
+ | if(i < 5) | ||
+ | n++; //increment a number | ||
+ | } | ||
+ | /* sample expression, same as java*/ | ||
+ | int b=4 > 5 ? 1 * 2 : 5 / 2; | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | ==Data Structures== | ||
+ | General purpose List, Map, Set & Table data structures are provided. The constructors can be used to prepopulate data: | ||
+ | <syntaxhighlight lang="amiscript" line="1"> | ||
+ | List mylist=new List(1,2,3,4); | ||
+ | Map mymap=new Map(“fname”,”Eric”,”lname”,”Johnson”); | ||
+ | Set set=new Set("a", "b", "c"); | ||
+ | Table t =new Table("People", "user String, age int"); | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | ==Type Safety & Coercion== | ||
+ | Type names are case insensitive, ex double and DOUBLE are the same. For compatibility, int and integer mean the same thing as well as char and character. | ||
+ | <syntaxhighlight lang="amiscript" line="1"> | ||
+ | int n=5; | ||
+ | Int m=n*n; | ||
+ | INTEGER o=m*m; | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | All types support null value. Dereferencing null, results in null. Expressions with null result in null | ||
+ | <syntaxhighlight lang="amiscript" line="1"> | ||
+ | List l=null; | ||
+ | Integer s=l.size(); //s is null, does not raise null pointer | ||
+ | Double n=5,m=null; | ||
+ | Double p=n*m;//p is null because anything times null is null | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | Flexible type coercion. When coercion is not possible the value is coerced to null. | ||
+ | <syntaxhighlight lang="amiscript" line="1"> | ||
+ | Int value="123"; //value will be 123 | ||
+ | Double value2=new List(); //list can’t be cast to double so value2 will be null | ||
+ | String value3=new List(1,2,3); //value3 is the string [1, 2, 3] | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | All types extend Object and casting is not necessary for assignment. | ||
+ | <syntaxhighlight lang="amiscript" line="1"> | ||
+ | Object o=new List(1,2,3); | ||
+ | List l=o; //this works because the value of o is a List. | ||
+ | Map m=0; //m will be null because a List can not be cast to a map | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | All types can be thrown / caught and all blocks can have catch clauses (try key word is not necessary) | ||
+ | <syntaxhighlight lang="amiscript" line="1"> | ||
+ | { | ||
+ | throw "what!"; | ||
+ | }catch(String s){ | ||
+ | } | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | ==String Templates== | ||
+ | If strings contain a ${...} the content of the curly brackets is interpreted | ||
+ | <syntaxhighlight lang="amiscript" line="1"> | ||
+ | String name="rob"; | ||
+ | String message1="hello ${name}"; // hello rob | ||
+ | String message2="A baker’s dozen is {12+1}"; // A baker’s dozen is 13 | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | ===String Template Example=== | ||
+ | In this example, we will use string templates to access and evaluate variables from amiscript and pass them to a div field. | ||
+ | <syntaxhighlight lang="amiscript" line="1"> | ||
+ | string topHeaderName = "Top Header"; | ||
+ | string subHeaderName = "Sub Header"; | ||
+ | |||
+ | string scripts = "<h1>${topHeaderName}</h1> <h3>${subHeaderName}</h3>"; | ||
+ | div.setValue(scripts); | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | [[File:StringTemplate html.png]] | ||
+ | |||
+ | Alternatively, you could also use string template inside the div field:<br> | ||
+ | <syntaxhighlight lang="amiscript" line="1"> | ||
+ | <h1>${__USERNAME}</h1> <h3>${__USERNAME+"123"}</h3> | ||
+ | </syntaxhighlight> | ||
+ | [[File:StrTemplate2.png]] | ||
+ | |||
+ | You can use triple quotes for literals: | ||
+ | <syntaxhighlight lang="amiscript"> | ||
+ | String m="""hello ${world}"""; // hello ${world} | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | ==SQL== | ||
+ | There are several reserved words that indicate an sql statement, including CREATE, SELECT, INSERT, DELETE, etc. | ||
+ | <syntaxhighlight lang="amiscript" line="1"> | ||
+ | CREATE TABLE T(username String, id int); | ||
+ | INSERT INTO t values ("rob",111),("dave",222"); //table t has 2 rows | ||
+ | CREATE TABLE t2 as select * from t where id<200; //table t2 has 1 row | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | Variables and templates can be used inside sql: | ||
+ | <syntaxhighlight lang="amiscript" line="1"> | ||
+ | String name="eric"; | ||
+ | Int id=333; | ||
+ | INSERT INTO T VALUES(name,id); //inserts eric,333 | ||
+ | String row="values (\"mike\",444)"; | ||
+ | INSERT INTO T ${row};//expands to INSERT INTO T values("mike",444); | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | Table coercion works for Table cells to objects, Columns to Lists and Rows to maps. | ||
+ | <syntaxhighlight lang="amiscript" line="1"> | ||
+ | String s=select username from t where id==111; //s=rob | ||
+ | List names=select username from t; //names= [rob, dave] | ||
+ | Map user=select * from t where id=222; //user={username=dave, id=222} | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | To query external data sources run the USE ds= … EXECUTE command. | ||
+ | <syntaxhighlight lang="amiscript" line="1"> | ||
+ | CREATE TABLE t3 as USE ds="mydatabase" EXECUTE SELECT * FROM ORDERS; | ||
+ | //RAN SELECT * FROM ORDERS on the mydatabase datasource and created a local table called t3 | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | To upload data to external data sources run the USE ds= … INSERT command. | ||
+ | <syntaxhighlight lang="amiscript" line="1"> | ||
+ | USE ds="targetdb" INSERT INTO TargetAccounts FROM useds="sourcedb" SELECT * from SourceAccounts;//query all data fromsourcedb’s SourceAccounts table and insert into targetdb’s TargetAccounts table | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | ==Custom Methods== | ||
+ | Methods are static and must return a type. If a return is clause is not reached, the function returns null. | ||
+ | <syntaxhighlight lang="amiscript" line="1"> | ||
+ | String combine(String s,String t){ | ||
+ | |||
+ | if(s!=null && t!=null) | ||
+ | |||
+ | return s+" "+t; | ||
+ | |||
+ | }; | ||
+ | |||
+ | String s=combine("apple","orange");//s is now apple orange | ||
+ | String t=combine("apple",null);//t is null | ||
+ | </syntaxhighlight> | ||
= AMI Script = | = AMI Script = | ||
Line 229: | Line 371: | ||
(evaluates to boolean) | (evaluates to boolean) | ||
{| class="wikitable" | {| class="wikitable" | ||
− | | || <span style="font-family: courier new; color: red;">!</span> || <span style="font-family: courier new; color: blue;">bool_expr</span> || | + | | || <span style="font-family: courier new; color: red;">!</span> || <span style="font-family: courier new; color: blue;">bool_expr</span> || ''boolean (logical) NOT'' |
|- | |- | ||
− | | <span style="font-family: courier new; color: blue;">expr</span> || <span style="font-family: courier new; color: red;"><</span> || <span style="font-family: courier new; color: blue;">expr</span>|| | + | | <span style="font-family: courier new; color: blue;">expr</span> || <span style="font-family: courier new; color: red;"><</span> || <span style="font-family: courier new; color: blue;">expr</span>|| ''less than (strings are case sensitive)'' |
|- | |- | ||
− | | <span style="font-family: courier new; color: blue;">expr</span> || <span style="font-family: courier new; color: red;">></span> || <span style="font-family: courier new; color: blue;">expr</span>|| | + | | <span style="font-family: courier new; color: blue;">expr</span> || <span style="font-family: courier new; color: red;">></span> || <span style="font-family: courier new; color: blue;">expr</span>|| ''greater than (strings are case sensitive)'' |
|- | |- | ||
− | | <span style="font-family: courier new; color: blue;">expr</span> || <span style="font-family: courier new; color: red;"><=</span> || <span style="font-family: courier new; color: blue;">expr</span>|| | + | | <span style="font-family: courier new; color: blue;">expr</span> || <span style="font-family: courier new; color: red;"><=</span> || <span style="font-family: courier new; color: blue;">expr</span>|| ''less than or equal to (strings are case sensitive)'' |
|- | |- | ||
− | | <span style="font-family: courier new; color: blue;">expr</span> || <span style="font-family: courier new; color: red;">>=</span> || <span style="font-family: courier new; color: blue;">expr</span>|| | + | | <span style="font-family: courier new; color: blue;">expr</span> || <span style="font-family: courier new; color: red;">>=</span> || <span style="font-family: courier new; color: blue;">expr</span>|| ''greater than or equal to (strings are case sensitive)'' |
|- | |- | ||
− | | <span style="font-family: courier new; color: blue;">expr</span> || <span style="font-family: courier new; color: red;">==</span> || <span style="font-family: courier new; color: blue;">expr</span>|| | + | | <span style="font-family: courier new; color: blue;">expr</span> || <span style="font-family: courier new; color: red;">==</span> || <span style="font-family: courier new; color: blue;">expr</span>|| ''equal to (strings are case sensitive)'' |
|- | |- | ||
− | | <span style="font-family: courier new; color: blue;">expr</span> || <span style="font-family: courier new; color: red;">!=</span> || <span style="font-family: courier new; color: blue;">expr</span>|| | + | | <span style="font-family: courier new; color: blue;">expr</span> || <span style="font-family: courier new; color: red;">!=</span> || <span style="font-family: courier new; color: blue;">expr</span>|| ''is not equal to (strings are case sensitive)'' |
|- | |- | ||
− | | <span style="font-family: courier new; color: blue;">expr</span> || <span style="font-family: courier new; color: red;">=~</span> || <span style="font-family: courier new; color: blue;">regex</span> || | + | | <span style="font-family: courier new; color: blue;">expr</span> || <span style="font-family: courier new; color: red;">=~</span> || <span style="font-family: courier new; color: blue;">regex</span> || ''matches regular expression (see Java Pattern for details)'' |
|- | |- | ||
− | | <span style="font-family: courier new; color: blue;">expr</span> || <span style="font-family: courier new; color: red;">!~</span> || <span style="font-family: courier new; color: blue;">regex</span> || | + | | <span style="font-family: courier new; color: blue;">expr</span> || <span style="font-family: courier new; color: red;">!~</span> || <span style="font-family: courier new; color: blue;">regex</span> || ''does not match regular expression (see Java Pattern for details)'' |
|- | |- | ||
− | | <span style="font-family: courier new; color: blue;">expr</span> || <span style="font-family: courier new; color: red;">~~</span> || <span style="font-family: courier new; color: blue;">simple_pattern</span> || | + | | <span style="font-family: courier new; color: blue;">expr</span> || <span style="font-family: courier new; color: red;">~~</span> || <span style="font-family: courier new; color: blue;">simple_pattern</span> || ''simplified text matching. See Simplified Text Matching section.'' |
|- | |- | ||
− | | <span style="font-family: courier new; color: blue;">expr</span> || <span style="font-family: courier new; color: red;"> | + | | <span style="font-family: courier new; color: blue;">expr</span> || <span style="font-family: courier new; color: red;">&&</span> || <span style="font-family: courier new; color: blue;">expr</span> || ''logical and. Short circuits if left expr returns false. Short circuits if right expr is const and false'' |
|- | |- | ||
− | | <span style="font-family: courier new; color: blue;">expr</span> || | + | | <span style="font-family: courier new; color: blue;">expr</span> || |
+ | [[File:AMIScript.StandardOperators.jpg|none]] | ||
+ | || <span style="font-family: courier new; color: blue;">expr</span> || ''logical or. Short circuits if left expr returns true. Short circuits if right expr is const and true'' | ||
+ | |} | ||
+ | |||
+ | == string_expressions == | ||
+ | (evaluates to boolean) | ||
+ | {| class="wikitable" | ||
|- | |- | ||
− | | <span style="font-family: courier new; color: blue;">expr</span> || | + | | <span style="font-family: courier new; color: blue;">string_expr+ expr</span> || ''String concatenation. Null values equate to empty string ("")'' |
|} | |} | ||
+ | |||
+ | == special_expressions == | ||
+ | {| class="wikitable" | ||
+ | |- | ||
+ | | <span style="font-family: courier new; ">(expression)</span> || <span style="font-family: courier new; ">Force Order of operations</span> | ||
+ | |- | ||
+ | | <span style="font-family: courier new; ">array_of_type[num_expr]</span> || <span style="font-family: courier new; ">Array index referencing</span> | ||
+ | |- | ||
+ | | <span style="font-family: courier new; ">(type)statement</span> || <span style="font-family: courier new; ">Explicit cast to type. Note that a failed cast returns null. Also, casting is automatic, so it's not necessary</span> | ||
+ | |- | ||
+ | | <span style="font-family: courier new; ">bool_expr ? tr_expr : fl_expr</span> || <span style="font-family: courier new; ">If bool_expr returns true, then evaluates to tr_expr, otherwise evaluates to fl_expr.</span> | ||
+ | |} | ||
+ | |||
+ | '''Examples'''<syntaxhighlight lang="amiscript"> | ||
+ | Long n = (10 + 5) * 2; //n is 30 | ||
+ | n += 5; //n is 35 | ||
+ | n = n/2; //n is 17 | ||
+ | Boolean b = n>10; //b is true (n is still 17) | ||
+ | b =! b; //b is false | ||
+ | b = (b || true) && true;//b is true | ||
+ | String test = "hello" + "world"; //test is helloworld | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | = Assignment & Declaration = | ||
+ | |||
+ | == special (evaluates to type) == | ||
+ | {| class="wikitable" | ||
+ | |- | ||
+ | | <span style="font-family: courier new; ">new type(param''[, param ...]'')</span> || <span style="font-family: courier new; ">Object Creation</span> | ||
+ | |- | ||
+ | | <span style="font-family: courier new; ">type var_name</span> || <span style="font-family: courier new; ">Variable declaration (Value is defaulted to null)</span> | ||
+ | |- | ||
+ | | <span style="font-family: courier new; ">type var_name = expression</span> || <span style="font-family: courier new; ">Variable declaration and assignment</span> | ||
+ | |- | ||
+ | | <span style="font-family: courier new; ">Variable declaration and assignment</span> || <span style="font-family: courier new; ">Variable declaration and assignment</span> | ||
+ | |} | ||
+ | |||
+ | ==assignment (evaluates to num_var type)== | ||
+ | |||
+ | {| class="wikitable" | ||
+ | |- | ||
+ | | <span style="font-family: courier new; color: blue;">num_var</span> || <span style="font-family: courier new; color: red;">++</span> || || <span style="font-family: courier new; ">combined post-increment assignment</span> | ||
+ | |- | ||
+ | | || <span style="font-family: courier new; color: red;">++</span> || <span style="font-family: courier new; color: blue;">num_var</span> || <span style="font-family: courier new; ">combined pre-increment assignment</span> | ||
+ | |- | ||
+ | | <span style="font-family: courier new; color: blue;">num_var</span> || <span style="font-family: courier new; color: red;">--</span> || || <span style="font-family: courier new; ">combined post-decrement assignment</span> | ||
+ | |- | ||
+ | | || <span style="font-family: courier new; color: red;">--</span> || <span style="font-family: courier new; color: blue;">num_var</span> || <span style="font-family: courier new; ">combined pre-decrement assignment</span> | ||
+ | |- | ||
+ | | <span style="font-family: courier new; color: blue;">num_var</span> || <span style="font-family: courier new; color: red;">*=</span> || <span style="font-family: courier new; color: blue;">num_expr</span> || <span style="font-family: courier new; ">combined multiplication assignment</span> | ||
+ | |- | ||
+ | | <span style="font-family: courier new; color: blue;">num_var</span> || <span style="font-family: courier new; color: red;">/=</span> || <span style="font-family: courier new; color: blue;">num_expr</span> || <span style="font-family: courier new; ">combined division assignment</span> | ||
+ | |- | ||
+ | | <span style="font-family: courier new; color: blue;">num_var</span> || <span style="font-family: courier new; color: red;">%=</span> || <span style="font-family: courier new; color: blue;">num_expr</span> || <span style="font-family: courier new; ">combined modulus assignment (remainder)</span> | ||
+ | |- | ||
+ | | <span style="font-family: courier new; color: blue;">num_var</span> || <span style="font-family: courier new; color: red;">+=</span> || <span style="font-family: courier new; color: blue;">num_expr</span> || <span style="font-family: courier new; ">combined addition assignment</span> | ||
+ | |- | ||
+ | | <span style="font-family: courier new; color: blue;">num_var</span> || <span style="font-family: courier new; color: red;">-=</span> || <span style="font-family: courier new; color: blue;">num_expr</span> || <span style="font-family: courier new; ">combined subtraction assignment</span> | ||
+ | |} | ||
+ | |||
+ | = Flow Control = | ||
+ | Complex AMI scripts can be achieved by combining multiple statements into statement blocks. A statement block is wrapped in curly brackets {...} and each statement is separated with a semi-colon;. Then, the execution of statement blocks can be determined using a variety of flow control statements including if, if/else, for, while, and for-each-loops. Note that for and while loops can use the continue and break directives as well. | ||
+ | ''Examples'' | ||
+ | <syntaxhighlight lang="amiscript"> | ||
+ | { | ||
+ | Integer count = 10; | ||
+ | Integer value = 1; | ||
+ | for(Integer i = 0; i < count; i++){ | ||
+ | value *= 2; | ||
+ | } | ||
+ | if(value < 2000) { | ||
+ | session.alert(value); //alert shows 1024 | ||
+ | } else | ||
+ | session.alert("High value"); // this is never hit. Also note: single statements don't need to be in {...} statement blocks | ||
+ | while(true){ | ||
+ | value -= 10; | ||
+ | if(value < 1000) | ||
+ | break; | ||
+ | } | ||
+ | //value is now 994 | ||
+ | } | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | == statement block == | ||
+ | <syntaxhighlight lang="amiscript"> | ||
+ | { statement [;statement ...] [;]} | ||
+ | </syntaxhighlight> | ||
+ | <span style="font-family: courier new; ">''** Evaluates to return value if a return_statment exists, otherwise it evaluates to the last statement's evaluation. If no statements, evaluates to Void''</span> | ||
+ | |||
+ | == for loop == | ||
+ | <syntaxhighlight lang="amiscript"> | ||
+ | for(initialization;termination_expression;increment) statement | ||
+ | </syntaxhighlight> | ||
+ | <span style="font-family: courier new; ">'''''initialization'''''</span>: <span style="font-family: courier new; ">''statement that is called first, used to declare variables with local scope''</span> | ||
+ | |||
+ | <span style="font-family: courier new; ">'''''termination_expression'''''</span>: <span style="font-family: courier new; ">''statement that must evaluate to boolean, false terminates''</span> | ||
+ | |||
+ | <span style="font-family: courier new; ">'''''increment'''''</span>: <span style="font-family: courier new; ">''statement called after each completion of the loop's statements''</span> | ||
+ | |||
+ | <span style="font-family: courier new; ">'''''statement'''''</span>: <span style="font-family: courier new; ">''called once per loop. Note'':</span> | ||
+ | |||
+ | * <span style="font-family: courier new; ">'''''continue_statement''''' will exit the statement and proceed to increment statement'''''</span> | ||
+ | |||
+ | * <span style="font-family: courier new; ">'''''break_statement''''' will exit the for loop entirely''</span> | ||
+ | |||
+ | <span style="font-family: courier new; ">''**Evaluates to Void''</span> | ||
+ | |||
+ | == for each loop == | ||
+ | <syntaxhighlight lang="amiscript"> | ||
+ | for(type_expr varname:iterable_or_array) statement | ||
+ | </syntaxhighlight> | ||
+ | <span style="font-family: courier new; ">'''''iterable_or_array''''' - values to iterate over in order'''''</span> | ||
+ | |||
+ | <span style="font-family: courier new; ">'''''statement'''''</span>: <span style="font-family: courier new; ">''called once per loop. Note'':</span> | ||
+ | |||
+ | * <span style="font-family: courier new; ">'''''continue_statement''''' will exit the statement and proceed to increment statement'''''</span> | ||
+ | |||
+ | * <span style="font-family: courier new; ">'''''break_statement''''' will exit the for loop entirely''</span> | ||
+ | |||
+ | <span style="font-family: courier new; ">''**Evaluates to Void''</span> | ||
+ | |||
+ | == while loop == | ||
+ | <syntaxhighlight lang="amiscript"> | ||
+ | while(bool_expression) statement | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | <span style="font-family: courier new; ">''same as for(;bool_expression;) statement''</span> | ||
+ | |||
+ | <span style="font-family: courier new; ">''**Evaluates to Void''</span> | ||
+ | |||
+ | == if statement == | ||
+ | <syntaxhighlight lang="amiscript"> | ||
+ | if(bool_expression) statement | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | <span style="font-family: courier new; ">''if bool_expression evaluates to true then execute statement''</span> | ||
+ | |||
+ | <span style="font-family: courier new; ">''**Evaluates to Void''</span> | ||
+ | |||
+ | == if else statement == | ||
+ | <syntaxhighlight lang="amiscript"> | ||
+ | if(bool_expression) statement else statement2 | ||
+ | </syntaxhighlight> | ||
+ | <span style="font-family: courier new; ">''if '''bool_expression''' evaluates to true then execute statement otherwise executestatement2''</span> | ||
+ | |||
+ | <span style="font-family: courier new; ">''**Evaluates to Void''</span> | ||
+ | |||
+ | == return statement == | ||
+ | <syntaxhighlight lang="amiscript"> | ||
+ | return statement | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | <span style="font-family: courier new; ">''** Evaluates to statement's value. Will cause call stack to be popped out to caller function.''</span> | ||
+ | |||
+ | == break statement == | ||
+ | <syntaxhighlight lang="amiscript"> | ||
+ | break | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | <span style="font-family: courier new; ">''** See for_loop, for_each_loop and while_loop''</span> | ||
+ | |||
+ | == continue statement == | ||
+ | <syntaxhighlight lang="amiscript"> | ||
+ | continue | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | <span style="font-family: courier new; ">''** See for_loop, for_each_loop and while_loop''</span> | ||
+ | |||
+ | == function call == | ||
+ | <syntaxhighlight lang="amiscript"> | ||
+ | function(param[, param ...]) | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | <span style="font-family: courier new; ">''**Evaluates to '''return_type''' value''</span> | ||
+ | |||
+ | == member method call == | ||
+ | <syntaxhighlight lang="amiscript"> | ||
+ | target_object.function(param[, param ...]) | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | <span style="font-family: courier new; ">''**Evaluates to '''return_type''' value''</span> | ||
+ | |||
+ | =Objects= | ||
+ | There is a predefined set of object types (classes). These are used to facilitate the interaction between AMI Script and various backend components, user inputs, dashboards, etc. Additionally, data structures are represented as objects and can be instantiated using the new operator. Objects can only be accessed via methods (not member variables). | ||
+ | |||
+ | ===The Session Object=== | ||
+ | |||
+ | <span style="font-family: courier new; color: blue;">session</span> - each user that is logged in has a session object (which is of type Session). This is the "starting point" for access to the user's information, along with various dashboard components. | ||
+ | |||
+ | === Attributes and Class Methods for a Session Object=== | ||
+ | 1. session values: A hash map that stores user defined variables in the format of '''Variable_name_key=variable_value'''. Initially it is an empty map.<br> | ||
+ | (1.1) session.setValue(string key, object value) && session.getValue(string key) && session.getValues() <br> | ||
+ | <syntaxhighlight lang="amiscript"> | ||
+ | int a = 3; | ||
+ | session.setValue("sessionVal_a",a); //setting a to the session value | ||
+ | session.getValue("sessionVal_a"); //getting the session value by the key | ||
+ | |||
+ | int b = 4; | ||
+ | session.setValue("sessionVal_b",b); //setting b to the session value | ||
+ | |||
+ | session.getValues(); //{sessionVal_a=3, sessionVal_b=4} | ||
+ | |||
+ | </syntaxhighlight> | ||
+ | |||
+ | 2. session variables: A list of variables that are predefined by dashboard and webserver. They cam be viewed from '''Dashboard -> Session Variables'''<br> | ||
+ | The dashboard editor can also define custom session variables by clicking '''Add variable'''. These are saved as part of the dashboard layout file<br> | ||
+ | [[File:SessionVar1.jpg]]<br> | ||
+ | [[File:SessionVar2.jpg]]<br> | ||
+ | [[File:SessionVar3.jpg]]<br> | ||
+ | Now this variable that we just defined is accessible everywhere in the current session.<br> | ||
+ | |||
+ | 3.session global properties: these are server properties defined in the '''default.properties, local.properties and all other properties files''' <br> | ||
+ | (3.1) session.getGlobalProperty(string propertyKey)<br> | ||
+ | <syntaxhighlight lang="amiscript"> | ||
+ | session.getGlobalProperty("ami.components"); | ||
+ | </syntaxhighlight> | ||
+ | [[File:SessionVar4.jpg]] <br> | ||
+ | |||
+ | 4. session Properties: another way to access session variables <br> | ||
+ | <syntaxhighlight lang="amiscript"> | ||
+ | //Suppose there is a session variable called "a", the two ways below for accessing "a" are equivalent | ||
+ | session.log(session.getProperty("a")); | ||
+ | session.log(a); | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | ===Common Data Structures=== | ||
+ | |||
+ | <span style="font-family: courier new; color: blue;">List</span>: A zero-indexed Array List implementation | ||
+ | |||
+ | <span style="font-family: courier new; color: blue;">Set</span>: A set of unique values | ||
+ | |||
+ | <span style="font-family: courier new; color: blue;">Map</span>: A Linked Hash Map implementation | ||
+ | |||
+ | <span style="font-family: courier new; color: blue;">Table</span>: A 2-dimensional table with the same characteristics as a SQL style table. Tables have a title. Columns are named and strongly typed. | ||
+ | |||
+ | <span style="font-family: courier new; color: blue;">Tableset</span>: A map of tables. Can be loosely thought of as a mini database. | ||
+ | |||
+ | '''Examnples''' | ||
+ | |||
+ | <syntaxhighlight lang="amiscript"> | ||
+ | session.alert("this is a test"); | ||
+ | session.log("something worth logging); | ||
+ | List l = new List("apple", "orange", "berry", "banana"); | ||
+ | l.splice(1, 2, "strawberry"); | ||
+ | String s = l; //s is now apple, strawberry, banana | ||
+ | Map m = new Map(1, "one", 2, "two", 3, "three"); //map contains three key/value pairs, ex: 2 = "two" | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | =Commenting= | ||
+ | |||
+ | Commenting is identical to the commenting syntax in Java & C++. There are two types of comments: single-line and multi-line. | ||
+ | |||
+ | ===comments (single-line)=== | ||
+ | //comments<linefeed> | ||
+ | |||
+ | ===comments (multi-line)=== | ||
+ | /*comments*/ | ||
+ | |||
+ | '''Examples''' | ||
+ | |||
+ | <syntaxhighlight lang="amiscript"> | ||
+ | /*multi-line | ||
+ | comment using the | ||
+ | slash stars*/ | ||
+ | //single-line comment | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | =AMI Script Constants= | ||
+ | AMI Script can reference constants just like other variables. Note the constant's values can not be changed using AMI Script. The standard naming convention for global variables is 2 under bars (__) followed by an all uppercase name. Constants can be defined in three ways: | ||
+ | |||
+ | * At the server level (via a config file loaded at startup, typically local.properties) | ||
+ | |||
+ | Typically the syntax is: <span style="font-family: courier new; ">amiscript.variable.varname=value</span> | ||
+ | |||
+ | (note that if value is a string, is must be surrounded in double quotes, see LITERALS for details) | ||
+ | |||
+ | For example, this could reside in your ''local.properties:'' | ||
+ | |||
+ | <span style="font-family: courier new; ">#My custom variables</span> | ||
+ | |||
+ | <span style="font-family: courier new; ">amiscript.variable.__COMPANY_NAME="Acme Technologies"</span> | ||
+ | |||
+ | <span style="font-family: courier new; ">amiscript.variable.__COPYRIGHT=2017</span> | ||
+ | |||
+ | * At the user level (using the authentication plugin, or the access.txt file) | ||
+ | |||
+ | Typically the syntax is: <span style="font-family: courier new; ">amiscript.variable.varname=value</span> | ||
+ | |||
+ | (note that if value is a string, is must be surrounded in double quotes, see LITERALS for details) | ||
+ | |||
+ | For example, this could reside in your ''access.txt'' file for user demo (with password demo123): | ||
+ | |||
+ | <span style="font-family: courier new; ">demo|demo123|amiscript.variable.__GROUP="infosec"|amiscript.variable.__SECURITY_LEVEL=12</span> | ||
+ | |||
+ | * There are also pre-determined variables defined by the AMI Web system: | ||
+ | ** <span style="font-family: courier new; ">__USERNAME</span>: (String) the username of the logged in user | ||
+ | ** <span style="font-family: courier new; "> __SESSIONID</span>: (String) a unique id for the web session | ||
+ | ** <span style="font-family: courier new; ">__TIMEZONE</span>: (String) the timezone of the user's session | ||
+ | ** <span style="font-family: courier new; ">__ADDRESS</span>: (String) the ip address of the user's browser | ||
+ | ** <span style="font-family: courier new; ">__LOADTIME</span>: (Long) the time in milliseconds that the user started the session | ||
+ | ** <span style="font-family: courier new; ">session</span>: (Session) the session object representing the user's session | ||
+ | |||
+ | Hint: Through the front end in editor mode you can view all declared constants via: ''Menu Bar -> Dashboard -> Variable Table'' | ||
+ | |||
+ | = SimplifiedText Matching = | ||
+ | |||
+ | '''Overview''' | ||
+ | |||
+ | The simplified text matching finds text entries using a simple pattern. When included in AMI script, it takes the form: <span style="font-family: courier new; color: blue;">'''var ~~ "my pattern"'''</span> | ||
+ | |||
+ | '''Rule 1, the general case''': the pattern supplied will match any text that contains the pattern, case insensitive. For example, assuming word is a variable let's consider the expression: <span style="font-family: courier new; color: blue;">word ~~ "AB"</span>. This will return true if word is cab or ABC or tabs but will return false if word is ''apple''. | ||
+ | |||
+ | '''Rule 2, special symbols''': If you need to look for symbols besides letters, numbers or white space, prefix with a back slash. For example, to look for the word ''P&L'', the expression is <span style="font-family: courier new; color: blue;">word ~~ "P\\&L"</span>. Remember, we are in a string so a double back slash evaluates to a single backslash. Note this includes the following list of symbols: <span style="font-family: courier new; color: blue;">*^$.[]()~|&!?:</span> | ||
+ | |||
+ | '''Rule 3, Additional syntax''': There are many special symbols that can be used for more advanced searches, for example the star (*) means anything, so <span style="font-family: courier new; color: blue;">"f*g"</span> will match any thing that has an f followed by g, such as ''3FORGE''. ''See the following sections for more advanced syntax''. | ||
+ | |||
+ | '''Syntax''' | ||
+ | The following syntaxes are used to do "basic" matching against expressions with some text. | ||
+ | |||
+ | 1. Simple Matching Expression | ||
+ | |||
+ | Matches any text that contains the supplied pattern regardless of case. The following characters are reserved and may be embedded in the expression: | ||
+ | |||
+ | * <span style="font-family: courier new; color: blue;">*</span> - '''Anything''': Can be expanded to include any text. | ||
+ | * <span style="font-family: courier new; color: blue;">^</span> - '''Starts With''': Symbolizes the "start" of the text. In other words, if an expression starts with ^, then the text must start with the following expression. Please note that carets (<span style="font-family: courier new; color: blue;">^</span>) not at the start of the expression will be treated as literals. (When used in conjunction with the tilde (<span style="font-family: courier new; color: blue;">~</span>), the hat should follow the tilde.) | ||
+ | * <span style="font-family: courier new; color: blue;">$</span> - '''Ends With''': Symbolizes the "end" of the text. In other words, if an expression ends with a dollar sign(<span style="font-family: courier new; color: blue;">$</span>) then the text must end with the preceding expression. Please note that dollar signs not at the end of the expression will be treated as literals. | ||
+ | * <span style="font-family: courier new; color: blue;">.</span> - '''Any single char.''': each dot will disregard one character and checks for the target character(s) in the remaining string, case INsensitive. | ||
+ | Examples: | ||
+ | # ".s" disregards the first character, checks for "s" OR "S" in the remaining string; | ||
+ | # "s." attempts to find "s" OR "S" in the string. If found, disregards the next character and returns a match. If not found, returns empty; | ||
+ | # "..s" disregards the first TWO characters, checks for "s" OR "S" in the remaining string. Return a match if "s" OR "S" is found, empty otherwise; | ||
+ | # "ss.." attempts to find "ss" OR either one of ("sS", "SS", "Ss") (must be consecutive "s") in the string. When found, disregards the next two characters and returns a match; | ||
+ | # "..s.S.." disregards the first TWO characters, attempts to find one "s" OR "S", if found, disregard the next character, then attempts to find another "s" OR "S" in the remaining string, if found, disregards the next two characters and returns a match. If "s" was not found in either one of the two scenarios, return empty. | ||
+ | # Note that the evluation order is always from left to right. Each character is checked at most once. | ||
+ | |||
+ | * <span style="font-family: courier new; color: blue;">[charlist]</span> '''Any of Chars.''': Match any one of the characters enclosed within the brackets. | ||
+ | * <span style="font-family: courier new; color: blue;">~</span>: '''Case Sensitive'''. Apply it before the first character. It indicates case sensitivity when matching the string. | ||
+ | * '''Escaped chars''': When referencing the following characters literally, they must be escaped with a back slash (\): <span style="font-family: courier new; color: blue;">*^$.[]()~|&!?:</span> | ||
+ | * '''Literals''': These are simply letter-for-letter matches to the expression | ||
+ | |||
+ | 2. ''<span style="font-family: courier new; color: blue;">'Exact Expression'</span>'' | ||
+ | |||
+ | Matches the exact expression supplied in quotes (other than an escaped quote using \' ). This would be similar to using an equals ( == ) | ||
+ | |||
+ | 3. '''/regex/'''''<options>/'' | ||
+ | |||
+ | This will use the java.util.regex package to match against regular expressions (see the java.util.regex.Pattern for details on building regular expressions). The <options> allow you to control behavior of how the regular expression operates. Simply supply the options you would like to apply in a continuous string between the 2nd and last forward slash (/). The following options are supported: | ||
+ | |||
+ | *'''q - Canonical Equivalence''': When this flag is specified, two characters will be considered to match if and only if their full canonical decompositions match. The expression "a\u030A", for example, will match the string "?" when this flag is specified. By default, matching does not take canonical equivalence into account. | ||
+ | *'''f - Full Line''': When this flag is specified, the text must fully match the regular expression. If this option is not specified, any portion of the text matching the expression will be considered a match. | ||
+ | *'''i - Case Insensitive''': By default, case-insensitive matching assumes that only characters in the US-ASCII charset are being matched. Unicode-aware case-insensitive matching can be enabled by specifying the '''u''' (Unicode case) flag in conjunction with this flag. | ||
+ | *'''c - Comments''': White space is ignored, and embedded comments starting with # are ignored until the end of a line. | ||
+ | *'''l - Literal''': White space is ignored, and embedded comments starting with # are ignored until the end of a line. | ||
+ | *'''d - Disable Dot All''': If the disable dot all flag is set then the dot expression (.) will match any character except a line terminator. By default, the dot expression only matches line terminators. | ||
+ | *'''m - Multiline''': In multiline mode the expressions ^ and $ match just after or just before, respectively, a line terminator or the end of the input sequence. By default, these expressions only match at the beginning and the end of the entire input sequence. | ||
+ | *'''u - unicode Case''': When this flag is specified, case-insensitive matching, enabled by the i (case insensitive) flag, is done in a manner consistent with the Unicode Standard. By default, case-insensitive matching assumes that only characters in the US-ASCII charset are being matched. | ||
+ | *'''x - Unix Lines''': In this mode, only the '\n' line terminator is recognized in the behavior of ., ^, and $. | ||
+ | *'''v - Not Matching''': Reverses the matching result. Expressions that normally would match will not match and expressions that would not normally match will match. | ||
+ | *'''n - No Error''': If the regular expression is invalid do not throw an exception, instead just always return false, unless the v flag is also set, in which case always return true. | ||
+ | |||
+ | 4. '''<null>''' | ||
+ | |||
+ | Null String - providing null will result in a matcher which matches nothing. | ||
+ | |||
+ | 5. '''<Empty String>''' | ||
+ | |||
+ | Providing an empty (zero length) string to the Matcher method will result in a matcher which matches only the empty string. | ||
+ | |||
+ | '''Conjugated Syntaxes''' | ||
+ | |||
+ | The following syntaxes allow for more complicated pattern matching. Nested syntaxes may also be conjugated syntaxes. For nested syntaxes which are basic syntaxes open parenthesis [ ( ] and close parenthesis [ ) ] must be escaped with a backslash [ \ ]. | ||
+ | |||
+ | 6. ''<span style="color: blue;">(Expression)</span>'': The parenthesis can be used to force order of operations, important when mixing or [ | ] and and [ & ] clauses. | ||
+ | |||
+ | 7. ''<span style="color: blue;">Expression1|Expression2</span>'': If either of the nested expressions match this expression will return true. | ||
+ | |||
+ | 8. ''<span style="color: blue;">Expression1&Expression2</span>'': If both of the nested expressions match this expression will return true. | ||
+ | |||
+ | 9. ''<span style="color: blue;">!Expression</span>'': Inverts the result of the expression. | ||
+ | |||
+ | 10. ''<span style="color: blue;">(Expression) ? (ExpressionTrue) : (ExpressionFalse)</span>'': If the Expression matches, return result of ExpressionTrue Otherwise return result of ExpressionFalse. | ||
+ | |||
+ | ''Sample Expressions'' | ||
+ | |||
+ | {| class="wikitable" | ||
+ | |- | ||
+ | ! Expression !! Examples Match !! Examples Mismatch !! Comments | ||
+ | |- | ||
+ | | <span style="font-family: courier new; color: blue;">FORG</span> || <span style="font-family: courier new; color: green;">3Forge</span> || <span style="font-family: courier new; color: red;">Frg</span> || ''Partial text, Case insensitive match'' | ||
+ | |- | ||
+ | | <span style="font-family: courier new; color: blue;">~FORG</span> || <span style="font-family: courier new; color: green;">FORGE</span> || <span style="font-family: courier new; color: red;">forge</span> || ''Partial text, Case sensitive match'' | ||
+ | |- | ||
+ | | <span style="font-family: courier new; color: blue;">^FORG$</span> || <span style="font-family: courier new; color: green;">FORG</span> || <span style="font-family: courier new; color: red;">FORGE</span> || ''Exact text, Case insensitive match'' | ||
+ | |- | ||
+ | | <span style="font-family: courier new; color: blue;">~^Forge$</span> || <span style="font-family: courier new; color: green;">Forge</span> || <span style="font-family: courier new; color: red;">forge</span> || ''Exact text, Case sensitive match'' | ||
+ | |- | ||
+ | | <span style="font-family: courier new; color: blue;">!FORG</span> || <span style="font-family: courier new; color: green;">3FOR</span> || <span style="font-family: courier new; color: red;">3FORGE</span> || ''Escape partial text, case insensitive'' | ||
+ | |- | ||
+ | | <span style="font-family: courier new; color: blue;">!^FORG$</span> || <span style="font-family: courier new; color: green;">FORGE</span> || <span style="font-family: courier new; color: red;">FORG</span> || ''Escape exact text, case insensitive'' | ||
+ | |- | ||
+ | | <span style="font-family: courier new; color: blue;">[RB]ob</span> || <span style="font-family: courier new; color: green;">Bobby</span> || <span style="font-family: courier new; color: red;">lob</span> || ''Using char list'' | ||
+ | |- | ||
+ | | <span style="font-family: courier new; color: blue;">[A-Z]ob</span> || <span style="font-family: courier new; color: green;">mob</span> || <span style="font-family: courier new; color: red;">7ob</span> || ''Char list range'' | ||
+ | |- | ||
+ | | <span style="font-family: courier new; color: blue;">3F*ge</span> || <span style="font-family: courier new; color: green;">3Forge llc</span> || <span style="font-family: courier new; color: red;">Forge llc</span> || ''Wild chars'' | ||
+ | |- | ||
+ | | <span style="font-family: courier new; color: blue;">3f.ge</span> || <span style="font-family: courier new; color: green;">3Frge</span> || <span style="font-family: courier new; color: red;">3Forge llc</span> || ''Match single char'' | ||
+ | |- | ||
+ | | <span style="font-family: courier new; color: blue;">Acme llc\.</span> || <span style="font-family: courier new; color: green;">Acme llc.</span> || <span style="font-family: courier new; color: red;">Acme llcc</span> || ''Escaping special chars'' | ||
+ | |- | ||
+ | | | ||
+ | [[File:AMIScript.SimpTextMatching.SampleExpressions.02.jpg|none]] | ||
+ | || <span style="font-family: courier new; color: green;">robert</span> || <span style="font-family: courier new; color: red;">ted</span> || ''Or clause partial match'' | ||
+ | |- | ||
+ | | | ||
+ | [[File:AMIScript.SimpTextMatching.SampleExpressions.03.jpg|none]] | ||
+ | || <span style="font-family: courier new; color: green;">rob</span> || <span style="font-family: courier new; color: red;">robert</span> || ''Or clause, exact match'' | ||
+ | |- | ||
+ | | <span style="font-family: courier new; color: blue;">bob&rob</span> || <span style="font-family: courier new; color: green;">robob</span> || <span style="font-family: courier new; color: red;">bobob</span> || ''And clause partial'' | ||
+ | |- | ||
+ | | <span style="font-family: courier new; color: blue;">'Exact'</span> || <span style="font-family: courier new; color: green;">Exact</span> || <span style="font-family: courier new; color: red;">exact</span> || ''Exact case sensitive text match'' | ||
+ | |- | ||
+ | | || || <span style="font-family: courier new; color: red;">a</span> || ''Empty string, only matches empty string'' | ||
+ | |- | ||
+ | | <span style="font-family: courier new; color: blue;">a?bb:s</span> || | ||
+ | <span style="font-family: courier new; color: green;">Abba</span> | ||
+ | |||
+ | <span style="font-family: courier new; color: green;">test</span> | ||
+ | |||
+ | || <span style="font-family: courier new; color: red;">acca</span> | ||
+ | |||
+ | <span style="font-family: courier new; color: red;">tent</span> | ||
+ | |||
+ | || ''If contains 'a', must contain 'bb' | ||
+ | |||
+ | ''If doesn't contain 'a', must contain 's' | ||
+ | |- | ||
+ | | | ||
+ | [[File:AMIScript.SimpTextMatching.SampleExpressions.04.jpg|none]] | ||
+ | || <span style="font-family: courier new; color: green;">af</span> || <span style="font-family: courier new; color: red;">ab</span> || Must contain a or b. Also must contain e or f | ||
+ | |- | ||
+ | | | ||
+ | [[File:AMIScript.SimpTextMatching.SampleExpressions.05.jpg|none]] | ||
+ | || <span style="font-family: courier new; color: green;">def</span> || <span style="font-family: courier new; color: red;">DEF</span> || Must be exactly 'abc' or 'def' | ||
+ | |- | ||
+ | | <span style="font-family: courier new; color: blue;">/reg/</span> || <span style="font-family: courier new; color: green;">regular</span> || <span style="font-family: courier new; color: red;">Regular</span> || ''By default, regex must be case sensitive'' | ||
+ | |- | ||
+ | | <span style="font-family: courier new; color: blue;">/reg/i/</span> || <span style="font-family: courier new; color: green;">Regular</span> || <span style="font-family: courier new; color: red;">whatever</span> || ''I option makes case insensitive'' | ||
+ | |- | ||
+ | | | ||
+ | [[File:AMIScript.SimpTextMatching.SampleExpressions.07.jpg|none]] | ||
+ | || <span style="font-family: courier new; color: green;">3F</span> | ||
+ | |||
+ | <span style="font-family: courier new; color: green;">reg</span> | ||
+ | || <span style="font-family: courier new; color: red;">3Forge</span> | ||
+ | |||
+ | <span style="font-family: courier new; color: red;">Regular</span> | ||
+ | || ''Mixing regex and non regex'' | ||
+ | |} | ||
+ | |||
+ | '''Sample Usage''' | ||
+ | The following snippet of code will print out all of the strings in the textList list that contain the phrase "my expression". See the Syntax section below for the various types of expressions that could be applied the someExpression variable. | ||
+ | |||
+ | <syntaxhighlight lang="amiscript"> | ||
+ | List<String> textList = someTextList; | ||
+ | String someExpression = "my expression"; | ||
+ | TextMatcher matcher SH.m(someExpression); | ||
+ | for(String text:textList){ | ||
+ | if(matcher.matches(text)) | ||
+ | System.out.println(text); | ||
+ | } | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | =AMI String Templating= | ||
+ | |||
+ | '''Goals''' | ||
+ | |||
+ | String templating is used to ease the dynamic creation of strings. Some key places that benefit from string templating: | ||
+ | |||
+ | *HTML generation | ||
+ | *SQL generation | ||
+ | *Content-rich messages for the end user | ||
+ | *Debugging / Logging | ||
+ | |||
+ | '''Basic Usage''' | ||
+ | |||
+ | As usual, strings are denoted using double quotes at the beginning and end, ex: "...". Within a string, ${...} is recognized as a special operator. The text between the curly braces is interpreted as code to be executed. For example, the code can be a simple variable name, or a complex set of expressions. | ||
+ | |||
+ | <span style="font-family: courier new; ">"text${code}text${code}..." </span> | ||
+ | |||
+ | If you wish to include a literal dollar sign followed by a curly bracket, the dollar sign must be escaped with a backslash. | ||
+ | |||
+ | <span style="font-family: courier new; ">"test\${stilltext}text"</span> ''<span style="font-family: courier new; ">//Evaluates to: test${stilltext}text</span>'' | ||
+ | |||
+ | To prevent against SQL (and other forms) of injections, ${...} wrapped with quotes ('), double quotes (") or back ticks (`) will cause the evaluated text to be escaped with a backslash (\) accordingly: | ||
+ | |||
+ | <span style="font-family: courier new; color: blue;">"text '${code}'" - results of code will have ' escaped to \'</span> | ||
+ | |||
+ | <span style="font-family: courier new; color: blue;">"text \"${code}\"" - results of code will have " escaped to \"</span> | ||
+ | |||
+ | <span style="font-family: courier new; color: blue;">"text `${code}`" - results of code will have ` escaped to \`</span> | ||
+ | |||
+ | For example: | ||
+ | |||
+ | <span style="font-family: courier new; ">"text `${code}`" - results of code will have ` escaped to \`</span> | ||
+ | |||
+ | <span style="font-family: courier new; ">String bar = "NAME LIKE '${foo}'";</span> ''<span style="font-family: courier new; ">//result is: NAME LIKE 'Eric\'s'</span>'' | ||
+ | |||
+ | Finally, null will evaluate to an empty string (""). | ||
+ | |||
+ | '''Examples''' | ||
+ | |||
+ | <syntaxhighlight lang="amiscript"> | ||
+ | Integer age = 20; | ||
+ | String name = "Sue"; | ||
+ | String message2 = "${name} is ${age} year(s) old"; // Simple Case: Sue is 20 year(s) old | ||
+ | String t = "Four times four is ${4 * 4}"; // Complex Expression: Four times four is 16 | ||
+ | String t2 = "40/9 is ${formatNumber(40/9d, "#.###")}"; // Calling functions: 40/9 is 4.444 | ||
+ | String t2 = "don't replace \${name}"; // Avoid Template: don't replace ${name} | ||
+ | |||
+ | String d = "ain't"; | ||
+ | String m1 = "escaping '${d}' easy"; // Evaluates to: escaping 'ain\'t' easy | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | ==Templated Flow Control== | ||
+ | |||
+ | The ${...} syntax can also be used to dictate if/how text should be included. This includes all flow control statements, including if-statements, for-loops, for-each-loops, and while-loops. All flow control statements are closed by the ${} token (empty curly brackets). | ||
+ | |||
+ | '''Flow Control Statement''' | ||
+ | |||
+ | <syntaxhighlight lang="amiscript"> | ||
+ | "[text]\ | ||
+ | ${flow_control(...)}\ | ||
+ | [text inside flow control]\ | ||
+ | ${}\ | ||
+ | [text]" | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | ''<span style="font-family: courier new; ">** Definition is a multiline string for clarity</span>'' | ||
+ | |||
+ | '''Single Line Flow Control Statement''' | ||
+ | |||
+ | <syntaxhighlight lang="amiscript"> | ||
+ | "[text]${flow_control(...)}[text inside flow control]${}[text]" | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | Ex: | ||
+ | |||
+ | <span style="font-family: courier new; color: blue;">"Count the apples: ${for(int i = 1; i <= 5; i++)} ${i} apple ${} There are 5 apples."</span> | ||
+ | |||
+ | <span style="font-family: courier new; color: blue;">"Count the apples: ${int i = 1; while(i++ < 6)} ${i} apple ${} There are 5 apples."</span> | ||
+ | |||
+ | <span style="font-family: courier new; color: blue;">"Count the apples: ${if(5 > 3)} apple apple apple apple apple ${} There are 5 apples."</span> | ||
+ | |||
+ | |||
+ | '''For if/else use the reserved ${else} token:''' | ||
+ | |||
+ | '''If/else Statements''' | ||
+ | |||
+ | <syntaxhighlight lang="amiscript"> | ||
+ | "[text]\ | ||
+ | ${if(...)}\ | ||
+ | [text inside if statement]\ | ||
+ | ${else}\ | ||
+ | [text inside else statement]\ | ||
+ | ${}\ | ||
+ | [text]" | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | ''<span style="font-family: courier new; ">** Definition is a multiline string for clarity</span>'' | ||
+ | |||
+ | '''Single Line If/else Statements''' | ||
+ | |||
+ | <syntaxhighlight lang="amiscript"> | ||
+ | "[text]${if(...)}[text inside if statement]${else}[text inside else statement]${}[text]" | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | Ex: | ||
+ | |||
+ | <span style="font-family: courier new; color: blue;">"Count the apples: ${if(5 < 3)} apple ${else} orange ${} There is one orange."</span> | ||
+ | |||
+ | '''Flow control statements can be nested:''' | ||
+ | |||
+ | '''Nested Flow Control Statements''' | ||
+ | |||
+ | <syntaxhighlight lang="amiscript"> | ||
+ | "[text]\ | ||
+ | ${flow_control_outer(...)}\ | ||
+ | [text inside outer flow_control]\ | ||
+ | ${flow_control_inner(...)}\ | ||
+ | [text inside inner flow_control]\ | ||
+ | ${}\ | ||
+ | [text inside outer flow_control]\ | ||
+ | ${}\ | ||
+ | [text]" | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | ''<span style="font-family: courier new; color: blue;">** Definition is a multiline string for clarity</span>'' | ||
+ | |||
+ | |||
+ | '''Single Line Nested Flow Control Statements''' | ||
+ | |||
+ | <syntaxhighlight lang="amiscript"> | ||
+ | "[text]${flow_control_outer(...)}[text inside outer flow_control]${flow_control_inner(...)}[text inside inner flow_control]${}[text inside outer flow_control]${}[text]" | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | Ex: | ||
+ | |||
+ | <syntaxhighlight lang="amiscript"> | ||
+ | "Courses:\n \ | ||
+ | ${for(int i = 120; i < 122; i++)} \ | ||
+ | Course: Math${i}\n \ | ||
+ | ${for(int j = 1000; j < 1009; j++) } \ | ||
+ | Students${j}\n \ | ||
+ | ${} \ | ||
+ | Professor For Math${i}:Stern\n \ | ||
+ | ${}\ | ||
+ | ====End====" | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | '''Examples''' | ||
+ | |||
+ | <syntaxhighlight lang="amiscript"> | ||
+ | List letters = new List("A", "B", "C"); | ||
+ | String s = "Easy as ${for(int i = 1; i <= 3; i++)} the number ${i} ${}";//Easy as 1 2 3 | ||
+ | String s2 = "${for(String i:letters)} ${i}${}, | ||
+ | Easy as ${for(int i = 1; i <= 3; i++)} ${i} ${}"; | ||
+ | //s2 evaluates to: A B C, Easy as 1 2 3 | ||
+ | |||
+ | { | ||
+ | Map messages = new Map(); | ||
+ | for(int num = 1; num <= 3; num++) | ||
+ | messages.put(num,"=is ${if(num == 2)}exactly${else}not${} two"); | ||
+ | session.alert(messages); // Evaluates to: {1=is not two,2=is exactly two,3=is not two} | ||
+ | } | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | =AMI Syntax for Embedding External Languages= | ||
+ | |||
+ | '''Goals''' | ||
+ | |||
+ | *Allow users familiar with other languages to embed familiar code into existing data models. | ||
+ | |||
+ | *Enable users to take advantage of existing libraries found in other languages | ||
+ | |||
+ | '''Syntax''' | ||
+ | |||
+ | <syntaxhighlight lang="amiscript"> | ||
+ | extern language {{ | ||
+ | ... | ||
+ | embedded_code_in_other_langauge | ||
+ | ... | ||
+ | }}; | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | Rules on Prefixing and terminating the custom code segment: | ||
+ | |||
+ | *The prefix must be at least 2 consecutive opening curly brackets ({). | ||
+ | *The termination must have the same number of closing curly brackets (}) as the prefix has. | ||
+ | *You can not include the suffix inside the embedded code. So for example, let's say you have a }} inside the embedded code, then you should wrap the embedded code in three curly brackets, ex: {{{custom_code_witha_double_curlys}}} | ||
+ | *The embedded code is evaluated literally, ex: all escapes, etc. are sent directly to the sub-language engine | ||
+ | |||
+ | Currently, python is supported out of the box. | ||
+ | |||
+ | '''Example''' | ||
+ | |||
+ | <syntaxhighlight lang="amiscript"> | ||
+ | { | ||
+ | int n=5; | ||
+ | |||
+ | extern python {{ | ||
+ | for i in xrange(2,5): | ||
+ | n=n*i; | ||
+ | }}; | ||
+ | |||
+ | session.log(n);// will log 120 | ||
+ | } | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | =Formatting Timestamps= | ||
+ | |||
+ | 3forge provides two ways of handling timestamps when it comes to formatting: | ||
+ | * '''User Settings''': If you like to maintain a unified date/time format across the dashboard, the formatting can be configured via user settings. Simply navigate to Account -> My Settings | ||
+ | |||
+ | [[File:timestamp-user-settings.png|alt Timestamp in User Settings]] | ||
+ | |||
+ | * '''AMI Script Methods''': If you like to have different formats in different places in the dashboard, AMI Script provides a handful of methods that can be utilized. To know more about their usage you can navigate to Help -> AMI Script Doc and the relevant methods will be available under AMI-Script Functions. | ||
+ | |||
+ | [[File:Timestamp-doc.png|alt AMI Script Methods for formatting timestamp]] | ||
+ | |||
+ | An example is provided below where an AMI Script Method has been used to format a table column. | ||
+ | |||
+ | [[File:Timestamp-amiscript.png|alt Formatting timestamp in table column via AMI Script]] | ||
+ | |||
+ | Additionally, You can set the default timezone for all users by setting the property in local.properties: | ||
+ | |||
+ | <span style="font-family: courier new; color: blue;">ami.default.user.timezone</span>=EST5EDT | ||
+ | |||
+ | =AMI Reserved WORDS (alphabetical)= | ||
+ | |||
+ | <span style="font-family: courier new; color: red;">ADD ALTER ANALYZE AND AS ASC BEFORE BINARY BOOLEAN BREAK BY CALL CASE CATCH CREATE CONCURRENT CONTINUE DEFAULT DELETE DESC DESCRIBE DISABLE DO DOUBLE DROP ELSE ENABLE EXECUTE EXTERN FLOAT FOR FROM GROUP HAVING IF IN INDEX INSERT INT INTEGER INTO JOIN LEFT LIMIT LONG MODIFY NEAREST NEW OFTYPE ON ONLY OR ORDER PARTITION PREPARE PRIORITY PROCEDURE PUBLIC RENAME RETURN RIGHT SELECT SET SHOW STEP STRING SWITCH SYNC TABLE TABLES TIMER TRIGGER TO TRUNCATE UNION UNPACK UPDATE USE UTC UTCN VALUES WHERE WHILE WINDOW</span> | ||
+ | |||
+ | ''Reserved words are case insensitive'' |
Latest revision as of 14:47, 11 January 2024
AMI Script Introduction
Overview
AMI has an embedded, versatile language which is a combination of the well-known C/Java style, SQL and String Templating languages. Here is a very quick example of the incredible versatility of the language which does a cross-database join:
1{
2 //Inspect the ACCOUNTS table of two pre-defined databases (qadb & proddb).
3 //Two temporary in-memory tables are created (qatemp and prtemp)
4 String table = "ACCOUNTS";
5 CREATE TABLE qatemp AS USE datasource=qadb EXECUTE SELECT * FROM ${table};
6 CREATE TABLE prtemp AS USE datasource=proddb EXECUTE SELECT * FROM ${table};
7
8 //Gather some statistics, Note that the results of the queries on the in-memory tables are
9 //stuffed into the local variables
10 int qaCnt = select count(*) from qatemp;
11 int prCnt = select count(*) from prtemp;
12 int bothCnt = select count(*) from qatemp, prtemp where qatemp.id == prtemp.id;
13
14 //Alert the user with some statistics, including the number of users in both qa and prod
15 session.alert("Found ${qaCnt + prCnt} ${table} rows: ${qaCnt} in qa and ${prCnt} in prod. \
16 There are ${bothCnt} ids existing in both");
17
18 //Create a Temporary ProdOnly table that contains all users in prod but not qa.
19 //This table can be used in the visualization layer
20 Create table ProdOnly as select * from prtemp where !(id in (select id from qatemp));
21}
In this introductory language you can see the interoperability of SQL and a procedural style language. The ${...} syntax is used for easily creating dynamic strings and SQL statements.
Key Features
AMI Script is a versatile language designed for optimized "on the fly" compilation, meaning expressions can be re-compiled and evaluated in an instant. Some key features of the language:
- Type Safe - All variables have well defined types, ex: String vs. Integer
- Compile Time Binding - Code is compiled before execution to minimize runtime issues
- Procedural - Custom methods (with overloading), along with a set of predefined procedures
- Object Oriented - Objects in AMI are represented as such in Ami Script
- Event Driven - Executes based on events, such as running a datamodel or clicking a button
- Implicit Casting - Casting from one type to another can be explicitly or implicitly defined
- Embedded SQL - For accessing external sources and tables directly in the language. See below
- String Templating - Ability to template code for reuse. See below
- Task Swapping - Tasks can be exported runtime for out-of-band execution. (separate thread)
Embedded SQL is an SQL-style language extension to AMI Script with near-full SQL support along with several enhancements geared towards data preparation for the visualization of data. All of these functions act on an in-memory database. It also supports "calling out" to external datasources. Some key features are:
- Query Clauses - For filtering, joining, and grouping data on the in-memory database
- Data Modification - For adding, updating, and deleting data on the in-memory database
- Schema Modification - For adding, editing, and deleting tables/columns on the in-memory database
- Use … Execute - For seamlessly running code on external datasources and storing results to the in-memory database
- Advanced Data Preparation and Analysis - For complex data calculations, not typically available on a standard SQL database
- Lambda Support -The ability to run AMI script code inside SQL. For example, to run a code snippet per row returned in a table
- Nested Queries - The in(…) clause supports full nested queries, and also supports multiple column in-clauses
- Intelligent Indexing - As joins, in-clauses, etc. are evaluated, indexes will automatically be spun up depending on data size and cardinality
AMI Script Template syntax is an extension of AMI Script with the aim of simplifying dynamic text generation, useful for creating dynamic HTML, dynamic SQL, etc.
- Embed Ami Script inside Text - Embed AMI script inside text allows for easy dynamic text generation
- Embed Ami Script inside SQL - Embed AMI script inside SQL allows for easy dynamic SQL generation
- Injection Protection - Properly escaping control characters, quotes, etc.
- Conditional Templating - Ability to do conditional & loop based template construction
AMI Script - A java syntax with embedded SQL and String Templates
Syntax
Same support as java for loops, if/else statements, white space, comments and expressions:
1double n=0;
2for(int i=0;i<10;i++){
3 if(i < 5)
4 n++; //increment a number
5}
6/* sample expression, same as java*/
7int b=4 > 5 ? 1 * 2 : 5 / 2;
Data Structures
General purpose List, Map, Set & Table data structures are provided. The constructors can be used to prepopulate data:
1List mylist=new List(1,2,3,4);
2Map mymap=new Map(“fname”,”Eric”,”lname”,”Johnson”);
3Set set=new Set("a", "b", "c");
4Table t =new Table("People", "user String, age int");
Type Safety & Coercion
Type names are case insensitive, ex double and DOUBLE are the same. For compatibility, int and integer mean the same thing as well as char and character.
1int n=5;
2Int m=n*n;
3INTEGER o=m*m;
All types support null value. Dereferencing null, results in null. Expressions with null result in null
1List l=null;
2Integer s=l.size(); //s is null, does not raise null pointer
3Double n=5,m=null;
4Double p=n*m;//p is null because anything times null is null
Flexible type coercion. When coercion is not possible the value is coerced to null.
1Int value="123"; //value will be 123
2Double value2=new List(); //list can’t be cast to double so value2 will be null
3String value3=new List(1,2,3); //value3 is the string [1, 2, 3]
All types extend Object and casting is not necessary for assignment.
1Object o=new List(1,2,3);
2List l=o; //this works because the value of o is a List.
3Map m=0; //m will be null because a List can not be cast to a map
All types can be thrown / caught and all blocks can have catch clauses (try key word is not necessary)
1{
2 throw "what!";
3}catch(String s){
4}
String Templates
If strings contain a ${...} the content of the curly brackets is interpreted
1String name="rob";
2String message1="hello ${name}"; // hello rob
3String message2="A baker’s dozen is {12+1}"; // A baker’s dozen is 13
String Template Example
In this example, we will use string templates to access and evaluate variables from amiscript and pass them to a div field.
1string topHeaderName = "Top Header";
2string subHeaderName = "Sub Header";
3
4string scripts = "<h1>${topHeaderName}</h1> <h3>${subHeaderName}</h3>";
5div.setValue(scripts);
Alternatively, you could also use string template inside the div field:
1<h1>${__USERNAME}</h1> <h3>${__USERNAME+"123"}</h3>
You can use triple quotes for literals:
String m="""hello ${world}"""; // hello ${world}
SQL
There are several reserved words that indicate an sql statement, including CREATE, SELECT, INSERT, DELETE, etc.
1CREATE TABLE T(username String, id int);
2INSERT INTO t values ("rob",111),("dave",222"); //table t has 2 rows
3CREATE TABLE t2 as select * from t where id<200; //table t2 has 1 row
Variables and templates can be used inside sql:
1String name="eric";
2Int id=333;
3INSERT INTO T VALUES(name,id); //inserts eric,333
4String row="values (\"mike\",444)";
5INSERT INTO T ${row};//expands to INSERT INTO T values("mike",444);
Table coercion works for Table cells to objects, Columns to Lists and Rows to maps.
1String s=select username from t where id==111; //s=rob
2List names=select username from t; //names= [rob, dave]
3Map user=select * from t where id=222; //user={username=dave, id=222}
To query external data sources run the USE ds= … EXECUTE command.
1CREATE TABLE t3 as USE ds="mydatabase" EXECUTE SELECT * FROM ORDERS;
2//RAN SELECT * FROM ORDERS on the mydatabase datasource and created a local table called t3
To upload data to external data sources run the USE ds= … INSERT command.
1USE ds="targetdb" INSERT INTO TargetAccounts FROM useds="sourcedb" SELECT * from SourceAccounts;//query all data fromsourcedb’s SourceAccounts table and insert into targetdb’s TargetAccounts table
Custom Methods
Methods are static and must return a type. If a return is clause is not reached, the function returns null.
1String combine(String s,String t){
2
3 if(s!=null && t!=null)
4
5 return s+" "+t;
6
7};
8
9String s=combine("apple","orange");//s is now apple orange
10String t=combine("apple",null);//t is null
AMI Script
Variable Naming
Case-sensitive combination of a-z, A-Z, _, 0-9. The first character must not be a number. Alternatively, variables can be wrapped in back ticks (`), in which case all characters are supported, allowing for accessibility with external language references. Note: `test` is equivalent to test. Variables are declared with the following syntax (the value will default to null if an expression is not supplied):
type variable_name [ = expression][, variable_name [ = expression] ... ];
Literals (Constants)
digits | Int constant |
0xdigits | Hex Int constant |
0digits | Octal Int constant |
digitsL | Long constant |
0xdigitsL | Hex long constant |
0digitsL | Octal long constant |
digits.digits | Float constant. Note, scientific (aka 'E') notation is supported |
digits.digitsD | Double constant. Note, scientific (aka 'E') notation is supported |
"chars" | String constant. Use backslash (\) to escape quotes, backslash (\\) and other control chars, ex: \n. A string can be defined over multiple lines using a trailing backslash on all but the last line, note that preceding white space is trimmed out for subsequent lines. Please see String Templating section for details on ${…} syntax |
\n\r\t<space> | White space (token delimiter) |
Reserved Type
All reserved types' values are immutable. Null is a valid value
Long | 64 bit signed whole number |
Double | 64 bit signed float |
String | Variable length string of UTF 8 characters |
Integer | 32 bit signed whole number |
Float | 32 bit signed float |
Byte | 8 bit signed whole number |
Boolean | boolean (true or false) |
Number | Base class for Long,Double,Integer,Float,Byte |
UTC | Timestamp with millisecond precision (since unix epoch) |
Examples
Integer i = 32;
Double d = 4.3, f = 132.d; //declaring multiple variables
Integer j = 0xaabcc;
String test = "hello world";
String Test = "Hello \
world"; //Multi line
Integer lng = 100000000000L;
Boolean flag = true;
Byte some_thing = null;
Casting
Variables are strongly typed, but casting can be explicit or implicit. If a cast fails, the result evaluates to null. Also, equality operations (==, <=, >=, >, <, !=) will also auto cast when possible as well.
Examples
String test1 = 123; //implicit cast from integer to string
String test2 = "0x123";//implicit cast from hexidecimal integer to string
Double val = "123.32"; //implicit case for string to double
Boolean b = "true"; //implicit cast from string to boolean
String val = (Integer) 123.d; //explicit cast from double to integer, then implicit cast to String
Boolean c = "test"; //Evaluates to null because the implicit cast from string to boolean is invalid
Byte d; //Evaluates to null by default
Variable Scoping
Scopes are defined using statement blocks, which are denoted by curly brackets: {…}. Within a statement block, variables are only visible after they are declared. When statement blocks are nested inside other statement blocks, all variables declared in the outer block are visible within the inner block as long as the variable is declared before the inner block. A variable cannot be re-declared when another variable with the same name is visible.
Examples
{
Byte a;
//a is visible;
Byte b;
//a & b are visible;
{
Byte c;
//a, b & c are visible;
Byte d;
//a, b, c & d are visible;
{
Byte e;
//a, b, c, d & e are visible;
}
//a, b, c & d are visible;
}
//a & b are visible;
Byte a; //Compiler error: a already exists and can not be redefined
}
Standard Operators (in order of significance)
math_expressions
(evaluates to num_var type)
num_expr | * | num_expr | multiplication |
num_expr | / | num_expr | division |
num_expr | % | num_expr | modulus (remainder) |
num_expr | + | num_expr | addition for numbers |
num_expr | - | num_expr | subtraction |
binary_expressions
(evaluates to num_int_expr type)
int_expr | ~ | int_expr | bitwise NOT |
int_expr | << | int_expr | signed bit shift left |
int_expr | >> | int_expr | signed bit shift right |
int_expr | >>> | int_expr | unsigned bit shift right |
int_expr | & | int_expr | bitwise AND |
int_expr | ^ | int_expr | bitwise XOR |
int_expr | ! | int_expr | bitwise OR |
boolean_expressions
(evaluates to boolean)
! | bool_expr | boolean (logical) NOT | |
expr | < | expr | less than (strings are case sensitive) |
expr | > | expr | greater than (strings are case sensitive) |
expr | <= | expr | less than or equal to (strings are case sensitive) |
expr | >= | expr | greater than or equal to (strings are case sensitive) |
expr | == | expr | equal to (strings are case sensitive) |
expr | != | expr | is not equal to (strings are case sensitive) |
expr | =~ | regex | matches regular expression (see Java Pattern for details) |
expr | !~ | regex | does not match regular expression (see Java Pattern for details) |
expr | ~~ | simple_pattern | simplified text matching. See Simplified Text Matching section. |
expr | && | expr | logical and. Short circuits if left expr returns false. Short circuits if right expr is const and false |
expr | expr | logical or. Short circuits if left expr returns true. Short circuits if right expr is const and true |
string_expressions
(evaluates to boolean)
string_expr+ expr | String concatenation. Null values equate to empty string ("") |
special_expressions
(expression) | Force Order of operations |
array_of_type[num_expr] | Array index referencing |
(type)statement | Explicit cast to type. Note that a failed cast returns null. Also, casting is automatic, so it's not necessary |
bool_expr ? tr_expr : fl_expr | If bool_expr returns true, then evaluates to tr_expr, otherwise evaluates to fl_expr. |
Examples
Long n = (10 + 5) * 2; //n is 30
n += 5; //n is 35
n = n/2; //n is 17
Boolean b = n>10; //b is true (n is still 17)
b =! b; //b is false
b = (b || true) && true;//b is true
String test = "hello" + "world"; //test is helloworld
Assignment & Declaration
special (evaluates to type)
new type(param[, param ...]) | Object Creation |
type var_name | Variable declaration (Value is defaulted to null) |
type var_name = expression | Variable declaration and assignment |
Variable declaration and assignment | Variable declaration and assignment |
assignment (evaluates to num_var type)
num_var | ++ | combined post-increment assignment | |
++ | num_var | combined pre-increment assignment | |
num_var | -- | combined post-decrement assignment | |
-- | num_var | combined pre-decrement assignment | |
num_var | *= | num_expr | combined multiplication assignment |
num_var | /= | num_expr | combined division assignment |
num_var | %= | num_expr | combined modulus assignment (remainder) |
num_var | += | num_expr | combined addition assignment |
num_var | -= | num_expr | combined subtraction assignment |
Flow Control
Complex AMI scripts can be achieved by combining multiple statements into statement blocks. A statement block is wrapped in curly brackets {...} and each statement is separated with a semi-colon;. Then, the execution of statement blocks can be determined using a variety of flow control statements including if, if/else, for, while, and for-each-loops. Note that for and while loops can use the continue and break directives as well. Examples
{
Integer count = 10;
Integer value = 1;
for(Integer i = 0; i < count; i++){
value *= 2;
}
if(value < 2000) {
session.alert(value); //alert shows 1024
} else
session.alert("High value"); // this is never hit. Also note: single statements don't need to be in {...} statement blocks
while(true){
value -= 10;
if(value < 1000)
break;
}
//value is now 994
}
statement block
{ statement [;statement ...] [;]}
** Evaluates to return value if a return_statment exists, otherwise it evaluates to the last statement's evaluation. If no statements, evaluates to Void
for loop
for(initialization;termination_expression;increment) statement
initialization: statement that is called first, used to declare variables with local scope
termination_expression: statement that must evaluate to boolean, false terminates
increment: statement called after each completion of the loop's statements
statement: called once per loop. Note:
- continue_statement will exit the statement and proceed to increment statement
- break_statement will exit the for loop entirely
**Evaluates to Void
for each loop
for(type_expr varname:iterable_or_array) statement
iterable_or_array - values to iterate over in order
statement: called once per loop. Note:
- continue_statement will exit the statement and proceed to increment statement
- break_statement will exit the for loop entirely
**Evaluates to Void
while loop
while(bool_expression) statement
same as for(;bool_expression;) statement
**Evaluates to Void
if statement
if(bool_expression) statement
if bool_expression evaluates to true then execute statement
**Evaluates to Void
if else statement
if(bool_expression) statement else statement2
if bool_expression evaluates to true then execute statement otherwise executestatement2
**Evaluates to Void
return statement
return statement
** Evaluates to statement's value. Will cause call stack to be popped out to caller function.
break statement
break
** See for_loop, for_each_loop and while_loop
continue statement
continue
** See for_loop, for_each_loop and while_loop
function call
function(param[, param ...])
**Evaluates to return_type value
member method call
target_object.function(param[, param ...])
**Evaluates to return_type value
Objects
There is a predefined set of object types (classes). These are used to facilitate the interaction between AMI Script and various backend components, user inputs, dashboards, etc. Additionally, data structures are represented as objects and can be instantiated using the new operator. Objects can only be accessed via methods (not member variables).
The Session Object
session - each user that is logged in has a session object (which is of type Session). This is the "starting point" for access to the user's information, along with various dashboard components.
Attributes and Class Methods for a Session Object
1. session values: A hash map that stores user defined variables in the format of Variable_name_key=variable_value. Initially it is an empty map.
(1.1) session.setValue(string key, object value) && session.getValue(string key) && session.getValues()
int a = 3;
session.setValue("sessionVal_a",a); //setting a to the session value
session.getValue("sessionVal_a"); //getting the session value by the key
int b = 4;
session.setValue("sessionVal_b",b); //setting b to the session value
session.getValues(); //{sessionVal_a=3, sessionVal_b=4}
2. session variables: A list of variables that are predefined by dashboard and webserver. They cam be viewed from Dashboard -> Session Variables
The dashboard editor can also define custom session variables by clicking Add variable. These are saved as part of the dashboard layout file
Now this variable that we just defined is accessible everywhere in the current session.
3.session global properties: these are server properties defined in the default.properties, local.properties and all other properties files
(3.1) session.getGlobalProperty(string propertyKey)
session.getGlobalProperty("ami.components");
4. session Properties: another way to access session variables
//Suppose there is a session variable called "a", the two ways below for accessing "a" are equivalent
session.log(session.getProperty("a"));
session.log(a);
Common Data Structures
List: A zero-indexed Array List implementation
Set: A set of unique values
Map: A Linked Hash Map implementation
Table: A 2-dimensional table with the same characteristics as a SQL style table. Tables have a title. Columns are named and strongly typed.
Tableset: A map of tables. Can be loosely thought of as a mini database.
Examnples
session.alert("this is a test");
session.log("something worth logging);
List l = new List("apple", "orange", "berry", "banana");
l.splice(1, 2, "strawberry");
String s = l; //s is now apple, strawberry, banana
Map m = new Map(1, "one", 2, "two", 3, "three"); //map contains three key/value pairs, ex: 2 = "two"
Commenting
Commenting is identical to the commenting syntax in Java & C++. There are two types of comments: single-line and multi-line.
comments (single-line)
//comments<linefeed>
comments (multi-line)
/*comments*/
Examples
/*multi-line
comment using the
slash stars*/
//single-line comment
AMI Script Constants
AMI Script can reference constants just like other variables. Note the constant's values can not be changed using AMI Script. The standard naming convention for global variables is 2 under bars (__) followed by an all uppercase name. Constants can be defined in three ways:
- At the server level (via a config file loaded at startup, typically local.properties)
Typically the syntax is: amiscript.variable.varname=value
(note that if value is a string, is must be surrounded in double quotes, see LITERALS for details)
For example, this could reside in your local.properties:
#My custom variables
amiscript.variable.__COMPANY_NAME="Acme Technologies"
amiscript.variable.__COPYRIGHT=2017
- At the user level (using the authentication plugin, or the access.txt file)
Typically the syntax is: amiscript.variable.varname=value
(note that if value is a string, is must be surrounded in double quotes, see LITERALS for details)
For example, this could reside in your access.txt file for user demo (with password demo123):
demo|demo123|amiscript.variable.__GROUP="infosec"|amiscript.variable.__SECURITY_LEVEL=12
- There are also pre-determined variables defined by the AMI Web system:
- __USERNAME: (String) the username of the logged in user
- __SESSIONID: (String) a unique id for the web session
- __TIMEZONE: (String) the timezone of the user's session
- __ADDRESS: (String) the ip address of the user's browser
- __LOADTIME: (Long) the time in milliseconds that the user started the session
- session: (Session) the session object representing the user's session
Hint: Through the front end in editor mode you can view all declared constants via: Menu Bar -> Dashboard -> Variable Table
SimplifiedText Matching
Overview
The simplified text matching finds text entries using a simple pattern. When included in AMI script, it takes the form: var ~~ "my pattern"
Rule 1, the general case: the pattern supplied will match any text that contains the pattern, case insensitive. For example, assuming word is a variable let's consider the expression: word ~~ "AB". This will return true if word is cab or ABC or tabs but will return false if word is apple.
Rule 2, special symbols: If you need to look for symbols besides letters, numbers or white space, prefix with a back slash. For example, to look for the word P&L, the expression is word ~~ "P\\&L". Remember, we are in a string so a double back slash evaluates to a single backslash. Note this includes the following list of symbols: *^$.[]()~|&!?:
Rule 3, Additional syntax: There are many special symbols that can be used for more advanced searches, for example the star (*) means anything, so "f*g" will match any thing that has an f followed by g, such as 3FORGE. See the following sections for more advanced syntax.
Syntax The following syntaxes are used to do "basic" matching against expressions with some text.
1. Simple Matching Expression
Matches any text that contains the supplied pattern regardless of case. The following characters are reserved and may be embedded in the expression:
- * - Anything: Can be expanded to include any text.
- ^ - Starts With: Symbolizes the "start" of the text. In other words, if an expression starts with ^, then the text must start with the following expression. Please note that carets (^) not at the start of the expression will be treated as literals. (When used in conjunction with the tilde (~), the hat should follow the tilde.)
- $ - Ends With: Symbolizes the "end" of the text. In other words, if an expression ends with a dollar sign($) then the text must end with the preceding expression. Please note that dollar signs not at the end of the expression will be treated as literals.
- . - Any single char.: each dot will disregard one character and checks for the target character(s) in the remaining string, case INsensitive.
Examples:
- ".s" disregards the first character, checks for "s" OR "S" in the remaining string;
- "s." attempts to find "s" OR "S" in the string. If found, disregards the next character and returns a match. If not found, returns empty;
- "..s" disregards the first TWO characters, checks for "s" OR "S" in the remaining string. Return a match if "s" OR "S" is found, empty otherwise;
- "ss.." attempts to find "ss" OR either one of ("sS", "SS", "Ss") (must be consecutive "s") in the string. When found, disregards the next two characters and returns a match;
- "..s.S.." disregards the first TWO characters, attempts to find one "s" OR "S", if found, disregard the next character, then attempts to find another "s" OR "S" in the remaining string, if found, disregards the next two characters and returns a match. If "s" was not found in either one of the two scenarios, return empty.
- Note that the evluation order is always from left to right. Each character is checked at most once.
- [charlist] Any of Chars.: Match any one of the characters enclosed within the brackets.
- ~: Case Sensitive. Apply it before the first character. It indicates case sensitivity when matching the string.
- Escaped chars: When referencing the following characters literally, they must be escaped with a back slash (\): *^$.[]()~|&!?:
- Literals: These are simply letter-for-letter matches to the expression
2. 'Exact Expression'
Matches the exact expression supplied in quotes (other than an escaped quote using \' ). This would be similar to using an equals ( == )
3. /regex/<options>/
This will use the java.util.regex package to match against regular expressions (see the java.util.regex.Pattern for details on building regular expressions). The <options> allow you to control behavior of how the regular expression operates. Simply supply the options you would like to apply in a continuous string between the 2nd and last forward slash (/). The following options are supported:
- q - Canonical Equivalence: When this flag is specified, two characters will be considered to match if and only if their full canonical decompositions match. The expression "a\u030A", for example, will match the string "?" when this flag is specified. By default, matching does not take canonical equivalence into account.
- f - Full Line: When this flag is specified, the text must fully match the regular expression. If this option is not specified, any portion of the text matching the expression will be considered a match.
- i - Case Insensitive: By default, case-insensitive matching assumes that only characters in the US-ASCII charset are being matched. Unicode-aware case-insensitive matching can be enabled by specifying the u (Unicode case) flag in conjunction with this flag.
- c - Comments: White space is ignored, and embedded comments starting with # are ignored until the end of a line.
- l - Literal: White space is ignored, and embedded comments starting with # are ignored until the end of a line.
- d - Disable Dot All: If the disable dot all flag is set then the dot expression (.) will match any character except a line terminator. By default, the dot expression only matches line terminators.
- m - Multiline: In multiline mode the expressions ^ and $ match just after or just before, respectively, a line terminator or the end of the input sequence. By default, these expressions only match at the beginning and the end of the entire input sequence.
- u - unicode Case: When this flag is specified, case-insensitive matching, enabled by the i (case insensitive) flag, is done in a manner consistent with the Unicode Standard. By default, case-insensitive matching assumes that only characters in the US-ASCII charset are being matched.
- x - Unix Lines: In this mode, only the '\n' line terminator is recognized in the behavior of ., ^, and $.
- v - Not Matching: Reverses the matching result. Expressions that normally would match will not match and expressions that would not normally match will match.
- n - No Error: If the regular expression is invalid do not throw an exception, instead just always return false, unless the v flag is also set, in which case always return true.
4. <null>
Null String - providing null will result in a matcher which matches nothing.
5. <Empty String>
Providing an empty (zero length) string to the Matcher method will result in a matcher which matches only the empty string.
Conjugated Syntaxes
The following syntaxes allow for more complicated pattern matching. Nested syntaxes may also be conjugated syntaxes. For nested syntaxes which are basic syntaxes open parenthesis [ ( ] and close parenthesis [ ) ] must be escaped with a backslash [ \ ].
6. (Expression): The parenthesis can be used to force order of operations, important when mixing or [ | ] and and [ & ] clauses.
7. Expression1|Expression2: If either of the nested expressions match this expression will return true.
8. Expression1&Expression2: If both of the nested expressions match this expression will return true.
9. !Expression: Inverts the result of the expression.
10. (Expression) ? (ExpressionTrue) : (ExpressionFalse): If the Expression matches, return result of ExpressionTrue Otherwise return result of ExpressionFalse.
Sample Expressions
Expression | Examples Match | Examples Mismatch | Comments |
---|---|---|---|
FORG | 3Forge | Frg | Partial text, Case insensitive match |
~FORG | FORGE | forge | Partial text, Case sensitive match |
^FORG$ | FORG | FORGE | Exact text, Case insensitive match |
~^Forge$ | Forge | forge | Exact text, Case sensitive match |
!FORG | 3FOR | 3FORGE | Escape partial text, case insensitive |
!^FORG$ | FORGE | FORG | Escape exact text, case insensitive |
[RB]ob | Bobby | lob | Using char list |
[A-Z]ob | mob | 7ob | Char list range |
3F*ge | 3Forge llc | Forge llc | Wild chars |
3f.ge | 3Frge | 3Forge llc | Match single char |
Acme llc\. | Acme llc. | Acme llcc | Escaping special chars |
robert | ted | Or clause partial match | |
rob | robert | Or clause, exact match | |
bob&rob | robob | bobob | And clause partial |
'Exact' | Exact | exact | Exact case sensitive text match |
a | Empty string, only matches empty string | ||
a?bb:s |
Abba test |
acca
tent |
If contains 'a', must contain 'bb'
If doesn't contain 'a', must contain 's' |
af | ab | Must contain a or b. Also must contain e or f | |
def | DEF | Must be exactly 'abc' or 'def' | |
/reg/ | regular | Regular | By default, regex must be case sensitive |
/reg/i/ | Regular | whatever | I option makes case insensitive |
3F
reg |
3Forge
Regular |
Mixing regex and non regex |
Sample Usage The following snippet of code will print out all of the strings in the textList list that contain the phrase "my expression". See the Syntax section below for the various types of expressions that could be applied the someExpression variable.
List<String> textList = someTextList;
String someExpression = "my expression";
TextMatcher matcher SH.m(someExpression);
for(String text:textList){
if(matcher.matches(text))
System.out.println(text);
}
AMI String Templating
Goals
String templating is used to ease the dynamic creation of strings. Some key places that benefit from string templating:
- HTML generation
- SQL generation
- Content-rich messages for the end user
- Debugging / Logging
Basic Usage
As usual, strings are denoted using double quotes at the beginning and end, ex: "...". Within a string, ${...} is recognized as a special operator. The text between the curly braces is interpreted as code to be executed. For example, the code can be a simple variable name, or a complex set of expressions.
"text${code}text${code}..."
If you wish to include a literal dollar sign followed by a curly bracket, the dollar sign must be escaped with a backslash.
"test\${stilltext}text" //Evaluates to: test${stilltext}text
To prevent against SQL (and other forms) of injections, ${...} wrapped with quotes ('), double quotes (") or back ticks (`) will cause the evaluated text to be escaped with a backslash (\) accordingly:
"text '${code}'" - results of code will have ' escaped to \'
"text \"${code}\"" - results of code will have " escaped to \"
"text `${code}`" - results of code will have ` escaped to \`
For example:
"text `${code}`" - results of code will have ` escaped to \`
String bar = "NAME LIKE '${foo}'"; //result is: NAME LIKE 'Eric\'s'
Finally, null will evaluate to an empty string ("").
Examples
Integer age = 20;
String name = "Sue";
String message2 = "${name} is ${age} year(s) old"; // Simple Case: Sue is 20 year(s) old
String t = "Four times four is ${4 * 4}"; // Complex Expression: Four times four is 16
String t2 = "40/9 is ${formatNumber(40/9d, "#.###")}"; // Calling functions: 40/9 is 4.444
String t2 = "don't replace \${name}"; // Avoid Template: don't replace ${name}
String d = "ain't";
String m1 = "escaping '${d}' easy"; // Evaluates to: escaping 'ain\'t' easy
Templated Flow Control
The ${...} syntax can also be used to dictate if/how text should be included. This includes all flow control statements, including if-statements, for-loops, for-each-loops, and while-loops. All flow control statements are closed by the ${} token (empty curly brackets).
Flow Control Statement
"[text]\
${flow_control(...)}\
[text inside flow control]\
${}\
[text]"
** Definition is a multiline string for clarity
Single Line Flow Control Statement
"[text]${flow_control(...)}[text inside flow control]${}[text]"
Ex:
"Count the apples: ${for(int i = 1; i <= 5; i++)} ${i} apple ${} There are 5 apples."
"Count the apples: ${int i = 1; while(i++ < 6)} ${i} apple ${} There are 5 apples."
"Count the apples: ${if(5 > 3)} apple apple apple apple apple ${} There are 5 apples."
For if/else use the reserved ${else} token:
If/else Statements
"[text]\
${if(...)}\
[text inside if statement]\
${else}\
[text inside else statement]\
${}\
[text]"
** Definition is a multiline string for clarity
Single Line If/else Statements
"[text]${if(...)}[text inside if statement]${else}[text inside else statement]${}[text]"
Ex:
"Count the apples: ${if(5 < 3)} apple ${else} orange ${} There is one orange."
Flow control statements can be nested:
Nested Flow Control Statements
"[text]\
${flow_control_outer(...)}\
[text inside outer flow_control]\
${flow_control_inner(...)}\
[text inside inner flow_control]\
${}\
[text inside outer flow_control]\
${}\
[text]"
** Definition is a multiline string for clarity
Single Line Nested Flow Control Statements
"[text]${flow_control_outer(...)}[text inside outer flow_control]${flow_control_inner(...)}[text inside inner flow_control]${}[text inside outer flow_control]${}[text]"
Ex:
"Courses:\n \
${for(int i = 120; i < 122; i++)} \
Course: Math${i}\n \
${for(int j = 1000; j < 1009; j++) } \
Students${j}\n \
${} \
Professor For Math${i}:Stern\n \
${}\
====End===="
Examples
List letters = new List("A", "B", "C");
String s = "Easy as ${for(int i = 1; i <= 3; i++)} the number ${i} ${}";//Easy as 1 2 3
String s2 = "${for(String i:letters)} ${i}${},
Easy as ${for(int i = 1; i <= 3; i++)} ${i} ${}";
//s2 evaluates to: A B C, Easy as 1 2 3
{
Map messages = new Map();
for(int num = 1; num <= 3; num++)
messages.put(num,"=is ${if(num == 2)}exactly${else}not${} two");
session.alert(messages); // Evaluates to: {1=is not two,2=is exactly two,3=is not two}
}
AMI Syntax for Embedding External Languages
Goals
- Allow users familiar with other languages to embed familiar code into existing data models.
- Enable users to take advantage of existing libraries found in other languages
Syntax
extern language {{
...
embedded_code_in_other_langauge
...
}};
Rules on Prefixing and terminating the custom code segment:
- The prefix must be at least 2 consecutive opening curly brackets ({).
- The termination must have the same number of closing curly brackets (}) as the prefix has.
- You can not include the suffix inside the embedded code. So for example, let's say you have a }} inside the embedded code, then you should wrap the embedded code in three curly brackets, ex: {{{custom_code_witha_double_curlys}}}
- The embedded code is evaluated literally, ex: all escapes, etc. are sent directly to the sub-language engine
Currently, python is supported out of the box.
Example
{
int n=5;
extern python {{
for i in xrange(2,5):
n=n*i;
}};
session.log(n);// will log 120
}
Formatting Timestamps
3forge provides two ways of handling timestamps when it comes to formatting:
- User Settings: If you like to maintain a unified date/time format across the dashboard, the formatting can be configured via user settings. Simply navigate to Account -> My Settings
- AMI Script Methods: If you like to have different formats in different places in the dashboard, AMI Script provides a handful of methods that can be utilized. To know more about their usage you can navigate to Help -> AMI Script Doc and the relevant methods will be available under AMI-Script Functions.
An example is provided below where an AMI Script Method has been used to format a table column.
Additionally, You can set the default timezone for all users by setting the property in local.properties:
ami.default.user.timezone=EST5EDT
AMI Reserved WORDS (alphabetical)
ADD ALTER ANALYZE AND AS ASC BEFORE BINARY BOOLEAN BREAK BY CALL CASE CATCH CREATE CONCURRENT CONTINUE DEFAULT DELETE DESC DESCRIBE DISABLE DO DOUBLE DROP ELSE ENABLE EXECUTE EXTERN FLOAT FOR FROM GROUP HAVING IF IN INDEX INSERT INT INTEGER INTO JOIN LEFT LIMIT LONG MODIFY NEAREST NEW OFTYPE ON ONLY OR ORDER PARTITION PREPARE PRIORITY PROCEDURE PUBLIC RENAME RETURN RIGHT SELECT SET SHOW STEP STRING SWITCH SYNC TABLE TABLES TIMER TRIGGER TO TRUNCATE UNION UNPACK UPDATE USE UTC UTCN VALUES WHERE WHILE WINDOW
Reserved words are case insensitive