This commit is contained in:
Enrique Zamudio
2013-05-13 18:54:44 -05:00
parent 160f780309
commit 2e521c2b6d
8 changed files with 92 additions and 58 deletions
@@ -51,6 +51,7 @@ public class IsoMessage {
/** Flag to enforce secondary bitmap even if empty. */
private boolean forceb2;
private boolean binBitmap;
private boolean forceStringEncoding;
private String encoding = System.getProperty("file.encoding");
/** Creates a new empty message with no values set. */
@@ -96,7 +97,15 @@ public class IsoMessage {
return encoding;
}
/** Sets the string to be sent as ISO header, that is, after the length header but before the message type.
/** Specified whether the variable-length fields should encode their length
* headers using string conversion with the proper character encoding. Default
* is false, which is the old behavior (encoding as ASCII). This is only useful
* for text format. */
public void setForceStringEncoding(boolean flag) {
forceStringEncoding = flag;
}
/** Sets the string to be sent as ISO header, that is, after the length header but before the message type.
* This is useful in case an application needs some custom data in the ISO header of each message (very rare). */
public void setIsoHeader(String value) {
isoHeader = value;
@@ -385,7 +394,7 @@ public class IsoMessage {
IsoValue<?> v = fields[i];
if (v != null) {
try {
v.write(bout, binary);
v.write(bout, binary, forceStringEncoding);
} catch (IOException ex) {
//should never happen, writing to a ByteArrayOutputStream
}
+41 -39
View File
@@ -245,48 +245,50 @@ public class IsoValue<T> implements Cloneable {
return encoder;
}
protected void writeLengthHeader(final int l, final OutputStream outs, final int digits,
final boolean binary, final boolean forceStringEncoding)
throws IOException {
if (binary) {
if (digits == 3) {
outs.write(l / 100); //00 to 09 automatically in BCD
}
//BCD encode the rest of the length
outs.write((((l % 100) / 10) << 4) | (l % 10));
} else if (forceStringEncoding) {
String lhead = Integer.toString(l);
final int ldiff = digits - lhead.length();
if (ldiff == 1) {
lhead = '0' + lhead;
} else if (ldiff == 2) {
lhead = "00" + lhead;
}
outs.write(lhead.getBytes(encoding));
} else {
//write the length in ASCII
if (digits == 3) {
outs.write((l / 100) + 48);
}
if (l >= 10) {
outs.write(((l % 100) / 10) + 48);
} else {
outs.write(48);
}
outs.write((l % 10) + 48);
}
}
/** Writes the formatted value to a stream, with the length header
* if it's a variable length type. */
public void write(OutputStream outs, boolean binary) throws IOException {
* if it's a variable length type.
* @param outs The stream to which the value will be written.
* @param binary Specifies whether the value should be written in binary or text format.
* @param forceStringEncoding When using text format, force the encoding of length headers
* for variable-length fields to be done with the proper character encoding. When false,
* the length headers are encoded as ASCII; this used to be the only behavior. */
public void write(final OutputStream outs, final boolean binary, final boolean forceStringEncoding) throws IOException {
if (type == IsoType.LLLVAR || type == IsoType.LLVAR) {
if (binary) {
if (type == IsoType.LLLVAR) {
outs.write(length / 100); //00 to 09 automatically in BCD
}
//BCD encode the rest of the length
outs.write((((length % 100) / 10) << 4) | (length % 10));
} else {
//write the length in ASCII
if (type == IsoType.LLLVAR) {
outs.write((length / 100) + 48);
}
if (length >= 10) {
outs.write(((length % 100) / 10) + 48);
} else {
outs.write(48);
}
outs.write((length % 10) + 48);
}
writeLengthHeader(length, outs, type == IsoType.LLLVAR ? 3 : 2, binary, forceStringEncoding);
} else if (type == IsoType.LLBIN || type == IsoType.LLLBIN) {
if (binary) {
if (type == IsoType.LLLBIN ) {
outs.write(length / 100); //00 to 09 automatically in BCD
}
//BCD encode the rest of the length
outs.write((((length % 100) / 10) << 4) | (length % 10));
} else {
int _l = length*2;
//write the length in ASCII
if (type == IsoType.LLLBIN) {
outs.write((_l / 100) + 48);
}
if (_l >= 10) {
outs.write(((_l % 100) / 10) + 48);
} else {
outs.write(48);
}
outs.write((_l % 10) + 48);
}
writeLengthHeader(binary ? length : length*2, outs, type == IsoType.LLLBIN ? 3 : 2, binary, forceStringEncoding);
} else if (binary) {
//numeric types in binary are coded like this
byte[] buf = null;
@@ -94,13 +94,24 @@ public class MessageFactory<T extends IsoMessage> {
throw new IllegalArgumentException("Cannot set null encoding.");
}
encoding = value;
if (parseMap.size() > 0) {
if (!parseMap.isEmpty()) {
for (Map<Integer, FieldParseInfo> pt : parseMap.values()) {
for (FieldParseInfo fpi : pt.values()) {
fpi.setCharacterEncoding(encoding);
}
}
}
if (!typeTemplates.isEmpty()) {
for (T tmpl : typeTemplates.values()) {
tmpl.setCharacterEncoding(encoding);
for (int i = 2 ; i<129; i++) {
IsoValue<?> v = tmpl.getField(i);
if (v != null) {
v.setCharacterEncoding(encoding);
}
}
}
}
}
/** Returns the encoding used to parse ALPHA, LLVAR and LLLVAR fields. The default is the file.encoding
@@ -143,12 +154,12 @@ public class MessageFactory<T extends IsoMessage> {
}
/** Returns a custom field encoder/decoder for the specified field number, if one is available. */
@SuppressWarnings("unchecked")
public <T> CustomField<T> getCustomField(int index) {
public <F> CustomField<F> getCustomField(int index) {
return customFields.get(index);
}
/** Returns a custom field encoder/decoder for the specified field number, if one is available. */
@SuppressWarnings("unchecked")
public <T> CustomField<T> getCustomField(Integer index) {
public <F> CustomField<F> getCustomField(Integer index) {
return customFields.get(index);
}
@@ -34,6 +34,7 @@ public abstract class FieldParseInfo {
protected IsoType type;
protected int length;
private String encoding = System.getProperty("file.encoding");
protected boolean forceStringDecoding;
/** Creates a new instance that parses a value of the specified type, with the specified length.
* The length is only useful for ALPHA and NUMERIC types.
@@ -47,6 +48,13 @@ public abstract class FieldParseInfo {
length = len;
}
/** Specified whether length headers for variable-length fields in text mode should
* be decoded using proper string conversion with the character encoding. Default is false,
* which means use the old behavior of decoding as ASCII. */
public void setForceStringDecoding(boolean flag) {
forceStringDecoding = flag;
}
public void setCharacterEncoding(String value) {
encoding = value;
}
@@ -119,4 +127,14 @@ public abstract class FieldParseInfo {
return fpi;
}
protected int decodeLength(byte[] buf, int pos, int digits) throws UnsupportedEncodingException {
if (forceStringDecoding) {
return Integer.parseInt(new String(buf, pos, digits, encoding));
} else if (digits == 3) {
return ((buf[pos] - 48) * 100) + ((buf[pos + 1] - 48) * 10) + (buf[pos + 2] - 48);
} else {
return ((buf[pos] - 48) * 10) + (buf[pos + 1] - 48);
}
}
}
@@ -18,6 +18,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
package com.solab.iso8583.parse;
import java.io.UnsupportedEncodingException;
import java.text.ParseException;
import com.solab.iso8583.CustomBinaryField;
@@ -40,7 +41,7 @@ public class LlbinParseInfo extends FieldParseInfo {
@Override
public <T> IsoValue<?> parse(final int field, final byte[] buf,
final int pos, final CustomField<T> custom)
throws ParseException {
throws ParseException, UnsupportedEncodingException {
if (pos < 0) {
throw new ParseException(String.format("Invalid LLBIN field %d position %d",
field, pos), pos);
@@ -48,7 +49,7 @@ public class LlbinParseInfo extends FieldParseInfo {
throw new ParseException(String.format("Insufficient LLBIN header field %d",
field), pos);
}
length = ((buf[pos] - 48) * 10) + (buf[pos + 1] - 48);
length = decodeLength(buf, pos, 2);
if (length < 0) {
throw new ParseException(String.format("Invalid LLBIN field %d length %d pos %d",
field, length, pos), pos);
@@ -18,6 +18,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
package com.solab.iso8583.parse;
import java.io.UnsupportedEncodingException;
import java.text.ParseException;
import com.solab.iso8583.CustomBinaryField;
@@ -40,7 +41,7 @@ public class LllbinParseInfo extends FieldParseInfo {
@Override
public <T> IsoValue<?> parse(final int field, final byte[] buf,
final int pos, final CustomField<T> custom)
throws ParseException {
throws ParseException, UnsupportedEncodingException {
if (pos < 0) {
throw new ParseException(String.format("Invalid LLLBIN field %d pos %d",
field, pos), pos);
@@ -48,11 +49,7 @@ public class LllbinParseInfo extends FieldParseInfo {
throw new ParseException(String.format("Insufficient LLLBIN header field %d",
field), pos);
}
if (!(Character.isDigit(buf[pos]) && Character.isDigit(buf[pos+1]) && Character.isDigit(buf[pos+2]))) {
throw new ParseException(String.format("Invalid LLLBIN length '%s' field %d pos %d",
new String(buf, pos, 3), field, pos), pos);
}
final int l = ((buf[pos] - 48) * 100) + ((buf[pos + 1] - 48) * 10) + (buf[pos + 2] - 48);
final int l = decodeLength(buf, pos, 3);
if (l < 0) {
throw new ParseException(String.format("Invalid LLLBIN length %d field %d pos %d",
l, field, pos), pos);
@@ -46,11 +46,7 @@ public class LllvarParseInfo extends FieldParseInfo {
throw new ParseException(String.format(
"Insufficient data for LLLVAR header field %d pos %d", field, pos), pos);
}
if (!(Character.isDigit(buf[pos]) && Character.isDigit(buf[pos+1]) && Character.isDigit(buf[pos+2]))) {
throw new ParseException(String.format("Invalid LLLVAR length '%s' field %d pos %d",
new String(buf, pos, 3), field, pos), pos);
}
length = ((buf[pos] - 48) * 100) + ((buf[pos + 1] - 48) * 10) + (buf[pos + 2] - 48);
length = decodeLength(buf, pos, 3);
if (length < 0) {
throw new ParseException(String.format("Invalid LLLVAR length %d field %d pos %d",
length, field, pos), pos);
@@ -44,7 +44,7 @@ public class LlvarParseInfo extends FieldParseInfo {
} else if (pos+2 > buf.length) {
throw new ParseException(String.format("Insufficient data for LLVAR header, pos %d", pos), pos);
}
length = ((buf[pos] - 48) * 10) + (buf[pos + 1] - 48);
length = decodeLength(buf, pos, 2);
if (length < 0) {
throw new ParseException(String.format(
"Invalid LLVAR length %d, field %d pos %d", length, field, pos), pos);