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