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    /**
048     * Default constructor.
049     * @throws ISOException if configuration fails
050     */
051    public GenericSubFieldPackager() throws ISOException
052    {
053        super();
054    }
055
056    @Override
057    public int getFieldNumber() {
058      return fieldId;
059    }
060
061    @Override
062    public void setGenericPackagerParams(Attributes atts) {
063        super.setGenericPackagerParams(atts);
064        fieldId = Integer.parseInt(atts.getValue("id"));
065    }
066
067    @Override
068    public int unpack (ISOComponent m, byte[] b) throws ISOException 
069    {
070        LogEvent evt = new LogEvent (this, "unpack");
071        try 
072        {
073            if (m.getComposite() != m) 
074                throw new ISOException ("Can't call packager on non Composite");
075            if (b.length == 0)
076                return 0; // nothing to do
077            if (logger != null)  // save a few CPU cycle if no logger available
078                evt.addMessage (ISOUtil.hexString (b));
079
080            int consumed=0;
081            ISOBitMap bitmap = new ISOBitMap (-1);
082
083            BitSet bmap = null;
084            int maxField = fld.length;
085            if (emitBitMap()) 
086            {
087                consumed += getBitMapfieldPackager().unpack(bitmap,b,consumed);
088                bmap = (BitSet) bitmap.getValue();
089                m.set (bitmap);
090                maxField = bmap.size();
091            }
092            for (int i=getFirstField(); i<maxField && consumed < b.length; i++) 
093            {
094                if ((bmap == null || bmap.get(i)) && i<fld.length && fld[i] != null) {
095                    ISOComponent c = fld[i].createComponent(i);
096                    consumed += fld[i].unpack (c, b, consumed);
097                    m.set(c);
098                }
099            }
100            if (b.length != consumed) 
101            {
102                evt.addMessage (
103                "WARNING: unpack len=" +b.length +" consumed=" +consumed);
104            }
105            return consumed;
106        } 
107        catch (ISOException e) 
108        {
109            evt.addMessage (e);
110            throw e;
111        } 
112        catch (Exception e)
113        {
114            evt.addMessage (e);
115            throw new ISOException (e);
116        }
117        finally 
118        {
119            Logger.log (evt);
120        }
121    }
122
123    /**
124     * Pack the subfield into a byte array
125     */
126    @Override
127    public byte[] pack(ISOComponent m) throws ISOException
128    {
129        LogEvent evt = new LogEvent (this, "pack");
130        try (ByteArrayOutputStream bout = new ByteArrayOutputStream(100))
131        {
132            ISOComponent c;
133            Map fields = m.getChildren();
134
135            if (emitBitMap()) 
136            {
137                // BITMAP (-1 in HashTable)
138                c = (ISOComponent) fields.get (-1);
139                byte[] b = getBitMapfieldPackager().pack(c);
140                bout.write(b);
141            }
142
143            for (int i=getFirstField(); i<=m.getMaxField(); i++) 
144            {
145                c = (ISOComponent) fields.get (i);
146                if (c == null && !emitBitMap())
147                    c = new ISOField (i, "");
148                if (c != null) {
149                    try 
150                    {
151                        byte[] b = fld[i].pack(c);
152                        bout.write(b);
153                    } 
154                    catch (Exception e) 
155                    {
156                        evt.addMessage ("error packing subfield "+i);
157                        evt.addMessage (c);
158                        evt.addMessage (e);
159                        throw e;
160                    }
161                }
162            }
163
164            byte[] d = bout.toByteArray();
165            if (logger != null)  // save a few CPU cycle if no logger available
166                evt.addMessage (ISOUtil.hexString (d));
167            return d;
168        } 
169        catch (ISOException e) 
170        {
171            evt.addMessage (e);
172            throw e;
173        } 
174        catch (Exception e)
175        {
176            evt.addMessage (e);
177            throw new ISOException (e);
178        }
179        finally 
180        {
181            Logger.log(evt);
182        }
183    }
184}
185
186