Page tree
Skip to end of metadata
Go to start of metadata

Overview

FIXEdge/J provides the 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 nameMethods signatureDescriptionExample
saveContextObject saveContext(Object key, Object value)

Associates the specified value with the specified key in this storage. If the storage previously contained mapping for the key, the old 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)

removeContextObject removeContext(Object key)

Removes the mapping for the key from the given storage if it is present.

The storage will not contain mapping for the specified key once the call returns.

Params:

  • key – the key whose 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)

getContextObject 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 whose 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)

cleanContextvoid cleanContext(Predicate<Map.Entry<Object, Object>> consumer)Removes entries from 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.


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

rules.groovy
...
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])
}
...
  • No labels