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.LogSource; 024import org.jpos.util.Logger; 025 026import java.io.ByteArrayOutputStream; 027import java.util.Map; 028import java.util.Map.Entry; 029import java.util.Set; 030 031/** 032 * EuroPay SubField packager 033 * @author Eoin Flood 034 * @version $Revision$ $Date$ 035 * @see ISOPackager 036 * @see ISOBasePackager 037 * @see ISOComponent 038 * 039 * This packager is used by EuroPackager to package subfields 040 * such as field 48. 041 */ 042@SuppressWarnings("unchecked") 043public class EuroSubFieldPackager extends ISOBasePackager 044{ 045 protected static Prefixer tagPrefixer = AsciiPrefixer.LL; 046 047 /** 048 * Always return false 049 */ 050 @Override 051 protected boolean emitBitMap() 052 { 053 return false; 054 } 055 056 @Override 057 public byte[] pack (ISOComponent c) throws ISOException { 058 LogEvent evt = new LogEvent (this, "pack"); 059 try (ByteArrayOutputStream bout = new ByteArrayOutputStream(100)) { 060 Map tab = c.getChildren(); 061 062 for (Entry ent : (Set<Entry>) tab.entrySet()) { 063 Integer i = (Integer) ent.getKey(); 064 if (i < 0) 065 continue; 066 if (fld[i] == null) 067 throw new ISOException ("Unsupported sub-field " + i + " packing field " + c.getKey()); 068 if (ent.getValue() instanceof ISOComponent) 069 try { 070 ISOComponent f = (ISOComponent) ent.getValue(); 071 byte[] b = fld[i].pack(f); 072 bout.write(b); 073 } catch (Exception e) { 074 evt.addMessage ("error packing subfield "+i); 075 evt.addMessage (c); 076 evt.addMessage (e); 077 throw e; 078 } 079 } 080 081 byte[] d = bout.toByteArray(); 082 if (logger != null) // save a few CPU cycle if no logger available 083 evt.addMessage (ISOUtil.hexString (d)); 084 return d; 085 } 086 catch (Exception ex) 087 { 088 throw new ISOException (ex); 089 } 090 } 091 092 093 /** 094 * This packager treats field 0 as a field that may or may not be present before the TLV subelements. 095 * 096 * Certain types of messages for some 8583 specs that extend this class' behavior (e.g., the Mastercard implementation 097 * in class {@link MasterCardEBCDICSubFieldPackager}) may not have field 0 present (the TCC in Mastercard's nomenclature). 098 * So, if the corresponding isofield packager for field 0 doesn't fill the {@link ISOComponent}'s value, 099 * we don't store anything as subfield 0 of m. 100 */ 101 @Override 102 public int unpack (ISOComponent m, byte[] b) throws ISOException 103 { 104 LogEvent evt = logger != null ? new LogEvent (this, "unpack") : null; 105 int consumed = 0; 106 ISOComponent c = null; 107 108 // Unpack the fields 109 while (consumed < b.length) { 110 //If this is first iteration and there is a packager for SE 0 then i=0, i.e. use field packager for SE 0 111 //Else determine current tag 112 int i = c == null && fld[0] != null ? 0 : tagPrefixer.decodeLength(b, consumed); 113 114 if (i >= fld.length || fld[i] == null) 115 throw new ISOException("Unsupported sub-field " + i + " unpacking field " + m.getKey()); 116 117 c = fld[i].createComponent(i); 118 consumed += fld[i].unpack (c, b, consumed); 119 if (i != 0 || c.getValue() != null) { 120 if (evt != null) { 121 fieldUnpackLogger(evt, i, c, fld[i], logFieldName); 122 } 123 124 m.set(c); 125 } 126 // else: 127 // If it was field 0 (TCC) && nothing was stored in the component, we discard this component 128 } 129 130 if (logger != null && evt != null) 131 Logger.log (evt); 132 133 return consumed; 134 } 135 136 137 @Override 138 public void setLogger (Logger logger, String realm) { 139 super.setLogger (logger, realm); 140 if (fld != null) { 141 for (int i=0; i<fld.length; i++) { 142 if (fld[i] instanceof ISOMsgFieldPackager) { 143 Object o = ((ISOMsgFieldPackager)fld[i]).getISOMsgPackager(); 144 if (o instanceof LogSource) { 145 ((LogSource)o).setLogger (logger, realm + "-fld-" + i); 146 } 147 } 148 } 149 } 150 } 151 152} 153