This topic describes the features and syntax of the StreamBase expression language. You can use StreamBase expressions in the Properties view of most EventFlow operators and as part of queries in the LiveView query language.
StreamBase provides two types of built-in functions in the expression language:
- Simple Functions
-
Simple functions operate on a single tuple field at a time. Most functions in the StreamBase expression language are simple functions. You can use simple functions in expressions for any StreamBase operator (except the Heartbeat, Metronome, and Union operators, which do not accept expressions). All infix operators (
+
,-
,*
,/
,%
,&&
,||
) are simple functions. - Aggregate Functions
-
Aggregate functions are used on sets of data to return a single result. Aggregate functions evaluate columns of data from windows or tables. In EventFlow applications, aggregate functions can only be used:
-
In aggregate expressions in Aggregate operators
-
In output expressions in Query Operators that perform Read or Delete operations
-
In the Iterate Condition field for Iterate operators
-
For a complete, categorized list of StreamBase functions and their syntaxes, see StreamBase Expression Language Functions.
StreamBase provides sample applications that feature custom functions for you to load into StreamBase Studio to see how they are built and configured. The custom sample applications are listed in Extending StreamBase Samples.
StreamBase Studio provides the following user assistance features to aid in writing expressions:
- Expression Evaluator Dialog
-
The Evaluate StreamBase Expression dialog allows you experiment with long or complex StreamBase expression syntax without having to run an EventFlow fragment with Map operator to see the results. The Evaluator performs the same syntax tests as the StreamBase Runtime and returns instantaneous validation results.
The dialog is especially useful when defining custom expression language functions, because it allows you to append parenthesized arguments to your proposed function to return an evaluation of your function on those arguments.
This feature is available starting with TIBCO® Data Streams 10.5.0, and replaces the
sbd --eval
functionality of the StreamBase 7 series.
The following features are described in more depth on the Properties View page.
- Expression Auto-Completion
-
When the cursor is in a field in the Properties view that accepts expressions, press Ctrl+Space to open a command-completion dialog. Type a few letters to show the expression language functions that begin with those letters. Select a function to see its syntax and description in a separate pane. Press Enter to finish typing from the selected function. See Expression Auto-Completion and Content Assistance for more on auto-completion.
- Functions Tab in the Properties View
-
The Functions tab shows a categorized list of all expression language functions. Type a regular expression in the filter box to narrow the selection to matching functions. Double-click a function name to see its syntax and description in the Detail sub-tab.
- Expression QuickRef Tab in the Properties View
-
The Expression QuickRef tab shows a summary of the features of the expression language. Click a Show in Help link to open the corresponding section of this page in the Help window.
You can define custom expression language functions using a constructor for the
function
data type, as described in Using the Function Data Type.
Expression language custom functions generally combine built-in expression language functions and math operators. If you need to call Java classes in a custom function, create a custom Java function as described next.
Certain built-in functions called higher-order functions take user-defined functions
as arguments. These include list manipulation functions such as filterlist
and maplist
. See Functions That Require Function Arguments.
You can use the custom function APIs in the StreamBase Java Client API to implement your own functions. For details on writing your own functions, see these topics in the API Guide:
You can call your custom functions in expressions by means of the calljava() function, or by defining and calling a function alias you have declared in a configuration file.
You define aliases for your custom functions using the streambase > pluginFunctions > java object of a configuration
file of type com.tibco.ep.streambase.configuration.sbengine
.
Expressions often need quotes around string values to designate those values as strings. The StreamBase expression language is agnostic about whether to use double or single quotes in expressions. For example, StreamBase interprets the following expressions identically when used in an expression in an operator or adapter in StreamBase Studio:
strftime("Traded on %b %d, %Y at %H:%M", now()) strftime('Traded on %b %d, %Y at %H:%M', now())
The only rule is that you must escape any instance of the same quote mark if you need to use it again inside a pair of quote marks. You can escape a quote mark with a preceding backslash, or you can surround it with the opposite quote mark. For example, StreamBase interprets the following lines identically in Studio:
strftime('Traded at Miller\'s Crossing on %b %d, %Y at %H:%M', now()) strftime("Traded at Miller's Crossing on %b %d, %Y at %H:%M", now())
Expressions use the StreamBase static data types:
blob | list |
bool | long |
capture | string |
double | timestamp |
function | tuple |
int |
In addition, the name of any named schema serves as a constructor for a data type of that name.
These data types are described in more detail in StreamBase Data Types.
To recast data types, use one of the StreamBase type conversion
functions. For example, to cast a value to a double in an expression, use the
double()
function. To cast a value to a string, use the
string()
function, and so on.
Casting may not be necessary if type coercion is supported for the data types, as described in the next section.
Data type coercion is the implicit conversion of a value
from one data type to another. For example, the +
(concatenation) string operator performs coercion from numeric and boolean values to
strings, as in:
"This is " + (2 > 1) => (string) “This is true” "1" + 2 + 3 => (string) "123"
Evaluation proceeds from left to right, so that order matters:
1 + 2 + "3" => (string) "33"
Arithmetic operators coerce values when evaluating expressions with mixed numeric data types, as in:
1 + 2L + 3.0 => (double) 6.0
StreamBase math functions that take arguments and return doubles accept int, long or
double input arguments. For example, the sqrt()
function accepts one int, long, or double input and
returns a double result (or NaN).
The following are the supported data type coercions and conversions:
Input data type | Converts to |
---|---|
int | long (concatenates to string) |
int | double (concatenates to string) |
long | double (concatenates to string) |
list(int) | list(long) |
list(int) | list(double) |
list(long) | list(double) |
list(tuple) merging with different list(tuple) | list(tuple), if a valid supertype of the two tuple schemas can be found |
sub-tuple field with unmatched schema | sub-tuple field with unioned schema |
string (numerals only) | int, long, double (via int(), long(), double()) |
The following rules apply to data type coercions:
-
For long-to-double coercion where the precision of the long cannot be preserved in the double, Java rounding rules apply.
-
When entering data to a stream whose schema contains a field of type tuple, StreamBase attempts to coerce the data into the sub-tuple fields using the same rules as for a loose union in the Union operator.
-
Coercion rules do not apply to output streams with declared, explicit schemas.
Expressions are case sensitive. Function names are usually all lowercase, with a few exceptions. If you add custom functions, follow the lowercase convention.
StreamBase identifier naming rules apply to the name you assign to any StreamBase component, including schemas, fields, operators, tables, modules, containers, data source names, custom function names, and custom function aliases. Specifically, identifiers you create should:
-
Begin with an alphabetic character or an underscore.
-
Contain only alphabetic characters, numbers, and underscores.
-
Not contain hyphens, colons or other non-alphanumeric characters.
Note
StreamBase may create internal identifiers that include colons, but you cannot use colons in your identifiers unless you escape them as described in the next section.
For clarity in your application modules and to make debugging easier, follow the rules below when choosing names for your StreamBase components. Wherever possible, these rules are enforced by typechecking in StreamBase Studio.
-
Do not use the name of a StreamBase data type, EventFlow reserved word, or LiveView reserved word to name your stream fields or other components.
-
Do not name a stream field the same as any dynamic variable or constant defined in the same module. StreamBase resolves unqualified names first against the names of dynamic variables and constants, and then against the names of fields in currently available streams. See Qualifying Field Names for more information.
-
For code clarity, avoid naming a stream field the same as any StreamBase expression language function, or the same as any custom function you have configured for use in the same application, or the same as any alias you have assigned to a custom function. You can refer to the alphabetic listing of expression language function names.
-
Do not name a field the same as any named schema.
Identifier names can include Unicode characters as long as Unicode support is enabled for both Studio and Server, as described in Unicode Support.
StreamBase supports an escaped identifier syntax to enable the use of arbitrary naming conventions for fields and identifiers. When you provide a name for a component of a StreamBase expression that violates the rules described in the previous section, StreamBase Studio automatically stores the name as an escaped identifier, which wraps the invalid identifier in a syntax that enables its use.
However, Studio does not automatically rename fields that violate the naming rules; you must explicitly enter escaped identifier syntax for the name of any field that would otherwise cause Studio to report an error.
The escaped identifier syntax is #"
— a pound or hash symbol,
followed by the otherwise-violating identifier you want to use within double quotes.
Escaped identifiers work throughout StreamBase for the names of all components and
fields.
name
"
You can use this syntax to name a field the same as a StreamBase reserved word, such
as #"AS"
.
When you name fields and expression components, do not use the following words, which are reserved for use in the expression language:
and | else | null |
as | false | or |
between | function | then |
cacheable | if | true |
define | not |
LiveView fragments have an additional list of reserved words described in LiveView Reserved Words.
In EventFlow modules, StreamBase Studio does not prevent you from naming a field with a reserved word in an input stream's Properties view. However, a schema that contains a reserved word causes one or more typecheck errors in downstream components. The error message in the Typecheck view identifies the offending field's name. To correct the typecheck error, rename the field in the input stream's Properties view.
Although the names of StreamBase data types are not reserved words, It is a best practice that you do not use data type names as field names, for clarity when developing and debugging your applications. The data type names are listed in Data Types.
If a name conflict occurs when referencing a field name used in an expression in an operator, you can qualify the name to clarify the inbound stream you mean.
For example, in the Properties view for a Gather operator, you can qualify the fields
as input[port-number].field-name
.
Example: input1.is_alarm, input2.is_alarm,
input3.is_alarm
.
In the Properties view for a Join operator, you can qualify the fields in the two
input streams as input1.field-name
and
input2.field-name
. The input1.field-name
refers to a field in the stream
arriving at the top port (#1). The input2.field-name
refers to a field in the stream
arriving at the bottom port (#2).
Examples:
input1.SKU input2.SKU
In the Properties view for a Query operator, you can qualify the fields in the two
input streams as input.field-name
and
old.field-name
. The input.field-name
refers to the current input tuple,
while old.field-name
refers to the field's
prior value.
Examples:
input.Symbol old.Symbol
Important
In any expression anywhere in StreamBase, unqualified names are resolved first
against the names of any dynamic variables and constants defined in the current
module, and then against the names of fields in currently available streams. This
means that a dynamic variable or constant named foo
can mask a field also named foo
, depending on the
context.
One consequence of this rule: If you use the same name for a dynamic variable and
for its updating expression field, StreamBase Studio issues a typecheck warning. To
distinguish a dynamic variable from the same-named field in the updating stream,
qualify the field name with input.
, or just rename the field.
fieldname
You can use +, –, *, /,
and %
. The ^
expression is not supported.
The following example shows the arithmetic operators in use. (This expression is shown on two lines for clarity.):
((((sector_in_fund_value_t + (shares_traded * price_at_trade)) * 100) / fund_value_t) > 25)
This expression is designed to run the 25% sector test, where one sector is not
allowed to be more than 25% of the total fund value. is_alarm
is set to true
if the test
fails.
You can also use the +
operator to concatenate strings;
see Concatenation in Expressions for details.
You can also use the *
operator to repeat a string
multiple times; see String Repetition for details.
The modulus operator (%) finds the remainder of a division operation. Division and
modulus are always related such that a/b*b+(a%b) ==
a
, where a/b
is an integer
division. For example, 15%4
can be resolved as follows:
as:
15 / 4 * 4 + MOD == 15 3 * 4 + MOD = 15 12 + MOD = 15 MOD = 3
This relationship is preserved with negative divisors. As a result, whenever the quotient is negative, the modulus is negative. For example:
15 % 4 = 3 15 % -4 = 3 -15 % 4 = -3 -15% -4 = -3
Also note that if you divide a smaller number by a larger number, the modulus is always the smaller number. For example:
4 % 15 = 4
This behavior may be different than modulus operators in some programming languages.
Use the between-and operator in expressions using the following syntax:
test-expr
betweenexpr1
andexpr2
where expr1
and expr2
resolve to instances of the same data type to
which test-expr
resolves. That is, the data
type of test-
expr, expr1
, and expr2
must be the same, or must be coercibly the
same, using the rules described in Data Type Coercion.
This construction returns Boolean true or false, and is thus ideally suited for use
in an if-then-else
construction:
iftest-value
betweenboundary1
andboundary2
thenexpr-if-true
elseexpr-if-false
For example, using the current value of fieldname
in the incoming tuple:
if fieldname
between 100 and 200 then true else false
The between-and operator can be negated with the ! or NOT operator:
if fieldname
not between 100 and 200 then true else false
The between-and operator is inclusive, which means if test-value
exactly matches either boundary1
or boundary2
, the operator returns true. Use this
operator as a more readable version of the following equivalent expression. Using
between-and has the advantage of only specifying test-value
once.
if (test-value
>=boundary1
andtest-value
<=boundary2
) thenexpr-if-true
elseexpr-if-false
The between-and operator works with any StreamBase data type, including list and tuple, using the relational comparison algorithms described for each operator on StreamBase Data Types.
Use the infix operator IN to test for list or string containment, returning Boolean
true or false. For example, the following expressions each return true
:
2 in [1, 2, 3] 2 in list(1, 2, 3)
For strings, IN returns true
if the string on the left
is a substring of the string on the right. For example,
'foo' in 'there is food here'
returns true
. However, if the right side argument is a
list of strings, a list element must exactly match the left side argument. For
example:
'foo' in ['there','is','food','here']
returns false
.
The IN operator is syntactic sugar for the contains() function.
Notice that IN is not among the reserved words for the expression language, and the string IN can still be used as an identifier in other contexts. The IN operator only becomes an operator in the context of a list containment expression as shown above, with the test value on its left and the queried list on its right. The queried list can be expressed in simple bracket format, or can be any function or expression that resolves to a list, including the list() and range() functions.
Unary operators act on only one operand in an expression. –a
is valid for integer, double, and long types.
!a
or NOT a
is valid for the bool type. +a
is not supported.
You can use the following relational operators: <
,
<=
, =
, ==
, >
, >=
, !=
The relational operator <>
is not supported.
StreamBase data types are comparable with relational operators in different ways, as listed in the entry for each data type on StreamBase Data Types.
You can use the following logical operators: &&
,
AND
, ||
, OR
, !
, NOT
.
Logical Operator | Meaning |
---|---|
&& or AND
|
Logical AND |
|| or OR
|
Logical OR |
! or NOT
|
NOT: negates its operand |
Note
The evaluation of expressions using && and || will short-circuit. This means that after StreamBase encounters the first term that evaluates as false, no other terms in a statement using && are evaluated. Similarly, evaluation of a statement using || stops after the first true term.
For related information on Boolean logic and nulls, see Using Nulls.
You can apply operators and functions to all fields in a tuple, using wildcards
(*
) in EventFlow expressions. The resulting values can
replace the current field values, be assigned as new fields, or evaluated as a
collection as arguments to EventFlow or custom functions, according on the syntax you
use to expand values.
You can use wildcards to produce lists of expressions when passing arguments to
functions. A simple wildcard expression such as input.*
replaces input field values with evaluation results. To assign the results to fields
at a lower level, use the AS
keyword. The following
table illustrates several syntaxes that illustrate the effect of using AS
in wildcard expansions.
Wildcard Expression | Expansion | Remarks |
---|---|---|
f(g(input.*))
|
f(g(input.x)), f(g(input.y)), f(g(input.z))
|
Replaces top-level fields |
f(g(input.* AS *))
|
f(g(input.x, input.y, input.z)))
|
Replaces top-level fields |
f(g(input.*) AS *)
|
f(g(input.x) as x, g(input.y) as y, g(input.z) as
z)
|
Creates lower-level fields with the same names |
Expressions such as (input.x AS *)
are not
legal. You must specify field names with wildcards when using AS *
.
For example, to determine whether all fields in a tuple are null, you could use the following expression:
andall(isnull(input.*) AS *)
The isnull
function is applied to all input fields, the
results are collected into boolean fields with the same names, and the resulting list
is evaluated by andall
, which only returns true if
every field is null. In this example, the fields do not have to be of the same type.
The precedence of mathematical operators in expressions, from highest to lowest, is as follows:
-
Unary operators:
!
,NOT
, and–
The logical negation operator,
!
orNOT
, reverses the meaning of its operand.The unary negation operator,
–
, produces the negative of its operand. -
Multiplicative operators:
*
and/
and%
Multiplication:
*
Division:
/
Modulus, the remainder from division:
%
-
Additive operators:
+
and–
Addition:
+
Subtraction:
–
-
Relational operators:
<
and<=
and>
and>=
Less than:
<
Less than or equal to:
<=
Greater than:
>
Greater than or equal to:
>=
-
Equality operator:
==
or=
-
Not equal:
!=
orNOT =
-
Logical AND:
&&
orAND
-
Logical OR:
||
orOR
-
The
if-then-else
construction -
The IN operator
For example, the expression "2 in if 2 > 1 then [1,3,4] else
[2,6,7]"
returns false
because the >
operator and the if-then-else
conditional expression are evaluated first.
You can use parentheses in expressions to override the default precedence.
You can add comments to your expressions using either C-style comments or legacy StreamBase comments:
-
StreamBase legacy comments begin with two hyphens and extend to the end of the same line.
-
C-style comments begin with slash-asterisk and end with asterisk-slash. You can insert C-style comments anywhere in the expression, including the middle of a line, and they can extend over multiple lines.
The following sample expression illustrates several uses of comments:
/* handle special APPL case */ if (input1.symbol=="APPL.N") then input2.symbol == "APPL" /* handle special IBM case */ else if (input1.symbol=="IBM.L") then input2.symbol == "IBM" else input2.symbol == input1.symbol -- accept the rest as given
This section describes how to specify literals in expressions, for each data type. (For information about the data types themselves, see StreamBase Data Types.)
- blob
-
Use the StreamBase blob() function, which converts a string to a blob.
Example:
blob("abcde")
creates a blob containing the bytes representing the string"abcde"
.You can use tobson() to convert strings of text, other literals, or any StreamBase value to a BSON blob. To convert a BSON blob containing a string back to a string literal, use the stringbson() function.
- bool
-
Use the literals
true
andfalse
. - int
-
Enter a number that is in the range of the int data type. Decimal, binary, octal and hex encodings are supported. Examples:
0
and31337
are both intsPrefix non-decimal integers with 0 (zero):
-
Binary:
0b11011
and0B11011
are interpreted as binary (decimal27
) -
Hexadecimal:
0x7F8
and0X7F8
are interpreted as hexadecimal (decimal2040
)
To represent a numeric literal as a long data type, terminate it with letter
l
(orL)
. -
- double
-
Enter a number using a decimal point, or using scientific notation. Use a
D
ord
suffix to avoid ambiguity.Examples:
10.0
and1e1
are both doubles, as are13.85d
and128D
- long
-
Enter a number that is in the range of the long data type, appending the letter
l
orL
to the number. The number can be formatted as decimal, binary, or hexadecimal.Examples:
100L
and3147483650L
are both longs, as are0B10110L
,0456L
, and0XA5B6L
.Note
If the L is omitted, StreamBase interprets your number as an int no matter how large the value is.
- list
-
Enter comma-separated values, surrounded by square brackets.
Examples:
[23, 46, 889]
is a list of three ints.
is a list of three strings.["IBM", "AAPL", "ORCL"]
- string
-
You can use single quotes (
'string'
) or double quotes ("string"
) around strings. Escape characters are supported, as follows:Character Results in \" Double quotation mark \' Single quotation mark \n Newline \t Tab \b Backspace \r Carriage return \f Form feed \\ Backslash \u NNNN
Unicode character with hex code point NNNN
Examples:
String Literal Results in "He said, \"Hello.\"" He said, "Hello." 'She said, \'Hello.\' ' She said, 'Hello.' "A\tB" A<tab>B "A\nB" A<newline>B "C:\\WINDOWS" C:\WINDOWS "Copyright \u00A9 2050" Copyright © 2050 - timestamp
-
You can use timestamp literals only in comparison expressions that use the operators
==
,!=
,<=
,>=
,<
, or>
, when one side of the comparison is a timestamp and the other side is a string literal that can be interpreted as a valid timestamp. Otherwise, you cannot enter timestamp literals directly in expressions. See timestamp in the StreamBase Data Types documentation.In cases other than the one just described, to use timestamps in expressions, convert a string in a particular format to a timestamp using a function such as the StreamBase timestamp() function. The string argument must be in the form of a time format pattern as defined in the
java.text.SimpleDateFormat
class described in the Oracle Java Platform SE reference documentation. See timestamp() for examples.Also see the format_time(), parse_time() and format() functions. The maximum precision for timestamps is milliseconds.
- tuple
-
In expressions, define a single tuple using this syntax:
tuple (
value
ASfieldname
[,...]) [AStuplename
]The tuple schema, delimited by parentheses, consists of one or more field specifications separated by commas. Each field name resolves to an instance of a StreamBase data type (including another tuple). The last field name can be followed by a comma, which StreamBase ignores.
Use the AS keyword to specify field names in the result. Omit the outermost
AS
in EventFlow expressions, where the tuple field's name is specified in StreamBase Studio.tuplename
To cast a set of values as a tuple that conforms to an existing named schema, use the tuple() function.
You can use nulls in the StreamBase expression language, one for each of the simple data types:
blob(null) bool(null) double(null) int(null) long(null) string(null) timestamp(null)
The data type of a null is never implicit. You must specify the data type of any null you are using in the expression.
In general, when you apply any arithmetic operator or function with data-type
(null) as one of the arguments, the result
is null. Three exceptions are the isnull()
and
notnull()
functions, which test whether an expression
evaluates to null, and the coalesce()
and coalesce_tuples()
functions, which select a non-null value from a
set of potentially null arguments.
Expression Example | Result |
---|---|
3 + int(null) | A null int |
int(null) + int(null) | A null int |
int(null) + bool(null) | A typecheck error. You cannot add an int and a bool. |
if bool(null) then 3 else 4 | A null int |
int(null) == int(null) | A null bool, because null is not equal to itself |
int(null) != int(null) | A null bool, because null is not equal to itself |
isnull(int(null)) | A bool that evaluates to true |
notnull(int(null)) | A bool that evaluates to false |
To specify a null list, use the nulllist()
function. See Null Lists for a discussion
of null lists compared to empty lists.
To specify a null tuple that uses a named schema, specify the name of the schema with empty parentheses. For
example, for the schema named nyse_data
, the expression
nyse_data()
creates a null tuple. See Null Tuples for a discussion
of null tuples compared to empty tuples.
For more detailed information, see Using Nulls.
In an expression such as: if p then e1 else
e2
, p
must be a valid boolean expression,
and both e1
and e2
must be
expressions that have the same type. If p is true, then e1 is evaluated and the
result returned. If p
is false, e2
is evaluated and the result returned. In either case, the other
sub-expression is not evaluated.
Note
In the StreamBase expression language, each if
clause
must have a pair of explicit
then
and else
clauses.
Should you create compound if
clauses, to avoid
ambiguity, remember to specify the then
and
else
clauses for each if
clause. For an example, see the next section.
You can use combinations of if-then
and else-if-then
statements to form compound conditional expressions.
For example:
if i==0 then "Buy" else if i==1 then "Sell" else if
i==2 then "Hold" else "None of the above"
Here is a second example, indented for clarity, where we nest an if then else
in a then
clause:
if p1 then if p2 then A else B else if p3 then C else D
Notice how each if
clause contains a then
clause and an else
clause.
You can enter an expression that concatenates a string with any StreamBase data type. For any such concatenation, a string must be the first value. For two string variables, the concatenation expression is:
stringvar1
+
stringvar2
For a numeric type with a static string, the concatenation expression is:
"staticstring
" +
number
For example:
"square root of 16 = " + sqrt(16)
displays as
square root of 16 = 4
For a string and a numeric variable, the concatenation expression is:
stringvar
+
numvar
For example, where month
= "September" and day
= 16:
month + day
displays as
September 16
Use the *
operator to repeat a string n
times, using the syntax:
"staticstring" * n
where n
is a positive integer or an
expression that evaluates to one. For example:
"abc." * 3 -> abc.abc.abc.
The *
operator simplifies creating fixed-length fields.
For example, if a string field needs to be 32 characters long, use an expression like
the following to pad its contents with blanks:
stringvar
+ ' ' * (32-length(stringvar
))
This use of the *
operator is also known as string multiplication.
When used with comparison operators ( == != > < <= >= ) you must compare time fields interval-to-interval, or timestamp-to-timestamp. You cannot use the comparison operators to forma an interval-to-timestamp comparison.
To express constant intervals, you can use the seconds()
and minutes()
functions.
For example, if you want to add 60 seconds to a timestamp, enter expressions such as:
t + seconds(60) t + minutes(1)
For more on comparing timestamp expressions, see timestamp Data Type.
You can declare operator parameters in configuration files, and can define module parameters in configuration files and in the Parameters tab of the EventFlow Editor. You can reference either parameter type in StreamBase expressions. See Constants, Variables, and Parameters for more on the difference between global and module parameters.
To reference a parameter in an expression, wrap the parameter name in braces and
prefix the open brace with a dollar sign: ${parameter}
. If you are referencing a parameter
that is defined as a string, use quotes around the entire reference: "${parameter}"
.
See StreamBase Engine Configuration to understand the difference between operator (global) parameters and module parameters.