package net.java.cargotracker.interfaces.handling.file; import java.io.File; import java.io.RandomAccessFile; import java.io.Serializable; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Arrays; import java.util.Date; import java.util.logging.Level; import java.util.logging.Logger; import javax.batch.api.chunk.AbstractItemReader; import javax.batch.runtime.context.JobContext; import javax.enterprise.context.Dependent; import javax.inject.Inject; import javax.inject.Named; import net.java.cargotracker.domain.model.cargo.TrackingId; import net.java.cargotracker.domain.model.handling.HandlingEvent; import net.java.cargotracker.domain.model.location.UnLocode; import net.java.cargotracker.domain.model.voyage.VoyageNumber; import net.java.cargotracker.interfaces.handling.HandlingEventRegistrationAttempt; @Dependent @Named("EventItemReader") public class EventItemReader extends AbstractItemReader { private static final String UPLOAD_DIRECTORY = "upload_directory"; private static final String ISO_8601_FORMAT = "yyyy-MM-dd HH:mm"; private static final Logger logger = Logger.getLogger( EventItemReader.class.getName()); @Inject private JobContext jobContext; private EventFilesCheckpoint checkpoint; private RandomAccessFile currentFile; @Override public void open(Serializable checkpoint) throws Exception { File uploadDirectory = new File( jobContext.getProperties().getProperty(UPLOAD_DIRECTORY)); if (checkpoint == null) { this.checkpoint = new EventFilesCheckpoint(); logger.log(Level.INFO, "Scanning upload directory: {0}", uploadDirectory); if (!uploadDirectory.exists()) { logger.log(Level.INFO, "Upload directory does not exist, creating it"); uploadDirectory.mkdirs(); } else { this.checkpoint.setFiles(Arrays.asList(uploadDirectory.listFiles())); } } else { logger.log(Level.INFO, "Starting from previous checkpoint"); this.checkpoint = (EventFilesCheckpoint) checkpoint; } File file = this.checkpoint.currentFile(); if (file == null) { logger.log(Level.INFO, "No files to process"); currentFile = null; } else { currentFile = new RandomAccessFile(file, "r"); logger.log(Level.INFO, "Processing file: {0}", file); currentFile.seek(this.checkpoint.getFilePointer()); } } @Override public Object readItem() throws Exception { if (currentFile != null) { String line = currentFile.readLine(); if (line != null) { this.checkpoint.setFilePointer(currentFile.getFilePointer()); return parseLine(line); } else { logger.log(Level.INFO, "Finished processing file, deleting: {0}", this.checkpoint.currentFile()); currentFile.close(); this.checkpoint.currentFile().delete(); File nextFile = this.checkpoint.nextFile(); if (nextFile == null) { logger.log(Level.INFO, "No more files to process"); return null; } else { currentFile = new RandomAccessFile(nextFile, "r"); logger.log(Level.INFO, "Processing file: {0}", nextFile); return readItem(); } } } else { return null; } } private Object parseLine(String line) throws EventLineParseException { String[] result = line.split(","); if (result.length != 5) { throw new EventLineParseException("Wrong number of data elements", line); } Date completionTime = null; try { completionTime = new SimpleDateFormat(ISO_8601_FORMAT).parse(result[0]); } catch (ParseException e) { throw new EventLineParseException("Cannot parse completion time", e, line); } TrackingId trackingId = null; try { trackingId = new TrackingId(result[1]); } catch (NullPointerException e) { throw new EventLineParseException("Cannot parse tracking ID", e, line); } VoyageNumber voyageNumber = null; try { if (!result[2].isEmpty()) { voyageNumber = new VoyageNumber(result[2]); } } catch (NullPointerException e) { throw new EventLineParseException("Cannot parse voyage number", e, line); } UnLocode unLocode = null; try { unLocode = new UnLocode(result[3]); } catch (IllegalArgumentException | NullPointerException e) { throw new EventLineParseException("Cannot parse UN location code", e, line); } HandlingEvent.Type eventType = null; try { eventType = HandlingEvent.Type.valueOf(result[4]); } catch (IllegalArgumentException | NullPointerException e) { throw new EventLineParseException("Cannot parse event type", e, line); } HandlingEventRegistrationAttempt attempt = new HandlingEventRegistrationAttempt(new Date(), completionTime, trackingId, voyageNumber, eventType, unLocode); return attempt; } @Override public Serializable checkpointInfo() throws Exception { return this.checkpoint; } }