forked from reposense/RepoSense
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathCsvParser.java
More file actions
135 lines (113 loc) · 4.99 KB
/
CsvParser.java
File metadata and controls
135 lines (113 loc) · 4.99 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
package reposense.parser;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;
import reposense.system.LogsManager;
public abstract class CsvParser<T> {
protected static final String COLUMN_VALUES_SEPARATOR = ";";
protected static final Logger logger = LogsManager.getLogger(CsvParser.class);
private static final String ELEMENT_SEPARATOR = ",";
private static final String MESSAGE_UNABLE_TO_READ_CSV_FILE = "Unable to read the supplied CSV file.";
private static final String MESSAGE_MALFORMED_LINE_FORMAT = "Warning! line %d in configuration file is malformed.\n"
+ "Contents: %s";
private Path csvFilePath;
/**
* @throws IOException if {@code csvFilePath} is an invalid path.
*/
public CsvParser(Path csvFilePath) throws IOException {
if (csvFilePath == null || !Files.exists(csvFilePath)) {
throw new IOException("Csv file does not exists in given path.\n"
+ "Use '-help' to list all the available subcommands and some concept guides.");
}
this.csvFilePath = csvFilePath;
}
/**
* @throws IOException if there are error accessing the given csv file.
*/
public List<T> parse() throws IOException {
List<T> results = new ArrayList<>();
int lineNumber = 1;
try (BufferedReader br = new BufferedReader(new FileReader(csvFilePath.toFile()))) {
// Skip first line, which is the header row
br.readLine();
String line;
while ((line = br.readLine()) != null) {
String[] elements = line.split(ELEMENT_SEPARATOR);
if (line.isEmpty() || isLineMalformed(elements, lineNumber, line)) {
continue;
}
processLine(results, elements);
lineNumber++;
}
} catch (IOException ioe) {
throw new IOException(MESSAGE_UNABLE_TO_READ_CSV_FILE, ioe);
} catch (ParseException pe) {
logger.log(Level.WARNING, pe.getMessage(), pe);
}
return results;
}
private boolean isLineMalformed(final String[] elements, int lineNumber, String line) {
for (int position : mandatoryPositions()) {
if (!containsValueAtPosition(elements, position)) {
logger.warning(String.format(MESSAGE_MALFORMED_LINE_FORMAT, lineNumber, line));
return true;
}
}
return false;
}
/**
* Checks that {@code position} in within the range of {@code element} array and
* value in {@code position} is not empty.
*/
private boolean containsValueAtPosition(final String[] elements, int position) {
return elements.length > position && !elements[position].isEmpty();
}
/**
* Gets the value of {@code position} in {@code elements}.
* Returns the value of {@code position} if it is in {@code element} and not empty.
* Otherwise returns an empty string.
*/
protected String getValueInElement(final String[] elements, int position) {
return (containsValueAtPosition(elements, position)) ? elements[position] : "";
}
/**
* Gets the value of {@code position} in {@code elements}.
* Returns the value of {@code position} if it is in {@code element} and not empty.
* Otherwise returns the {@code defaultValue}.
*/
protected String getValueInElement(final String[] elements, int position, String defaultValue) {
return (containsValueAtPosition(elements, position)) ? elements[position] : defaultValue;
}
/**
* Gets the value of {@code position} in {@code elements}.
* Returns the value of {@code element} at {@code position} as a {@code List},
* delimited by {@code COLUMN_VALUES_SEPARATOR} if it is in {@code element} and not empty.
* Otherwise returns an empty {@code List}.
*/
protected List<String> getManyValueInElement(final String[] elements, int position) {
if (!containsValueAtPosition(elements, position)) {
return Collections.emptyList();
}
String manyValue = getValueInElement(elements, position);
return Arrays.stream(manyValue.split(COLUMN_VALUES_SEPARATOR)).map(String::trim).collect(Collectors.toList());
}
/**
* Gets the list of positions that are mandatory for verification.
*/
protected abstract int[] mandatoryPositions();
/**
* Processes the csv file line by line.
* All CsvParsers should use {@code getValueInElement} or {@code getManyValueInElement} to read contents in
* {@code elements} and add created objects into {@code results}.
*/
protected abstract void processLine(List<T> results, final String[] elements) throws ParseException;
}