javajpos

Jpos Iso message keep showing a non-existent field based on the primary and secondary bitmap


I am new on attempting to unpack Jpos message, I try to follow the only answer from this old question JPOS unpacking running example

However, I receive this error

Error handling message -> org.jpos.iso.ISOException: field packager '5' is null unpacking field=5, consumed=50

and this is my iso message in hex form

49534F3031353030303037303032313046323341383030314145393038303130...

(notes: I purposely cut the message short since the rest has sensitive info)

I am using a custom packager as this following

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE isopackager SYSTEM "genericpackager.dtd">

<!-- ISO 8583:1987 (ASCII) field descriptions for GenericPackager -->
<!-- Bitmap is BINARY in this case -->

<isopackager headerLength="12">
    <isofield
            id="0"
            length="4"
            name="MESSAGE TYPE INDICATOR"
            class="org.jpos.iso.IFA_NUMERIC"/>
    <isofield
            id="1"
            length="16"
            name="BIT MAP"
            class="org.jpos.iso.IFA_BITMAP"/>
    <isofield
            id="2"
            length="19"
            name="PAN - PRIMARY ACCOUNT NUMBER"
            class="org.jpos.iso.IFA_LLNUM"/>
    <isofield
            id="3"
            length="6"
            name="PROCESSING CODE"
            class="org.jpos.iso.IFA_NUMERIC"/>
    <isofield
            id="4"
            length="12"
            name="AMOUNT, TRANSACTION"
            class="org.jpos.iso.IFA_NUMERIC"/>
    <isofield
            id="7"
            length="10"
            name="TRANSMISSION DATE AND TIME"
            class="org.jpos.iso.IFA_NUMERIC"/>
    <isofield
            id="11"
            length="6"
            name="SYSTEM TRACE AUDIT NUMBER"
            class="org.jpos.iso.IFA_NUMERIC"/>
    <isofield
            id="12"
            length="6"
            name="TIME, LOCAL TRANSACTION"
            class="org.jpos.iso.IFA_NUMERIC"/>
    <isofield
            id="13"
            length="4"
            name="DATE, LOCAL TRANSACTION"
            class="org.jpos.iso.IFA_NUMERIC"/>
    <isofield
            id="15"
            length="4"
            name="DATE, SETTLEMENT"
            class="org.jpos.iso.IFA_NUMERIC"/>
    <isofield
            id="17"
            length="4"
            name="DATE, CAPTURE"
            class="org.jpos.iso.IFA_NUMERIC"/>
    <isofield
            id="32"
            length="11"
            name="ACQUIRING INSTITUTION IDENT CODE"
            class="org.jpos.iso.IFA_LLNUM"/>
    <isofield
            id="33"
            length="11"
            name="FORWARDING INSTITUTION IDENT CODE"
            class="org.jpos.iso.IFA_LLNUM"/>
    <isofield
            id="35"
            length="37"
            name="TRACK 2 DATA"
            class="org.jpos.iso.IFA_LLNUM"/>
    <isofield
            id="37"
            length="12"
            name="RETRIEVAL REFERENCE NUMBER"
            class="org.jpos.iso.IF_CHAR"/>
    <isofield
            id="38"
            length="6"
            name="AUTHORIZATION IDENTIFICATION RESPONSE"
            class="org.jpos.iso.IF_CHAR"/>
    <isofield
            id="39"
            length="2"
            name="RESPONSE CODE"
            class="org.jpos.iso.IF_CHAR"/>
    <isofield
            id="41"
            length="16"
            name="CARD ACCEPTOR TERMINAL IDENTIFICACION"
            class="org.jpos.iso.IF_CHAR"/>
    <isofield
            id="44"
            length="27"
            name="ADITIONAL RESPONSE DATA"
            class="org.jpos.iso.IFA_LLCHAR"/>
    <isofield
            id="49"
            length="3"
            name="CURRENCY CODE, TRANSACTION"
            class="org.jpos.iso.IF_CHAR"/>
    <isofield
            id="60"
            length="15"
            name="RESERVED PRIVATE"
            class="org.jpos.iso.IFA_LLLCHAR"/>
    <isofield
            id="100"
            length="11"
            name="RECEIVING INSTITUTION IDENT CODE"
            class="org.jpos.iso.IFA_LLNUM"/>
    <isofield
            id="103"
            length="19"
            name="ACCOUNT IDENTIFICATION 2"
            class="org.jpos.iso.IFA_LLCHAR"/>
    <isofield
            id="126"
            length="999"
            name="RESERVED PRIVATE USE"
            class="org.jpos.iso.IFA_LLLCHAR"/>
</isopackager>

Notice that there is no field 5? because that is how it is supposed to be if I convert my hex to ascii it will give me this

ISO0150000700210F23A8001AE908010

which the spec is this

if I turn my primary bit map to binary it will give me this

11110010 00111010 10000000 00000001 10101110 10010000 10000000 00010000

and from that info, the field that should be active is 1,2,3,4,7,11,12,13,15,17,32,33,35,37,38,39,41,44,49,60,100,103,126

Where did I go wrong? this is the rest of my code

public synchronized Map<String, String> receiver(Socket socket) throws ISOException {

        Map<String, String> response = new HashMap<>();
        ISOMsg iso = new ISOMsg();
        response.put("mti","0000");
        try {
            byte[] messageByte = new byte[socket.getReceiveBufferSize()];
            DataInputStream inputByte = new DataInputStream(socket.getInputStream());
            int bytesRead = inputByte.read(messageByte);
            byte[] sendByte = new byte[bytesRead];
            System.arraycopy(messageByte,0,sendByte,0,bytesRead);
            String rawMessage = ISOUtil.hexString(sendByte);
            log.info("request iso string : {}",rawMessage);

            int messageLen = Integer.parseInt(rawMessage.substring(0,4),16);
            log.info("message length : {}",messageLen);
            String isoData = rawMessage.substring(4);
            response.put("data",isoData);
//            String isoData = rawMessage.substring(8,(messageLen * 2) + 8);
            InputStream inputStream = getClass().getResourceAsStream("/iso-prima-msg.xml");
            GenericPackager packager = new GenericPackager(inputStream);
            iso.setPackager(packager);
            iso.unpack(ISOUtil.hex2byte(isoData));
            createDump(iso,"INCOMING");
            response.put("mti",iso.getMTI());

        } catch (Exception err) {
            StringWriter stack = new StringWriter();
            err.printStackTrace(new PrintWriter(stack));
            log.error("Error handling message -> {}",stack);
            createDump(iso,"INCOMING-ERROR");
        }
        return response;
    }

Solution

  • I have managed to find out the answer. While https://stackoverflow.com/a/78803181/10467473 doesn't directly solve the problem but it gives me to some insight.

    the main problem is from my receiver function itself. I don't need to cut the oncoming hex message before unpacking it as the hex message already start with the header itself.

    Also, since in my packager xml I already state the length of my header <isopackager headerLength="12"> ; I don't need to cut the header manually from my hex code.

    This is my fixed function and it serves me well

    public synchronized Map<String, String> receiver(Socket socket) throws ISOException {
    
            Map<String, String> response = new HashMap<>();
            ISOMsg iso = new ISOMsg();
            response.put("mti","0000");
            try {
                byte[] messageByte = new byte[socket.getReceiveBufferSize()];
                DataInputStream inputByte = new DataInputStream(socket.getInputStream());
                int bytesRead = inputByte.read(messageByte);
                byte[] sendByte = new byte[bytesRead];
                System.arraycopy(messageByte,0,sendByte,0,bytesRead);
                String rawMessage = ISOUtil.hexString(sendByte);
                log.info("request iso string : {}",rawMessage);
                response.put("data",rawMessage);
                InputStream inputStream = getClass().getResourceAsStream("/iso-prima-msg.xml");
                GenericPackager packager = new GenericPackager(inputStream);
                iso.setPackager(packager);
                iso.unpack(ISOUtil.hex2byte(rawMessage));
                createDump(iso,"INCOMING");
                response.put("mti",iso.getMTI());
                log.info("CHECK ISO FIELD 33 => {}", iso.getString(33));
    
            } catch (Exception err) {
                StringWriter stack = new StringWriter();
                err.printStackTrace(new PrintWriter(stack));
                log.error("Error handling message -> {}",stack);
                createDump(iso,"INCOMING-ERROR");
            }
    
            return response;
        }