All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jpos.iso.ISOFormattableBinaryFieldPackager Maven / Gradle / Ivy

Go to download

jPOS is an ISO-8583 based financial transaction library/framework that can be customized and extended in order to implement financial interchanges.

There is a newer version: 3.0.0
Show newest version
/*
 * jPOS Project [http://jpos.org]
 * Copyright (C) 2000-2019 jPOS Software SRL
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see .
 */

package org.jpos.iso;

import java.io.IOException;
import java.io.InputStream;

/**
 * Generic class for handling binary fields in Tag-Len-Value format
 * 
 * Format is assemblied by header formatter
 * Where
 *       TT is the n>0 digit field number (Tag)
 *       LL is the n>=0 digit field length (if n=0 it's means fixed length field with prefixer)
 *       .. is the field content
 * 
 * @author Mikolaj Sosna
 * @version $Revision: 2854 $ $Date: 2010-01-02 11:34:31 +0100 (sob) $
 */
public class ISOFormattableBinaryFieldPackager extends ISOFieldPackager
{
    private Prefixer tagPrefixer;
    private BinaryInterpreter interpreter;
    private Padder padder;
    private Prefixer prefixer;
    private IsoFieldHeaderFormatter headerFormatter;

    /**
     * Constructs a default ISOTagBinaryFieldPackager. There is ASCII tag L prefixer, no padding,
     * no length prefix and a literal binary interpretation. The set methods must be called to
     * make this ISOBaseFieldPackager useful.
     */
    public ISOFormattableBinaryFieldPackager() {
        super();
        this.tagPrefixer = AsciiPrefixer.L;
        this.interpreter = LiteralBinaryInterpreter.INSTANCE;
        this.padder = NullPadder.INSTANCE;
        this.prefixer = NullPrefixer.INSTANCE;
        this.headerFormatter = IsoFieldHeaderFormatter.TAG_FIRST;
    }

    /**
     * Constructs an ISOTagBinaryFieldPackager with a specific Padder, Interpreter and Prefixer.
     * The length and description should be set with setLength() and setDescription methods.
     * @param tagPrefixer The type of tag prefixer used to encode tag.
     * @param padder The type of padding used.
     * @param interpreter The interpreter used to encode the field.
     * @param prefixer The type of length prefixer used to encode this field.
     */
    public ISOFormattableBinaryFieldPackager(Prefixer tagPrefixer, Padder padder,
                                             BinaryInterpreter interpreter, Prefixer prefixer) {
        super();
        this.tagPrefixer = tagPrefixer;
        this.padder = padder;
        this.interpreter = interpreter;
        this.prefixer = prefixer;
        this.headerFormatter = IsoFieldHeaderFormatter.TAG_FIRST;
    }

/**
     * Constructs an ISOTagBinaryFieldPackager with a specific Padder, Interpreter and Prefixer.
     * The length and description should be set with setLength() and setDescription methods.
     * @param tagPrefixer The type of tag prefixer used to encode tag.
     * @param padder The type of padding used.
     * @param interpreter The interpreter used to encode the field.
     * @param lengthPrefixer The type of length prefixer used to encode this field.
     * @param headerFormatter The format of TAG TT and Length LL part
     */
    public ISOFormattableBinaryFieldPackager(Prefixer tagPrefixer, Padder padder,
                                             BinaryInterpreter interpreter, Prefixer lengthPrefixer,
                                             IsoFieldHeaderFormatter headerFormatter) {
        super();
        this.tagPrefixer = tagPrefixer;
        this.padder = padder;
        this.interpreter = interpreter;
        this.prefixer = lengthPrefixer;
        this.headerFormatter = headerFormatter;
    }

    /**
     * Creates an ISOTagBinaryFieldPackager.
     * @param maxLength The maximum length of the field in characters or bytes depending on the datatype.
     * @param description The description of the field. For human readable output.
     * @param tagPrefixer The type of tag prefixer used to encode tag.
     * @param interpreter The interpreter used to encode the field.
     * @param padder The type of padding used.
     * @param lengthPrefixer The type of length prefixer used to encode this field.
     * @param headerFormatter The format of TAG TT and Length LL part
     */
    public ISOFormattableBinaryFieldPackager(int maxLength, String description, Prefixer tagPrefixer,
                                             Padder padder, BinaryInterpreter interpreter, Prefixer lengthPrefixer,
                                             IsoFieldHeaderFormatter headerFormatter) {
        super(maxLength, description);
        this.tagPrefixer = tagPrefixer;
        this.padder = padder;
        this.interpreter = interpreter;
        this.prefixer = lengthPrefixer;
        this.headerFormatter = headerFormatter;
    }

    /**
     * Sets the Padder.
     * @param padder The padder to use during packing and unpacking.
     */
    public void setPadder(Padder padder) {
        this.padder = padder;
    }

    /**
     * Sets the Interpreter.
     * @param interpreter The interpreter to use in packing and unpacking.
     */
    public void setInterpreter(BinaryInterpreter interpreter) {
        this.interpreter = interpreter;
    }

    /**
     * Sets the length prefixer.
     * @param prefixer The length prefixer to use during packing and unpacking.
     */
    public void setPrefixer(Prefixer prefixer) {
        this.prefixer = prefixer;
    }

    /**
     * Gets the formatter, which assembles tag TT and length LL parts in required format
     * @return the formatter of the header part (length and tag parts)
     */
    public IsoFieldHeaderFormatter getHeaderFormatter() {
        return headerFormatter;
    }

    /**
     * Sets the formatter, which assembles tag TT and length LL parts in required format
     * @param headerFormatter the formatter of the header part (length and tag parts)
     */
    public void setHeaderFormatter(IsoFieldHeaderFormatter headerFormatter) {
        this.headerFormatter = headerFormatter;
    }

    /**
     * Returns the prefixer's packed length and the interpreter's packed length.
     * @see ISOFieldPackager#getMaxPackedLength()
     */
    @Override
    public int getMaxPackedLength() {
        return tagPrefixer.getPackedLength() + prefixer.getPackedLength() + interpreter.getPackedLength(getLength());
    }

    /**
     * Create a nice readable message for errors
     */
    private String makeExceptionMessage(ISOComponent c, String operation) {
        Object fieldKey = "unknown";
        if (c != null)
            try{
                fieldKey = c.getKey();
            } catch (Exception ignore){}
        return this.getClass().getName() + ": Problem " + operation + " field " + fieldKey;
    }

    /**
     * Convert the component into a byte[].
     */
    @Override
    public byte[] pack(ISOComponent c) throws ISOException {
        try{
            byte[] valueBytes = (byte[])c.getValue();
            if (valueBytes.length < 0 || valueBytes.length > getLength())
                throw new ISOException("Field length " + valueBytes.length + " too long. Max: " + getLength());

            int tag = (Integer)c.getKey();
            byte[] paddedValueBytes = valueBytes;

            if (!(padder instanceof NullPadder)) //for save few cycles
              paddedValueBytes = ISOUtil.hex2byte(padder.pad(ISOUtil.hexString(valueBytes), getLength()));

            byte[] rawData = new byte[tagPrefixer.getPackedLength() + prefixer.getPackedLength() + interpreter.getPackedLength(paddedValueBytes.length)];
            byte[] rawTagData = new byte[tagPrefixer.getPackedLength()];
            tagPrefixer.encodeLength(tag, rawTagData);

            byte[] rawLen = new byte[prefixer.getPackedLength()];
            prefixer.encodeLength(!headerFormatter.isTagFirst() ? paddedValueBytes.length + tagPrefixer.getPackedLength() : paddedValueBytes.length, rawLen);

            headerFormatter.format(tagPrefixer, prefixer, rawTagData, rawLen, rawData);

            interpreter.interpret(paddedValueBytes, rawData, headerFormatter.getTotalLength(tagPrefixer, prefixer));

            return rawData;
        } catch(Exception e) {
            throw new ISOException(makeExceptionMessage(c, "packing"), e);
        }
    }

    /**
     * Unpacks the byte array into the component.
     * @param c The component to unpack into.
     * @param b The byte array to unpack.
     * @param offset The index in the byte array to start unpacking from.
     * @return The number of bytes consumed unpacking the component.
     */
    @Override
    public int unpack(ISOComponent c, byte[] b, int offset) throws ISOException {
        try{
            int tagLen = tagPrefixer.getPackedLength();
            c.setFieldNumber(tagPrefixer.decodeLength(b, offset + headerFormatter.getTagIndex(prefixer)));
            int len = prefixer.decodeLength(b, offset + headerFormatter.getLengthIndex(tagPrefixer));
            if (!headerFormatter.isTagFirst()) {
                len -= tagPrefixer.getPackedLength();
            }
            if (len == -1) {
                // The prefixer doesn't know how long the field is, so use
                // maxLength instead
                len = getLength();
            } else if (getLength() > 0 && len > getLength()) {
                throw new ISOException("Field length " + len + " too long. Max: " + getLength());
            }
            int lenLen = prefixer.getPackedLength();
            byte[] unpacked = interpreter.uninterpret(b, offset + tagPrefixer.getPackedLength() + prefixer.getPackedLength(), len);

            byte[] paddedValueBytes = unpacked;
            if (!(padder instanceof NullPadder)) //for save few cycles
                paddedValueBytes = ISOUtil.hex2byte(padder.unpad(ISOUtil.hexString(unpacked)));

            c.setValue(paddedValueBytes);
            return tagLen + lenLen + interpreter.getPackedLength(len);
        } catch(Exception e){
            throw new ISOException(makeExceptionMessage(c, "unpacking"), e);
        }
    }

    /**
     * Unpack the input stream into the component.
     * @param c  The Component to unpack into.
     * @param in Input stream where the packed bytes come from.
     * @exception IOException Thrown if there's a problem reading the input stream.
     */
    @Override
    public void unpack (ISOComponent c, InputStream in)
        throws IOException, ISOException {

        try {
            int tagLen = tagPrefixer.getPackedLength();
            int lenLen = prefixer.getPackedLength() == 0 ? getLength() : prefixer.getPackedLength();
            int len = -1;
            if (headerFormatter.getTagIndex(prefixer) == 0) {
                c.setFieldNumber(tagPrefixer.decodeLength(readBytes(in, tagLen), 0));
                len = prefixer.decodeLength(readBytes(in, lenLen), 0);
            } else {
                len = prefixer.decodeLength(readBytes(in, lenLen), 0);
                c.setFieldNumber(tagPrefixer.decodeLength(readBytes(in, tagLen), 0));
            }
            if (getLength() > 0 && len > 0 && len > getLength()) {
                throw new ISOException("Field length " + len + " too long. Max: " + getLength());
            }
            int packedLen = interpreter.getPackedLength(len);
            byte[] unpacked = interpreter.uninterpret(readBytes (in, packedLen), 0, len);
            c.setValue(unpacked);
        } catch(ISOException e){
            throw new ISOException(makeExceptionMessage(c, "unpacking"), e);
        }
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy