Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
09c006fdc4 | ||
|
|
360cb3e3e5 | ||
|
|
ee8a4bca08 | ||
|
|
ce95be85e3 | ||
|
|
c19ff8ded1 | ||
|
|
c1bed18cb1 | ||
|
|
bc3c2b553b | ||
|
|
51da1fe599 | ||
|
|
d7cf38ffd5 | ||
|
|
f61826f064 | ||
|
|
2783dde094 | ||
|
|
70f2c89c3e | ||
|
|
774af5d220 | ||
|
|
69dd786f99 | ||
|
|
0506c39585 | ||
|
|
27f1331096 | ||
|
|
8db7571cb6 | ||
|
|
3e3fb61e3a | ||
|
|
c76d5e9b40 | ||
|
|
a84dacb9f3 | ||
|
|
e7306681eb | ||
|
|
b92bd46a0e | ||
|
|
a3bca5144a | ||
|
|
6e6cd45302 | ||
|
|
f42e9bf664 | ||
|
|
c18e56ce0c | ||
|
|
3f13f26b9d | ||
|
|
b5fdf63120 | ||
|
|
7694b5cc9c | ||
|
|
eeb8cb7ec1 | ||
|
|
d615114b33 | ||
|
|
c5f57b9eef | ||
|
|
abfd4f3e17 | ||
|
|
21d8824045 |
+3
-3
@@ -1,7 +1,7 @@
|
|||||||
apply plugin:'java'
|
apply plugin:'java'
|
||||||
apply plugin: 'maven'
|
apply plugin: 'maven'
|
||||||
defaultTasks 'build'
|
defaultTasks 'build'
|
||||||
version='1.12.0'
|
version='1.13.0'
|
||||||
description='Java implementation of the ISO 8583 protocol, focused on making the creation, edition and reading of ISO8583 messages as simple and flexible as possible.'
|
description='Java implementation of the ISO 8583 protocol, focused on making the creation, edition and reading of ISO8583 messages as simple and flexible as possible.'
|
||||||
sourceCompatibility=7
|
sourceCompatibility=7
|
||||||
targetCompatibility=7
|
targetCompatibility=7
|
||||||
@@ -17,9 +17,9 @@ configurations {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
compile 'org.slf4j:slf4j-api:1.7.12'
|
compile 'org.slf4j:slf4j-api:1.7.21'
|
||||||
testCompile 'junit:junit:4.12'
|
testCompile 'junit:junit:4.12'
|
||||||
testRuntime 'org.slf4j:slf4j-simple:1.7.12'
|
testRuntime 'org.slf4j:slf4j-simple:1.7.21'
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.javadoc.options.use=true
|
tasks.javadoc.options.use=true
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<groupId>net.sf.j8583</groupId>
|
<groupId>net.sf.j8583</groupId>
|
||||||
<artifactId>j8583</artifactId>
|
<artifactId>j8583</artifactId>
|
||||||
<version>1.10.2</version>
|
<version>1.13.0</version>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
<name>j8583</name>
|
<name>j8583</name>
|
||||||
<description>Java implementation of the ISO 8583 protocol, focused on making the creation, edition and reading of ISO8583 messages as simple and flexible as possible.</description>
|
<description>Java implementation of the ISO 8583 protocol, focused on making the creation, edition and reading of ISO8583 messages as simple and flexible as possible.</description>
|
||||||
@@ -27,15 +27,21 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.slf4j</groupId>
|
<groupId>org.slf4j</groupId>
|
||||||
<artifactId>slf4j-api</artifactId>
|
<artifactId>slf4j-api</artifactId>
|
||||||
<version>1.7.7</version>
|
<version>1.7.23</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>junit</groupId>
|
<groupId>junit</groupId>
|
||||||
<artifactId>junit</artifactId>
|
<artifactId>junit</artifactId>
|
||||||
<version>4.11</version>
|
<version>4.12</version>
|
||||||
<type>jar</type>
|
<type>jar</type>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.slf4j</groupId>
|
||||||
|
<artifactId>slf4j-simple</artifactId>
|
||||||
|
<version>1.7.23</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
<organization>
|
<organization>
|
||||||
<name>Enrique Zamudio</name>
|
<name>Enrique Zamudio</name>
|
||||||
@@ -60,10 +66,10 @@
|
|||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-compiler-plugin</artifactId>
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
<version>2.3.2</version>
|
<version>3.5</version>
|
||||||
<configuration>
|
<configuration>
|
||||||
<source>1.6</source>
|
<source>1.7</source>
|
||||||
<target>1.6</target>
|
<target>1.7</target>
|
||||||
</configuration>
|
</configuration>
|
||||||
</plugin>
|
</plugin>
|
||||||
<plugin>
|
<plugin>
|
||||||
|
|||||||
@@ -251,6 +251,7 @@ public class IsoMessage {
|
|||||||
} else {
|
} else {
|
||||||
setValue(index, value, current.getEncoder(), current.getType(), current.getLength());
|
setValue(index, value, current.getEncoder(), current.getType(), current.getLength());
|
||||||
getField(index).setCharacterEncoding(current.getCharacterEncoding());
|
getField(index).setCharacterEncoding(current.getCharacterEncoding());
|
||||||
|
getField(index).setTimeZone(current.getTimeZone());
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,6 +41,8 @@ public enum IsoType {
|
|||||||
LLVAR(false, 0),
|
LLVAR(false, 0),
|
||||||
/** A variable length alphanumeric value with a 3-digit header length. */
|
/** A variable length alphanumeric value with a 3-digit header length. */
|
||||||
LLLVAR(false, 0),
|
LLLVAR(false, 0),
|
||||||
|
/** A date in format YYYYMMddHHmmss */
|
||||||
|
DATE14(false, 14),
|
||||||
/** A date in format MMddHHmmss */
|
/** A date in format MMddHHmmss */
|
||||||
DATE10(false, 10),
|
DATE10(false, 10),
|
||||||
/** A date in format MMdd */
|
/** A date in format MMdd */
|
||||||
@@ -62,7 +64,9 @@ public enum IsoType {
|
|||||||
/** variable length byte array with 4-digit header length. */
|
/** variable length byte array with 4-digit header length. */
|
||||||
LLLLBIN(false, 0),
|
LLLLBIN(false, 0),
|
||||||
/** Date in format yyMMddHHmmss. */
|
/** Date in format yyMMddHHmmss. */
|
||||||
DATE12(false,12);
|
DATE12(false,12),
|
||||||
|
/** Date in format yyMMdd */
|
||||||
|
DATE6(false,6);
|
||||||
|
|
||||||
private boolean needsLen;
|
private boolean needsLen;
|
||||||
private int length;
|
private int length;
|
||||||
@@ -82,7 +86,7 @@ public enum IsoType {
|
|||||||
return length;
|
return length;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Formats a Date if the receiver is DATE10, DATE4, DATE_EXP, DATE12 or TIME; throws an exception
|
/** Formats a Date if the receiver is DATE10, DATE4, DATE_EXP, DATE12, DATE14 or TIME; throws an exception
|
||||||
* otherwise. */
|
* otherwise. */
|
||||||
public String format(final Date value, final TimeZone tz) {
|
public String format(final Date value, final TimeZone tz) {
|
||||||
final SimpleDateFormat sdf;
|
final SimpleDateFormat sdf;
|
||||||
@@ -96,6 +100,10 @@ public enum IsoType {
|
|||||||
sdf = new SimpleDateFormat("HHmmss");
|
sdf = new SimpleDateFormat("HHmmss");
|
||||||
} else if (this == DATE12) {
|
} else if (this == DATE12) {
|
||||||
sdf = new SimpleDateFormat("yyMMddHHmmss");
|
sdf = new SimpleDateFormat("yyMMddHHmmss");
|
||||||
|
} else if (this == DATE14) {
|
||||||
|
sdf = new SimpleDateFormat("YYYYMMddHHmmss");
|
||||||
|
} else if (this == DATE6) {
|
||||||
|
sdf = new SimpleDateFormat("yyMMdd");
|
||||||
} else {
|
} else {
|
||||||
throw new IllegalArgumentException("Cannot format date as " + this);
|
throw new IllegalArgumentException("Cannot format date as " + this);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -334,7 +334,8 @@ public class IsoValue<T> implements Cloneable {
|
|||||||
} else if (type == IsoType.AMOUNT) {
|
} else if (type == IsoType.AMOUNT) {
|
||||||
buf = new byte[6];
|
buf = new byte[6];
|
||||||
} else if (type == IsoType.DATE10 || type == IsoType.DATE4 ||
|
} else if (type == IsoType.DATE10 || type == IsoType.DATE4 ||
|
||||||
type == IsoType.DATE_EXP || type == IsoType.TIME || type == IsoType.DATE12) {
|
type == IsoType.DATE_EXP || type == IsoType.TIME ||
|
||||||
|
type == IsoType.DATE12 || type == IsoType.DATE14) {
|
||||||
buf = new byte[length / 2];
|
buf = new byte[length / 2];
|
||||||
}
|
}
|
||||||
//Encode in BCD if it's one of these types
|
//Encode in BCD if it's one of these types
|
||||||
|
|||||||
@@ -241,7 +241,16 @@ public class MessageFactory<T extends IsoMessage> {
|
|||||||
m.setValue(11, traceGen.nextTrace(), IsoType.NUMERIC, 6);
|
m.setValue(11, traceGen.nextTrace(), IsoType.NUMERIC, 6);
|
||||||
}
|
}
|
||||||
if (setDate) {
|
if (setDate) {
|
||||||
m.setValue(7, new Date(), IsoType.DATE10, 10);
|
if (m.hasField(7)) {
|
||||||
|
//We may have a field with a timezone but no value
|
||||||
|
m.updateValue(7, new Date());
|
||||||
|
} else {
|
||||||
|
IsoValue<Date> now = new IsoValue<>(IsoType.DATE10, new Date());
|
||||||
|
if (DateTimeParseInfo.getDefaultTimeZone() != null) {
|
||||||
|
now.setTimeZone(DateTimeParseInfo.getDefaultTimeZone());
|
||||||
|
}
|
||||||
|
m.setField(7, now);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return m;
|
return m;
|
||||||
}
|
}
|
||||||
@@ -280,6 +289,9 @@ public class MessageFactory<T extends IsoMessage> {
|
|||||||
|
|
||||||
/** Sets the timezone for the specified FieldParseInfo, if it's needed for parsing dates. */
|
/** Sets the timezone for the specified FieldParseInfo, if it's needed for parsing dates. */
|
||||||
public void setTimezoneForParseGuide(int messageType, int field, TimeZone tz) {
|
public void setTimezoneForParseGuide(int messageType, int field, TimeZone tz) {
|
||||||
|
if (field == 0) {
|
||||||
|
DateTimeParseInfo.setDefaultTimeZone(tz);
|
||||||
|
}
|
||||||
Map<Integer, FieldParseInfo> guide = parseMap.get(messageType);
|
Map<Integer, FieldParseInfo> guide = parseMap.get(messageType);
|
||||||
if (guide != null) {
|
if (guide != null) {
|
||||||
FieldParseInfo fpi = guide.get(field);
|
FieldParseInfo fpi = guide.get(field);
|
||||||
@@ -441,7 +453,8 @@ public class MessageFactory<T extends IsoMessage> {
|
|||||||
boolean abandon = false;
|
boolean abandon = false;
|
||||||
for (int i = 1; i < bs.length(); i++) {
|
for (int i = 1; i < bs.length(); i++) {
|
||||||
if (bs.get(i) && !index.contains(i+1)) {
|
if (bs.get(i) && !index.contains(i+1)) {
|
||||||
log.warn("ISO8583 MessageFactory cannot parse field {}: unspecified in parsing guide", i+1);
|
log.warn("ISO8583 MessageFactory cannot parse field {}: unspecified in parsing guide for type {}",
|
||||||
|
i+1, Integer.toString(type, 16));
|
||||||
abandon = true;
|
abandon = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -465,7 +478,9 @@ public class MessageFactory<T extends IsoMessage> {
|
|||||||
m.setField(i, val);
|
m.setField(i, val);
|
||||||
if (val != null) {
|
if (val != null) {
|
||||||
if (val.getType() == IsoType.NUMERIC || val.getType() == IsoType.DATE10
|
if (val.getType() == IsoType.NUMERIC || val.getType() == IsoType.DATE10
|
||||||
|| val.getType() == IsoType.DATE4 || val.getType() == IsoType.DATE12
|
|| val.getType() == IsoType.DATE4
|
||||||
|
|| val.getType() == IsoType.DATE12
|
||||||
|
|| val.getType() == IsoType.DATE14
|
||||||
|| val.getType() == IsoType.DATE_EXP
|
|| val.getType() == IsoType.DATE_EXP
|
||||||
|| val.getType() == IsoType.AMOUNT
|
|| val.getType() == IsoType.AMOUNT
|
||||||
|| val.getType() == IsoType.TIME) {
|
|| val.getType() == IsoType.TIME) {
|
||||||
|
|||||||
@@ -32,16 +32,30 @@ import java.math.BigInteger;
|
|||||||
*/
|
*/
|
||||||
public class BigIntBcdCodec implements CustomBinaryField<BigInteger> {
|
public class BigIntBcdCodec implements CustomBinaryField<BigInteger> {
|
||||||
|
|
||||||
|
private final boolean rightPadded;
|
||||||
|
|
||||||
|
public BigIntBcdCodec() {
|
||||||
|
this(false);
|
||||||
|
}
|
||||||
|
public BigIntBcdCodec(boolean rightPadded) {
|
||||||
|
this.rightPadded = rightPadded;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public BigInteger decodeBinaryField(byte[] value, int pos, int len) {
|
public BigInteger decodeBinaryField(byte[] value, int pos, int len) {
|
||||||
return Bcd.decodeToBigInteger(value, pos, len*2);
|
return rightPadded ? Bcd.decodeRightPaddedToBigInteger(value, pos, len*2)
|
||||||
|
: Bcd.decodeToBigInteger(value, pos, len*2);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public byte[] encodeBinaryField(BigInteger value) {
|
public byte[] encodeBinaryField(BigInteger value) {
|
||||||
final String s = value.toString(10);
|
final String s = value.toString(10);
|
||||||
final byte[] buf = new byte[s.length() / 2 + s.length() % 2];
|
final byte[] buf = new byte[s.length() / 2 + s.length() % 2];
|
||||||
|
if (rightPadded) {
|
||||||
|
Bcd.encodeRightPadded(s, buf);
|
||||||
|
} else {
|
||||||
Bcd.encode(s, buf);
|
Bcd.encode(s, buf);
|
||||||
|
}
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ public class CompositeField implements CustomBinaryField<CompositeField> {
|
|||||||
if (v.getType() == IsoType.NUMERIC || v.getType() == IsoType.DATE10
|
if (v.getType() == IsoType.NUMERIC || v.getType() == IsoType.DATE10
|
||||||
|| v.getType() == IsoType.DATE4 || v.getType() == IsoType.DATE_EXP
|
|| v.getType() == IsoType.DATE4 || v.getType() == IsoType.DATE_EXP
|
||||||
|| v.getType() == IsoType.AMOUNT || v.getType() == IsoType.TIME
|
|| v.getType() == IsoType.AMOUNT || v.getType() == IsoType.TIME
|
||||||
|| v.getType() == IsoType.DATE12) {
|
|| v.getType() == IsoType.DATE12 || v.getType() == IsoType.DATE14) {
|
||||||
pos += (v.getLength() / 2) + (v.getLength() % 2);
|
pos += (v.getLength() / 2) + (v.getLength() % 2);
|
||||||
} else {
|
} else {
|
||||||
pos += v.getLength();
|
pos += v.getLength();
|
||||||
|
|||||||
@@ -30,16 +30,30 @@ import com.solab.iso8583.util.Bcd;
|
|||||||
*/
|
*/
|
||||||
public class LongBcdCodec implements CustomBinaryField<Long> {
|
public class LongBcdCodec implements CustomBinaryField<Long> {
|
||||||
|
|
||||||
|
private final boolean rightPadded;
|
||||||
|
|
||||||
|
public LongBcdCodec() {
|
||||||
|
this(false);
|
||||||
|
}
|
||||||
|
public LongBcdCodec(boolean rightPadding) {
|
||||||
|
rightPadded = rightPadding;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Long decodeBinaryField(byte[] value, int pos, int length) {
|
public Long decodeBinaryField(byte[] value, int pos, int length) {
|
||||||
return Bcd.decodeToLong(value, pos, length*2);
|
return rightPadded ? Bcd.decodeRightPaddedToLong(value, pos, length*2)
|
||||||
|
: Bcd.decodeToLong(value, pos, length*2);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public byte[] encodeBinaryField(Long value) {
|
public byte[] encodeBinaryField(Long value) {
|
||||||
final String s = Long.toString(value, 10);
|
final String s = Long.toString(value, 10);
|
||||||
final byte[] buf = new byte[s.length() / 2 + s.length() % 2];
|
final byte[] buf = new byte[s.length() / 2 + s.length() % 2];
|
||||||
|
if (rightPadded) {
|
||||||
|
Bcd.encodeRightPadded(s, buf);
|
||||||
|
} else {
|
||||||
Bcd.encode(s, buf);
|
Bcd.encode(s, buf);
|
||||||
|
}
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ import java.text.ParseException;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.TimeZone;
|
||||||
|
|
||||||
import javax.xml.parsers.DocumentBuilder;
|
import javax.xml.parsers.DocumentBuilder;
|
||||||
import javax.xml.parsers.DocumentBuilderFactory;
|
import javax.xml.parsers.DocumentBuilderFactory;
|
||||||
@@ -274,8 +275,13 @@ public class ConfigParser {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return itype.needsLength() ? new IsoValue<>(itype, cf, length, cf) :
|
IsoValue<?> rv = itype.needsLength() ? new IsoValue<>(itype, cf, length, cf) :
|
||||||
new IsoValue<>(itype, cf, cf);
|
new IsoValue<>(itype, cf, cf);
|
||||||
|
if (f.hasAttribute("tz")) {
|
||||||
|
TimeZone tz = TimeZone.getTimeZone(f.getAttribute("tz"));
|
||||||
|
rv.setTimeZone(tz);
|
||||||
|
}
|
||||||
|
return rv;
|
||||||
}
|
}
|
||||||
final String v;
|
final String v;
|
||||||
if (f.getChildNodes().getLength() == 0) {
|
if (f.getChildNodes().getLength() == 0) {
|
||||||
@@ -284,15 +290,22 @@ public class ConfigParser {
|
|||||||
v = f.getChildNodes().item(0).getNodeValue();
|
v = f.getChildNodes().item(0).getNodeValue();
|
||||||
}
|
}
|
||||||
final CustomField<Object> cf = toplevel ? mfact.getCustomField(num) : null;
|
final CustomField<Object> cf = toplevel ? mfact.getCustomField(num) : null;
|
||||||
|
IsoValue<?> rv;
|
||||||
if (cf == null) {
|
if (cf == null) {
|
||||||
return itype.needsLength() ? new IsoValue<>(itype, v, length) : new IsoValue<>(itype, v);
|
rv = itype.needsLength() ? new IsoValue<>(itype, v, length) : new IsoValue<>(itype, v);
|
||||||
}
|
} else {
|
||||||
return itype.needsLength() ? new IsoValue<>(itype, cf.decodeField(v), length, cf) :
|
rv = itype.needsLength() ? new IsoValue<>(itype, cf.decodeField(v), length, cf) :
|
||||||
new IsoValue<>(itype, cf.decodeField(v), cf);
|
new IsoValue<>(itype, cf.decodeField(v), cf);
|
||||||
}
|
}
|
||||||
|
if (f.hasAttribute("tz")) {
|
||||||
|
TimeZone tz = TimeZone.getTimeZone(f.getAttribute("tz"));
|
||||||
|
rv.setTimeZone(tz);
|
||||||
|
}
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
protected static <T extends IsoMessage> FieldParseInfo getParser(
|
protected static <T extends IsoMessage> FieldParseInfo getParser(
|
||||||
Element f, MessageFactory<T> mfact) throws IOException {
|
Element f, MessageFactory<T> mfact) {
|
||||||
IsoType itype = IsoType.valueOf(f.getAttribute("type"));
|
IsoType itype = IsoType.valueOf(f.getAttribute("type"));
|
||||||
int length = 0;
|
int length = 0;
|
||||||
if (f.getAttribute("length").length() > 0) {
|
if (f.getAttribute("length").length() > 0) {
|
||||||
@@ -310,6 +323,10 @@ public class ConfigParser {
|
|||||||
}
|
}
|
||||||
fpi.setDecoder(combo);
|
fpi.setDecoder(combo);
|
||||||
}
|
}
|
||||||
|
if (f.hasAttribute("tz") && fpi instanceof DateTimeParseInfo) {
|
||||||
|
TimeZone tz = TimeZone.getTimeZone(f.getAttribute("tz"));
|
||||||
|
((DateTimeParseInfo)fpi).setTimeZone(tz);
|
||||||
|
}
|
||||||
return fpi;
|
return fpi;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -67,11 +67,7 @@ public class Date10ParseInfo extends DateTimeParseInfo {
|
|||||||
cal.set(Calendar.SECOND, ((buf[pos + 8] - 48) * 10) + buf[pos + 9] - 48);
|
cal.set(Calendar.SECOND, ((buf[pos + 8] - 48) * 10) + buf[pos + 9] - 48);
|
||||||
}
|
}
|
||||||
cal.set(Calendar.MILLISECOND,0);
|
cal.set(Calendar.MILLISECOND,0);
|
||||||
if (tz != null) {
|
return createValue(cal, true);
|
||||||
cal.setTimeZone(tz);
|
|
||||||
}
|
|
||||||
adjustWithFutureTolerance(cal);
|
|
||||||
return new IsoValue<>(type, cal.getTime(), null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -101,11 +97,7 @@ public class Date10ParseInfo extends DateTimeParseInfo {
|
|||||||
cal.set(Calendar.MINUTE, tens[3]);
|
cal.set(Calendar.MINUTE, tens[3]);
|
||||||
cal.set(Calendar.SECOND, tens[4]);
|
cal.set(Calendar.SECOND, tens[4]);
|
||||||
cal.set(Calendar.MILLISECOND,0);
|
cal.set(Calendar.MILLISECOND,0);
|
||||||
if (tz != null) {
|
return createValue(cal, true);
|
||||||
cal.setTimeZone(tz);
|
|
||||||
}
|
|
||||||
adjustWithFutureTolerance(cal);
|
|
||||||
return new IsoValue<>(type, cal.getTime(), null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,11 +59,7 @@ public class Date12ParseInfo extends DateTimeParseInfo {
|
|||||||
cal.set(Calendar.YEAR, 2000+year);
|
cal.set(Calendar.YEAR, 2000+year);
|
||||||
}
|
}
|
||||||
cal.set(Calendar.MILLISECOND,0);
|
cal.set(Calendar.MILLISECOND,0);
|
||||||
if (tz != null) {
|
return createValue(cal, true);
|
||||||
cal.setTimeZone(tz);
|
|
||||||
}
|
|
||||||
adjustWithFutureTolerance(cal);
|
|
||||||
return new IsoValue<>(type, cal.getTime(), null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -98,11 +94,7 @@ public class Date12ParseInfo extends DateTimeParseInfo {
|
|||||||
cal.set(Calendar.MINUTE, tens[4]);
|
cal.set(Calendar.MINUTE, tens[4]);
|
||||||
cal.set(Calendar.SECOND, tens[5]);
|
cal.set(Calendar.SECOND, tens[5]);
|
||||||
cal.set(Calendar.MILLISECOND,0);
|
cal.set(Calendar.MILLISECOND,0);
|
||||||
if (tz != null) {
|
return createValue(cal, true);
|
||||||
cal.setTimeZone(tz);
|
|
||||||
}
|
|
||||||
adjustWithFutureTolerance(cal);
|
|
||||||
return new IsoValue<>(type, cal.getTime(), null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,90 @@
|
|||||||
|
package com.solab.iso8583.parse;
|
||||||
|
|
||||||
|
import com.solab.iso8583.CustomField;
|
||||||
|
import com.solab.iso8583.IsoType;
|
||||||
|
import com.solab.iso8583.IsoValue;
|
||||||
|
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
|
import java.text.ParseException;
|
||||||
|
import java.util.Calendar;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Blabla.
|
||||||
|
*
|
||||||
|
* @author Enrique Zamudio
|
||||||
|
* Date: 06/01/16 10:52 AM
|
||||||
|
*/
|
||||||
|
public class Date14ParseInfo extends DateTimeParseInfo {
|
||||||
|
|
||||||
|
public Date14ParseInfo() {
|
||||||
|
super(IsoType.DATE14, 14);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> IsoValue<Date> parse(final int field, final byte[] buf,
|
||||||
|
final int pos, final CustomField<T> custom)
|
||||||
|
throws ParseException, UnsupportedEncodingException {
|
||||||
|
if (pos < 0) {
|
||||||
|
throw new ParseException(String.format("Invalid DATE14 field %d position %d",
|
||||||
|
field, pos), pos);
|
||||||
|
}
|
||||||
|
if (pos+14 > buf.length) {
|
||||||
|
throw new ParseException(String.format("Insufficient data for DATE14 field %d, pos %d",
|
||||||
|
field, pos), pos);
|
||||||
|
}
|
||||||
|
//A SimpleDateFormat in the case of dates won't help because of the missing data
|
||||||
|
//we have to use the current date for reference and change what comes in the buffer
|
||||||
|
Calendar cal = Calendar.getInstance();
|
||||||
|
//Set the month in the date
|
||||||
|
if (forceStringDecoding) {
|
||||||
|
cal.set(Calendar.YEAR, Integer.parseInt(new String(buf, pos, 4, getCharacterEncoding()), 10));
|
||||||
|
cal.set(Calendar.MONTH, Integer.parseInt(new String(buf, pos, 2, getCharacterEncoding()), 10)-1);
|
||||||
|
cal.set(Calendar.DATE, Integer.parseInt(new String(buf, pos+2, 2, getCharacterEncoding()), 10));
|
||||||
|
cal.set(Calendar.HOUR_OF_DAY, Integer.parseInt(new String(buf, pos+4, 2, getCharacterEncoding()), 10));
|
||||||
|
cal.set(Calendar.MINUTE, Integer.parseInt(new String(buf, pos+6, 2, getCharacterEncoding()), 10));
|
||||||
|
cal.set(Calendar.SECOND, Integer.parseInt(new String(buf, pos+8, 2, getCharacterEncoding()), 10));
|
||||||
|
} else {
|
||||||
|
cal.set(Calendar.YEAR, ((buf[pos] - 48) * 1000) + ((buf[pos + 1] - 48) * 100) + ((buf[pos + 2] - 48) * 10) + buf[pos + 3] - 48);
|
||||||
|
cal.set(Calendar.MONTH, ((buf[pos+4] - 48) * 10) + buf[pos + 5] - 49);
|
||||||
|
cal.set(Calendar.DATE, ((buf[pos + 6] - 48) * 10) + buf[pos + 7] - 48);
|
||||||
|
cal.set(Calendar.HOUR_OF_DAY, ((buf[pos + 8] - 48) * 10) + buf[pos + 9] - 48);
|
||||||
|
cal.set(Calendar.MINUTE, ((buf[pos + 10] - 48) * 10) + buf[pos + 11] - 48);
|
||||||
|
cal.set(Calendar.SECOND, ((buf[pos + 12] - 48) * 10) + buf[pos + 13] - 48);
|
||||||
|
}
|
||||||
|
cal.set(Calendar.MILLISECOND,0);
|
||||||
|
return createValue(cal, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> IsoValue<Date> parseBinary(final int field, final byte[] buf,
|
||||||
|
final int pos, final CustomField<T> custom)
|
||||||
|
throws ParseException {
|
||||||
|
if (pos < 0) {
|
||||||
|
throw new ParseException(String.format("Invalid DATE14 field %d position %d",
|
||||||
|
field, pos), pos);
|
||||||
|
}
|
||||||
|
if (pos+7 > buf.length) {
|
||||||
|
throw new ParseException(String.format("Insufficient data for DATE14 field %d, pos %d",
|
||||||
|
field, pos), pos);
|
||||||
|
}
|
||||||
|
int[] tens = new int[7];
|
||||||
|
int start = 0;
|
||||||
|
for (int i = pos; i < pos + tens.length; i++) {
|
||||||
|
tens[start++] = (((buf[i] & 0xf0) >> 4) * 10) + (buf[i] & 0x0f);
|
||||||
|
}
|
||||||
|
Calendar cal = Calendar.getInstance();
|
||||||
|
//A SimpleDateFormat in the case of dates won't help because of the missing data
|
||||||
|
//we have to use the current date for reference and change what comes in the buffer
|
||||||
|
//Set the month in the date
|
||||||
|
cal.set(Calendar.YEAR, (tens[0] * 100) + tens[1]);
|
||||||
|
cal.set(Calendar.MONTH, tens[2] - 1);
|
||||||
|
cal.set(Calendar.DATE, tens[3]);
|
||||||
|
cal.set(Calendar.HOUR_OF_DAY, tens[4]);
|
||||||
|
cal.set(Calendar.MINUTE, tens[5]);
|
||||||
|
cal.set(Calendar.SECOND, tens[6]);
|
||||||
|
cal.set(Calendar.MILLISECOND,0);
|
||||||
|
return createValue(cal, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -62,11 +62,7 @@ public class Date4ParseInfo extends DateTimeParseInfo {
|
|||||||
cal.set(Calendar.MONTH, ((buf[pos] - 48) * 10) + buf[pos + 1] - 49);
|
cal.set(Calendar.MONTH, ((buf[pos] - 48) * 10) + buf[pos + 1] - 49);
|
||||||
cal.set(Calendar.DATE, ((buf[pos + 2] - 48) * 10) + buf[pos + 3] - 48);
|
cal.set(Calendar.DATE, ((buf[pos + 2] - 48) * 10) + buf[pos + 3] - 48);
|
||||||
}
|
}
|
||||||
if (tz != null) {
|
return createValue(cal, true);
|
||||||
cal.setTimeZone(tz);
|
|
||||||
}
|
|
||||||
Date10ParseInfo.adjustWithFutureTolerance(cal);
|
|
||||||
return new IsoValue<>(type, cal.getTime(), null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -90,11 +86,7 @@ public class Date4ParseInfo extends DateTimeParseInfo {
|
|||||||
cal.set(Calendar.MONTH, tens[0] - 1);
|
cal.set(Calendar.MONTH, tens[0] - 1);
|
||||||
cal.set(Calendar.DATE, tens[1]);
|
cal.set(Calendar.DATE, tens[1]);
|
||||||
cal.set(Calendar.MILLISECOND,0);
|
cal.set(Calendar.MILLISECOND,0);
|
||||||
if (tz != null) {
|
return createValue(cal, true);
|
||||||
cal.setTimeZone(tz);
|
|
||||||
}
|
|
||||||
DateTimeParseInfo.adjustWithFutureTolerance(cal);
|
|
||||||
return new IsoValue<>(type, cal.getTime(), null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,93 @@
|
|||||||
|
package com.solab.iso8583.parse;
|
||||||
|
|
||||||
|
import com.solab.iso8583.CustomField;
|
||||||
|
import com.solab.iso8583.IsoType;
|
||||||
|
import com.solab.iso8583.IsoValue;
|
||||||
|
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
|
import java.text.ParseException;
|
||||||
|
import java.util.Calendar;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parser for fields of type DATE6.
|
||||||
|
*
|
||||||
|
* @author Enrique Zamudio
|
||||||
|
* Date: 4/17/18 12:41 PM
|
||||||
|
*/
|
||||||
|
public class Date6ParseInfo extends DateTimeParseInfo {
|
||||||
|
|
||||||
|
public Date6ParseInfo() {
|
||||||
|
super(IsoType.DATE6, 6);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> IsoValue<Date> parse(int field, byte[] buf, int pos, CustomField<T> custom) throws ParseException, UnsupportedEncodingException {
|
||||||
|
if (pos < 0) {
|
||||||
|
throw new ParseException(String.format("Invalid DATE6 field %d position %d",
|
||||||
|
field, pos), pos);
|
||||||
|
}
|
||||||
|
if (pos+6 > buf.length) {
|
||||||
|
throw new ParseException(String.format(
|
||||||
|
"Insufficient data for DATE6 field %d, pos %d", field, pos), pos);
|
||||||
|
}
|
||||||
|
Calendar cal = Calendar.getInstance();
|
||||||
|
cal.set(Calendar.HOUR_OF_DAY, 0);
|
||||||
|
cal.set(Calendar.MINUTE, 0);
|
||||||
|
cal.set(Calendar.SECOND, 0);
|
||||||
|
cal.set(Calendar.MILLISECOND, 0);
|
||||||
|
//Set the month in the date
|
||||||
|
int year;
|
||||||
|
if (forceStringDecoding) {
|
||||||
|
year = Integer.parseInt(new String(buf, pos, 2, getCharacterEncoding()), 10);
|
||||||
|
cal.set(Calendar.MONTH, Integer.parseInt(new String(buf, pos+2, 2, getCharacterEncoding()), 10)-1);
|
||||||
|
cal.set(Calendar.DATE, Integer.parseInt(new String(buf, pos+4, 2, getCharacterEncoding()), 10));
|
||||||
|
} else {
|
||||||
|
year = ((buf[pos] - 48) * 10) + buf[pos + 1] - 48;
|
||||||
|
cal.set(Calendar.MONTH, ((buf[pos + 2] - 48) * 10) + buf[pos + 3] - 49);
|
||||||
|
cal.set(Calendar.DATE, ((buf[pos + 4] - 48) * 10) + buf[pos + 5] - 48);
|
||||||
|
}
|
||||||
|
if (year > 50) {
|
||||||
|
cal.set(Calendar.YEAR, 1900+year);
|
||||||
|
} else {
|
||||||
|
cal.set(Calendar.YEAR, 2000+year);
|
||||||
|
}
|
||||||
|
return createValue(cal, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> IsoValue<Date> parseBinary(int field, byte[] buf, int pos, CustomField<T> custom) throws ParseException, UnsupportedEncodingException {
|
||||||
|
if (pos < 0) {
|
||||||
|
throw new ParseException(String.format("Invalid DATE6 field %d position %d",
|
||||||
|
field, pos), pos);
|
||||||
|
}
|
||||||
|
if (pos+3 > buf.length) {
|
||||||
|
throw new ParseException(String.format("Insufficient data for DATE6 field %d, pos %d",
|
||||||
|
field, pos), pos);
|
||||||
|
}
|
||||||
|
int[] tens = new int[3];
|
||||||
|
int start = 0;
|
||||||
|
for (int i = pos; i < pos + tens.length; i++) {
|
||||||
|
tens[start++] = (((buf[i] & 0xf0) >> 4) * 10) + (buf[i] & 0x0f);
|
||||||
|
}
|
||||||
|
Calendar cal = Calendar.getInstance();
|
||||||
|
//A SimpleDateFormat in the case of dates won't help because of the missing data
|
||||||
|
//we have to use the current date for reference and change what comes in the buffer
|
||||||
|
//Set the month in the date
|
||||||
|
if (tens[0] > 50) {
|
||||||
|
cal.set(Calendar.YEAR, 1900+tens[0]);
|
||||||
|
} else {
|
||||||
|
cal.set(Calendar.YEAR, 2000+tens[0]);
|
||||||
|
}
|
||||||
|
cal.set(Calendar.MONTH, tens[1] - 1);
|
||||||
|
cal.set(Calendar.DATE, tens[2]);
|
||||||
|
cal.set(Calendar.HOUR_OF_DAY, 0);
|
||||||
|
cal.set(Calendar.MINUTE, 0);
|
||||||
|
cal.set(Calendar.SECOND, 0);
|
||||||
|
cal.set(Calendar.MILLISECOND,0);
|
||||||
|
if (tz != null) {
|
||||||
|
cal.setTimeZone(tz);
|
||||||
|
}
|
||||||
|
return createValue(cal, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -64,10 +64,7 @@ public class DateExpParseInfo extends DateTimeParseInfo {
|
|||||||
+ ((buf[pos] - 48) * 10) + buf[pos + 1] - 48);
|
+ ((buf[pos] - 48) * 10) + buf[pos + 1] - 48);
|
||||||
cal.set(Calendar.MONTH, ((buf[pos + 2] - 48) * 10) + buf[pos + 3] - 49);
|
cal.set(Calendar.MONTH, ((buf[pos + 2] - 48) * 10) + buf[pos + 3] - 49);
|
||||||
}
|
}
|
||||||
if (tz != null) {
|
return createValue(cal, false);
|
||||||
cal.setTimeZone(tz);
|
|
||||||
}
|
|
||||||
return new IsoValue<>(type, cal.getTime(), null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -96,9 +93,6 @@ public class DateExpParseInfo extends DateTimeParseInfo {
|
|||||||
cal.set(Calendar.YEAR, cal.get(Calendar.YEAR)
|
cal.set(Calendar.YEAR, cal.get(Calendar.YEAR)
|
||||||
- (cal.get(Calendar.YEAR) % 100) + tens[0]);
|
- (cal.get(Calendar.YEAR) % 100) + tens[0]);
|
||||||
cal.set(Calendar.MONTH, tens[1] - 1);
|
cal.set(Calendar.MONTH, tens[1] - 1);
|
||||||
if (tz != null) {
|
return createValue(cal, false);
|
||||||
cal.setTimeZone(tz);
|
|
||||||
}
|
|
||||||
return new IsoValue<>(type, cal.getTime(), null);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
package com.solab.iso8583.parse;
|
package com.solab.iso8583.parse;
|
||||||
|
|
||||||
import com.solab.iso8583.IsoType;
|
import com.solab.iso8583.IsoType;
|
||||||
|
import com.solab.iso8583.IsoValue;
|
||||||
|
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
|
import java.util.Date;
|
||||||
import java.util.TimeZone;
|
import java.util.TimeZone;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -15,11 +17,19 @@ public abstract class DateTimeParseInfo extends FieldParseInfo {
|
|||||||
|
|
||||||
protected static final long FUTURE_TOLERANCE;
|
protected static final long FUTURE_TOLERANCE;
|
||||||
protected TimeZone tz;
|
protected TimeZone tz;
|
||||||
|
private static TimeZone defaultTimezone;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
FUTURE_TOLERANCE = Long.parseLong(System.getProperty("j8583.future.tolerance", "900000"));
|
FUTURE_TOLERANCE = Long.parseLong(System.getProperty("j8583.future.tolerance", "900000"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void setDefaultTimeZone(TimeZone tz) {
|
||||||
|
defaultTimezone = tz;
|
||||||
|
}
|
||||||
|
public static TimeZone getDefaultTimeZone() {
|
||||||
|
return defaultTimezone;
|
||||||
|
}
|
||||||
|
|
||||||
protected DateTimeParseInfo(IsoType type, int length) {
|
protected DateTimeParseInfo(IsoType type, int length) {
|
||||||
super(type, length);
|
super(type, length);
|
||||||
}
|
}
|
||||||
@@ -40,4 +50,21 @@ public abstract class DateTimeParseInfo extends FieldParseInfo {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected IsoValue<Date> createValue(Calendar cal, boolean adjusting) {
|
||||||
|
if (tz != null) {
|
||||||
|
cal.setTimeZone(tz);
|
||||||
|
} else if (getDefaultTimeZone() != null) {
|
||||||
|
cal.setTimeZone(getDefaultTimeZone());
|
||||||
|
}
|
||||||
|
if (adjusting) {
|
||||||
|
adjustWithFutureTolerance(cal);
|
||||||
|
}
|
||||||
|
IsoValue<Date> v = new IsoValue<>(type, cal.getTime(), null);
|
||||||
|
if (tz != null) {
|
||||||
|
v.setTimeZone(tz);
|
||||||
|
} else if (getDefaultTimeZone() != null) {
|
||||||
|
v.setTimeZone(getDefaultTimeZone());
|
||||||
|
}
|
||||||
|
return v;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -113,6 +113,8 @@ public abstract class FieldParseInfo {
|
|||||||
fpi = new Date10ParseInfo();
|
fpi = new Date10ParseInfo();
|
||||||
} else if (t == IsoType.DATE12) {
|
} else if (t == IsoType.DATE12) {
|
||||||
fpi = new Date12ParseInfo();
|
fpi = new Date12ParseInfo();
|
||||||
|
} else if (t == IsoType.DATE14) {
|
||||||
|
fpi = new Date14ParseInfo();
|
||||||
} else if (t == IsoType.DATE4) {
|
} else if (t == IsoType.DATE4) {
|
||||||
fpi = new Date4ParseInfo();
|
fpi = new Date4ParseInfo();
|
||||||
} else if (t == IsoType.DATE_EXP) {
|
} else if (t == IsoType.DATE_EXP) {
|
||||||
|
|||||||
@@ -55,7 +55,8 @@ public class LllbinParseInfo extends FieldParseInfo {
|
|||||||
l, field, pos), pos);
|
l, field, pos), pos);
|
||||||
} else if (l+pos+3 > buf.length) {
|
} else if (l+pos+3 > buf.length) {
|
||||||
throw new ParseException(String.format(
|
throw new ParseException(String.format(
|
||||||
"Insufficient data for LLLBIN field %d, pos %d", field, pos), pos);
|
"Insufficient data for LLLBIN field %d, pos %d len %d",
|
||||||
|
field, pos, l), pos);
|
||||||
}
|
}
|
||||||
byte[] binval = l == 0 ? new byte[0] : HexCodec.hexDecode(new String(buf, pos + 3, l));
|
byte[] binval = l == 0 ? new byte[0] : HexCodec.hexDecode(new String(buf, pos + 3, l));
|
||||||
if (custom == null) {
|
if (custom == null) {
|
||||||
@@ -68,7 +69,8 @@ public class LllbinParseInfo extends FieldParseInfo {
|
|||||||
new IsoValue<>(type, dec, 0, custom);
|
new IsoValue<>(type, dec, 0, custom);
|
||||||
} catch (IndexOutOfBoundsException ex) {
|
} catch (IndexOutOfBoundsException ex) {
|
||||||
throw new ParseException(String.format(
|
throw new ParseException(String.format(
|
||||||
"Insufficient data for LLLBIN field %d, pos %d", field, pos), pos);
|
"Insufficient data for LLLBIN field %d, pos %d len %d",
|
||||||
|
field, pos, l), pos);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
@@ -78,7 +80,8 @@ public class LllbinParseInfo extends FieldParseInfo {
|
|||||||
new IsoValue<>(type, dec, l, custom);
|
new IsoValue<>(type, dec, l, custom);
|
||||||
} catch (IndexOutOfBoundsException ex) {
|
} catch (IndexOutOfBoundsException ex) {
|
||||||
throw new ParseException(String.format(
|
throw new ParseException(String.format(
|
||||||
"Insufficient data for LLLBIN field %d, pos %d", field, pos), pos);
|
"Insufficient data for LLLBIN field %d, pos %d len %d",
|
||||||
|
field, pos, l), pos);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,18 +48,18 @@ public class LllvarParseInfo extends FieldParseInfo {
|
|||||||
}
|
}
|
||||||
final int len = decodeLength(buf, pos, 3);
|
final int len = decodeLength(buf, pos, 3);
|
||||||
if (len < 0) {
|
if (len < 0) {
|
||||||
throw new ParseException(String.format("Invalid LLLVAR length %d field %d pos %d",
|
throw new ParseException(String.format("Invalid LLLVAR length %d(%s) field %d pos %d",
|
||||||
len, field, pos), pos);
|
len, new String(buf, pos, 3), field, pos), pos);
|
||||||
} else if (len+pos+3 > buf.length) {
|
} else if (len+pos+3 > buf.length) {
|
||||||
throw new ParseException(String.format("Insufficient data for LLLVAR field %d, pos %d",
|
throw new ParseException(String.format("Insufficient data for LLLVAR field %d, pos %d len %d",
|
||||||
field, pos), pos);
|
field, pos, len), pos);
|
||||||
}
|
}
|
||||||
String _v;
|
String _v;
|
||||||
try {
|
try {
|
||||||
_v = len == 0 ? "" : new String(buf, pos + 3, len, getCharacterEncoding());
|
_v = len == 0 ? "" : new String(buf, pos + 3, len, getCharacterEncoding());
|
||||||
} catch (IndexOutOfBoundsException ex) {
|
} catch (IndexOutOfBoundsException ex) {
|
||||||
throw new ParseException(String.format(
|
throw new ParseException(String.format(
|
||||||
"Insufficient data for LLLVAR header, field %d pos %d", field, pos), pos);
|
"Insufficient data for LLLVAR header, field %d pos %d len %d", field, pos, len), pos);
|
||||||
}
|
}
|
||||||
//This is new: if the String's length is different from the specified length in the
|
//This is new: if the String's length is different from the specified length in the
|
||||||
//buffer, there are probably some extended characters. So we create a String from
|
//buffer, there are probably some extended characters. So we create a String from
|
||||||
|
|||||||
@@ -52,14 +52,16 @@ public class LlvarParseInfo extends FieldParseInfo {
|
|||||||
"Invalid LLVAR length %d, field %d pos %d", len, field, pos), pos);
|
"Invalid LLVAR length %d, field %d pos %d", len, field, pos), pos);
|
||||||
} else if (len+pos+2 > buf.length) {
|
} else if (len+pos+2 > buf.length) {
|
||||||
throw new ParseException(String.format(
|
throw new ParseException(String.format(
|
||||||
"Insufficient data for LLVAR field %d, pos %d", field, pos), pos);
|
"Insufficient data for LLVAR field %d, pos %d len %d",
|
||||||
|
field, pos, len), pos);
|
||||||
}
|
}
|
||||||
String _v;
|
String _v;
|
||||||
try {
|
try {
|
||||||
_v = len == 0 ? "" : new String(buf, pos + 2, len, getCharacterEncoding());
|
_v = len == 0 ? "" : new String(buf, pos + 2, len, getCharacterEncoding());
|
||||||
} catch (IndexOutOfBoundsException ex) {
|
} catch (IndexOutOfBoundsException ex) {
|
||||||
throw new ParseException(String.format(
|
throw new ParseException(String.format(
|
||||||
"Insufficient data for LLVAR header, field %d pos %d", field, pos), pos);
|
"Insufficient data for LLVAR header, field %d pos %d len %d",
|
||||||
|
field, pos, len), pos);
|
||||||
}
|
}
|
||||||
//This is new: if the String's length is different from the specified
|
//This is new: if the String's length is different from the specified
|
||||||
// length in the buffer, there are probably some extended characters.
|
// length in the buffer, there are probably some extended characters.
|
||||||
|
|||||||
@@ -59,10 +59,7 @@ public class TimeParseInfo extends DateTimeParseInfo {
|
|||||||
cal.set(Calendar.MINUTE, ((buf[pos + 2] - 48) * 10) + buf[pos + 3] - 48);
|
cal.set(Calendar.MINUTE, ((buf[pos + 2] - 48) * 10) + buf[pos + 3] - 48);
|
||||||
cal.set(Calendar.SECOND, ((buf[pos + 4] - 48) * 10) + buf[pos + 5] - 48);
|
cal.set(Calendar.SECOND, ((buf[pos + 4] - 48) * 10) + buf[pos + 5] - 48);
|
||||||
}
|
}
|
||||||
if (tz != null) {
|
return createValue(cal, false);
|
||||||
cal.setTimeZone(tz);
|
|
||||||
}
|
|
||||||
return new IsoValue<Date>(type, cal.getTime(), null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -51,6 +51,28 @@ public final class Bcd {
|
|||||||
return l;
|
return l;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static long decodeRightPaddedToLong(byte[] buf, int pos, int length)
|
||||||
|
throws IndexOutOfBoundsException {
|
||||||
|
if (length > 18) {
|
||||||
|
throw new IndexOutOfBoundsException("Buffer too big to decode as long");
|
||||||
|
}
|
||||||
|
long l = 0;
|
||||||
|
long power = 1L;
|
||||||
|
int end = pos + (length / 2) + (length % 2) - 1;
|
||||||
|
if ((buf[end] & 0xf) == 0xf) {
|
||||||
|
l += (buf[end] & 0xf0) >> 4;
|
||||||
|
power *= 10L;
|
||||||
|
end--;
|
||||||
|
}
|
||||||
|
for (int i = end; i >= pos; i--) {
|
||||||
|
l += (buf[i] & 0x0f) * power;
|
||||||
|
power *= 10L;
|
||||||
|
l += ((buf[i] & 0xf0) >> 4) * power;
|
||||||
|
power *= 10L;
|
||||||
|
}
|
||||||
|
return l;
|
||||||
|
}
|
||||||
|
|
||||||
/** Encode the value as BCD and put it in the buffer. The buffer must be big enough
|
/** Encode the value as BCD and put it in the buffer. The buffer must be big enough
|
||||||
* to store the digits in the original value (half the length of the string). */
|
* to store the digits in the original value (half the length of the string). */
|
||||||
public static void encode(String value, byte[] buf) {
|
public static void encode(String value, byte[] buf) {
|
||||||
@@ -71,6 +93,30 @@ public final class Bcd {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Encode the value as BCD and put it in the buffer. The buffer must be big enough
|
||||||
|
* to store the digits in the original value (half the length of the string).
|
||||||
|
* If the value contains an odd number of digits, the last one is stored in
|
||||||
|
* its own byte at the end, padded with an F nibble. */
|
||||||
|
public static void encodeRightPadded(String value, byte[] buf) {
|
||||||
|
int bufpos = 0;
|
||||||
|
int charpos = 0;
|
||||||
|
int limit = value.length();
|
||||||
|
if (limit % 2 == 1) {
|
||||||
|
limit--;
|
||||||
|
}
|
||||||
|
//encode the rest of the string
|
||||||
|
while (charpos < limit) {
|
||||||
|
buf[bufpos] = (byte)(((value.charAt(charpos) - 48) << 4)
|
||||||
|
| (value.charAt(charpos + 1) - 48));
|
||||||
|
charpos += 2;
|
||||||
|
bufpos++;
|
||||||
|
}
|
||||||
|
if (value.length() % 2 == 1) {
|
||||||
|
buf[bufpos] = (byte)(((value.charAt(limit) - 48) << 4)
|
||||||
|
| 0xf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** Decodes a BCD-encoded number as a BigInteger.
|
/** Decodes a BCD-encoded number as a BigInteger.
|
||||||
* @param buf The byte buffer containing the BCD data.
|
* @param buf The byte buffer containing the BCD data.
|
||||||
* @param pos The starting position in the buffer.
|
* @param pos The starting position in the buffer.
|
||||||
@@ -91,4 +137,22 @@ public final class Bcd {
|
|||||||
return new BigInteger(new String(digits));
|
return new BigInteger(new String(digits));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Decodes a right-padded BCD-encoded number as a BigInteger.
|
||||||
|
* @param buf The byte buffer containing the BCD data.
|
||||||
|
* @param pos The starting position in the buffer.
|
||||||
|
* @param length The number of DIGITS (not bytes) to read. */
|
||||||
|
public static BigInteger decodeRightPaddedToBigInteger(byte[] buf, int pos, int length)
|
||||||
|
throws IndexOutOfBoundsException {
|
||||||
|
char[] digits = new char[length];
|
||||||
|
int start = 0;
|
||||||
|
int i = pos;
|
||||||
|
int limit = pos + (length / 2) + (length % 2);
|
||||||
|
for (;i < limit; i++) {
|
||||||
|
digits[start++] = (char)(((buf[i] & 0xf0) >> 4) + 48);
|
||||||
|
int r = buf[i] & 0xf;
|
||||||
|
digits[start++] = r == 15 ? ' ' : (char)(r + 48);
|
||||||
|
}
|
||||||
|
return new BigInteger(new String(digits, 0, start).trim());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ public class SimpleParser {
|
|||||||
for (int i = 2; i <= 128; i++) {
|
for (int i = 2; i <= 128; i++) {
|
||||||
IsoValue<?> f = m.getField(i);
|
IsoValue<?> f = m.getField(i);
|
||||||
if (f != null) {
|
if (f != null) {
|
||||||
System.out.printf("%5d %-6s [", i, f.getType());
|
System.out.printf("%5d %-7s (%4d) [", i, f.getType(), f.getLength());
|
||||||
System.out.print(f.toString());
|
System.out.print(f.toString());
|
||||||
System.out.println(']');
|
System.out.println(']');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,4 +16,5 @@
|
|||||||
<!ELEMENT field ( #PCDATA|field )* >
|
<!ELEMENT field ( #PCDATA|field )* >
|
||||||
<!ATTLIST field num NMTOKEN #REQUIRED >
|
<!ATTLIST field num NMTOKEN #REQUIRED >
|
||||||
<!ATTLIST field length NMTOKEN #IMPLIED >
|
<!ATTLIST field length NMTOKEN #IMPLIED >
|
||||||
<!ATTLIST field type ( ALPHA | NUMERIC | AMOUNT | DATE10 | DATE4 | DATE_EXP | TIME | LLVAR | LLLVAR | BINARY | LLBIN | LLLBIN | LLLLVAR | LLLLBIN | exclude) #REQUIRED >
|
<!ATTLIST field tz NMTOKEN #IMPLIED >
|
||||||
|
<!ATTLIST field type ( ALPHA | NUMERIC | AMOUNT | DATE4 | DATE10 | DATE12 | DATE14 | DATE_EXP | TIME | LLVAR | LLLVAR | BINARY | LLBIN | LLLBIN | LLLLVAR | LLLLBIN | exclude) #REQUIRED >
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ public class TestFormats {
|
|||||||
Assert.assertEquals("7301", IsoType.DATE_EXP.format(date, null));
|
Assert.assertEquals("7301", IsoType.DATE_EXP.format(date, null));
|
||||||
Assert.assertEquals("213456", IsoType.TIME.format(date, null));
|
Assert.assertEquals("213456", IsoType.TIME.format(date, null));
|
||||||
Assert.assertEquals("730125213456", IsoType.DATE12.format(date, null));
|
Assert.assertEquals("730125213456", IsoType.DATE12.format(date, null));
|
||||||
|
Assert.assertEquals("19730125213456", IsoType.DATE14.format(date, null));
|
||||||
//Now with GMT
|
//Now with GMT
|
||||||
TimeZone gmt = TimeZone.getTimeZone("GMT");
|
TimeZone gmt = TimeZone.getTimeZone("GMT");
|
||||||
Assert.assertEquals("0126033456", IsoType.DATE10.format(date, gmt));
|
Assert.assertEquals("0126033456", IsoType.DATE10.format(date, gmt));
|
||||||
@@ -29,6 +30,7 @@ public class TestFormats {
|
|||||||
Assert.assertEquals("7301", IsoType.DATE_EXP.format(date, gmt));
|
Assert.assertEquals("7301", IsoType.DATE_EXP.format(date, gmt));
|
||||||
Assert.assertEquals("033456", IsoType.TIME.format(date, gmt));
|
Assert.assertEquals("033456", IsoType.TIME.format(date, gmt));
|
||||||
Assert.assertEquals("730126033456", IsoType.DATE12.format(date, gmt));
|
Assert.assertEquals("730126033456", IsoType.DATE12.format(date, gmt));
|
||||||
|
Assert.assertEquals("19730126033456", IsoType.DATE14.format(date, gmt));
|
||||||
//And now with GMT+1
|
//And now with GMT+1
|
||||||
gmt = TimeZone.getTimeZone("GMT+0100");
|
gmt = TimeZone.getTimeZone("GMT+0100");
|
||||||
Assert.assertEquals("0126043456", IsoType.DATE10.format(date, gmt));
|
Assert.assertEquals("0126043456", IsoType.DATE10.format(date, gmt));
|
||||||
@@ -36,6 +38,7 @@ public class TestFormats {
|
|||||||
Assert.assertEquals("7301", IsoType.DATE_EXP.format(date, gmt));
|
Assert.assertEquals("7301", IsoType.DATE_EXP.format(date, gmt));
|
||||||
Assert.assertEquals("043456", IsoType.TIME.format(date, gmt));
|
Assert.assertEquals("043456", IsoType.TIME.format(date, gmt));
|
||||||
Assert.assertEquals("730126043456", IsoType.DATE12.format(date, gmt));
|
Assert.assertEquals("730126043456", IsoType.DATE12.format(date, gmt));
|
||||||
|
Assert.assertEquals("19730126043456", IsoType.DATE14.format(date, gmt));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
@@ -3,17 +3,32 @@ package com.solab.iso8583;
|
|||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.junit.runners.Parameterized;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extended test for LLLLVar field
|
* Extended test for LLLLVar field
|
||||||
*
|
*
|
||||||
* @author Peter Margetiak
|
* @author Peter Margetiak
|
||||||
*/
|
*/
|
||||||
|
@RunWith(Parameterized.class)
|
||||||
public class TestLlllPatch {
|
public class TestLlllPatch {
|
||||||
|
|
||||||
private MessageFactory<IsoMessage> mfact = new MessageFactory<>();
|
private MessageFactory<IsoMessage> mfact = new MessageFactory<>();
|
||||||
|
private int fieldLength;
|
||||||
|
|
||||||
|
@Parameterized.Parameters
|
||||||
|
public static List<Integer> lengths() {
|
||||||
|
return Arrays.asList(5, 50, 500, 5000);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TestLlllPatch(int l) {
|
||||||
|
fieldLength = l;
|
||||||
|
}
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setup() throws IOException {
|
public void setup() throws IOException {
|
||||||
@@ -23,18 +38,23 @@ public class TestLlllPatch {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testParsingLength() throws Exception {
|
public void testParsingLength() throws Exception {
|
||||||
final int LENGTH = 1234;
|
|
||||||
|
|
||||||
// prepare
|
// prepare
|
||||||
String LLLLVar = makeLLLLVar(LENGTH);
|
String llllvar = makeLLLLVar(fieldLength);
|
||||||
StringBuilder LLLLVarBuilder = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
LLLLVarBuilder.append("01004000000000000000")
|
sb.append("01004000000000000000")
|
||||||
.append(String.format("%04d", LENGTH)).append(LLLLVar);
|
.append(String.format("%04d", fieldLength)).append(llllvar);
|
||||||
|
|
||||||
// parse
|
// parse
|
||||||
IsoMessage m = mfact.parseMessage(LLLLVarBuilder.toString().getBytes(), 0);
|
IsoMessage m = mfact.parseMessage(sb.toString().getBytes(), 0);
|
||||||
Assert.assertNotNull(m);
|
Assert.assertNotNull(m);
|
||||||
Assert.assertEquals(LLLLVar, m.getObjectValue(2));
|
String f2 = m.getObjectValue(2);
|
||||||
|
Assert.assertEquals(llllvar, f2);
|
||||||
|
Assert.assertEquals(fieldLength, f2.length());
|
||||||
|
//Encode
|
||||||
|
m = mfact.newMessage(0x100);
|
||||||
|
m.setIsoHeader(null);
|
||||||
|
m.setValue(2, llllvar, IsoType.LLLLVAR, 0);
|
||||||
|
Assert.assertEquals(sb.toString(), m.debugString());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -83,11 +103,11 @@ public class TestLlllPatch {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private String makeLLLLVar(final int length) {
|
private String makeLLLLVar(final int length) {
|
||||||
final StringBuilder sb = new StringBuilder();
|
final char[] chars = new char[length];
|
||||||
for (int i = 0; i < length; i++) {
|
for (int i = 0; i < length; i++) {
|
||||||
sb.append("a");
|
chars[i] = 'a';
|
||||||
}
|
}
|
||||||
|
|
||||||
return sb.toString();
|
return new String(chars);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ public class TestParsing {
|
|||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void init() throws IOException {
|
public void init() throws IOException {
|
||||||
mf = new MessageFactory<IsoMessage>();
|
mf = new MessageFactory<>();
|
||||||
mf.setCharacterEncoding("UTF-8");
|
mf.setCharacterEncoding("UTF-8");
|
||||||
mf.setCustomField(48, new CustomField48());
|
mf.setCustomField(48, new CustomField48());
|
||||||
mf.setConfigPath("config.xml");
|
mf.setConfigPath("config.xml");
|
||||||
@@ -120,20 +120,33 @@ public class TestParsing {
|
|||||||
Assert.assertEquals(25, cal.get(Calendar.DATE));
|
Assert.assertEquals(25, cal.get(Calendar.DATE));
|
||||||
Assert.assertEquals(21, cal.get(Calendar.HOUR_OF_DAY));
|
Assert.assertEquals(21, cal.get(Calendar.HOUR_OF_DAY));
|
||||||
Assert.assertEquals("debug string should match", "060002000000000000000125213456", m.debugString());
|
Assert.assertEquals("debug string should match", "060002000000000000000125213456", m.debugString());
|
||||||
mf.setTimezoneForParseGuide(0x600, 7, TimeZone.getTimeZone("GMT"));
|
mf.setTimezoneForParseGuide(0x600, 7, TimeZone.getTimeZone("UTC"));
|
||||||
m = mf.parseMessage("060002000000000000000125213456".getBytes(), 0);
|
m = mf.parseMessage("060002000000000000000125213456".getBytes(), 0);
|
||||||
f = m.getObjectValue(7);
|
f = m.getObjectValue(7);
|
||||||
cal.setTime(f);
|
cal.setTime(f);
|
||||||
Assert.assertEquals(Calendar.JANUARY, cal.get(Calendar.MONTH));
|
Assert.assertEquals(Calendar.JANUARY, cal.get(Calendar.MONTH));
|
||||||
Assert.assertEquals(25, cal.get(Calendar.DATE));
|
Assert.assertEquals(25, cal.get(Calendar.DATE));
|
||||||
Assert.assertEquals(15, cal.get(Calendar.HOUR_OF_DAY));
|
Assert.assertEquals("Hour of day mismatch", 15, cal.get(Calendar.HOUR_OF_DAY));
|
||||||
|
Assert.assertEquals(TimeZone.getTimeZone("UTC"), m.getField(7).getTimeZone());
|
||||||
mf.setTimezoneForParseGuide(0x600, 7, TimeZone.getTimeZone("GMT+0100"));
|
mf.setTimezoneForParseGuide(0x600, 7, TimeZone.getTimeZone("GMT+0100"));
|
||||||
m = mf.parseMessage("060002000000000000000125213456".getBytes(), 0);
|
m = mf.parseMessage("060002000000000000000125213456".getBytes(), 0);
|
||||||
f = m.getObjectValue(7);
|
f = m.getObjectValue(7);
|
||||||
cal.setTime(f);
|
cal.setTime(f);
|
||||||
Assert.assertEquals(Calendar.JANUARY, cal.get(Calendar.MONTH));
|
Assert.assertEquals(Calendar.JANUARY, cal.get(Calendar.MONTH));
|
||||||
Assert.assertEquals(25, cal.get(Calendar.DATE));
|
Assert.assertEquals(25, cal.get(Calendar.DATE));
|
||||||
Assert.assertEquals(14, cal.get(Calendar.HOUR_OF_DAY));
|
Assert.assertEquals("Hour of day mismatch", 14, cal.get(Calendar.HOUR_OF_DAY));
|
||||||
|
Assert.assertEquals(TimeZone.getTimeZone("GMT+0100"), m.getField(7).getTimeZone());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testTimezoneInResponse() throws ParseException, IOException {
|
||||||
|
mf.setTimezoneForParseGuide(0x600, 7, TimeZone.getTimeZone("UTC"));
|
||||||
|
IsoMessage m = mf.parseMessage("060002000000000000000125213456".getBytes(), 0);
|
||||||
|
Assert.assertEquals(TimeZone.getTimeZone("UTC"), m.getField(7).getTimeZone());
|
||||||
|
IsoMessage r = mf.createResponse(m);
|
||||||
|
Assert.assertEquals(0x610, r.getType());
|
||||||
|
Assert.assertTrue(r.hasField(7));
|
||||||
|
Assert.assertTrue(m.getField(7) != r.getField(7));
|
||||||
|
Assert.assertEquals(TimeZone.getTimeZone("UTC"), r.getField(7).getTimeZone());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,53 @@
|
|||||||
|
package com.solab.iso8583;
|
||||||
|
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.text.ParseException;
|
||||||
|
import java.util.TimeZone;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test timezone assignment in date/time fields.
|
||||||
|
*
|
||||||
|
* @author Enrique Zamudio
|
||||||
|
* Date: 4/17/18 11:50 AM
|
||||||
|
*/
|
||||||
|
public class TestTimezones {
|
||||||
|
|
||||||
|
private final TimeZone utc = TimeZone.getTimeZone("UTC");
|
||||||
|
private final TimeZone gmt5 = TimeZone.getTimeZone("GMT-500");
|
||||||
|
private MessageFactory<IsoMessage> mf;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void init() throws IOException {
|
||||||
|
mf = new MessageFactory<>();
|
||||||
|
mf.setCharacterEncoding("UTF-8");
|
||||||
|
mf.setConfigPath("timezones.xml");
|
||||||
|
mf.setAssignDate(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testTemplate() {
|
||||||
|
IsoMessage t = mf.getMessageTemplate(0x100);
|
||||||
|
Assert.assertTrue(t.hasEveryField(7, 12, 13));
|
||||||
|
Assert.assertEquals(utc, t.getField(7).getTimeZone());
|
||||||
|
Assert.assertEquals(gmt5, t.getField(12).getTimeZone());
|
||||||
|
Assert.assertNull(t.getField(13).getTimeZone());
|
||||||
|
t = mf.newMessage(0x100);
|
||||||
|
Assert.assertTrue(t.hasField(7));
|
||||||
|
Assert.assertEquals(utc, t.getField(7).getTimeZone());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testParsingGuide() throws ParseException, IOException {
|
||||||
|
String trama = "011002180000000000001231112233112233112233";
|
||||||
|
IsoMessage m = mf.parseMessage(trama.getBytes(), 0);
|
||||||
|
Assert.assertTrue(m.hasEveryField(7, 12, 13));
|
||||||
|
Assert.assertEquals(utc, m.getField(7).getTimeZone());
|
||||||
|
Assert.assertEquals(gmt5, m.getField(12).getTimeZone());
|
||||||
|
Assert.assertNull(m.getField(13).getTimeZone());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -25,6 +25,8 @@ public class CustomBinCodecs {
|
|||||||
private final BigInteger b29 = new BigInteger("12345678901234567890123456789");
|
private final BigInteger b29 = new BigInteger("12345678901234567890123456789");
|
||||||
final byte[] longData2 = new byte[]{ 0x12, 0x34, 0x56, 0x78, (byte)0x90, 00, 00, 00, 00, 00 };
|
final byte[] longData2 = new byte[]{ 0x12, 0x34, 0x56, 0x78, (byte)0x90, 00, 00, 00, 00, 00 };
|
||||||
final byte[] bigintData1 = new byte[]{ 1, 0x23, 0x45, 0x67, (byte)0x89, 1, 0x23, 0x45, 0x67, (byte)0x89, 1, 0x23, 0x45, 0x67, (byte)0x89, 00, 00, 00, 00, 00 };
|
final byte[] bigintData1 = new byte[]{ 1, 0x23, 0x45, 0x67, (byte)0x89, 1, 0x23, 0x45, 0x67, (byte)0x89, 1, 0x23, 0x45, 0x67, (byte)0x89, 00, 00, 00, 00, 00 };
|
||||||
|
final byte[] rlong = new byte[]{ 0x12, 0x34, 0x56, 0x78, (byte)0x9F };
|
||||||
|
final byte[] rbi = new byte[]{ 0x12, 0x34, 0x56, 0x78, (byte)0x90, 0x12, 0x34, 0x56, 0x78, (byte)0x9F };
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testLongCodec() {
|
public void testLongCodec() {
|
||||||
@@ -98,4 +100,11 @@ public class CustomBinCodecs {
|
|||||||
testFieldType(IsoType.LLLBIN, new LllbinParseInfo(), 12, 19);
|
testFieldType(IsoType.LLLBIN, new LllbinParseInfo(), 12, 19);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRightPadding() {
|
||||||
|
final LongBcdCodec lc = new LongBcdCodec(true);
|
||||||
|
Assert.assertEquals(123456789L, (long) lc.decodeBinaryField(rlong, 0, 5));
|
||||||
|
final BigIntBcdCodec bc = new BigIntBcdCodec(true);
|
||||||
|
Assert.assertEquals(new BigInteger("1234567890123456789"), bc.decodeBinaryField(rbi, 0, 10));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -61,4 +61,34 @@ public class TestDates {
|
|||||||
Assert.assertEquals(comp.getValue().getTime(), bin.getValue().getTime());
|
Assert.assertEquals(comp.getValue().getTime(), bin.getValue().getTime());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDate14FutureTolerance() throws ParseException, IOException {
|
||||||
|
Date soon = new Date(System.currentTimeMillis() + 50000);
|
||||||
|
byte[] buf = IsoType.DATE14.format(soon, null).getBytes();
|
||||||
|
IsoValue<Date> comp = new Date14ParseInfo().parse(0, buf, 0, null);
|
||||||
|
assert comp.getValue().after(new Date());
|
||||||
|
//Now with the binary
|
||||||
|
ByteArrayOutputStream bout = new ByteArrayOutputStream();
|
||||||
|
comp.write(bout, true, false);
|
||||||
|
IsoValue<Date> bin = new Date14ParseInfo().parseBinary(0, bout.toByteArray(), 0, null);
|
||||||
|
Assert.assertEquals(comp.getValue().getTime(), bin.getValue().getTime());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDate6() throws ParseException, IOException {
|
||||||
|
Date nye = new Date(1514700000000L);
|
||||||
|
IsoValue<Date> f = new IsoValue<>(IsoType.DATE6, nye);
|
||||||
|
Assert.assertEquals("171231", f.toString());
|
||||||
|
IsoValue<Date> parsed = new Date6ParseInfo().parse(1, "171231".getBytes(), 0, null);
|
||||||
|
Assert.assertEquals("171231", parsed.toString());
|
||||||
|
Assert.assertEquals(f.getValue(), parsed.getValue());
|
||||||
|
byte[] buf = new byte[3];
|
||||||
|
buf[0] = 0x17;
|
||||||
|
buf[1] = 0x12;
|
||||||
|
buf[2] = 0x31;
|
||||||
|
parsed = new Date6ParseInfo().parseBinary(2, buf, 0, null);
|
||||||
|
Assert.assertEquals("171231", parsed.toString());
|
||||||
|
Assert.assertEquals(f.getValue(), parsed.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ package com.solab.iso8583.util;
|
|||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.math.BigInteger;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* BCD encoding tests.
|
* BCD encoding tests.
|
||||||
*
|
*
|
||||||
@@ -29,6 +31,8 @@ public class TestBcd {
|
|||||||
Assert.assertArrayEquals(new byte[]{7, 0x79}, buf);
|
Assert.assertArrayEquals(new byte[]{7, 0x79}, buf);
|
||||||
Bcd.encode("999", buf);
|
Bcd.encode("999", buf);
|
||||||
Assert.assertArrayEquals(new byte[]{9,(byte)0x99}, buf);
|
Assert.assertArrayEquals(new byte[]{9,(byte)0x99}, buf);
|
||||||
|
Bcd.encodeRightPadded("999", buf);
|
||||||
|
Assert.assertArrayEquals(new byte[]{(byte)0x99,(byte)0x9f}, buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -52,6 +56,11 @@ public class TestBcd {
|
|||||||
Assert.assertEquals(199, Bcd.decodeToLong(buf,0,4));
|
Assert.assertEquals(199, Bcd.decodeToLong(buf,0,4));
|
||||||
buf[0]=9;
|
buf[0]=9;
|
||||||
Assert.assertEquals(999, Bcd.decodeToLong(buf,0,4));
|
Assert.assertEquals(999, Bcd.decodeToLong(buf,0,4));
|
||||||
|
Assert.assertEquals(new BigInteger("999"), Bcd.decodeToBigInteger(buf,0,3));
|
||||||
|
buf[0] = (byte)0x99;
|
||||||
|
buf[1] = (byte)0x9f;
|
||||||
|
Assert.assertEquals(999, Bcd.decodeRightPaddedToLong(buf,0,4));
|
||||||
|
Assert.assertEquals(new BigInteger("999"), Bcd.decodeRightPaddedToBigInteger(buf,0,4));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
<j8583-config>
|
||||||
|
|
||||||
|
<template type="0100">
|
||||||
|
<field num="7" type="DATE10" tz="UTC" />
|
||||||
|
<field num="12" type="TIME" tz="GMT-500" />
|
||||||
|
<field num="13" type="TIME" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<parse type="0110">
|
||||||
|
<field num="7" type="DATE10" tz="UTC" />
|
||||||
|
<field num="12" type="TIME" tz="GMT-500" />
|
||||||
|
<field num="13" type="TIME" />
|
||||||
|
</parse>
|
||||||
|
|
||||||
|
</j8583-config>
|
||||||
Reference in New Issue
Block a user