9. Flow Inheritance

9.1. Introduction

Flow inheritance allows one flow to inherit the configuration of another flow. Inheritance can occur at both the flow and state levels. A common use case is for a parent flow to define global transitions and exception handlers, then each child flow can inherit those settings.

In order for a parent flow to be found, it must be added to the flow-registry just like any other flow.

9.2. Is flow inheritance like Java inheritance?

Flow inheritance is similar to Java inheritance in that elements defined in a parent are exposed via the child, however, there are key differences.

A child flow cannot override an element from a parent flow. Similar elements between the parent and child flows will be merged. Unique elements in the parent flow will be added to the child.

A child flow can inherit from multiple parent flows. Java inheritance is limited to a single class.

9.3. Types of Flow Inheritance

9.3.1. Flow level inheritance

Flow level inheritance is defined by the parent attribute on the flow element. The attribute contains a comma separated list of flow identifiers to inherit from. The child flow will inherit from each parent in the order it is listed adding elements and content to the resulting flow. The resulting flow from the first merge will be considered the child in the second merge, and so on.

<flow parent="common-transitions, common-states">
			

9.3.2. State level inheritance

State level inheritance is similar to flow level inheritance, except only one state inherits from the parent, instead of the entire flow.

Unlike flow inheritance, only a single parent is allowed. Additionally, the identifier of the flow state to inherit from must also be defined. The identifiers for the flow and the state within that flow are separated by a #.

The parent and child states must be of the same type. For instance a view-state cannot inherit from an end-state, only another view-state.

<view-state id="child-state" parent="parent-flow#parent-view-state">
			
[Note]Note

The intent for flow-level inheritance is to define common states to be added to and shared among multiple flow definitions while the intent for state-level inheritance is to extend from and merge with a single parent state. Flow-level inheritance is a good fit for composition and multiple inheritance but at the state level you can still only inherit from a single parent state.

9.4. Abstract flows

Often parent flows are not designed to be executed directly. In order to protect these flows from running, they can be marked as abstract. If an abstract flow attempts to run, a FlowBuilderException will be thrown.

<flow abstract="true">
		

9.5. Inheritance Algorithm

When a child flow inherits from it's parent, essentially what happens is that the parent and child are merged together to create a new flow. There are rules for every element in the Web Flow definition language that govern how that particular element is merged.

There are two types of elements: mergeable and non-mergeable. Mergeable elements will always attempt to merge together if the elements are similar. Non-mergeable elements in a parent or child flow will always be contained in the resulting flow intact. They will not be modified as part of the merge process.

[Note]Note

Paths to external resources in the parent flow should be absolute. Relative paths will break when the two flows are merged unless the parent and child flow are in the same directory. Once merged, all relative paths in the parent flow will become relative to the child flow.

9.5.1. Mergeable Elements

If the elements are of the same type and their keyed attribute are identical, the content of the parent element will be merged with the child element. The merge algorithm will continue to merge each sub-element of the merging parent and child. Otherwise the parent element is added as a new element to the child.

In most cases, elements from a parent flow that are added will be added after elements in the child flow. Exceptions to this rule include action elements (evaluate, render and set) which will be added at the beginning. This allows for the results of parent actions to be used by child actions.

Mergeable elements are:

  • action-state: id

  • attribute: name

  • decision-state: id

  • end-state: id

  • flow: always merges

  • if: test

  • on-end: always merges

  • on-entry: always merges

  • on-exit: always merges

  • on-render: always merges

  • on-start: always merges

  • input: name

  • output: name

  • secured: attributes

  • subflow-state: id

  • transition: on and on-exception

  • view-state: id

9.5.2. Non-mergeable Elements

Non-mergeable elements are:

  • bean-import

  • evaluate

  • exception-handler

  • persistence-context

  • render

  • set

  • var