Table of Contents |
---|
Overview
FIXEdge/J provides an ability to store information in the memory for purposes of message enrichment during the routing process. This functionality is based on a key-value storage.
While processing a message from one endpoint to another, FIXEdge/J may store any information in the storage and then retrieve it while routing in the opposite direction.
Advantages: storing data in-memory confers performance advantages.
Disadvantages: FIXEdge/J will lose all stored information on restart.
Configuration
There are several methods in the Groovy rules that can be used for this functionality:
Method name | Methods signature | Description | Example | ||
---|---|---|---|---|---|
saveContext | Object saveContext(Object key, Object value) | Associates the specified value with the specified key in this storage. If the storage previously contained a mapping for the key, the old value is replaced by the specified value. Params:
Returns:
|
or
| ||
removeContext | Object removeContext(Object key) | Removes the mapping for the key from the given storage if it is present. The storage will not contain a mapping for the specified key once the call returns. Params:
Returns:
|
| ||
getContext | Object getContext(Object key) | Returns the value to which the specified key is mapped, or NULL if this map contains no mapping for the key. Params:
Returns:
|
| ||
cleanContext | void cleanContext(Predicate<Map.Entry<Object, Object>> consumer) | Removes entries from context according to the provided predicate. |
|
Examples
ClOrdID replacement
Business case: Broker should replace the identificators provided by the Clients to the IDs corresponding to Exchange's requirements and format.
...
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
[ rule("Identificator_Order") //Condition block .condition({ ctx -> def msg = ctx.getMessage() //Apply rule for the messages with DeliverToCompID = Exchange return msg.isTagExists(Header.DeliverToCompID) && msg.getTagValueAsString(Header.DeliverToCompID) == "Exchange" }) //Action block .action({ ctx -> def msg = ctx.getMessage() //Get values from the tags DeliverToCompID (128) and SenderCompID (49) def destination = msg.getTagValueAsString(Header.DeliverToCompID) def senderCompID = msg.getTagValueAsString(Header.SenderCompID) //Get the full date from the tag TransactTime (60) for using in the message def fullDate = msg.getTagValueAsString(60) //Get the date only from the tag TransactTime (60) for storing in the context def dateOnly = fullDate.substring(0, 8) try { //Replace OrigClOrdID (41) with the unique generated ID from the context //The order and replace should have the same date (or date should be excluded from the key) if (msg.isTagExists(41)) { def origClOrdID = msg.getTagValueAsString(41) def origId = senderCompID+origClOrdID+dateOnly logger.info("I transformed ID, {}", origId) def savedContext = getContext(origId) msg.set(41, savedContext.get("generatedID")) } //Replace ClOrdID (11) with the unique generated ID and store it into the context if (msg.isTagExists(11)) { def uniqueId = generateUniqueId() def clOrdId = msg.getTagValueAsString(11) logger.info("I saved the following: '{}' by the following key: '{}'", [49: senderCompID, 11: clOrdId, 60: dateOnly], uniqueId) saveContext(uniqueId, [49: senderCompID, 11: clOrdId, 60: dateOnly]) def id = senderCompID+clOrdId+dateOnly saveContext(id, ["generatedID": uniqueId]) logger.info("I saved the following: '{}' by the following key: '{}'", ["generatedID": uniqueId], id) msg.set(11, uniqueId) } //Use values from the tags DeliverToCompID (128) and SenderCompID (49) for routing msg.set(Header.OnBehalfOfCompID, senderCompID) send(routingContext, ctx, destination) } catch (all) { logger.error(all.getMessage(), all) routingContext.sendReject(ctx.getSourceParams(), ctx.getMessageEvent(), "Cannot process the message") } ctx.exit() }) .build(), rule("Identificator_Report") //Condition block .condition({ ctx -> def msg = ctx.getMessage() //Apply rule for the messages with DeliverToCompID contains 'Client' return msg.isTagExists(Header.DeliverToCompID) && msg.getTagValueAsString(Header.DeliverToCompID).matches("Client.*") }) //Action block .action({ ctx -> def msg = ctx.getMessage() //Get values from the tags DeliverToCompID (128) and SenderCompID (49) def destination = msg.getTagValueAsString(Header.DeliverToCompID) def senderCompID = msg.getTagValueAsString(Header.SenderCompID) try { //Replace OrigClOrdID (41) with the original identifier received from the Client if (msg.isTagExists(41)) { def uniqueOrigClOrdID = msg.getTagValueAsString(41) def savedOrigContext = getContext(uniqueOrigClOrdID) msg.set(41, savedOrigContext.get(11)) } //Replace ClOrdID (11) with the original identifier received from the Client if (msg.isTagExists(11)) { def uniqueClOrdId = msg.getTagValueAsString(11) def savedContext = getContext(uniqueClOrdId) def clientID = savedContext.get(11) msg.set(11, clientID) if ((msg.getTagValueAsString(39) == "2")||(msg.getTagValueAsString(39)=="4")||(msg.getTagValueAsString(39)=="8")||(msg.getTagValueAsString(39)=="C")||(msg.getTagValueAsString(39)=="5")){ logger.info("I received ER filled, {}", uniqueClOrdId) removeContext(uniqueClOrdId) def removedContext = getContext(uniqueClOrdId) def fullDate = msg.getTagValueAsString(60) def dateOnly = fullDate.substring(0, 8) def id = destination+clientID+dateOnly removeContext(id) msg.set(58, String.valueOf(removedContext)) } } //Use values from the tags DeliverToCompID (128) and SenderCompID (49) for routing msg.set(Header.OnBehalfOfCompID, senderCompID) send(routingContext, ctx, destination) } catch (all) { logger.error(all.getMessage(), all) routingContext.sendReject(ctx.getSourceParams(), ctx.getMessageEvent(), "Something's not quite right") } ctx.exit() }) .build(), //Add other rules getRejectionRule(routingContext) ] |
Saving/updating data
Code Block | ||||
---|---|---|---|---|
| ||||
... def senderCompID = msg.getTagValueAsString(49) def clOrdId = msg.getTagValueAsString(11) def uniqueId = generateUniqueId() saveContext(uniqueId, [49: senderCompID, 11: clOrdId]) msg.set(11, uniqueId) //route message ... |
Getting/removing data
Code Block | ||||
---|---|---|---|---|
| ||||
... def uniqueId = msg.getTagValueAsString(11) def savedContext = getContext(uniqueId) removeContext(uniqueId) msg.set(11, savedContext.get(11)) msg.set(56, savedContext.get(49)) //route message ... |
Saving repeating group
Code Block | ||||
---|---|---|---|---|
| ||||
... def map = [:] def numberOfEntries = msg.getTagAsInt(453) map["NoPartyIDs"] = numberOfEntries for (int i = 1; i <= numberOfEntries; i++) { map["PartyID" + i] = msg.getTagValueAsString(448, i) map["PartyIDSource" + i] = msg.getTagValueAsString(447, i) map["PartyRole" + i] = msg.getTagValueAsString(452, i) } numberOfEntries = msg.getTagAsInt(604) map["NoLegSecurityAltID"] = numberOfEntries for (int i = 1; i <= numberOfEntries; i++) { map["LegSecurityAltID" + i] = msg.getTagValueAsString(605, i) map["LegSecurityAltIDSource" + i] = msg.getTagValueAsString(606, i) } saveContext(uniqueId, map) ... |
Getting repeating group
Code Block | ||||
---|---|---|---|---|
| ||||
... def savedMap = getContext(uniqueId) def numberOfEntries = savedMap["NoPartyIDs"] msg.set(453, numberOfEntries); for (int i = 1; i <= numberOfEntries; i++) { msg.addTag(448, savedMap["PartyID" + i]) msg.addTag(447, savedMap["PartyIDSource" + i]) msg.addTag(452, savedMap["PartyRole" + i]) } numberOfEntries = savedMap["NoLegSecurityAltID"] msg.set(604, numberOfEntries); for (int i = 1; i <= numberOfEntries; i++) { msg.addTag(605, savedMap["LegSecurityAltID" + i]) msg.addTag(606, savedMap["LegSecurityAltIDSource" + i]) } ... |