Skip to content

Commit

Permalink
AER-3104 Import screen error formatting (#291)
Browse files Browse the repository at this point in the history
- Adjusted GMLReaderFactory to add each error to the list of errors and fail the import if there are any
- Added unit test
  • Loading branch information
MichielJanssen-DAT authored Aug 6, 2024
1 parent e93823e commit bac9e90
Show file tree
Hide file tree
Showing 4 changed files with 94 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import java.io.InputStream;
import java.io.UTFDataFormatException;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
Expand Down Expand Up @@ -105,8 +106,11 @@ public GMLReader createReader(final InputStream inputStream, final boolean valid
//determine version of the XML based on the namespaces available.
factory = readerProxy.determineReaderFactory(reader.getNamespaceContext());
final GMLReader gmlr = new GMLReader(gmlHelper, factory, convertToCollection(reader, factory, vec, validate), errors, warnings);
checkEvents(vec.getEvents());
return gmlr;
errors.addAll(checkEvents(vec.getEvents()));
if (errors.isEmpty()) {
return gmlr;
}
return null;
} catch (final XMLStreamException e) {
throw newGmlParseError(e);
}
Expand All @@ -116,12 +120,12 @@ public ValidationHelper createValidationHelper() {
return gmlHelper.getValidationHelper();
}

private static void checkEvents(final List<ValidationEvent> events) throws AeriusException {
// information like required elements not being present will not throw an exception, but will trigger an event.
// check for these events and throw exception if present.
private static List<AeriusException> checkEvents(final List<ValidationEvent> events) {
// Return any error events found.
if ((events != null) && !events.isEmpty()) {
throw newValidationFailed(events);
return newValidationFailed(events);
}
return List.of();
}

private static FeatureCollection convertToCollection(final XMLStreamReader xmlStreamReader, final GMLVersionReaderFactory factory,
Expand All @@ -138,20 +142,17 @@ private static FeatureCollection convertToCollection(final XMLStreamReader xmlSt
} catch (final NumberFormatException e) {
throw new AeriusException(ImaerExceptionReason.GML_GENERIC_PARSE_ERROR, e.getMessage());
} catch (final JAXBException e) {
processException(vec, e);
processException(e);
}
return collection;
}

private static void processException(final CustomValidationEventCollector vec, final JAXBException e) throws AeriusException {
private static void processException(final JAXBException e) throws AeriusException {
if ((e.getLinkedException() instanceof UTFDataFormatException) || (e.getLinkedException() instanceof UnsupportedEncodingException)) {
throw new AeriusException(ImaerExceptionReason.GML_ENCODING_INCORRECT);
} else if (e.getLinkedException() instanceof XMLStreamException) {
throw newGmlParseError((XMLStreamException) e.getLinkedException());
} else {
LOG.error("JAXBException occurred.", e);
throw newValidationFailed(vec.getEvents());
}
} else if (e.getLinkedException() instanceof final XMLStreamException streamException) {
throw newGmlParseError(streamException);
} // Rely on custom event collection instead
}

private static AeriusException newGmlParseError(final XMLStreamException e) {
Expand All @@ -165,13 +166,14 @@ private static AeriusException newGmlParseError(final XMLStreamException e) {
}
}

private static AeriusException newValidationFailed(final List<ValidationEvent> list) {
final StringBuilder errorLine = new StringBuilder();
private static List<AeriusException> newValidationFailed(final List<ValidationEvent> list) {
final List<AeriusException> errors = new ArrayList<>();
for (final ValidationEvent event : list) {
errorLine.append(event.getMessage());
errorLine.append(' ');
final String errorMessage = event.getMessage().trim();
final AeriusException error = new AeriusException(ImaerExceptionReason.GML_VALIDATION_FAILED, errorMessage);
errors.add(error);
LOG.debug("validation error: {}", errorMessage);
}
LOG.debug("validation error: {}", errorLine);
return new AeriusException(ImaerExceptionReason.GML_VALIDATION_FAILED, errorLine.toString().trim());
return errors;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,10 @@ public void importStream(final InputStream inputStream, final Set<ImportOption>
result.getExceptions().add(e);
return;
}
if (reader == null) {
return;
}

final AeriusGMLVersion version = reader.getVersion();
setImportResultMetaData(result, reader);
GMLValidator.validateMetaData(result.getImportedMetaData(), result.getExceptions(), ImportOption.VALIDATE_METADATA.in(importOptions)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,16 @@ void testGMLGeometryNotPermitted() throws IOException {
assertResult("fout_5205_unallowed_source_geometry", "GML Geometry not permitted", ImaerExceptionReason.SHIPPING_ROUTE_GEOMETRY_NOT_ALLOWED);
}

@Test
void testGMLMultipleErrors() throws IOException, AeriusException {
final List<String> expectedErrors = List.of(
"cvc-enumeration-valid: Value 'None' is not facet-valid with respect to enumeration '[HOUR, DAY, MONTH, YEAR]'. It must be a value from the enumeration.",
"cvc-type.3.1.3: The value 'None' of element 'imaer:timeUnit' is not valid.",
"cvc-complex-type.2.4.b: The content of element 'imaer:CustomVehicle' is not complete. One of '{\"http://imaer.aerius.nl/5.1\":emission}' is expected.",
"cvc-complex-type.2.4.a: Invalid content was found starting with element '{\"http://imaer.aerius.nl/5.1\":diurnalVariation}'. One of '{\"http://imaer.aerius.nl/5.1\":vehicles, \"http://imaer.aerius.nl/5.1\":roadManager, \"http://imaer.aerius.nl/5.1\":trafficDirection, \"http://imaer.aerius.nl/5.1\":width}' is expected.");
assertResults("fout_multiple_errors", expectedErrors, ImaerExceptionReason.GML_VALIDATION_FAILED);
}

@Test
void testGMLGeometryUnknown() throws IOException {
assertResult("fout_5206_unsupported_geometry", "GML Geometry unkown", ImaerExceptionReason.GML_VALIDATION_FAILED,
Expand Down Expand Up @@ -333,6 +343,19 @@ private static <T extends Throwable> T assertResult(final String fileName, final
"Expected an exception " + clazz.getSimpleName());
}

private static void assertResults(final String fileName, final List<String> expectedReasonsTxt, final Reason expectedReason)
throws IOException, AeriusException {
final ImportParcel result = getImportResult(LATEST_VALIDATE, fileName);
assertEquals(expectedReasonsTxt.size(), result.getExceptions().size(), "Number of exceptions should match number of expected reason texts");

for (int i = 0; i < expectedReasonsTxt.size(); i++) {
final AeriusException aeriusException = result.getExceptions().get(i);
assertEquals(1, aeriusException.getArgs().length, "Only one argument expected");
assertEquals(expectedReasonsTxt.get(i), aeriusException.getArgs()[0], "Reason texts should match");
assertEquals(expectedReason, aeriusException.getReason(), "Reasons should match");
}
}

private static ImportParcel getImportResult(final String relativePath, final String fileName)
throws IOException, AeriusException {
return AssertGML.getImportResult(relativePath, fileName);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<imaer:FeatureCollectionCalculator xsi:schemaLocation="http://imaer.aerius.nl/5.1 http://imaer.aerius.nl/5.1/IMAER.xsd" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:imaer="http://imaer.aerius.nl/5.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:gml="http://www.opengis.net/gml/3.2" gml:id="NL.IMAER.Collection">
<imaer:metadata>
<imaer:AeriusCalculatorMetadata>
<imaer:project>
<imaer:ProjectMetadata>
<imaer:year>2023</imaer:year>
<imaer:description></imaer:description>
</imaer:ProjectMetadata>
</imaer:project>
<imaer:gmlCreator>QgisImaerPlugin-3.4.2</imaer:gmlCreator>
</imaer:AeriusCalculatorMetadata>
</imaer:metadata>
<imaer:featureMember>
<imaer:ADMSRoad sectorId="3100" roadType="" roadAreaType="" gml:id="ES.0">
<imaer:identifier>
<imaer:NEN3610ID>
<imaer:namespace>NL.IMAER</imaer:namespace>
<imaer:localId>ES.0</imaer:localId>
</imaer:NEN3610ID>
</imaer:identifier>
<imaer:geometry>
<imaer:EmissionSourceGeometry>
<imaer:GM_Curve>
<gml:LineString srsName="urn:ogc:def:crs:EPSG::27700" gml:id="ES.0.CURVE">
<gml:posList srsDimension="2">201425.333 637649.561 201227.783 637602.222 201149.036 637563.987 201120.587 637536.448 201096.69 637496.961 201075.297 637444.615 201082.58 637393.975 201081.442 637329.339 201066.421 637128.603 201054.586 637104.479 200679.515 636943.116 200642.189 636923.088 200577.781 636867.1 200557.525 636842.065</gml:posList>
</gml:LineString>
</imaer:GM_Curve>
</imaer:EmissionSourceGeometry>
</imaer:geometry>
<imaer:vehicles>
<imaer:CustomVehicle>
<imaer:vehiclesPerTimeUnit>3</imaer:vehiclesPerTimeUnit>
<imaer:timeUnit>None</imaer:timeUnit>
<imaer:description>None</imaer:description>
</imaer:CustomVehicle>
</imaer:vehicles>
<imaer:diurnalVariation>
<imaer:StandardDiurnalVariation>
<imaer:standardType>800.0</imaer:standardType>
</imaer:StandardDiurnalVariation>
</imaer:diurnalVariation>
</imaer:ADMSRoad>
</imaer:featureMember>
</imaer:FeatureCollectionCalculator>

0 comments on commit bac9e90

Please sign in to comment.