summaryrefslogtreecommitdiff
path: root/support/arara/doc/chapters/mvel.tex
blob: 4ccca9b814ded3e76e440c591cd54ecea169980e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
% !TeX root = ../arara-manual.tex
\chapter{MVEL}
\label{chap:mvel}

According to the \href{https://en.wikipedia.org/wiki/MVEL}{Wikipedia entry}, the MVFLEX Expression Language (hereafter referred as MVEL) is a hybrid, dynamic, statically typed, embeddable expression language and runtime for the Java platform. Originally started as a utility language for an application framework, the project is now developed completely independently. \arara\ relies on this scripting language in two circumstances:

\begin{enumerate}
\item\emph{Rules}, as nominal attributes gathered from directives are used to build complex command invocations and additional computations. A rule follows a very strict model, detailed in Section~\ref{sec:rule}, on page~\pageref{sec:rule}.

\item\emph{Conditionals}, as logical expressions must be evaluated in order to decide whether and how a directive should be interpreted. Conditionals are detailed in Section~\ref{sec:directives}, on page~\pageref{sec:directives}.
\end{enumerate}

This chapter only covers the relevant parts of the MVEL language for a consistent use with \arara. For advanced topics, I highly recommend the official language guide for MVEL 2.0, available online.

\section{Basic usage}
\label{sec:mvelbasicusage}

The following primer is provided by the \href{https://mvel.documentnode.com/}{official language guide}, almost verbatim, with a few modifications to make it more adherent to our needs with \arara. Consider the following expression:

\begin{codebox}{Simple property expression}{teal}{\icnote}{white}
user.name
\end{codebox}

In this expression, we have a single identifier \rbox{user.name}, which by itself is a property expression, in that the only purpose of such an expression is to extract a property out of a variable or context object, namely \rbox{user}. Property expressions are widely used by \arara, as directive parameters are converted to a map inside the corresponding rule scope. For instance, a parameter \rbox{foo} in a directive will be mapped as \rbox{parameters.foo} inside a rule during interpretation. This topic is detailed in Section~\ref{sec:directives}, on page~\pageref{sec:directives}. The scripting language can also be used for evaluating a boolean expression:

\begin{codebox}{Boolean expression evaluation}{teal}{\icnote}{white}
user.name == 'John Doe'
\end{codebox}

This expression yields a boolean result, either \rbox{true} or \rbox{false} based on a comparison operation. Like a typical programming language, MVEL supports the full gamut of operator precedence rules, including the ability to use bracketing to control execution order:

\begin{codebox}{Execution order control through bracketing}{teal}{\icnote}{white}
(user.name == 'John Doe') && ((x * 2) - 1) > 20
\end{codebox}

You may write scripts with an arbitrary number of statements using a semicolon to denote the termination of a statement. This is required in all cases except in cases where there is only one statement, or for the last statement in a script:

\begin{codebox}{Multiple statements}{teal}{\icnote}{white}
statement1; statement2; statement3
\end{codebox}

It is important to observe that MVEL expressions use a \emph{last value out} principle. This means, that although MVEL supports the \rbox{return} keyword, it can be safely omitted. For example:

\begin{codebox}{Automatic return}{teal}{\icnote}{white}
foo = 10;
bar = (foo = foo * 2) + 10;
foo;
\end{codebox}

In this particular example, the expression automatically returns the value of \rbox{foo} as it is the last value of the expression. It is functionally identical to:

\begin{codebox}{Explicit return}{teal}{\icnote}{white}
foo = 10;
bar = (foo = foo * 2) + 10;
return foo;
\end{codebox}

Personally, I like to explicitly add a \rbox{return} statement, as it provides a visual indication of the expression exit point. All rules released with \arara\ favour this writing style. However, feel free to choose any writing style you want, as long as the resulting code is consistent.

The type coercion system of MVEL is applied in cases where two incomparable types are presented by attempting to coerce the right value to that of the type of the left value, and then vice-versa. For example:

\begin{codebox}{Type coercion}{teal}{\icnote}{white}
"123" == 123;
\end{codebox}

Surprisingly, the evaluation of such expression holds \rbox{true} in MVEL because the underlying type coercion system will coerce the untyped number \rbox{123} to a string \rbox{123} in order to perform the comparison.

\section{Inline lists, maps and arrays}
\label{sec:mvelinlinelistsmapsandarrays}

According to the documentation, MVEL allows you to express lists, maps and arrays using simple elegant syntax. Lists are expressed in the following format:

\begin{codebox}{Creating a list}{teal}{\icnote}{white}
[ "Jim", "Bob", "Smith" ]
\end{codebox}

Note that lists are denoted by comma-separated values delimited by square brackets. Similarly, maps (sets of key/value attributes) are expressed in the following format: 

\begin{codebox}{Creating a map}{teal}{\icnote}{white}
[ "Foo" : "Bar", "Bar" : "Foo" ]
\end{codebox}

Note that attributes are composed by a key, a colon and the corresponding value. A map is denoted by comma-separated attributes delimited  by square brackets. Finally, arrays are expressed in the following format:

\begin{codebox}{Creating an array}{teal}{\icnote}{white}
{ "Jim", "Bob", "Smith" }
\end{codebox}

One important aspect about inline arrays is their special ability to be coerced to other array types. When you declare an inline array, it is untyped at first and later coerced to the type needed in context. For instance, consider the following code, in which \rbox{sum} takes an array of integers:

\begin{codebox}{Array coercion}{teal}{\icnote}{white}
math.sum({ 1, 2, 3, 4 });
\end{codebox}

In this case, the scripting language will see that the target method accepts an integer array and automatically type the provided untyped array as such. This is an important feature exploited by \arara\ when calling methods within the rule or conditional scope.

\section{Property navigation}
\label{sec:propertynavigation}

MVEL provides a single, unified syntax for accessing properties, static fields, maps and other structures. Lists are accessed the same as arrays. For example, these two constructs are equivalent (MVEL and Java access styles for lists and arrays, respectively):

\begin{codebox}{MVEL access style for lists and arrays}{teal}{\icnote}{white}
user[5]
\end{codebox}

\begin{codebox}{Java access style for lists and arrays}{teal}{\icnote}{white}
user.get(5)
\end{codebox}

Observe that MVEL accepts plain Java methods as well. Maps are accessed in the same way as arrays except any object can be passed as the index value. For example, these two constructs are equivalent (MVEL and Java access styles for maps, respectively):

\begin{codebox}{MVEL access style for maps}{teal}{\icnote}{white}
user["foobar"]
user.foobar
\end{codebox}

\begin{codebox}{Java access style for maps}{teal}{\icnote}{white}
user.get("foobar")
\end{codebox}

It is advisable to favour such access styles over their Java counterparts when writing rules and conditionals for \arara. The clean syntax helps to ensure more readable code.

\section{Flow control}
\label{sec:mvelflowcontrol}

The expression language goes beyond simple evaluations. In fact, MVEL supports an assortment of control flow operators (namely, conditionals and repetitions) which allows advanced scripting operations. Consider this conditional statement:

\begin{codebox}{Conditional statement}{teal}{\icnote}{white}
if (var > 0) {
   r = "greater than zero";
}
else if (var == 0) { 
   r = "exactly zero";
}
else { 
   r = "less than zero";
}
\end{codebox}

As seen in the previous code, the syntax is very similar to the ones found in typical programming languages. MVEL also provides a shorter version, known as a ternary statement:

\begin{codebox}{Ternary statement}{teal}{\icnote}{white}
answer == true ? "yes" : "no";
\end{codebox}

The \rbox{foreach} statement accepts two parameters separated by a colon, the first being the local variable holding the current element, and the second the collection or array to be iterated over. For example:

\begin{codebox}{Iteration statement}{teal}{\icnote}{white}
foreach (name : people) {
    System.out.println(name);
}
\end{codebox}

As expected, MVEL also implements the standard C \rbox{for} loop. Observe that newer versions of MVEL allow an abbreviation of \rbox{foreach} to the usual \rbox{for} statement, as syntactic sugar. In order to explicitly indicate a collection iteration, we usually use \rbox{foreach} in the default rules for \arara, but both statements behave exactly the same from a semantic point of view. 

\begin{codebox}{Iteration statement}{teal}{\icnote}{white}
for (int i = 0; i < 100; i++) { 
   System.out.println(i);
}
\end{codebox}

The scripting language also provides two versions of the \rbox{do} statement: one with \rbox{while} and one with \rbox{until} (the latter being the exact inverse of the former):

\begin{codebox}{Iteration statement}{teal}{\icnote}{white}
do {
    x = something();
} while (x != null);
\end{codebox}

\begin{codebox}{Iteration statement}{teal}{\icnote}{white}
do {
   x = something();
} until (x == null);
\end{codebox}

Finally, MVEL also implements the standard \rbox{while}, with the significant addition of an \rbox{until} counterpart (for inverted logic):

\begin{codebox}{Iteration statement}{teal}{\icnote}{white}
while (isTrue()) {
   doSomething();
}
\end{codebox}

\begin{codebox}{Iteration statement}{teal}{\icnote}{white}
until (isFalse()) {
   doSomething();
}
\end{codebox}

Since \rbox{while} and \rbox{until} are unbounded (i.e, the number of iterations required to solve a problem may be unpredictable), we usually tend to avoid using such statements when writing rules for \arara.

\section{Projections and folds}
\label{sec:mvelprojectionsandfolds}

Projections are a way of representing collections. According to the official documentation, using a very simple syntax, one can inspect very complex object models inside collections in MVEL using the \rbox{in} operator. For example:

\begin{codebox}{Projection and fold}{teal}{\icnote}{white}
names = (user.name in users);
\end{codebox}

As seen in the above code, \rbox{names} holds all values from the \rbox{name} property of each element, represented locally by a placeholder \rbox{user}, from the collection \rbox{users} being inspected. This feature can even perform nested operations.

\section{Assignments}
\label{sec:mvelassignments}

According to the official documentation, the scripting language allows variable assignment in expressions, either for extraction from the runtime, or for use inside the expression. As MVEL is a dynamically typed language, there is no need to specify a type in order to declare a new variable. However, feel free to explicitly declare the type when desired.

\begin{codebox}{Assignment}{teal}{\icnote}{white}
str = "My string";
String str = "My string";
\end{codebox}

Unlike Java, however, the scripting language provides automatic type conversion (when possible) when assigning a value to a typed variable. In the following example, an integer value is assigned to a string:

\begin{codebox}{Assignment}{teal}{\icnote}{white}
String num = 1;
\end{codebox}

For dynamically typed variables, in order to perform a type conversion, it is just a matter of explicitly casting the value to the desired type. In the following example, an explicit string cast is assigned to the \rbox{num} variable:

\begin{codebox}{Assignment}{teal}{\icnote}{white}
num = (String) 1;
\end{codebox}

When writing rules for \arara, is advisable to keep variables to a minimum in order to avoid unnecessary assignments and a potential performance drop. However, make sure to favour readability over unmaintained code.

\section{Basic templating}
\label{sec:mvelbasictemplating}

MVEL templates are comprised of \emph{orb} tags inside a plain text document. Orb tags denote dynamic elements of the template which the engine will evaluate at runtime. \arara\ heavily relies on this concept for runtime evaluation of conditionals and rules. For rules, we use orb tags to return either a string from a textual template or a proper command object. The former constituted the basis of command generation in previous versions of our tool; we highly recommend the latter, detailed in Section~\ref{sec:rule}, on page~\ref{sec:rule}. Conditionals are in fact orb tags in disguise, such that the expression (or a sequence of expressions) is properly evaluated at runtime. Consider the following example:

\begin{codebox}{Template}{teal}{\icnote}{white}
My favourite team is @{ person.name == 'Enrico'
? 'Juventus' : 'Palmeiras' }!
\end{codebox}

The above code features a basic form of orb tag named \emph{expression orb}. It contains an expression (or a sequence of expressions) which will be evaluated to a certain value, as seen earlier on, when discussing the \emph{last value out} principle. In the example, the value to be returned will be a string containing a football team name (the result is of course based on the comparison outcome).

\section{Further reading}
\label{sec:mvelfurtherreading}

This chapter does not cover all features of the MVEL expression language, so further reading is advisable. I highly recommend the \href{http://mvel.documentnode.com/}{MVEL language guide} currently covering version 2.0 of the language.