Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -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);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,16 @@ public class NoticeContainer {
private final List<ValidationNotice> validationNotices = new ArrayList<>();
private final List<SystemError> 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<ValidationNotice> getValidationNotices() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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(
Expand All @@ -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);
}

Expand All @@ -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,
Expand All @@ -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,
Expand All @@ -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,
Expand All @@ -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(
Expand All @@ -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(
Expand All @@ -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);
}
Expand All @@ -285,7 +289,8 @@ public BigDecimal asDecimal(int columnIndex, boolean required, NumberBounds boun
* @return the same value as passed to the function
*/
private <T extends Comparable<T>> 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;
}
Expand Down Expand Up @@ -329,12 +334,13 @@ private <T extends Comparable<T>> 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 <E> Integer asEnum(int columnIndex, boolean required, EnumCreator<E> enumCreator) {
public <E> Integer asEnum(int columnIndex, boolean required, EnumCreator<E> enumCreator)
throws ErrorDetectedException {
Integer i = asInteger(columnIndex, required);
if (i == null) {
return null;
Expand All @@ -348,12 +354,12 @@ public <E> Integer asEnum(int columnIndex, boolean required, EnumCreator<E> 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);
}

Expand All @@ -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;
}
Expand Down Expand Up @@ -407,7 +413,7 @@ private <T> T parseAsType(
int columnIndex,
boolean required,
Function<String, T> parsingFunction,
NoticingFunction noticingFunction) {
NoticingFunction noticingFunction) throws ErrorDetectedException {
String s = asString(columnIndex, required);
if (s == null) {
return null;
Expand Down Expand Up @@ -447,7 +453,7 @@ private String asValidatedString(
int columnIndex,
boolean required,
Predicate<String> validatingFunction,
NoticingFunction noticingFunction) {
NoticingFunction noticingFunction) throws ErrorDetectedException {
String s = asString(columnIndex, required);
if (s == null) {
return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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<TableAndNoticeContainers> 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()));
Expand Down Expand Up @@ -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<NoticeContainer> 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()));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -43,10 +44,10 @@ public abstract GtfsTableContainer<T> load(
InputStream inputStream,
ValidationContext validationContext,
ValidatorLoader validatorLoader,
NoticeContainer noticeContainer);
NoticeContainer noticeContainer) throws ErrorDetectedException;

public abstract GtfsTableContainer<T> loadMissingFile(
ValidationContext validationContext,
ValidatorLoader validatorLoader,
NoticeContainer noticeContainer);
NoticeContainer noticeContainer) throws ErrorDetectedException;
}
Loading