Taylor

Status Flow

From Taylor

UML State Machines can be used to model many facets of software. We have already used them to model page flows.

Here we are using them to model the status/state transitions of a specific domain entity instance.

To distinguish this use of state machines from others we call this pattern the Status Flow Machine.

An entity will typically have a single property that stores its current status. This property is usually implemented as an enumeration. The value of this status property determines what actions are valid to perform on the entity.

This logic is often complicated and the requirements hard to determine without a useful modeling technique. This is where the Status Flow diagram comes in handy. It helps uncover the rules and then provides code generation.

Contents

Status Flow Diagram

  • Each state represents a specific status of the entity.
  • Each transition represents an action that can be invoked to transition to another status.

This is the status flow for the Ticket entity in the Taylor Tracker model.

To create the diagram:

  1. Right-click on an entity in the navigator and select New > State Machine
  2. Then add a Region to the state machine
  3. The select New Pageflow Diagram (Note: a future version will have a dedicated Statusflow Diagram)

Editor Status Machine Code

Once you have your model, the following code is either generated or part of the editor framework.

  • Status property
  • Status enumeration
  • Status machine
  • Current status
  • Transition actions
  • UI control

Entity and Enumeration

The status property and enumeration are not generated from the status flow diagram. They are modeled in and generated from an Entity/Class diagram per usual. However, modeling the status flow will identify what literals the status enumeration should contain.

  • Each state becomes an enumeration literal
enum TicketStatus {Created, Submitted, Approved, Rejected, ... Closed}
  • The status is stored on the entity as a property
@Entity
public class Ticket {
	...
	private TicketStatus ststus;

	// setter/getter

	@Transient
	public boolean isCreated() {
		return TicketStatis.Created.equals(status);
	}
	...
}

Machine Initialization

The initStatusMachine() method is generated on the editor bean when a status machine is defined for the entity.

This method initializes the status machine transition metadata. A status action combination is added to the machine for each transition.


	protected void initStatusMachine(StatusMachine machine) {

		machine.addStatusAction(TicketStatus.Created, "submit");
		machine.addStatusAction(TicketStatus.Created, "delete");

		machine.addStatusAction(TicketStatus.Submitted, "approve");
		machine.addStatusAction(TicketStatus.Submitted, "reject");

		machine.addStatusAction(TicketStatus.Approved, "start");

		machine.addStatusAction(TicketStatus.Rejected, "close");
		machine.addStatusAction(TicketStatus.Rejected, "resubmit");

		machine.addStatusAction(TicketStatus.Completed, "accept");
		machine.addStatusAction(TicketStatus.Completed, "reject");

		machine.addStatusAction(TicketStatus.Accepted, "close");

		machine.addStatusAction(TicketStatus.Started, "complete");
	}

StatusMachine.java

Current Status

The getCurrentStatus() method is also generated on the editor bean when a status machine is defined for the entity.

Override this method to return the status of the entity instance. The value returned is used to lookup the valid transition actions in the status machine metadata.

	protected Object getCurrentStatus() {
		return getInstance().getStatus();
	}

Transition Actions

An action method is generated on the editor bean for each transition when a status machine is defined for the entity.

These methods are responsible for updating the status of the entity instance. For example,

  1. The submit method invokes the ticket service to change the status and start business processes.
  2. The accept method updates the status directly.
	@In
	private TicketService ticketService;

	@End
	@Action
	public String submit() {
		service.submit(getInstance());
		flush();
		return getFindOutcome();
	}

	@End @Action
	public String approve() { ... }

	@End @Action
	public String accept() {
		getInstance().setStatus(TicketStatus.Accepted);
		flush();
		return getFindOutcome();
	}

	@End @Action
	public String reject() { ... }

	@End @Action
	public String close() { ... }

	@End @Action
	public String start() { ... }

	@End @Action
	public String complete() { ... }

	@End @Action
	public String resubmit() { ... }

	@End @Action
	public String delete() { ... }

Action Annotation

The @Action annotation does two main things:

  1. flags an action operation to be used by the status machine
  2. provides display information to control display in the facelet (see below)

Facelet

  • The entity CRUD View and Edit facelet extends entity-template.xhtml
  • Links to the transition actions are displayed based on the status of the entity.
	<tt:sidebar-panel label="Workflow" rendered="#{not empty statusActions}">

		<ui:repeat value="#{statusActions}" var="action">
			<li>
				<a4j:htmlCommandLink
					value="#{action.label}"
					title="#{action.title}"
					rendered="#{action.rendered}"
					disabled="#{action.disabled}"
					action="#{editor[action.value]}">
					<s:conversationId/>
				</a4j:htmlCommandLink>
			</li>
		</ui:repeat>

	</tt:sidebar-panel>