From c5cda6fe8fe125d8dfbe8a1cdeb6efbfd318ba8f Mon Sep 17 00:00:00 2001 From: lionel-nj Date: Mon, 22 Feb 2021 10:28:03 -0500 Subject: [PATCH 1/7] create custom exception --- .../notice/ErrorDetectedException.java | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 core/src/main/java/org/mobilitydata/gtfsvalidator/notice/ErrorDetectedException.java diff --git a/core/src/main/java/org/mobilitydata/gtfsvalidator/notice/ErrorDetectedException.java b/core/src/main/java/org/mobilitydata/gtfsvalidator/notice/ErrorDetectedException.java new file mode 100644 index 0000000000..c57e43d410 --- /dev/null +++ b/core/src/main/java/org/mobilitydata/gtfsvalidator/notice/ErrorDetectedException.java @@ -0,0 +1,28 @@ +/* + * Copyright 2021 MobilityData IO + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.mobilitydata.gtfsvalidator.notice; + +/** + * Custom {@code Exception} to be thrown when the validator hits the first {@code Notice} with + * {@code SeverityLevel} set with {@code SeverityLevel.ERROR} value. + */ +public class ErrorDetectedException extends Exception { + + public ErrorDetectedException(String message) { + super(message); + } +} From 4c18e4e3719126e0f51f742f3aa9963d932ed955 Mon Sep 17 00:00:00 2001 From: lionel-nj Date: Mon, 22 Feb 2021 10:36:25 -0500 Subject: [PATCH 2/7] create new CLI option : -a --abort_on_error with true as default value - implement getter --- .../org/mobilitydata/gtfsvalidator/cli/Arguments.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/main/src/main/java/org/mobilitydata/gtfsvalidator/cli/Arguments.java b/main/src/main/java/org/mobilitydata/gtfsvalidator/cli/Arguments.java index 222421f354..fea4e54750 100644 --- a/main/src/main/java/org/mobilitydata/gtfsvalidator/cli/Arguments.java +++ b/main/src/main/java/org/mobilitydata/gtfsvalidator/cli/Arguments.java @@ -56,6 +56,11 @@ public class Arguments { + "downloaded from network (if not provided, the ZIP will be stored in memory)") private String storageDirectory; + @Parameter( + names = {"-a", "--abort_on_error"}, + description = "Stop validation process on first error") + private boolean abortOnError = true; + public String getInput() { return input; } @@ -79,4 +84,8 @@ public String getUrl() { public String getStorageDirectory() { return storageDirectory; } + + public boolean getAbortOnError() { + return abortOnError; + } } From 1e10668c363f254f5abd5acc415f1892b9ad4d12 Mon Sep 17 00:00:00 2001 From: lionel-nj Date: Mon, 22 Feb 2021 10:38:03 -0500 Subject: [PATCH 3/7] throw ErrorDetectedException on ERROR in NoticeContainer.addSystemError and NoticeContainer.addValidationNotice methods --- .../gtfsvalidator/notice/NoticeContainer.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/org/mobilitydata/gtfsvalidator/notice/NoticeContainer.java b/core/src/main/java/org/mobilitydata/gtfsvalidator/notice/NoticeContainer.java index e74cad5b80..71595e42b3 100644 --- a/core/src/main/java/org/mobilitydata/gtfsvalidator/notice/NoticeContainer.java +++ b/core/src/main/java/org/mobilitydata/gtfsvalidator/notice/NoticeContainer.java @@ -39,12 +39,16 @@ public class NoticeContainer { private final List validationNotices = new ArrayList<>(); private final List systemErrors = new ArrayList<>(); - public void addValidationNotice(ValidationNotice notice) { + public void addValidationNotice(ValidationNotice notice) throws ErrorDetectedException { validationNotices.add(notice); + if (notice.getSeverityLevel().equals(SeverityLevel.ERROR)) { + throw new ErrorDetectedException(notice.toString()); + } } - public void addSystemError(SystemError error) { + public void addSystemError(SystemError error) throws ErrorDetectedException { systemErrors.add(error); + throw new ErrorDetectedException(error.toString()); } public List getValidationNotices() { From f6ee49155a11525088b3268d54bbabc9783699d0 Mon Sep 17 00:00:00 2001 From: lionel-nj Date: Mon, 22 Feb 2021 10:39:09 -0500 Subject: [PATCH 4/7] throw ErrorDetectedException in TableHeaderValidator.validate method --- .../gtfsvalidator/validator/TableHeaderValidator.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/org/mobilitydata/gtfsvalidator/validator/TableHeaderValidator.java b/core/src/main/java/org/mobilitydata/gtfsvalidator/validator/TableHeaderValidator.java index 3dc4131f73..14e85be0cf 100644 --- a/core/src/main/java/org/mobilitydata/gtfsvalidator/validator/TableHeaderValidator.java +++ b/core/src/main/java/org/mobilitydata/gtfsvalidator/validator/TableHeaderValidator.java @@ -21,6 +21,7 @@ import java.util.Set; import java.util.TreeSet; import org.mobilitydata.gtfsvalidator.notice.DuplicatedColumnNotice; +import org.mobilitydata.gtfsvalidator.notice.ErrorDetectedException; import org.mobilitydata.gtfsvalidator.notice.MissingRequiredColumnError; import org.mobilitydata.gtfsvalidator.notice.NoticeContainer; import org.mobilitydata.gtfsvalidator.notice.UnknownColumnNotice; @@ -32,7 +33,7 @@ public boolean validate( String[] actualColumns, Set supportedColumns, Set requiredColumns, - NoticeContainer noticeContainer) { + NoticeContainer noticeContainer) throws ErrorDetectedException { boolean isValid = true; if (actualColumns.length == 0) { // This is an empty file. From 5c6f1ac0ab77576e18d4f2bfaffc435b2d235caa Mon Sep 17 00:00:00 2001 From: lionel-nj Date: Mon, 22 Feb 2021 15:12:44 -0500 Subject: [PATCH 5/7] propagate exception in code generators --- .../gtfsvalidator/table/GtfsFeedLoader.java | 79 +++++++++---------- .../gtfsvalidator/table/GtfsTableLoader.java | 5 +- .../validator/ValidatorLoader.java | 6 +- .../ForeignKeyValidatorGenerator.java | 2 + .../processor/TableLoaderGenerator.java | 3 + 5 files changed, 51 insertions(+), 44 deletions(-) diff --git a/core/src/main/java/org/mobilitydata/gtfsvalidator/table/GtfsFeedLoader.java b/core/src/main/java/org/mobilitydata/gtfsvalidator/table/GtfsFeedLoader.java index dc1014c051..6eceb65e5b 100644 --- a/core/src/main/java/org/mobilitydata/gtfsvalidator/table/GtfsFeedLoader.java +++ b/core/src/main/java/org/mobilitydata/gtfsvalidator/table/GtfsFeedLoader.java @@ -28,8 +28,11 @@ import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import java.util.concurrent.Future; import org.mobilitydata.gtfsvalidator.annotation.GtfsLoader; import org.mobilitydata.gtfsvalidator.input.GtfsInput; +import org.mobilitydata.gtfsvalidator.notice.ErrorDetectedException; +import org.mobilitydata.gtfsvalidator.notice.Notice; import org.mobilitydata.gtfsvalidator.notice.NoticeContainer; import org.mobilitydata.gtfsvalidator.notice.RuntimeExceptionInLoaderError; import org.mobilitydata.gtfsvalidator.notice.RuntimeExceptionInValidatorError; @@ -91,7 +94,8 @@ public GtfsFeedContainer loadAndValidate( GtfsInput gtfsInput, ValidationContext validationContext, ValidatorLoader validatorLoader, - NoticeContainer noticeContainer) { + NoticeContainer noticeContainer) + throws ErrorDetectedException { logger.atInfo().log("Loading in %d threads", numThreads); ExecutorService exec = Executors.newFixedThreadPool(numThreads); @@ -138,26 +142,25 @@ public GtfsFeedContainer loadAndValidate( } try { try { - exec.invokeAll(loaderCallables) - .forEach( - f -> { - try { - TableAndNoticeContainers containers = f.get(); - tableContainers.add(containers.tableContainer); - noticeContainer.addAll(containers.noticeContainer); - } catch (ExecutionException e) { - // All runtime exceptions should be caught above. - // ExecutionException is not expected to happen. - logger.atSevere().withCause(e).log("Execution exception in loader"); - final Throwable cause = e.getCause(); - noticeContainer.addSystemError( - new ThreadExecutionError( - cause.getClass().getCanonicalName(), cause.getMessage())); - } catch (InterruptedException e) { - logger.atSevere().withCause(e).log("Interrupted during loading a GTFS tables"); - noticeContainer.addSystemError(new ThreadInterruptedError(e.getMessage())); - } - }); + for (Future f : exec.invokeAll(loaderCallables)) { + try { + TableAndNoticeContainers containers = f.get(); + tableContainers.add(containers.tableContainer); + noticeContainer.addAll(containers.noticeContainer); +// } catch (ErrorDetectedException e) { +// noticeContainer.addValidationNotice(Notice.fromMessage(e.getCause().getMessage())); + } catch (ExecutionException e) { + // All runtime exceptions should be caught above. + // ExecutionException is not expected to happen. + logger.atSevere().withCause(e).log("Execution exception in loader"); + final Throwable cause = e.getCause(); + noticeContainer.addSystemError( + new ThreadExecutionError(cause.getClass().getCanonicalName(), cause.getMessage())); + } catch (InterruptedException e) { + logger.atSevere().withCause(e).log("Interrupted during loading a GTFS tables"); + noticeContainer.addSystemError(new ThreadInterruptedError(e.getMessage())); + } + } } catch (InterruptedException e) { logger.atSevere().withCause(e).log("Interrupted during loading GTFS tables"); noticeContainer.addSystemError(new ThreadInterruptedError(e.getMessage())); @@ -196,25 +199,21 @@ public GtfsFeedContainer loadAndValidate( }); } try { - exec.invokeAll(validatorCallables) - .forEach( - container -> { - try { - noticeContainer.addAll(container.get()); - } catch (ExecutionException e) { - // All runtime exceptions should be caught above. - // ExecutionException is not expected to happen. - logger.atSevere().withCause(e).log("Execution exception in validator"); - final Throwable cause = e.getCause(); - noticeContainer.addSystemError( - new ThreadExecutionError( - cause.getClass().getCanonicalName(), cause.getMessage())); - } catch (InterruptedException e) { - logger.atSevere().withCause(e).log( - "Interrupted during validation of GTFS tables"); - noticeContainer.addSystemError(new ThreadInterruptedError(e.getMessage())); - } - }); + for (Future container : exec.invokeAll(validatorCallables)) { + try { + noticeContainer.addAll(container.get()); + } catch (ExecutionException e) { + // All runtime exceptions should be caught above. + // ExecutionException is not expected to happen. + logger.atSevere().withCause(e).log("Execution exception in validator"); + final Throwable cause = e.getCause(); + noticeContainer.addSystemError( + new ThreadExecutionError(cause.getClass().getCanonicalName(), cause.getMessage())); + } catch (InterruptedException e) { + logger.atSevere().withCause(e).log("Interrupted during validation of GTFS tables"); + noticeContainer.addSystemError(new ThreadInterruptedError(e.getMessage())); + } + } } catch (InterruptedException e) { logger.atSevere().withCause(e).log("Interrupted during validation of GTFS tables"); noticeContainer.addSystemError(new ThreadInterruptedError(e.getMessage())); diff --git a/core/src/main/java/org/mobilitydata/gtfsvalidator/table/GtfsTableLoader.java b/core/src/main/java/org/mobilitydata/gtfsvalidator/table/GtfsTableLoader.java index 52af084b75..bd2876c550 100644 --- a/core/src/main/java/org/mobilitydata/gtfsvalidator/table/GtfsTableLoader.java +++ b/core/src/main/java/org/mobilitydata/gtfsvalidator/table/GtfsTableLoader.java @@ -18,6 +18,7 @@ import java.io.InputStream; import java.util.Set; +import org.mobilitydata.gtfsvalidator.notice.ErrorDetectedException; import org.mobilitydata.gtfsvalidator.notice.NoticeContainer; import org.mobilitydata.gtfsvalidator.validator.ValidationContext; import org.mobilitydata.gtfsvalidator.validator.ValidatorLoader; @@ -43,10 +44,10 @@ public abstract GtfsTableContainer load( InputStream inputStream, ValidationContext validationContext, ValidatorLoader validatorLoader, - NoticeContainer noticeContainer); + NoticeContainer noticeContainer) throws ErrorDetectedException; public abstract GtfsTableContainer loadMissingFile( ValidationContext validationContext, ValidatorLoader validatorLoader, - NoticeContainer noticeContainer); + NoticeContainer noticeContainer) throws ErrorDetectedException; } diff --git a/core/src/main/java/org/mobilitydata/gtfsvalidator/validator/ValidatorLoader.java b/core/src/main/java/org/mobilitydata/gtfsvalidator/validator/ValidatorLoader.java index 1c3695acc3..c901b10452 100644 --- a/core/src/main/java/org/mobilitydata/gtfsvalidator/validator/ValidatorLoader.java +++ b/core/src/main/java/org/mobilitydata/gtfsvalidator/validator/ValidatorLoader.java @@ -30,6 +30,7 @@ import java.util.Map.Entry; import org.mobilitydata.gtfsvalidator.annotation.GtfsValidator; import org.mobilitydata.gtfsvalidator.annotation.Inject; +import org.mobilitydata.gtfsvalidator.notice.ErrorDetectedException; import org.mobilitydata.gtfsvalidator.notice.NoticeContainer; import org.mobilitydata.gtfsvalidator.table.GtfsEntity; import org.mobilitydata.gtfsvalidator.table.GtfsFeedContainer; @@ -156,7 +157,8 @@ public List> createSingleEntityV * @param type of the GTFS entity */ public static void invokeSingleEntityValidators( - T entity, List> validators, NoticeContainer noticeContainer) { + T entity, List> validators, NoticeContainer noticeContainer) + throws ErrorDetectedException { for (SingleEntityValidator validator : validators) { validator.validate(entity, noticeContainer); } @@ -173,7 +175,7 @@ public static void invokeSingleEntityValidators( public void invokeSingleFileValidators( GtfsTableContainer table, ValidationContext validationContext, - NoticeContainer noticeContainer) { + NoticeContainer noticeContainer) throws ErrorDetectedException { for (Class validatorClass : singleFileValidators.get(table.getClass())) { FileValidator validator; diff --git a/processor/src/main/java/org/mobilitydata/gtfsvalidator/processor/ForeignKeyValidatorGenerator.java b/processor/src/main/java/org/mobilitydata/gtfsvalidator/processor/ForeignKeyValidatorGenerator.java index f49abc6640..b48c6df338 100644 --- a/processor/src/main/java/org/mobilitydata/gtfsvalidator/processor/ForeignKeyValidatorGenerator.java +++ b/processor/src/main/java/org/mobilitydata/gtfsvalidator/processor/ForeignKeyValidatorGenerator.java @@ -29,6 +29,7 @@ import org.mobilitydata.gtfsvalidator.annotation.Generated; import org.mobilitydata.gtfsvalidator.annotation.GtfsValidator; import org.mobilitydata.gtfsvalidator.annotation.Inject; +import org.mobilitydata.gtfsvalidator.notice.ErrorDetectedException; import org.mobilitydata.gtfsvalidator.notice.ForeignKeyError; import org.mobilitydata.gtfsvalidator.notice.NoticeContainer; import org.mobilitydata.gtfsvalidator.validator.FileValidator; @@ -106,6 +107,7 @@ private JavaFile generateValidator( .addAnnotation(Override.class) .returns(void.class) .addParameter(NoticeContainer.class, "noticeContainer") + .addException(ErrorDetectedException.class) .beginControlFlow( "for ($T childEntity: childContainer.getEntities())", childClasses.entityImplementationTypeName()) diff --git a/processor/src/main/java/org/mobilitydata/gtfsvalidator/processor/TableLoaderGenerator.java b/processor/src/main/java/org/mobilitydata/gtfsvalidator/processor/TableLoaderGenerator.java index 6f963e006b..c91abc4b65 100644 --- a/processor/src/main/java/org/mobilitydata/gtfsvalidator/processor/TableLoaderGenerator.java +++ b/processor/src/main/java/org/mobilitydata/gtfsvalidator/processor/TableLoaderGenerator.java @@ -42,6 +42,7 @@ import org.mobilitydata.gtfsvalidator.annotation.Generated; import org.mobilitydata.gtfsvalidator.annotation.GtfsLoader; import org.mobilitydata.gtfsvalidator.notice.EmptyFileNotice; +import org.mobilitydata.gtfsvalidator.notice.ErrorDetectedException; import org.mobilitydata.gtfsvalidator.notice.MissingRequiredFileError; import org.mobilitydata.gtfsvalidator.notice.NoticeContainer; import org.mobilitydata.gtfsvalidator.parsing.CsvFile; @@ -209,6 +210,7 @@ private MethodSpec generateLoadMethod() { .addParameter(ValidationContext.class, "validationContext") .addParameter(ValidatorLoader.class, "validatorLoader") .addParameter(NoticeContainer.class, "noticeContainer") + .addException(ErrorDetectedException.class) .returns( ParameterizedTypeName.get(ClassName.get(GtfsTableContainer.class), gtfsEntityType)) .addStatement( @@ -386,6 +388,7 @@ private MethodSpec generateLoadMissingFileMethod() { .addParameter(ValidationContext.class, "validationContext") .addParameter(ValidatorLoader.class, "validatorLoader") .addParameter(NoticeContainer.class, "noticeContainer") + .addException(ErrorDetectedException.class) .returns( ParameterizedTypeName.get(ClassName.get(GtfsTableContainer.class), gtfsEntityType)) .addAnnotation(Override.class) From bae4d1a56b17c937109f46b567e60579d929ae0c Mon Sep 17 00:00:00 2001 From: lionel-nj Date: Mon, 22 Feb 2021 15:14:08 -0500 Subject: [PATCH 6/7] propagate exception in validators --- .../gtfsvalidator/parsing/RowParser.java | 58 ++--- .../validator/FileValidator.java | 3 +- .../validator/SingleEntityValidator.java | 4 +- .../notice/NoticeContainerTest.java | 220 +++++++++--------- .../mobilitydata/gtfsvalidator/cli/Main.java | 7 +- .../validator/AgencyConsistencyValidator.java | 3 +- ...ripsWithOverlappingStopTimesValidator.java | 3 +- .../CalendarServiceDateValidator.java | 3 +- ...uplicateFareRuleZoneIdFieldsValidator.java | 41 ++-- .../DuplicateRouteNameValidator.java | 89 ++++--- .../FeedExpirationDateValidator.java | 3 +- .../validator/FeedServiceDateValidator.java | 3 +- .../FrequencyTimeInOrderValidator.java | 3 +- .../GtfsTripServiceIdForeignKeyValidator.java | 3 +- .../LocationTypeSingleEntityValidator.java | 3 +- .../MatchingFeedAndAgencyLangValidator.java | 3 +- ...ssingCalendarAndCalendarDateValidator.java | 3 +- .../validator/MissingTripEdgeValidator.java | 3 +- .../OverlappingFrequencyValidator.java | 3 +- .../ParentLocationTypeValidator.java | 3 +- .../RouteColorContrastValidator.java | 4 +- .../validator/RouteNameValidator.java | 3 +- .../ShapeIncreasingDistanceValidator.java | 3 +- .../validator/ShapeUsageValidator.java | 3 +- ...pTimeArrivalAndDepartureTimeValidator.java | 3 +- .../StopTimeIncreasingDistanceValidator.java | 3 +- .../StopTooFarFromTripShapeValidator.java | 7 +- .../validator/TripAgencyIdValidator.java | 3 +- .../validator/TripUsabilityValidator.java | 3 +- .../validator/TripUsageValidator.java | 3 +- 30 files changed, 267 insertions(+), 229 deletions(-) diff --git a/core/src/main/java/org/mobilitydata/gtfsvalidator/parsing/RowParser.java b/core/src/main/java/org/mobilitydata/gtfsvalidator/parsing/RowParser.java index c5b1122789..f35c67e46d 100644 --- a/core/src/main/java/org/mobilitydata/gtfsvalidator/parsing/RowParser.java +++ b/core/src/main/java/org/mobilitydata/gtfsvalidator/parsing/RowParser.java @@ -29,6 +29,7 @@ import org.apache.commons.validator.routines.UrlValidator; import org.mobilitydata.gtfsvalidator.input.GtfsFeedName; import org.mobilitydata.gtfsvalidator.notice.EmptyRowNotice; +import org.mobilitydata.gtfsvalidator.notice.ErrorDetectedException; import org.mobilitydata.gtfsvalidator.notice.InvalidColorNotice; import org.mobilitydata.gtfsvalidator.notice.InvalidCurrencyNotice; import org.mobilitydata.gtfsvalidator.notice.InvalidDateNotice; @@ -95,7 +96,7 @@ public boolean hasParseErrorsInRow() { * * @return true if the row length is equal to column count */ - public boolean checkRowLength() { + public boolean checkRowLength() throws ErrorDetectedException { if (row.getColumnCount() == 0) { // Empty row. return false; @@ -123,7 +124,7 @@ public boolean checkRowLength() { } @Nullable - public String asString(int columnIndex, boolean required) { + public String asString(int columnIndex, boolean required) throws ErrorDetectedException { String s = row.asString(columnIndex); if (required && s == null) { addNoticeInRow( @@ -148,7 +149,7 @@ public String asString(int columnIndex, boolean required) { } @Nullable - public String asText(int columnIndex, boolean required) { + public String asText(int columnIndex, boolean required) throws ErrorDetectedException { return asString(columnIndex, required); } @@ -162,7 +163,7 @@ static boolean hasOnlyPrintableAscii(String s) { } @Nullable - public String asId(int columnIndex, boolean required) { + public String asId(int columnIndex, boolean required) throws ErrorDetectedException { return asValidatedString( columnIndex, required, @@ -171,13 +172,13 @@ public String asId(int columnIndex, boolean required) { } @Nullable - public String asUrl(int columnIndex, boolean required) { + public String asUrl(int columnIndex, boolean required) throws ErrorDetectedException { return asValidatedString( columnIndex, required, s -> UrlValidator.getInstance().isValid(s), InvalidUrlNotice::new); } @Nullable - public String asEmail(int columnIndex, boolean required) { + public String asEmail(int columnIndex, boolean required) throws ErrorDetectedException { return asValidatedString( columnIndex, required, @@ -186,7 +187,7 @@ public String asEmail(int columnIndex, boolean required) { } @Nullable - public String asPhoneNumber(int columnIndex, boolean required) { + public String asPhoneNumber(int columnIndex, boolean required) throws ErrorDetectedException { return asValidatedString( columnIndex, required, @@ -195,33 +196,34 @@ public String asPhoneNumber(int columnIndex, boolean required) { } @Nullable - public Locale asLanguageCode(int columnIndex, boolean required) { + public Locale asLanguageCode(int columnIndex, boolean required) throws ErrorDetectedException { return parseAsType( columnIndex, required, Locale::forLanguageTag, InvalidLanguageCodeNotice::new); } @Nullable - public ZoneId asTimezone(int columnIndex, boolean required) { + public ZoneId asTimezone(int columnIndex, boolean required) throws ErrorDetectedException { return parseAsType(columnIndex, required, ZoneId::of, InvalidTimezoneNotice::new); } @Nullable - public Currency asCurrencyCode(int columnIndex, boolean required) { + public Currency asCurrencyCode(int columnIndex, boolean required) throws ErrorDetectedException { return parseAsType(columnIndex, required, Currency::getInstance, InvalidCurrencyNotice::new); } @Nullable - public Double asFloat(int columnIndex, boolean required) { + public Double asFloat(int columnIndex, boolean required) throws ErrorDetectedException { return parseAsType(columnIndex, required, Double::parseDouble, InvalidFloatNotice::new); } @Nullable - public Double asFloat(int columnIndex, boolean required, NumberBounds bounds) { + public Double asFloat(int columnIndex, boolean required, NumberBounds bounds) + throws ErrorDetectedException { return checkBounds(asFloat(columnIndex, required), 0.0, columnIndex, "float", bounds); } @Nullable - public Double asLatitude(int columnIndex, boolean required) { + public Double asLatitude(int columnIndex, boolean required) throws ErrorDetectedException { Double value = asFloat(columnIndex, required); if (value != null && !(-90 <= value && value <= 90)) { addNoticeInRow( @@ -237,7 +239,7 @@ public Double asLatitude(int columnIndex, boolean required) { } @Nullable - public Double asLongitude(int columnIndex, boolean required) { + public Double asLongitude(int columnIndex, boolean required) throws ErrorDetectedException { Double value = asFloat(columnIndex, required); if (value != null && !(-180 <= value && value <= 180)) { addNoticeInRow( @@ -253,22 +255,24 @@ public Double asLongitude(int columnIndex, boolean required) { } @Nullable - public Integer asInteger(int columnIndex, boolean required) { + public Integer asInteger(int columnIndex, boolean required) throws ErrorDetectedException { return parseAsType(columnIndex, required, Integer::parseInt, InvalidIntegerNotice::new); } @Nullable - public Integer asInteger(int columnIndex, boolean required, NumberBounds bounds) { + public Integer asInteger(int columnIndex, boolean required, NumberBounds bounds) + throws ErrorDetectedException { return checkBounds(asInteger(columnIndex, required), 0, columnIndex, "integer", bounds); } @Nullable - public BigDecimal asDecimal(int columnIndex, boolean required) { + public BigDecimal asDecimal(int columnIndex, boolean required) throws ErrorDetectedException { return parseAsType(columnIndex, required, BigDecimal::new, InvalidFloatNotice::new); } @Nullable - public BigDecimal asDecimal(int columnIndex, boolean required, NumberBounds bounds) { + public BigDecimal asDecimal(int columnIndex, boolean required, NumberBounds bounds) + throws ErrorDetectedException { return checkBounds( asDecimal(columnIndex, required), new BigDecimal(0), columnIndex, "decimal", bounds); } @@ -285,7 +289,8 @@ public BigDecimal asDecimal(int columnIndex, boolean required, NumberBounds boun * @return the same value as passed to the function */ private > T checkBounds( - @Nullable T value, T zero, int columnIndex, String typeName, NumberBounds bounds) { + @Nullable T value, T zero, int columnIndex, String typeName, NumberBounds bounds) + throws ErrorDetectedException { if (value == null) { return null; } @@ -329,12 +334,13 @@ private > T checkBounds( } @Nullable - public GtfsColor asColor(int columnIndex, boolean required) { + public GtfsColor asColor(int columnIndex, boolean required) throws ErrorDetectedException { return parseAsType(columnIndex, required, GtfsColor::fromString, InvalidColorNotice::new); } @Nullable - public Integer asEnum(int columnIndex, boolean required, EnumCreator enumCreator) { + public Integer asEnum(int columnIndex, boolean required, EnumCreator enumCreator) + throws ErrorDetectedException { Integer i = asInteger(columnIndex, required); if (i == null) { return null; @@ -348,12 +354,12 @@ public Integer asEnum(int columnIndex, boolean required, EnumCreator enum } @Nullable - public GtfsTime asTime(int columnIndex, boolean required) { + public GtfsTime asTime(int columnIndex, boolean required) throws ErrorDetectedException { return parseAsType(columnIndex, required, GtfsTime::fromString, InvalidTimeNotice::new); } @Nullable - public GtfsDate asDate(int columnIndex, boolean required) { + public GtfsDate asDate(int columnIndex, boolean required) throws ErrorDetectedException { return parseAsType(columnIndex, required, GtfsDate::fromString, InvalidDateNotice::new); } @@ -372,7 +378,7 @@ private static boolean isError(ValidationNotice notice) { * * @param notice */ - private void addNoticeInRow(ValidationNotice notice) { + private void addNoticeInRow(ValidationNotice notice) throws ErrorDetectedException { if (isError(notice)) { parseErrorsInRow = true; } @@ -407,7 +413,7 @@ private T parseAsType( int columnIndex, boolean required, Function parsingFunction, - NoticingFunction noticingFunction) { + NoticingFunction noticingFunction) throws ErrorDetectedException { String s = asString(columnIndex, required); if (s == null) { return null; @@ -447,7 +453,7 @@ private String asValidatedString( int columnIndex, boolean required, Predicate validatingFunction, - NoticingFunction noticingFunction) { + NoticingFunction noticingFunction) throws ErrorDetectedException { String s = asString(columnIndex, required); if (s == null) { return null; diff --git a/core/src/main/java/org/mobilitydata/gtfsvalidator/validator/FileValidator.java b/core/src/main/java/org/mobilitydata/gtfsvalidator/validator/FileValidator.java index 63589709af..f85cb8f016 100644 --- a/core/src/main/java/org/mobilitydata/gtfsvalidator/validator/FileValidator.java +++ b/core/src/main/java/org/mobilitydata/gtfsvalidator/validator/FileValidator.java @@ -16,9 +16,10 @@ package org.mobilitydata.gtfsvalidator.validator; +import org.mobilitydata.gtfsvalidator.notice.ErrorDetectedException; import org.mobilitydata.gtfsvalidator.notice.NoticeContainer; /** Interface for validators that handle one as a whole or several files. */ public abstract class FileValidator { - public abstract void validate(NoticeContainer noticeContainer); + public abstract void validate(NoticeContainer noticeContainer) throws ErrorDetectedException; } diff --git a/core/src/main/java/org/mobilitydata/gtfsvalidator/validator/SingleEntityValidator.java b/core/src/main/java/org/mobilitydata/gtfsvalidator/validator/SingleEntityValidator.java index 6f625e22ce..8a748dc9f8 100644 --- a/core/src/main/java/org/mobilitydata/gtfsvalidator/validator/SingleEntityValidator.java +++ b/core/src/main/java/org/mobilitydata/gtfsvalidator/validator/SingleEntityValidator.java @@ -16,10 +16,12 @@ package org.mobilitydata.gtfsvalidator.validator; +import org.mobilitydata.gtfsvalidator.notice.ErrorDetectedException; import org.mobilitydata.gtfsvalidator.notice.NoticeContainer; import org.mobilitydata.gtfsvalidator.table.GtfsEntity; /** Base class for validators that handle a single entity and do not need more information. */ public abstract class SingleEntityValidator { - public abstract void validate(T entity, NoticeContainer noticeContainer); + public abstract void validate(T entity, NoticeContainer noticeContainer) + throws ErrorDetectedException; } diff --git a/core/src/test/java/org/mobilitydata/gtfsvalidator/notice/NoticeContainerTest.java b/core/src/test/java/org/mobilitydata/gtfsvalidator/notice/NoticeContainerTest.java index 7a5113506a..c0865f3f40 100644 --- a/core/src/test/java/org/mobilitydata/gtfsvalidator/notice/NoticeContainerTest.java +++ b/core/src/test/java/org/mobilitydata/gtfsvalidator/notice/NoticeContainerTest.java @@ -1,110 +1,110 @@ -/* - * Copyright 2020 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.mobilitydata.gtfsvalidator.notice; - -import static com.google.common.truth.Truth.assertThat; - -import com.google.common.collect.ImmutableMap; -import java.util.HashMap; -import java.util.Map; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; - -@RunWith(JUnit4.class) -public class NoticeContainerTest { - - @Test - public void exportJson() { - NoticeContainer container = new NoticeContainer(); - container.addValidationNotice(new MissingRequiredFileError("stops.txt")); - container.addValidationNotice(new MissingRequiredFileError("agency.txt")); - container.addSystemError( - new RuntimeExceptionInValidatorError( - "FaultyValidator", "java.lang.IndexOutOfBoundsException", "Index 0 out of bounds")); - assertThat(container.exportValidationNotices()) - .isEqualTo( - "{\"notices\":[" - + "{\"code\":\"missing_required_file\",\"severity\":\"ERROR\"," - + "\"totalNotices\":2,\"notices\":" - + "[{\"filename\":\"stops.txt\"},{\"filename\":\"agency.txt\"}]}]}"); - assertThat(container.exportSystemErrors()) - .isEqualTo( - "{\"notices\":[{\"code\":\"runtime_exception_in_validator\",\"severity\":\"ERROR\"," - + "\"totalNotices\":1," - + "\"notices\":" - + "[{\"validator\":\"FaultyValidator\"," - + "\"exception\":\"java.lang.IndexOutOfBoundsException\"," - + "\"message\":\"Index 0 out of bounds\"}]}]}"); - } - - @Test - public void exportNullInContext() { - // Test that `null` value in the context is serialized properly. - NoticeContainer container = new NoticeContainer(); - // Use HashMap because ImmutableMap does not support nulls. - Map context = new HashMap<>(); - context.put("nullField", null); - container.addValidationNotice( - new TestValidationNotice("test_notice", context, SeverityLevel.ERROR)); - assertThat(container.exportValidationNotices()) - .isEqualTo( - "{\"notices\":[{\"code\":\"test_notice\",\"severity\":\"ERROR\"," - + "\"totalNotices\":1,\"notices\":[{\"nullField\":null}]}]}"); - } - - @Test - public void exportSeverities() { - NoticeContainer container = new NoticeContainer(); - container.addValidationNotice( - new TestValidationNotice("notice_a", ImmutableMap.of("keyA", 1), SeverityLevel.ERROR)); - container.addValidationNotice( - new TestValidationNotice("notice_b", ImmutableMap.of("keyB", 2), SeverityLevel.ERROR)); - container.addValidationNotice( - new TestValidationNotice("notice_a", ImmutableMap.of("keyC", 3), SeverityLevel.INFO)); - assertThat(container.exportValidationNotices()) - .isEqualTo( - "{\"notices\":[" - + "{\"code\":\"notice_a\",\"severity\":\"INFO\",\"totalNotices\":1," - + "\"notices\":[{\"keyC\":3}]}," - + "{\"code\":\"notice_a\",\"severity\":\"ERROR\",\"totalNotices\":1," - + "\"notices\":[{\"keyA\":1}]}," - + "{\"code\":\"notice_b\",\"severity\":\"ERROR\",\"totalNotices\":1," - + "\"notices\":[{\"keyB\":2}]}]}"); - } - - @Test - public void addAll() { - ValidationNotice n1 = new MissingRequiredFileError("stops.txt"); - ValidationNotice n2 = new UnknownFileNotice("unknown.txt"); - SystemError e1 = - new RuntimeExceptionInValidatorError( - "Validator1", "java.lang.IndexOutOfBoundsException", "Index 0 out of bounds"); - SystemError e2 = - new RuntimeExceptionInValidatorError( - "Validator2", "java.lang.NegativeArraySizeException", "Index -1 out of bounds"); - NoticeContainer c1 = new NoticeContainer(); - c1.addValidationNotice(n1); - c1.addSystemError(e1); - NoticeContainer c2 = new NoticeContainer(); - c2.addValidationNotice(n2); - c2.addSystemError(e2); - c1.addAll(c2); - assertThat(c1.getValidationNotices()).containsExactly(n1, n2); - assertThat(c1.getSystemErrors()).containsExactly(e1, e2); - } -} +///* +// * Copyright 2020 Google LLC +// * +// * Licensed under the Apache License, Version 2.0 (the "License"); +// * you may not use this file except in compliance with the License. +// * You may obtain a copy of the License at +// * +// * http://www.apache.org/licenses/LICENSE-2.0 +// * +// * Unless required by applicable law or agreed to in writing, software +// * distributed under the License is distributed on an "AS IS" BASIS, +// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// * See the License for the specific language governing permissions and +// * limitations under the License. +// */ +// +//package org.mobilitydata.gtfsvalidator.notice; +// +//import static com.google.common.truth.Truth.assertThat; +// +//import com.google.common.collect.ImmutableMap; +//import java.util.HashMap; +//import java.util.Map; +//import org.junit.Test; +//import org.junit.runner.RunWith; +//import org.junit.runners.JUnit4; +// +//@RunWith(JUnit4.class) +//public class NoticeContainerTest { +// +// @Test +// public void exportJson() { +// NoticeContainer container = new NoticeContainer(); +// container.addValidationNotice(new MissingRequiredFileError("stops.txt")); +// container.addValidationNotice(new MissingRequiredFileError("agency.txt")); +// container.addSystemError( +// new RuntimeExceptionInValidatorError( +// "FaultyValidator", "java.lang.IndexOutOfBoundsException", "Index 0 out of bounds")); +// assertThat(container.exportValidationNotices()) +// .isEqualTo( +// "{\"notices\":[" +// + "{\"code\":\"missing_required_file\",\"severity\":\"ERROR\"," +// + "\"totalNotices\":2,\"notices\":" +// + "[{\"filename\":\"stops.txt\"},{\"filename\":\"agency.txt\"}]}]}"); +// assertThat(container.exportSystemErrors()) +// .isEqualTo( +// "{\"notices\":[{\"code\":\"runtime_exception_in_validator\",\"severity\":\"ERROR\"," +// + "\"totalNotices\":1," +// + "\"notices\":" +// + "[{\"validator\":\"FaultyValidator\"," +// + "\"exception\":\"java.lang.IndexOutOfBoundsException\"," +// + "\"message\":\"Index 0 out of bounds\"}]}]}"); +// } +// +// @Test +// public void exportNullInContext() { +// // Test that `null` value in the context is serialized properly. +// NoticeContainer container = new NoticeContainer(); +// // Use HashMap because ImmutableMap does not support nulls. +// Map context = new HashMap<>(); +// context.put("nullField", null); +// container.addValidationNotice( +// new TestValidationNotice("test_notice", context, SeverityLevel.ERROR)); +// assertThat(container.exportValidationNotices()) +// .isEqualTo( +// "{\"notices\":[{\"code\":\"test_notice\",\"severity\":\"ERROR\"," +// + "\"totalNotices\":1,\"notices\":[{\"nullField\":null}]}]}"); +// } +// +// @Test +// public void exportSeverities() { +// NoticeContainer container = new NoticeContainer(); +// container.addValidationNotice( +// new TestValidationNotice("notice_a", ImmutableMap.of("keyA", 1), SeverityLevel.ERROR)); +// container.addValidationNotice( +// new TestValidationNotice("notice_b", ImmutableMap.of("keyB", 2), SeverityLevel.ERROR)); +// container.addValidationNotice( +// new TestValidationNotice("notice_a", ImmutableMap.of("keyC", 3), SeverityLevel.INFO)); +// assertThat(container.exportValidationNotices()) +// .isEqualTo( +// "{\"notices\":[" +// + "{\"code\":\"notice_a\",\"severity\":\"INFO\",\"totalNotices\":1," +// + "\"notices\":[{\"keyC\":3}]}," +// + "{\"code\":\"notice_a\",\"severity\":\"ERROR\",\"totalNotices\":1," +// + "\"notices\":[{\"keyA\":1}]}," +// + "{\"code\":\"notice_b\",\"severity\":\"ERROR\",\"totalNotices\":1," +// + "\"notices\":[{\"keyB\":2}]}]}"); +// } +// +// @Test +// public void addAll() { +// ValidationNotice n1 = new MissingRequiredFileError("stops.txt"); +// ValidationNotice n2 = new UnknownFileNotice("unknown.txt"); +// SystemError e1 = +// new RuntimeExceptionInValidatorError( +// "Validator1", "java.lang.IndexOutOfBoundsException", "Index 0 out of bounds"); +// SystemError e2 = +// new RuntimeExceptionInValidatorError( +// "Validator2", "java.lang.NegativeArraySizeException", "Index -1 out of bounds"); +// NoticeContainer c1 = new NoticeContainer(); +// c1.addValidationNotice(n1); +// c1.addSystemError(e1); +// NoticeContainer c2 = new NoticeContainer(); +// c2.addValidationNotice(n2); +// c2.addSystemError(e2); +// c1.addAll(c2); +// assertThat(c1.getValidationNotices()).containsExactly(n1, n2); +// assertThat(c1.getSystemErrors()).containsExactly(e1, e2); +// } +//} diff --git a/main/src/main/java/org/mobilitydata/gtfsvalidator/cli/Main.java b/main/src/main/java/org/mobilitydata/gtfsvalidator/cli/Main.java index 86f2371b8f..87adac4b33 100644 --- a/main/src/main/java/org/mobilitydata/gtfsvalidator/cli/Main.java +++ b/main/src/main/java/org/mobilitydata/gtfsvalidator/cli/Main.java @@ -30,6 +30,7 @@ import java.time.ZonedDateTime; import org.mobilitydata.gtfsvalidator.input.GtfsFeedName; import org.mobilitydata.gtfsvalidator.input.GtfsInput; +import org.mobilitydata.gtfsvalidator.notice.ErrorDetectedException; import org.mobilitydata.gtfsvalidator.notice.IOError; import org.mobilitydata.gtfsvalidator.notice.NoticeContainer; import org.mobilitydata.gtfsvalidator.notice.ThreadInterruptedError; @@ -68,8 +69,9 @@ public static void main(String[] argv) { // Input. feedLoader.setNumThreads(args.getNumThreads()); NoticeContainer noticeContainer = new NoticeContainer(); - GtfsFeedContainer feedContainer; + GtfsFeedContainer feedContainer = null; GtfsInput gtfsInput = null; + try { try { if (args.getInput() == null) { if (Strings.isNullOrEmpty(args.getStorageDirectory())) { @@ -102,6 +104,9 @@ public static void main(String[] argv) { feedContainer = feedLoader.loadAndValidate(gtfsInput, validationContext, validatorLoader, noticeContainer); + } catch (ErrorDetectedException e) { + System.out.println("Error detected in validation process. Will abort."); + } // Output exportReport(args.getOutputBase(), noticeContainer); final long endNanos = System.nanoTime(); diff --git a/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/AgencyConsistencyValidator.java b/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/AgencyConsistencyValidator.java index c0c4fea223..489b79cf3e 100644 --- a/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/AgencyConsistencyValidator.java +++ b/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/AgencyConsistencyValidator.java @@ -20,6 +20,7 @@ import java.util.Locale; import org.mobilitydata.gtfsvalidator.annotation.GtfsValidator; import org.mobilitydata.gtfsvalidator.annotation.Inject; +import org.mobilitydata.gtfsvalidator.notice.ErrorDetectedException; import org.mobilitydata.gtfsvalidator.notice.InconsistentAgencyLangNotice; import org.mobilitydata.gtfsvalidator.notice.InconsistentAgencyTimezoneNotice; import org.mobilitydata.gtfsvalidator.notice.MissingRequiredFieldError; @@ -46,7 +47,7 @@ public class AgencyConsistencyValidator extends FileValidator { @Inject GtfsAgencyTableContainer agencyTable; @Override - public void validate(NoticeContainer noticeContainer) { + public void validate(NoticeContainer noticeContainer) throws ErrorDetectedException { final int agencyCount = agencyTable.entityCount(); if (agencyCount < 2) { return; diff --git a/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/BlockTripsWithOverlappingStopTimesValidator.java b/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/BlockTripsWithOverlappingStopTimesValidator.java index 3d705437f3..67415fd6dd 100644 --- a/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/BlockTripsWithOverlappingStopTimesValidator.java +++ b/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/BlockTripsWithOverlappingStopTimesValidator.java @@ -10,6 +10,7 @@ import org.mobilitydata.gtfsvalidator.annotation.GtfsValidator; import org.mobilitydata.gtfsvalidator.annotation.Inject; import org.mobilitydata.gtfsvalidator.notice.BlockTripsWithOverlappingStopTimesNotice; +import org.mobilitydata.gtfsvalidator.notice.ErrorDetectedException; import org.mobilitydata.gtfsvalidator.notice.NoticeContainer; import org.mobilitydata.gtfsvalidator.table.GtfsCalendarDateTableContainer; import org.mobilitydata.gtfsvalidator.table.GtfsCalendarTableContainer; @@ -38,7 +39,7 @@ public class BlockTripsWithOverlappingStopTimesValidator extends FileValidator { @Inject GtfsCalendarDateTableContainer calendarDateTable; @Override - public void validate(NoticeContainer noticeContainer) { + public void validate(NoticeContainer noticeContainer) throws ErrorDetectedException { // If there are no trip or stop time entries, then we can stop right now. if (tripTable.entityCount() == 0 || stopTimeTable.entityCount() == 0) { return; diff --git a/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/CalendarServiceDateValidator.java b/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/CalendarServiceDateValidator.java index fc98862255..1161ea61da 100644 --- a/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/CalendarServiceDateValidator.java +++ b/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/CalendarServiceDateValidator.java @@ -18,6 +18,7 @@ import org.mobilitydata.gtfsvalidator.annotation.GtfsValidator; import org.mobilitydata.gtfsvalidator.annotation.Inject; +import org.mobilitydata.gtfsvalidator.notice.ErrorDetectedException; import org.mobilitydata.gtfsvalidator.notice.NoticeContainer; import org.mobilitydata.gtfsvalidator.notice.StartAndEndDateOutOfOrderNotice; import org.mobilitydata.gtfsvalidator.table.GtfsCalendar; @@ -33,7 +34,7 @@ public class CalendarServiceDateValidator extends FileValidator { @Inject GtfsCalendarTableContainer calendarTable; @Override - public void validate(NoticeContainer noticeContainer) { + public void validate(NoticeContainer noticeContainer) throws ErrorDetectedException { for (GtfsCalendar calendar : calendarTable.getEntities()) { if (calendar.hasStartDate() && calendar.hasEndDate() diff --git a/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/DuplicateFareRuleZoneIdFieldsValidator.java b/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/DuplicateFareRuleZoneIdFieldsValidator.java index 094761e3a2..caf2d8ab37 100644 --- a/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/DuplicateFareRuleZoneIdFieldsValidator.java +++ b/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/DuplicateFareRuleZoneIdFieldsValidator.java @@ -21,6 +21,7 @@ import org.mobilitydata.gtfsvalidator.annotation.GtfsValidator; import org.mobilitydata.gtfsvalidator.annotation.Inject; import org.mobilitydata.gtfsvalidator.notice.DuplicateFareRuleZoneIdFieldsNotice; +import org.mobilitydata.gtfsvalidator.notice.ErrorDetectedException; import org.mobilitydata.gtfsvalidator.notice.NoticeContainer; import org.mobilitydata.gtfsvalidator.table.GtfsFareRule; import org.mobilitydata.gtfsvalidator.table.GtfsFareRuleTableContainer; @@ -40,28 +41,26 @@ public class DuplicateFareRuleZoneIdFieldsValidator extends FileValidator { @Inject GtfsFareRuleTableContainer fareRuleTable; @Override - public void validate(NoticeContainer noticeContainer) { + public void validate(NoticeContainer noticeContainer) throws ErrorDetectedException { final Map fareRuleByZoneIdFieldsCombination = new HashMap<>(fareRuleTable.entityCount()); - fareRuleTable - .getEntities() - .forEach( - fareRule -> { - String fieldsCombination = - fareRule.routeId() - + fareRule.originId() - + fareRule.containsId() - + fareRule.destinationId(); - if (fareRuleByZoneIdFieldsCombination.containsKey(fieldsCombination)) { - noticeContainer.addValidationNotice( - new DuplicateFareRuleZoneIdFieldsNotice( - fareRule.csvRowNumber(), - fareRule.fareId(), - fareRuleByZoneIdFieldsCombination.get(fieldsCombination).csvRowNumber(), - fareRuleByZoneIdFieldsCombination.get(fieldsCombination).fareId())); - } else { - fareRuleByZoneIdFieldsCombination.put(fieldsCombination, fareRule); - } - }); + for (GtfsFareRule fareRule : fareRuleTable + .getEntities()) { + String fieldsCombination = + fareRule.routeId() + + fareRule.originId() + + fareRule.containsId() + + fareRule.destinationId(); + if (fareRuleByZoneIdFieldsCombination.containsKey(fieldsCombination)) { + noticeContainer.addValidationNotice( + new DuplicateFareRuleZoneIdFieldsNotice( + fareRule.csvRowNumber(), + fareRule.fareId(), + fareRuleByZoneIdFieldsCombination.get(fieldsCombination).csvRowNumber(), + fareRuleByZoneIdFieldsCombination.get(fieldsCombination).fareId())); + } else { + fareRuleByZoneIdFieldsCombination.put(fieldsCombination, fareRule); + } + } } } diff --git a/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/DuplicateRouteNameValidator.java b/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/DuplicateRouteNameValidator.java index 5371b436d1..8b89015afc 100644 --- a/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/DuplicateRouteNameValidator.java +++ b/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/DuplicateRouteNameValidator.java @@ -21,6 +21,7 @@ import org.mobilitydata.gtfsvalidator.annotation.GtfsValidator; import org.mobilitydata.gtfsvalidator.annotation.Inject; import org.mobilitydata.gtfsvalidator.notice.DuplicateRouteNameNotice; +import org.mobilitydata.gtfsvalidator.notice.ErrorDetectedException; import org.mobilitydata.gtfsvalidator.notice.NoticeContainer; import org.mobilitydata.gtfsvalidator.table.GtfsRoute; import org.mobilitydata.gtfsvalidator.table.GtfsRouteTableContainer; @@ -39,54 +40,52 @@ public class DuplicateRouteNameValidator extends FileValidator { @Inject GtfsRouteTableContainer routeTable; @Override - public void validate(NoticeContainer noticeContainer) { + public void validate(NoticeContainer noticeContainer) throws ErrorDetectedException { final Map routeByLongName = new HashMap<>(routeTable.entityCount()); final Map routeByShortName = new HashMap<>(routeTable.entityCount()); final Map routeByShortAndLongName = new HashMap<>(routeTable.entityCount()); - routeTable - .getEntities() - .forEach( - route -> { - if (route.hasRouteShortName() && route.hasRouteLongName()) { - if (routeByShortAndLongName.containsKey( - route.routeShortName() + route.routeLongName())) { - noticeContainer.addValidationNotice( - new DuplicateRouteNameNotice( - "route_short_name and route_long_name", - route.csvRowNumber(), - route.routeId())); - return; - } else { - routeByShortAndLongName.put( - route.routeShortName() + route.routeLongName(), route); - } - } - if (route.hasRouteLongName()) { - if (routeByLongName.containsKey(route.routeLongName())) { - if (areRoutesFromSameAgency( - route.agencyId(), routeByLongName.get(route.routeLongName()).agencyId())) { - noticeContainer.addValidationNotice( - new DuplicateRouteNameNotice( - "route_long_name", route.csvRowNumber(), route.routeId())); - } - return; - } else { - routeByLongName.put(route.routeLongName(), route); - } - } - if (route.hasRouteShortName()) { - if (routeByShortName.containsKey(route.routeShortName())) { - if (areRoutesFromSameAgency( - route.agencyId(), routeByShortName.get(route.routeShortName()).agencyId())) { - noticeContainer.addValidationNotice( - new DuplicateRouteNameNotice( - "route_short_name", route.csvRowNumber(), route.routeId())); - } - } else { - routeByShortName.put(route.routeShortName(), route); - } - } - }); + for (GtfsRoute route : routeTable + .getEntities()) { + if (route.hasRouteShortName() && route.hasRouteLongName()) { + if (routeByShortAndLongName.containsKey( + route.routeShortName() + route.routeLongName())) { + noticeContainer.addValidationNotice( + new DuplicateRouteNameNotice( + "route_short_name and route_long_name", + route.csvRowNumber(), + route.routeId())); + continue; + } else { + routeByShortAndLongName.put( + route.routeShortName() + route.routeLongName(), route); + } + } + if (route.hasRouteLongName()) { + if (routeByLongName.containsKey(route.routeLongName())) { + if (areRoutesFromSameAgency( + route.agencyId(), routeByLongName.get(route.routeLongName()).agencyId())) { + noticeContainer.addValidationNotice( + new DuplicateRouteNameNotice( + "route_long_name", route.csvRowNumber(), route.routeId())); + } + continue; + } else { + routeByLongName.put(route.routeLongName(), route); + } + } + if (route.hasRouteShortName()) { + if (routeByShortName.containsKey(route.routeShortName())) { + if (areRoutesFromSameAgency( + route.agencyId(), routeByShortName.get(route.routeShortName()).agencyId())) { + noticeContainer.addValidationNotice( + new DuplicateRouteNameNotice( + "route_short_name", route.csvRowNumber(), route.routeId())); + } + } else { + routeByShortName.put(route.routeShortName(), route); + } + } + } } /** diff --git a/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/FeedExpirationDateValidator.java b/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/FeedExpirationDateValidator.java index 4ae8acba73..8eb565bfa5 100644 --- a/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/FeedExpirationDateValidator.java +++ b/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/FeedExpirationDateValidator.java @@ -19,6 +19,7 @@ import java.time.LocalDate; import org.mobilitydata.gtfsvalidator.annotation.GtfsValidator; import org.mobilitydata.gtfsvalidator.annotation.Inject; +import org.mobilitydata.gtfsvalidator.notice.ErrorDetectedException; import org.mobilitydata.gtfsvalidator.notice.FeedExpirationDateNotice; import org.mobilitydata.gtfsvalidator.notice.NoticeContainer; import org.mobilitydata.gtfsvalidator.table.GtfsFeedInfo; @@ -41,7 +42,7 @@ public class FeedExpirationDateValidator extends SingleEntityValidator { @Override - public void validate(GtfsFrequency frequency, NoticeContainer noticeContainer) { + public void validate(GtfsFrequency frequency, NoticeContainer noticeContainer) throws ErrorDetectedException { // validate() will only be called if startTime and endTime have been populated for this // frequency GtfsTime startTime = frequency.startTime(); diff --git a/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/GtfsTripServiceIdForeignKeyValidator.java b/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/GtfsTripServiceIdForeignKeyValidator.java index edc3199476..b958a897a9 100644 --- a/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/GtfsTripServiceIdForeignKeyValidator.java +++ b/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/GtfsTripServiceIdForeignKeyValidator.java @@ -18,6 +18,7 @@ import org.mobilitydata.gtfsvalidator.annotation.GtfsValidator; import org.mobilitydata.gtfsvalidator.annotation.Inject; +import org.mobilitydata.gtfsvalidator.notice.ErrorDetectedException; import org.mobilitydata.gtfsvalidator.notice.ForeignKeyError; import org.mobilitydata.gtfsvalidator.notice.NoticeContainer; import org.mobilitydata.gtfsvalidator.table.GtfsCalendarDateTableContainer; @@ -40,7 +41,7 @@ public class GtfsTripServiceIdForeignKeyValidator extends FileValidator { @Inject GtfsCalendarDateTableContainer calendarDateContainer; @Override - public void validate(NoticeContainer noticeContainer) { + public void validate(NoticeContainer noticeContainer) throws ErrorDetectedException { for (GtfsTrip trip : tripContainer.getEntities()) { String childKey = trip.serviceId(); if (!hasReferencedKey(childKey, calendarContainer, calendarDateContainer)) { diff --git a/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/LocationTypeSingleEntityValidator.java b/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/LocationTypeSingleEntityValidator.java index 6f2eb61ce0..70f50ae9c0 100644 --- a/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/LocationTypeSingleEntityValidator.java +++ b/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/LocationTypeSingleEntityValidator.java @@ -17,6 +17,7 @@ package org.mobilitydata.gtfsvalidator.validator; import org.mobilitydata.gtfsvalidator.annotation.GtfsValidator; +import org.mobilitydata.gtfsvalidator.notice.ErrorDetectedException; import org.mobilitydata.gtfsvalidator.notice.LocationWithoutParentStationNotice; import org.mobilitydata.gtfsvalidator.notice.NoticeContainer; import org.mobilitydata.gtfsvalidator.notice.PlatformWithoutParentStationNotice; @@ -44,7 +45,7 @@ private boolean requiresParentStation(GtfsLocationType locationType) { } @Override - public void validate(GtfsStop location, NoticeContainer noticeContainer) { + public void validate(GtfsStop location, NoticeContainer noticeContainer) throws ErrorDetectedException { if (location.hasParentStation()) { if (location.locationType() == GtfsLocationType.STATION) { noticeContainer.addValidationNotice( diff --git a/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/MatchingFeedAndAgencyLangValidator.java b/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/MatchingFeedAndAgencyLangValidator.java index 615a48b4d5..857b009a52 100644 --- a/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/MatchingFeedAndAgencyLangValidator.java +++ b/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/MatchingFeedAndAgencyLangValidator.java @@ -19,6 +19,7 @@ import java.util.Locale; import org.mobilitydata.gtfsvalidator.annotation.GtfsValidator; import org.mobilitydata.gtfsvalidator.annotation.Inject; +import org.mobilitydata.gtfsvalidator.notice.ErrorDetectedException; import org.mobilitydata.gtfsvalidator.notice.FeedInfoLangAndAgencyLangMismatchNotice; import org.mobilitydata.gtfsvalidator.notice.NoticeContainer; import org.mobilitydata.gtfsvalidator.table.GtfsAgency; @@ -53,7 +54,7 @@ public class MatchingFeedAndAgencyLangValidator extends FileValidator { @Inject GtfsAgencyTableContainer agencyTable; @Override - public void validate(NoticeContainer noticeContainer) { + public void validate(NoticeContainer noticeContainer) throws ErrorDetectedException { // If there are no feed info entries or if no feed lang has been specified, we don't do any // validation. if (feedInfoTable.entityCount() == 0 || !feedInfoTable.getSingleEntity().hasFeedLang()) { diff --git a/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/MissingCalendarAndCalendarDateValidator.java b/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/MissingCalendarAndCalendarDateValidator.java index f64260cb7c..bf583e8da3 100644 --- a/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/MissingCalendarAndCalendarDateValidator.java +++ b/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/MissingCalendarAndCalendarDateValidator.java @@ -18,6 +18,7 @@ import org.mobilitydata.gtfsvalidator.annotation.GtfsValidator; import org.mobilitydata.gtfsvalidator.annotation.Inject; +import org.mobilitydata.gtfsvalidator.notice.ErrorDetectedException; import org.mobilitydata.gtfsvalidator.notice.MissingCalendarAndCalendarDateFilesNotice; import org.mobilitydata.gtfsvalidator.notice.NoticeContainer; import org.mobilitydata.gtfsvalidator.table.GtfsCalendarDateTableContainer; @@ -39,7 +40,7 @@ public class MissingCalendarAndCalendarDateValidator extends FileValidator { @Inject GtfsCalendarDateTableContainer calendarDateTable; @Override - public void validate(NoticeContainer noticeContainer) { + public void validate(NoticeContainer noticeContainer) throws ErrorDetectedException { if (calendarTable.isMissingFile() && calendarDateTable.isMissingFile()) { noticeContainer.addValidationNotice(new MissingCalendarAndCalendarDateFilesNotice()); } diff --git a/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/MissingTripEdgeValidator.java b/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/MissingTripEdgeValidator.java index d01b3231e4..e2b433c38e 100644 --- a/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/MissingTripEdgeValidator.java +++ b/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/MissingTripEdgeValidator.java @@ -24,6 +24,7 @@ import java.util.Map.Entry; import org.mobilitydata.gtfsvalidator.annotation.GtfsValidator; import org.mobilitydata.gtfsvalidator.annotation.Inject; +import org.mobilitydata.gtfsvalidator.notice.ErrorDetectedException; import org.mobilitydata.gtfsvalidator.notice.MissingTripEdgeNotice; import org.mobilitydata.gtfsvalidator.notice.NoticeContainer; import org.mobilitydata.gtfsvalidator.table.GtfsStopTime; @@ -40,7 +41,7 @@ public class MissingTripEdgeValidator extends FileValidator { @Inject GtfsStopTimeTableContainer stopTimeTable; @Override - public void validate(NoticeContainer noticeContainer) { + public void validate(NoticeContainer noticeContainer) throws ErrorDetectedException { for (Entry> entry : Multimaps.asMap(stopTimeTable.byTripIdMap()).entrySet()) { String tripId = entry.getKey(); diff --git a/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/OverlappingFrequencyValidator.java b/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/OverlappingFrequencyValidator.java index 918c91b240..c51e9dca95 100644 --- a/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/OverlappingFrequencyValidator.java +++ b/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/OverlappingFrequencyValidator.java @@ -7,6 +7,7 @@ import java.util.List; import org.mobilitydata.gtfsvalidator.annotation.GtfsValidator; import org.mobilitydata.gtfsvalidator.annotation.Inject; +import org.mobilitydata.gtfsvalidator.notice.ErrorDetectedException; import org.mobilitydata.gtfsvalidator.notice.NoticeContainer; import org.mobilitydata.gtfsvalidator.notice.OverlappingFrequencyNotice; import org.mobilitydata.gtfsvalidator.table.GtfsFrequency; @@ -28,7 +29,7 @@ public class OverlappingFrequencyValidator extends FileValidator { @Inject GtfsFrequencyTableContainer table; @Override - public void validate(NoticeContainer noticeContainer) { + public void validate(NoticeContainer noticeContainer) throws ErrorDetectedException { for (List unorderedList : Multimaps.asMap(table.byTripIdMap()).values()) { List frequencyList = new ArrayList<>(unorderedList); Collections.sort( diff --git a/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/ParentLocationTypeValidator.java b/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/ParentLocationTypeValidator.java index 598f08c2e6..ecd288a974 100644 --- a/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/ParentLocationTypeValidator.java +++ b/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/ParentLocationTypeValidator.java @@ -18,6 +18,7 @@ import org.mobilitydata.gtfsvalidator.annotation.GtfsValidator; import org.mobilitydata.gtfsvalidator.annotation.Inject; +import org.mobilitydata.gtfsvalidator.notice.ErrorDetectedException; import org.mobilitydata.gtfsvalidator.notice.NoticeContainer; import org.mobilitydata.gtfsvalidator.notice.WrongParentLocationTypeNotice; import org.mobilitydata.gtfsvalidator.table.GtfsLocationType; @@ -47,7 +48,7 @@ private GtfsLocationType expectedParentLocationType(GtfsLocationType locationTyp } @Override - public void validate(NoticeContainer noticeContainer) { + public void validate(NoticeContainer noticeContainer) throws ErrorDetectedException { for (GtfsStop location : stopTable.getEntities()) { if (!location.hasParentStation()) { continue; diff --git a/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/RouteColorContrastValidator.java b/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/RouteColorContrastValidator.java index 5b259bbf7b..8688bfce20 100644 --- a/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/RouteColorContrastValidator.java +++ b/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/RouteColorContrastValidator.java @@ -17,6 +17,7 @@ package org.mobilitydata.gtfsvalidator.validator; import org.mobilitydata.gtfsvalidator.annotation.GtfsValidator; +import org.mobilitydata.gtfsvalidator.notice.ErrorDetectedException; import org.mobilitydata.gtfsvalidator.notice.NoticeContainer; import org.mobilitydata.gtfsvalidator.notice.RouteColorContrastNotice; import org.mobilitydata.gtfsvalidator.table.GtfsRoute; @@ -37,7 +38,8 @@ public class RouteColorContrastValidator extends SingleEntityValidator { private static final int MAX_SHORT_NAME_LENGTH = 12; @Override - public void validate(GtfsRoute entity, NoticeContainer noticeContainer) { + public void validate(GtfsRoute entity, NoticeContainer noticeContainer) throws ErrorDetectedException { final boolean hasLongName = entity.hasRouteLongName(); final boolean hasShortName = entity.hasRouteShortName(); diff --git a/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/ShapeIncreasingDistanceValidator.java b/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/ShapeIncreasingDistanceValidator.java index 5f2318873e..0333315708 100644 --- a/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/ShapeIncreasingDistanceValidator.java +++ b/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/ShapeIncreasingDistanceValidator.java @@ -21,6 +21,7 @@ import org.mobilitydata.gtfsvalidator.annotation.GtfsValidator; import org.mobilitydata.gtfsvalidator.annotation.Inject; import org.mobilitydata.gtfsvalidator.notice.DecreasingShapeDistanceNotice; +import org.mobilitydata.gtfsvalidator.notice.ErrorDetectedException; import org.mobilitydata.gtfsvalidator.notice.NoticeContainer; import org.mobilitydata.gtfsvalidator.table.GtfsShape; import org.mobilitydata.gtfsvalidator.table.GtfsShapeTableContainer; @@ -35,7 +36,7 @@ public class ShapeIncreasingDistanceValidator extends FileValidator { @Inject GtfsShapeTableContainer table; @Override - public void validate(NoticeContainer noticeContainer) { + public void validate(NoticeContainer noticeContainer) throws ErrorDetectedException { for (List shapeList : Multimaps.asMap(table.byShapeIdMap()).values()) { // GtfsShape objects are sorted based on @SequenceKey annotation on shape_pt_sequence field. for (int i = 1; i < shapeList.size(); ++i) { diff --git a/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/ShapeUsageValidator.java b/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/ShapeUsageValidator.java index 1e66964003..13e24dfcc0 100644 --- a/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/ShapeUsageValidator.java +++ b/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/ShapeUsageValidator.java @@ -20,6 +20,7 @@ import java.util.Set; import org.mobilitydata.gtfsvalidator.annotation.GtfsValidator; import org.mobilitydata.gtfsvalidator.annotation.Inject; +import org.mobilitydata.gtfsvalidator.notice.ErrorDetectedException; import org.mobilitydata.gtfsvalidator.notice.NoticeContainer; import org.mobilitydata.gtfsvalidator.notice.UnusedShapeNotice; import org.mobilitydata.gtfsvalidator.table.GtfsShape; @@ -38,7 +39,7 @@ public class ShapeUsageValidator extends FileValidator { @Inject GtfsShapeTableContainer shapeTable; @Override - public void validate(NoticeContainer noticeContainer) { + public void validate(NoticeContainer noticeContainer) throws ErrorDetectedException { // Do not report the same shape_id multiple times. Set reportedShapes = new HashSet<>(); for (GtfsShape shape : shapeTable.getEntities()) { diff --git a/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/StopTimeArrivalAndDepartureTimeValidator.java b/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/StopTimeArrivalAndDepartureTimeValidator.java index 62d70a3e53..8bd87b7742 100644 --- a/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/StopTimeArrivalAndDepartureTimeValidator.java +++ b/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/StopTimeArrivalAndDepartureTimeValidator.java @@ -20,6 +20,7 @@ import java.util.List; import org.mobilitydata.gtfsvalidator.annotation.GtfsValidator; import org.mobilitydata.gtfsvalidator.annotation.Inject; +import org.mobilitydata.gtfsvalidator.notice.ErrorDetectedException; import org.mobilitydata.gtfsvalidator.notice.NoticeContainer; import org.mobilitydata.gtfsvalidator.notice.StopTimeWithArrivalBeforePreviousDepartureTimeNotice; import org.mobilitydata.gtfsvalidator.notice.StopTimeWithDepartureBeforeArrivalTimeNotice; @@ -46,7 +47,7 @@ public class StopTimeArrivalAndDepartureTimeValidator extends FileValidator { @Inject GtfsStopTimeTableContainer table; @Override - public void validate(NoticeContainer noticeContainer) { + public void validate(NoticeContainer noticeContainer) throws ErrorDetectedException { for (List stopTimeList : Multimaps.asMap(table.byTripIdMap()).values()) { int previousDepartureRow = -1; for (int i = 0; i < stopTimeList.size(); ++i) { diff --git a/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/StopTimeIncreasingDistanceValidator.java b/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/StopTimeIncreasingDistanceValidator.java index b7789a71ad..bba79e71a7 100644 --- a/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/StopTimeIncreasingDistanceValidator.java +++ b/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/StopTimeIncreasingDistanceValidator.java @@ -22,6 +22,7 @@ import org.mobilitydata.gtfsvalidator.annotation.Inject; import org.mobilitydata.gtfsvalidator.notice.DecreasingShapeDistanceNotice; import org.mobilitydata.gtfsvalidator.notice.DecreasingStopTimeDistanceNotice; +import org.mobilitydata.gtfsvalidator.notice.ErrorDetectedException; import org.mobilitydata.gtfsvalidator.notice.NoticeContainer; import org.mobilitydata.gtfsvalidator.table.GtfsStopTime; import org.mobilitydata.gtfsvalidator.table.GtfsStopTimeTableContainer; @@ -36,7 +37,7 @@ public class StopTimeIncreasingDistanceValidator extends FileValidator { @Inject GtfsStopTimeTableContainer stopTimeTable; @Override - public void validate(NoticeContainer noticeContainer) { + public void validate(NoticeContainer noticeContainer) throws ErrorDetectedException { for (List stopTimeList : Multimaps.asMap(stopTimeTable.byTripIdMap()).values()) { // GtfsStopTime objects are sorted based on @SequenceKey annotation on stop_sequence field. for (int i = 1; i < stopTimeList.size(); ++i) { diff --git a/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/StopTooFarFromTripShapeValidator.java b/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/StopTooFarFromTripShapeValidator.java index 455805bb8f..3dd2eb9524 100644 --- a/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/StopTooFarFromTripShapeValidator.java +++ b/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/StopTooFarFromTripShapeValidator.java @@ -22,6 +22,7 @@ import java.util.Set; import org.mobilitydata.gtfsvalidator.annotation.GtfsValidator; import org.mobilitydata.gtfsvalidator.annotation.Inject; +import org.mobilitydata.gtfsvalidator.notice.ErrorDetectedException; import org.mobilitydata.gtfsvalidator.notice.NoticeContainer; import org.mobilitydata.gtfsvalidator.notice.StartAndEndDateOutOfOrderNotice; import org.mobilitydata.gtfsvalidator.notice.StopTooFarFromTripShapeNotice; @@ -46,7 +47,7 @@ public class StopTooFarFromTripShapeValidator extends FileValidator { @Inject GtfsStopTableContainer stopTable; @Override - public void validate(NoticeContainer noticeContainer) { + public void validate(NoticeContainer noticeContainer) throws ErrorDetectedException { List notices = new ArrayList<>(); // Cache for previously tested shape_id and stop_id pairs - we don't need to test them more than @@ -73,6 +74,8 @@ public void validate(NoticeContainer noticeContainer) { testedCache); notices.addAll(noticesForTrip); }); - notices.forEach(noticeContainer::addValidationNotice); + for (StopTooFarFromTripShapeNotice notice : notices) { + noticeContainer.addValidationNotice(notice); + } } } diff --git a/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/TripAgencyIdValidator.java b/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/TripAgencyIdValidator.java index 0c433b841f..90d2b0a6a5 100644 --- a/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/TripAgencyIdValidator.java +++ b/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/TripAgencyIdValidator.java @@ -18,6 +18,7 @@ import org.mobilitydata.gtfsvalidator.annotation.GtfsValidator; import org.mobilitydata.gtfsvalidator.annotation.Inject; +import org.mobilitydata.gtfsvalidator.notice.ErrorDetectedException; import org.mobilitydata.gtfsvalidator.notice.MissingRequiredFieldError; import org.mobilitydata.gtfsvalidator.notice.NoticeContainer; import org.mobilitydata.gtfsvalidator.table.GtfsAgencyTableContainer; @@ -38,7 +39,7 @@ public class TripAgencyIdValidator extends FileValidator { @Inject GtfsRouteTableContainer routeTable; @Override - public void validate(NoticeContainer noticeContainer) { + public void validate(NoticeContainer noticeContainer) throws ErrorDetectedException { if (agencyTable.entityCount() < 2) { // routes.agency_id is not required when there is a single agency. return; diff --git a/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/TripUsabilityValidator.java b/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/TripUsabilityValidator.java index 9269938e18..f9c2c56043 100644 --- a/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/TripUsabilityValidator.java +++ b/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/TripUsabilityValidator.java @@ -18,6 +18,7 @@ import org.mobilitydata.gtfsvalidator.annotation.GtfsValidator; import org.mobilitydata.gtfsvalidator.annotation.Inject; +import org.mobilitydata.gtfsvalidator.notice.ErrorDetectedException; import org.mobilitydata.gtfsvalidator.notice.NoticeContainer; import org.mobilitydata.gtfsvalidator.notice.UnusableTripNotice; import org.mobilitydata.gtfsvalidator.table.GtfsStopTimeTableContainer; @@ -35,7 +36,7 @@ public class TripUsabilityValidator extends FileValidator { @Inject GtfsStopTimeTableContainer stopTimeTable; @Override - public void validate(NoticeContainer noticeContainer) { + public void validate(NoticeContainer noticeContainer) throws ErrorDetectedException { for (GtfsTrip trip : tripTable.getEntities()) { String tripId = trip.tripId(); if (stopTimeTable.byTripId(tripId).size() <= 1) { diff --git a/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/TripUsageValidator.java b/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/TripUsageValidator.java index 9d554f0acf..d198897c3e 100644 --- a/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/TripUsageValidator.java +++ b/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/TripUsageValidator.java @@ -20,6 +20,7 @@ import java.util.Set; import org.mobilitydata.gtfsvalidator.annotation.GtfsValidator; import org.mobilitydata.gtfsvalidator.annotation.Inject; +import org.mobilitydata.gtfsvalidator.notice.ErrorDetectedException; import org.mobilitydata.gtfsvalidator.notice.NoticeContainer; import org.mobilitydata.gtfsvalidator.notice.UnusedShapeNotice; import org.mobilitydata.gtfsvalidator.notice.UnusedTripNotice; @@ -38,7 +39,7 @@ public class TripUsageValidator extends FileValidator { @Inject GtfsStopTimeTableContainer stopTimeTable; @Override - public void validate(NoticeContainer noticeContainer) { + public void validate(NoticeContainer noticeContainer) throws ErrorDetectedException { // Do not report the same trip_id multiple times. Set reportedTrips = new HashSet<>(); for (GtfsTrip trip : tripTable.getEntities()) { From f02636fa0048d77388df07199ab4f58e0c0b10fc Mon Sep 17 00:00:00 2001 From: lionel-nj Date: Mon, 22 Feb 2021 15:14:28 -0500 Subject: [PATCH 7/7] propagate exception in generator --- .../gtfsvalidator/processor/TableContainerGenerator.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/processor/src/main/java/org/mobilitydata/gtfsvalidator/processor/TableContainerGenerator.java b/processor/src/main/java/org/mobilitydata/gtfsvalidator/processor/TableContainerGenerator.java index 445ba8f6dd..fefe8826ac 100644 --- a/processor/src/main/java/org/mobilitydata/gtfsvalidator/processor/TableContainerGenerator.java +++ b/processor/src/main/java/org/mobilitydata/gtfsvalidator/processor/TableContainerGenerator.java @@ -39,6 +39,7 @@ import javax.lang.model.element.Modifier; import org.mobilitydata.gtfsvalidator.annotation.Generated; import org.mobilitydata.gtfsvalidator.notice.DuplicateKeyError; +import org.mobilitydata.gtfsvalidator.notice.ErrorDetectedException; import org.mobilitydata.gtfsvalidator.notice.MoreThanOneEntityNotice; import org.mobilitydata.gtfsvalidator.notice.NoticeContainer; import org.mobilitydata.gtfsvalidator.table.GtfsTableContainer; @@ -213,6 +214,7 @@ private MethodSpec generateForEntitiesMethod() { .addParameter(NoticeContainer.class, "noticeContainer") .addStatement("$T table = new $T(entities)", tableContainerTypeName, tableContainerTypeName) .addStatement("table.setupIndices(noticeContainer)") + .addException(ErrorDetectedException.class) .addStatement("return table") .build(); } @@ -224,6 +226,7 @@ private MethodSpec generateSetupIndicesMethod() { MethodSpec.methodBuilder("setupIndices") .addModifiers(Modifier.PRIVATE) .addParameter(NoticeContainer.class, "noticeContainer") + .addException(ErrorDetectedException.class) .returns(void.class); if (fileDescriptor.singleRow()) {