In-memory data context

In-memory data context

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: in-memory data storing 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

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 former value is replaced by the specified value.

 

Params:

  • key – the key with which the specified value is to be associated

  • value – the value to be associated with the specified key

Returns:

  • the previous value associated with the key, or NULL if there was no mapping for the key

 

def senderCompID = msg.getTagValueAsString(49)
def clOrdId = msg.getTagValueAsString(11)
def uniqueId = generateUniqueId()
saveContext(uniqueId, [49: senderCompID, 11: clOrdId])

or

def senderCompID = msg.getTagValueAsString(49)
def clOrdId = msg.getTagValueAsString(11)
def uniqueId = generateUniqueId()
saveContext(uniqueId + 49, senderCompID)
saveContext(uniqueId + 11, clOrdId)

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:

  • key – the key which mapping is to be removed from the storage

Returns:

  • the previous value associated with the key, or NULL if there was no mapping for the key

def uniqueId = msg.getTagValueAsString(11)
removeContext(uniqueId)

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:

  • key – the key with which the associated value is to be returned

Returns:

  • the value to which the specified key is mapped, or NULL if this map contains no mapping for the key

def uniqueId = msg.getTagValueAsString(11)
def savedContext = getContext(uniqueId)
msg.set(11, savedContext.get(11))

or

 

def uniqueId = msg.getTagValueAsString(11)
def savedId = getContext(uniqueId + 11)
msg.set(11, savedId)

cleanContext

void cleanContext(Predicate<Map.Entry<Object, Object>> consumer)

Removes entries from the context according to the provided predicate.

cleanContext({entry -> entry.getKey() == "orderId"})

Examples

ClOrdID replacement

Business case: Broker should replace the identificators provided by the Clients to the IDs corresponding to Exchange's requirements and format.

 

[ 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

rules.groovy
... 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

rules.groovy
... 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

rules.groovy