From 5529ac70a6cf70592f3b73ff2fd49667dd971612 Mon Sep 17 00:00:00 2001 From: JornC Date: Tue, 27 Jan 2026 16:53:49 +0100 Subject: [PATCH 1/6] Euroclass removed codes support --- .../nl/overheid/aerius/gml/GMLReader.java | 13 ++ .../aerius/gml/base/GMLConversionData.java | 12 ++ .../gml/base/GMLLegacyCodesSupplier.java | 12 ++ .../RemovedVehicleCodeConverter.java | 96 +++++++++++ .../RemovedVehicleCodeConverterTest.java | 157 ++++++++++++++++++ 5 files changed, 290 insertions(+) create mode 100644 source/imaer-gml/src/main/java/nl/overheid/aerius/gml/base/conversion/RemovedVehicleCodeConverter.java create mode 100644 source/imaer-gml/src/test/java/nl/overheid/aerius/gml/base/conversion/RemovedVehicleCodeConverterTest.java diff --git a/source/imaer-gml/src/main/java/nl/overheid/aerius/gml/GMLReader.java b/source/imaer-gml/src/main/java/nl/overheid/aerius/gml/GMLReader.java index 35683d95..6a80849e 100644 --- a/source/imaer-gml/src/main/java/nl/overheid/aerius/gml/GMLReader.java +++ b/source/imaer-gml/src/main/java/nl/overheid/aerius/gml/GMLReader.java @@ -25,6 +25,7 @@ import nl.overheid.aerius.gml.base.GMLHelper; import nl.overheid.aerius.gml.base.GMLVersionReader; import nl.overheid.aerius.gml.base.GMLVersionReaderFactory; +import nl.overheid.aerius.gml.base.conversion.RemovedVehicleCodeConverter; import nl.overheid.aerius.shared.domain.Theme; import nl.overheid.aerius.shared.domain.calculation.CalculationSetOptions; import nl.overheid.aerius.shared.domain.scenario.SituationType; @@ -109,6 +110,18 @@ public void enforceEmissions(final List emissionSourceLis gmlHelper.enforceEmissions(year, emissionSourceList); } + /** + * Converts any SpecificVehicles with removed vehicle codes to CustomVehicles with zero emissions. + * This should be called after reading emission sources and before validation. + * + * @param emissionSourceList List of sources to convert + * @throws AeriusException error + */ + public void convertRemovedVehicleCodes(final List emissionSourceList) throws AeriusException { + final RemovedVehicleCodeConverter converter = conversionData.createRemovedVehicleCodeConverter(); + converter.convertRemovedVehicleCodes(emissionSourceList); + } + /** * Gets the name from the feature collection. */ diff --git a/source/imaer-gml/src/main/java/nl/overheid/aerius/gml/base/GMLConversionData.java b/source/imaer-gml/src/main/java/nl/overheid/aerius/gml/base/GMLConversionData.java index be8a31f1..74f5c7f4 100644 --- a/source/imaer-gml/src/main/java/nl/overheid/aerius/gml/base/GMLConversionData.java +++ b/source/imaer-gml/src/main/java/nl/overheid/aerius/gml/base/GMLConversionData.java @@ -28,6 +28,7 @@ import nl.overheid.aerius.gml.base.conversion.FarmLodgingConversion; import nl.overheid.aerius.gml.base.conversion.MobileSourceOffRoadConversion; import nl.overheid.aerius.gml.base.conversion.PlanConversion; +import nl.overheid.aerius.gml.base.conversion.RemovedVehicleCodeConverter; import nl.overheid.aerius.gml.base.source.ship.v31.InlandShippingUtil; import nl.overheid.aerius.shared.domain.Substance; import nl.overheid.aerius.shared.domain.v2.building.BuildingFeature; @@ -246,4 +247,15 @@ public S determineDefaultCharacteristicsBySect public S determineDefaultCharacteristicsBySectorId(final int sectorId, final GeometryType geometryType) { return characteristicsSupplier.determineDefaultCharacteristicsBySectorId(sectorId, geometryType); } + + /** + * Creates a converter that handles removed vehicle codes by converting them to custom vehicles + * with zero emissions. + * + * @return the removed vehicle code converter + * @throws AeriusException if the removed codes cannot be retrieved + */ + public RemovedVehicleCodeConverter createRemovedVehicleCodeConverter() throws AeriusException { + return new RemovedVehicleCodeConverter(helper.getRemovedVehicleCodes(), warnings); + } } diff --git a/source/imaer-gml/src/main/java/nl/overheid/aerius/gml/base/GMLLegacyCodesSupplier.java b/source/imaer-gml/src/main/java/nl/overheid/aerius/gml/base/GMLLegacyCodesSupplier.java index d56e9e05..4e1b2771 100644 --- a/source/imaer-gml/src/main/java/nl/overheid/aerius/gml/base/GMLLegacyCodesSupplier.java +++ b/source/imaer-gml/src/main/java/nl/overheid/aerius/gml/base/GMLLegacyCodesSupplier.java @@ -17,6 +17,7 @@ package nl.overheid.aerius.gml.base; import java.util.Map; +import java.util.Set; import nl.overheid.aerius.gml.base.GMLLegacyCodeConverter.Conversion; import nl.overheid.aerius.gml.base.GMLLegacyCodeConverter.GMLLegacyCodeType; @@ -69,4 +70,15 @@ default Map getLegacyFarmLodgingConversions() thr return Map.of(); } + /** + * Returns a set of removed vehicle codes. + * Sources with these codes will be converted to custom vehicles with zero emissions during import. + * + * @return set of removed vehicle codes + * @throws AeriusException + */ + default Set getRemovedVehicleCodes() throws AeriusException { + return Set.of(); + } + } diff --git a/source/imaer-gml/src/main/java/nl/overheid/aerius/gml/base/conversion/RemovedVehicleCodeConverter.java b/source/imaer-gml/src/main/java/nl/overheid/aerius/gml/base/conversion/RemovedVehicleCodeConverter.java new file mode 100644 index 00000000..9f5ca473 --- /dev/null +++ b/source/imaer-gml/src/main/java/nl/overheid/aerius/gml/base/conversion/RemovedVehicleCodeConverter.java @@ -0,0 +1,96 @@ +/* + * Copyright the State of the Netherlands + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see http://www.gnu.org/licenses/. + */ +package nl.overheid.aerius.gml.base.conversion; + +import java.util.List; +import java.util.Set; + +import nl.overheid.aerius.shared.domain.v2.source.ColdStartEmissionSource; +import nl.overheid.aerius.shared.domain.v2.source.EmissionSource; +import nl.overheid.aerius.shared.domain.v2.source.EmissionSourceFeature; +import nl.overheid.aerius.shared.domain.v2.source.RoadEmissionSource; +import nl.overheid.aerius.shared.domain.v2.source.road.CustomVehicles; +import nl.overheid.aerius.shared.domain.v2.source.road.SpecificVehicles; +import nl.overheid.aerius.shared.domain.v2.source.road.Vehicles; +import nl.overheid.aerius.shared.exception.AeriusException; +import nl.overheid.aerius.shared.exception.ImaerExceptionReason; + +/** + * Converts {@link SpecificVehicles} with removed vehicle codes to {@link CustomVehicles} with zero + * emissions. This handles backward compatibility when importing old GML files containing vehicle + * codes (e.g., euro classes) that have been removed from the database. + * + *

Only vehicle codes that are explicitly marked as "removed" in the database will be converted. + * Unknown codes that are not in the removed codes list will still produce validation errors. + */ +public class RemovedVehicleCodeConverter { + + private final Set removedVehicleCodes; + private final List warnings; + + public RemovedVehicleCodeConverter( + final Set removedVehicleCodes, + final List warnings) { + this.removedVehicleCodes = removedVehicleCodes; + this.warnings = warnings; + } + + /** + * Processes all emission sources and converts any SpecificVehicles with removed codes to + * CustomVehicles with zero emissions. + */ + public void convertRemovedVehicleCodes(final List emissionSourceList) { + for (final EmissionSourceFeature feature : emissionSourceList) { + final EmissionSource source = feature.getProperties(); + if (source instanceof final RoadEmissionSource roadSource) { + convertSubSources(roadSource.getSubSources(), source.getLabel()); + } else if (source instanceof final ColdStartEmissionSource coldStartSource) { + convertSubSources(coldStartSource.getSubSources(), source.getLabel()); + } + } + } + + private void convertSubSources(final List subSources, final String sourceLabel) { + for (int i = 0; i < subSources.size(); i++) { + final Vehicles vehicles = subSources.get(i); + if (vehicles instanceof final SpecificVehicles specific + && removedVehicleCodes.contains(specific.getVehicleCode())) { + subSources.set(i, convertToCustomVehicles(specific)); + addWarning(sourceLabel, specific.getVehicleCode()); + } + } + } + + private void addWarning(final String sourceLabel, final String vehicleCode) { + warnings.add( + new AeriusException( + ImaerExceptionReason.GML_UNKNOWN_MOBILE_SOURCE_CODE, sourceLabel, vehicleCode)); + } + + private static CustomVehicles convertToCustomVehicles(final SpecificVehicles specific) { + final CustomVehicles custom = new CustomVehicles(); + custom.setTimeUnit(specific.getTimeUnit()); + custom.setVehiclesPerTimeUnit(specific.getVehiclesPerTimeUnit()); + custom.setDescription("Voormalig " + specific.getVehicleCode()); + return custom; + } + + /** Checks if a given vehicle code is a removed code. */ + public boolean isRemovedVehicleCode(final String code) { + return removedVehicleCodes.contains(code); + } +} diff --git a/source/imaer-gml/src/test/java/nl/overheid/aerius/gml/base/conversion/RemovedVehicleCodeConverterTest.java b/source/imaer-gml/src/test/java/nl/overheid/aerius/gml/base/conversion/RemovedVehicleCodeConverterTest.java new file mode 100644 index 00000000..5b45c3cf --- /dev/null +++ b/source/imaer-gml/src/test/java/nl/overheid/aerius/gml/base/conversion/RemovedVehicleCodeConverterTest.java @@ -0,0 +1,157 @@ +/* + * Copyright the State of the Netherlands + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see http://www.gnu.org/licenses/. + */ +package nl.overheid.aerius.gml.base.conversion; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import nl.overheid.aerius.shared.domain.v2.base.TimeUnit; +import nl.overheid.aerius.shared.domain.v2.source.ColdStartEmissionSource; +import nl.overheid.aerius.shared.domain.v2.source.EmissionSourceFeature; +import nl.overheid.aerius.shared.domain.v2.source.SRM1RoadEmissionSource; +import nl.overheid.aerius.shared.domain.v2.source.road.CustomVehicles; +import nl.overheid.aerius.shared.domain.v2.source.road.SpecificVehicles; +import nl.overheid.aerius.shared.exception.AeriusException; +import nl.overheid.aerius.shared.exception.ImaerExceptionReason; + +class RemovedVehicleCodeConverterTest { + + private static final String REMOVED_CODE = "BABCEUR4"; + private static final String UNKNOWN_CODE = "UNKNOWN_CODE"; + private static final String SOURCE_LABEL = "Source label"; + + @Test + void testRoadSourceWithRemovedCodeIsConverted() { + final Set removedCodes = Set.of(REMOVED_CODE); + final List warnings = new ArrayList<>(); + final RemovedVehicleCodeConverter converter = + new RemovedVehicleCodeConverter(removedCodes, warnings); + + final List sources = + List.of(createRoadSourceWithSpecificVehicle(REMOVED_CODE)); + + converter.convertRemovedVehicleCodes(sources); + + // Verify the SpecificVehicles was converted to CustomVehicles + final SRM1RoadEmissionSource roadSource = + (SRM1RoadEmissionSource) sources.get(0).getProperties(); + assertEquals(1, roadSource.getSubSources().size()); + assertInstanceOf(CustomVehicles.class, roadSource.getSubSources().get(0)); + + final CustomVehicles customVehicles = (CustomVehicles) roadSource.getSubSources().get(0); + assertEquals(TimeUnit.DAY, customVehicles.getTimeUnit()); + assertEquals(100.0, customVehicles.getVehiclesPerTimeUnit()); + assertEquals("Voormalig " + REMOVED_CODE, customVehicles.getDescription()); + + // Verify warning was added + assertEquals(1, warnings.size()); + assertEquals(ImaerExceptionReason.GML_UNKNOWN_MOBILE_SOURCE_CODE, warnings.get(0).getReason()); + } + + @Test + void testRoadSourceWithUnknownCodeIsNotConverted() { + final Set removedCodes = Set.of(REMOVED_CODE); + final List warnings = new ArrayList<>(); + final RemovedVehicleCodeConverter converter = + new RemovedVehicleCodeConverter(removedCodes, warnings); + + final List sources = + List.of(createRoadSourceWithSpecificVehicle(UNKNOWN_CODE)); + + converter.convertRemovedVehicleCodes(sources); + + // Verify the SpecificVehicles was NOT converted (unknown code not in removed list) + final SRM1RoadEmissionSource roadSource = + (SRM1RoadEmissionSource) sources.get(0).getProperties(); + assertEquals(1, roadSource.getSubSources().size()); + assertInstanceOf(SpecificVehicles.class, roadSource.getSubSources().get(0)); + + // Verify no warning was added + assertEquals(0, warnings.size()); + } + + @Test + void testColdStartSourceWithRemovedCodeIsConverted() { + final Set removedCodes = Set.of(REMOVED_CODE); + final List warnings = new ArrayList<>(); + final RemovedVehicleCodeConverter converter = + new RemovedVehicleCodeConverter(removedCodes, warnings); + + final List sources = + List.of(createColdStartSourceWithSpecificVehicle(REMOVED_CODE)); + + converter.convertRemovedVehicleCodes(sources); + + // Verify the SpecificVehicles was converted to CustomVehicles + final ColdStartEmissionSource coldStartSource = + (ColdStartEmissionSource) sources.get(0).getProperties(); + assertEquals(1, coldStartSource.getSubSources().size()); + assertInstanceOf(CustomVehicles.class, coldStartSource.getSubSources().get(0)); + + // Verify warning was added + assertEquals(1, warnings.size()); + assertEquals(ImaerExceptionReason.GML_UNKNOWN_MOBILE_SOURCE_CODE, warnings.get(0).getReason()); + } + + @Test + void testIsRemovedVehicleCode() { + final Set removedCodes = Set.of(REMOVED_CODE); + final List warnings = new ArrayList<>(); + final RemovedVehicleCodeConverter converter = + new RemovedVehicleCodeConverter(removedCodes, warnings); + + assertTrue(converter.isRemovedVehicleCode(REMOVED_CODE)); + assertFalse(converter.isRemovedVehicleCode(UNKNOWN_CODE)); + } + + private EmissionSourceFeature createRoadSourceWithSpecificVehicle(final String vehicleCode) { + final SRM1RoadEmissionSource source = new SRM1RoadEmissionSource(); + source.setLabel(SOURCE_LABEL); + + final SpecificVehicles specific = new SpecificVehicles(); + specific.setVehicleCode(vehicleCode); + specific.setTimeUnit(TimeUnit.DAY); + specific.setVehiclesPerTimeUnit(100.0); + source.getSubSources().add(specific); + + final EmissionSourceFeature feature = new EmissionSourceFeature(); + feature.setProperties(source); + return feature; + } + + private EmissionSourceFeature createColdStartSourceWithSpecificVehicle(final String vehicleCode) { + final ColdStartEmissionSource source = new ColdStartEmissionSource(); + source.setLabel(SOURCE_LABEL); + + final SpecificVehicles specific = new SpecificVehicles(); + specific.setVehicleCode(vehicleCode); + specific.setTimeUnit(TimeUnit.DAY); + specific.setVehiclesPerTimeUnit(100.0); + source.getSubSources().add(specific); + + final EmissionSourceFeature feature = new EmissionSourceFeature(); + feature.setProperties(source); + return feature; + } +} From 9e65d595a7176a448342dfa6dc47ef65533a2757 Mon Sep 17 00:00:00 2001 From: JornC Date: Tue, 27 Jan 2026 17:02:40 +0100 Subject: [PATCH 2/6] Improve comments --- .../gml/base/conversion/RemovedVehicleCodeConverter.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/imaer-gml/src/main/java/nl/overheid/aerius/gml/base/conversion/RemovedVehicleCodeConverter.java b/source/imaer-gml/src/main/java/nl/overheid/aerius/gml/base/conversion/RemovedVehicleCodeConverter.java index 9f5ca473..26f32e81 100644 --- a/source/imaer-gml/src/main/java/nl/overheid/aerius/gml/base/conversion/RemovedVehicleCodeConverter.java +++ b/source/imaer-gml/src/main/java/nl/overheid/aerius/gml/base/conversion/RemovedVehicleCodeConverter.java @@ -32,9 +32,9 @@ /** * Converts {@link SpecificVehicles} with removed vehicle codes to {@link CustomVehicles} with zero * emissions. This handles backward compatibility when importing old GML files containing vehicle - * codes (e.g., euro classes) that have been removed from the database. + * codes (e.g., euro classes) that are no longer valid. * - *

Only vehicle codes that are explicitly marked as "removed" in the database will be converted. + *

Only vehicle codes that are explicitly supplied as "removed" will be converted. * Unknown codes that are not in the removed codes list will still produce validation errors. */ public class RemovedVehicleCodeConverter { From c0f0c4347954dca682de6f39c4ff117cf317beb6 Mon Sep 17 00:00:00 2001 From: JornC Date: Tue, 27 Jan 2026 17:37:53 +0100 Subject: [PATCH 3/6] Simplify code --- .../conversion/RemovedVehicleCodeConverter.java | 14 ++++---------- .../RemovedVehicleCodeConverterTest.java | 13 ------------- 2 files changed, 4 insertions(+), 23 deletions(-) diff --git a/source/imaer-gml/src/main/java/nl/overheid/aerius/gml/base/conversion/RemovedVehicleCodeConverter.java b/source/imaer-gml/src/main/java/nl/overheid/aerius/gml/base/conversion/RemovedVehicleCodeConverter.java index 26f32e81..c9c6b25c 100644 --- a/source/imaer-gml/src/main/java/nl/overheid/aerius/gml/base/conversion/RemovedVehicleCodeConverter.java +++ b/source/imaer-gml/src/main/java/nl/overheid/aerius/gml/base/conversion/RemovedVehicleCodeConverter.java @@ -20,7 +20,6 @@ import java.util.Set; import nl.overheid.aerius.shared.domain.v2.source.ColdStartEmissionSource; -import nl.overheid.aerius.shared.domain.v2.source.EmissionSource; import nl.overheid.aerius.shared.domain.v2.source.EmissionSourceFeature; import nl.overheid.aerius.shared.domain.v2.source.RoadEmissionSource; import nl.overheid.aerius.shared.domain.v2.source.road.CustomVehicles; @@ -55,11 +54,10 @@ public RemovedVehicleCodeConverter( */ public void convertRemovedVehicleCodes(final List emissionSourceList) { for (final EmissionSourceFeature feature : emissionSourceList) { - final EmissionSource source = feature.getProperties(); - if (source instanceof final RoadEmissionSource roadSource) { - convertSubSources(roadSource.getSubSources(), source.getLabel()); - } else if (source instanceof final ColdStartEmissionSource coldStartSource) { - convertSubSources(coldStartSource.getSubSources(), source.getLabel()); + if (feature.getProperties() instanceof final RoadEmissionSource roadSource) { + convertSubSources(roadSource.getSubSources(), roadSource.getLabel()); + } else if (feature.getProperties() instanceof final ColdStartEmissionSource coldStartSource) { + convertSubSources(coldStartSource.getSubSources(), coldStartSource.getLabel()); } } } @@ -89,8 +87,4 @@ private static CustomVehicles convertToCustomVehicles(final SpecificVehicles spe return custom; } - /** Checks if a given vehicle code is a removed code. */ - public boolean isRemovedVehicleCode(final String code) { - return removedVehicleCodes.contains(code); - } } diff --git a/source/imaer-gml/src/test/java/nl/overheid/aerius/gml/base/conversion/RemovedVehicleCodeConverterTest.java b/source/imaer-gml/src/test/java/nl/overheid/aerius/gml/base/conversion/RemovedVehicleCodeConverterTest.java index 5b45c3cf..99d6cede 100644 --- a/source/imaer-gml/src/test/java/nl/overheid/aerius/gml/base/conversion/RemovedVehicleCodeConverterTest.java +++ b/source/imaer-gml/src/test/java/nl/overheid/aerius/gml/base/conversion/RemovedVehicleCodeConverterTest.java @@ -22,9 +22,7 @@ import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertInstanceOf; -import static org.junit.jupiter.api.Assertions.assertTrue; import nl.overheid.aerius.shared.domain.v2.base.TimeUnit; import nl.overheid.aerius.shared.domain.v2.source.ColdStartEmissionSource; @@ -114,17 +112,6 @@ void testColdStartSourceWithRemovedCodeIsConverted() { assertEquals(ImaerExceptionReason.GML_UNKNOWN_MOBILE_SOURCE_CODE, warnings.get(0).getReason()); } - @Test - void testIsRemovedVehicleCode() { - final Set removedCodes = Set.of(REMOVED_CODE); - final List warnings = new ArrayList<>(); - final RemovedVehicleCodeConverter converter = - new RemovedVehicleCodeConverter(removedCodes, warnings); - - assertTrue(converter.isRemovedVehicleCode(REMOVED_CODE)); - assertFalse(converter.isRemovedVehicleCode(UNKNOWN_CODE)); - } - private EmissionSourceFeature createRoadSourceWithSpecificVehicle(final String vehicleCode) { final SRM1RoadEmissionSource source = new SRM1RoadEmissionSource(); source.setLabel(SOURCE_LABEL); From bfa3dfe8f30f74c1211e773a94bb0c60c223bf57 Mon Sep 17 00:00:00 2001 From: JornC Date: Wed, 28 Jan 2026 14:41:13 +0100 Subject: [PATCH 4/6] Wire up removed vehicle code conversion during GML import Call convertRemovedVehicleCodes in ImaerImporter after reading sources and before validation, enabling the euroclass removed codes feature. Includes short-circuit optimization when no removed codes are configured, and integration test to verify the wiring. --- .../RemovedVehicleCodeConverter.java | 3 + .../aerius/importer/ImaerImporter.java | 1 + .../nl/overheid/aerius/gml/AssertGML.java | 2 + .../gml/RemovedVehicleCodeImportTest.java | 73 +++++++++++++++++++ 4 files changed, 79 insertions(+) create mode 100644 source/imaer-gml/src/test/java/nl/overheid/aerius/gml/RemovedVehicleCodeImportTest.java diff --git a/source/imaer-gml/src/main/java/nl/overheid/aerius/gml/base/conversion/RemovedVehicleCodeConverter.java b/source/imaer-gml/src/main/java/nl/overheid/aerius/gml/base/conversion/RemovedVehicleCodeConverter.java index c9c6b25c..af82e0af 100644 --- a/source/imaer-gml/src/main/java/nl/overheid/aerius/gml/base/conversion/RemovedVehicleCodeConverter.java +++ b/source/imaer-gml/src/main/java/nl/overheid/aerius/gml/base/conversion/RemovedVehicleCodeConverter.java @@ -53,6 +53,9 @@ public RemovedVehicleCodeConverter( * CustomVehicles with zero emissions. */ public void convertRemovedVehicleCodes(final List emissionSourceList) { + if (removedVehicleCodes.isEmpty()) { + return; + } for (final EmissionSourceFeature feature : emissionSourceList) { if (feature.getProperties() instanceof final RoadEmissionSource roadSource) { convertSubSources(roadSource.getSubSources(), roadSource.getLabel()); diff --git a/source/imaer-gml/src/main/java/nl/overheid/aerius/importer/ImaerImporter.java b/source/imaer-gml/src/main/java/nl/overheid/aerius/importer/ImaerImporter.java index fc3e96bf..d835f28d 100644 --- a/source/imaer-gml/src/main/java/nl/overheid/aerius/importer/ImaerImporter.java +++ b/source/imaer-gml/src/main/java/nl/overheid/aerius/importer/ImaerImporter.java @@ -198,6 +198,7 @@ protected GMLReader createGMLReader(final InputStream inputStream, final Set importOptions, final ImportParcel result) throws AeriusException { if (ImportOption.INCLUDE_SOURCES.in(importOptions)) { final List sources = reader.readEmissionSourceList(); + reader.convertRemovedVehicleCodes(sources); if (ImportOption.VALIDATE_SOURCES.in(importOptions)) { EmissionSourceValidator.validateSources(sources, result.getExceptions(), result.getWarnings(), factory.createValidationHelper()); diff --git a/source/imaer-gml/src/test/java/nl/overheid/aerius/gml/AssertGML.java b/source/imaer-gml/src/test/java/nl/overheid/aerius/gml/AssertGML.java index ee34af4e..461869d1 100644 --- a/source/imaer-gml/src/test/java/nl/overheid/aerius/gml/AssertGML.java +++ b/source/imaer-gml/src/test/java/nl/overheid/aerius/gml/AssertGML.java @@ -43,6 +43,7 @@ import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.Set; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -255,6 +256,7 @@ static GMLHelper mockGMLHelper(final CharacteristicsType ct) throws AeriusExcept when(gmlHelper.getLegacyMobileSourceOffRoadConversions()).thenReturn(TestValidationAndEmissionHelper.legacyMobileSourceOffRoadConversions()); when(gmlHelper.getLegacyPlanConversions()).thenReturn(TestValidationAndEmissionHelper.legacyPlanConversions()); when(gmlHelper.getLegacyFarmLodgingConversions()).thenReturn(TestValidationAndEmissionHelper.legacyFarmLodgingConversions()); + when(gmlHelper.getRemovedVehicleCodes()).thenReturn(Set.of()); when(gmlHelper.determineDefaultCharacteristicsBySectorId(anyInt(), any())).thenReturn(determineDefaultCharacteristics(ct)); when(gmlHelper.getValidationHelper()).thenReturn(validationAndEmissionHelper); when(gmlHelper.getDefaultSector()).thenReturn(new Sector(GMLTestDomain.DEFAULT_SECTOR_ID, SectorGroup.INDUSTRY, "")); diff --git a/source/imaer-gml/src/test/java/nl/overheid/aerius/gml/RemovedVehicleCodeImportTest.java b/source/imaer-gml/src/test/java/nl/overheid/aerius/gml/RemovedVehicleCodeImportTest.java new file mode 100644 index 00000000..d47ff14b --- /dev/null +++ b/source/imaer-gml/src/test/java/nl/overheid/aerius/gml/RemovedVehicleCodeImportTest.java @@ -0,0 +1,73 @@ +/* + * Copyright the State of the Netherlands + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see http://www.gnu.org/licenses/. + */ +package nl.overheid.aerius.gml; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.when; + +import java.io.IOException; +import java.io.InputStream; +import java.util.EnumSet; +import java.util.Set; + +import org.junit.jupiter.api.Test; + +import nl.overheid.aerius.gml.base.GMLHelper; +import nl.overheid.aerius.importer.ImaerImporter; +import nl.overheid.aerius.importer.ImportOption; +import nl.overheid.aerius.shared.domain.v2.importer.ImportParcel; +import nl.overheid.aerius.shared.domain.v2.source.SRM2RoadEmissionSource; +import nl.overheid.aerius.shared.domain.v2.source.road.CustomVehicles; +import nl.overheid.aerius.shared.exception.AeriusException; +import nl.overheid.aerius.shared.exception.ImaerExceptionReason; + +/** + * Integration test verifying that ImaerImporter calls convertRemovedVehicleCodes during import. + */ +class RemovedVehicleCodeImportTest { + + private static final String REMOVED_CODE = "BA-B-E3"; + + @Test + void testRemovedVehicleCodeIsConvertedDuringImport() throws IOException, AeriusException { + final GMLHelper mockHelper = AssertGML.mockGMLHelper(); + when(mockHelper.getRemovedVehicleCodes()).thenReturn(Set.of(REMOVED_CODE)); + + // Create fresh factory with our mock helper (not cached) so getRemovedVehicleCodes is used + final GMLReaderFactory factory = new GMLReaderFactory(mockHelper); + final ImaerImporter importer = new ImaerImporter(mockHelper, factory); + final ImportParcel result = new ImportParcel(); + + try (final InputStream inputStream = AssertGML.getFileInputStream( + AssertGML.PATH_LATEST_VERSION + "roundtrip", "road_specific_and_custom")) { + importer.importStream(inputStream, EnumSet.of(ImportOption.INCLUDE_SOURCES), result); + } + + assertEquals(0, result.getExceptions().size(), "Expected no exceptions"); + assertTrue(result.getWarnings().stream() + .anyMatch(w -> w.getReason() == ImaerExceptionReason.GML_UNKNOWN_MOBILE_SOURCE_CODE), + "Expected warning for removed vehicle code"); + + final SRM2RoadEmissionSource roadSource = + (SRM2RoadEmissionSource) result.getSituation().getEmissionSourcesList().get(0).getProperties(); + final CustomVehicles converted = assertInstanceOf(CustomVehicles.class, roadSource.getSubSources().get(0)); + assertEquals("Voormalig " + REMOVED_CODE, converted.getDescription()); + } + +} From b5071d1b8b9b9e56385a5cc82d613eb304af4ef1 Mon Sep 17 00:00:00 2001 From: JornC Date: Wed, 28 Jan 2026 18:08:17 +0100 Subject: [PATCH 5/6] Handle removed vehicle codes during GML parsing Move removed vehicle code handling from post-processing to parsing. When a removed code is encountered in GML2VehicleUtil, the specific vehicle is converted to a CustomVehicle with zero emissions and a warning is added. - Add RemovedVehicleUtil for converting specific to custom vehicles - Add checkRemovedCode() to GMLConversionData - Change getRemovedCodes() to return Map> - Remove post-processing RemovedVehicleCodeConverter --- .../nl/overheid/aerius/gml/GMLReader.java | 13 -- .../aerius/gml/base/GMLConversionData.java | 17 ++- .../gml/base/GMLLegacyCodesSupplier.java | 10 +- .../RemovedVehicleCodeConverter.java | 93 ----------- .../aerius/gml/base/source/road/GML2Road.java | 2 +- .../gml/base/source/road/GML2VehicleUtil.java | 11 +- .../base/source/road/RemovedVehicleUtil.java | 46 ++++++ .../gml/base/source/road/v40/GML2SRMRoad.java | 13 +- .../aerius/importer/ImaerImporter.java | 1 - .../nl/overheid/aerius/gml/AssertGML.java | 2 +- .../gml/RemovedVehicleCodeImportTest.java | 4 +- .../RemovedVehicleCodeConverterTest.java | 144 ------------------ .../base/source/road/GML2VehicleUtilTest.java | 90 +++++++++++ .../source/road/RemovedVehicleUtilTest.java | 78 ++++++++++ 14 files changed, 254 insertions(+), 270 deletions(-) delete mode 100644 source/imaer-gml/src/main/java/nl/overheid/aerius/gml/base/conversion/RemovedVehicleCodeConverter.java create mode 100644 source/imaer-gml/src/main/java/nl/overheid/aerius/gml/base/source/road/RemovedVehicleUtil.java delete mode 100644 source/imaer-gml/src/test/java/nl/overheid/aerius/gml/base/conversion/RemovedVehicleCodeConverterTest.java create mode 100644 source/imaer-gml/src/test/java/nl/overheid/aerius/gml/base/source/road/GML2VehicleUtilTest.java create mode 100644 source/imaer-gml/src/test/java/nl/overheid/aerius/gml/base/source/road/RemovedVehicleUtilTest.java diff --git a/source/imaer-gml/src/main/java/nl/overheid/aerius/gml/GMLReader.java b/source/imaer-gml/src/main/java/nl/overheid/aerius/gml/GMLReader.java index 6a80849e..35683d95 100644 --- a/source/imaer-gml/src/main/java/nl/overheid/aerius/gml/GMLReader.java +++ b/source/imaer-gml/src/main/java/nl/overheid/aerius/gml/GMLReader.java @@ -25,7 +25,6 @@ import nl.overheid.aerius.gml.base.GMLHelper; import nl.overheid.aerius.gml.base.GMLVersionReader; import nl.overheid.aerius.gml.base.GMLVersionReaderFactory; -import nl.overheid.aerius.gml.base.conversion.RemovedVehicleCodeConverter; import nl.overheid.aerius.shared.domain.Theme; import nl.overheid.aerius.shared.domain.calculation.CalculationSetOptions; import nl.overheid.aerius.shared.domain.scenario.SituationType; @@ -110,18 +109,6 @@ public void enforceEmissions(final List emissionSourceLis gmlHelper.enforceEmissions(year, emissionSourceList); } - /** - * Converts any SpecificVehicles with removed vehicle codes to CustomVehicles with zero emissions. - * This should be called after reading emission sources and before validation. - * - * @param emissionSourceList List of sources to convert - * @throws AeriusException error - */ - public void convertRemovedVehicleCodes(final List emissionSourceList) throws AeriusException { - final RemovedVehicleCodeConverter converter = conversionData.createRemovedVehicleCodeConverter(); - converter.convertRemovedVehicleCodes(emissionSourceList); - } - /** * Gets the name from the feature collection. */ diff --git a/source/imaer-gml/src/main/java/nl/overheid/aerius/gml/base/GMLConversionData.java b/source/imaer-gml/src/main/java/nl/overheid/aerius/gml/base/GMLConversionData.java index 74f5c7f4..671c4b17 100644 --- a/source/imaer-gml/src/main/java/nl/overheid/aerius/gml/base/GMLConversionData.java +++ b/source/imaer-gml/src/main/java/nl/overheid/aerius/gml/base/GMLConversionData.java @@ -28,7 +28,6 @@ import nl.overheid.aerius.gml.base.conversion.FarmLodgingConversion; import nl.overheid.aerius.gml.base.conversion.MobileSourceOffRoadConversion; import nl.overheid.aerius.gml.base.conversion.PlanConversion; -import nl.overheid.aerius.gml.base.conversion.RemovedVehicleCodeConverter; import nl.overheid.aerius.gml.base.source.ship.v31.InlandShippingUtil; import nl.overheid.aerius.shared.domain.Substance; import nl.overheid.aerius.shared.domain.v2.building.BuildingFeature; @@ -249,13 +248,19 @@ public S determineDefaultCharacteristicsBySect } /** - * Creates a converter that handles removed vehicle codes by converting them to custom vehicles - * with zero emissions. + * Checks if the given code is a removed code and adds a warning if so. * - * @return the removed vehicle code converter + * @param type the type of legacy code + * @param code the code to check + * @param sourceLabel the label of the source for warning messages + * @return true if the code is a removed code, false otherwise * @throws AeriusException if the removed codes cannot be retrieved */ - public RemovedVehicleCodeConverter createRemovedVehicleCodeConverter() throws AeriusException { - return new RemovedVehicleCodeConverter(helper.getRemovedVehicleCodes(), warnings); + public boolean warnIfRemovedCode(final GMLLegacyCodeType type, final String code, final String sourceLabel) throws AeriusException { + if (helper.getRemovedCodes().getOrDefault(type, Set.of()).contains(code)) { + warnings.add(new AeriusException(ImaerExceptionReason.GML_UNKNOWN_MOBILE_SOURCE_CODE, sourceLabel, code)); + return true; + } + return false; } } diff --git a/source/imaer-gml/src/main/java/nl/overheid/aerius/gml/base/GMLLegacyCodesSupplier.java b/source/imaer-gml/src/main/java/nl/overheid/aerius/gml/base/GMLLegacyCodesSupplier.java index 4e1b2771..a0ccd014 100644 --- a/source/imaer-gml/src/main/java/nl/overheid/aerius/gml/base/GMLLegacyCodesSupplier.java +++ b/source/imaer-gml/src/main/java/nl/overheid/aerius/gml/base/GMLLegacyCodesSupplier.java @@ -71,14 +71,14 @@ default Map getLegacyFarmLodgingConversions() thr } /** - * Returns a set of removed vehicle codes. - * Sources with these codes will be converted to custom vehicles with zero emissions during import. + * Returns a map of removed codes by type. + * Sources with these codes will be converted to alternative representations during import. * - * @return set of removed vehicle codes + * @return map of code type to set of removed codes * @throws AeriusException */ - default Set getRemovedVehicleCodes() throws AeriusException { - return Set.of(); + default Map> getRemovedCodes() throws AeriusException { + return Map.of(); } } diff --git a/source/imaer-gml/src/main/java/nl/overheid/aerius/gml/base/conversion/RemovedVehicleCodeConverter.java b/source/imaer-gml/src/main/java/nl/overheid/aerius/gml/base/conversion/RemovedVehicleCodeConverter.java deleted file mode 100644 index af82e0af..00000000 --- a/source/imaer-gml/src/main/java/nl/overheid/aerius/gml/base/conversion/RemovedVehicleCodeConverter.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright the State of the Netherlands - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see http://www.gnu.org/licenses/. - */ -package nl.overheid.aerius.gml.base.conversion; - -import java.util.List; -import java.util.Set; - -import nl.overheid.aerius.shared.domain.v2.source.ColdStartEmissionSource; -import nl.overheid.aerius.shared.domain.v2.source.EmissionSourceFeature; -import nl.overheid.aerius.shared.domain.v2.source.RoadEmissionSource; -import nl.overheid.aerius.shared.domain.v2.source.road.CustomVehicles; -import nl.overheid.aerius.shared.domain.v2.source.road.SpecificVehicles; -import nl.overheid.aerius.shared.domain.v2.source.road.Vehicles; -import nl.overheid.aerius.shared.exception.AeriusException; -import nl.overheid.aerius.shared.exception.ImaerExceptionReason; - -/** - * Converts {@link SpecificVehicles} with removed vehicle codes to {@link CustomVehicles} with zero - * emissions. This handles backward compatibility when importing old GML files containing vehicle - * codes (e.g., euro classes) that are no longer valid. - * - *

Only vehicle codes that are explicitly supplied as "removed" will be converted. - * Unknown codes that are not in the removed codes list will still produce validation errors. - */ -public class RemovedVehicleCodeConverter { - - private final Set removedVehicleCodes; - private final List warnings; - - public RemovedVehicleCodeConverter( - final Set removedVehicleCodes, - final List warnings) { - this.removedVehicleCodes = removedVehicleCodes; - this.warnings = warnings; - } - - /** - * Processes all emission sources and converts any SpecificVehicles with removed codes to - * CustomVehicles with zero emissions. - */ - public void convertRemovedVehicleCodes(final List emissionSourceList) { - if (removedVehicleCodes.isEmpty()) { - return; - } - for (final EmissionSourceFeature feature : emissionSourceList) { - if (feature.getProperties() instanceof final RoadEmissionSource roadSource) { - convertSubSources(roadSource.getSubSources(), roadSource.getLabel()); - } else if (feature.getProperties() instanceof final ColdStartEmissionSource coldStartSource) { - convertSubSources(coldStartSource.getSubSources(), coldStartSource.getLabel()); - } - } - } - - private void convertSubSources(final List subSources, final String sourceLabel) { - for (int i = 0; i < subSources.size(); i++) { - final Vehicles vehicles = subSources.get(i); - if (vehicles instanceof final SpecificVehicles specific - && removedVehicleCodes.contains(specific.getVehicleCode())) { - subSources.set(i, convertToCustomVehicles(specific)); - addWarning(sourceLabel, specific.getVehicleCode()); - } - } - } - - private void addWarning(final String sourceLabel, final String vehicleCode) { - warnings.add( - new AeriusException( - ImaerExceptionReason.GML_UNKNOWN_MOBILE_SOURCE_CODE, sourceLabel, vehicleCode)); - } - - private static CustomVehicles convertToCustomVehicles(final SpecificVehicles specific) { - final CustomVehicles custom = new CustomVehicles(); - custom.setTimeUnit(specific.getTimeUnit()); - custom.setVehiclesPerTimeUnit(specific.getVehiclesPerTimeUnit()); - custom.setDescription("Voormalig " + specific.getVehicleCode()); - return custom; - } - -} diff --git a/source/imaer-gml/src/main/java/nl/overheid/aerius/gml/base/source/road/GML2Road.java b/source/imaer-gml/src/main/java/nl/overheid/aerius/gml/base/source/road/GML2Road.java index 7f990268..cb281ea2 100644 --- a/source/imaer-gml/src/main/java/nl/overheid/aerius/gml/base/source/road/GML2Road.java +++ b/source/imaer-gml/src/main/java/nl/overheid/aerius/gml/base/source/road/GML2Road.java @@ -70,7 +70,7 @@ public S convert(final T source) throws AeriusException { protected abstract void setOptionalVariables(T source, S emissionSource) throws AeriusException; protected void addVehicleEmissions(final List addToVehicles, final T source, final IsGmlProperty vp, - final List mergingStandardVehicles) { + final List mergingStandardVehicles) throws AeriusException { final IsGmlVehicle av = vp.getProperty(); if (av instanceof final IsGmlStandardVehicle standardVehicle) { addEmissionValues(addToVehicles, source, standardVehicle, mergingStandardVehicles); diff --git a/source/imaer-gml/src/main/java/nl/overheid/aerius/gml/base/source/road/GML2VehicleUtil.java b/source/imaer-gml/src/main/java/nl/overheid/aerius/gml/base/source/road/GML2VehicleUtil.java index 5b9d604f..38d8422f 100644 --- a/source/imaer-gml/src/main/java/nl/overheid/aerius/gml/base/source/road/GML2VehicleUtil.java +++ b/source/imaer-gml/src/main/java/nl/overheid/aerius/gml/base/source/road/GML2VehicleUtil.java @@ -27,6 +27,7 @@ import nl.overheid.aerius.shared.domain.v2.source.road.CustomVehicles; import nl.overheid.aerius.shared.domain.v2.source.road.SpecificVehicles; import nl.overheid.aerius.shared.domain.v2.source.road.Vehicles; +import nl.overheid.aerius.shared.exception.AeriusException; /** * @@ -38,9 +39,15 @@ private GML2VehicleUtil() { } static void addEmissionValuesSpecific(final List addToVehicles, final IsGmlEmissionSource source, final IsGmlSpecificVehicle sv, - final GMLConversionData conversionData) { - final SpecificVehicles vse = new SpecificVehicles(); + final GMLConversionData conversionData) throws AeriusException { final String vehicleCode = conversionData.getCode(GMLLegacyCodeType.ON_ROAD_MOBILE_SOURCE, sv.getCode(), source.getLabel()); + + if (conversionData.warnIfRemovedCode(GMLLegacyCodeType.ON_ROAD_MOBILE_SOURCE, vehicleCode, source.getLabel())) { + addToVehicles.add(RemovedVehicleUtil.toCustomVehicles(sv, vehicleCode)); + return; + } + + final SpecificVehicles vse = new SpecificVehicles(); vse.setVehicleCode(vehicleCode); vse.setTimeUnit(TimeUnit.valueOf(sv.getTimeUnit().name())); vse.setVehiclesPerTimeUnit(sv.getVehiclesPerTimeUnit()); diff --git a/source/imaer-gml/src/main/java/nl/overheid/aerius/gml/base/source/road/RemovedVehicleUtil.java b/source/imaer-gml/src/main/java/nl/overheid/aerius/gml/base/source/road/RemovedVehicleUtil.java new file mode 100644 index 00000000..7a43b9a9 --- /dev/null +++ b/source/imaer-gml/src/main/java/nl/overheid/aerius/gml/base/source/road/RemovedVehicleUtil.java @@ -0,0 +1,46 @@ +/* + * Copyright the State of the Netherlands + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see http://www.gnu.org/licenses/. + */ +package nl.overheid.aerius.gml.base.source.road; + +import nl.overheid.aerius.shared.domain.v2.base.TimeUnit; +import nl.overheid.aerius.shared.domain.v2.source.road.CustomVehicles; + +/** + * Utility for converting removed vehicle codes to custom vehicles. + */ +public final class RemovedVehicleUtil { + + private RemovedVehicleUtil() { + // Util class + } + + /** + * Converts a specific vehicle with a removed code to a custom vehicle with zero emissions. + * + * @param sv the specific vehicle to convert + * @param vehicleCode the removed vehicle code + * @return a custom vehicle preserving the vehicle count and time unit + */ + public static CustomVehicles toCustomVehicles(final IsGmlSpecificVehicle sv, final String vehicleCode) { + final CustomVehicles custom = new CustomVehicles(); + custom.setTimeUnit(TimeUnit.valueOf(sv.getTimeUnit().name())); + custom.setVehiclesPerTimeUnit(sv.getVehiclesPerTimeUnit()); + custom.setDescription("Voormalig " + vehicleCode); + return custom; + } + +} diff --git a/source/imaer-gml/src/main/java/nl/overheid/aerius/gml/base/source/road/v40/GML2SRMRoad.java b/source/imaer-gml/src/main/java/nl/overheid/aerius/gml/base/source/road/v40/GML2SRMRoad.java index 852f1f9c..9f7f2c87 100644 --- a/source/imaer-gml/src/main/java/nl/overheid/aerius/gml/base/source/road/v40/GML2SRMRoad.java +++ b/source/imaer-gml/src/main/java/nl/overheid/aerius/gml/base/source/road/v40/GML2SRMRoad.java @@ -29,6 +29,7 @@ import nl.overheid.aerius.gml.base.source.road.IsGmlCustomVehicle; import nl.overheid.aerius.gml.base.source.road.IsGmlSpecificVehicle; import nl.overheid.aerius.gml.base.source.road.IsGmlVehicle; +import nl.overheid.aerius.gml.base.source.road.RemovedVehicleUtil; import nl.overheid.aerius.shared.domain.v2.base.TimeUnit; import nl.overheid.aerius.shared.domain.v2.source.RoadEmissionSource; import nl.overheid.aerius.shared.domain.v2.source.road.CustomVehicles; @@ -80,7 +81,7 @@ public S convert(final T source) throws AeriusException { protected abstract void setOptionalVariables(T source, S emissionSource) throws AeriusException; protected void addVehicleEmissions(final List addToVehicles, final T source, final IsGmlProperty vp, - final List mergingStandardVehicles) { + final List mergingStandardVehicles) throws AeriusException { final IsGmlVehicle av = vp.getProperty(); if (av instanceof IsGmlStandardVehicle) { addEmissionValues(addToVehicles, source, (IsGmlStandardVehicle) av, mergingStandardVehicles); @@ -120,9 +121,15 @@ protected Optional findExistingMatch(final IsGmlStandardVehicl .findFirst(); } - protected void addEmissionValues(final List addToVehicles, final T source, final IsGmlSpecificVehicle sv) { - final SpecificVehicles vse = new SpecificVehicles(); + protected void addEmissionValues(final List addToVehicles, final T source, final IsGmlSpecificVehicle sv) throws AeriusException { final String vehicleCode = getConversionData().getCode(GMLLegacyCodeType.ON_ROAD_MOBILE_SOURCE, sv.getCode(), source.getLabel()); + + if (getConversionData().warnIfRemovedCode(GMLLegacyCodeType.ON_ROAD_MOBILE_SOURCE, vehicleCode, source.getLabel())) { + addToVehicles.add(RemovedVehicleUtil.toCustomVehicles(sv, vehicleCode)); + return; + } + + final SpecificVehicles vse = new SpecificVehicles(); vse.setVehicleCode(vehicleCode); vse.setTimeUnit(TimeUnit.valueOf(sv.getTimeUnit().name())); vse.setVehiclesPerTimeUnit(sv.getVehiclesPerTimeUnit()); diff --git a/source/imaer-gml/src/main/java/nl/overheid/aerius/importer/ImaerImporter.java b/source/imaer-gml/src/main/java/nl/overheid/aerius/importer/ImaerImporter.java index d835f28d..fc3e96bf 100644 --- a/source/imaer-gml/src/main/java/nl/overheid/aerius/importer/ImaerImporter.java +++ b/source/imaer-gml/src/main/java/nl/overheid/aerius/importer/ImaerImporter.java @@ -198,7 +198,6 @@ protected GMLReader createGMLReader(final InputStream inputStream, final Set importOptions, final ImportParcel result) throws AeriusException { if (ImportOption.INCLUDE_SOURCES.in(importOptions)) { final List sources = reader.readEmissionSourceList(); - reader.convertRemovedVehicleCodes(sources); if (ImportOption.VALIDATE_SOURCES.in(importOptions)) { EmissionSourceValidator.validateSources(sources, result.getExceptions(), result.getWarnings(), factory.createValidationHelper()); diff --git a/source/imaer-gml/src/test/java/nl/overheid/aerius/gml/AssertGML.java b/source/imaer-gml/src/test/java/nl/overheid/aerius/gml/AssertGML.java index 461869d1..21c1fcde 100644 --- a/source/imaer-gml/src/test/java/nl/overheid/aerius/gml/AssertGML.java +++ b/source/imaer-gml/src/test/java/nl/overheid/aerius/gml/AssertGML.java @@ -256,7 +256,7 @@ static GMLHelper mockGMLHelper(final CharacteristicsType ct) throws AeriusExcept when(gmlHelper.getLegacyMobileSourceOffRoadConversions()).thenReturn(TestValidationAndEmissionHelper.legacyMobileSourceOffRoadConversions()); when(gmlHelper.getLegacyPlanConversions()).thenReturn(TestValidationAndEmissionHelper.legacyPlanConversions()); when(gmlHelper.getLegacyFarmLodgingConversions()).thenReturn(TestValidationAndEmissionHelper.legacyFarmLodgingConversions()); - when(gmlHelper.getRemovedVehicleCodes()).thenReturn(Set.of()); + when(gmlHelper.getRemovedCodes()).thenReturn(Map.of()); when(gmlHelper.determineDefaultCharacteristicsBySectorId(anyInt(), any())).thenReturn(determineDefaultCharacteristics(ct)); when(gmlHelper.getValidationHelper()).thenReturn(validationAndEmissionHelper); when(gmlHelper.getDefaultSector()).thenReturn(new Sector(GMLTestDomain.DEFAULT_SECTOR_ID, SectorGroup.INDUSTRY, "")); diff --git a/source/imaer-gml/src/test/java/nl/overheid/aerius/gml/RemovedVehicleCodeImportTest.java b/source/imaer-gml/src/test/java/nl/overheid/aerius/gml/RemovedVehicleCodeImportTest.java index d47ff14b..a83bd545 100644 --- a/source/imaer-gml/src/test/java/nl/overheid/aerius/gml/RemovedVehicleCodeImportTest.java +++ b/source/imaer-gml/src/test/java/nl/overheid/aerius/gml/RemovedVehicleCodeImportTest.java @@ -24,11 +24,13 @@ import java.io.IOException; import java.io.InputStream; import java.util.EnumSet; +import java.util.Map; import java.util.Set; import org.junit.jupiter.api.Test; import nl.overheid.aerius.gml.base.GMLHelper; +import nl.overheid.aerius.gml.base.GMLLegacyCodeConverter.GMLLegacyCodeType; import nl.overheid.aerius.importer.ImaerImporter; import nl.overheid.aerius.importer.ImportOption; import nl.overheid.aerius.shared.domain.v2.importer.ImportParcel; @@ -47,7 +49,7 @@ class RemovedVehicleCodeImportTest { @Test void testRemovedVehicleCodeIsConvertedDuringImport() throws IOException, AeriusException { final GMLHelper mockHelper = AssertGML.mockGMLHelper(); - when(mockHelper.getRemovedVehicleCodes()).thenReturn(Set.of(REMOVED_CODE)); + when(mockHelper.getRemovedCodes()).thenReturn(Map.of(GMLLegacyCodeType.ON_ROAD_MOBILE_SOURCE, Set.of(REMOVED_CODE))); // Create fresh factory with our mock helper (not cached) so getRemovedVehicleCodes is used final GMLReaderFactory factory = new GMLReaderFactory(mockHelper); diff --git a/source/imaer-gml/src/test/java/nl/overheid/aerius/gml/base/conversion/RemovedVehicleCodeConverterTest.java b/source/imaer-gml/src/test/java/nl/overheid/aerius/gml/base/conversion/RemovedVehicleCodeConverterTest.java deleted file mode 100644 index 99d6cede..00000000 --- a/source/imaer-gml/src/test/java/nl/overheid/aerius/gml/base/conversion/RemovedVehicleCodeConverterTest.java +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright the State of the Netherlands - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see http://www.gnu.org/licenses/. - */ -package nl.overheid.aerius.gml.base.conversion; - -import java.util.ArrayList; -import java.util.List; -import java.util.Set; - -import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertInstanceOf; - -import nl.overheid.aerius.shared.domain.v2.base.TimeUnit; -import nl.overheid.aerius.shared.domain.v2.source.ColdStartEmissionSource; -import nl.overheid.aerius.shared.domain.v2.source.EmissionSourceFeature; -import nl.overheid.aerius.shared.domain.v2.source.SRM1RoadEmissionSource; -import nl.overheid.aerius.shared.domain.v2.source.road.CustomVehicles; -import nl.overheid.aerius.shared.domain.v2.source.road.SpecificVehicles; -import nl.overheid.aerius.shared.exception.AeriusException; -import nl.overheid.aerius.shared.exception.ImaerExceptionReason; - -class RemovedVehicleCodeConverterTest { - - private static final String REMOVED_CODE = "BABCEUR4"; - private static final String UNKNOWN_CODE = "UNKNOWN_CODE"; - private static final String SOURCE_LABEL = "Source label"; - - @Test - void testRoadSourceWithRemovedCodeIsConverted() { - final Set removedCodes = Set.of(REMOVED_CODE); - final List warnings = new ArrayList<>(); - final RemovedVehicleCodeConverter converter = - new RemovedVehicleCodeConverter(removedCodes, warnings); - - final List sources = - List.of(createRoadSourceWithSpecificVehicle(REMOVED_CODE)); - - converter.convertRemovedVehicleCodes(sources); - - // Verify the SpecificVehicles was converted to CustomVehicles - final SRM1RoadEmissionSource roadSource = - (SRM1RoadEmissionSource) sources.get(0).getProperties(); - assertEquals(1, roadSource.getSubSources().size()); - assertInstanceOf(CustomVehicles.class, roadSource.getSubSources().get(0)); - - final CustomVehicles customVehicles = (CustomVehicles) roadSource.getSubSources().get(0); - assertEquals(TimeUnit.DAY, customVehicles.getTimeUnit()); - assertEquals(100.0, customVehicles.getVehiclesPerTimeUnit()); - assertEquals("Voormalig " + REMOVED_CODE, customVehicles.getDescription()); - - // Verify warning was added - assertEquals(1, warnings.size()); - assertEquals(ImaerExceptionReason.GML_UNKNOWN_MOBILE_SOURCE_CODE, warnings.get(0).getReason()); - } - - @Test - void testRoadSourceWithUnknownCodeIsNotConverted() { - final Set removedCodes = Set.of(REMOVED_CODE); - final List warnings = new ArrayList<>(); - final RemovedVehicleCodeConverter converter = - new RemovedVehicleCodeConverter(removedCodes, warnings); - - final List sources = - List.of(createRoadSourceWithSpecificVehicle(UNKNOWN_CODE)); - - converter.convertRemovedVehicleCodes(sources); - - // Verify the SpecificVehicles was NOT converted (unknown code not in removed list) - final SRM1RoadEmissionSource roadSource = - (SRM1RoadEmissionSource) sources.get(0).getProperties(); - assertEquals(1, roadSource.getSubSources().size()); - assertInstanceOf(SpecificVehicles.class, roadSource.getSubSources().get(0)); - - // Verify no warning was added - assertEquals(0, warnings.size()); - } - - @Test - void testColdStartSourceWithRemovedCodeIsConverted() { - final Set removedCodes = Set.of(REMOVED_CODE); - final List warnings = new ArrayList<>(); - final RemovedVehicleCodeConverter converter = - new RemovedVehicleCodeConverter(removedCodes, warnings); - - final List sources = - List.of(createColdStartSourceWithSpecificVehicle(REMOVED_CODE)); - - converter.convertRemovedVehicleCodes(sources); - - // Verify the SpecificVehicles was converted to CustomVehicles - final ColdStartEmissionSource coldStartSource = - (ColdStartEmissionSource) sources.get(0).getProperties(); - assertEquals(1, coldStartSource.getSubSources().size()); - assertInstanceOf(CustomVehicles.class, coldStartSource.getSubSources().get(0)); - - // Verify warning was added - assertEquals(1, warnings.size()); - assertEquals(ImaerExceptionReason.GML_UNKNOWN_MOBILE_SOURCE_CODE, warnings.get(0).getReason()); - } - - private EmissionSourceFeature createRoadSourceWithSpecificVehicle(final String vehicleCode) { - final SRM1RoadEmissionSource source = new SRM1RoadEmissionSource(); - source.setLabel(SOURCE_LABEL); - - final SpecificVehicles specific = new SpecificVehicles(); - specific.setVehicleCode(vehicleCode); - specific.setTimeUnit(TimeUnit.DAY); - specific.setVehiclesPerTimeUnit(100.0); - source.getSubSources().add(specific); - - final EmissionSourceFeature feature = new EmissionSourceFeature(); - feature.setProperties(source); - return feature; - } - - private EmissionSourceFeature createColdStartSourceWithSpecificVehicle(final String vehicleCode) { - final ColdStartEmissionSource source = new ColdStartEmissionSource(); - source.setLabel(SOURCE_LABEL); - - final SpecificVehicles specific = new SpecificVehicles(); - specific.setVehicleCode(vehicleCode); - specific.setTimeUnit(TimeUnit.DAY); - specific.setVehiclesPerTimeUnit(100.0); - source.getSubSources().add(specific); - - final EmissionSourceFeature feature = new EmissionSourceFeature(); - feature.setProperties(source); - return feature; - } -} diff --git a/source/imaer-gml/src/test/java/nl/overheid/aerius/gml/base/source/road/GML2VehicleUtilTest.java b/source/imaer-gml/src/test/java/nl/overheid/aerius/gml/base/source/road/GML2VehicleUtilTest.java new file mode 100644 index 00000000..76cdd9d6 --- /dev/null +++ b/source/imaer-gml/src/test/java/nl/overheid/aerius/gml/base/source/road/GML2VehicleUtilTest.java @@ -0,0 +1,90 @@ +/* + * Copyright the State of the Netherlands + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see http://www.gnu.org/licenses/. + */ +package nl.overheid.aerius.gml.base.source.road; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.util.ArrayList; +import java.util.List; + +import org.junit.jupiter.api.Test; + +import nl.overheid.aerius.gml.base.GMLConversionData; +import nl.overheid.aerius.gml.base.GMLLegacyCodeConverter.GMLLegacyCodeType; +import nl.overheid.aerius.gml.base.source.IsGmlEmissionSource; +import nl.overheid.aerius.gml.base.source.IsGmlTimeUnit; +import nl.overheid.aerius.shared.domain.v2.source.road.CustomVehicles; +import nl.overheid.aerius.shared.domain.v2.source.road.SpecificVehicles; +import nl.overheid.aerius.shared.domain.v2.source.road.Vehicles; +import nl.overheid.aerius.shared.exception.AeriusException; + +class GML2VehicleUtilTest { + + private static final String REMOVED_CODE = "BABCEUR4"; + private static final String VALID_CODE = "VALID_CODE"; + private static final String SOURCE_LABEL = "Test source"; + + @Test + void testRemovedCodeRoutesToCustomVehicles() throws AeriusException { + final GMLConversionData conversionData = mock(GMLConversionData.class); + when(conversionData.getCode(GMLLegacyCodeType.ON_ROAD_MOBILE_SOURCE, REMOVED_CODE, SOURCE_LABEL)) + .thenReturn(REMOVED_CODE); + when(conversionData.warnIfRemovedCode(GMLLegacyCodeType.ON_ROAD_MOBILE_SOURCE, REMOVED_CODE, SOURCE_LABEL)) + .thenReturn(true); + + final List vehicles = new ArrayList<>(); + GML2VehicleUtil.addEmissionValuesSpecific(vehicles, mockSource(), mockSpecificVehicle(REMOVED_CODE), conversionData); + + assertEquals(1, vehicles.size()); + assertInstanceOf(CustomVehicles.class, vehicles.get(0)); + } + + @Test + void testValidCodeRoutesToSpecificVehicles() throws AeriusException { + final GMLConversionData conversionData = mock(GMLConversionData.class); + when(conversionData.getCode(GMLLegacyCodeType.ON_ROAD_MOBILE_SOURCE, VALID_CODE, SOURCE_LABEL)) + .thenReturn(VALID_CODE); + when(conversionData.warnIfRemovedCode(GMLLegacyCodeType.ON_ROAD_MOBILE_SOURCE, VALID_CODE, SOURCE_LABEL)) + .thenReturn(false); + + final List vehicles = new ArrayList<>(); + GML2VehicleUtil.addEmissionValuesSpecific(vehicles, mockSource(), mockSpecificVehicle(VALID_CODE), conversionData); + + assertEquals(1, vehicles.size()); + assertInstanceOf(SpecificVehicles.class, vehicles.get(0)); + } + + private IsGmlEmissionSource mockSource() { + final IsGmlEmissionSource source = mock(IsGmlEmissionSource.class); + when(source.getLabel()).thenReturn(SOURCE_LABEL); + return source; + } + + private IsGmlSpecificVehicle mockSpecificVehicle(final String code) { + final IsGmlSpecificVehicle vehicle = mock(IsGmlSpecificVehicle.class); + when(vehicle.getCode()).thenReturn(code); + when(vehicle.getVehiclesPerTimeUnit()).thenReturn(100.0); + final IsGmlTimeUnit timeUnit = mock(IsGmlTimeUnit.class); + when(timeUnit.name()).thenReturn("DAY"); + when(vehicle.getTimeUnit()).thenReturn(timeUnit); + return vehicle; + } + +} diff --git a/source/imaer-gml/src/test/java/nl/overheid/aerius/gml/base/source/road/RemovedVehicleUtilTest.java b/source/imaer-gml/src/test/java/nl/overheid/aerius/gml/base/source/road/RemovedVehicleUtilTest.java new file mode 100644 index 00000000..7ff8954b --- /dev/null +++ b/source/imaer-gml/src/test/java/nl/overheid/aerius/gml/base/source/road/RemovedVehicleUtilTest.java @@ -0,0 +1,78 @@ +/* + * Copyright the State of the Netherlands + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see http://www.gnu.org/licenses/. + */ +package nl.overheid.aerius.gml.base.source.road; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import org.junit.jupiter.api.Test; + +import nl.overheid.aerius.gml.base.source.IsGmlTimeUnit; +import nl.overheid.aerius.shared.domain.v2.base.TimeUnit; +import nl.overheid.aerius.shared.domain.v2.source.road.CustomVehicles; + +class RemovedVehicleUtilTest { + + @Test + void testToCustomVehiclesPreservesTimeUnit() { + final IsGmlSpecificVehicle vehicle = createMockVehicle("TEST_CODE", 100.0, "DAY"); + + final CustomVehicles result = RemovedVehicleUtil.toCustomVehicles(vehicle, "TEST_CODE"); + + assertEquals(TimeUnit.DAY, result.getTimeUnit()); + } + + @Test + void testToCustomVehiclesPreservesVehicleCount() { + final IsGmlSpecificVehicle vehicle = createMockVehicle("TEST_CODE", 42.5, "YEAR"); + + final CustomVehicles result = RemovedVehicleUtil.toCustomVehicles(vehicle, "TEST_CODE"); + + assertEquals(42.5, result.getVehiclesPerTimeUnit()); + } + + @Test + void testToCustomVehiclesSetsDescriptionWithVehicleCode() { + final IsGmlSpecificVehicle vehicle = createMockVehicle("BABCEUR4", 100.0, "DAY"); + + final CustomVehicles result = RemovedVehicleUtil.toCustomVehicles(vehicle, "BABCEUR4"); + + assertEquals("Voormalig BABCEUR4", result.getDescription()); + } + + @Test + void testToCustomVehiclesHasZeroEmissions() { + final IsGmlSpecificVehicle vehicle = createMockVehicle("TEST_CODE", 100.0, "DAY"); + + final CustomVehicles result = RemovedVehicleUtil.toCustomVehicles(vehicle, "TEST_CODE"); + + assertTrue(result.getEmissionFactors().isEmpty()); + } + + private IsGmlSpecificVehicle createMockVehicle(final String code, final double vehiclesPerTimeUnit, final String timeUnitName) { + final IsGmlSpecificVehicle vehicle = mock(IsGmlSpecificVehicle.class); + when(vehicle.getCode()).thenReturn(code); + when(vehicle.getVehiclesPerTimeUnit()).thenReturn(vehiclesPerTimeUnit); + final IsGmlTimeUnit timeUnit = mock(IsGmlTimeUnit.class); + when(timeUnit.name()).thenReturn(timeUnitName); + when(vehicle.getTimeUnit()).thenReturn(timeUnit); + return vehicle; + } + +} From 50b8abea7dcb695b2918aa9ae197131fb692a214 Mon Sep 17 00:00:00 2001 From: JornC Date: Fri, 30 Jan 2026 14:10:48 +0100 Subject: [PATCH 6/6] Review comments --- .../aerius/gml/base/GMLConversionData.java | 7 +++---- .../aerius/gml/base/GMLLegacyCodeConverter.java | 17 ++++++++++++++++- .../gml/base/GMLVersionReaderFactory.java | 2 +- .../aerius/gml/base/source/road/GML2Road.java | 2 +- .../gml/base/source/road/GML2VehicleUtil.java | 3 +-- .../base/source/road/RemovedVehicleUtil.java | 2 +- .../gml/base/source/road/v40/GML2SRMRoad.java | 4 ++-- .../gml/RemovedVehicleCodeImportTest.java | 4 ++-- .../base/source/road/GML2VehicleUtilTest.java | 2 +- .../source/road/RemovedVehicleUtilTest.java | 2 +- .../shared/exception/ImaerExceptionReason.java | 7 +++++++ 11 files changed, 36 insertions(+), 16 deletions(-) diff --git a/source/imaer-gml/src/main/java/nl/overheid/aerius/gml/base/GMLConversionData.java b/source/imaer-gml/src/main/java/nl/overheid/aerius/gml/base/GMLConversionData.java index 671c4b17..86a09262 100644 --- a/source/imaer-gml/src/main/java/nl/overheid/aerius/gml/base/GMLConversionData.java +++ b/source/imaer-gml/src/main/java/nl/overheid/aerius/gml/base/GMLConversionData.java @@ -254,11 +254,10 @@ public S determineDefaultCharacteristicsBySect * @param code the code to check * @param sourceLabel the label of the source for warning messages * @return true if the code is a removed code, false otherwise - * @throws AeriusException if the removed codes cannot be retrieved */ - public boolean warnIfRemovedCode(final GMLLegacyCodeType type, final String code, final String sourceLabel) throws AeriusException { - if (helper.getRemovedCodes().getOrDefault(type, Set.of()).contains(code)) { - warnings.add(new AeriusException(ImaerExceptionReason.GML_UNKNOWN_MOBILE_SOURCE_CODE, sourceLabel, code)); + public boolean warnIfRemovedCode(final GMLLegacyCodeType type, final String code, final String sourceLabel) { + if (legacyCodeConverter.isRemovedCode(type, code)) { + warnings.add(new AeriusException(ImaerExceptionReason.GML_REMOVED_CODE_CONVERTED, sourceLabel, code)); return true; } return false; diff --git a/source/imaer-gml/src/main/java/nl/overheid/aerius/gml/base/GMLLegacyCodeConverter.java b/source/imaer-gml/src/main/java/nl/overheid/aerius/gml/base/GMLLegacyCodeConverter.java index 761525c0..7899ff0e 100644 --- a/source/imaer-gml/src/main/java/nl/overheid/aerius/gml/base/GMLLegacyCodeConverter.java +++ b/source/imaer-gml/src/main/java/nl/overheid/aerius/gml/base/GMLLegacyCodeConverter.java @@ -17,6 +17,7 @@ package nl.overheid.aerius.gml.base; import java.util.Map; +import java.util.Set; import nl.overheid.aerius.gml.base.conversion.FarmLodgingConversion; import nl.overheid.aerius.gml.base.conversion.MobileSourceOffRoadConversion; @@ -42,20 +43,24 @@ public enum GMLLegacyCodeType { private final Map mobileSourceOffRoadConversions; private final Map planConversions; private final Map farmLodgingConversions; + private final Map> removedCodes; /** * @param codeMaps The <OldCode, NewCode> maps to use for each legacy code type. * @param mobileSourceOffRoadConversions The <OldCode, ConversionValues> to use for mobile sources. * @param planConversions The <OldCode, ConversionValues> to use for plan activities. * @param farmLodgingConversions The <OldCode, ConversionValues> to use for farm lodgings. + * @param removedCodes The removed codes by type. */ public GMLLegacyCodeConverter(final Map> codeMaps, final Map mobileSourceOffRoadConversions, - final Map planConversions, final Map farmLodgingConversions) { + final Map planConversions, final Map farmLodgingConversions, + final Map> removedCodes) { this.codeMaps = safe(codeMaps); this.mobileSourceOffRoadConversions = safe(mobileSourceOffRoadConversions); this.planConversions = safe(planConversions); this.farmLodgingConversions = safe(farmLodgingConversions); + this.removedCodes = safe(removedCodes); } private static Map safe(final Map map) { @@ -89,6 +94,16 @@ protected FarmLodgingConversion getFarmLodgingConversion(final String oldCode) { return farmLodgingConversions.get(oldCode); } + /** + * Check if a code is a removed code. + * @param type The type of legacy code. + * @param code The code to check. + * @return true if the code is a removed code, false otherwise. + */ + protected boolean isRemovedCode(final GMLLegacyCodeType type, final String code) { + return removedCodes.getOrDefault(type, Set.of()).contains(code); + } + /** * The conversion of a an old code. */ diff --git a/source/imaer-gml/src/main/java/nl/overheid/aerius/gml/base/GMLVersionReaderFactory.java b/source/imaer-gml/src/main/java/nl/overheid/aerius/gml/base/GMLVersionReaderFactory.java index 6fc20be6..df8dae37 100644 --- a/source/imaer-gml/src/main/java/nl/overheid/aerius/gml/base/GMLVersionReaderFactory.java +++ b/source/imaer-gml/src/main/java/nl/overheid/aerius/gml/base/GMLVersionReaderFactory.java @@ -50,7 +50,7 @@ protected GMLVersionReaderFactory(final GMLLegacyCodesSupplier legacyCodeSupplie schema = GMLSchemaFactory.createSchema(schemaLocation); legacyCodeConverter = new GMLLegacyCodeConverter(legacyCodeSupplier.getLegacyCodes(version), legacyCodeSupplier.getLegacyMobileSourceOffRoadConversions(), legacyCodeSupplier.getLegacyPlanConversions(), - legacyCodeSupplier.getLegacyFarmLodgingConversions()); + legacyCodeSupplier.getLegacyFarmLodgingConversions(), legacyCodeSupplier.getRemovedCodes()); } /** diff --git a/source/imaer-gml/src/main/java/nl/overheid/aerius/gml/base/source/road/GML2Road.java b/source/imaer-gml/src/main/java/nl/overheid/aerius/gml/base/source/road/GML2Road.java index cb281ea2..7f990268 100644 --- a/source/imaer-gml/src/main/java/nl/overheid/aerius/gml/base/source/road/GML2Road.java +++ b/source/imaer-gml/src/main/java/nl/overheid/aerius/gml/base/source/road/GML2Road.java @@ -70,7 +70,7 @@ public S convert(final T source) throws AeriusException { protected abstract void setOptionalVariables(T source, S emissionSource) throws AeriusException; protected void addVehicleEmissions(final List addToVehicles, final T source, final IsGmlProperty vp, - final List mergingStandardVehicles) throws AeriusException { + final List mergingStandardVehicles) { final IsGmlVehicle av = vp.getProperty(); if (av instanceof final IsGmlStandardVehicle standardVehicle) { addEmissionValues(addToVehicles, source, standardVehicle, mergingStandardVehicles); diff --git a/source/imaer-gml/src/main/java/nl/overheid/aerius/gml/base/source/road/GML2VehicleUtil.java b/source/imaer-gml/src/main/java/nl/overheid/aerius/gml/base/source/road/GML2VehicleUtil.java index 38d8422f..84b4d529 100644 --- a/source/imaer-gml/src/main/java/nl/overheid/aerius/gml/base/source/road/GML2VehicleUtil.java +++ b/source/imaer-gml/src/main/java/nl/overheid/aerius/gml/base/source/road/GML2VehicleUtil.java @@ -27,7 +27,6 @@ import nl.overheid.aerius.shared.domain.v2.source.road.CustomVehicles; import nl.overheid.aerius.shared.domain.v2.source.road.SpecificVehicles; import nl.overheid.aerius.shared.domain.v2.source.road.Vehicles; -import nl.overheid.aerius.shared.exception.AeriusException; /** * @@ -39,7 +38,7 @@ private GML2VehicleUtil() { } static void addEmissionValuesSpecific(final List addToVehicles, final IsGmlEmissionSource source, final IsGmlSpecificVehicle sv, - final GMLConversionData conversionData) throws AeriusException { + final GMLConversionData conversionData) { final String vehicleCode = conversionData.getCode(GMLLegacyCodeType.ON_ROAD_MOBILE_SOURCE, sv.getCode(), source.getLabel()); if (conversionData.warnIfRemovedCode(GMLLegacyCodeType.ON_ROAD_MOBILE_SOURCE, vehicleCode, source.getLabel())) { diff --git a/source/imaer-gml/src/main/java/nl/overheid/aerius/gml/base/source/road/RemovedVehicleUtil.java b/source/imaer-gml/src/main/java/nl/overheid/aerius/gml/base/source/road/RemovedVehicleUtil.java index 7a43b9a9..32117496 100644 --- a/source/imaer-gml/src/main/java/nl/overheid/aerius/gml/base/source/road/RemovedVehicleUtil.java +++ b/source/imaer-gml/src/main/java/nl/overheid/aerius/gml/base/source/road/RemovedVehicleUtil.java @@ -39,7 +39,7 @@ public static CustomVehicles toCustomVehicles(final IsGmlSpecificVehicle sv, fin final CustomVehicles custom = new CustomVehicles(); custom.setTimeUnit(TimeUnit.valueOf(sv.getTimeUnit().name())); custom.setVehiclesPerTimeUnit(sv.getVehiclesPerTimeUnit()); - custom.setDescription("Voormalig " + vehicleCode); + custom.setDescription(vehicleCode); return custom; } diff --git a/source/imaer-gml/src/main/java/nl/overheid/aerius/gml/base/source/road/v40/GML2SRMRoad.java b/source/imaer-gml/src/main/java/nl/overheid/aerius/gml/base/source/road/v40/GML2SRMRoad.java index 9f7f2c87..7926603e 100644 --- a/source/imaer-gml/src/main/java/nl/overheid/aerius/gml/base/source/road/v40/GML2SRMRoad.java +++ b/source/imaer-gml/src/main/java/nl/overheid/aerius/gml/base/source/road/v40/GML2SRMRoad.java @@ -81,7 +81,7 @@ public S convert(final T source) throws AeriusException { protected abstract void setOptionalVariables(T source, S emissionSource) throws AeriusException; protected void addVehicleEmissions(final List addToVehicles, final T source, final IsGmlProperty vp, - final List mergingStandardVehicles) throws AeriusException { + final List mergingStandardVehicles) { final IsGmlVehicle av = vp.getProperty(); if (av instanceof IsGmlStandardVehicle) { addEmissionValues(addToVehicles, source, (IsGmlStandardVehicle) av, mergingStandardVehicles); @@ -121,7 +121,7 @@ protected Optional findExistingMatch(final IsGmlStandardVehicl .findFirst(); } - protected void addEmissionValues(final List addToVehicles, final T source, final IsGmlSpecificVehicle sv) throws AeriusException { + protected void addEmissionValues(final List addToVehicles, final T source, final IsGmlSpecificVehicle sv) { final String vehicleCode = getConversionData().getCode(GMLLegacyCodeType.ON_ROAD_MOBILE_SOURCE, sv.getCode(), source.getLabel()); if (getConversionData().warnIfRemovedCode(GMLLegacyCodeType.ON_ROAD_MOBILE_SOURCE, vehicleCode, source.getLabel())) { diff --git a/source/imaer-gml/src/test/java/nl/overheid/aerius/gml/RemovedVehicleCodeImportTest.java b/source/imaer-gml/src/test/java/nl/overheid/aerius/gml/RemovedVehicleCodeImportTest.java index a83bd545..45eb5c23 100644 --- a/source/imaer-gml/src/test/java/nl/overheid/aerius/gml/RemovedVehicleCodeImportTest.java +++ b/source/imaer-gml/src/test/java/nl/overheid/aerius/gml/RemovedVehicleCodeImportTest.java @@ -63,13 +63,13 @@ void testRemovedVehicleCodeIsConvertedDuringImport() throws IOException, AeriusE assertEquals(0, result.getExceptions().size(), "Expected no exceptions"); assertTrue(result.getWarnings().stream() - .anyMatch(w -> w.getReason() == ImaerExceptionReason.GML_UNKNOWN_MOBILE_SOURCE_CODE), + .anyMatch(w -> w.getReason() == ImaerExceptionReason.GML_REMOVED_CODE_CONVERTED), "Expected warning for removed vehicle code"); final SRM2RoadEmissionSource roadSource = (SRM2RoadEmissionSource) result.getSituation().getEmissionSourcesList().get(0).getProperties(); final CustomVehicles converted = assertInstanceOf(CustomVehicles.class, roadSource.getSubSources().get(0)); - assertEquals("Voormalig " + REMOVED_CODE, converted.getDescription()); + assertEquals(REMOVED_CODE, converted.getDescription()); } } diff --git a/source/imaer-gml/src/test/java/nl/overheid/aerius/gml/base/source/road/GML2VehicleUtilTest.java b/source/imaer-gml/src/test/java/nl/overheid/aerius/gml/base/source/road/GML2VehicleUtilTest.java index 76cdd9d6..c441ceb0 100644 --- a/source/imaer-gml/src/test/java/nl/overheid/aerius/gml/base/source/road/GML2VehicleUtilTest.java +++ b/source/imaer-gml/src/test/java/nl/overheid/aerius/gml/base/source/road/GML2VehicleUtilTest.java @@ -57,7 +57,7 @@ void testRemovedCodeRoutesToCustomVehicles() throws AeriusException { } @Test - void testValidCodeRoutesToSpecificVehicles() throws AeriusException { + void testUnknownCodeStaysSpecificVehicle() throws AeriusException { final GMLConversionData conversionData = mock(GMLConversionData.class); when(conversionData.getCode(GMLLegacyCodeType.ON_ROAD_MOBILE_SOURCE, VALID_CODE, SOURCE_LABEL)) .thenReturn(VALID_CODE); diff --git a/source/imaer-gml/src/test/java/nl/overheid/aerius/gml/base/source/road/RemovedVehicleUtilTest.java b/source/imaer-gml/src/test/java/nl/overheid/aerius/gml/base/source/road/RemovedVehicleUtilTest.java index 7ff8954b..6d63063a 100644 --- a/source/imaer-gml/src/test/java/nl/overheid/aerius/gml/base/source/road/RemovedVehicleUtilTest.java +++ b/source/imaer-gml/src/test/java/nl/overheid/aerius/gml/base/source/road/RemovedVehicleUtilTest.java @@ -53,7 +53,7 @@ void testToCustomVehiclesSetsDescriptionWithVehicleCode() { final CustomVehicles result = RemovedVehicleUtil.toCustomVehicles(vehicle, "BABCEUR4"); - assertEquals("Voormalig BABCEUR4", result.getDescription()); + assertEquals("BABCEUR4", result.getDescription()); } @Test diff --git a/source/imaer-shared/src/main/java/nl/overheid/aerius/shared/exception/ImaerExceptionReason.java b/source/imaer-shared/src/main/java/nl/overheid/aerius/shared/exception/ImaerExceptionReason.java index 64873e93..2a52ff1a 100644 --- a/source/imaer-shared/src/main/java/nl/overheid/aerius/shared/exception/ImaerExceptionReason.java +++ b/source/imaer-shared/src/main/java/nl/overheid/aerius/shared/exception/ImaerExceptionReason.java @@ -613,6 +613,13 @@ public enum ImaerExceptionReason implements Reason { * @param 2 source name */ GML_SECTOR_OUT_OF_DATE(5266), + /** + * GML contains a source with a removed vehicle code that has been converted. + * + * @param 0 the label of the source. + * @param 1 the old code. + */ + GML_REMOVED_CODE_CONVERTED(5267), /** * Geometry contains too many vertices. *