Table of Contents
List of Tables
Table of Contents
Forms are used to display and edit the data of underlying work objects. The work object data and the form definition are fetched from the server, and the expressions used within the form definition are then used to link the form fields with corresponding data. For editable fields, any changes made are reflected in the underlying work object data, which is sent back to the server to be persisted when the form is submitted:
Form data binding expressions are placed between two sets of curly braces, e.g.{{expression}}
,
and are set into a form component's
Value
property:
The
Value
property of a form component may only be bound to a single expression,
and this may not be preceded or followed by other text.
The only exception to this rule is the output component, which doesn't display and edit a single value, but uses form expressions embedded within a rich text template to create textual output dynamically.
A simple value name in double curly braces (e.g.{{value}}
)
is used to link to the corresponding variable in the current work object. If the
work object variable doesn't exist when the form is opened then it will be created
automatically.
A work object in edoras one is typically part of a hierarchy, where work objects are linked together in a tree of parent/child relationships. For example a case typically serves as a container for other work objects (tasks, running processes, documents etc.). Form binding expressions can also be used to access the values from related work objects in the work object hierarchy. This is done be preceding the variable to be accessed by a qualifier:
{{parent.value}}
binds to the corresponding value in the current work object's parent.
{{root.value}}
binds to the corresponding value in the work object that is at the root of the current work object's hierarchy. The root is determined by following the parent references until a work object is found that has no parent.
As an example, if we start a process within a case then the process's parent work object will be the case. A form task created by that process will have the process work object as its parent:
In this case
{{root.name}}
will bind to"Example case"
,
{{parent.name}}
will bind to
"Example process"
and
{{name}}
will bind to"Example task"
.
Bindings can be created for new variables as required, but a number of predefined bindings are used to access common work object attributes:
Table 1.1. Standard form bindings
Binding | Editable | Form Component | Binds to |
---|---|---|---|
{{name}}
| Yes | Text | the work object's name |
{{description}}
| Yes | Text | the work object's description |
{{state}}
| No | Text | the work object's state |
{{type}}
| No | Text | the work object's type |
{{ownerId}}
| Yes | User selection | the work object's owner |
{{assigneeId}}
| Yes | User selection | the work object's assignee |
{{candidateGroupIds}}
| Yes | Share with groups selection | the work object's candidate groups |
{{creationTime}}
| No | Date | the work object's creation time |
{{updateTime}}
| No | Date | the work object's last update time |
{{dueTime}}
| Yes | Date | the work object's last due time |
{{resubmissionTime}}
| Yes | Date | the work object's last resubmission time |
Table of Contents
Expressions can also be used within the process models to access data from the work object hierarchy and interact with other system components. In contrast to the form binding expressions, process model expressions can be more complex and have side-effects within the system (for example causing an e-mail to be sent). Whereas form expressions serve simply to link a particular data item with a form component (which then takes over the responsibility of interacting with the data), process expressions allow data object hierarchies to be traversed and method calls to be made.
The full expression language is part of the EE6 specification and only an brief overview will be provided here. For a full description of the expression language syntax please refer to the EE6 specification.
There are two basic expression types:
value expressions
have the form
#{value.property}
and resolve to a value
method expressions
have the form
#{bean.method(value)}
and result in a method invocation
One other difference between the form bindings and process expressions is that the work objects used by a form binding may have been pre-processed by the server so that the property values are in a form that makes more sense in the client's context. With process expressions this processing is not performed so you will be working with raw work objects.
As an example, state is represented in a work object by an instance of the
State
class. In a form binding, the
{{state}}
expression will be bound to
the
name
field of this object (e.g."ACTIVE"
). The conversion from
State
instance to the state name string has already been performed by the server.
The corresponding process binding,
#{state}
resolves to the underlying State object,
which if it is used in a string context will be converted to a string literal, e.g.
[State@51d838d9 name = 'ACTIVE']
. To access the plain string value
("ACTIVE"
) we can use the java bean property convention to get the name:
#{state.name}
.
The same binding values that are used in forms (seeTable 1.1, “Standard form bindings”) can also be used in process model expressions, although in some cases the expression results will have a different type than the corresponding form binding (see the state example above for an explanation).
The
parent
and
root
qualifiers are supported by process expressions, and
there is also a
self
qualifier that refers to the current work object.
self
is the default qualifier, and so it's rarely needed.
Work objects are referenced using IDs, and is often necessary to access not the ID itself but the
referenced work object. To support this use case, an expression that resolves to a work object ID
will automatically be converted to the corresponding work object instance if is followed by another expression.
For example the expression
#{ownerId.name}
will extract the owner ID value, look up the
corresponding work object (the user definition) and then access the
name
property of that
work object.
As access to the user data for a work object is so common there are also some shortcut expressions to access this information directly:
Table 2.1. Work object user expressions
Expression | Return type | Description |
---|---|---|
owner
| User work object | the work object's owner (corresponding toownerId.value )
|
assignee
| User work object | the work object's assignee (corresponding toassigneeId.value )
|
The previous section showed how we can gain access to the user information relating to a work object.
Once we have accessed the user work object there are a number of useful user properties that can be
accessed (e.g. as#{owner.name}
:
Table 2.2. User properties
Property | Return type | Description |
---|---|---|
userLogin
| String | the user's login name (email address) |
name
| String | the user's display name |
userFirstName
| String | the user's first name |
userName
| String | the user's surname |
userAddress
| String | the user's address |
userPhone
| String | the user's telephone number |
userMobile
| String | the user's mobile telephone number |
language
| String | the user's language |
Another difference between form binding expressions and process binding expressions is the
visibility of work object variables within the work object hierarchy. With form binding expressions,
accessing parent or root variables requires explicit use of the appropriate
parent
or
root
qualifier. With process expressions, however, this is not always required.
With a process expression, variables from parent work objects in the hierarchy are also visible in the
child work object. If a parent and child both have variables with the same name then the child
variable will be resolved.
For example, take the following work object hierarchy:
If we are resolving variables in the task context, then the expression
#{root.message}
will resolve to
"Case message"
as
root
refers to the case.
The expression
#{parent.message}
will also resolve to
"Case message"
as
parent
refers to the process and this work object will inherit the
message
value from its parent (the case). The expression
#{message}
will resolve to
"Task message"
however, as the inherited variable from the case has been hidden by a more
local value.
As mentioned earlier, process expressions can also be used to invoke methods and access properties of java beans. For security reasons it is obviously not a good idea to allow access to all beans within the server, and so edoras one defines a bean white-list containing the bean names that may be accessed. Exactly which beans are available will depend on the edoras one installation, but the following sections describe standard service beans that may be supported.
The process variable handling service allows process variables to be manipulated using a process service task. The following methods are provided:
#{processVariables.initVariables(execution, "variableName", "variableValue")}
initializes variables if they have not yet been set on the process scope. Variable names and values may
also be provided by expressions (e.g.#{processVariables.initVariables(execution, "var", owner.name)}
),
and multiple variable name/value pairs may also be set in one call (e.g.
#{processVariables.initVariables(execution, "var1", "a", "var2", "b")}
).
#{processVariables.setVariables(execution, "variableName", "variableValue")}
follows the same syntax as
processVariables.initVariables()
but will overwrite
the variable values if the variable already exists.
The modeler provides predefined task definitions for a number of common operations, including initializing variables. It will usually be easier and more reliable to use these templates instead of directly using expressions to achieve the same results.
Process expressions can be used in a number of different places within a process description. The following sections describe the details of each possible usage.
Expressions may be embedded within a task name to automatically create task names that are based on the context:
When the task is created, the expressions embedded in the task name will be replaced by the evaluation results.
A service task contains an
Expression
property which will evaluated when the service task is
created. This will typically be used to invoke a bean method that performs the required action:
Sequence flows can be controlled by adding a condition expression to the sequence flow transition:
The expression should resolve to a boolean expression using the boolean operators from the
EE6 specification. The sequence flow
will be taken when the expression resolves totrue
.