Skip to main content

check-enabled and LogonManager Integration

The problem

QMUX.isConnected() returns true as soon as the TCP connection is up — before any logon has taken place. In a production environment, a connected-but-not-logged-on link must not receive financial transactions. Without a logon gate, the pool would route traffic to a fresh connection before LogonManager has had a chance to complete the sign-on sequence.

check-enabled bridges this gap: a MUX is only considered usable by the pool after LogonManager explicitly marks it as enabled.

The enabled semaphore

When check-enabled=true is set on MUXPool, isUsable() runs this check for each candidate MUX:

String enabledKey = qmux.getName() + ".enabled";   // e.g. "upstream-a.enabled"
String readyKey = qmux.getReadyIndicatorNames()[0]; // e.g. "upstream-a.ready"

return mux.isConnected()
&& sp.rdp(enabledKey) == sp.rdp(readyKey); // reference equality!

Two conditions must both be true:

  1. The QMUX's own isConnected() — the ready semaphore is present in Space.
  2. The enabled key holds the exact same object reference as the ready key.

The == comparison is object reference equality, not .equals(). This is intentional and crucial to the design.

Why reference equality?

ChannelAdaptor publishes the ready semaphore as:

sp.out(ready, new Date());   // a new Date instance on every connect

TSpace stores object references. When LogonManager reads the ready semaphore and stores it under enabled:

Object sessionId = sp.rd(readyKey, 60000);   // same Date reference from TSpace
// ...after successful logon...
sp.out(enabledKey, sessionId); // same reference stored in enabled

Both sp.rdp(enabledKey) and sp.rdp(readyKey) now return the same in-memory Date object → == is true → MUX is usable.

On reconnect, ChannelAdaptor creates a brand-new Date:

ready   →  Date@7b3a4e9f  (new)
enabled → Date@4c2d8b12 (old, from previous session)

Date@7b3a4e9f == Date@4c2d8b12 is false → MUX is not usable → LogonManager must re-logon before traffic flows again.

This is the same reconnect detection mechanism used by LogonManager's own logonRequired() check — both rely on the identity of the Date object that ChannelAdaptor puts in Space.

LogonManager integration

With check-enabled=true, LogonManager's doLogon() adds one step after a successful logon:

private void doLogon(Object sessionId) throws ISOException {
ISOMsg resp = mux.request(buildMsg(logonTemplate), timeout);
if (resp != null && "0000".equals(resp.getString(39))) {
sp.inp(logonKey);
sp.out(logonKey, sessionId, logonInterval);

if (checkEnabled) {
sp.inp(enabledKey);
sp.out(enabledKey, sessionId); // ← same object, no TTL
}
getLog().info("Logon OK — " + muxName);
}
}

Note that enabledKey is stored without a TTL. It lives until explicitly removed. This is intentional: if the logon session is still valid (the ready semaphore hasn't changed) the link should remain enabled even after logon-interval elapses — the LogonManager will re-logon and refresh the entry before it matters.

doLogoff() removes enabledKey first, before sending the logoff message, so the pool stops routing to this link immediately:

private void doLogoff() throws ISOException {
sp.inp(logonKey);
if (checkEnabled)
sp.inp(enabledKey); // ← pool sees it as unavailable immediately
mux.request(buildMsg(logoffTemplate), timeout);
}

Full lifecycle with check-enabled

The window during which the pool skips a reconnecting link is exactly the time between ChannelAdaptor publishing the new ready semaphore and LogonManager completing re-logon. No additional coordination is required — the pattern emerges from the shared Space.