ChannelAdaptor Tutorial
The configuration for this tutorial lives under tutorials/channel-adaptor. From the repo root you can build/run it with:
./gradlew :tutorials:channel-adaptor:installApp
./tutorials/channel-adaptor/build/install/channel-adaptor/bin/q2
This tutorial connects to the qserver tutorial instance. Start that first:
./gradlew :tutorials:qserver:installApp
./tutorials/qserver/build/install/qserver/bin/q2
QServer vs ChannelAdaptor
QServer is the server side of a TCP connection: it binds a port and accepts incoming connections.
ChannelAdaptor is the client side: it initiates the connection to a remote host, maintains it, and bridges the channel to jPOS Space via two named queues.
The key insight is that no application code talks directly to the channel. Everything goes through Space queues. The ChannelAdaptor owns the connection; the rest of your application is just a producer/consumer of messages on those queues.
The Space Bridge
The adaptor exposes two Space queues, configured via the <in> and <out> elements:
| Element | Direction | Description |
|---|---|---|
<in> | Application → Channel | Messages your application wants to send to the remote host |
<out> | Channel → Application | Messages received from the remote host |
Any component in your Q2 system can participate: put an ISOMsg onto the in queue to send it; read from the out queue to process what arrived. No direct channel handle required. This decoupling is what makes it easy to add multiplexers, transaction managers, or monitoring components later without touching the connection layer.
Channel Adaptor XML descriptor
In src/dist/deploy add a file 10_channel.xml:
<channel-adaptor name="upstream" logger="Q2">
<channel class="org.jpos.iso.channel.XMLChannel" logger="Q2">
<property name="packager" value="org.jpos.iso.packager.XMLPackager"/>
<property name="host" value="${upstream.host}"/>
<property name="port" value="${upstream.port}"/>
</channel>
<in>upstream-send</in>
<out>upstream-receive</out>
<reconnect-delay>10000</reconnect-delay>
<keep-alive>no</keep-alive>
</channel-adaptor>
Key elements
name— registers the adaptor inNameRegistrarunder this name. Other components can look it up withNameRegistrar.get("upstream").<channel>— the underlyingISOChannelimplementation. Accepts the same attributes as when used standalone:class,packager,host,port, and any<property>children. Host and port here usecfg/default.ymlsubstitution.<in>/<out>— Space queue names. Choose names that reflect the logical peer, not the channel implementation (e.g.upstream-send/upstream-receiverather thanxmlchannel-in/xmlchannel-out).<reconnect-delay>— milliseconds to wait before attempting a reconnect after a disconnection. Defaults to10000if omitted.<keep-alive>— whenyes, theSenderthread sends a keep-alive probe to detect stale connections. See the Sender/Receiver deep dive for details.
Edit cfg/default.yml
upstream:
host: localhost
port: 10000
These values are injected via jPOS Environment substitution (${upstream.host}, ${upstream.port}).
Build and Run
./gradlew :tutorials:channel-adaptor:installApp
./tutorials/channel-adaptor/build/install/channel-adaptor/bin/q2
With the qserver tutorial already running on port 10000, you should see the adaptor connect:
<log realm="upstream" at="2024-09-26T15:30:00.123456">
<info>
connected to localhost:10000
</info>
</log>
The adaptor is now waiting for messages on the upstream-send Space queue, and will deliver anything received from the server onto upstream-receive. The next section covers exactly how that waiting — and recovering from failures — is implemented.