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
.
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.
<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>
If you have an external barcode scanner available, it is worth your time to try value_extractor_handler
out.
Download Workflow (Pre-Assignment)