CTL2 is a new version of CloudConnect transformation language. It adds many improvements to the CTL concept.
Table 59.1. CTL Version Comparison
Feature | CTL1 | CTL2 |
---|---|---|
Strongly typed | ||
Interpreted mode | ||
Compiled mode | ||
Speed | slower | faster |
CTL has been redesigned to be strongly typed in CTL2. With variable declarations already containing type information the introduction of type checking mostly affects container types and functions. In CTL2, container types (lists and maps) must declare the element type and user-defined functions must declare return type as well as types of their arguments.
Naturally, strict typing for functions requires introduction of void
type for
functions not returning any value. typing also introduces function
overloading in local code as well as in the built-in library.
CTL2 allows to declare variables and functions in any place of the code. Only one condition must be fulfilled - each variable and function must be declared before it is used.
CTL2 also allows to define mapping in any place of the transformation and be followed by other code.
Parts of CTL2 code may be interspersed almost arbitrarily.
CTL2 code can be transformed into pure Java which greatly increases speed of the transformation. This is called "compiled mode" and CloudConnect can do it for you transparently each time you run a graph with CTL2 code in it. The transformation into compiled form is done internally so you do not need to be Java programmer to use it.
Each time you use a component with CTL2 transform and explicitly set it to work in compiled mode, CloudConnect produces an in-memory Java code from your CTL and runs the Java natively - giving you a great speed increase.
A strict type checking is further extended to validation of lookup tables and sequences access. For lookup tables the actual arguments of lookup operation are validated against lookup table keys, while using the record returned by table in further type checked.
Sequences support three possible return
types explicitly set by user: integer
, long
, and string
.
In CTL1 records, lookup tables, and sequences were identified by their IDs -
in CTL2 they are defined by names. For this reason, names of these graph elements must always be unique in a graph.
In CTL2, any metadata is considered to be a data type. This changes the way records are declared in CTL transformation code, as sou can use your metadata names directly in your code to declare a variable:
Employee tmpEmployee; recordName1 myRecord;
The following table presents an overview of differences between both versions of CTL.
Table 59.2. CTL Version Differences
CTL1 | CTL2 |
---|---|
Header (interpreted mode) | |
//#TL | //#CTL2 |
//#CTL1 | |
Header (compiled mode) | |
unavailable | //#CTL2:COMPILED
|
Declaration of primitive variables | |
int | integer |
bytearray | byte |
Declaration of container variables | |
list myList; | <element type>[] myList; Example: |
map myMap; | map[<type of key>, <type of value>] myMap; Example: |
Declaration of records | |
record (<metadataID>) myRecord; | <metadataName> myRecord; |
Declaration of functions | |
function fName(arg1,arg2) { <functionBody> } | function <data type> fName(<type1> arg1,<type2> arg2) { <functionBody> } |
Mapping operator | |
$0.field1 := $0.field1; (please note ':=' vs '=' ) | $0.field1 = $0.field1; (please note ':=' vs '=' ) |
Accessing input records | |
@<port No> | unavailable, may be replaced with: |
$<port No>.* | |
@<metadata name> | unavailable, may be replaced with: |
$<metadata name>.* | |
Accessing field values | |
@<port No>[<field No>] | unavailable, may be replaced with: |
$<port No>.<field name> | |
@<metadata name>[<field No>] | unavailable, may be replaced with: |
$<metadata name>.<field name> | |
<record variable name>["<field name>"] | <record variable name>.<field name> |
Conditional fail expression (interpreted mode only) | |
$0.field1 := expr1 : expr2 : ... : exprN; | $0.field1 = expr1 : expr2 : ... : exprN; |
unavailable | myVar = expr1 : expr2 : ... : exprN; |
unavailable | myFunction(expr1 : expr2 : ... : exprN) |
Dictionary declaration | |
need not be defined | must always be defined |
Dictionary entry types | |
string, readable.channel, writable.channel | boolean, byte, date, decimal, integer, long, number, string, readable.channel, writable.channel, object |
Writing to dictionary | |
signature: | syntax: |
void write_dict(string name, string value) | dictionary.<entry name> = value; |
example 1: | example: |
write_dict("customer", "John Smith"); | dictionary.customer = "John Smith"; |
example 2: | |
string customer; write_dict(customer, "John Smith"); | |
signature: | |
boolean dict_put_str(string name, string value); | |
example 3: | |
dict_put_str("customer", "John Smith"); | |
example 4: | |
string customer; dict_put_str(customer, "John Smith"); | |
Reading from dictionary | |
signature: | syntax: |
string read_dict(string name) | value = dictionary.<entry name>; |
example 1: | example: |
string myString; myString = read_dict("customer"); | string myString; myString = dictionary.customer; |
example 2: | |
string myString; string customer; myString = read_dict(customer); | |
signature: | |
string dict_get_str(string name) | |
example 3: | |
string myString; myString = dict_get_str("customer"); | |
example 4: | |
string myString; string customer; dict_get_str(customer); | |
Lookup table functions | |
lookup_admin(<lookup ID>,init) 1) | unavailable |
lookup(<lookup ID>,keyValue) | lookup(<lookup name>).get(keyValue) |
lookup_next(<lookup ID>) | lookup(<lookup name>).next() |
lookup_found(<lookup ID>) | lookup(<lookup name>).count(keyValue) |
lookup_admin(<lookup ID>,free) 1) | unavailable |
Sequence functions | |
sequence(<sequence ID>).current | sequence(<sequence name>).current() |
sequence(<sequence ID>).next | sequence(<sequence name>).next() |
sequence(<sequence ID>).reset | sequence(<sequence name>).reset() |
Switch statement | |
switch (Expr) { case (Expr1) : { StatementA StatementB } case (Expr2) : { StatementC StatementD } [default : { StatementE StatementF }] } | switch (Expr) { case Const1 : StatementA StatementB break; case Const2 : StatementC StatementD break; [default : StatementE StatementF] } |
For loop | |
int myInt; for(Initialization;Condition,Iteration) (Initialization, Condition and Iteration are required) | for(integer myInt;Condition;Iteration) (Initialization, Condition and Iteration are optional) |
Foreach loop | |
int myInt; list myList; foreach(myInt : myList) Statement | integer[] myList; foreach(integer myInt : myList) Statement |
Error handling | |
string MyException; try Statement1 catch(MyException) [Statement2] | unavailable |
following set of optional functions can be used in both CTL1 and CTL2: | |
<required template function>OnError() (e.g. transformOnError() , etc.) | |
Jump statements | |
break | break; |
continue | continue; |
return Expression | return Expression; |
Contained-in operator | |
myVar .in. myContainer | in(myVar,myContainer) |
or | |
myVar.in(myContainer) | |
Eval functions | |
eval() | unavailable |
eval_exp() | unavailable |
Ternary operator | |
unavailable but iif(Condition,ExprIfTrue,ExprIfFalse)can be used instead | Condition ? ExprIfTrue : ExprIfFalse but iif(Condition,ExprIfTrue,ExprIfFalse)also exists |
Legend:
1) These functions do nothing since version 3.0 of CloudConnect and can be removed from the code.