ADR-0029: MessageTransport, two implementations — Core for read/write fidelity, Jolokia for the rest
- Status: accepted
- Date: 2026-09-04
- Deciders: Mahdi Amirabdollahi
Context
ADR-0002 said the broker-client interface would be "extracted then, from two real implementations, not guessed up front", where then is Phase 4. ADR-0021 made Phase 3 message operations Jolokia-only and disclosed the consequence per message: the management channel stringifies bodies and truncates oversized values at management-message-attribute-size-limit, so binary payloads are unusable and the detail panel shows the broker.xml snippet that raises the limit. That disclosure was always a promissory note against the Core client.
Now the Core client exists (ADR-0026). The question is how much of the message surface gets a Core path.
Decision
Supersede ADR-0021. We will extract broker/MessageTransport with two real implementations:
JolokiaMessageTransport— a thin adapter over the existingMessageBrowserandMessageOperations, unchanged. It is the fallback and stays the well-tested path.CoreMessageTransport—browsevia a JMSQueueBrowser(real property types, real byte bodies via base64, no truncation) andsendwith typedsetXPropertyand aBytesMessagewhen the request says the body is base64.
Only browse and send get a Core path. Move / retry / delete / expire / purge are management operations addressed by id or selector; they carry no payload and have no fidelity dimension, so a Core implementation would be a second way to invoke the identical broker operation. They stay on MessageOperations. The interface covers exactly the fidelity surface.
- Selection.
MessageService.transportFor(clusterId)returnsCoreMessageTransportwhenCoreSubscriptionManager.verdictFor(clusterId)isConnected, elseJolokiaMessageTransport— reusing ADR-0026's cached verdict, opening no connection on the read path. - Deep-page honesty. A
QueueBrowserhas no server-side offset, so a page pastMessageBrowser.BROKER_PAGE_CAP(200) is served over Jolokia instead, and every browse/detail response carriestransport(CORE/JOLOKIA) — the channel that actually served it. A silent slow path breaks non-negotiable #1 as surely as a silent lossy one breaks #5. - Disclosure.
MessageDetailViewgainsbodyEncoding(TEXT/BASE64),contentType, andtransport;bodyTruncatedis always false on Core. The UI shows a "via Core" / "via Jolokia" badge and a base64/binary notice. - The safety layer is untouched. Audit, the per-node call limiter,
?dryRun, the bulk cap and typed confirmation all wrapMessageServiceabove the transport swap, so they apply identically regardless of channel. - Internal representation.
BrowsedMessage.bodystays aString(base64 when the encoding isBASE64) rather than widening tobyte[]— the observable contract at the API boundary ("bytes with an encoding indicator") is met without the ripple through every call site and test. The design doc's D9 proposedbyte[]; this is the smaller equivalent.
Consequences
- Faithful binary read and typed-property read/write when a Core connection exists; honest fallback and honest disclosure otherwise.
- Two transport implementations to keep in step, but the mutation surface is not duplicated.
- The Core browse walks the queue locally to page (no server offset); capped at the broker page size, past which it is Jolokia's problem.
- ADR-0021 is marked superseded; its decision text is not edited.
Alternatives considered
- A full Core transport including mutations — doubles the mutation surface for no fidelity gain and a second thing to keep in step.
- Widen
BrowsedMessage.bodytobyte[]— the design's first form; a much larger diff (DTO, mappers, every test) for the same observable behaviour. - No interface, a branch in
MessageService— ADR-0002 explicitly wanted the interface once two implementations existed.