After all the previous lessons, you should now be able to implement most components. However, there is still a workflow element we haven't covered: Handlers.

Handlers encapsulate more complex logical modules (compared to actions). They run in the background while the workflow is executed and listen for certain events which they then process, emitting events of their own. There can only be one handler of each type in a step. Handlers do not have IDs.

There's only a small number of handlers. In this lesson, we will cover one handler that is used quite often - the value_extractor_handler.

Reading Barcodes

The value_extractor_handler validates input and extracts relevant information from the input. It is mostly used for barcode scanning and sometimes for speech commands. You will need to provide a regular expression (regex) that regulates which type of input is valid and also defines which parts of the input you want to store in variables.

The following example shows what your handler definition could look like.

Example

<step ...>
    <handlers>
        <value_extractor_handler pattern="(?:(?:ADD|PLUS\s)(?:((\d{1,2})\sTIMES\s(\d{1,2}))|(\d{1,3})))|(\d{8,12})|(S([1-7])R([1-4]))|(B#[A-F0-9]{12})|(EXIT))">
            <grp>
                <param name="grp_1" type="string">add_mutiplication</param>
                <param name="grp_2" type="string">add_factor_1</param>
                <param name="grp_3" type="string">add_factor_2</param>
                <param name="grp_4" type="string">add</param>
                <param name="grp_5" type="string">serialno</param>
                <param name="grp_6" type="string">location</param>
                <param name="grp_7" type="string">shelve</param>
                <param name="grp_8" type="string">rack</param>
                <param name="grp_9" type="string">code</param>
                <param name="grp_10" type="string">exit</param>
            </grp>
        </value_extractor_handler>
    </handlers>
</step>

If you're familiar with regular expressions, there is nothing new here. Each group you create using () will be captured in a step variable. You can ignore groups that you need to create to express "or" by using ?:. Let's take the regex apart:

(?:(?:ADD|PLUS\s)(?:(           grp_1: e.g #{add_multiplication} == "10 Times 5"
        (\d{1,2})\sTIMES\s      grp_2: e.g. #{add_factor_1} == "10"
        (\d{1,2}))|             grp_3: e.g. #{add_factor_2} == "5"
    (\d{1,3})))|                grp_4: e.g. #{add} == "255"
(\d{8,12})|                     grp_5: e.g. #{serialno} == "123456789"
(S                              grp_6: e.g. #{location} == "S5R2"
    ([1-7])R                    grp_7: e.g. #{shelve} == "5"
    ([1-4]))|                   grp_8: e.g. #{rack} == "2"
(B#[A-F0-9]{12})|               grp_9: e.g. #{code} == "B#ABCDEF123456
(EXIT))                         grp10: #{exit} == "EXIT"

You have defined different code types that can be scanned in the current step. Whenever a particular type of code is scanned, the variables of the other types will be undefined. For example, if you scan "PLUS 10 TIMES 5", the variables for groups 1-3 will have content but the rest will be undefined. Therefore, your rules should check whether the variable exists. You can check the handler documentation to see which events are emitted. You can see some example rules for the processing below:

<onevent>
    <rule id="location_scanned">
        <expression><![CDATA[ #{event(value_extractor):command} == 'VALID_EXTRACTION' && exists(#{shelve}) && exists(#{rack}) ]]></expression>
        <actions>
            <setvar id="set_loction">
                <context_of>workflow</context_of>
                <context_update>
                    <param name="shelve" type="long">#{shelve}</param>
                    <param name="rack" type="long">#{rack}</param>
                </context_update>
            </setvar>
        </actions>
    </rule>

    <rule id="invalid_input">
        <expression><![CDATA[ #{event(value_extractor):command} == 'INVALID_EXTRACTION' ]]></expression>    
        <actions>
            <ui_notification id="invalid_codeer" type="ERROR" duration="SHORT" show_immediately="true">
               <message>"#{event:payload.code}" is not valid!</message>
            </ui_notification>
        </actions>
    </rule>
</onevent>

📌Assignment

If you have an external barcode scanner available, it is worth your time to try value_extractor_handler out.

  • Enable the user to scan barcodes to make their choice.
  • Add a new configuration input field to each option for the expected barcode value (for example the worker could scan a barcode on a box of apples containing the product code 123456).
  • Perform some test scans.

 Download Workflow (Pre-Assignment)

Solution

 Download Workflow (Post-Assignment)