| @@ -0,0 +1,217 @@ | ||
| /* | ||
| * jPOS Project [http://jpos.org] | ||
| * Copyright (C) 2000-2012 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 org.jpos.iso.packager.TagMapper; | ||
|
|
||
| import java.io.IOException; | ||
| import java.io.InputStream; | ||
| import java.io.ObjectOutput; | ||
| import java.io.UnsupportedEncodingException; | ||
|
|
||
| /** | ||
| * Base class and template for handling tagged fields. | ||
| * <p/> | ||
| * This should support both fixed length and variable length tags. | ||
| */ | ||
| public abstract class TaggedFieldPackagerBase extends ISOFieldPackager { | ||
|
|
||
| private TagMapper tagMapper; | ||
| private ISOFieldPackager delegate; | ||
| private int parentFieldNumber; | ||
| private boolean packingLenient = false; | ||
| private boolean unpackingLenient = false; | ||
|
|
||
| public TaggedFieldPackagerBase() { | ||
| super(); | ||
| } | ||
|
|
||
| /** | ||
| * @param len - | ||
| * field len | ||
| * @param description symbolic description | ||
| */ | ||
| public TaggedFieldPackagerBase(int len, String description) { | ||
| super(len, description); | ||
| this.delegate = getDelegate(len, description); | ||
| } | ||
|
|
||
| /** | ||
| * @param c - | ||
| * a component | ||
| * @return packed component | ||
| * @throws org.jpos.iso.ISOException | ||
| */ | ||
| public byte[] pack(ISOComponent c) throws ISOException { | ||
| byte[] packed; | ||
| if (c.getValue() == null) { | ||
| packed = new byte[0]; | ||
| } else { | ||
| String tag = getTagMapper().getTagForField(getParentFieldNumber(), (Integer) c.getKey()); | ||
| if (tag == null) { | ||
| if (!isPackingLenient()) { | ||
| throw new ISOException("No tag mapping found for field: " + parentFieldNumber + "." + c.getKey()); | ||
| } | ||
| packed = new byte[0]; | ||
| } else { | ||
| byte[] tagBytes; | ||
| try { | ||
| tagBytes = tag.getBytes(ISOUtil.ENCODING); | ||
| } catch (UnsupportedEncodingException e) { | ||
| throw new ISOException(e); | ||
| } | ||
| byte[] message = getDelegate().pack(c); | ||
| packed = new byte[tagBytes.length + message.length]; | ||
| System.arraycopy(tagBytes, 0, packed, 0, tagBytes.length); | ||
| System.arraycopy(message, 0, packed, tagBytes.length, message.length); | ||
| } | ||
| } | ||
| return packed; | ||
| } | ||
|
|
||
| @Override | ||
| public void pack(ISOComponent c, ObjectOutput out) throws IOException, ISOException { | ||
| if (c.getValue() != null) { | ||
| super.pack(c, out); | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * @param c - | ||
| * the Component to unpack | ||
| * @param b - | ||
| * binary image | ||
| * @param offset - | ||
| * starting offset within the binary image | ||
| * @return consumed bytes | ||
| * @throws ISOException | ||
| */ | ||
| public int unpack(ISOComponent c, byte[] b, int offset) throws ISOException { | ||
| try { | ||
| int consumed; | ||
| byte[] tagBytes = new byte[getTagNameLength()]; | ||
| System.arraycopy(b, offset, tagBytes, 0, getTagNameLength()); | ||
| String tag = new String(tagBytes, ISOUtil.ENCODING); | ||
| if (!(c instanceof ISOField)) | ||
| throw new ISOException(c.getClass().getName() | ||
| + " is not an ISOField"); | ||
| Integer fieldNumber = getTagMapper().getFieldNumberForTag(getParentFieldNumber(), tag); | ||
| if (fieldNumber == null || fieldNumber.intValue() < 0) { | ||
| if (!isUnpackingLenient()) { | ||
| throw new ISOException("No field mapping found for tag: " + parentFieldNumber + "." + tag); | ||
| } | ||
| consumed = 0; | ||
| } else { | ||
| if (c.getKey().equals(fieldNumber)) { | ||
| consumed = getTagNameLength() + getDelegate().unpack(c, b, offset + tagBytes.length); | ||
| } else { | ||
| consumed = 0; | ||
| } | ||
| } | ||
| return consumed; | ||
| } catch (UnsupportedEncodingException e) { | ||
| throw new ISOException(e); | ||
| } | ||
| } | ||
|
|
||
| public void unpack(ISOComponent c, InputStream in) throws IOException, | ||
| ISOException { | ||
| if (!in.markSupported()) { | ||
| throw new ISOException("InputStream should support marking"); | ||
| } | ||
| if (!(c instanceof ISOField)) | ||
| throw new ISOException(c.getClass().getName() | ||
| + " is not an ISOField"); | ||
| in.mark(getTagNameLength() + 1); | ||
| Integer fieldNumber; | ||
| String tag; | ||
| tag = new String(readBytes(in, getTagNameLength()), ISOUtil.ENCODING); | ||
| fieldNumber = getTagMapper().getFieldNumberForTag(getParentFieldNumber(), tag); | ||
| if (fieldNumber == null || fieldNumber.intValue() < 0) { | ||
| if (!isUnpackingLenient()) { | ||
| throw new ISOException("No field mapping found for tag: " + parentFieldNumber + "." + tag); | ||
| } | ||
| in.reset(); | ||
| } else { | ||
| if (c.getKey().equals(fieldNumber)) { | ||
| getDelegate().unpack(c, in); | ||
| } else { | ||
| in.reset(); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| private ISOFieldPackager getDelegate() { | ||
| if (delegate == null) { | ||
| synchronized (this) { | ||
| if (delegate == null) { | ||
| delegate = getDelegate(getLength(), getDescription()); | ||
| } | ||
| } | ||
| } | ||
| return delegate; | ||
| } | ||
|
|
||
| protected abstract ISOFieldPackager getDelegate(int len, String description); | ||
|
|
||
| protected abstract int getTagNameLength(); | ||
|
|
||
| /** | ||
| * @return A boolean value for or against lenient packing | ||
| */ | ||
| protected boolean isPackingLenient() { | ||
| return packingLenient; | ||
| } | ||
|
|
||
| /** | ||
| * @return A boolean value for or against lenient unpacking | ||
| */ | ||
| protected boolean isUnpackingLenient() { | ||
| return unpackingLenient; | ||
| } | ||
|
|
||
| public void setPackingLenient(boolean packingLenient) { | ||
| this.packingLenient = packingLenient; | ||
| } | ||
|
|
||
| public void setUnpackingLenient(boolean unpackingLenient) { | ||
| this.unpackingLenient = unpackingLenient; | ||
| } | ||
|
|
||
| public int getMaxPackedLength() { | ||
| return getTagNameLength() + getDelegate().getMaxPackedLength(); | ||
| } | ||
|
|
||
| public int getParentFieldNumber() { | ||
| return parentFieldNumber; | ||
| } | ||
|
|
||
| public void setParentFieldNumber(int parentFieldNumber) { | ||
| this.parentFieldNumber = parentFieldNumber; | ||
| } | ||
|
|
||
| public void setTagMapper(TagMapper tagMapper) { | ||
| this.tagMapper = tagMapper; | ||
| } | ||
|
|
||
| protected TagMapper getTagMapper() { | ||
| return tagMapper; | ||
| } | ||
|
|
||
| } |
| @@ -0,0 +1,243 @@ | ||
| /* | ||
| * jPOS Project [http://jpos.org] | ||
| * Copyright (C) 2000-2012 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.packager; | ||
|
|
||
| import org.jpos.iso.*; | ||
| import org.jpos.util.LogEvent; | ||
| import org.jpos.util.Logger; | ||
| import org.xml.sax.Attributes; | ||
|
|
||
| import java.io.EOFException; | ||
| import java.io.IOException; | ||
| import java.io.InputStream; | ||
| import java.util.ArrayList; | ||
| import java.util.List; | ||
| import java.util.Map; | ||
|
|
||
| /** | ||
| * | ||
| * Packager for fields containing TLV sub-fields without a bitmap | ||
| * | ||
| * The Tag is alphanumeric so a mapping between fieldNumber and tag are required. A TagMapper | ||
| * implementation should provide this mapping | ||
| * | ||
| */ | ||
|
|
||
| public class GenericTaggedFieldsPackager extends GenericPackager { | ||
|
|
||
| private TagMapper tagMapper = null; | ||
| private Integer fieldId = 0; | ||
|
|
||
| public GenericTaggedFieldsPackager() throws ISOException { | ||
| super(); | ||
| } | ||
|
|
||
| @Override | ||
| public int unpack(ISOComponent m, byte[] b) throws ISOException { | ||
| LogEvent evt = new LogEvent(this, "unpack"); | ||
| try { | ||
| if (m.getComposite() != m) | ||
| throw new ISOException("Can't call packager on non Composite"); | ||
| if (b.length == 0) | ||
| return 0; // nothing to do | ||
| if (logger != null) // save a few CPU cycle if no logger available | ||
| evt.addMessage(ISOUtil.hexString(b)); | ||
|
|
||
| int consumed = 0; | ||
| int maxField = fld.length; | ||
| for (int i = getFirstField(); i < maxField && consumed < b.length; i++) { | ||
| if (fld[i] != null) { | ||
| ISOComponent c = fld[i].createComponent(i); | ||
| int unpacked = fld[i].unpack(c, b, consumed); | ||
| consumed = consumed + unpacked; | ||
| if (unpacked > 0) { | ||
| m.set(c); | ||
| } | ||
| } | ||
| } | ||
| 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); | ||
| } finally { | ||
| Logger.log(evt); | ||
| } | ||
| } | ||
|
|
||
| @Override | ||
| 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); | ||
| } | ||
|
|
||
| int maxField = fld.length; | ||
| for (int i = getFirstField(); i < maxField; i++) { | ||
| if (fld[i] == null) | ||
| continue; | ||
|
|
||
| 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); | ||
|
|
||
| } | ||
| } 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); | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Pack the subfield into a byte array | ||
| */ | ||
|
|
||
| public byte[] pack(ISOComponent m) throws ISOException { | ||
| LogEvent evt = new LogEvent(this, "pack"); | ||
| try { | ||
| ISOComponent c; | ||
| List<byte[]> l = new ArrayList<byte[]>(); | ||
| Map fields = m.getChildren(); | ||
| int len = 0; | ||
|
|
||
| for (int i = getFirstField(); i <= m.getMaxField(); i++) { | ||
| c = (ISOComponent) fields.get(i); | ||
| if (c != null) { | ||
| try { | ||
| byte[] b = fld[i].pack(c); | ||
| len += b.length; | ||
| l.add(b); | ||
| } catch (Exception e) { | ||
| evt.addMessage("error packing subfield " + i); | ||
| evt.addMessage(c); | ||
| evt.addMessage(e); | ||
| throw e; | ||
| } | ||
| } | ||
| } | ||
| int k = 0; | ||
| byte[] d = new byte[len]; | ||
| for (byte[] b : l) { | ||
| System.arraycopy(b, 0, d, k, b.length); | ||
| k += b.length; | ||
| } | ||
| if (logger != null) // save a few CPU cycle if no logger available | ||
| evt.addMessage(ISOUtil.hexString(d)); | ||
| return d; | ||
| } catch (ISOException e) { | ||
| evt.addMessage(e); | ||
| throw e; | ||
| } catch (Exception e) { | ||
| evt.addMessage(e); | ||
| throw new ISOException(e); | ||
| } finally { | ||
| Logger.log(evt); | ||
| } | ||
| } | ||
|
|
||
| public void setFieldPackager(ISOFieldPackager[] fld) { | ||
| super.setFieldPackager(fld); | ||
| for (int i = 0; i < fld.length; i++) { | ||
| if (fld[i] instanceof TaggedFieldPackagerBase) { | ||
| ((TaggedFieldPackagerBase) fld[i]).setParentFieldNumber(fieldId); | ||
| ((TaggedFieldPackagerBase) fld[i]).setTagMapper(tagMapper); | ||
| ((TaggedFieldPackagerBase) fld[i]).setPackingLenient(isPackingLenient()); | ||
| ((TaggedFieldPackagerBase) fld[i]).setUnpackingLenient(isUnpackingLenient()); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| @Override | ||
| protected void setGenericPackagerParams(Attributes atts) { | ||
| super.setGenericPackagerParams(atts); | ||
| try { | ||
| Class<? extends TagMapper> clazz = Class.forName(atts.getValue("tagMapper")).asSubclass(TagMapper.class); | ||
| tagMapper = clazz.newInstance(); | ||
| fieldId = Integer.parseInt(atts.getValue("id")); | ||
| } catch (InstantiationException e) { | ||
| throw new RuntimeException(e); | ||
| } catch (IllegalAccessException e) { | ||
| throw new RuntimeException(e); | ||
| } catch (ClassNotFoundException e) { | ||
| throw new RuntimeException(e); | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Subclasses may override this method if a lenient packing is required when a | ||
| * field-to-tag mapping cannot be found. | ||
| * | ||
| * @return A boolean value for or against lenient packing | ||
| */ | ||
| protected boolean isPackingLenient() { | ||
| return false; | ||
| } | ||
|
|
||
| /** | ||
| * Subclasses may override this method if a lenient unpacking is required when a | ||
| * tag-to-field mapping cannot be found. | ||
| * | ||
| * @return A boolean value for or against lenient unpacking | ||
| */ | ||
| protected boolean isUnpackingLenient() { | ||
| return false; | ||
| } | ||
|
|
||
| } | ||
|
|
||
|
|
| @@ -0,0 +1,30 @@ | ||
| /* | ||
| * jPOS Project [http://jpos.org] | ||
| * Copyright (C) 2000-2012 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.packager; | ||
|
|
||
| /** | ||
| * | ||
| */ | ||
| public interface TagMapper { | ||
|
|
||
| public String getTagForField(int fieldNumber, int subFieldNumber); | ||
|
|
||
| public Integer getFieldNumberForTag(int fieldNumber, String tag); | ||
|
|
||
| } |
| @@ -0,0 +1,34 @@ | ||
| <?xml version="1.0" encoding="UTF-8"?> | ||
|
|
||
| <!ELEMENT isopackager (isofield+,isofieldpackager*)*> | ||
| <!ATTLIST isopackager maxValidField CDATA #IMPLIED> | ||
| <!ATTLIST isopackager bitmapField CDATA #IMPLIED> | ||
| <!ATTLIST isopackager firstField CDATA #IMPLIED> | ||
| <!ATTLIST isopackager emitBitmap (true|false) #IMPLIED> | ||
| <!ATTLIST isopackager headerLength CDATA #IMPLIED> | ||
|
|
||
| <!-- isofield --> | ||
| <!ELEMENT isofield (#PCDATA)> | ||
| <!ATTLIST isofield id CDATA #REQUIRED> | ||
| <!ATTLIST isofield length CDATA #REQUIRED> | ||
| <!ATTLIST isofield name CDATA #REQUIRED> | ||
| <!ATTLIST isofield class NMTOKEN #REQUIRED> | ||
| <!ATTLIST isofield token CDATA #IMPLIED> | ||
| <!ATTLIST isofield pad (true|false) #IMPLIED> | ||
|
|
||
| <!-- isofieldpackager --> | ||
| <!ELEMENT isofieldpackager (isofield+,isofieldpackager*)*> | ||
| <!ATTLIST isofieldpackager id CDATA #REQUIRED> | ||
| <!ATTLIST isofieldpackager name CDATA #REQUIRED> | ||
| <!ATTLIST isofieldpackager length CDATA #REQUIRED> | ||
| <!ATTLIST isofieldpackager class NMTOKEN #REQUIRED> | ||
| <!ATTLIST isofieldpackager token CDATA #IMPLIED> | ||
| <!ATTLIST isofieldpackager pad (true|false) #IMPLIED> | ||
| <!ATTLIST isofieldpackager packager NMTOKEN #REQUIRED> | ||
| <!ATTLIST isofieldpackager emitBitmap (true|false) #IMPLIED> | ||
| <!ATTLIST isofieldpackager maxValidField CDATA #IMPLIED> | ||
| <!ATTLIST isofieldpackager bitmapField CDATA #IMPLIED> | ||
| <!ATTLIST isofieldpackager firstField CDATA #IMPLIED> | ||
| <!ATTLIST isofieldpackager headerLength CDATA #IMPLIED> | ||
| <!ATTLIST isofieldpackager tagMapper CDATA #IMPLIED> | ||
|
|
| @@ -0,0 +1,116 @@ | ||
| /* | ||
| * jPOS Project [http://jpos.org] | ||
| * Copyright (C) 2000-2012 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.packager; | ||
|
|
||
| import junit.framework.TestCase; | ||
| import org.jpos.iso.ISOField; | ||
| import org.jpos.iso.ISOMsg; | ||
| import org.junit.Test; | ||
|
|
||
| import java.io.FileInputStream; | ||
| import java.io.FileOutputStream; | ||
| import java.util.HashMap; | ||
| import java.util.Map; | ||
|
|
||
| /** | ||
| * | ||
| */ | ||
| public class TaggedFieldPackagerBaseTest extends TestCase { | ||
|
|
||
| @Test | ||
| public void testPack() throws Exception { | ||
| String path = "target/test-classes/org/jpos/iso/packagers/"; | ||
| GenericPackager genericPackager = new GenericPackager(new FileInputStream(path + "ISO93TLVPackager.xml")); | ||
|
|
||
| ISOMsg msg = new ISOMsg(); | ||
| msg.setMTI("1100"); | ||
| msg.set(new ISOField(2, "123456")); | ||
|
|
||
| ISOMsg subFieldsContainer = new ISOMsg(48); | ||
| ISOField tlvField = new ISOField(1); | ||
| tlvField.setValue("48TagA1"); | ||
| subFieldsContainer.set(tlvField); | ||
|
|
||
| ISOField tlvField2 = new ISOField(3); | ||
| tlvField2.setValue("48TagA3"); | ||
| subFieldsContainer.set(tlvField2); | ||
|
|
||
| msg.set(subFieldsContainer); | ||
|
|
||
| ISOMsg subFieldsContainer2 = new ISOMsg(60); | ||
| ISOField tlvField3 = new ISOField(1); | ||
| tlvField3.setValue("60TagA1"); | ||
| subFieldsContainer2.set(tlvField3); | ||
|
|
||
| msg.set(subFieldsContainer2); | ||
|
|
||
| msg.setHeader("HEADER ".getBytes()); | ||
| msg.setPackager(genericPackager); | ||
| byte[] packed = msg.pack(); | ||
| assertNotNull(packed); | ||
|
|
||
| FileOutputStream fos = new FileOutputStream(path + "ISO93TLVPackager.bin"); | ||
| fos.write(packed); | ||
| fos.close(); | ||
| } | ||
|
|
||
|
|
||
| @Test | ||
| public void testUnpack() throws Exception { | ||
| String path = "target/test-classes/org/jpos/iso/packagers/"; | ||
| GenericPackager genericPackager = new GenericPackager(new FileInputStream(path + "ISO93TLVPackager.xml")); | ||
|
|
||
| ISOMsg msg = new ISOMsg(); | ||
| genericPackager.unpack(msg, new FileInputStream(path + "ISO93TLVPackager.bin")); | ||
|
|
||
| assertEquals("1100", msg.getMTI()); | ||
| assertEquals("48TagA1", ((ISOField) ((ISOMsg) msg.getComponent(48)).getComponent(1)).getValue()); | ||
| } | ||
|
|
||
| public static class TagMapperImpl implements TagMapper { | ||
|
|
||
| private static Map<String, Integer> tagToNumberMap = new HashMap<String, Integer>(); | ||
| private static Map<String, String> numberToTagMap = new HashMap<String, String>(); | ||
|
|
||
| static { | ||
| tagToNumberMap.put("48.A1", 1); | ||
| numberToTagMap.put("48.1", "A1"); | ||
|
|
||
| tagToNumberMap.put("48.A2", 2); | ||
| numberToTagMap.put("48.2", "A2"); | ||
|
|
||
| tagToNumberMap.put("48.A3", 3); | ||
| numberToTagMap.put("48.3", "A3"); | ||
|
|
||
| tagToNumberMap.put("60.A1", 1); | ||
| numberToTagMap.put("60.1", "A1"); | ||
| } | ||
|
|
||
| public TagMapperImpl() { | ||
| } | ||
|
|
||
| public String getTagForField(int fieldNumber, int subFieldNumber) { | ||
| return numberToTagMap.get(fieldNumber + "." + subFieldNumber); | ||
| } | ||
|
|
||
| public Integer getFieldNumberForTag(int fieldNumber, String tag) { | ||
| return tagToNumberMap.get(fieldNumber + "." + tag); | ||
| } | ||
| } | ||
| } |
| @@ -0,0 +1,250 @@ | ||
| <?xml version="1.0" encoding="UTF-8" standalone="no"?> | ||
| <!DOCTYPE isopackager SYSTEM "./generic-subtag-packager.dtd"> | ||
|
|
||
| <!-- ISO 8583:2003 (ASCII) field descriptions for GenericPackager --> | ||
|
|
||
| <isopackager> | ||
| <isofield | ||
| id="0" | ||
| length="4" | ||
| name="Message Type Indicator" | ||
| pad="false" | ||
| class="org.jpos.iso.IFA_NUMERIC"/> | ||
| <isofield | ||
| id="1" | ||
| length="16" | ||
| name="Bitmap" | ||
| class="org.jpos.iso.IFB_BITMAP"/> | ||
| <isofield | ||
| id="2" | ||
| length="19" | ||
| name="Primary Account number" | ||
| pad="false" | ||
| class="org.jpos.iso.IFA_LLCHAR"/> | ||
| <isofield | ||
| id="3" | ||
| length="6" | ||
| name="Processing Code" | ||
| pad="false" | ||
| class="org.jpos.iso.IFA_NUMERIC"/> | ||
| <isofield | ||
| id="4" | ||
| length="12" | ||
| name="Transaction Amount" | ||
| pad="true" | ||
| class="org.jpos.iso.IFA_NUMERIC"/> | ||
| <isofield | ||
| id="7" | ||
| length="14" | ||
| name="Transaction Date and Time" | ||
| pad="false" | ||
| class="org.jpos.iso.IFA_NUMERIC"/> | ||
| <isofield | ||
| id="8" | ||
| length="12" | ||
| name="Amount, Cardholder Billing Fee" | ||
| pad="true" | ||
| class="org.jpos.iso.IFA_NUMERIC"/> | ||
| <isofield | ||
| id="11" | ||
| length="6" | ||
| name="System Trace Audit Number" | ||
| pad="true" | ||
| class="org.jpos.iso.IFA_NUMERIC"/> | ||
| <isofield | ||
| id="12" | ||
| length="6" | ||
| name="Time, Local Transaction" | ||
| pad="false" | ||
| class="org.jpos.iso.IFA_NUMERIC"/> | ||
| <isofield | ||
| id="13" | ||
| length="8" | ||
| name="Date, Local Transaction" | ||
| pad="false" | ||
| class="org.jpos.iso.IFA_NUMERIC"/> | ||
| <isofield | ||
| id="14" | ||
| length="4" | ||
| name="Date, Expiration" | ||
| pad="false" | ||
| class="org.jpos.iso.IFA_NUMERIC"/> | ||
| <isofield | ||
| id="15" | ||
| length="4" | ||
| name="Date, Settlement" | ||
| pad="false" | ||
| class="org.jpos.iso.IFA_NUMERIC"/> | ||
| <isofield | ||
| id="18" | ||
| length="4" | ||
| name="Merchant Type" | ||
| pad="false" | ||
| class="org.jpos.iso.IFA_NUMERIC"/> | ||
| <isofield | ||
| id="22" | ||
| length="3" | ||
| name="POS Entry Mode" | ||
| pad="false" | ||
| class="org.jpos.iso.IFA_NUMERIC"/> | ||
| <isofield | ||
| id="23" | ||
| length="2" | ||
| name="EMV Contactless PAN Sequence Number" | ||
| pad="true" | ||
| class="org.jpos.iso.IFA_NUMERIC"/> | ||
| <isofield | ||
| id="25" | ||
| length="2" | ||
| name="POS Condition Code" | ||
| pad="false" | ||
| class="org.jpos.iso.IFA_NUMERIC"/> | ||
| <isofield | ||
| id="35" | ||
| length="37" | ||
| name="Track 2 data" | ||
| class="org.jpos.iso.IFA_LLCHAR"/> | ||
| <isofield | ||
| id="37" | ||
| length="12" | ||
| name="Retrieval reference number" | ||
| class="org.jpos.iso.IF_CHAR"/> | ||
| <isofield | ||
| id="38" | ||
| length="6" | ||
| name="Authorization ID Response" | ||
| class="org.jpos.iso.IF_CHAR"/> | ||
| <isofield | ||
| id="39" | ||
| length="2" | ||
| name="Response Code" | ||
| pad="false" | ||
| class="org.jpos.iso.IF_CHAR"/> | ||
| <isofield | ||
| id="41" | ||
| length="3" | ||
| name="Card Acquirer Terminal Id" | ||
| class="org.jpos.iso.IFA_NUMERIC"/> | ||
| <isofield | ||
| id="42" | ||
| length="12" | ||
| name="Card Acquirer Id" | ||
| class="org.jpos.iso.IFA_NUMERIC"/> | ||
| <isofield | ||
| id="44" | ||
| length="9999" | ||
| name="Additional Response Data Private Use" | ||
| class="org.jpos.iso.IFA_LLLLCHAR"/> | ||
| <isofield | ||
| id="45" | ||
| length="76" | ||
| name="Track 1 Data" | ||
| class="org.jpos.iso.IFA_LLCHAR"/> | ||
|
|
||
| <isofieldpackager | ||
| id="48" | ||
| length="999" | ||
| name="Additional Data Private Use" | ||
| class="org.jpos.iso.IFA_LLLCHAR" | ||
| emitBitmap="false" | ||
| tagMapper="org.jpos.iso.packager.TaggedFieldPackagerBaseTest$TagMapperImpl" | ||
| packager="org.jpos.iso.packager.GenericTaggedFieldsPackager"> | ||
| <isofield | ||
| id="1" | ||
| length="29" | ||
| name="Address Verification (AVS) Request Data" | ||
| class="org.jpos.iso.IFA_TTLLCHAR"/> | ||
| <isofield | ||
| id="2" | ||
| length="1" | ||
| name="Address Verification (AVS) Response Data" | ||
| class="org.jpos.iso.IFA_TTLLCHAR"/> | ||
| <isofield | ||
| id="3" | ||
| length="8" | ||
| name="Generic Transaction Additional Data" | ||
| class="org.jpos.iso.IFA_TTLLCHAR"/> | ||
| <isofield | ||
| id="4" | ||
| length="1" | ||
| name="Canadian Debit Account Type" | ||
| class="org.jpos.iso.IFA_TTLLCHAR"/> | ||
| <isofield | ||
| id="5" | ||
| length="1" | ||
| name="Transaction Identifier Data" | ||
| class="org.jpos.iso.IFA_TTLLCHAR"/> | ||
| </isofieldpackager> | ||
|
|
||
| <isofield | ||
| id="49" | ||
| length="3" | ||
| name="Currency Code, Transaction" | ||
| class="org.jpos.iso.IFA_NUMERIC"/> | ||
| <isofield | ||
| id="52" | ||
| length="16" | ||
| name="Personal Identification Number" | ||
| class="org.jpos.iso.IF_CHAR"/> | ||
| <isofield | ||
| id="53" | ||
| length="16" | ||
| name="Security Related Control Information" | ||
| class="org.jpos.iso.IF_CHAR"/> | ||
| <isofield | ||
| id="54" | ||
| length="12" | ||
| pad="true" | ||
| name="Additional Amount" | ||
| class="org.jpos.iso.IFA_NUMERIC"/> | ||
| <isofield | ||
| id="55" | ||
| length="513" | ||
| name="Chip Card Data EMV Contactless Specification" | ||
| class="org.jpos.iso.IFB_LLLCHAR"/> | ||
| <isofieldpackager | ||
| id="60" | ||
| length="999" | ||
| name="Reserved National – 1 - Transaction Environment Data" | ||
| class="org.jpos.iso.IFA_LLLCHAR" | ||
| emitBitmap="false" | ||
| tagMapper="org.jpos.iso.packager.TaggedFieldPackagerBaseTest$TagMapperImpl" | ||
| packager="org.jpos.iso.packager.GenericTaggedFieldsPackager"> | ||
| <isofield | ||
| id="1" | ||
| length="21" | ||
| name="Chase Paymentech Defined Point of Service Data" | ||
| class="org.jpos.iso.IFA_TTLLLCHAR"/> | ||
| </isofieldpackager> | ||
| <isofield | ||
| id="62" | ||
| length="999" | ||
| name="Reserved Private 2" | ||
| class="org.jpos.iso.IFA_LLLCHAR"/> | ||
| <isofield | ||
| id="63" | ||
| length="999" | ||
| name="Reserved Private 2" | ||
| class="org.jpos.iso.IFA_LLLCHAR"/> | ||
| <isofield | ||
| id="70" | ||
| length="3" | ||
| name="Network Management Information Code" | ||
| class="org.jpos.iso.IFA_NUMERIC"/> | ||
| <isofield | ||
| id="71" | ||
| length="7" | ||
| name="Message Number Security Message Counter" | ||
| class="org.jpos.iso.IFB_NUMERIC"/> | ||
| <isofield | ||
| id="72" | ||
| length="7" | ||
| name="Message Number Last Security Message Counter" | ||
| class="org.jpos.iso.IFB_NUMERIC"/> | ||
| <isofield | ||
| id="90" | ||
| length="46" | ||
| name="Original Transaction Data" | ||
| pad="false" | ||
| class="org.jpos.iso.IF_CHAR"/> | ||
| </isopackager> |
| @@ -0,0 +1,138 @@ | ||
| jPOS Project | ||
| Contributor License Agreement V1.0 | ||
| based on http://www.apache.org/licenses/ | ||
|
|
||
| Thank you for your interest in the jPOS project by Alejandro P. Revilla | ||
| (Uruguayan company #212 752 380 016) doing business as jPOS Organization | ||
| (jPOS.org). In order to clarify the intellectual property license granted with | ||
| Contributions from any person or entity, jPOS.org must have a Contributor | ||
| License Agreement ("CLA") that has been signed by each Contributor, indicating | ||
| agreement to the license terms below. This license is for your protection as a | ||
| Contributor as well as the protection of jPOS.org and its users; it does not | ||
| change your rights to use your own Contributions for any other purpose. | ||
|
|
||
| If you have not already done so, please complete this agreement and | ||
| commit it to the jPOS repository at | ||
| https://svn.sourceforge.net/svnroot/jpos at legal/cla-USERNAME.txt using | ||
| your authenticated SourceForge login. If you do not have commit | ||
| privilege to the repository, please email the file to license@jpos.org. | ||
| If possible, digitally sign the committed file, otherwise also send a | ||
| signed Agreement to jPOS.org. | ||
|
|
||
| Please read this document carefully before signing and keep a copy for | ||
| your records. | ||
|
|
||
| Full name: Vishnu Pillai | ||
| E-Mail: vishnu_pillai@yahoo.com | ||
| Mailing Address: 4205 Mowry Ave, Apt 10, Fremont, CA - 94538 | ||
|
|
||
| You accept and agree to the following terms and conditions for Your | ||
| present and future Contributions submitted to jPOS.org. In return, | ||
| jPOS.org shall not use Your Contributions in a way that is | ||
| contrary to the software license in effect at the time of the | ||
| Contribution. Except for the license granted herein to jPOS.org | ||
| and recipients of software distributed by jPOS.org, You reserve | ||
| all right, title, and interest in and to Your Contributions. | ||
|
|
||
| 1. Definitions. | ||
|
|
||
| "You" (or "Your") shall mean the copyright owner or legal entity | ||
| authorized by the copyright owner that is making this Agreement | ||
| with jPOS.org. For legal entities, the entity making a | ||
| Contribution and all other entities that control, are controlled | ||
| by, or are under common control with that entity are considered to | ||
| be a single Contributor. For the purposes of this definition, | ||
| "control" means (i) the power, direct or indirect, to cause the | ||
| direction or management of such entity, whether by contract or | ||
| otherwise, or (ii) ownership of fifty percent (50%) or more of the | ||
| outstanding shares, or (iii) beneficial ownership of such entity. | ||
|
|
||
| "Contribution" shall mean any original work of authorship, | ||
| including any modifications or additions to an existing work, that | ||
| is intentionally submitted by You to jPOS.org for inclusion | ||
| in, or documentation of, any of the products owned or managed by | ||
| jPOS.org (the "Work"). For the purposes of this definition, | ||
| "submitted" means any form of electronic, verbal, or written | ||
| communication sent to jPOS.org or its representatives, | ||
| including but not limited to communication on electronic mailing | ||
| lists, source code control systems, and issue tracking systems that | ||
| are managed by, or on behalf of, jPOS.org for the purpose of | ||
| discussing and improving the Work, but excluding communication that | ||
| is conspicuously marked or otherwise designated in writing by You | ||
| as "Not a Contribution." | ||
|
|
||
| 2. Grant of Copyright License. Subject to the terms and conditions of | ||
| this Agreement, You hereby grant to jPOS.org and to | ||
| recipients of software distributed by jPOS.org a perpetual, | ||
| worldwide, non-exclusive, no-charge, royalty-free, irrevocable | ||
| copyright license to reproduce, prepare derivative works of, | ||
| publicly display, publicly perform, sublicense, and distribute Your | ||
| Contributions and such derivative works. | ||
|
|
||
| 3. Grant of Patent License. Subject to the terms and conditions of | ||
| this Agreement, You hereby grant to jPOS.org and to | ||
| recipients of software distributed by jPOS.org a perpetual, | ||
| worldwide, non-exclusive, no-charge, royalty-free, irrevocable | ||
| (except as stated in this section) patent license to make, have | ||
| made, use, offer to sell, sell, import, and otherwise transfer the | ||
| Work, where such license applies only to those patent claims | ||
| licensable by You that are necessarily infringed by Your | ||
| Contribution(s) alone or by combination of Your Contribution(s) | ||
| with the Work to which such Contribution(s) was submitted. If any | ||
| entity institutes patent litigation against You or any other entity | ||
| (including a cross-claim or counterclaim in a lawsuit) alleging | ||
| that your Contribution, or the Work to which you have contributed, | ||
| constitutes direct or contributory patent infringement, then any | ||
| patent licenses granted to that entity under this Agreement for | ||
| that Contribution or Work shall terminate as of the date such | ||
| litigation is filed. | ||
|
|
||
| 4. You represent that you are legally entitled to grant the above | ||
| license. If your employer(s) has rights to intellectual property | ||
| that you create that includes your Contributions, you represent | ||
| that you have received permission to make Contributions on behalf | ||
| of that employer, that your employer has waived such rights for | ||
| your Contributions to jPOS.org, or that your employer has | ||
| executed a separate Corporate CLA with jPOS.org. | ||
|
|
||
| 5. You represent that each of Your Contributions is Your original | ||
| creation (see section 7 for submissions on behalf of others). You | ||
| represent that Your Contribution submissions include complete | ||
| details of any third-party license or other restriction (including, | ||
| but not limited to, related patents and trademarks) of which you | ||
| are personally aware and which are associated with any part of Your | ||
| Contributions. | ||
|
|
||
| 6. You are not expected to provide support for Your Contributions, | ||
| except to the extent You desire to provide support. You may provide | ||
| support for free, for a fee, or not at all. Unless required by | ||
| applicable law or agreed to in writing, You provide Your | ||
| Contributions on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS | ||
| OF ANY KIND, either express or implied, including, without | ||
| limitation, any warranties or conditions of TITLE, NON- | ||
| INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. | ||
|
|
||
| 7. Should You wish to submit work that is not Your original creation, | ||
| You may submit it to jPOS.org separately from any | ||
| Contribution, identifying the complete details of its source and of | ||
| any license or other restriction (including, but not limited to, | ||
| related patents, trademarks, and license agreements) of which you | ||
| are personally aware, and conspicuously marking the work as | ||
| "Submitted on behalf of a third-party: [named here]". | ||
|
|
||
| 8. You agree to notify jPOS.org of any facts or circumstances of | ||
| which you become aware that would make these representations | ||
| inaccurate in any respect. | ||
|
|
||
| Date: 2012-05-09 | ||
| Please sign: Vishnu Pillai | ||
|
|
||
| -----BEGIN PGP MESSAGE----- | ||
| Version: BCPG C# v1.6.1.0 | ||
|
|
||
| hIwDWBUDo6q5z14BA/4qbmM2S9Dlj/6KDNxnRqKB+hfX0vrr1uVvAOPuQXdn6yFr | ||
| Ob/k2n9iccEm5dCmWcvZx3l1P+Fk4u1/Bm3pAokZJBDp9iE5GQ0BDsQnYylPbhOu | ||
| RKISEwh/UBPkGzKVNMxMmGd4kFr8z+1H6Xku7dqO0sCoSp7vrNFWf6zHeRexrMkr | ||
| jcUA+ik+YvmXexgQq9xK3VeUEWD2fZWWXbbd3sXycu2QWwxPUH1cP2Onag== | ||
| =73fP | ||
| -----END PGP MESSAGE----- |
| @@ -0,0 +1,12 @@ | ||
| -----BEGIN PGP PUBLIC KEY BLOCK----- | ||
| Version: BCPG C# v1.6.1.0 | ||
|
|
||
| mI0ET6qm6QEEAJGhjkeD/wyQDG6fXHx+i3jiSLymB63CM/y9iaSlj8cjlTISuEL2 | ||
| LqfBQw3JeoIvz8h0Qby+zMidC8ueAtIr/jou275+bVgDf9wdWcHlLQGNWlAqJFJ3 | ||
| /twyLAnZs5Km0r2gSBB3e8R26ZkytNZxj+Cb/nffdTXeO50FRdhHvciLABEBAAG0 | ||
| F3Zpc2hudV9waWxsYWlAeWFob28uY29tiJwEEAECAAYFAk+qpukACgkQWBUDo6q5 | ||
| z150SgQAg7UrOFqoUtfichgLes17gCIuyh/eSSsSePRDyof3Fv/QmqHzB6G3pFKJ | ||
| scXiiaACV9YZto4RZe7VvNbz3sEmT0S+lSPbXAonOePX0/YspFOnEZGp2D6SOkmx | ||
| 1qz65UvJtW3nZA8di67gccUlEtI3iZ26FhY37+JC6R53KtYEr6k= | ||
| =xWzS | ||
| -----END PGP PUBLIC KEY BLOCK----- |