Transaction sending in jPOS is primarily handled by two key components: QMUX and MUX. These components provide a high-level abstraction for sending and receiving ISO-8583 messages.
QMUX is a Q2 adaptor that implements the MUX interface. It's designed to multiplex messages over a single connection or multiple connections.
To set up QMUX in your jPOS client, you need to add a configuration in your deploy/05_spring_client_context.xml:
<bean id="clientQMUX" class="org.jpos.q2.iso.QMUX" init-method="start" destroy-method="stop">
<property name="name" value="client-mux"/>
<property name="space" ref="tspace"/>
<property name="in" value="send"/>
<property name="out" value="receive"/>
<property name="unhandled" value="unhandled"/>
<property name="ready" value="ready"/>
</bean>Here's an example of how to use QMUX to send a transaction:
import org.jpos.iso.ISOMsg;
import org.jpos.iso.MUX;
import org.jpos.util.NameRegistrar;
import org.springframework.stereotype.Service;
@Service
public class TransactionSender {
private final MUX mux;
public TransactionSender() throws NameRegistrar.NotFoundException {
this.mux = NameRegistrar.get("mux.client-mux");
}
public ISOMsg sendTransaction(ISOMsg message) throws Exception {
long timeout = 30000; // 30 seconds timeout
return mux.request(message, timeout);
}
}MUX is an interface that defines methods for sending ISO messages and receiving responses. QMUX is an implementation of this interface.
request(ISOMsg m, long timeout): Sends a message and waits for a response.request(ISOMsg m, long timeout, ISOResponseListener rl): Sends a message and registers a listener for the response.send(ISOMsg m): Sends a message without expecting a response.
Here's an example of how to send a transaction asynchronously using MUX:
import org.jpos.iso.ISOMsg;
import org.jpos.iso.ISOResponseListener;
import org.jpos.iso.MUX;
import org.jpos.util.NameRegistrar;
import org.springframework.stereotype.Service;
@Service
public class AsyncTransactionSender {
private final MUX mux;
public AsyncTransactionSender() throws NameRegistrar.NotFoundException {
this.mux = NameRegistrar.get("mux.client-mux");
}
public void sendTransactionAsync(ISOMsg message) throws Exception {
long timeout = 30000; // 30 seconds timeout
mux.request(message, timeout, new ISOResponseListener() {
@Override
public void expired(long id) {
System.out.println("Request " + id + " expired");
}
@Override
public void response(ISOMsg response, long id) {
System.out.println("Received response for " + id + ": " + response);
}
});
}
}Before sending transactions, you need to create ISO-8583 messages. Here's an example of creating a simple authorization request:
import org.jpos.iso.ISOMsg;
import org.jpos.iso.ISOException;
import org.springframework.stereotype.Component;
@Component
public class MessageCreator {
public ISOMsg createAuthorizationRequest(String pan, String amount) throws ISOException {
ISOMsg message = new ISOMsg();
message.setMTI("0100");
message.set(2, pan);
message.set(3, "000000");
message.set(4, amount);
message.set(7, String.format("%010d", System.currentTimeMillis() / 1000));
message.set(11, String.format("%06d", (int) (Math.random() * 1000000)));
message.set(41, "12345678");
message.set(42, "MERCHANT_ID_123");
return message;
}
}Now, let's create a service that combines message creation and sending:
import org.jpos.iso.ISOException;
import org.jpos.iso.ISOMsg;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class TransactionService {
private final TransactionSender sender;
private final MessageCreator creator;
@Autowired
public TransactionService(TransactionSender sender, MessageCreator creator) {
this.sender = sender;
this.creator = creator;
}
public ISOMsg performAuthorization(String pan, String amount) throws Exception {
ISOMsg request = creator.createAuthorizationRequest(pan, amount);
return sender.sendTransaction(request);
}
}Here's a JUnit test for the TransactionService:
import org.jpos.iso.ISOMsg;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.when;
@ExtendWith(MockitoExtension.class)
class TransactionServiceTest {
@Mock
private TransactionSender sender;
@Mock
private MessageCreator creator;
private TransactionService service;
@BeforeEach
void setUp() {
service = new TransactionService(sender, creator);
}
@Test
void testPerformAuthorization() throws Exception {
// Arrange
ISOMsg request = new ISOMsg();
request.setMTI("0100");
ISOMsg response = new ISOMsg();
response.setMTI("0110");
response.set(39, "00");
when(creator.createAuthorizationRequest("1234567890123456", "100000")).thenReturn(request);
when(sender.sendTransaction(any(ISOMsg.class))).thenReturn(response);
// Act
ISOMsg result = service.performAuthorization("1234567890123456", "100000");
// Assert
assertThat(result.getMTI()).isEqualTo("0110");
assertThat(result.getString(39)).isEqualTo("00");
}
}This covers the essential aspects of transaction sending in a jPOS client implementation. The combination of QMUX, MUX, and proper message creation allows for efficient and reliable ISO-8583 message transmission.