Pattern 17 (Interleaved Parallel Routing)

If you start a pure OpenWFE concurrence, current workitems will be sent to each branch. If each branch corresponds to a participant, OpenWFE cannot warranty that a participant will react before another. Thus implementing this pattern would be very difficult. It's possible, but let's first look at an alternative, showing the flexibility and the 'many possible paths' to implementation of a business process.

Outside of the engine scope and the process definition expressiveness, there is a possibility to have the desired effect : the worklist component requires to have a lock on a workitem in order to edit / proceed it.


    <process-definition name="entry-test">
        <sequence>
            <participant ref="testers" />
            <if>
                <not>
                    <and>
                        <equals field-value="physical_test" other-value="true" />
                        <equals field-value="medical_test" other-value="true />
                    </and>
                </not>
                <!-- then -->
                <subprocess ref="entry-test" />
            </if>
        </sequence>
    </process-definition>

The worklist for this process definition would have at least two users : the "physical-tester" and the "medical-tester". They would share the same workitem store. The first to grab the item would perform the tests with the candidate. The workitem would come back to the workitem store as long as both tests haven't been performed. This isn't 'routing' but it's elegant.

But there is a better way to implement IPR with OpenWFE.


    <concurrence>
        <when>
            <undefined variable-value="/mutex" />
            <!-- then -->
            <sequence>
                <set variable="/mutex" value="set" />
                <participant ref="physical-tester" />
                <unset variable="/mutex" />
            </sequence>
        </when>
        <when>
            <undefined variable-value="/mutex" />
            <!-- then -->
            <sequence>
                <set variable="/mutex" value="set" />
                <participant ref="medical-tester" />
                <unset variable="/mutex" />
            </sequence>
        </when>
    </concurrence>

Put your favourite 'when' on top of the concurrence list. This snippet takes advantage of the '/' variable feature. This slash indicates that the variable has to be set at the root of the flow definition, being thus available for every expression under it.

Or even better, with function tsm() (Test and Set Mutex) put to a good use :


    <concurrence>
    
	<when>
	    <equals value="${c:tsm('/mutex')}" other-value="true" />
	    <sequence>
		<participant ref="role-alpha" />
		<unset variable="/mutex" />
	    </sequence>
	</when>

	<when>
	    <equals value="${c:tsm('/mutex')}" other-value="true" />
	    <sequence>
		<participant ref="role-bravo" />
		<unset variable="/mutex" />
	    </sequence>
	</when>

    </concurrence>

Yet another way of implementing this (see http://is.tm.tue.nl/research/patterns/download/swf/pat_17.swf) :


    <sequence>

        <participant ref="a" />

        <iterator
            on-value="${call:shuffle('b, c, d')}"
            to-variable="p"
        >
            <participant ref="${p}" />
        </iterator>

        <participant ref="e" />

    </sequence>

This example uses a function named 'shuffle', which randomly reorders a list (here 'b, c, d'). The decision in this implementation is left to the flow engine, it decides (randomly) which participant receives the workitem (in sequence, it's not a concurrent-iterator).

The most elegant way of applying this pattern 17 is by using the 'interleaved' expression (the section called “interleaved”). The vanilla pattern example would become :


    <sequence>

        <participant ref="a" />

        <interleaved>
            <participant ref="b" />
            <participant ref="c" />
            <participant ref="d" />
        </interleaved>

        <participant ref="e" />

    </sequence>

Where the interleaved expression would take care of executing only one of its chld at a time. The order of execution is randomly chosen.