Also, it is very unlikely that you will need to use MVEL from inside an Automation Script (using an @{expression}
value). Still, form Automation Scripting, you have access to very useful objects and helpers (Document
, CurrentUser
, Fn
, etc., see below)
How to Use Scripting Features in Parameters Values
When using automation, values you put in operation parameters are provided with scripting capability (when using JavaScript Automation, parameters are a JavaScript expression, string, number, function returning a value, etc.). Basically, when the system evaluates the value, it detects whether it is a raw value or an expression to be evaluated/resolved. The syntax used to tell the system you are passing an expression to be evaluated is @{the_expression}
.
So, for example, say we want to set the value
parameter of the Document.SetProperty
operation to set the dc:title
field of a document:
If we pass
The New Title
, there is no interpretation (default behavior), the parameter is taken "as is", which means that the title will be "The New Title".If we pass
@{Title}
, the system interpretsTitle
(inside the brackets) as a scripting expression. In that case, it means the value of the title will be updated with the content of the variable Title (that will have been set previously)The expression between brackets can be concatenated with a non-interpreted value.
The New @{Title}
will set the title to "The New " plus the content of the variable Title.
Notice it is also possible to use the expr:
prefix: expr:Title
is the same as @{Title}
and expr:The New @{Title}
is the same as The New @{Title}
.
The expression between brackets (@{the_expression}
) is evaluated/calculated and can be contextual objects or embedded helper functions:
- You can put your own Context Variables (Using
Context.SetVar
previously in your chain) - Nuxeo provides objects for your convenience. We will discuss these objects below. For example, the
Document
,CurrentUser
,CurrentDate
objects provide accessors to facilitate getting values from the current context.@{Document.title}
returns the title of the current document.@{CurrentUser.mail}
the mail address of the current user (typically used with theSendMail
operation).@{CurrentDate.days(7).calendar}
returns a date "in 7 days" (for example, stored indc:expired
).
The expression can return any value, it is not limited to strings. For example, if we have an order:total_price
floating point field, we can set its value (still using the Document.SetProperty
operation) with @{Document["order:quantity"] * Document["order:price"]}
.
MVEL
The scripting language used is MVEL. See the MVEL language guide. You can use all the features of the scripting language itself.
For instance, you can use the substring method, when dealing with paths:
@{Document.path.substring(26)}
.This is especially useful if you manipulate strings inside your expression: No need to write a Java plugin for this, you can just use
toLowerCase()
ortoUpperCase()
for example. The following converts theorder:label
string field to all upper case:@{Document["order:label"].toUpperCase()}
(This expression would be used as thevalue
parameter of theDocument.SetProperty
operation.)It is easy to format a string with padding zeros: Use
String.format()
. Notice the value to pass must be a number:@{String.format("%06d", 1234)
=> "001234".Now, the following example looks more complex: It combines several objects and accessors and returns a unique Claim ID starting with "CLM-", using a sequence number (see below the
Fn
object). We need to convert the string returned byFn.getNextId
to a number:CLM-@{String.format("%06d", Integer.parseInt(Fn.getNextId("claim")))}
=> "CLM-000354", "CLM-000355", etc.
Testing if a variable is null:
@{WorkflowVariables["mail"] == empty ? "VoidChain" : "MyChain"}
Usage of
empty
variable allows for evaluating the expression to empty string. For instance, to set a property of a document to""
(empty string), you can define the value withempty
@{empty}
(you also can use
@{""}
).As MVEL will consider values to be string by default, you can set hard-coded values depending on the type of the field. To set an integer value to ten, write
@{10}
. To reset a field to null:@{null}
. To set a string field to "" you can use@{""}
Scripting Context
The Expression Editor in Nuxeo Studio displays the Browse Context drop down and its related features, which contain all the features explained in this documentation.
Document: The Document object represents the input document, when the operation takes a document as input. You can use it to get a property value of it:
@{Document.path}
,@{Document["yourschema:yourfield"]}
,@{Document.domain.title}
You can also use methods provided by theDocumentWrapper
, see below.variable_name: If you set a context variable in a previous operation, you can access it in the parameter value by just referring to its name. In the following sample, we previously used
Context.SetVar
to store the path of a document in thepath_of_the_workspace
variable. The parameter's value will be this path:@{path_of_the_workspace}
(orexpr:path_of_the_workspace
)Do not use "-" character in the variable name. Prefer the use of_
.Relative paths: Each time you need to use a path expression (whether it is as a direct parameter of an operation, such as move, or in a NXQL query, for STARTSWITH operator, you can leverage relative path capability:
- "." will be replaced with the path of the input document;
- ".." will be replaced with the path of the parent of the input document.
CurrentDate: The
CurrentDate
object provides various utility methods to handle dates (current date, date in one month, format a date, etc.), see "Date Wrapper" below.CurrentUser: The
CurrentUser
object provides various utility methods returning information about the current user (login, first/last name, mail, etc.), see "User Wrapper" below.Event: In the context of an Automation Chain called from an Event Handler, the
Event
object can be used to access some of the event's properties. For instance,@{Event.getName()}
returns the name of event ("aboutToCreated", "beforeDocumentModification", etc.)Fn: The
Fn
object provides several utilities to access miscellaneous information (see below): Get the label of a vocabulary given its ID, get all the mails of a group of users, get a sequence number, etc.Other objects are available, less often used:
Env
allows for getting the value of a configuration parameter (see below)WorkflowVariables
andNodeVariables
allow for retrieving the values of your variables in the context of a workflowContext
is maintained for compatibility reason. All its objects are available in other objects, or can be accessed an easier way. For example, to get the value of a Context variable, you can write@{Context["the_variable"]}
, but@{the_variable}
looks more readable.
Document Wrapper
The Document wrapper, used by the system for any document put in scripting context (whether under a variable name, or as the input document ("Document") provides several utility methods:
Document.parent
: Returns a document wrapper of the parent of the document;Document.workspace
: Returns a document wrapper of the parent workspace of the document;Document.domain
: Returns a document wrapper of the parent domain of the document;Document.path
: Returns a string representing the value of the path of the document, like "/default-domain/workspaces/my-workspace";Document.title
: Returns the title of the document;Document.description
: Returns the description of the document;Document.type
: Returns the Nuxeo EP Document type of the document (like "File", "Folder", ...);Document.lifeCycle
: Returns the current lifecycle state of the document;Document.name
: Returns the name of the document (last part of the path);Document.versionLabel
: Returns the version name of the document (like "1.1"...).
currentDocument
is an alias for Document
.
Document
is a DocumentWrapper
and you can also check the code to see all the available accessors.
For example, you can also use hasFacet(String facet)
, hasSchema(String schemaName)
, etc. Make sure to select the branch corresponding to the version of Nuxeo you are using.
Date Wrapper
The Date wrapper is useful to update documents' date properties and to build time-relative NXQL queries.
CurrentDate.date
: returns the date. It is the method to use to update a document date field, likedc:valid
, or whatever custom date field.
Some other methods are provided to display the current date as a string:
CurrentDate.format("_java formatting expression_
")
: returns the current date in the specified format;CurrentDate.time
: returns the date in milliseconds;CurrentDate.day
: returns the day of the current time;CurrentDate.month
: returns the month of the current time;CurrentDate.year
: returns the year of the current time;CurrentDate.hour
: returns the hour of the current time;CurrentDate.minute
: returns the minutes of the current time;CurrentDate.second
: returns the seconds of the current time;CurrentDate.week
: returns the week of the current time.
Some others can be used when building an NXQL query to express dates relatively to the current date:
CurrentDate.days(-3)
: returns the current date minus three days;CurrentDate.years(10)
: returns the current date plus ten years;CurrentDate.months(-5).weeks(2).seconds(23)
: returns the current date minus five months plus two weeks and 23 seconds;
- ...
If you want to work on a date stored in a field of your document, you first need to get a
DateWrapper
object, by using:@{Fn.calendar(Document["dc:created"])}
For example:@{Fn.calendar(Document["dc:created"]).format("yyyy-MM-dd")}
To set a date property based on the current date, use the
CurrentDate
object, and ends the expression with thecalendar
or thedate
wrapper. For example, to set up a field to:- today:
@{CurrentDate.days(0).calendar}
- in 7 days:
@{CurrentDate.days(7).date}
- today:
To create a date that you can set on a date property from a string, you can use
@{new java.text.SimpleDateFormat("yyyy-MM-dd").parse(date_str)}
wheredate_str
is a Context variable containing a value such as "2019-09-26". You must pass toSimpleDateFormat
the format of this date, so the parse() method work.
User Wrapper
The CurrentUser
object wraps useful functions to get information about the current user:
CurrentUser.name: Returns the user ID (used for logging in)
User information:
CurrentUser.email
,CurrentUser.firstName
,CurrentUser.lastName
,CurrentUser.company
.User information - advanced: There also are accessors to get more advanced information about the current user.
CurrentUser["xpath"]
returns the value of a field in theuser
schemaCurrentUser.allGroups
returns an array with all the groups the user belongs to. It is a JavaList<String>
. To test if the current user is a member of the "marketing" group, you can useCurrentUser.allGroups.contains("marketing")
CurrentUser.principal returns the
NuxeoPrincipal
Java object, allowing for getting more tuned/detailed information (see the Source Code on GitHub or the Java Doc). For example:CurrentUser.principal.isMemberOf("marketing")
,CurrentUser.principal.isAdministrator()
,CurrentUser.principal.isAnonymous()
,CurrentUser.principal.isTransient()
, etc.CurrentUser.actingUser: In a workflow context, all the automation operations executed by the workflow engine are executed using a temporary unrestricted session (if the current user is not an administrator, this is a session with the user "system"). This variable allows you to fetch the current user. This can also be useful when the operation "Users and groups > Login as" has been used to retrieve the current username.
currentUser
is an alias forCurrentUser
.
Functions
The Functions object is providing a set of useful functions. This object is named Fn
and it provides the following functions (the full list can also be checked in the code, make sure to select the branch of your version):
Fn.getNextId(String key)
: Returns a unique value for the given key using the default sequencer. Each time this function is called using the same key a different string will be returned.Fn.getNextId(String key, String sequencerName)
: Same asFn.getNextId(String key)
but allows for using a specific sequencer.Fn.getVocabularyLabel(String vocabularyName, String key)
: Returns a value from the named vocabulary that is associated with the given key.Fn.getPrincipal(String userName)
: Returns a JavaNuxeoPrincipal
object for the given username string.Fn.getPrincipalsFromGroup(String group)
: Returns a JavaSet
ofNuxeoPrincipal
for the given group. Also returns the subgroups.Fn.getPrincipalsFromGroup(String group, boolean ignoreGroups)
: Returns a JavaSet
ofNuxeoPrincipal
for the given group. Only the users are returned, not subgroups.Fn.getEmail(String userName)
: Returns the e-mail of the given username.Fn.getEmails(List<String> userNames)
: Returns a list of e-mails for the given user name list.Fn.getEmails(List<String> userNames, boolean usePrefix)
: Returns a list of e-mails for the given user name list. IfuserPrefix
istrue
, each item is prefixed withuser:
.Fn.getPrincipalEmails(List<NuxeoPrincipal> principals)
: Same as above but the input object is a list of Nuxeo principals.Fn.getEmailsFromGroup(String groupName)
: Returns a list of e-mails of all the users of the group.Fn.concatenateIntoList(List<T> list, Object... values)
: Adds the values to the list. If a value is itself an array or a collection, each of its members is added to the list. The list is returned.Fn.concatenateValuesAsNewList(Object... values)
: Same asconcatenateIntoList
but using a newly-created list.Fn.htmlEscape(String string)
: Returns an escaped version of the string suitable for HTML inclusion.Fn.nxqlEscape(String string)
: Returns an escaped version of the string suitable for NXQL inclusion inside single quotes.Fn.documentExists(CoreSession session, String idOrPath)
: Returnstrue
if the document exists in the repository.Fn.getDirService()
: Returns theDirectoryService
. Requires administration privileges.
Nuxeo Environment Properties
Nuxeo environment properties are accessible in scripts using the Env
map object. All the properties defined in Nuxeo (typically in the nuxeo.conf
file) are available through the Env
map. This is very useful when you want to configure your operations using values that can be modified later on a running server.
For example, let's say you want to make an operation that is creating a document and initialize its description from a Nuxeo property named automation.document.description
.
To do this:
- Fetch the property using the
Env
map in your operation parameter:Env["automation.document.description"]
. - And then set the configuration parameter in the
nuxeo.conf
file of your Nuxeo Server:automation.document.description = My Description
Date Management Example
Notice: These examples are for usage in Automation. if you are writing an Automation Script, you also can use the JavaScript native Date
object (while the CurrentDate
object is still available in Automation Scripting if you need it.).
Operation | Parameter | Expected value | Expression Example |
---|---|---|---|
Document > Document.SetProperty | value | Today, now |
@{CurrentDate.date}
|
Document > Document.SetProperty | value | In one month |
@{CurrentDate.month(1).date}
|
Document > Document.SetProperty | value | Hard-coded date | 2020-07-14T00:00:00Z |
Document > Document.SetProperty | value | Date property from the input document |
@{Document["achema:aDateField"]}
|
Adding values (days, months, ...) to a date field requires some manipulation (it is easier when using Automation Scripting with JavaScript), please read this blog on the topic.
If you have this error in server.log
...
No type adapter found for input: class org.nuxeo.ecm.automation.core.scripting.DateWrapper and output class java.util.Date
... it means you are presenting a DateWrapper
value type into a field that waits for a java.util.Date
object.
User and Group Management Example
Operation | Parameter | Expected value | Expression Example |
---|---|---|---|
Document > Document.SetProperty | value | Hardcoded user | user:jdoe |
Document > Document.SetProperty | value | Hardcoded group | group:marketing |
Document > Document.SetProperty | value | Current user |
@{CurrentUser.name}
|
Notification > Document.Mail | from | Current user mail |
@{CurrentUser.mail}
|
Notification > Document.Mail | to | All users of the "ClaimAdjusters" group |
@{Fn.getEmailsFromGroup("marketing")}
|
Using Auth.Login
/Auth.Logout
During the flow of a chain, we must change the permissions on a document.
For example, Alice is creating a Marketing Campaign and assigns Bob as a creative. Now, Bob must be able to upload files to the campaign: We need to change Bob's permissions on the Marketing Campaign to give him ReadWrite access (assuming he only had Read permission).
Alice does not have enough rights to change the permission: Calling Document.AddPermission
will fail. In our chain, we can do the following instead:
. . . previous operations . . .
Auth.LoginAs
Document.AddPermission:
permission: ReadWrite
acl: local
blockInheritance: false
notify: false
username: user:bob
Auth.Logout
. . . next operations . . .
Numbers Management Example
Operation | Parameter(s) | Expected value | Expression Example |
---|---|---|---|
Conversion > Picture.Resize | maxHeight | Hardcoded values | 100 |
Conversion > Picture.Resize | maxHeight | Value from a field of input document |
@{Document["aSchema:maxHeightForImages"]}
|
Document > Document.SetProperty | value | Add two numeric fields |
@{Document["invoice:amount"] + Document["invoice:tax"]}
(the xpath parameter of the operation would be @{Document["invoice:total"]}
|
Document Management Example
Operation | Parameter | Expected value | Expression example | Note |
---|---|---|---|---|
Document > Document.Copy | target | Hardcoded value |
/default-domain/workspaces
|
Here is specified the path of the container where the document is to be copied, assuming this document exists |
Document > Document.Create | type | Hardcoded value | File |
Creating a File document type.
|
Document > Document.Create | name | String | node-name-of-my-document | This field is a technical one and used to build the URL. This is not the title. If you look at the URL after navigating to a document and you will see its path based on the names of the document's ancestor and its name. Typical example with Nuxeo out of the box: The domain's title is "Domain" while its name is "default-domain". |
Referencing Automation Chain Parameters
It is possible to define parameters to your chain (in Nuxeo Studio, you can use the "Parameters" tab). When the chain is called, you access the values of the parameters with:
@{ChainParameters["parameterName"]}
Using the RunScript
Operation
The Scripting > RunScript
operation allows, basically, for using Java APIs (with security restriction. You cannot access a file on the server for example, etc.). When you need this, you may find it easier to use Automation Scripting (which also allows for using Java in JavaScript).
When calling the operation, you must use full qualified names. For example, when calling a service:
org.nuxeo.business.days.management.service.BusinessDaysService bdService = org.nuxeo.runtime.api.Framework.getService(org.nuxeo.business.days.management.service.BusinessDaysService);
Context["limitDate"] = bdService.getLimitDate("myRule",CurrentDate.date);
=> You now can use the context variable limitDate
in other operations.
RunScript
, then we strongly recommend that you write a Java plugin instead.