public class Workflow extends Object implements Serializable
Sequence of Step
objects linked together. Workflows are always
initialized with a message key that denotes the name of the Workflow, and a
Principal that represents its owner.
getCurrentState()
) will be one of the
following:
CREATED
: after the Workflow has been
instantiated, but before it has been started using the start()
method.RUNNING
: after the Workflow has been started
using the start()
method, but before it has finished processing all
Steps. Note that a Workflow can only be started once; attempting to start it
again results in an IllegalStateException. Callers can place the Workflow
into the WAITING state by calling waitstate()
.WAITING
: when the Workflow has temporarily
paused, for example because of a pending Decision. Once the responsible actor
decides what to do, the caller can change the Workflow back to the RUNNING
state by calling the restart()
method (this is done automatically by
the Decision class, for instance, when the Decision.decide(Outcome)
method is invoked)COMPLETED
: after the Workflow has finished
processing all Steps, without errors.ABORTED
: if a Step has elected to abort the
Workflow.
Workflow Step objects can be of type Decision
, Task
or other
Step subclasses. Decisions require user input, while Tasks do not. See the
Step
class for more details.
After instantiating a new Workflow (but before telling it to start()
),
calling classes should specify the first Step by executing the
setFirstStep(Step)
method. Additional Steps can be chained by
invoking the first step's Step.addSuccessor(Outcome, Step)
method.
When a Workflow's start
method is invoked, the Workflow
retrieves the first Step and processes it. This Step, and subsequent ones,
are processed as follows:
Step.start()
method executes, which sets the start
time.Step.execute()
method is called to begin processing,
which will return an Outcome to indicate completion, continuation or errors:Outcome.STEP_COMPLETE
indicates that the execution method ran
without errors, and that the Step should be considered "completed."Outcome.STEP_CONTINUE
indicates that the execution method ran
without errors, but that the Step is not "complete" and should be put into
the WAITING state.Outcome.STEP_ABORT
indicates that the execution method
encountered errors, and should abort the Step and the Workflow as
a whole. When this happens, the Workflow will set the current Step's Outcome
to Outcome.STEP_ABORT
and invoke the Workflow's abort()
method. The Step's processing errors, if any, can be retrieved by
Step.getErrors()
.execute
method also affects what
happens next. Depending on the result (and assuming the Step did not abort),
the Workflow will either move on to the next Step or put the Workflow into
the WAITING
state:Step.isCompleted()
method returns true
) then the Step
is considered complete; the Workflow looks up the next Step by calling the
current Step's Step.getSuccessor(Outcome)
method. If
successor()
returns a non-null
Step, the
return value is marked as the current Step and added to the Workflow's Step
history. If successor()
returns null
, then the
Workflow has no more Steps and it enters the COMPLETED
state.Step.isCompleted()
method returns false
), then the
Step still has further work to do. The Workflow enters the WAITING
state and stops further processing until a caller restarts it.
The currently executing Step can be obtained by getCurrentStep()
. The
actor for the current Step is returned by getCurrentActor()
.
To provide flexibility for specific implementations, the Workflow class provides two additional features that enable Workflow participants (i.e., Workflow subclasses and Step/Task/Decision subclasses) to share context and state information. These two features are named attributes and message arguments:
setAttribute(String, Object)
and retrieved with getAttribute(String)
.InternationalizationManager
to
create language-independent user interface messages. The message argument
array is retrieved via getMessageArguments()
; the first two array
elements will always be these: a String representing work flow owner's name,
and a String representing the current actor's name. Workflow participants
can add to this array by invoking addMessageArgument(Serializable)
.Workflow Steps can be very powerful when linked together. JSPWiki provides two abstract subclasses classes that you can use to build your own Workflows: Tasks and Decisions. As noted, Tasks are Steps that execute without user intervention, while Decisions require actors (aka Principals) to take action. Decisions and Tasks can be mixed freely to produce some highly elaborate branching structures.
Here is a simple case. For example, suppose you would like to create a Workflow that (a) executes a initialization Task, (b) pauses to obtain an approval Decision from a user in the Admin group, and if approved, (c) executes a "finish" Task. Here's sample code that illustrates how to do it:
// Create workflow; owner is current user 1 Workflow workflow = new Workflow("workflow.myworkflow", context.getCurrentUser()); // Create custom initialization task 2 Step initTask = new InitTask(this); // Create finish task 3 Step finishTask = new FinishTask(this); // Create an intermediate decision step 4 Principal actor = new GroupPrincipal("Admin"); 5 Step decision = new SimpleDecision(this, "decision.AdminDecision", actor); // Hook the steps together 6 initTask.addSuccessor(Outcome.STEP_COMPLETE, decision); 7 decision.addSuccessor(Outcome.DECISION_APPROVE, finishTask); // Set workflow's first step 8 workflow.setFirstStep(initTask);
Some comments on the source code:
Admin
group, who will be the actor in the Decision stepAdmin
GroupPrincipal) selects DECISION_APPROVE, the FinishTask
step should be invokedModifier and Type | Field and Description |
---|---|
static int |
ABORTED
State value: Workflow aborted before completion.
|
static int |
COMPLETED
State value: Workflow completed all Steps without errors.
|
static int |
CREATED
State value: Workflow instantiated, but not started.
|
static int |
ID_NOT_SET
ID value: the workflow ID has not been set.
|
static int |
RUNNING
State value: Workflow started, and is running.
|
static Date |
TIME_NOT_SET
Time value: the start or end time has not been set.
|
static int |
WAITING
State value: Workflow paused, typically because a Step returned an
Outcome that doesn't signify "completion."
|
Constructor and Description |
---|
Workflow(String messageKey,
Principal owner)
Constructs a new Workflow object with a supplied message key, owner
Principal, and undefined unique identifier
ID_NOT_SET . |
Modifier and Type | Method and Description |
---|---|
void |
abort()
Aborts the Workflow by setting the current Step's Outcome to
Outcome.STEP_ABORT , and the Workflow's overall state to
ABORTED . |
void |
addMessageArgument(Serializable obj)
Appends a message argument object to the array returned by
getMessageArguments() . |
void |
addWikiEventListener(WikiEventListener listener)
Registers a WikiEventListener with this instance.
|
protected void |
cleanup()
Clears the attribute map and sets the current step field to
null . |
protected void |
complete()
Protected helper method that changes the Workflow's state to
COMPLETED and sets the current Step to null . |
protected void |
fireEvent(int type)
Fires a WorkflowEvent of the provided type to all registered listeners.
|
Object |
getAttribute(String attr)
Retrieves a named Object associated with this Workflow.
|
Principal |
getCurrentActor()
Returns the actor Principal responsible for the current Step.
|
int |
getCurrentState()
|
Step |
getCurrentStep()
Returns the current Step, or
null if the workflow has not
started or already completed. |
Date |
getEndTime()
The end time for this Workflow, expressed as a system time number.
|
List<Step> |
getHistory()
Returns a Step history for this Workflow as a List, chronologically, from the
first Step to the currently executing one.
|
int |
getId()
Returns the unique identifier for this Workflow.
|
Serializable[] |
getMessageArguments()
Returns an array of message arguments, used by
MessageFormat to create localized messages. |
String |
getMessageKey()
Returns an i18n message key for the name of this workflow; for example,
workflow.saveWikiPage . |
Principal |
getOwner()
The owner Principal on whose behalf this Workflow is being executed; that
is, the user who created the workflow.
|
Step |
getPreviousStep()
Convenience method that returns the predecessor of the current Step.
|
Date |
getStartTime()
The start time for this Workflow, expressed as a system time number.
|
WorkflowManager |
getWorkflowManager()
Returns the WorkflowManager that contains this Workflow.
|
boolean |
isAborted()
Returns
true if the workflow had been previously aborted. |
boolean |
isCompleted()
Determines whether this Workflow is completed; that is, if it has no
additional Steps to perform.
|
boolean |
isStarted()
Determines whether this Workflow has started; that is, its
start() method has been executed. |
protected Step |
previousStep(Step step)
Protected method that returns the predecessor for a supplied Step.
|
protected void |
processCurrentStep()
Protected method that processes the current Step by calling
Step.execute() . |
void |
removeWikiEventListener(WikiEventListener listener)
Un-registers a WikiEventListener with this instance.
|
void |
restart()
|
void |
setAttribute(String attr,
Object obj)
Temporarily associates an object with this Workflow, as a named attribute, for the
duration of workflow execution.
|
void |
setFirstStep(Step step)
Sets the first Step for this Workflow, which will be executed immediately
after the
start() method executes. |
void |
setId(int id)
Sets the unique identifier for this Workflow.
|
void |
setWorkflowManager(WorkflowManager manager)
Sets the WorkflowManager that contains this Workflow.
|
void |
start()
Starts the Workflow and sets the state to
RUNNING . |
void |
waitstate()
Sets the Workflow in the
WAITING state. |
public static final Date TIME_NOT_SET
public static final int ID_NOT_SET
public static final int COMPLETED
public static final int ABORTED
public static final int WAITING
public static final int RUNNING
public static final int CREATED
public Workflow(String messageKey, Principal owner)
ID_NOT_SET
. Once
instantiated the Workflow is considered to be in the CREATED
state; a caller must explicitly invoke the start()
method to
begin processing.messageKey
- the message key used to construct a localized workflow name,
such as workflow.saveWikiPage
owner
- the Principal who owns the Workflow. Typically, this is the
user who created and submitted itpublic final void abort()
Outcome.STEP_ABORT
, and the Workflow's overall state to
ABORTED
. It also appends the aborted Step into the workflow
history, and sets the current step to null
. If the Step
is a Decision, it is removed from the DecisionQueue. This method
can be called at any point in the lifecycle prior to completion, but it
cannot be called twice. It finishes by calling the cleanup()
method to flush retained objects. If the Workflow had been previously
aborted, this method throws an IllegalStateException.public final void addMessageArgument(Serializable obj)
getMessageArguments()
. The object must be an type
used by the MessageFormat
: String, Date, or Number
(BigDecimal, BigInteger, Byte, Double, Float, Integer, Long, Short).
If the object is not of type String, Number or Date, this method throws
an IllegalArgumentException.obj
- the object to addpublic final Principal getCurrentActor()
null
.public final int getCurrentState()
public final Step getCurrentStep()
null
if the workflow has not
started or already completed.public final Object getAttribute(String attr)
null
.attr
- the name of the attributepublic final Date getEndTime()
Step.getEndTime()
method, if the workflow has completed.
Otherwise, this method returns TIME_NOT_SET
.public final int getId()
public final Serializable[] getMessageArguments()
Returns an array of message arguments, used by
MessageFormat
to create localized messages. The first
two array elements will always be these:
getOwner()
)getCurrentActor()
).
If the current step is null
because the workflow hasn't started or has already
finished, the value of this argument will be a dash character (-
)
Workflow and Step subclasses are free to append items to this collection
with addMessageArgument(Serializable)
.
public final String getMessageKey()
workflow.saveWikiPage
.public final Principal getOwner()
public final Date getStartTime()
Step.getStartTime()
method, if the workflow has started already.
Otherwise, this method returns TIME_NOT_SET
.public final WorkflowManager getWorkflowManager()
public final List<Step> getHistory()
public final boolean isAborted()
true
if the workflow had been previously aborted.public final boolean isCompleted()
true
.true
if the workflow has been started but has no
more steps to perform; false
if not.public final boolean isStarted()
start()
method has been executed.true
if the workflow has been started;
false
if not.public final Step getPreviousStep()
null
if the first Step is
currently executingpublic final void restart() throws WikiException
WAITING
state and puts it into
the RUNNING
state again. If the Workflow had not previously been
paused, this method throws an IllegalStateException. If any of the
Steps in this Workflow throw a WikiException, the Workflow will abort
and propagate the exception to callers.WikiException
- if the current task's AbstractStep.execute()
method
throws an exceptionpublic final void setAttribute(String attr, Object obj)
attr
- the attribute nameobj
- the valuepublic final void setFirstStep(Step step)
start()
method executes. Note than the Step is not
marked as the "current" step or added to the Workflow history until the
start()
method is called.step
- the first step for the workflowpublic final void setId(int id)
id
- the unique identifierpublic final void setWorkflowManager(WorkflowManager manager)
manager
- the workflow managerpublic final void start() throws WikiException
RUNNING
. If the
Workflow has already been started (or previously aborted), this method
returns an IllegalStateException. If any of the
Steps in this Workflow throw a WikiException, the Workflow will abort
and propagate the exception to callers.WikiException
- if the current Step's Step.start()
method throws an exception of any kindpublic final void waitstate()
protected void cleanup()
null
.protected final void complete()
protected final Step previousStep(Step step)
step
- the Step for which the predecessor is requestednull
if the first Step was
supplied.protected final void processCurrentStep() throws WikiException
Step.execute()
. If the execute
throws an
exception, this method will propagate the exception immediately
to callers without aborting.WikiException
- if the current Step's Step.start()
method throws an exception of any kindpublic final void addWikiEventListener(WikiEventListener listener)
listener
- the event listenerpublic final void removeWikiEventListener(WikiEventListener listener)
listener
- the event listenerprotected final void fireEvent(int type)
type
- the event type to be firedWorkflowEvent
Copyright © 2001-2019 The Apache Software Foundation. All rights reserved.