jPOS Client Asynchronous Request

Today, i want to share about jPOS Client Asynchronous Request. When we look at MUX interface there are two overloading request(ISOMsg, timeout) and request(ISOMsg, timeout, ISORequestListener, handback) method for synchronous and asynchronous messaging.

usually, i’am using request(ISOMsg, timeout) method for sending request to server. But when i look at MUX source for fun, i realize that there are asynchronous way to send request. So in this post i will share about jPOS Client Asynchronous Request.

You can see the different with my old post about jPOS Client Receive Response to Specific Port. in this post about jPOS Client Asynchronous Request receive response with same port when we are sending request, even both of my post can be used for asynchronous request methods.

So, why we need this asynchronous request?? to answere these question, look at image below:

jPOS Client Asynchronous Request
jPOS Client Asynchronous Request

Now, are you getting my point? yes, we can parallel the process! we don’t need to waste 200 ms for waiting the response. because waiting is always boring! 😀

See the QBean bellow to sending request asynchronously.

[java]
package com.didikhari.web.id.client;

import org.jpos.iso.ISOException;
import org.jpos.iso.ISOMsg;
import org.jpos.iso.ISOResponseListener;
import org.jpos.iso.MUX;
import org.jpos.q2.QBeanSupport;
import org.jpos.q2.iso.QMUX;
import org.jpos.space.Space;
import org.jpos.space.SpaceFactory;
import org.jpos.util.NameRegistrar;
import org.jpos.util.NameRegistrar.NotFoundException;

public class JposClient extends QBeanSupport implements ISOResponseListener {

private Long timeout ;
private Space responseMap ;

@SuppressWarnings(“unchecked” )
@Override
protected void initService() throws Exception {
this.timeout = cfg .getLong(“timeout”);
this.responseMap = SpaceFactory.getSpace (cfg .get(“spaceName” ));
NameRegistrar. register(getName(), this);
}

/**
* send request asynchronous way
* @param handback
* @param muxName
* @return
*/
public void sendRequest(ISOMsg reqMsg, String handback, String muxName) {
try {
MUX mux = QMUX. getMUX(muxName);
mux.request( reqMsg, timeout, this, handback );
} catch (NotFoundException e ) {
e. printStackTrace();
} catch (ISOException e ) {
e.printStackTrace();
}
}

/**
* getting response
* @param handback
* @return
*/
public ISOMsg getResponse(String handback ){
return responseMap .in(handback , timeout );
}

@Override
public void responseReceived(ISOMsg resp, Object handBack) {
responseMap.out(String.valueOf( handBack), resp, timeout);
}

@Override
public void expired(Object handBack) {
System. out.println(“Request ” +handBack +” is timeout” );
}
}
[/java]

And this sniped code for deploy the QBean

[xml]


[/xml]

So, lets test the bean using this code:

[java]
package com.didikhari.web.id.test;

import java.util.Date;
import java.util.Random;
import java.util.TimeZone;

import org.jpos.iso.ISODate;
import org.jpos.iso.ISOException;
import org.jpos.iso.ISOMsg;
import org.jpos.iso.ISOUtil;
import org.jpos.q2.Q2;
import org.jpos.util.NameRegistrar;
import org.junit.Assert;
import org.junit.Before;

import com.didikhari.web.id.client.JposClient;
import com.didikhari.web.id.constant.Parameter;

public class Test {

@Before
public void setUp() {
Q2 scanner = new Q2();
scanner.start();
ISOUtil. sleep(2000L);
}

@org.junit. Test
public void sendRequest() throws InterruptedException {
Thread t = new Thread(new Runnable() {

@Override
public void run() {
for (int i = 0; i < 5; i++) { JposClient client = (JposClient) NameRegistrar.getIfExists("requester"); client.sendRequest(createReqMsg(), "Testing"+i , "client-mux"); ISOMsg response = client.getResponse("Testing" +i ); Assert. assertNotNull("response is not null", response); } } }); t.start(); t.join(); } private ISOMsg createReqMsg() { ISOMsg m = new ISOMsg(); try { m.setMTI( "0800"); m.set(11, ISOUtil. getRandomDigits(new Random(), 6, 6)); m.set(7,ISODate. getDateTime(new Date(), TimeZone. getTimeZone(Parameter.JAKARTA_TIMEZONE))); m.set(70, "001"); } catch (ISOException e ) { e.printStackTrace(); } return m ; } } [/java]

So, as you can see! We can sending and getting response with this three line

[java]
JposClient client = (JposClient) NameRegistrar.getIfExists( “requester”);
client.sendRequest(createReqMsg(), “Testing” +i , “client-mux” );
//TODO do another parallel process
ISOMsg response = client .getResponse(“Testing” +i );
[/java]

So, i think i can’t share my project source. But feel free to ask me from comment section bellow, or from contact page.

I think, thats all i can share about jPOS Client Asynchronous Request, hope this post can help someone.
Thanks for visiting my blog. and so… um… if you need help for finish your project about jPOS, i think i can help you by remote your computer/laptop for some donation to my blog. 😀

27 responses to “jPOS Client Asynchronous Request”

  1. demigod Avatar
    demigod

    Great BLOG! so helpful. Is it possible to integrate this with SOAP web services? should the MUX object be static like the channel? thanks!

    1. Didik H Avatar

      Thanks demigod,

      what do you mean by integrate with SOAP web service?
      MUX object is saved by NameRegistrar, so its singleton object.

      1. demigod Avatar
        demigod

        The web service will be the source of http request then convert it to ISO message object then send it to the ISO Server.

        This is my current set up:

        public class ISOManager extends QBeanSupport {
        private static long MAX_TIME_OUT;
        private static QMUX mux;

        @Override
        protected void initService() throws ISOException {
        log.info(“initializing ChannelManager Service”);
        try {
        mux = (QMUX) NameRegistrar.getIfExists(“mux.” + cfg.get(“mux”));
        MAX_TIME_OUT = cfg.getLong(“timeout”);
        NameRegistrar.register(getName(), this);
        } catch (NameRegistrar.NotFoundException e) {
        log.error(“Error in initializing service :” + e.getMessage());
        }
        }
        }
        I re-use the static QMux obect for every request, or should I create a new QMux object every request? See sample send method below.

        private ISOMsg sendMsg(ISOMsg msg, long timeout) throws Exception {
        long start = System.currentTimeMillis();
        QMUX mux = (QMUX) NameRegistrar.getIfExists(“mux.” + cfg.get(“mux”));
        ISOMsg respMsg = mux.request(msg, MAX_TIME_OUT);
        if (respMsg == null) {
        respMsg = msg;
        respMsg.setResponseMTI();
        respMsg.set(39, “08”);
        return respMsg;
        } else {
        long duration = System.currentTimeMillis() – start;
        log.info(“Response time (ms):” + duration);
        return respMsg;
        }
        }

        Thanks.

        1. Didik H Avatar

          Actually, by calling NameRegistrar.getIfExists(“mux.” + cfg.get(“mux”)); static methods, you will get same object. these method is not initiate/instantiate new QMux object. jPOS will initiate the QMux object while you starting Q2, and saved the object into NameRegistrar, and because NameRegistrar is singleton object, so every object saved there will live until the JVM is stoped/restarted.

          So, the static QMUX mux and NameRegistrar.getIfExists(“mux.” + cfg.get(“mux”)); is same QMux object.

          1. demigod Avatar
            demigod

            Thanks. So which is more efficient to use? the synchronous or asynchronous approach? I was able to make them both work just not sure which is the best approach to use since we anticipate a large volume of request.

          2. Didik H Avatar

            I think its depend on your flow, with async request, you can parallelize you process and get the response when you need it. you should use sync approach when your business flow need to sequence the process.

    2. shahrad Avatar
      shahrad

      Hi Didik ,
      It was very useful and it solved my issue.

      1. didikhari Avatar
        didikhari

        Hi Shahrad.. i’m glad to hear that. thanks for visiting my blog.

  2. demii Avatar
    demii

    Saya baru dalam iso8583,
    saya ingin membuat RESTFul webservice yang melakukan request ke server ISO8583 dan memproses respon yang didapatkan sebagai keluaran webservice REST.
    apakah memungkinkan?

    1. Didik H Avatar

      kalau melakukan request ke server ISO8583 secara langsung sepertinya tidak memungkinkan, karena jPOS menggunakan TCP, bukan HTTP. kalau tetap ingin menggunakan restful, silakan buka postingan saya bagian Receiving Http Request using jPOS

    2. demii Avatar
      demii

      Bagaimana jika RESTFul –> Client ISO8583 –> Server ISO8583 apakah memungkinkan?

      1. Didik H Avatar

        Tergantung sistem yang sedang dibuat, jika itu adalah Rest Server yang didalamnya memanggil fungsi iso client (ISOMux), ya hal tersebut memungkinkan.

  3. demii Avatar
    demii

    saya betul-betul baru di iso8583. saya sudah mencoba membuat Rest Server yang didalamnya memanggil fungsi iso client namun selalu gagal oleh karena “connection reset”, dan kebanyakkan tutorial iso client Q2 menggunakan maven sedangkan saya tidak menggunkan maven, adakah cara lain untuk iso client ?

    1. Didik H Avatar

      Sebenarnya, maven yang digunakan hanya untuk download dependency library, jadi seharusnya tidak ada bedanya (dalam kode) jika tidak menggunakan maven. apakah server iso nya sudah ada? connection reset biasanya error dikarenakan client yang tidak bisa terhubung dengan server nya.

  4. demii Avatar
    demii

    Server iso-nya sudah ada, beberapa error karena header terlalu panjang. dari yang saya pahami header sudah diatur oleh channel. Saya mencoba berdasarkan tutorial, saat di run yg muncul hanya Q2 started…
    sedangkan request ke server tidak pernah dijalankan. Apakah anda tau referensi lain apa yang saya butuhkan untuk membuat iso client dengan Q2 secara benar dari awal (paling basic) ?

    1. Didik H Avatar

      Apakah sudah dipastikan spesifikasi channel dan packager nya sama? bisa coba di dump? referensi lainnya silakan tanya di jpos user group

  5. Edvaldo Nascimento Avatar
    Edvaldo Nascimento

    Parabéns, pelo post me ajudou bastante.

    1. Didik H Avatar

      Obrigado por ler o meu blog (Google Translate)

  6. Maycon Lima Avatar

    Hi Didik,
    I have a question about jpos async request.
    Imagine that scenario, according method signature above:

    void request(ISOMsg m, long timeout, ISOResponseListener r, Object handBack)…

    I can pass in ‘handBack’ a Jpos Context object right?
    Inside my context object, have DB(org.jpos.DB) instance.

    When fire a request msg (by async), my actual thread it’s free to work again right?

    So i ask, the database connection remains open? If my request waste 2 minutes, i will have database session lock?

    Ps.: I’m assuming that at the beginning of the transaction processing, a connection was opened on an ‘Open participant’ (responsible for picking up a connection from the pool C3P0).

    Please, help with this analysis. If you prefer, send me a email: [email protected]

    Great for you attemption.

    Congrats for the post.

    1. Didik H Avatar

      Hi Maycon,

      Thank you for your feedback.
      Yes, you can pass jpos context for handBack parameter.

      because i never use org.jpos.DB before, so im not sure about it Maycon. is the database session lock is on org.jpos.DB feature?
      i think you can use C3P0 parameter setting for avoid session lock (im not sure about this).

      usually im using custom QBean for database connection and operation here: Integrating Hibernate and jPOS Framework and use template method or hibernate currentSession that will close any session automatically. we can use hibernate second level cache for improve the performance.

  7. Maycon Lima Avatar

    Didik H,
    Thank for your response.

    I think you not understood correctly my question context.

    When i sad “database session lock”, i mean “database session waiting”.

    Let me explain again.

    Imagine, my system started processing one transaction. My first participant ‘Open participant’ (responsible for picking up a connection from the pool C3P0), so, this opened a connection with database.

    During processing, another participant (called MyQueryHost) send a msg, using a async jpos request method (remember, passing context on handBack parameter).

    Supposed, at this point, from the moment you got the pool connection so far, it’s been 20 seconds. So my “MyQueryHost” send a msg async. Remember that my DB instance is on Context jpos object.

    So, my question is: When my actual thread is free to do another task, what happen with DB conection? The database conection, that was sent within the context, remains active?

    Thanks for you attention.

    1. Didik H Avatar

      Yes, if you are not closing the database session, then it still active. its depend on you db session management,

  8. Rofi Avatar
    Rofi

    Hallo dikdik hari. Saya mencoba membuat project qserver dan qmux. Namun ketika saya running program qmux, respon nya null.
    mux.xml :

    jpos-receive
    jpos-send
    jpos.ready

    client_channel.xml :

    jpos-send
    jpos-receive
    tspace:default
    30000

    java source code :
    qmux = (QMUX) NameRegistrar.getIfExists(“mux.jpos-mux”);
    ISOMsg reply = qmux.request(createReqMsg(), 5000);
    public static ISOMsg createReqMsg() {

    ISOMsg reqMsg = new ISOMsg();
    reqMsg.setHeader(“ISO011000017”.getBytes());
    try {
    reqMsg.setMTI(“0200”);
    reqMsg.set(3, “530020”);
    } catch (ISOException e) {
    e.printStackTrace();
    }
    return reqMsg;
    }

    Mohon bantuannya

  9. shahrad Avatar
    shahrad

    Hi Didik

    There is an issue with this problem. I use Restful with Jpos it mean rest web service send a request to jpos services but when i run this part of code response is null.

    ArghamChannel arghamChannel = (ArghamChannel) NameRegistrar.getIfExists(“requester”);
    arghamChannel.sendRequest(requestMsg, requestMsg.getString(37), “BTIToArgham-mux”);
    responseMsg = arghamChannel.getResponse(requestMsg.getString(37));

    this is my channel:

    public class ArghamChannel extends QBeanSupport implements ISOResponseListener {
    private Long timeout = 10000l;
    private Space responseMap;

    @SuppressWarnings(“unchecked”)
    @Override
    public void initService() throws Exception {
    this.timeout = cfg.getLong(“timeout”);
    this.responseMap = SpaceFactory.getSpace();
    NameRegistrar.register(getName(), this);
    }

    public void sendRequest(ISOMsg reqMsg, String handback, String muxName) {

    try {

    MUX mux = QMUX.getMUX(muxName);
    mux.request(reqMsg, 10000, this, handback);

    } catch (NotFoundException e) {
    e.printStackTrace();
    } catch (ISOException e) {
    e.printStackTrace();
    }
    }

    public ISOMsg getResponse(String handback) throws InterruptedException {
    Thread.sleep(timeout);
    return responseMap.in(handback, timeout);
    }

    @Override
    public void responseReceived(ISOMsg resp, Object handBack) {
    responseMap.out(String.valueOf(handBack), resp, timeout);

    }

    @Override
    public void expired(Object handBack) {
    System.out.println(“Request ” + handBack + ” is timeout”);
    }
    }

    1. didikhari Avatar
      didikhari

      Hi shahrad,

      do you send iso8583 format string through rest client to jPOS channel?
      jPOS is TCP based, and Restful is http/s based, so you need to open rest server that accept the message.

      1. shahrad Avatar
        shahrad

        Hi didik,

        No rest request send an object to jpos and i convert it to isomsg object . when response received from server i convert it again to an object and pass it to rest.

        this is my test class

        *************************************************

        @Test
        public void sendRequest() throws InterruptedException {

        BalanceRequest balanceRequest = new BalanceRequest(“5859831099367236”, “100012”
        , BankID.TEJARAT, BankID.TEJARAT, ChannelID.MOBILE, “2530”, “321456213669”,
        “12345”, “9905”);

        // Thread t = new Thread(new Runnable() {

        BalanceResponse response = balanceService.doBalance(balanceRequest);
        Assert.assertNotNull(response);

        // Assert.assertEquals(“00″, response.getResponseCode());
        // }
        // });
        // t.start();
        // t.join();
        }
        *********************************
        and this is balance class

        @Service
        public class BalanceService {

        public BalanceResponse doBalance(BalanceRequest balanceRequest) {
        BalanceResponse balanceResponse;
        ISOMsg responseMsg = null;

        try {

        String fld_07 = balanceRequest.getCurrentDate() + balanceRequest.getCurrentTime();
        String fld_48 = ” ” + balanceRequest.getCVV2() + “00”;

        BaseMobileMessage baseMobileMessage = new BaseMobileMessage(“0200”, balanceRequest.getCardNo(), “310000”, fld_07,
        balanceRequest.getSystemTraceAuditNumber(), balanceRequest.getCurrentTime(), balanceRequest.getCurrentDate(),
        balanceRequest.getExpireDate(), balanceRequest.getCurrentDate(), balanceRequest.getChannel().getDescription(),
        balanceRequest.getRequestReferenceNumber(), fld_48, balanceRequest.getSecondPin());
        ISOMsg requestMsg = baseMobileMessage.messageFactory();
        requestMsg.set(4, “000000000000”);
        requestMsg.set(6, “000000000000”);
        requestMsg.set(10, “00000001”);
        requestMsg.set(35, “”);
        requestMsg.set(43, “2920000000000000000000000000000000000000”);
        requestMsg.set(49, “364”);
        requestMsg.set(51, “364”);
        requestMsg.set(100, “585983”);
        MacGenerator macGenerator = new MacGenerator();
        requestMsg.set(128, macGenerator.createMac(requestMsg));
        ArghamChannel arghamChannel = (ArghamChannel) NameRegistrar.getIfExists(“requester”);
        responseMsg = arghamChannel.sendRequest(requestMsg, requestMsg.getString(37), “BTIToArgham-mux”);

        if (responseMsg != null) {
        if (responseMsg.getString(39).equals(“00”)) {
        balanceResponse = new BalanceResponse(responseMsg.getString(39), responseMsg.getString(11), responseMsg.getString(54).substring(8, 19), responseMsg.getString(54).substring(28, 39));
        return balanceResponse;
        }
        } else
        throw new BusinessException(ErrorConstants.TMBError.getError(“91”));
        } catch (Exception e) {
        e.printStackTrace();
        throw new BusinessException(ErrorConstants.TMBError.getError(“91”));
        }

        throw new BusinessException(ErrorConstants.TMBError.getError(responseMsg.getString(39)));

        }
        }

Leave a Reply

Your email address will not be published. Required fields are marked *