Creating an ISO8583 Client using jPOS Q2

Creating an ISO8583 Client using jPOS Q2 is really simple compared to Spring Integration or Netty. Unlike both Spring Integration or Netty, jPOS is specialized messaging with ISO 8583 format. There are a bunch of utility classes and modules we can use, but please read the jPOS licence before you decide to use jPOS for commercial usage.

Ok, let’s start with the purpose of this tutorial, we are going to create an ISO8583 Client using jPOS Q2. Basically all we need to do is create a mux and channel configuration, but we should know what happens when we send a request and receive a response.

Below diagram describes the flow when we send requests using mux on jPOS Q2. We can get the mux instance by calling QMux.getMux(“my-mux-name”) and calling mux.request(reqMsg, timeout) to send a request and wait for the response. In the mux point of view, we are sending and receiving the response synchronously, but correlation happens in the queue space.

  1. When we are calling the mux.request() method, it will put the request message into configured space and wait for the response with the same message key (usually bit 11 and bit 41) until specified timeout.
  2. Channel Adaptor: On startup, Channel Adaptor will execute Sender and Receiver on background thread. Sender’s task is to poll the space to get the request message to be processed by ISO Channel and Receiver is to wait for the incoming response message.
  3. ISO Channel transforms ISOMsg object into byte array and sends transformed message to the Socket OutputStream.
  4. Socket will send the data to the wire.
  5. Sockets receive data from the wire.
  6. Channel Adaptor’s Receiver will get any incoming message, and use ISO Channel to transform a byte array into ISOMsg object.
  7. Transformed response ISOMsg will be put into the Queue Space.
  8. MUX gets the response message from the Queue Space and then returns the ISOMsg object to the Caller.

Let's get down to the code. First of all, let's put jPOS dependency to the pom.xml, there is a new jPOS version called jPOS 3.0.0, it’s required to use the latest openjdk version (java 23). This tutorial is using jPOS version 2.1.10 and java 17 (it should work with java 7 or later).

	
<dependencies>
	<dependency>
		<groupId>org.jpos</groupId>
		<artifactId>jpos</artifactId>
		<version>2.1.10</version>
	</dependency>
</dependencies>
    

For the configuration, by default jPOS will scan all xml files inside the deploy directory placed on the root folder. Then we will create 3 configuration files called 00_logger.xml, 20_client_channel.xml, and 30_client_mux.xml.

00_logger.xml is used to print the log into the file or console. Below configuration is only printing logs into the console.

	
<?xml version="1.0" encoding="UTF-8"?>
<logger name="Q2" class="org.jpos.q2.qbean.LoggerAdaptor">
	<property name="redirect" value="stdout, stderr" />
	<log-listener class="org.jpos.util.SimpleLogListener" />
	<log-listener class="org.jpos.util.BufferedLogListener">
		<property name="max-size" value="100" />
		<property name="name" value="logger.Q2.buffered" />
	</log-listener>
</logger>
    

20_client_channel.xml is used to configure the Channel Adaptor and ISO Channel. Key points to remember:

  1. Name: Channel Adaptor’s name. It can be used to get ChannelAdaptor objects programmatically by calling NameRegistrar.get(“client-channel”).
  2. Logger: set the logger name configured before.
  3. Channel class: ASCIIChannel to use 4 digit number as message length indicator.
  4. Channel packager: Packager used to pack and unpack (transforming) message bytes into ISOMsg objects.
  5. Property Host: Server Host.
  6. Property Port: Server Port.
  7. In: Space Name to get the request message.
  8. Out: Space name to put the request message.
  9. Reconnect delay: delay to reconnect to the server address.
	
<channel-adaptor name='client-channel' class="org.jpos.q2.iso.ChannelAdaptor" logger="Q2">

	<channel class="org.jpos.iso.channel.ASCIIChannel" packager="org.jpos.iso.packager.ISO87APackager" logger="Q2">
		<property name="host" value="localhost" />
		<property name="port" value="7080" />		
	</channel>

	<in>client-send</in>
	<out>client-receive</out>
	<reconnect-delay>10000</reconnect-delay>
</channel-adaptor>    
    

The last configuration is 30_client_mux.xml, key points to remember:

  1. Mux Name: name of the mux, use QMUX.getMux(“client-mux") to get the mux object programmatically.
  2. Class: Q2 will initiate QMUX on startup.
  3. Logger: Configured logger name.
  4. In: Space Name to get the response.
  5. Out: Space Name to put the request.
	
<mux name="client-mux" class="org.jpos.q2.iso.QMUX" logger="Q2">
	<in>client-receive</in>
	<out>client-send</out>
</mux>  
    

Please note that configured “in” and “out” in the 20_client_channel.xml and 30_client_mux.xml is reversed.

Testing the client:
We will use this client to send request echo messages to middleware netty server. Start Q2 by calling the Q2.start() method, this will scan all configuration files with xml extension in the deploy directory. Wait for 5 seconds, so the logger, mux, and channel is deployed. Then call mux.request(reqMsg, timeout) to send a request and wait for the response.

	
public static void main(String[] args) throws Exception {		
	Q2 q2 = new Q2();
	q2.start();
	ISOUtil.sleep(5000);
	ISOMsg isoMsg = new ISOMsg("0800");
	isoMsg.set(11, ISOUtil.getRandomDigits(new Random(), 6, 9));
	isoMsg.set(41, "T-112233");
	isoMsg.set(70, "301");

	MUX mux = QMUX.getMUX("client-mux");
	ISOMsg response = mux.request(isoMsg, 30000);
	if (response != null) {
		String rc = response.getString(39);
		System.out.println("Echo Response Code "+rc);
	}
} 
    

Below is the result log for above code:

	
<log realm="channel/127.0.0.1:7080" at="2025-04-07T14:35:50.392183976" lifespan="19ms">
  <connect>
    Try 0 localhost:7080
      Connection established to 127.0.0.1:7080
  </connect>
</log>
<log realm="channel/127.0.0.1:7080" at="2025-04-07T14:35:54.657672292" lifespan="2ms">
  <send>
    <isomsg direction="outgoing">
      <!-- org.jpos.iso.packager.ISO87APackager -->
      <field id="0" value="0800"/>
      <field id="11" value="567527"/>
      <field id="41" value="T-112233"/>
      <field id="70" value="301"/>
    </isomsg>
  </send>
</log>
<log realm="channel/127.0.0.1:7080" at="2025-04-07T14:35:59.225976427" lifespan="8833ms">
  <receive>
    <isomsg direction="incoming">
      <!-- org.jpos.iso.packager.ISO87APackager -->
      <field id="0" value="0810"/>
      <field id="11" value="567527"/>
      <field id="39" value="00"/>
      <field id="41" value="T-112233"/>
      <field id="70" value="301"/>
    </isomsg>
  </receive>
</log>
<log realm="stdout" at="2025-04-07T14:35:59.728357651" lifespan="500ms">
    Echo Response Code 00
</log>
    

Thats all about Creating an ISO8583 Client using jPOS Q2. you can get the complete source code in my Github Repository

Comments