Message
The message binding is a "GroovyMessage" object. The GroovMessage class is a convenience class that wraps the standard GatewayMessage class, which in turn wraps json object. The message object is not a map, and fields cannot be accessed using the Groovy dot notation for getters. In order to use the map notation, use asMap() as follows:
messageMap=message.asMap()
messageMap.incident.description
Tip: to avoid null pointer exceptions in Groovy, you can use “Safe navigation”:
messageMap.incident?.description
In this case, if the message does not contain a structure called “incident”, the expression returns null instead of throwing an exception. In combination with the Groovy Elvis operator, this can be used to assign a default value like this:
def description = messageMap.incident?.description :? "A default description"
For more detail see http://www.groovy-lang.org/operators.html#_safe_navigation_operator
To access the message directly, use get and put with the slash notation:
message.get("incident/description")
message.put("incident/description","The crossbeam has gone out of skew on the treddle")
Method | Purpose | Example |
changed(key) | To determine whether a certain key in the message has changed since the last time this message was processed. Looks across the entire life of the message. | if (message.changed(“/ticket/priority”) escalate(); |
changed() | Returns true if anything has changed in the message since it was seen last time. | |
previous() | Returns the message as seen last time it was processed |
|
put(key,value) | Add or replace a part of the message | if (message.changed(“/ticket/priority”)) message.put(“/ticket/newnote”,”The priority has changed from “+previous().ticket.priority+” to “+message.ticket.priority); |
putJson(key,value) | Parse and insert a json structure into the message | |
headers() | Returns a map of all the message headers. | |
getId() | Returns the id of the object that this message represents. | |
findIdmap(endpoint) | Returns the id map entry for this message and the specified endpoint | |
addIdmap(endpoint,id) | Records an ID mapping for this message and the specified endpoint/id pair. | |
discard() | Discard this message (only used in mappings) | if (message.value==null) message.discard() |
updates(messagetype) | Returns a nested map that contains all inserted, updated and deleted fields of the message. Only processes the message of type messagetype. The resulting map contains an entry for each field, in the same place where that field appears in the message, with a structure containing action=insert/update/delete and the before and after values where applicable. | |
updates() | Same as updates(message.headers().message_type) | |
getMessages() | Returns the messages inside this message. In case of a bulk message, they are the individual messages. In case of a mapped message, they are the messages before and after each mapper. | |
toJson() | Returns the message content as a Json string | |
asMap() | Returns the message content as a map |
Iterating over message content
There are two ways of iterating over a message: using a regular expression in the “from” field of a mapping, or using the Groovy “each()” method on the map representation of the message. The examples in this section use a Groovy poller that retrieves data from the WHO listing average life expectancy by country:
http=option.http
ret=http.get("https://apps.who.int/gho/athena/api/GHO/WHOSIS_000001?format=json")
api.publish(ret,"WhoMessage",false)
return null
Using a regular expression
When you define a mapping with a regular expression and a capture group in the “from” field, the mapping will be executed once for each matching result, automatically iterating over the result set. In the mapping itself, the content of the current branch (the part of the message referenced by the matching from field) is made available as “curnode”. In this example, we basically add a country code lookup table to the message.
Using Groovy each()
message.asMap().dimension.each() { dim ->
dim.code.each() { code ->
message.put("Lookup/"+dim.label.textValue()+ "/" + code.label.textValue(),code.display.textValue())
}
}
In this second example, there are two nested iterations to create a lookup table not just for countries, but for all dimensions of the data.
CAUTION: The iterator function each() only works on arrays. If a certain part of the message should be an array but isn’t, you can easily convert it into an array by using the “Convert object node to array” mapping before processing it in Groovy.
CAUTION: The closure parameter of the each() operator (dim and code in the example) represent Jackson JsonNode objects. To turn them into scalar values, use the textValue(), intValue() or doubleValue() methods.
Another example of Groovy each()
In the following example we poll a URL to search for issues from Jira. For each ticket we get the issue details by getting each issue individually.
// search for tickets
query = "updated>='"+lasttime+"' AND project=TEST order by updated ASC"
query = java.net.URLEncoder.encode(query, "UTF-8")
url = "https://faciligate.atlassian.net/rest/api/2/search?jql=" + query
option.http.content("application/json")
option.http.useAuth("jira")
ticketsres=option.http.get(url)
// parse the response as messages
msgs = api.parse(ticketsres,msgtype, true)
// iterate over messages
msgs.extractMessages().each() { m ->
// set message id to GET the message
m.headers().set("idlocation","key")
url = "https://faciligate.atlassian.net/rest/api/2/issue/" + m.getId()
extendedTicketStr=option.http.get(url)
resMap = parser.asMap(extendedTicketStr)
// parse the response as message
msg = api.parse(parser.asJson(resMap),msgtype, false)
// publish each mesage
api.publish(msg)
}
Headers
The following headers can be manipulated using message.headers().set(headername,value). You can also read the current header value using message.headers().headername
Headername | Meaning | Example |
plugin | Plugin name in the origin header | set(“plugin”,”Ivanti poller”) |
product | Product name in origin header | set(“product”,”Ivanti”) |
endpoint | Endpoint in origin header | set(“endpoint”,”IvantiProd”) |
idlocation | The pointer to the id in the message | set(“idlocation”,”/incident/identifier/value”) |
id | The id itself | set(“id”,”MONI43985”) |
message_type | The message type | set(“message_type”,”IncomingIvantiIncident”) |
record_type | The type of object this message represents | set(“record_type”,”Incident”) |
timestamp | The message timestamp in epoch | set(“timestamp”, 1630233221) |
table | The table name where to persist this message | set(“table”,”Incidents”) |
detail | The detail to persist (0=headers only, 1=whole message) | set(“detail”,0) |
track_updates | Whether to automatically keep track of changes in this message | set(“track_updates”,true) |
persist | Whether to persist this message | set(“persist”,true) |