UML: Sequence, Activity & State Diagrams

Composite States & History

18 min Lesson 8 of 10

Composite States & History

The state machine diagrams you studied in the previous lesson model each behavior as a flat set of named states with transitions between them. That works perfectly for simple objects. Real systems, however, often contain states that are themselves complex enough to deserve their own internal structure. A clinic appointment is not just "Active" — while Active it is either waiting for confirmation, confirmed, or in progress. Flattening those sub-states into the outer diagram would force you to duplicate every transition that exits the Active group, resulting in a tangled, unreadable chart.

Composite states solve this by letting you nest a complete sub-machine inside a single rounded rectangle. They are the UML equivalent of a folder: the outer state gives a name to the group, and the inner states capture the detail. Combined with history pseudo-states — which remember where a machine was before an interruption — composite states let you model sophisticated real-world workflows cleanly and precisely.

Anatomy of a Composite State

A composite state looks exactly like a regular state (rounded rectangle with the name at the top) but contains one or more inner states, their own initial pseudo-state, and their own transitions drawn inside the outer boundary. The rules are:

  • Every composite state has exactly one initial pseudo-state inside it (the filled circle), showing which sub-state is entered by default.
  • Transitions from outside the composite state that target the composite state itself enter via its default initial sub-state.
  • Transitions that originate from inside a sub-state and exit the composite boundary are called exit transitions; they leave regardless of which sub-state the machine is currently in.
  • A composite state may have an optional entry action (runs whenever the state is entered) and an exit action (runs whenever it is left), written as entry / action() and exit / action() inside the state box.
Entry and exit actions are inherited by all sub-states. If the outer state has entry / startTimer(), that action fires every time the machine enters any path into the composite state — whether via the default initial sub-state or via a direct transition targeting a specific sub-state.

Example 1 — Online Order Lifecycle

Consider an online store order object. At the top level it can be Pending, Processing, Shipped, or Cancelled. The Processing state is itself composite: internally the order moves through Payment Verification, Warehouse Picking, and Packed before it transitions to Shipped. An emergency cancel event can exit Processing at any sub-state, triggering a single exit / releaseInventory() action.

Composite state — online order lifecycle Pending entry / notifyCustomer() Processing entry / reserveInventory() exit / releaseInventory() Payment Verification Warehouse Picking paymentOK Packed pickingDone Shipped entry / sendTrackingNo() packed / dispatch() Cancelled cancel [any sub-state] orderPlaced delivered
Figure 1 — The Processing composite state nests three sub-states. A single cancel exit transition leaves from any sub-state; exit / releaseInventory() always fires when leaving Processing.

Entry and Exit Actions in Depth

Every state — simple or composite — may declare up to three kinds of internal behavior:

  • entry / action() — executes once when the state is entered, regardless of which transition brought the machine here.
  • do / activity() — a continuous activity that runs while the machine stays in the state and is automatically interrupted when the state is exited.
  • exit / action() — executes once when the state is left, regardless of which transition fires to cause the exit.

For a composite state these behaviors apply to the boundary crossing, not to the internal transitions. When the order in the example above moves from Payment Verification to Warehouse Picking, neither the composite entry nor exit action fires — because the machine is still inside Processing. Only when a transition crosses the outer boundary does releaseInventory() run.

Analyst use: Entry and exit actions are the right place to capture mandatory side-effects that business rules require every time a state is entered or left — sending a notification, updating a timestamp, releasing a lock. Model them explicitly rather than scattering them across individual transitions.

History Pseudo-States

Imagine a library member who is mid-way through renewing a book online. The session times out and the member is forced back to the Login state. When they log in again, should the system restart the renewal workflow from the beginning, or resume exactly where the member left off?

UML answers this with the history pseudo-state. It is drawn as a small circle containing the letter H inside the composite state. When a transition targets the history pseudo-state instead of the composite state itself, the machine re-enters the sub-state that was active when the composite state was last exited. If the composite state has never been entered before, the machine falls through to a designated default transition.

There are two variants:

  • Shallow History (H) — remembers only the directly nested sub-state at the level of the composite state. Inner composite states within that sub-state are re-entered via their own default initial pseudo-state.
  • Deep History (H*) — remembers the exact active configuration at all nesting levels, resuming the most deeply nested active sub-state.
Deep history creates tight coupling. In practice, use H* only when the business requirement explicitly demands resumption at the deepest level. Shallow history covers the majority of real-world resume scenarios and is much easier for stakeholders to understand.

Example 2 — Library Renewal Workflow with History

The diagram below models a library self-service kiosk. The machine has three top-level states: Idle, Session (composite), and Timeout. Inside Session the member progresses through Authenticate, Select Book, and Renew. A timeout event exits Session and pushes the machine to Timeout. When the member swipes their card again (cardSwiped), the machine targets the shallow history pseudo-state (H) inside Session, resuming from whichever sub-state was last active.

Shallow history pseudo-state — library kiosk session Idle Session entry / startSessionTimer() exit / saveProgress() Authenticate Select Book do / showCatalogue() Renew verified bookSelected H default Timeout entry / showWarning() timeout cardSwiped / resumeSession() cardSwiped renewalConfirmed
Figure 2 — The H pseudo-state inside Session resumes whichever sub-state was active when the timeout occurred. On first entry the default arrow points to Authenticate.

Reading Composite State Diagrams as an Analyst

When you encounter a composite state diagram in a specification or review, ask these questions systematically:

  1. What business concept does each composite state represent? It should map to a recognizable phase — "order being fulfilled", "session in progress", "claim under review".
  2. Which events can exit the composite regardless of internal position? These are your exception paths (cancel, timeout, escalation). Ensure every one is documented in the requirements.
  3. What do the entry/exit actions represent in business terms? Each should correspond to a concrete system action — sending a notification, logging a record, releasing a resource.
  4. Is there a resume requirement? If stakeholders say "pick up where the user left off", that is a history pseudo-state. Clarify whether shallow or deep history matches the expected behavior.
Simplification rule: If a composite state has only one sub-state, collapse it to a simple state. Composite states add value only when there are at least two distinct sub-states with meaningful transitions between them.

Summary

  • A composite state nests a complete sub-machine (initial pseudo-state, sub-states, internal transitions) inside a rounded rectangle, letting you organize complex behavior hierarchically.
  • Entry actions fire whenever the composite boundary is entered; exit actions fire whenever it is left — regardless of internal path taken.
  • An exit transition on the composite boundary triggers from any sub-state, capturing exception paths (cancel, timeout) without duplicating transitions.
  • The H (shallow history) pseudo-state resumes the last-active direct sub-state on re-entry; H* (deep history) resumes the deepest active configuration.
  • History pseudo-states model "resume where left off" requirements — common in session management, multi-step wizards, and interrupted workflows.