Tutorial 05 - Keeping local landing reports in sync with the Elandings Database
For the completed project for this section see
A web service client could be used by third-party developers to keep their local database in sync with the eLandings database. The client could be added to a scheduled task. Each time it wakes up and runs, it could be configured to pull any landing reports from eLandings that have been modified since the last time the client ran. In order to do this, we need to have the Client keep track of when it last ran.
To begin with, we will add a utililty class called CalendarUtility
Right click on the elandingsclient package > New >Java Class
Enter the class name of LastRunTimestamp
Click Finish
We now have an empty class called LastRunTimestamp.
We will use this class to help us keep track of when we last ran time we ran the client. To do this, we will need some tools to work with Date objects and the ability to store and retrieve a Date object. There are lots of different ways that this might be accomplished. In this simple example, we will store the date in a local file and reference it on subsequent runs.
Add the following code to the file:
private static String LAST_RUN_TIMESTAMP_FILE_NAME = "lastRunDate.dat";
private static String TIMESTAMP_DATE_FORMAT = "yyyy-MM-dd-HH.mm.ss.mmm";
private SimpleDateFormat dateFormatter;
Date lastRunDate;
Date currentDate;
We will store our last run in a file called lastRunDate.dat
Next we will create a constructor for the class:
public LastRunTimestamp() {
currentDate = Calendar.getInstance().getTime();
dateFormatter = new SimpleDateFormat(TIMESTAMP_DATE_FORMAT);
}
We need a method to write the currentDate to a file. Add the following code:
public void writeCurrentDateToFile() throws FileNotFoundException, IOException{
String timestamp = dateFormatter.format(currentDate);
BufferedWriter out = new BufferedWriter(new FileWriter(LAST_RUN_TIMESTAMP_FILE_NAME));
out.write(timestamp);
out.close();
}
Notice that the writeCurrentDateToFile() uses the dateFormatter object to convert the currentDate object into a human readable string. This string is then written to the file lastRunDate.dat
Test the method. Go to the main method of ELandingsClient.java. Edit the main method to just run:
LastRunTimestamp lastRun = new LastRunTimestamp();
lastRun.writeCurrentDateToFile();
Run the application.
Look in the netbeans project for the lastRunDate.dat file
Open the lastRunDate.dat file with a text editor. You should see a single line like "2011-08-17-10.09.34.009"
We now have a way to record when the client ran last. Now we need a way to retrieve this date from the file.
Go back to the LastRunTimestamp.java file
Add the following code to the end of the class:
public void readDateFromFile() throws IOException, ParseException{
BufferedReader in = null;
String lastRunDateText = "";
try {
in = new BufferedReader(new FileReader(LAST_RUN_TIMESTAMP_FILE_NAME));
lastRunDateText = in.readLine();
if (null != lastRunDateText) {
lastRunDate = dateFormatter.parse(lastRunDateText);
}
} catch (FileNotFoundException ex) {
//DO NOTHING
} finally {
if (null != in) {
try {
in.close();
} catch (IOException ex) {
//do nothing
}
}
}
}
The readDateFromFile() will open up the file lastRunDate.dat and read in the date string stored in the file. It will then convert the string into a Date object and store this value in the Date lastRunDate. Notice that if the method cannot find the file, it captures the error and does nothing. The file will not exist if the application is running for the first time. This handles this situation for us.
In order to see the results of the readDateFromFile(), we will add two print methods:
public void printCurrentDateString() {
if (null == currentDate) {
System.out.println("The Current Date is not defined");
} else {
String timestamp = dateFormatter.format(currentDate);
System.out.println("The current date is " + timestamp);
}
}
public void printLastRunDateString() {
if (null == lastRunDate) {
System.out.println("The Last Run Date is not defined");
} else {
String timestamp = dateFormatter.format(lastRunDate);
System.out.println("The Last Run Date was " + timestamp);
}
}
Now test the LastRunTimestamp methods by modifying ElandingsClient.java main method:
LastRunTimestamp lastRun = new LastRunTimestamp();
lastRun.readDateFromFile();
lastRun.printCurrentDateString();
lastRun.printLastRunDateString();
lastRun.writeCurrentDateToFile();
Run the application to test the behavior.
If the lastRunDate.dat file does not exist on the first run, you should see something like:
The current date is 2011-08-17-11.03.26.003
The Last Run Date is not defined
Run the application to test the behavior.
If the lastRunDate.dat file does not exist on the first run, you should see something like:
The current date is 2011-08-17-11.04.13.004
The Last Run Date was 2011-08-17-11.03.26.003
We now have a means of recording and loading the last time the elandingsClient application was executed.
We want a means of using this date help us get all landing reports that have changed in the eLandings database, since the last time we ran the eLandingsClient application.
In ElandingsClient.java, find the getLandingReportList()
In the last tutorial, we had to pass the web service method findUserLandingReports001() an XMLGregorianCalendar object called fromLastUpdateDateArg. The fromLastUpdateDateArg tells the eLandings database to get all landing reports that the current user can see that have changed from the fromLastUpdateDateArg to the present.
We want to pass the LastRunDate into this argument so that we can get all the landing reports that have been updated in eLandings since the last time we ran eLandingsClient.
Open the LastRunTimestamp.java file and add the following code to create an XMLGregorianCalendar object containing the lastRunDate
At the top of the LastRunTimestamp.java class, add a DatetypeFactory object and instanciate it in the constructor:
private DatatypeFactory datatypeFactory;
public LastRunTimestamp() throws DatatypeConfigurationException {
currentDate = Calendar.getInstance().getTime();
dateFormatter = new SimpleDateFormat(TIMESTAMP_DATE_FORMAT);
datatypeFactory = DatatypeFactory.newInstance();
}
At the end of the LastRunTimestamp.java, create a new method called getLastRunXmlGregorianCalendar():
public XMLGregorianCalendar getLastRunXmlGregorianCalendar(){
if(null == lastRunDate){
return null;
}
Calendar calendar = Calendar.getInstance();
calendar.setTime(lastRunDate);
XMLGregorianCalendar calArg = (null == calendar) ? null : datatypeFactory.newXMLGregorianCalendar((GregorianCalendar) calendar);
return calArg;
}
Go back to the ElandingsClient.java file and find the getLandingReportList(). Modify the method to be:
public void getLandingReportList(LastRunTimestamp lastRun) throws JAXBException {
XMLGregorianCalendar fromLastUpdateDateArg = lastRun.getLastRunXmlGregorianCalendar();
if (null == fromLastUpdateDateArg) {
System.out.println("The fromDate is null.");
System.out.println("Calling the webservice without a fromDate, would result in attempting to download all eLandings landing reports.");
System.out.println("This may result in an out of memory error and is not recommended.");
System.out.println("Please enter a more manageable date range and try again.");
System.out.println("The getLandingReportList() request has been aborted");
return;
}
String xml = svc.findUserLandingReports001("amarx", "A_marx", "2.1", null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
null, null, null, null, fromLastUpdateDateArg, null);
System.out.println(xml);
LandingReportInfoWrapper infoWrapper = new LandingReportInfoWrapper(xml, unmarshaller);
ArrayList<LandingReportWrapper> landingReports = new ArrayList<LandingReportWrapper>();
int size = infoWrapper.getInfo().getLandingReportSummary().size();
for (int x = 0; x < size; x++) {
String landingReportId = infoWrapper.getInfo().getLandingReportSummary().get(x).getLandingReportId().getValue().toString();
System.out.println((x + 1) + " " + landingReportId);
String landingReportXml = svc.getLandingReport("amarx", "A_marx", "2.1", landingReportId);
System.out.println(landingReportXml);
LandingReportWrapper landingReportWrapper = new LandingReportWrapper(landingReportXml, unmarshaller);
landingReports.add(landingReportWrapper);
}
System.out.println("The landingReports arrayList contains " + landingReports.size() + " reports ");
}
Notice that we are now passing in the LastRunTimestamp object into the getLandingReportList() method. Within the getLandingReportList() method, we are calling the LastRunTimestamp. getLastRunXmlGregorianCalendar() method to get an XMLGregorianCalendar instance of our lastRunDate. This xml calendar object is then being passed into the webservice call.
Notice that we have some basic logic to cancel the webservice call if the XMLGregorianCalendar object is null. Imagine that you have been working with eLandings since it's inseption in 2005. If you were to call the findUserLandingReports() without a date range of any kind, eLandings would attempt to send you all landing reports available to you. This could result in the download of tens of thousands of records depending on the user making the request. This method might run for hours before it completes the requests or more likely eLandings may terminate the request or your local java heap would run out of memory and crash. The eLandings team recommends working with smaller time ranges to minimize impact on the eLandnigs system and your own system.
Modify the ElandingsClient.java main() method to test these changes
public static void main(String\[\] args) {
System.out.println("Hello ELandings Client");
try {
ElandingsClient client = new ElandingsClient();
//client.connectToWebService();
LastRunTimestamp lastRun = new LastRunTimestamp();
lastRun.readDateFromFile();
lastRun.printCurrentDateString();
lastRun.printLastRunDateString();
client.getLandingReportList(lastRun);
lastRun.writeCurrentDateToFile();
} catch (Exception e) {
e.printStackTrace();
}
}
Run the ElandingsClient application
If you don't have a lastRunDate.dat file, you may get the following results.
Hello ELandings Client
The current date is 2011-08-17-11.48.52.048
The Last Run Date is not defined
The fromDate is null.
Calling the webservice without a fromDate, would result in attempting to download all eLandngs landing reports.
This may result in an out of memory error and is not recommended.
Please enter a more manageable date range and try again.
getLandingReportList request has been aborted