Result Override Scripts allow you to override a task's behaviour, with regards to its output result type and/or XML message. For example, if a task execution is succeeding in a certain case and you would like to force it to fail instead, a result override script can accomplish that.
Result override scripts are run after the task has finished its built-in execution logic, so they don't allow you to interrupt its normal processing. These scripts allow you to override its normal output, after that normal output has already been generated. From the perspective of downstream tasks, logs, and alerts, it is as though the task's built-in code produced the output which is the result of your override script.
You can add a result override script to any type of task. For this first example we'll use the Shell Task. The Shell Task has an output element named "commandOutput", which contains the standard output of the external program. You can use a result override script to search for a keyword in that standard output, and fail the task execution if the keyword is found. Using conventional XML DOM programming in your Jython code to access the "engine.outputDom" object, you would write a result override script such as this one:
if engine.resultType == 'success': commandOutput = engine.outputDom.getElementsByTagName('commandOutput').item(0).getFirstChild().getNodeValue() if 'error' in commandOutput: engine.fail()
The "engine.resultType" variable is defined by MD Link for all result override scripts. It will have a value of either 'success', 'cancel', 'retry', or 'fail'.
If you select the "output" XML shorthand variables (similar to the feature of the same name in the Custom Task) on this result override script using the checkbox near the top, you can simplify the script above into this one:
if engine.resultType == 'success' and 'error' in commandOutput: engine.fail()
Note that engine.outputDom and the output shorthand variables are only defined when engine.resultType == 'success'. This is because according to MD Link's architecture, tasks have no usable XML output in the 'cancel', 'retry', and 'fail' cases.
There is no rule which says that your result override script must examine the output message. For any task, not just the Shell Task, you could write a blanket override of the result type, turning all fails into cancels, for example:
if engine.resultType == 'fail': engine.resultType = 'cancel'
An alternative to the last line - engine.resultType = 'cancel'
is to write engine.cancel()
. The effect is the same.
The examples above examine the task's output message. You can also examine the task's input message. The code below checks the "stdin" element of the input message for the string "TEST_PATIENT":
if engine.resultType == 'success': stdin = engine.inputDom.getElementsByTagName('stdin').item(0).getFirstChild().getNodeValue() if 'TEST_PATIENT' in stdin: engine.fail()
If you select the "input" checkbox for XML shorthand variables, you can simplify the script above into this one:
if engine.resultType == 'success' and 'TEST_PATIENT' in stdin: engine.fail()
You can write a result override script to implement "retry" functionality:
if engine.resultType == 'fail': engine.retry(1000)
The script above will turn all failures into retries. These retries will continue indefinitely, with 1000 milliseconds between each retry. The following script, on the other hand, will limit the number of retries to 5:
if engine.resultType == 'fail': engine.retry(5, 1000)
The retry examples above specify the two retry options in the result override script: i) the number of retries and ii) the retry delay in milliseconds. Some tasks allow you to set these two retry options graphically. If you would like your result override script to use the task's graphical retry options, use this code:
engine.resultType = 'retry'
The examples above show how to turn one result type into another. You can also write a result override script that leaves the result type as it is, and modifies the content of the XML output message instead. This kind of script only applies if the result type is a success.
Below is an example of adding a "header" element to an HTTP POST Task. This script checks whether an "X-Custom-Header" element was returned by the remote web service and is in the output message already. If it isn't, this script adds one. Any task downstream of this HTTP POST Task won't be able to tell whether this header was returned by the remote web service or added by our result override script.
if engine.resultType == 'success': foundHeader = False # Loop through 'header' elements. "header" will be a list (rather than a # string) because it has multiple cardinality in the output schema for # this task. So we can write a "for" loop on "header". For this code to # work, the "output" XML shorthand variables checkbox needs to be selected. for h in header: if h.startswith('X-Custom-Header:'): foundHeader = True break if not foundHeader: # We can use XML shorthand variables to examine the default output message, # but to modify it, we need to use DOM programming: util.addXMLElement(engine.outputDom, 'header', 'X-Custom-Header: DEFAULT')
Unlike in the Custom Task, you can't use XML shorthand variables to modify the output XML message in a result override script - only to examine it. If you want to modify the output XML message, you need to write DOM code, as above. The script above uses a "util" function to simplify some of the DOM code.
Result override scripts are most useful for turning a success into a non-success ('cancel', 'retry', or 'fail'), or a non-success into a different kind of non-success. While it is technically possible to turn a non-success into a success, it is difficult to do this in a useful way. In this scenario you will need to build an output message yourself to mimic normal output, entirely in your result override script. Again, you will need to build this output message with DOM programming - not with XML shorthand variables. Here is an example of how to turn a Shell Task fail into a success, and how to build an output DOM message that mimics a real Shell Task output:
if engine.resultType == 'fail': engine.resultType = 'success' engine.outputDom = util.makeXMLDocument('ShellTaskOutput') util.addXMLElement(engine.outputDom, 'commandOutput', 'mimicking stdout') util.addXMLElement(engine.outputDom, 'commandError', 'mimicking stderr') util.addXMLElement(engine.outputDom, 'exitValue', '0')
All task types provide, at a minimum, a common API for result override scripts. This includes all of the "engine" functions provided to all task scripts. Also, the fields below are defined.
engine.resultType engine.exception engine.outputDom engine.outputDoms
In addition to the common API above, the four HTTP Tasks - GET, DELETE, POST, and PUT - provide an additional variable called "responseBodyParsedJson" when the "output" XML shorthand variables checkbox is selected.
To show how this feature works, here is a script that doesn't use it yet, but could benefit from it. It is a result override script defined on an HTTP POST Task which is expecting a JSON document such as {"status":"error"}
in the response that it gets from the remote web server. This script doesn't use any XML shorthand variables yet.
import json responseBody = util.xmlGetElementText(engine.outputDom, '/HttpPostTaskOutput/responseBody') parsedResponse = json.loads(responseBody) if parsedResponse['status'] == 'error': engine.fail('Result override script detected error in JSON response')
If you select "output" XML shorthand variables, you can remove the second line of code, because a variable called "responseBody" will already be defined. Therefore the following script is equivalent to the one above:
import json parsedResponse = json.loads(responseBody) if parsedResponse['status'] == 'error': engine.fail('Result override script detected error in JSON response')
Our next refinement to this script uses the API extension specific to the HTTP Tasks. If the response body is a valid JSON document, then MD Link will define another XML shorthand variable named "responseBodyParsedJson". It is a parsed version of "responseBody". Therefore the following script is equivalent to both of the scripts above:
if responseBodyParsedJson['status'] == 'error': engine.fail('Result override script detected error in JSON response')