Content Automation is a Nuxeo service that exposes commons actions you do on a Nuxeo application as atomic operations so that one can assemble them to create complex business rules and logic, without writing any Java code.
In other words, content automation provides a high level API over Nuxeo services - an API made of operations that can be assembled in complex operation chains (or macro operations). These operations are also exposed remotely through a REST API.
The main goal of automation is to enable end users to rapidly build complex business logic without writing any Java code - just by assembling the built-in set of atomic operations into complex chains and then plugging these chains inside Nuxeo as UI actions, event handlers, REST bindings, etc.
You can also create new atomic operations (write a Java class that defines an operation) and contribute them to the set of built-in operations. To define an operation chain, you just need to write an XML contribution that describes the chain by listing each operation in the chain along with the parameter values that will be used to execute the operation. If you need to define dynamic operation parameters (which value will be computed at runtime when the operation is executed) you can use scripting (e.g. EL syntax) to fetch the actual parameter value at execution time.
This documentation is oriented toward developers looking for extending and/or using the REST API of Content Automation. You can also easily and graphically create new chains and actions using Nuxeo Studio.
Outline of this document:
What is an Operation?
From an end-user point of view: an operation is an action that can be triggered by the user either directly through the User Interface, or by responding to an event, or by a REST call to a remote server.
The operations an user can invoke usually deal with the document repository (like creating or updating documents), but they can also do some other tasks like sending emails, converting blobs, etc.
The automation service already provides tens of frequent operations that you may need to build your business logic. More operations can be contributed using a Nuxeo extension point. This involves of course writing the right Java code to implement the operation logic.
From a developer point of view: an operation is a Java class annotated using the right annotations and providing a one or more methods that are doing the actual work.
For more information about how to write and contribute a new operation, see Contributing an Operation.
What is an Operation Chain?
The power of operations is that operations can be chained into a sort of macro operation that is composed of atomic operations and which executes each operation in turn by using an operation output as the input of the next operation.
This way you can for example construct an operation chain that creates a document, then attaches a blob into the document, then publishes it and so on. Each operation in the chain does the required step by working on the input of the previous operation and when finished outputs a result that will be used by the next operation as its input.
This is called in Nuxeo Automation an operation chain. Operation chains give you the possibility to build complex business logic only by assembling atomic operations that are provided by the server. Thus, you can script your business logic using operation chains which thank to Nuxeo Studio can be done by using drag and drop (without coding anything or even writing XML extension files).
If you are a developer and don't want to use Nuxeo Studio, you can check the Contributing an Operation Chain page to see how you can define and contribute a new operation chain using Nuxeo extension points.
Working With Operations
In this section I will discuss more about how operations work and how they can be chained to obtain working operation chains.
We've seen that an operation works on an input object by doing something (like updating this object or creating new objects) and at the end it outputs the operation result. When you are constructing a chain of operations, this result will be used as the input of the next operation. The last output in the chain will be the output of the chain itself. As you noticed, an operation works on an input so you should provide an initial input to start an operation (or an operation chain).
More, as there is an Execute Operation atomic operation which takes as the argument the name of the chain to execute, you can create very complex chains that can call sub-chains to execute some particular steps in the chain.
In a chain, every operation has a cause and an effect. The effect of one operation in a chain is the cause of the next event. The initial cause is the user action (doing something with a document for example), the final effect is what the chain is assumed to do.
An atomic operation can be view as a finite operation chain with an initial cause (the action that triggered it) and having the effect of the execution of the operation itself. This way you can chain as many cause and effects you want - you can create your ECM universe using operations.
Now, lets discuss about the bricks that compose an operation:
- An operation has an input (provided by the cause)
- An operation may have zero or more parameters (used to parametrize the way an operation is behaving)
- An operation has an output (that can be used by the next operation in the chain as the input)
The Operation Input
The operation input can be a Document or a Blob (i.e. a file).
The input is provided by the execution context, either by getting the input from the user action (in the case of a single operation or for the first operation in the chain), or from the output of the previous operation when executing a chain.
So we can say that an operation is working on a Document or a Blob.
There are some special operations that don't need any input. For example you may want to run a query in the repository. In this case, you don't need an input for your query operation. Thus, operations can accept void inputs (or nothing as input). To pass a void input to an operation, just use a null value as the input. If an operation is doesn't expect any input (i.e, void input) and an input is given, the input will be ignored.
The Operation Parameters
An operation can define parameters to be able to modify its execution at runtime depending on those parameter values.
Any parameter value can be expressed as a string. The string will be converted to the right type at runtime if possible. If not possible an exception is thrown.
There are several types of predefined parameters:
- string - any string
- boolean - a boolean parameter
- integer - an integer number
- float - a floating point number
- date - a date (in W3C format if is specified as a string)
- resource - an URL to a resource
- properties - a Java properties content (key=value pairs separated by new lines)
- document - a Nuxeo Document (use its absolute PATH or its UID when expressing it as a string)
- blob - a Nuxeo blob (the raw content of the blob in the case of a REST invocation)
- documents - a list of documents
- bloblist - a list of blobs
- any other object that is convertible from a string - you can register new object converters trough the "adapters" extension point of the "org.nuxeo.ecm.core.operation.OperationServiceComponent" Nuxeo Component.
- an expression - this represents a MVEL expression (which is compatible with basic EL expressions) that can output dynamic values. Whe using expressions you *must* prepend it with the _expr:_ prefix.
Example: For the complete list of objects and functions available in an expression see Nuxeo Studio.
- an expression template. This is the same as an expression but it will be interpreted as a string (by doing variable substitution). This is very useful when you want to create expressions like this:
You notice that you still need to prepend your template string with an expr: prefix.
where mytitle is a variable name that will be substituted with its string form.
The Operation Output
The operation output is either a Document, a Blob or void (as the input).
In some rare cases you may want your operation to not return anything (a void operation). For example your operation may send an email without returning anything. When an operation is returning void (i.e. nothing), then a null Java object will be returned .
As said before, the output of an operation is the input of the next operation when running in a chain.
Contributing new Input/Output types (since Nuxeo 5.4.2)
If needed, you can extend the input/output types by contributing the new marshalling logic to automation.
Marshalling and operation binding logic is selected client and server side using the JSON type name. At this stage,
we're always using the java type simple name in lowercase. This makes the operation binding logic being happy.
The logic you need to provide is as follow :
- the JSON type name
- the POJO class
- a writing method that put data extracted from the POJO object into the JSON object
- a reading method that get data from the JSON object and builds a POJO object from
- a reference builder that extracts the server reference from a POJO object
- a reference resolver that provides access to POJO object giving a server reference
Server and client do not share classes, so you need to provide two marshalling implementation class.
Server side, you should provide an implementation of
The implementation class is to be contributed to the automation server component using the
marshallers extension point.
Client side, you should implement the
The implementation class is to be registered to the automation client marshalling framework by invoking the static method
Here is some snip-sets extracted from the Automation Server Rest Test Suite.
Using scripting expression in operations
Operations can be parametrized using MVEL scripting expressions. For more details about scripting you can look at Use scripting with operations.