1 package se.citerus.dddsample.interfaces.handling.file;
2
3 import org.apache.commons.io.FileUtils;
4 import org.apache.commons.logging.Log;
5 import org.apache.commons.logging.LogFactory;
6 import org.springframework.beans.factory.InitializingBean;
7 import se.citerus.dddsample.application.ApplicationEvents;
8 import se.citerus.dddsample.domain.model.cargo.TrackingId;
9 import se.citerus.dddsample.domain.model.handling.HandlingEvent;
10 import se.citerus.dddsample.domain.model.location.UnLocode;
11 import se.citerus.dddsample.domain.model.voyage.VoyageNumber;
12 import se.citerus.dddsample.interfaces.handling.HandlingEventRegistrationAttempt;
13 import static se.citerus.dddsample.interfaces.handling.HandlingReportParser.*;
14
15 import java.io.File;
16 import java.io.IOException;
17 import java.util.ArrayList;
18 import java.util.Date;
19 import java.util.List;
20 import java.util.TimerTask;
21
22
23
24
25
26
27
28
29 public class UploadDirectoryScanner extends TimerTask implements InitializingBean {
30
31 private File uploadDirectory;
32 private File parseFailureDirectory;
33
34 private final static Log logger = LogFactory.getLog(UploadDirectoryScanner.class);
35 private ApplicationEvents applicationEvents;
36
37 @Override
38 public void run() {
39 for (File file : uploadDirectory.listFiles()) {
40 try {
41 parse(file);
42 delete(file);
43 logger.info("Import of " + file.getName() + " complete");
44 } catch (Exception e) {
45 logger.error(e, e);
46 move(file);
47 }
48 }
49 }
50
51 private void parse(final File file) throws IOException {
52 final List<String> lines = FileUtils.readLines(file);
53 final List<String> rejectedLines = new ArrayList<String>();
54 for (String line : lines) {
55 try {
56 parseLine(line);
57 } catch (Exception e) {
58 logger.error("Rejected line \n" + line + "\nReason is: " + e);
59 rejectedLines.add(line);
60 }
61 }
62 if (!rejectedLines.isEmpty()) {
63 writeRejectedLinesToFile(toRejectedFilename(file), rejectedLines);
64 }
65 }
66
67 private String toRejectedFilename(final File file) {
68 return file.getName() + ".reject";
69 }
70
71 private void writeRejectedLinesToFile(final String filename, final List<String> rejectedLines) throws IOException {
72 FileUtils.writeLines(
73 new File(parseFailureDirectory, filename), rejectedLines
74 );
75 }
76
77 private void parseLine(final String line) throws Exception {
78 final String[] columns = line.split("\t");
79 if (columns.length == 5) {
80 queueAttempt(columns[0], columns[1], columns[2], columns[3], columns[4]);
81 } else if (columns.length == 4) {
82 queueAttempt(columns[0], columns[1], "", columns[2], columns[3]);
83 } else {
84 throw new IllegalArgumentException("Wrong number of columns on line: " + line + ", must be 4 or 5");
85 }
86 }
87
88 private void queueAttempt(String completionTimeStr, String trackingIdStr, String voyageNumberStr, String unLocodeStr, String eventTypeStr) throws Exception {
89 final List<String> errors = new ArrayList<String>();
90
91 final Date date = parseDate(completionTimeStr, errors);
92 final TrackingId trackingId = parseTrackingId(trackingIdStr, errors);
93 final VoyageNumber voyageNumber = parseVoyageNumber(voyageNumberStr, errors);
94 final HandlingEvent.Type eventType = parseEventType(eventTypeStr, errors);
95 final UnLocode unLocode = parseUnLocode(unLocodeStr, errors);
96
97 if (errors.isEmpty()) {
98 final HandlingEventRegistrationAttempt attempt = new HandlingEventRegistrationAttempt(new Date(), date, trackingId, voyageNumber, eventType, unLocode);
99 applicationEvents.receivedHandlingEventRegistrationAttempt(attempt);
100 } else {
101 throw new Exception(errors.toString());
102 }
103 }
104
105 private void delete(final File file) {
106 if (!file.delete()) {
107 logger.error("Could not delete " + file.getName());
108 }
109 }
110
111 private void move(final File file) {
112 final File destination = new File(parseFailureDirectory, file.getName());
113 final boolean result = file.renameTo(destination);
114 if (!result) {
115 logger.error("Could not move " + file.getName() + " to " + destination.getAbsolutePath());
116 }
117 }
118
119 @Override
120 public void afterPropertiesSet() throws Exception {
121 if (uploadDirectory.equals(parseFailureDirectory)) {
122 throw new Exception("Upload and parse failed directories must not be the same directory: " + uploadDirectory);
123 }
124 if (!uploadDirectory.exists()) {
125 uploadDirectory.mkdirs();
126 }
127 if (!parseFailureDirectory.exists()) {
128 parseFailureDirectory.mkdirs();
129 }
130 }
131
132 public void setUploadDirectory(File uploadDirectory) {
133 this.uploadDirectory = uploadDirectory;
134 }
135
136 public void setParseFailureDirectory(File parseFailureDirectory) {
137 this.parseFailureDirectory = parseFailureDirectory;
138 }
139
140 public void setApplicationEvents(ApplicationEvents applicationEvents) {
141 this.applicationEvents = applicationEvents;
142 }
143 }