Actions are executed during the entry and exit phases of a user task, during the execution
of an automated task, or during the processing of a RunActionTimerHandler
. This
means that an action is typically executed in the context of a task, but that it may be
executed in the context of a process, too, if used with a timer handler.
By means of the interface
Action,
you can only implement server-side actions, that is, actions that run completely within the
Workflow Server. Actions are run on the server on behalf
of the workflow user as configured in the file workflowserver.properties
.
The main method of an action is execute(WorkflowObject)
, where the argument is
either a task or a process depending on the context of the action. While executing, the
action implementation should only read and write variables of the argument workflow object
and its view. It is recommended that the exact variable names are made configurable by means
of bean-style getters and setters.
The method isExecutable(WorkflowObject)
, should return false, when it is not
currently possible to execute an action. Normally, you should always return
true
from this method, but there are cases where you might want to wait for a
workflow variable to be set correctly before processing an action.
After execution, you may return a new instance of
ActionResult
in order to indicate success or failure. If you use the attributes successVariable
and/or
resultVariable
in your XML workflow definition, the action result is automatically evaluated
to set those variables. The action result can also take exceptions that are interpreted as
warnings. If you include warnings in your result, they are added to the list that is
returned from the method getWarnings()
of the affected workflow object.
The method abort()
should be implemented to let all running
execute
calls return early, possibly by throwing an
ActionAbortedException.
This method is called when the Workflow Server is shutting down. There is no need to
implement special logic if the execute method always returns early. If execution takes some
time, you should also consider implementing a long action instead.
The name returned by the method getName()
of an action is used solely for
logging and for parameterizing exceptions. It does not carry any semantic meaning, so that
you may choose it as you like.
In order to simplify the development of an action, you may derive your class from the
predefined classes
AbstractAction
or
SimpleAction.
Thereby, it is enough to implement a single method, namely execute(Process)
in
the former and doExecute(Process)
in the latter case. Because the exact task in
which the action is executed is not included in the signature of these methods, this
approach requires that all relevant variables are defined at the process level. This is the
typical use case. A detailed example of an action sending mail implemented as
SimpleAction
is given in Section 6.11.3, “Example Code of the Mail Action”.
The server may run an action more than once, in particular when a transaction has to be restarted due to concurrent activity. Therefore, you should design your actions in such a way that either the second execution detects that the action has already been executed or that a repeated execution is acceptable. For example, it is preferable to set a variable to a certain value rather than to increment an integer or to toggle a flag