An ISO 8583 message is composed of data elements. Time data elements are formatted as HHmmss (hours-minutes-seconds) strings. Date data elements are formatted as MMdd (month-day) strings. The current code base had a lot of duplicated code that used SimpleDateFormat instances to set the date/time data elements. To remove duplication (and avoid future duplication), we needed a helper method that would format date/time objects correctly and set the desired data element.
We didn't want to extend the ISO 8583 message (ISOMsg) class of jPOS. Instead, we created a helper class that wraps the ISOMsg class, and provides methods that we needed.
Again, we start with a test.
import static org.junit.Assert.*;
import java.util.*;
import org.junit.*;
import org.jpos.iso.ISOException;
import org.jpos.iso.ISOMsg;
public class ISOMsgHelperTest {
private ISOMsg isoMsg = new ISOMsg();
private ISOMsgHelper helper = new ISOMsgHelper(isoMsg);
private Date dateTime =
new GregorianCalendar(2011, Calendar.APRIL, 15, 9, 30, 59).getTime();
@Test
public void setsIsoDateAsMonthDay() throws Exception {
helper.setIsoDate(12, dateTime);
assertEquals("0415", isoMsg.getString(12));
}
@Test
public void setsIsoTimeAsHourMinuteSecond() throws Exception {
helper.setIsoDate(13, dateTime);
assertEquals("093059", isoMsg.getString(13));
}
@Test
public void setsIsoDateTime() throws Exception {
helper.setIsoDate(7, dateTime);
assertEquals("0415093059", isoMsg.getString(7));
}
}
And here's the class that passes the test.
import java.util.Date;
import java.text.*;
import org.jpos.iso.ISOException;
import org.jpos.iso.ISOMsg;
public class ISOMsgHelper {
private ISOMsg isoMsg;
public ISOMsgHelper(ISOMsg isoMsg) {
if (isoMsg == null) {
throw new IllegalArgumentException("isoMsg cannot be null");
}
this.isoMsg = isoMsg;
}
public void setIsoDate(int fldNo, Date date) throws ISOException {
this.isoMsg.set(fldNo, dateFormat.get().format(date));
}
public void setIsoTime(int fldNo, Date time) throws ISOException {
this.isoMsg.set(fldNo, timeFormat.get().format(time));
}
public void setIsoDateTime(int fldNo, Date dateTime) throws ISOException {
this.isoMsg.set(fldNo, dateTimeFormat.get().format(dateTime));
}
public Date getIsoDate(int fldNo) throws ISOException {
if (this.isoMsg.hasField(fldNo)) {
try {
return dateFormat.get().parse(this.isoMsg.getString(fldNo));
} catch (ParseException e) {
throw new ISOException("Error getting date field " + fldNo, e);
}
}
return null;
}
// Other getters were removed to improve clarity
// Need to make SimpleDateFormat objects thread-safe
private static final ThreadLocal<SimpleDateFormat> dateFormat =
new ThreadLocal<SimpleDateFormat>() {
@Override
protected SimpleDateFormat initialValue() {
return new SimpleDateFormat("MMdd");
}
};
private static final ThreadLocal<SimpleDateFormat> timeFormat =
new ThreadLocal<SimpleDateFormat>() {
@Override
protected SimpleDateFormat initialValue() {
return new SimpleDateFormat("HHmmss");
}
};
private static final ThreadLocal<SimpleDateFormat> dateTimeFormat =
new ThreadLocal<SimpleDateFormat>() {
@Override
protected SimpleDateFormat initialValue() {
return new SimpleDateFormat("MMddHHmmss");
}
};
}
Now, we can easily set date/time fields! And the date formatting objects are nicely encapsulated in one place.
ISOMsg isoMsg = ...;
ISOMsgHelper isoMsgHelper = new ISOMsgHelper(isoMsg);
Date now = new Date();
isoMsgHelper.setIsoDate(12, now); // local transaction date
isoMsgHelper.setIsoTime(13, now); // local transaction time
...
isoMsgHelper.setIsoDateTime(7, new Date()); // transmission date/time
So far, it has removed a lot of duplicated code. We are expanding ISOMsgHelper to support other commonly used formats. Hope this helps!