Skip to content

Commit c135b3c

Browse files
authored
Merge 2eae957 into ada0b25
2 parents ada0b25 + 2eae957 commit c135b3c

File tree

38 files changed

+270
-454
lines changed

38 files changed

+270
-454
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,3 +104,4 @@ app/pkg/bin/
104104
processor/notices/bin/
105105
processor/notices/tests/bin/
106106
web/service/bin/
107+
/web/service/execution_result.json

core/src/main/java/org/mobilitydata/gtfsvalidator/table/AnyTableLoader.java

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -61,22 +61,19 @@ public static GtfsTableContainer load(
6161
csvFile = new CsvFile(csvInputStream, gtfsFilename, settings);
6262
} catch (TextParsingException e) {
6363
noticeContainer.addValidationNotice(new CsvParsingFailedNotice(gtfsFilename, e));
64-
return tableDescriptor.createContainerForInvalidStatus(
65-
GtfsTableContainer.TableStatus.INVALID_HEADERS);
64+
return tableDescriptor.createContainerForInvalidStatus(TableStatus.INVALID_HEADERS);
6665
}
6766
if (csvFile.isEmpty()) {
6867
noticeContainer.addValidationNotice(new EmptyFileNotice(gtfsFilename));
69-
return tableDescriptor.createContainerForInvalidStatus(
70-
GtfsTableContainer.TableStatus.EMPTY_FILE);
68+
return tableDescriptor.createContainerForInvalidStatus(TableStatus.EMPTY_FILE);
7169
}
7270
final CsvHeader header = csvFile.getHeader();
7371
final ImmutableList<GtfsColumnDescriptor> columnDescriptors = tableDescriptor.getColumns();
7472
final NoticeContainer headerNotices =
7573
validateHeaders(validatorProvider, gtfsFilename, header, columnDescriptors);
7674
noticeContainer.addAll(headerNotices);
7775
if (headerNotices.hasValidationErrors()) {
78-
return tableDescriptor.createContainerForInvalidStatus(
79-
GtfsTableContainer.TableStatus.INVALID_HEADERS);
76+
return tableDescriptor.createContainerForInvalidStatus(TableStatus.INVALID_HEADERS);
8077
}
8178
final int nColumns = columnDescriptors.size();
8279
final ImmutableMap<String, GtfsFieldLoader> fieldLoadersMap = tableDescriptor.getFieldLoaders();
@@ -133,15 +130,13 @@ public static GtfsTableContainer load(
133130
}
134131
} catch (TextParsingException e) {
135132
noticeContainer.addValidationNotice(new CsvParsingFailedNotice(gtfsFilename, e));
136-
return tableDescriptor.createContainerForInvalidStatus(
137-
GtfsTableContainer.TableStatus.UNPARSABLE_ROWS);
133+
return tableDescriptor.createContainerForInvalidStatus(TableStatus.UNPARSABLE_ROWS);
138134
} finally {
139135
logFieldCacheStats(gtfsFilename, fieldCaches, columnDescriptors);
140136
}
141137
if (hasUnparsableRows) {
142138
logger.atSevere().log("Failed to parse some rows in %s", gtfsFilename);
143-
return tableDescriptor.createContainerForInvalidStatus(
144-
GtfsTableContainer.TableStatus.UNPARSABLE_ROWS);
139+
return tableDescriptor.createContainerForInvalidStatus(TableStatus.UNPARSABLE_ROWS);
145140
}
146141
GtfsTableContainer table =
147142
tableDescriptor.createContainerForHeaderAndEntities(header, entities, noticeContainer);
@@ -203,8 +198,7 @@ public static GtfsTableContainer loadMissingFile(
203198
NoticeContainer noticeContainer) {
204199
String gtfsFilename = tableDescriptor.gtfsFilename();
205200
GtfsTableContainer table =
206-
tableDescriptor.createContainerForInvalidStatus(
207-
GtfsTableContainer.TableStatus.MISSING_FILE);
201+
tableDescriptor.createContainerForInvalidStatus(TableStatus.MISSING_FILE);
208202
if (tableDescriptor.isRecommended()) {
209203
noticeContainer.addValidationNotice(new MissingRecommendedFileNotice(gtfsFilename));
210204
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package org.mobilitydata.gtfsvalidator.table;
2+
3+
import java.util.List;
4+
import java.util.Optional;
5+
6+
public abstract class GtfsContainer<T extends GtfsEntity, D extends GtfsDescriptor> {
7+
8+
private final D descriptor;
9+
private final TableStatus tableStatus;
10+
11+
public GtfsContainer(D descriptor, TableStatus tableStatus) {
12+
this.tableStatus = tableStatus;
13+
this.descriptor = descriptor;
14+
}
15+
16+
public TableStatus getTableStatus() {
17+
return tableStatus;
18+
}
19+
20+
public D getDescriptor() {
21+
return descriptor;
22+
}
23+
24+
public abstract Class<T> getEntityClass();
25+
26+
public int entityCount() {
27+
return getEntities().size();
28+
}
29+
30+
public abstract List<T> getEntities();
31+
32+
public abstract String gtfsFilename();
33+
34+
public abstract Optional<T> byTranslationKey(String recordId, String recordSubId);
35+
36+
public boolean isMissingFile() {
37+
return tableStatus == TableStatus.MISSING_FILE;
38+
}
39+
40+
public boolean isParsedSuccessfully() {
41+
switch (tableStatus) {
42+
case PARSABLE_HEADERS_AND_ROWS:
43+
return true;
44+
case MISSING_FILE:
45+
return !descriptor.isRequired();
46+
default:
47+
return false;
48+
}
49+
}
50+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package org.mobilitydata.gtfsvalidator.table;
2+
3+
// TODO: review class name maybe GtfsFileDescriptor
4+
public abstract class GtfsDescriptor<T extends GtfsEntity> {
5+
// True if the specified file is required in a feed.
6+
private boolean required;
7+
8+
private TableStatus tableStatus;
9+
10+
public abstract boolean isRecommended();
11+
12+
public abstract Class<T> getEntityClass();
13+
14+
public abstract String gtfsFilename();
15+
16+
public boolean isRequired() {
17+
return this.required;
18+
}
19+
20+
public void setRequired(boolean required) {
21+
this.required = required;
22+
}
23+
}

core/src/main/java/org/mobilitydata/gtfsvalidator/table/GtfsFeedContainer.java

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -18,20 +18,19 @@
1818

1919
import com.google.common.base.Ascii;
2020
import java.util.*;
21-
import org.mobilitydata.gtfsvalidator.table.GtfsTableContainer.TableStatus;
2221

2322
/**
2423
* Container for a whole parsed GTFS feed with all its tables.
2524
*
26-
* <p>The tables are kept as {@code GtfsTableContainer} instances.
25+
* <p>The tables are kept as {@code GtfsContainer} instances.
2726
*/
2827
public class GtfsFeedContainer {
29-
private final Map<String, GtfsTableContainer<?>> tables = new HashMap<>();
30-
private final Map<Class<? extends GtfsTableContainer>, GtfsTableContainer<?>> tablesByClass =
28+
private final Map<String, GtfsContainer<?, ?>> tables = new HashMap<>();
29+
private final Map<Class<? extends GtfsContainer>, GtfsContainer<?, ?>> tablesByClass =
3130
new HashMap<>();
3231

33-
public GtfsFeedContainer(List<GtfsTableContainer<?>> tableContainerList) {
34-
for (GtfsTableContainer<?> table : tableContainerList) {
32+
public GtfsFeedContainer(List<GtfsContainer<?, ?>> tableContainerList) {
33+
for (GtfsContainer<?, ?> table : tableContainerList) {
3534
tables.put(table.gtfsFilename(), table);
3635
tablesByClass.put(table.getClass(), table);
3736
}
@@ -49,11 +48,12 @@ public GtfsFeedContainer(List<GtfsTableContainer<?>> tableContainerList) {
4948
* @param filename file name, including ".txt" extension
5049
* @return GTFS table or empty if the table is not supported by schema
5150
*/
52-
public Optional<GtfsTableContainer<?>> getTableForFilename(String filename) {
53-
return Optional.ofNullable(tables.getOrDefault(Ascii.toLowerCase(filename), null));
51+
public <T extends GtfsContainer<?, ?>> Optional<T> getTableForFilename(String filename) {
52+
return (Optional<T>)
53+
Optional.ofNullable(tables.getOrDefault(Ascii.toLowerCase(filename), null));
5454
}
5555

56-
public <T extends GtfsTableContainer<?>> T getTable(Class<T> clazz) {
56+
public <T extends GtfsContainer<?, ?>> T getTable(Class<T> clazz) {
5757
return (T) tablesByClass.get(clazz);
5858
}
5959

@@ -65,21 +65,21 @@ public <T extends GtfsTableContainer<?>> T getTable(Class<T> clazz) {
6565
* @return true if all files were successfully parsed, false otherwise
6666
*/
6767
public boolean isParsedSuccessfully() {
68-
for (GtfsTableContainer<?> table : tables.values()) {
68+
for (GtfsContainer<?, ?> table : tables.values()) {
6969
if (!table.isParsedSuccessfully()) {
7070
return false;
7171
}
7272
}
7373
return true;
7474
}
7575

76-
public Collection<GtfsTableContainer<?>> getTables() {
76+
public Collection<GtfsContainer<?, ?>> getTables() {
7777
return tables.values();
7878
}
7979

8080
public String tableTotalsText() {
8181
List<String> totalList = new ArrayList<>();
82-
for (GtfsTableContainer<?> table : tables.values()) {
82+
for (GtfsContainer<?, ?> table : tables.values()) {
8383
if (table.getTableStatus() == TableStatus.MISSING_FILE
8484
&& !table.getDescriptor().isRequired()) {
8585
continue;

core/src/main/java/org/mobilitydata/gtfsvalidator/table/GtfsFeedLoader.java

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ public GtfsFeedContainer loadAndValidate(
107107
loaderCallables.add(
108108
() -> {
109109
NoticeContainer loaderNotices = new NoticeContainer();
110-
GtfsTableContainer<?> tableContainer;
110+
GtfsContainer<?, ?> tableContainer;
111111
try (InputStream inputStream = gtfsInput.getFile(filename)) {
112112
try {
113113
tableContainer =
@@ -130,7 +130,7 @@ public GtfsFeedContainer loadAndValidate(
130130
});
131131
}
132132
}
133-
ArrayList<GtfsTableContainer<?>> tableContainers = new ArrayList<>();
133+
ArrayList<GtfsContainer<?, ?>> tableContainers = new ArrayList<>();
134134
tableContainers.ensureCapacity(tableDescriptors.size());
135135
for (GtfsTableDescriptor<?> tableDescriptor : remainingDescriptors.values()) {
136136
tableContainers.add(
@@ -186,11 +186,10 @@ private static void addThreadExecutionError(
186186
}
187187

188188
static class TableAndNoticeContainers {
189-
final GtfsTableContainer tableContainer;
189+
final GtfsContainer tableContainer;
190190
final NoticeContainer noticeContainer;
191191

192-
public TableAndNoticeContainers(
193-
GtfsTableContainer tableContainer, NoticeContainer noticeContainer) {
192+
public TableAndNoticeContainers(GtfsContainer tableContainer, NoticeContainer noticeContainer) {
194193
this.tableContainer = tableContainer;
195194
this.noticeContainer = noticeContainer;
196195
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package org.mobilitydata.gtfsvalidator.table;
2+
3+
public abstract class GtfsJsonContainer<T extends GtfsEntity, D extends GtfsDescriptor<T>>
4+
extends GtfsContainer<T, D> {
5+
6+
public GtfsJsonContainer(D descriptor, TableStatus tableStatus) {
7+
super(descriptor, tableStatus);
8+
}
9+
}

core/src/main/java/org/mobilitydata/gtfsvalidator/table/GtfsTableContainer.java

Lines changed: 4 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -31,29 +31,16 @@
3131
*
3232
* @param <T> subclass of {@code GtfsEntity}
3333
*/
34-
public abstract class GtfsTableContainer<T extends GtfsEntity> {
35-
36-
private final GtfsTableDescriptor<T> descriptor;
37-
38-
private final TableStatus tableStatus;
34+
public abstract class GtfsTableContainer<T extends GtfsEntity, D extends GtfsTableDescriptor>
35+
extends GtfsContainer<T, D> {
3936

4037
private final CsvHeader header;
4138

42-
public GtfsTableContainer(
43-
GtfsTableDescriptor<T> descriptor, TableStatus tableStatus, CsvHeader header) {
44-
this.descriptor = descriptor;
45-
this.tableStatus = tableStatus;
39+
public GtfsTableContainer(D descriptor, TableStatus tableStatus, CsvHeader header) {
40+
super(descriptor, tableStatus);
4641
this.header = header;
4742
}
4843

49-
public GtfsTableDescriptor<T> getDescriptor() {
50-
return descriptor;
51-
}
52-
53-
public TableStatus getTableStatus() {
54-
return tableStatus;
55-
}
56-
5744
public CsvHeader getHeader() {
5845
return header;
5946
}
@@ -94,74 +81,4 @@ public boolean hasColumn(String columnName) {
9481
* @return entity with the given translation record id, if any
9582
*/
9683
public abstract Optional<T> byTranslationKey(String recordId, String recordSubId);
97-
98-
/**
99-
* Tells if the file is missing.
100-
*
101-
* @return true if the file is missing, false otherwise
102-
*/
103-
public boolean isMissingFile() {
104-
return tableStatus == TableStatus.MISSING_FILE;
105-
}
106-
107-
/**
108-
* Tells if the file was successfully parsed.
109-
*
110-
* <p>If all files in the feed were successfully parsed, then file validators may be executed.
111-
*
112-
* <p>A successfully parsed file must meet the following conditions:
113-
*
114-
* <ul>
115-
* <li>the file was successfully parsed as CSV;
116-
* <li>all headers are valid, required headers are present;
117-
* <li>all rows are successfully parsed;
118-
* <li>if the file is required, it is present in the feed.
119-
* </ul>
120-
*
121-
* @return true if file was successfully parsed, false otherwise
122-
*/
123-
public boolean isParsedSuccessfully() {
124-
switch (tableStatus) {
125-
case PARSABLE_HEADERS_AND_ROWS:
126-
return true;
127-
case MISSING_FILE:
128-
return !descriptor.isRequired();
129-
default:
130-
return false;
131-
}
132-
}
133-
134-
/**
135-
* Status of loading this table. This is includes parsing of the CSV file and validation of the
136-
* single file, but does not include any cross-file validations.
137-
*/
138-
public enum TableStatus {
139-
/** The file is completely empty, i.e. it has no rows and even no headers. */
140-
EMPTY_FILE,
141-
142-
/** The file is missing in the GTFS feed. */
143-
MISSING_FILE,
144-
145-
/** The file was parsed successfully. It has headers and 0, 1 or many rows. */
146-
PARSABLE_HEADERS_AND_ROWS,
147-
148-
/**
149-
* The file has invalid headers, e.g., they failed to parse or some required headers are
150-
* missing. The other rows were not scanned.
151-
*
152-
* <p>Note that unknown headers are not considered invalid.
153-
*/
154-
INVALID_HEADERS,
155-
156-
/**
157-
* Some of the rows failed to parse, e.g., they have missing required fields or invalid field
158-
* values.
159-
*
160-
* <p>However, the headers are valid.
161-
*
162-
* <p>This does not include cross-file or cross-row validation. This also does not include
163-
* single-entity validation.
164-
*/
165-
UNPARSABLE_ROWS,
166-
}
16784
}

core/src/main/java/org/mobilitydata/gtfsvalidator/table/GtfsTableDescriptor.java

Lines changed: 2 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -7,35 +7,17 @@
77
import org.mobilitydata.gtfsvalidator.notice.NoticeContainer;
88
import org.mobilitydata.gtfsvalidator.parsing.CsvHeader;
99

10-
public abstract class GtfsTableDescriptor<T extends GtfsEntity> {
10+
public abstract class GtfsTableDescriptor<T extends GtfsEntity> extends GtfsDescriptor<T> {
1111

12-
// True if the specified file is required in a feed.
13-
private boolean required;
14-
15-
public abstract GtfsTableContainer createContainerForInvalidStatus(
16-
GtfsTableContainer.TableStatus tableStatus);
12+
public abstract GtfsTableContainer createContainerForInvalidStatus(TableStatus tableStatus);
1713

1814
public abstract GtfsTableContainer createContainerForHeaderAndEntities(
1915
CsvHeader header, List<T> entities, NoticeContainer noticeContainer);
2016

2117
public abstract GtfsEntityBuilder createEntityBuilder();
2218

23-
public abstract Class<T> getEntityClass();
24-
25-
public abstract String gtfsFilename();
26-
2719
public abstract ImmutableMap<String, GtfsFieldLoader> getFieldLoaders();
2820

29-
public abstract boolean isRecommended();
30-
31-
public boolean isRequired() {
32-
return this.required;
33-
}
34-
35-
public void setRequired(boolean required) {
36-
this.required = required;
37-
}
38-
3921
public abstract Optional<Integer> maxCharsPerColumn();
4022

4123
public abstract ImmutableList<GtfsColumnDescriptor> getColumns();

0 commit comments

Comments
 (0)