Skip to main content

Context

Context is the transaction's blackboard. It flows through every participant and carries everything they need to communicate — the incoming message, the response being built, database handles, audit data, and anything else a participant wants to share with participants that run later.

Structure

public class Context implements Externalizable, Loggeable, Cloneable, Pausable {
private transient Map<Object, Object> map; // volatile, not persisted
private Map<Object, Object> pmap; // persisted to persistent-space
}

Two maps:

MapKeyPersistedUse
map (transient)Any objectNoIn-flight data: ISOSource, open DB handles, computed values
pmap (persistent)SerializableYes (if persistent-space is configured)Data that must survive a JVM crash: amounts, card data, timestamps

Put data into the persistent map with:

ctx.put("AMOUNT", amount, true);  // third arg = persist

Without the third arg (or false), data goes only to the transient map.

ContextConstants

ContextConstants is an enum of well-known keys that participants agree on:

public enum ContextConstants {
PROFILER, TIMESTAMP,
SOURCE, REQUEST, RESPONSE,
LOGEVT, DB, TX,
IRC, TXNNAME, RESULT,
MID, TID, PCODE, CARD,
AMOUNT, LOCAL_AMOUNT,
...
}

Each constant's toString() returns its name (e.g. SOURCE.toString() = "SOURCE"). Participants use the string form as the map key:

ISOMsg req  = ctx.get(REQUEST.toString());
ISOSource src = ctx.get(SOURCE.toString());
ctx.put(RESPONSE.toString(), resp);

This is a convention, not enforcement — you can use any string or object as a key. Sticking to ContextConstants for the core fields makes participants interoperable.

What IncomingListener puts in Context

When IncomingListener creates a Context for an incoming message it populates three entries:

KeyTypeContent
TIMESTAMPDateTime the message was received
SOURCEISOSourceThe channel connection — used by SendResponse to send the reply
REQUESTISOMsgThe incoming ISO message

Participants read these and add their own:

// HandleNMM adds:
ctx.put(RESPONSE.toString(), resp); // the outbound reply

// A database participant might add:
ctx.put(DB.toString(), session); // Hibernate session, etc.

Logging

ctx.log(...) appends entries to the context's internal log event, which the TM prints atomically when the transaction completes:

ctx.log("approve mti=" + resp.getMTI() + " f70=" + f70);
ctx.log(someException);

This produces the <txn> log block you see in the Q2 log:

<txn id="1" name="" rc="PREPARED" elapsed="3ms">
<handle-nmm>approve mti=2810 f70=001</handle-nmm>
</txn>

Each <participant-realm> block contains messages logged by that participant. The entire block is written once when the transaction finishes — never interleaved with output from other concurrent transactions.

Result

ctx.getResult() returns a Result object used by participants to record structured outcomes (IRC codes, inhibit flags). For the tutorial it is not used directly, but SendResponse checks ctx.getResult().hasInhibit() — if any participant has set an inhibit flag, the response is suppressed even in the commit path.