org.jpos.iso.ISOBasePackager.java Source code

Java tutorial

Introduction

Here is the source code for org.jpos.iso.ISOBasePackager.java

Source

/*
 * jPOS Project [http://jpos.org]
 * Copyright (C) 2000-2013 Alejandro P. Revilla
 *
 * 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 <http://www.gnu.org/licenses/>.
 */

package org.jpos.iso;

import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.BitSet;
import java.util.Map;

import org.apache.commons.lang.StringUtils;
import org.jpos.util.CardNoEncodeUtil;
import org.jpos.util.LogEvent;
import org.jpos.util.LogSource;
import org.jpos.util.Logger;

/**
 * provides base functionality for the actual packagers
 * 
 * @author apr
 */
@SuppressWarnings("unused")
public abstract class ISOBasePackager implements ISOPackager, LogSource {
    protected ISOFieldPackager[] fld;

    protected Logger logger = null;
    protected String realm = null;
    //   protected int headerLength = 0;

    public void setFieldPackager(ISOFieldPackager[] fld) {
        this.fld = fld;
    }

    /**
     * @return true if BitMap have to be emited
     */
    protected boolean emitBitMap() {
        return (fld[1] instanceof ISOBitMapPackager);
    }

    /**
     * usually 2 for normal fields, 1 for bitmap-less or ANSI X9.2
     * 
     * @return first valid field
     */
    protected int getFirstField() {
        if ((!(fld[0] instanceof ISOMsgFieldPackager)) && fld.length > 1)
            return (fld[1] instanceof ISOBitMapPackager) ? 2 : 1;
        return 0;
    }

    /**
     * @param m
     *            the Component to pack
     * @return Message image
     * @exception ISOException
     */
    public byte[] pack(ISOComponent m) throws ISOException {
        LogEvent evt = null;
        if (logger != null)
            evt = new LogEvent(this, "pack");
        try {
            if (m.getComposite() != m)
                throw new ISOException("Can't call packager on non Composite");

            ISOComponent c;
            ArrayList<byte[]> v = new ArrayList<byte[]>(128);
            Map fields = m.getChildren();
            int len = 0;
            int first = getFirstField();

            c = (ISOComponent) fields.get(0);
            byte[] b;

            //         if (m instanceof ISOMsg && headerLength > 0) {
            //            byte[] h = ((ISOMsg) m).getHeader();
            //            if (h != null)
            //               len += h.length;
            //         }

            if (first > 0 && c != null) {
                b = fld[0].pack(c);
                len += b.length;
                v.add(b);
            }

            if (emitBitMap()) {
                // BITMAP (-1 in HashTable)
                c = (ISOComponent) fields.get(-1);
                b = getBitMapfieldPackager().pack(c);
                len += b.length;
                v.add(b);

                if (logger != null) {
                    BitSet bmap = (BitSet) c.getValue();
                    evt.addMessage("<bitmap>" + bmap.toString() + "</bitmap>");
                }
            }

            // if Field 1 is a BitMap then we are packing an
            // ISO-8583 message so next field is fld#2.
            // else we are packing an ANSI X9.2 message, first field is 1
            int tmpMaxField = Math.min(m.getMaxField(), 128);

            for (int i = first; i <= tmpMaxField; i++) {
                if ((c = (ISOComponent) fields.get(i)) != null) {
                    try {
                        ISOFieldPackager fp = fld[i];
                        if (fp == null)
                            throw new ISOException("null field " + i + " packager");
                        b = fp.pack(c);
                        len += b.length;
                        v.add(b);

                        if (logger != null) {
                            String value = c.getValue() + "";
                            evt.addMessage("<pack fld=\"" + i + "\" packager=\"" + fld[i].getClass().getName()
                                    + "\" name=\"" + fld[i].getDescription() + "\">");
                            if (c.getValue() instanceof ISOMsg)
                                evt.addMessage(c.getValue());
                            else if (c.getValue() instanceof byte[]) {
                                evt.addMessage("  <value type='binary'>" + ISOUtil.hexString((byte[]) c.getValue())
                                        + "</value>");
                            } else {
                                if (i == 2) {
                                    value = simpleEncodeCardNo(value);
                                }
                                evt.addMessage("  <value>" + value + "</value>");
                            }
                            evt.addMessage("</pack>");
                        }

                    } catch (ISOException e) {
                        if (evt != null) {
                            evt.addMessage("error packing field " + i);
                            evt.addMessage(c);
                            evt.addMessage(e);
                        }
                        throw new ISOException("error packing field " + i, e);
                    }
                }
            }

            if (m.getMaxField() > 128 && fld.length > 128) {
                for (int i = 1; i <= 64; i++) {
                    if ((c = (ISOComponent) fields.get(i + 128)) != null) {
                        try {
                            b = fld[i + 128].pack(c);
                            len += b.length;
                            v.add(b);
                        } catch (ISOException e) {
                            if (evt != null) {
                                evt.addMessage("error packing field " + (i + 128));
                                evt.addMessage(c);
                                evt.addMessage(e);
                            }
                            throw e;
                        }
                    }
                }
            }

            int k = 0;
            byte[] d = new byte[len];

            // if ISOMsg insert header
            //         if (m instanceof ISOMsg && headerLength > 0) {
            //            byte[] h = ((ISOMsg) m).getHeader();
            //            if (h != null) {
            //               System.arraycopy(h, 0, d, k, h.length);
            //               k += h.length;
            //            }
            //         }
            for (byte[] bb : v) {
                System.arraycopy(bb, 0, d, k, bb.length);
                k += bb.length;
            }
            if (evt != null) // save a few CPU cycle if no logger available
                evt.addMessage(CardNoEncodeUtil.encodeCardNo((ISOUtil.hexString(d))));
            return d;
        } catch (ISOException e) {
            if (evt != null)
                evt.addMessage(e);
            throw e;
        } finally {
            if (evt != null)
                Logger.log(evt);
        }
    }

    /**
     * @param m
     *            the Container of this message
     * @param b
     *            ISO message image
     * @return consumed bytes
     * @exception ISOException
     */
    public int unpack(ISOComponent m, byte[] b) throws ISOException {
        LogEvent evt = new LogEvent(this, "unpack");
        int consumed = 0;

        try {
            if (m.getComposite() != m)
                throw new ISOException("Can't call packager on non Composite");
            if (logger != null) // save a few CPU cycle if no logger available
                evt.addMessage(CardNoEncodeUtil.encodeCardNo((ISOUtil.hexString(b))));

            // if ISOMsg and headerLength defined
            //         if (m instanceof ISOMsg /* && ((ISOMsg) m).getHeader()==null */
            //               && headerLength > 0) {
            //            byte[] h = new byte[headerLength];
            //            System.arraycopy(b, 0, h, 0, headerLength);
            //            ((ISOMsg) m).setHeader(h);
            //            consumed += headerLength;
            //         }

            if (!(fld[0] == null) && !(fld[0] instanceof ISOBitMapPackager)) {
                ISOComponent mti = fld[0].createComponent(0);
                consumed += fld[0].unpack(mti, b, consumed);
                m.set(mti);
            }
            BitSet bmap = null;
            int maxField = fld.length;
            if (emitBitMap()) {
                ISOBitMap bitmap = new ISOBitMap(-1);
                consumed += getBitMapfieldPackager().unpack(bitmap, b, consumed);
                bmap = (BitSet) bitmap.getValue();
                if (logger != null)
                    evt.addMessage("<bitmap>" + bmap.toString() + "</bitmap>");
                m.set(bitmap);
                maxField = Math.min(maxField, bmap.size());
            }
            for (int i = getFirstField(); i < maxField; i++) {
                try {
                    if (bmap == null && fld[i] == null)
                        continue;
                    if (maxField > 128 && i == 65)
                        continue; // ignore extended bitmap

                    if (bmap == null || bmap.get(i)) {
                        if (fld[i] == null)
                            throw new ISOException("field packager '" + i + "' is null");

                        ISOComponent c = fld[i].createComponent(i);
                        consumed += fld[i].unpack(c, b, consumed);
                        if (logger != null) {
                            String value = c.getValue() + "";
                            evt.addMessage("<unpack fld=\"" + i + "\" packager=\"" + fld[i].getClass().getName()
                                    + "\" name=\"" + fld[i].getDescription() + "\">");
                            if (c.getValue() instanceof ISOMsg)
                                evt.addMessage(c.getValue());
                            else if (c.getValue() instanceof byte[]) {
                                evt.addMessage("  <value type='binary'>" + ISOUtil.hexString((byte[]) c.getValue())
                                        + "</value>");
                            } else {
                                if (i == 2) {
                                    value = simpleEncodeCardNo(value);
                                }
                                evt.addMessage("  <value>" + value + "</value>");
                            }
                            evt.addMessage("</unpack>");
                        }
                        m.set(c);
                    }
                } catch (ISOException e) {
                    evt.addMessage("error unpacking field " + i + " consumed=" + consumed);
                    evt.addMessage(e);
                    // jPOS-3
                    e = new ISOException(String.format("%s (%s) unpacking field=%d, consumed=%d", e.getMessage(),
                            e.getNested().toString(), i, consumed));
                    throw e;
                }
            }
            if (b.length != consumed) {
                evt.addMessage("WARNING: unpack len=" + b.length + " consumed=" + consumed);
            }
            return consumed;
        } catch (ISOException e) {
            evt.addMessage(e);
            throw e;
        } catch (Exception e) {
            evt.addMessage(e);
            throw new ISOException(e.getMessage() + " consumed=" + consumed);
        } finally {
            Logger.log(evt);
        }
    }

    public void unpack(ISOComponent m, InputStream in) throws IOException, ISOException {
        LogEvent evt = new LogEvent(this, "unpack");
        try {
            if (m.getComposite() != m)
                throw new ISOException("Can't call packager on non Composite");

            // if ISOMsg and headerLength defined
            //         if (m instanceof ISOMsg && ((ISOMsg) m).getHeader() == null && headerLength > 0) {
            //            byte[] h = new byte[headerLength];
            //            in.read(h, 0, headerLength);
            //            ((ISOMsg) m).setHeader(h);
            //         }

            if (!(fld[0] instanceof ISOMsgFieldPackager) && !(fld[0] instanceof ISOBitMapPackager)) {
                ISOComponent mti = fld[0].createComponent(0);
                fld[0].unpack(mti, in);
                m.set(mti);
            }
            BitSet bmap = null;
            int maxField = fld.length;
            if (emitBitMap()) {
                ISOBitMap bitmap = new ISOBitMap(-1);
                getBitMapfieldPackager().unpack(bitmap, in);
                bmap = (BitSet) bitmap.getValue();
                if (logger != null)
                    evt.addMessage("<bitmap>" + bmap.toString() + "</bitmap>");
                m.set(bitmap);
                maxField = Math.min(maxField, bmap.size());
            }

            for (int i = getFirstField(); i < maxField; i++) {
                if (bmap == null && fld[i] == null)
                    continue;

                if (bmap == null || bmap.get(i)) {
                    if (fld[i] == null)
                        throw new ISOException("field packager '" + i + "' is null");

                    ISOComponent c = fld[i].createComponent(i);
                    fld[i].unpack(c, in);
                    if (logger != null) {

                        evt.addMessage(
                                "<unpack fld=\"" + i + "\" packager=\"" + fld[i].getClass().getName() + "\">");
                        if (c.getValue() instanceof ISOMsg)
                            evt.addMessage(c.getValue());
                        else
                            evt.addMessage("  <value>" + c.getValue().toString() + "</value>");
                        evt.addMessage("</unpack>");
                    }
                    m.set(c);
                }
            }
            if (bmap != null && bmap.get(65) && fld.length > 128 && fld[65] instanceof ISOBitMapPackager) {
                bmap = (BitSet) ((ISOComponent) m.getChildren().get(65)).getValue();
                for (int i = 1; i < 64; i++) {
                    if (bmap == null || bmap.get(i)) {
                        ISOComponent c = fld[i + 128].createComponent(i);
                        fld[i + 128].unpack(c, in);
                        if (logger != null) {
                            evt.addMessage("<unpack fld=\"" + i + 128 + "\" packager=\""
                                    + fld[i + 128].getClass().getName() + "\">");
                            evt.addMessage("  <value>" + c.getValue().toString() + "</value>");
                            evt.addMessage("</unpack>");
                        }
                        m.set(c);
                    }
                }
            }
        } catch (ISOException e) {
            evt.addMessage(e);
            throw e;
        } catch (EOFException e) {
            throw e;
        } catch (Exception e) {
            evt.addMessage(e);
            throw new ISOException(e);
        } finally {
            Logger.log(evt);
        }
    }

    /**
     * @param m
     *            the Container (i.e. an ISOMsg)
     * @param fldNumber
     *            the Field Number
     * @return Field Description
     */
    public String getFieldDescription(ISOComponent m, int fldNumber) {
        return fld[fldNumber].getDescription();
    }

    /**
     * @param fldNumber
     *            the Field Number
     * @return Field Packager for this field
     */
    public ISOFieldPackager getFieldPackager(int fldNumber) {
        return fld != null && fldNumber < fld.length ? fld[fldNumber] : null;
    }

    /**
     * @param fldNumber
     *            the Field Number
     * @param fieldPackager
     *            the Field Packager
     */
    public void setFieldPackager(int fldNumber, ISOFieldPackager fieldPackager) {
        fld[fldNumber] = fieldPackager;
    }

    public ISOMsg createISOMsg() {
        return new ISOMsg();
    }

    /**
     * @return 128 for ISO-8583, should return 64 for ANSI X9.2
     */
    protected int getMaxValidField() {
        return 128;
    }

    /**
     * @return suitable ISOFieldPackager for Bitmap
     */
    protected ISOFieldPackager getBitMapfieldPackager() {
        return fld[1];
    }

    public void setLogger(Logger logger, String realm) {
        this.logger = logger;
        this.realm = realm;
    }

    public String getRealm() {
        return realm;
    }

    public Logger getLogger() {
        return logger;
    }
    //
    //   public int getHeaderLength() {
    //      return headerLength;
    //   }
    //
    //   public void setHeaderLength(int len) {
    //      headerLength = len;
    //   }

    public String getDescription() {
        return getClass().getName();
    }

    public String simpleEncodeCardNo(String cardNo) {
        if (StringUtils.isBlank(cardNo)) {
            return "";
        }
        int length = cardNo.length();
        String result = cardNo.substring(0, 6) + "******" + cardNo.substring(length - 3, length);
        return result;
    }
}