com.thelastcheck.io.base.Field Maven / Gradle / Ivy
The newest version!
/*******************************************************************************
* Copyright (c) 2009-2015 The Last Check, LLC, All Rights Reserved
*
* Licensed under the Apache License, Version 2.0 (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
package com.thelastcheck.io.base;
import com.thelastcheck.commons.base.exception.InvalidDataException;
import com.thelastcheck.commons.base.fields.OnUsField;
import com.thelastcheck.commons.base.fields.RoutingNumber;
import com.thelastcheck.commons.base.utils.ToXmlBuilder;
import com.thelastcheck.commons.buffer.ByteArray;
import com.thelastcheck.io.base.exception.InvalidLengthException;
import org.apache.commons.lang3.builder.ToStringBuilder;
import java.text.DateFormat;
import java.text.NumberFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
public class Field {
private static final String SPACES_80 =
" " + " " +
" " + " ";
private int offset;
private int length;
private FieldType type;
private String name;
private int number;
private static Map dateFormatterMap = Collections
.synchronizedMap(new HashMap());
private static Map timeFormatterHHmmssMap = Collections
.synchronizedMap(new HashMap());
private static Map timeFormatterHHmmMap = Collections
.synchronizedMap(new HashMap());
private static NumberFormat numberFormatter = NumberFormat.getInstance();
protected static SimpleDateFormat sdfDate = new SimpleDateFormat("yyyy-MM-dd");
protected static SimpleDateFormat sdfTime = new SimpleDateFormat("HH:mm:ss");
public Field() {
super();
}
public Field(int offset, int length) {
this.offset = offset;
this.length = length;
this.type = com.thelastcheck.io.base.FieldType.STRING;
}
public Field(int offset, int length, FieldType type) {
this.offset = offset;
this.length = length;
this.type = type;
}
public Field(String fieldName, int fieldNumber, int offset, int length) {
this(offset, length);
this.name = fieldName;
this.number = fieldNumber;
}
public Field(String fieldName, int fieldNumber, int offset, int length,
FieldType type) {
this(offset, length, type);
this.name = fieldName;
this.number = fieldNumber;
}
public boolean isType(FieldType type) {
return type.equals(this.type);
}
public FieldType type() {
return this.type;
}
/**
* Extract a data field from a ByteArray.
*
* @param record A ByteArray containing an ASN.1 format record
* @return An Object containing the extracted data. The type of object
* returned depends on the field type.
* @throws InvalidDataException
*/
public Object extract(ByteArray record) throws InvalidDataException {
Object value = null;
switch (type) {
case STRING:
value = extractAsString(record);
break;
case BINARY:
value = extractAsByteArray(record);
break;
case INT:
value = extractStringAsInt(record);
break;
case LONG:
value = extractStringAsLong(record);
break;
case DATE:
value = extractStringAsDate(record);
break;
case TIME:
value = extractStringAsTime(record);
break;
case ROUTING_NUMBER:
value = new RoutingNumber(extractAsString(record));
break;
case ONUS:
value = new OnUsField(extractAsString(record));
break;
}
return value;
}
/**
* Extract a data field from a ByteArray as byte[].
*
* @param record A ByteArray containing an ASN.1 format record
* @return A byte array containing the extracted data.
*/
public byte[] extractAsBytes(ByteArray record) {
return record.read(offset, length);
}
/**
* Extract a data field from a ByteArray as a ByteArray.
*
* @param record A ByteArray containing an ASN.1 format record
* @return A ByteArray containing the extracted data.
*/
public ByteArray extractAsByteArray(ByteArray record) {
return record.readAsByteArray(offset, length);
}
/**
* Extract a data field from a ByteArray record as a String.
*
* @param record A ByteArray containing an ASN.1 format record
* @return A String containing the extracted data.
*/
public String extractAsString(ByteArray record) {
return record.readAsString(offset, length);
}
/**
* Extract a data field from a ByteArray as a String and convert value to a
* long.
*
* @param record A ByteArray containing an ASN.1 format record
* @return A long containing the extracted data.
* @throws InvalidDataException
*/
public long extractStringAsLong(ByteArray record)
throws InvalidDataException {
String s = extractAsString(record).trim();
long value = 0;
// Give a default value of zero to a blank string
if (s.length() > 0) {
try {
value = Long.parseLong(s);
} catch (NumberFormatException e) {
throw new InvalidDataException(e);
}
}
return value;
}
/**
* Extract a data field from a ByteArray as a String and convert value to an
* int.
*
* @param record A ByteArray containing a ASN.1 format record
* @return An int containing the extracted data.
* @throws InvalidDataException
*/
public int extractStringAsInt(ByteArray record) throws InvalidDataException {
String s = extractAsString(record).trim();
int value = 0;
// Give a default value of zero to a blank string
if (s.length() > 0) {
try {
value = Integer.parseInt(s);
} catch (NumberFormatException e) {
throw new InvalidDataException(e);
}
}
return value;
}
/**
* Extract a data field from a ByteArray as a long.
*
* @param record A ByteArray containing an ASN.1 format record
* @return A long containing the extracted data.
*/
public long extractAsLong(ByteArray record) {
long value;
switch (length) {
case 8:
value = record.readAsLong(offset);
break;
case 4:
value = record.readAsInt(offset);
break;
case 2:
value = record.readAsShort(offset);
break;
case 1:
value = record.readAsByte(offset);
break;
default:
throw new InvalidLengthException();
}
return value;
}
/**
* Extract a data field from a ByteArray as a byte.
*
* @param record A ByteArray containing an ASN.1 format record
* @return A byte containing the extracted data.
*/
public byte extractAsByte(ByteArray record) {
byte value;
switch (length) {
case 1:
value = record.readAsByte(offset);
break;
case 2:
value = (byte) record.readAsShort(offset);
break;
case 4:
value = (byte) record.readAsInt(offset);
break;
case 8:
value = (byte) record.readAsLong(offset);
break;
default:
throw new InvalidLengthException();
}
return value;
}
/**
* Extract a data field from a ByteArray as a short.
*
* @param record A ByteArray containing an ASN.1 format record
* @return A short containing the extracted data.
*/
public short extractAsShort(ByteArray record) {
short value;
switch (length) {
case 2:
value = record.readAsShort(offset);
break;
case 1:
value = (short) record.readAsByte(offset);
break;
case 4:
value = (short) record.readAsInt(offset);
break;
case 8:
value = (short) record.readAsLong(offset);
break;
default:
throw new InvalidLengthException();
}
return value;
}
/**
* Extract a data field from a ByteArray as an int.
*
* @param record A ByteArray containing an ASN.1 format record
* @return An int containing the extracted data.
*/
public int extractAsInt(ByteArray record) {
int value;
switch (length) {
case 4:
value = record.readAsInt(offset);
break;
case 2:
value = record.readAsShort(offset);
break;
case 1:
value = record.readAsByte(offset);
break;
case 8:
value = (int) record.readAsLong(offset);
break;
default:
throw new InvalidLengthException();
}
return value;
}
/**
* Extract a data field from a ByteArray converting from PNS to a String.
*
* @param record A ByteArray containing an ASN.1 format record
* @return A string containing the unpacked data
*/
public String extractPnsAsString(ByteArray record) {
return record.readPns(offset, length);
}
/**
* Extract a data field from a ByteArray as a Date.
*
* @param record A ByteArray containing an ASN.1 format record
* @return A Date containing the extracted data.
* @throws InvalidDataException
*/
public Date extractStringAsDate(ByteArray record)
throws InvalidDataException {
return extractStringAsDate(record, null);
}
/**
* Extract a data field from a ByteArray as a Date.
*
* @param record A ByteArray containing an ASN.1 format record
* @return A Date containing the extracted data or null if the
* string value is empty.
* @throws InvalidDataException
*/
public Date extractStringAsDate(ByteArray record, TimeZone zone)
throws InvalidDataException {
String date = extractAsString(record);
if (date.length() != 8) {
throw new InvalidDataException("Date field must be 8 characters in length");
}
DateFormat format = dateFormatForZone(zone);
return formatDateTime(date, format);
}
/**
* Extract a data field from a ByteArray as a Date object containing only
* time values.
*
* @param record A ByteArray containing an ASN.1 format record
* @return A time value formatted as Date containing the extracted data
* or null if the string value is empty.
* @throws InvalidDataException
*/
public Date extractStringAsTime(ByteArray record)
throws InvalidDataException {
return extractStringAsTime(record, null);
}
/**
* Extract a data field from a ByteArray as a Date object containing only
* time values.
*
* @param record A ByteArray containing an ASN.1 format record
* @param zone A TimeZone object identifying the time zone for the time being
* extracted
* @return A time value formatted as Date containing the extracted data
* or null if the string value is empty.
* @throws InvalidDataException
*/
public Date extractStringAsTime(ByteArray record, TimeZone zone)
throws InvalidDataException {
String time = extractAsString(record);
if (time.length() != 4 && time.length() != 6) {
throw new InvalidDataException("Time field must be 4 or 6 characters in length");
}
DateFormat format;
if (time.length() == 4) {
format = timeFormatHHmmForZone(zone);
} else {
format = timeFormatHHmmssForZone(zone);
}
return formatDateTime(time, format);
}
private Date formatDateTime(String time, DateFormat format) throws InvalidDataException {
Date value = null;
if (time.trim().length() > 0) {
synchronized (format) {
try {
value = format.parse(time);
} catch (ParseException e) {
throw new InvalidDataException(e);
}
}
}
return value;
}
/**
* Extract a data field from a ByteArray as a String and convert value to an
* RoutingNumber.
*
* @param record A ByteArray containing a ASN.1 format record
* @return A RoutingNumber containing the extracted data.
* @throws InvalidDataException
*/
public RoutingNumber extractStringAsRoutingNumber(ByteArray record) {
String s = extractAsString(record).trim();
return new RoutingNumber(s);
}
/**
* Extract a data field from a ByteArray as a String and convert value to an
* OnusField.
*
* @param record A ByteArray containing a ASN.1 format record
* @return A OnUsField containing the extracted data.
* @throws InvalidDataException
*/
public OnUsField extractStringAsOnUsField(ByteArray record) {
String s = extractAsString(record).trim();
return new OnUsField(s);
}
/**
* @param value A field value contained in an array of bytes.
* @param record A ByteArray containing an ASN.1 format record
*/
public void insert(byte[] value, ByteArray record) {
record.write(value, 0, length, offset);
}
/**
* @param value A field value contained in a ByteArray to be stored into the
* ByteArray.
* @param record A ByteArray containing an ASN.1 format record
*/
public void insert(ByteArray value, ByteArray record) {
record.write(value, offset, length);
}
/**
* @param value A field value contained in a String to be stored into the
* ByteArray.
* @param record A ByteArray containing an ASN.1 format record
*/
public void insert(String value, ByteArray record) {
record.write(value, offset, length, false);
}
/**
* @param value A field value contained in a String to be stored into the
* ByteArray right justified and space filled.
* @param record A ByteArray containing an ASN.1 format record
*/
public void insertRight(String value, ByteArray record) {
if (value.length() > length) {
value = value.substring(value.length() - length);
}
while (value.length() < length) {
if ((length - value.length()) > 80) {
value = SPACES_80 + value;
} else {
value = SPACES_80.substring(0, length - value.length()) + value;
}
}
record.write(value, offset, length, false);
}
/**
* @param value A field value contained in a long to be converted to a String
* and then to be stored into the ByteArray.
* @param record A ByteArray containing an ASN.1 format record
*/
public void insertAsString(long value, ByteArray record) {
String s;
synchronized (numberFormatter) {
numberFormatter.setGroupingUsed(false);
numberFormatter.setMinimumIntegerDigits(length);
s = numberFormatter.format(value);
}
insert(s, record);
}
/**
* @param value A field value contained in an int to be converted to a String
* and then to be stored into the ByteArray.
* @param record A ByteArray containing an ASN.1 format record
*/
public void insertAsString(int value, ByteArray record) {
String s;
synchronized (numberFormatter) {
numberFormatter.setGroupingUsed(false);
numberFormatter.setMinimumIntegerDigits(length);
s = numberFormatter.format(value);
}
insert(s, record);
}
/**
* @param value A field value contained in an int and stored in big endion
* binary format in the ByteArray.
* @param record A ByteArray containing an ASN.1 format record
*/
public void insert(byte value, ByteArray record) {
switch (length) {
case 1:
record.write(value, offset);
break;
case 2:
record.write((short) value, offset);
break;
case 4:
record.write((int) value, offset);
break;
default:
throw new InvalidLengthException();
}
}
/**
* @param value A field value contained in an int and stored in big endion
* binary format in the ByteArray.
* @param record A ByteArray containing an ASN.1 format record
*/
public void insert(short value, ByteArray record) {
switch (length) {
case 2:
record.write(value, offset);
break;
case 1:
record.write((byte) value, offset);
break;
case 4:
record.write((int) value, offset);
break;
default:
throw new InvalidLengthException();
}
}
/**
* @param value A field value contained in an int and stored in big endion
* binary format in the ByteArray.
* @param record A ByteArray containing an ASN.1 format record
*/
public void insert(int value, ByteArray record) {
switch (length) {
case 4:
record.write(value, offset);
break;
case 2:
record.write((short) value, offset);
break;
case 1:
record.write((byte) value, offset);
break;
default:
throw new InvalidLengthException();
}
}
/**
* @param value A field value contained in an long and stored in big endion
* binary format in the ByteArray.
* @param record A ByteArray containing an ASN.1 format record
*/
public void insert(long value, ByteArray record) {
switch (length) {
case 8:
record.write(value, offset);
break;
case 4:
record.write((int) value, offset);
break;
case 2:
record.write((short) value, offset);
break;
case 1:
record.write((byte) value, offset);
break;
default:
throw new InvalidLengthException();
}
}
/**
* @param value A field value contained in a Date object to be converted to a
* String and then to be stored into the ByteArray.
* @param record A ByteArray containing an ASN.1 format record
*/
public void insertDate(Date value, ByteArray record) {
insertDate(value, record, null);
}
/**
* @param value A field value contained in a Date object to be converted to a
* String and then to be stored into the ByteArray.
* @param zone A TimeZone object identifying the time zone for the date being
* extracted. Based on the time value in the date object, this
* could result in the date value being a different date than the
* local date.
* @param record A ByteArray containing an ASN.1 format record
*/
public void insertDate(Date value, ByteArray record, TimeZone zone) {
DateFormat df = dateFormatForZone(zone);
String date;
synchronized (df) {
date = df.format(value);
}
insert(date, record);
}
/**
* @param value A field value contained in a Date object as a time value to be
* converted to a String and then to be stored into the
* ByteArray.
* @param record A ByteArray containing an ASN.1 format record
*/
public void insertTime(Date value, ByteArray record) {
insertTime(value, record, null);
}
/**
* @param value A field value contained in a Date object as a time value to be
* converted to a String and then to be stored into the
* ByteArray.
* @param record A ByteArray containing an ASN.1 format record
*/
public void insertTime(Date value, ByteArray record, TimeZone zone) {
DateFormat df;
if (length == 4) {
df = timeFormatHHmmForZone(zone);
} else {
df = timeFormatHHmmssForZone(zone);
}
String time;
synchronized (df) {
time = df.format(value);
}
insert(time, record);
}
private DateFormat dateFormatForZone(TimeZone zone) {
return formatForZone(dateFormatterMap, "yyyyMMdd", zone);
}
private DateFormat timeFormatHHmmssForZone(TimeZone zone) {
return formatForZone(timeFormatterHHmmssMap, "HHmmss", zone);
}
private DateFormat timeFormatHHmmForZone(TimeZone zone) {
return formatForZone(timeFormatterHHmmMap, "HHmm", zone);
}
private DateFormat formatForZone(Map map,
String format, TimeZone zone) {
DateFormat df;
if (zone == null) {
df = map.get(null);
} else {
df = map.get(zone.getID());
}
if (df == null) {
df = new SimpleDateFormat(format);
if (zone == null) {
map.put(null, df);
} else {
Calendar cal = Calendar.getInstance(zone);
df.setCalendar(cal);
map.put(zone.getID(), df);
}
}
return df;
}
/**
* @param value A field value contained in a RoutingNumber to be stored into
* the ByteArray.
* @param record A ByteArray containing an ASN.1 format record
*/
public void insert(RoutingNumber value, ByteArray record) {
record.write(value.toString(), offset, length, false);
}
/**
* @param value A field value contained in a OnUsField to be stored into the
* ByteArray.
* @param record A ByteArray containing an ASN.1 format record
*/
public void insert(OnUsField value, ByteArray record) {
record.write(value.toString(), offset, length, false);
}
/**
* @param value A field value to be stored as a PNS value in the ByteArray
* @param record A ByteArray containing an ASN.1 format record
*/
public void insertPns(String value, ByteArray record) {
record.writeAsPns(value, offset, length);
}
/**
* @param mask A mask value to indicate which bits are to be set.
* @param record A ByteArray containing an ASN.1 format record
*/
public void setBit(byte mask, ByteArray record) {
record.setBit(offset, mask);
}
/**
* @param mask A mask value to indicate which bits are to be cleared.
* @param record A ByteArray containing an ASN.1 format record
*/
public void clearBit(byte mask, ByteArray record) {
record.clearBit(offset, mask);
}
/**
* @param mask A mask value to indicate which bits are to be tested.
* @param record A ByteArray containing an ASN.1 format record
*/
public boolean testBit(byte mask, ByteArray record) {
return record.testBit(offset, mask);
}
public String name() {
return this.name;
}
@Override
public String toString() {
ToStringBuilder sb = new ToStringBuilder(this);
sb.append("Offset", offset);
sb.append("Length", length);
sb.append("Type", type);
sb.append("Number", number);
sb.append("Name", name);
return sb.build();
}
/**
* Format the field into a ToStringBuilder object.
*
* @param record
* @param sb
*/
public void formatToString(ByteArray record, ToStringBuilder sb) {
switch (type) {
case BINARY:
int len = (length < 16) ? length : 16;
String data = record.readPns(offset, len);
sb.append(name, "BINARY DATA[LEN=" + length + ",x'" + data + "']");
break;
case DATE:
synchronized (sdfDate) {
try {
sb.append(name, sdfDate.format(extract(record)));
} catch (Exception e) {
sb.append(name, extractAsString(record));
}
}
break;
case TIME:
synchronized (sdfTime) {
try {
sb.append(name, sdfTime.format(extract(record)));
} catch (Exception e) {
sb.append(name, extractAsString(record));
}
}
break;
default:
sb.append(name, extractAsString(record));
}
}
/**
* Format the field into a ToStringBuilder object.
*
* @param record
* @param xb
*/
public void formatToXml(ByteArray record, ToXmlBuilder xb) {
switch (type) {
case BINARY:
int len = (length < 16) ? length : 16;
String data = record.readPns(offset, len);
xb.append(name, "BINARY DATA[LEN=" + length + ",x'" + data + "']");
break;
case DATE:
synchronized (sdfDate) {
try {
xb.append(name, sdfDate.format(extract(record)));
} catch (Exception e) {
xb.append(name, extractAsString(record));
}
}
break;
case TIME:
synchronized (sdfTime) {
try {
xb.append(name, sdfTime.format(extract(record)));
} catch (Exception e) {
xb.append(name, extractAsString(record));
}
}
break;
default:
xb.append(name, extractAsString(record));
}
}
}