001/*
002 * jPOS Project [http://jpos.org]
003 * Copyright (C) 2000-2026 jPOS Software SRL
004 *
005 * This program is free software: you can redistribute it and/or modify
006 * it under the terms of the GNU Affero General Public License as
007 * published by the Free Software Foundation, either version 3 of the
008 * License, or (at your option) any later version.
009 *
010 * This program is distributed in the hope that it will be useful,
011 * but WITHOUT ANY WARRANTY; without even the implied warranty of
012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
013 * GNU Affero General Public License for more details.
014 *
015 * You should have received a copy of the GNU Affero General Public License
016 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
017 */
018
019package org.jpos.iso.packager;
020
021import org.jpos.iso.*;
022import org.jpos.util.LogEvent;
023import org.jpos.util.Logger;
024
025import java.io.ByteArrayOutputStream;
026import java.util.BitSet;
027import java.util.Map;
028import org.xml.sax.Attributes;
029
030/**
031 * GenericSubFieldPackager
032 * Used to pack composite SubFields from the GenericPackager
033 *
034 * @author Eoin Flood
035 * @see GenericPackager
036 *
037 * This class is basically the same as Base1SubFieldPackager except that it extends
038 * GenericPackager which means that parameters such as emitBitmap, maxvalidField and 
039 * bitmapField can be specified in the GenericPackager xml config file.
040 */
041
042public class GenericSubFieldPackager extends GenericPackager implements ISOSubFieldPackager
043{
044
045    private Integer fieldId = 0;
046
047    public GenericSubFieldPackager() throws ISOException
048    {
049        super();
050    }
051
052    @Override
053    public int getFieldNumber() {
054      return fieldId;
055    }
056
057    @Override
058    public void setGenericPackagerParams(Attributes atts) {
059        super.setGenericPackagerParams(atts);
060        fieldId = Integer.parseInt(atts.getValue("id"));
061    }
062
063    @Override
064    public int unpack (ISOComponent m, byte[] b) throws ISOException 
065    {
066        LogEvent evt = new LogEvent (this, "unpack");
067        try 
068        {
069            if (m.getComposite() != m) 
070                throw new ISOException ("Can't call packager on non Composite");
071            if (b.length == 0)
072                return 0; // nothing to do
073            if (logger != null)  // save a few CPU cycle if no logger available
074                evt.addMessage (ISOUtil.hexString (b));
075
076            int consumed=0;
077            ISOBitMap bitmap = new ISOBitMap (-1);
078
079            BitSet bmap = null;
080            int maxField = fld.length;
081            if (emitBitMap()) 
082            {
083                consumed += getBitMapfieldPackager().unpack(bitmap,b,consumed);
084                bmap = (BitSet) bitmap.getValue();
085                m.set (bitmap);
086                maxField = bmap.size();
087            }
088            for (int i=getFirstField(); i<maxField && consumed < b.length; i++) 
089            {
090                if ((bmap == null || bmap.get(i)) && i<fld.length && fld[i] != null) {
091                    ISOComponent c = fld[i].createComponent(i);
092                    consumed += fld[i].unpack (c, b, consumed);
093                    m.set(c);
094                }
095            }
096            if (b.length != consumed) 
097            {
098                evt.addMessage (
099                "WARNING: unpack len=" +b.length +" consumed=" +consumed);
100            }
101            return consumed;
102        } 
103        catch (ISOException e) 
104        {
105            evt.addMessage (e);
106            throw e;
107        } 
108        catch (Exception e)
109        {
110            evt.addMessage (e);
111            throw new ISOException (e);
112        }
113        finally 
114        {
115            Logger.log (evt);
116        }
117    }
118
119    /**
120     * Pack the subfield into a byte array
121     */
122    @Override
123    public byte[] pack(ISOComponent m) throws ISOException
124    {
125        LogEvent evt = new LogEvent (this, "pack");
126        try (ByteArrayOutputStream bout = new ByteArrayOutputStream(100))
127        {
128            ISOComponent c;
129            Map fields = m.getChildren();
130
131            if (emitBitMap()) 
132            {
133                // BITMAP (-1 in HashTable)
134                c = (ISOComponent) fields.get (-1);
135                byte[] b = getBitMapfieldPackager().pack(c);
136                bout.write(b);
137            }
138
139            for (int i=getFirstField(); i<=m.getMaxField(); i++) 
140            {
141                c = (ISOComponent) fields.get (i);
142                if (c == null && !emitBitMap())
143                    c = new ISOField (i, "");
144                if (c != null) {
145                    try 
146                    {
147                        byte[] b = fld[i].pack(c);
148                        bout.write(b);
149                    } 
150                    catch (Exception e) 
151                    {
152                        evt.addMessage ("error packing subfield "+i);
153                        evt.addMessage (c);
154                        evt.addMessage (e);
155                        throw e;
156                    }
157                }
158            }
159
160            byte[] d = bout.toByteArray();
161            if (logger != null)  // save a few CPU cycle if no logger available
162                evt.addMessage (ISOUtil.hexString (d));
163            return d;
164        } 
165        catch (ISOException e) 
166        {
167            evt.addMessage (e);
168            throw e;
169        } 
170        catch (Exception e)
171        {
172            evt.addMessage (e);
173            throw new ISOException (e);
174        }
175        finally 
176        {
177            Logger.log(evt);
178        }
179    }
180}
181
182