diff --git a/src/main/java/fi/fmi/avi/model/AviationCodeListUser.java b/src/main/java/fi/fmi/avi/model/AviationCodeListUser.java index 4d95ab5..2f9061a 100644 --- a/src/main/java/fi/fmi/avi/model/AviationCodeListUser.java +++ b/src/main/java/fi/fmi/avi/model/AviationCodeListUser.java @@ -1,829 +1,845 @@ -package fi.fmi.avi.model; - -import static fi.fmi.avi.model.AviationCodeListUser.RelationalOperator.BELOW; -import static java.util.Objects.requireNonNull; - -import java.util.Optional; - -import fi.fmi.avi.model.taf.TAF; - -/** - * A convenience interface containing references to shared codelists and enums. - */ -public interface AviationCodeListUser { - - String CODELIST_CLOUD_AMOUNT_REPORTED_AT_AERODROME = "http://codes.wmo.int/49-2/CloudAmountReportedAtAerodrome"; - String CODELIST_SIGNIFICANT_CONVECTIVE_CLOUD_TYPE = "http://codes.wmo.int/49-2/SigConvectiveCloudType"; - - String CODELIST_VALUE_PREFIX_SIG_WEATHER = "http://codes.wmo.int/306/4678/"; - String CODELIST_VALUE_PREFIX_CLOUD_AMOUNT_REPORTED_AT_AERODROME = "http://codes.wmo.int/49-2/CloudAmountReportedAtAerodrome/"; - String CODELIST_VALUE_PREFIX_SIG_CONVECTIVE_CLOUD_TYPE = "http://codes.wmo.int/49-2/SigConvectiveCloudType/"; - String CODELIST_VALUE_PREFIX_SEA_SURFACE_STATE = "http://codes.wmo.int/bufr4/codeflag/0-22-061/"; - String CODELIST_VALUE_PREFIX_RUNWAY_DEPOSITS = "http://codes.wmo.int/bufr4/codeflag/0-20-086/"; - String CODELIST_VALUE_PREFIX_RUNWAY_CONTAMINATION = "http://codes.wmo.int/bufr4/codeflag/0-20-087/"; - String CODELIST_VALUE_PREFIX_RUNWAY_SURFACE_FRICTION_OR_BRAKING_ACTION = "http://codes.wmo.int/bufr4/codeflag/0-20-089/"; - - String CODELIST_VALUE_NIL_REASON_NOTHING_OF_OPERATIONAL_SIGNIFICANCE = "http://codes.wmo.int/common/nil/nothingOfOperationalSignificance"; - String CODELIST_VALUE_NIL_REASON_NOT_OBSERVABLE = "http://codes.wmo.int/common/nil/notObservable"; - String CODELIST_VALUE_NIL_REASON_NOT_DETECTED_BY_AUTO_SYSTEM = "http://codes.wmo.int/common/nil/notDetectedByAutoSystem"; - String CODELIST_VALUE_NIL_REASON_NO_SIGNIFICANT_CHANGE = "http://codes.wmo.int/common/nil/noSignificantChange"; - String CODELIST_VALUE_NIL_REASON_MISSING = "http://codes.wmo.int/common/nil/missing"; - String CODELIST_VALUE_NIL_REASON_INAPPLICABLE = "http://codes.wmo.int/common/nil/inapplicable"; - String CODELIST_VALUE_NIL_REASON_WITHHELD = "http://codes.wmo.int/common/nil/withheld"; - String CODELIST_VALUE_NIL_REASON_UNKNOWN = "http://codes.wmo.int/common/nil/unknown"; - - String MET_AERODROME_FORECAST_TYPE = "http://codes.wmo.int/49-2/observation-type/iwxxm/2.1/MeteorologicalAerodromeForecast"; - String MET_AERODROME_FORECAST_PROPERTIES = "http://codes.wmo.int/49-2/observable-property/MeteorologicalAerodromeForecast"; - String TAF_PROCEDURE_DESCRIPTION = "WMO No. 49 Volume 2 Meteorological Service for International Air Navigation APPENDIX 5 TECHNICAL SPECIFICATIONS RELATED TO FORECASTS"; - - String MET_AERODROME_OBSERVATION_TYPE = "http://codes.wmo.int/49-2/observation-type/iwxxm/2.1/MeteorologicalAerodromeObservation"; - String MET_AERODROME_OBSERVATION_PROPERTIES = "http://codes.wmo.int/49-2/observable-property/MeteorologicalAerodromeObservation"; - String METAR_PROCDURE_DESCRIPTION = "WMO No. 49 Volume 2 Meteorological Service for International Air Navigation APPENDIX 3 TECHNICAL SPECIFICATIONS RELATED TO METEOROLOGICAL OBSERVATIONS AND REPORTS"; - - String TREND_FORECAST_OBSERVATION_TYPE = "http://codes.wmo.int/49-2/observation-type/iwxxm/2.1/MeteorologicalAerodromeTrendForecast"; - String TREND_FORECAST_PROPERTIES = "http://codes.wmo.int/49-2/observable-property/MeteorologicalAerodromeTrendForecast"; - - String CODELIST_VALUE_PREFIX_OM_SAMPLING = "http://www.opengis.net/def/samplingFeatureType/OGC-OM/2.0/"; - String CODELIST_VALUE_EPSG_4326 = "http://www.opengis.net/def/crs/EPSG/0/4326"; - - String CODELIST_VALUE_SIGMET_PROCESS = "WMO No. 49 Volume 2 Meteorological Service for International Air Navigation APPENDIX 6-1 TECHNICAL SPECIFICATIONS " - + "RELATED TO SIGMET INFORMATION"; - String CODELIST_SIGMET_EVOLVING_CONDITION_COLLECTION_ANALYSIS = "http://codes.wmo.int/49-2/observation-type/iwxxm/2.1/SIGMETEvolvingConditionCollectionAnalysis"; - String CODELIST_SIGWX_PHENOMENA_ROOT = "http://codes.wmo.int/49-2/SigWxPhenomena/"; - String CODELIST_SIGMET_POSITION_COLLECTION_ANALYSIS = "http://codes.wmo.int/49-2/observable-property/SIGMETPositionCollectionAnalysis"; - - String CODELIST_AIRMET_PHENOMENA_ROOT = "http://codes.wmo.int/49-2/AirWxPhenomena/"; - String CODELIST_VALUE_AIRMET_PROCESS = "WMO No. 49 Volume 2 Meteorological Service for International Air Navigation APPENDIX 6-1 TECHNICAL SPECIFICATIONS " - + "RELATED TO AIRMET INFORMATION"; - String CODELIST_AIRMET_EVOLVING_CONDITION_COLLECTION_ANALYSIS = - "http://codes.wmo.int/49-2/observation-type/iwxxm/2" + ".1/AIRMETEvolvingConditionCollectionAnalysis"; - String CODELIST_VALUE_WEATHERCAUSINGVISIBILITYREDUCTION = "http://codes.wmo.int/49-2/WeatherCausingVisibilityReduction"; - - @Deprecated - enum MetarStatus { - NORMAL(0, AviationWeatherMessage.ReportStatus.NORMAL), // - CORRECTION(1, AviationWeatherMessage.ReportStatus.CORRECTION), // - MISSING(2, AviationWeatherMessage.ReportStatus.NORMAL); - - private final int code; - private final AviationWeatherMessage.ReportStatus reportStatus; - - MetarStatus(final int code, final AviationWeatherMessage.ReportStatus reportStatus) { - this.code = code; - this.reportStatus = reportStatus; - } - - public static MetarStatus fromInt(final int code) { - switch (code) { - case 0: - return NORMAL; - case 1: - return CORRECTION; - case 2: - return MISSING; - default: - throw new IllegalArgumentException("No value for code " + code); - } - } - - public static MetarStatus fromReportStatus(final AviationWeatherMessage.ReportStatus reportStatus, final boolean missingMessage) { - requireNonNull(reportStatus, "reportStatus"); - if (missingMessage) { - return MISSING; - } - switch (reportStatus) { - case CORRECTION: - case AMENDMENT: - return CORRECTION; - case NORMAL: - return NORMAL; - default: - throw new IllegalArgumentException("Unknown reportStatus: " + reportStatus); - } - } - - public int getCode() { - return this.code; - } - - public AviationWeatherMessage.ReportStatus getReportStatus() { - return reportStatus; - } - - public boolean isMissingMessage() { - return this == MISSING; - } - } - - /** - * TAF Status. - * - * @deprecated use {@link AviationWeatherMessage.ReportStatus}, {@link TAF#isCancelMessage()} and {@link TAF#isMissingMessage()} instead. - * In future releases this method will be made an internal implementation detail of IWXXM 2.1 conversion. - */ - @Deprecated - enum TAFStatus { - NORMAL(0, AviationWeatherMessage.ReportStatus.NORMAL),// - AMENDMENT(1, AviationWeatherMessage.ReportStatus.AMENDMENT),// - CANCELLATION(2, AviationWeatherMessage.ReportStatus.AMENDMENT),// - CORRECTION(3, AviationWeatherMessage.ReportStatus.CORRECTION),// - MISSING(4, AviationWeatherMessage.ReportStatus.NORMAL);// - - private final int code; - private final AviationWeatherMessage.ReportStatus reportStatus; - - TAFStatus(final int code, final AviationWeatherMessage.ReportStatus reportStatus) { - this.code = code; - this.reportStatus = reportStatus; - } - - public static TAFStatus fromInt(final int code) { - switch (code) { - case 0: - return NORMAL; - case 1: - return AMENDMENT; - case 2: - return CANCELLATION; - case 3: - return CORRECTION; - case 4: - return MISSING; - default: - throw new IllegalArgumentException("No value for code " + code); - } - } - - public static TAFStatus fromReportStatus(final AviationWeatherMessage.ReportStatus reportStatus, final boolean cancelMessage, - final boolean missingMessage) { - requireNonNull(reportStatus, "reportStatus"); - if (cancelMessage) { - return CANCELLATION; - } - if (missingMessage) { - return MISSING; - } - switch (reportStatus) { - case CORRECTION: - return CORRECTION; - case AMENDMENT: - return AMENDMENT; - case NORMAL: - return NORMAL; - default: - throw new IllegalArgumentException("Unknown reportStatus: " + reportStatus); - } - } - - public int getCode() { - return this.code; - } - - public AviationWeatherMessage.ReportStatus getReportStatus() { - return reportStatus; - } - - public boolean isCancelMessage() { - return this == CANCELLATION; - } - - public boolean isMissingMessage() { - return this == MISSING; - } - } - - enum RelationalOperator { - ABOVE(0), BELOW(1); - - private final int code; - - RelationalOperator(final int code) { - this.code = code; - } - - public static RelationalOperator fromInt(final int code) { - switch (code) { - case 0: - return ABOVE; - case 1: - return BELOW; - default: - throw new IllegalArgumentException("No value for code " + code); - } - } - - public int getCode() { - return this.code; - } - - } - - enum VisualRangeTendency { - UPWARD(0), NO_CHANGE(1), DOWNWARD(2), MISSING_VALUE(3); - - private final int code; - - VisualRangeTendency(final int code) { - this.code = code; - } - - public static VisualRangeTendency fromInt(final int code) { - switch (code) { - case 0: - return UPWARD; - case 1: - return NO_CHANGE; - case 2: - return DOWNWARD; - case 3: - return MISSING_VALUE; - default: - throw new IllegalArgumentException("No value for code " + code); - } - } - - public int getCode() { - return this.code; - } - - } - - enum CloudAmount { - SKC("SKC", 0), - FEW("FEW", 1), - SCT("SCT", 2), - BKN("BKN", 3), - OVC("OVC", 4), - ISOL("ISOL", 8), - OCNL("OCNL", 10), - FRQ("FRQ", 12), - LYR("LYR", 14), - EMBD("EMBD", 16); - - private final String code; - private final int bufrCode; - - CloudAmount(final String code, final int bufrCode) { - this.code = code; - this.bufrCode = bufrCode; - } - - public static CloudAmount fromInt(final int code) { - switch (code) { - case 0: - return SKC; - case 1: - return FEW; - case 2: - return SCT; - case 3: - return BKN; - case 4: - return OVC; - case 8: - return ISOL; - case 10: - return OCNL; - case 12: - return FRQ; - case 14: - return LYR; - case 16: - return EMBD; - default: - throw new IllegalArgumentException("No value for code " + code); - } - } - - public String getCode() { - return code; - } - - public int getBufrCode() { - return bufrCode; - } - } - - enum CloudType { - CB("CB", 9), TCU("TCU", 32); - - private final String code; - private final int bufrCode; - - CloudType(final String code, final int bufrCode) { - this.code = code; - this.bufrCode = bufrCode; - } - - public static CloudType fromInt(final int code) { - switch (code) { - case 9: - return CB; - case 32: - return TCU; - default: - throw new IllegalArgumentException("No value for code " + code); - } - } - - public String getCode() { - return code; - } - - public int getBufrCode() { - return bufrCode; - } - } - - enum SeaSurfaceState { - CALM_GLASSY(0), - CALM_RIPPLED(1), - SMOOTH_WAVELETS(2), - SLIGHT(3), - MODERATE(4), - ROUGH(5), - VERY_ROUGH(6), - HIGH(7), - VERY_HIGH(8), - PHENOMENAL(9), - MISSING_VALUE(15); - - private final int code; - - SeaSurfaceState(final int code) { - this.code = code; - } - - public static SeaSurfaceState fromInt(final int code) { - switch (code) { - case 0: - return CALM_GLASSY; - case 1: - return CALM_RIPPLED; - case 2: - return SMOOTH_WAVELETS; - case 3: - return SLIGHT; - case 4: - return MODERATE; - case 5: - return ROUGH; - case 6: - return VERY_ROUGH; - case 7: - return HIGH; - case 8: - return VERY_HIGH; - case 9: - return PHENOMENAL; - case 15: - return MISSING_VALUE; - default: - throw new IllegalArgumentException("No value for code " + code); - } - } - - public int getCode() { - return this.code; - } - } - - enum RunwayDeposit { - CLEAR_AND_DRY(0), DAMP(1), WET_WITH_WATER_PATCHES(2), RIME_AND_FROST_COVERED(3), // (depth normally less than 1mm) - DRY_SNOW(4), WET_SNOW(5), SLUSH(6), ICE(7), COMPACT_OR_ROLLED_SNOW(8), FROZEN_RUTS_OR_RIDGES(9), MISSING_OR_NOT_REPORTED(15); - - private final int code; - - RunwayDeposit(final int code) { - this.code = code; - } - - public static RunwayDeposit fromInt(final int code) { - switch (code) { - case 0: - return CLEAR_AND_DRY; - case 1: - return DAMP; - case 2: - return WET_WITH_WATER_PATCHES; - case 3: - return RIME_AND_FROST_COVERED; - case 4: - return DRY_SNOW; - case 5: - return WET_SNOW; - case 6: - return SLUSH; - case 7: - return ICE; - case 8: - return COMPACT_OR_ROLLED_SNOW; - case 9: - return FROZEN_RUTS_OR_RIDGES; - case 15: - return MISSING_OR_NOT_REPORTED; - default: - throw new IllegalArgumentException("No value for code " + code); - } - } - - public int getCode() { - return this.code; - } - } - - enum RunwayContamination { - PCT_COVERED_LESS_THAN_10(1), PCT_COVERED_11_25(2), PCT_COVERED_26_50(5), PCT_COVERED_51_100(9), MISSING_OR_NOT_REPORTED(15); - - private final int code; - - RunwayContamination(final int code) { - this.code = code; - } - - public static RunwayContamination fromInt(final int code) { - switch (code) { - case 1: - return PCT_COVERED_LESS_THAN_10; - case 2: - return PCT_COVERED_11_25; - case 5: - return PCT_COVERED_26_50; - case 9: - return PCT_COVERED_51_100; - case 15: - return MISSING_OR_NOT_REPORTED; - default: - throw new IllegalArgumentException("No value for code " + code); - } - } - - public int getCode() { - return this.code; - } - } - - enum BrakingAction { - POOR(91), MEDIUM_POOR(92), MEDIUM(93), MEDIUM_GOOD(94), GOOD(95); - - private final int code; - - BrakingAction(final int code) { - this.code = code; - } - - public static BrakingAction fromInt(final int code) { - switch (code) { - case 91: - return POOR; - case 92: - return MEDIUM_POOR; - case 93: - return MEDIUM; - case 94: - return MEDIUM_GOOD; - case 95: - return GOOD; - default: - return null; - } - } - - public int getCode() { - return this.code; - } - } - - enum TrendForecastChangeIndicator { - BECOMING(1), TEMPORARY_FLUCTUATIONS(2); - - private final int code; - - TrendForecastChangeIndicator(final int code) { - this.code = code; - } - - public static TrendForecastChangeIndicator fromInt(final int code) { - switch (code) { - case 1: - return BECOMING; - case 2: - return TEMPORARY_FLUCTUATIONS; - default: - throw new IllegalArgumentException("No value for code " + code); - } - } - - public int getCode() { - return this.code; - } - } - - enum TAFChangeIndicator { - BECOMING(1), - TEMPORARY_FLUCTUATIONS(2), - FROM(3), - PROBABILITY_30(4), - PROBABILITY_30_TEMPORARY_FLUCTUATIONS(5), - PROBABILITY_40(6), - PROBABILITY_40_TEMPORARY_FLUCTUATIONS(7); - - private final int code; - - TAFChangeIndicator(final int code) { - this.code = code; - } - - public static TAFChangeIndicator fromInt(final int code) { - switch (code) { - case 1: - return BECOMING; - case 2: - return TEMPORARY_FLUCTUATIONS; - case 3: - return FROM; - case 4: - return PROBABILITY_30; - case 5: - return PROBABILITY_30_TEMPORARY_FLUCTUATIONS; - case 6: - return PROBABILITY_40; - case 7: - return PROBABILITY_40_TEMPORARY_FLUCTUATIONS; - default: - throw new IllegalArgumentException("No value for code " + code); - } - } - - public int getCode() { - return this.code; - } - } - - enum ColorState { - BLU(2500, 8000), - WHT(1500, 5000), - GRN(700, 3700), - YLO1(500, 2500), - YLO2(300, 1600), - AMB(200, 800), - RED(200, 800, BELOW), - BLACK(-1, -1, null, true), - BLACKBLU(2500, 8000, null, true), - BLACKWHT(1500, 5000, null, true), - BLACKGRN(700, 3700, null, true), - BLACKYLO1(500, 2500, null, true), - BLACKYLO2(300, 1600, null, true), - BLACKAMB(200, 800, null, true), - BLACKRED(200, 800, BELOW, true); - - private final double minCloudHeight; - private final double minVisibility; - private final boolean unusable; - private final RelationalOperator operator; - - ColorState(final double cloudHeight, final double visibility) { - this(cloudHeight, visibility, null, false); - } - - ColorState(final double cloudHeight, final double visibility, final RelationalOperator operator) { - this(cloudHeight, visibility, operator, false); - } - - ColorState(final double cloudHeight, final double visibility, final RelationalOperator operator, final boolean unusable) { - this.minCloudHeight = cloudHeight; - this.minVisibility = visibility; - this.operator = operator; - this.unusable = unusable; - } - - public double getMinCloudHeight() { - return minCloudHeight; - } - - public double getMinVisibility() { - return minVisibility; - } - - public boolean isUnusable() { - return unusable; - } - - public RelationalOperator getOperator() { - return operator; - } - } - - enum PermissibleUsage {OPERATIONAL, NON_OPERATIONAL} - - enum PermissibleUsageReason {TEST, EXERCISE} - - //From: http://codes.wmo.int/49-2/SigWxPhenomena - enum AeronauticalSignificantWeatherPhenomenon { - EMBD_TS("EMBD_TS"), - EMBD_TSGR("EMBD_TSGR"), - FRQ_TS("FRQ_TS"), - FRQ_TSGR("FRQ_TSGR"), - HVY_DS("HVY_DS"), - HVY_SS("HVY_SS"), - OBSC_TS("OBSC_TS"), - OBSC_TSGR("OBSC_TSGR"), - RDOACT_CLD("RDOACT_CLD"), - SEV_ICE("SEV_ICE"), - SEV_ICE_FZRA("SEV_ICE_FZRA"), - SEV_MTW("SEV_MTW"), - SEV_TURB("SEV_TURB"), - SQL_TS("SQL_TS"), - SQL_TSGR("SQL_TSGR"), - TC("TC"), - VA("VA"); - - private final String text; - - AeronauticalSignificantWeatherPhenomenon(final String phen) { - this.text = phen; - } - - public String getText() { - return this.text; - } - - public AeronauticalSignificantWeatherPhenomenon fromString(final String phen) { - for (final AeronauticalSignificantWeatherPhenomenon ph : AeronauticalSignificantWeatherPhenomenon.values()) { - if (ph.getText().equals(phen)) { - return ph; - } - } - return null; - } - - } - - @Deprecated - enum SigmetAirmetReportStatus { - NORMAL(0, AviationWeatherMessage.ReportStatus.NORMAL), // - CANCELLATION(1, AviationWeatherMessage.ReportStatus.NORMAL); - - private final int code; - private final AviationWeatherMessage.ReportStatus reportStatus; - - SigmetAirmetReportStatus(final int code, final AviationWeatherMessage.ReportStatus reportStatus) { - this.code = code; - this.reportStatus = reportStatus; - } - - public static SigmetAirmetReportStatus fromInt(final int code) { - switch (code) { - case 0: - return NORMAL; - case 1: - return CANCELLATION; - default: - throw new IllegalArgumentException("No value for code " + code); - } - } - - public static SigmetAirmetReportStatus fromReportStatus(final AviationWeatherMessage.ReportStatus reportStatus, final boolean cancelMessage) { - requireNonNull(reportStatus, "reportStatus"); - return cancelMessage ? CANCELLATION : NORMAL; - } - - public int getCode() { - return this.code; - } - - public AviationWeatherMessage.ReportStatus getReportStatus() { - return reportStatus; - } - - public boolean isCancelMessage() { - return this == CANCELLATION; - } - } - - enum SigmetEvolvingConditionCollectionTimeIndicatorType { - OBSERVATION, FORECAST - } - - //From: http://codes.wmo.int/49-2/WeatherCausingVisibilityReduction - enum WeatherCausingVisibilityReduction { - DZ("DZ", "Drizzle"), - DU("DU", "Dust"), - PO("PO", "Dust/sand whirls"), - DS("DS", "Duststorm"), - FG("FG", "Fog"), - FC("FC", "Funnel cloud"), - GR("GR", "Hail"), - HZ("HZ", "Haze"), - PL("PL", "Ice Pellets"), - BR("BR", "Mist"), - RA("RA", "Rain"), - SA("SA", "Sand"), - SS("SS", "Sandstorm"), - GS("GS", "Small hail"), - FU("FU", "Smoke"), - SN("SN", "Snow"), - SG("SG", "Snow grams"), - SQ("SQ", "Squall"), - VA("VA", "Volcanic Ash"); - - private final String text; - private final String description; - - WeatherCausingVisibilityReduction(final String s, final String description) { - this.text = s; - this.description = description; - } - - public static WeatherCausingVisibilityReduction fromString(final String weather) { - for (final WeatherCausingVisibilityReduction ph : WeatherCausingVisibilityReduction.values()) { - if (ph.getText().equals(weather)) { - return ph; - } - } - return null; - } - - public String getText() { - return text; - } - - public String getDescription() { - return description; - } - } - - enum AirmetPhenomenonParamInfo { - NEEDS_OBSCURATION, NEEDS_WIND, NEEDS_CLOUDLEVELS - } - - //From: http://codes.wmo.int/49-2/AirWxPhenomena - enum AeronauticalAirmetWeatherPhenomenon { - BKN_CLD("BKN_CLD", AirmetPhenomenonParamInfo.NEEDS_CLOUDLEVELS), - FRQ_CB("FRQ_CB"), - FRQ_TCU("FRQ_TCU"), - ISOL_CB("ISOL_CB"), - ISOL_TCU("ISOL_TCU"), - ISOL_TS("ISOL_TS"), - ISOL_TSGR("ISOL_TSGR"), - MOD_ICE("MOD_ICE"), - MOD_MTW("MOD_MTW"), - MOD_TURB("MOD_TURB"), - MT_OBSC("MT_OBSC"), - OCNL_CB("OCNL_CB"), - OCNL_TS("OCNL_TS"), - OCNL_TSGR("OCNL_TSGR"), - OCNL_TCU("OCNL_TCU"), - OVC_CLD("OVC_CLD", AirmetPhenomenonParamInfo.NEEDS_CLOUDLEVELS), - SFC_VIS("SFC_VIS", AirmetPhenomenonParamInfo.NEEDS_OBSCURATION), - SFC_WIND("SFC_WIND", AirmetPhenomenonParamInfo.NEEDS_WIND); - - private final String text; - private final AirmetPhenomenonParamInfo info; //does parameter need extra info - - AeronauticalAirmetWeatherPhenomenon(final String phen) { - this.text = phen; - this.info = null; - } - - AeronauticalAirmetWeatherPhenomenon(final String phen, final AirmetPhenomenonParamInfo info) { - this.text = phen; - this.info = info; - } - - public String getText() { - return this.text; - } - - public Optional getInfo() { - return Optional.ofNullable(info); - } - - public AeronauticalAirmetWeatherPhenomenon fromString(final String phen) { - for (final AeronauticalAirmetWeatherPhenomenon ph : AeronauticalAirmetWeatherPhenomenon.values()) { - if (ph.getText().equals(phen)) { - return ph; - } - } - return null; - } - } - - enum MessageType { - TAF, - METAR, - SPECI, - SIGMET, - GAFOR, - AIRMET, - TROPICAL_CYCLONE_ADVISORY, - VOLCANIC_ASH_ADVISORY, - BULLETIN, - GENERIC, - LOW_WIND, - WX_WARNING, - SPECIAL_AIR_REPORT, - WXREP, - SPACE_WEATHER_ADVISORY - } -} +package fi.fmi.avi.model; + +import fi.fmi.avi.model.taf.TAF; + +import java.util.Optional; + +import static fi.fmi.avi.model.AviationCodeListUser.RelationalOperator.BELOW; +import static java.util.Objects.requireNonNull; + +/** + * A convenience interface containing references to shared codelists and enums. + */ +public interface AviationCodeListUser { + + String CODELIST_CLOUD_AMOUNT_REPORTED_AT_AERODROME = "http://codes.wmo.int/49-2/CloudAmountReportedAtAerodrome"; + String CODELIST_SIGNIFICANT_CONVECTIVE_CLOUD_TYPE = "http://codes.wmo.int/49-2/SigConvectiveCloudType"; + + String CODELIST_VALUE_PREFIX_SIG_WEATHER = "http://codes.wmo.int/306/4678/"; + String CODELIST_VALUE_PREFIX_CLOUD_AMOUNT_REPORTED_AT_AERODROME = "http://codes.wmo.int/49-2/CloudAmountReportedAtAerodrome/"; + String CODELIST_VALUE_PREFIX_SIG_CONVECTIVE_CLOUD_TYPE = "http://codes.wmo.int/49-2/SigConvectiveCloudType/"; + String CODELIST_VALUE_PREFIX_SEA_SURFACE_STATE = "http://codes.wmo.int/bufr4/codeflag/0-22-061/"; + String CODELIST_VALUE_PREFIX_RUNWAY_DEPOSITS = "http://codes.wmo.int/bufr4/codeflag/0-20-086/"; + String CODELIST_VALUE_PREFIX_RUNWAY_CONTAMINATION = "http://codes.wmo.int/bufr4/codeflag/0-20-087/"; + String CODELIST_VALUE_PREFIX_RUNWAY_SURFACE_FRICTION_OR_BRAKING_ACTION = "http://codes.wmo.int/bufr4/codeflag/0-20-089/"; + + String CODELIST_VALUE_NIL_REASON_NOTHING_OF_OPERATIONAL_SIGNIFICANCE = "http://codes.wmo.int/common/nil/nothingOfOperationalSignificance"; + String CODELIST_VALUE_NIL_REASON_NOT_OBSERVABLE = "http://codes.wmo.int/common/nil/notObservable"; + String CODELIST_VALUE_NIL_REASON_NOT_DETECTED_BY_AUTO_SYSTEM = "http://codes.wmo.int/common/nil/notDetectedByAutoSystem"; + String CODELIST_VALUE_NIL_REASON_NO_SIGNIFICANT_CHANGE = "http://codes.wmo.int/common/nil/noSignificantChange"; + String CODELIST_VALUE_NIL_REASON_MISSING = "http://codes.wmo.int/common/nil/missing"; + String CODELIST_VALUE_NIL_REASON_INAPPLICABLE = "http://codes.wmo.int/common/nil/inapplicable"; + String CODELIST_VALUE_NIL_REASON_WITHHELD = "http://codes.wmo.int/common/nil/withheld"; + String CODELIST_VALUE_NIL_REASON_UNKNOWN = "http://codes.wmo.int/common/nil/unknown"; + + String MET_AERODROME_FORECAST_TYPE = "http://codes.wmo.int/49-2/observation-type/iwxxm/2.1/MeteorologicalAerodromeForecast"; + String MET_AERODROME_FORECAST_PROPERTIES = "http://codes.wmo.int/49-2/observable-property/MeteorologicalAerodromeForecast"; + String TAF_PROCEDURE_DESCRIPTION = "WMO No. 49 Volume 2 Meteorological Service for International Air Navigation APPENDIX 5 TECHNICAL SPECIFICATIONS RELATED TO FORECASTS"; + + String MET_AERODROME_OBSERVATION_TYPE = "http://codes.wmo.int/49-2/observation-type/iwxxm/2.1/MeteorologicalAerodromeObservation"; + String MET_AERODROME_OBSERVATION_PROPERTIES = "http://codes.wmo.int/49-2/observable-property/MeteorologicalAerodromeObservation"; + String METAR_PROCDURE_DESCRIPTION = "WMO No. 49 Volume 2 Meteorological Service for International Air Navigation APPENDIX 3 TECHNICAL SPECIFICATIONS RELATED TO METEOROLOGICAL OBSERVATIONS AND REPORTS"; + + String TREND_FORECAST_OBSERVATION_TYPE = "http://codes.wmo.int/49-2/observation-type/iwxxm/2.1/MeteorologicalAerodromeTrendForecast"; + String TREND_FORECAST_PROPERTIES = "http://codes.wmo.int/49-2/observable-property/MeteorologicalAerodromeTrendForecast"; + + String CODELIST_VALUE_PREFIX_OM_SAMPLING = "http://www.opengis.net/def/samplingFeatureType/OGC-OM/2.0/"; + String CODELIST_VALUE_EPSG_4326 = "http://www.opengis.net/def/crs/EPSG/0/4326"; + + String CODELIST_VALUE_SIGMET_PROCESS = "WMO No. 49 Volume 2 Meteorological Service for International Air Navigation APPENDIX 6-1 TECHNICAL SPECIFICATIONS " + + "RELATED TO SIGMET INFORMATION"; + String CODELIST_SIGMET_EVOLVING_CONDITION_COLLECTION_ANALYSIS = "http://codes.wmo.int/49-2/observation-type/iwxxm/2.1/SIGMETEvolvingConditionCollectionAnalysis"; + String CODELIST_SIGWX_PHENOMENA_ROOT = "http://codes.wmo.int/49-2/SigWxPhenomena/"; + String CODELIST_SIGMET_POSITION_COLLECTION_ANALYSIS = "http://codes.wmo.int/49-2/observable-property/SIGMETPositionCollectionAnalysis"; + + String CODELIST_AIRMET_PHENOMENA_ROOT = "http://codes.wmo.int/49-2/AirWxPhenomena/"; + String CODELIST_VALUE_AIRMET_PROCESS = "WMO No. 49 Volume 2 Meteorological Service for International Air Navigation APPENDIX 6-1 TECHNICAL SPECIFICATIONS " + + "RELATED TO AIRMET INFORMATION"; + String CODELIST_AIRMET_EVOLVING_CONDITION_COLLECTION_ANALYSIS = + "http://codes.wmo.int/49-2/observation-type/iwxxm/2" + ".1/AIRMETEvolvingConditionCollectionAnalysis"; + String CODELIST_VALUE_WEATHERCAUSINGVISIBILITYREDUCTION = "http://codes.wmo.int/49-2/WeatherCausingVisibilityReduction"; + + @Deprecated + enum MetarStatus { + NORMAL(0, AviationWeatherMessage.ReportStatus.NORMAL), // + CORRECTION(1, AviationWeatherMessage.ReportStatus.CORRECTION), // + MISSING(2, AviationWeatherMessage.ReportStatus.NORMAL); + + private final int code; + private final AviationWeatherMessage.ReportStatus reportStatus; + + MetarStatus(final int code, final AviationWeatherMessage.ReportStatus reportStatus) { + this.code = code; + this.reportStatus = reportStatus; + } + + public static MetarStatus fromInt(final int code) { + switch (code) { + case 0: + return NORMAL; + case 1: + return CORRECTION; + case 2: + return MISSING; + default: + throw new IllegalArgumentException("No value for code " + code); + } + } + + public static MetarStatus fromReportStatus(final AviationWeatherMessage.ReportStatus reportStatus, final boolean missingMessage) { + requireNonNull(reportStatus, "reportStatus"); + if (missingMessage) { + return MISSING; + } + switch (reportStatus) { + case CORRECTION: + case AMENDMENT: + return CORRECTION; + case NORMAL: + return NORMAL; + default: + throw new IllegalArgumentException("Unknown reportStatus: " + reportStatus); + } + } + + public int getCode() { + return this.code; + } + + public AviationWeatherMessage.ReportStatus getReportStatus() { + return reportStatus; + } + + public boolean isMissingMessage() { + return this == MISSING; + } + } + + /** + * TAF Status. + * + * @deprecated use {@link AviationWeatherMessage.ReportStatus}, {@link TAF#isCancelMessage()} and {@link TAF#isMissingMessage()} instead. + * In future releases this method will be made an internal implementation detail of IWXXM 2.1 conversion. + */ + @Deprecated + enum TAFStatus { + NORMAL(0, AviationWeatherMessage.ReportStatus.NORMAL),// + AMENDMENT(1, AviationWeatherMessage.ReportStatus.AMENDMENT),// + CANCELLATION(2, AviationWeatherMessage.ReportStatus.AMENDMENT),// + CORRECTION(3, AviationWeatherMessage.ReportStatus.CORRECTION),// + MISSING(4, AviationWeatherMessage.ReportStatus.NORMAL);// + + private final int code; + private final AviationWeatherMessage.ReportStatus reportStatus; + + TAFStatus(final int code, final AviationWeatherMessage.ReportStatus reportStatus) { + this.code = code; + this.reportStatus = reportStatus; + } + + public static TAFStatus fromInt(final int code) { + switch (code) { + case 0: + return NORMAL; + case 1: + return AMENDMENT; + case 2: + return CANCELLATION; + case 3: + return CORRECTION; + case 4: + return MISSING; + default: + throw new IllegalArgumentException("No value for code " + code); + } + } + + public static TAFStatus fromReportStatus(final AviationWeatherMessage.ReportStatus reportStatus, final boolean cancelMessage, + final boolean missingMessage) { + requireNonNull(reportStatus, "reportStatus"); + if (cancelMessage) { + return CANCELLATION; + } + if (missingMessage) { + return MISSING; + } + switch (reportStatus) { + case CORRECTION: + return CORRECTION; + case AMENDMENT: + return AMENDMENT; + case NORMAL: + return NORMAL; + default: + throw new IllegalArgumentException("Unknown reportStatus: " + reportStatus); + } + } + + public int getCode() { + return this.code; + } + + public AviationWeatherMessage.ReportStatus getReportStatus() { + return reportStatus; + } + + public boolean isCancelMessage() { + return this == CANCELLATION; + } + + public boolean isMissingMessage() { + return this == MISSING; + } + } + + enum RelationalOperator { + ABOVE(0), BELOW(1); + + private final int code; + + RelationalOperator(final int code) { + this.code = code; + } + + public static RelationalOperator fromInt(final int code) { + switch (code) { + case 0: + return ABOVE; + case 1: + return BELOW; + default: + throw new IllegalArgumentException("No value for code " + code); + } + } + + public int getCode() { + return this.code; + } + + } + + enum VisualRangeTendency { + UPWARD(0), NO_CHANGE(1), DOWNWARD(2), MISSING_VALUE(3); + + private final int code; + + VisualRangeTendency(final int code) { + this.code = code; + } + + public static VisualRangeTendency fromInt(final int code) { + switch (code) { + case 0: + return UPWARD; + case 1: + return NO_CHANGE; + case 2: + return DOWNWARD; + case 3: + return MISSING_VALUE; + default: + throw new IllegalArgumentException("No value for code " + code); + } + } + + public int getCode() { + return this.code; + } + + } + + enum CloudAmount { + SKC("SKC", 0), + FEW("FEW", 1), + SCT("SCT", 2), + BKN("BKN", 3), + OVC("OVC", 4), + ISOL("ISOL", 8), + OCNL("OCNL", 10), + FRQ("FRQ", 12), + LYR("LYR", 14), + EMBD("EMBD", 16); + + private final String code; + private final int bufrCode; + + CloudAmount(final String code, final int bufrCode) { + this.code = code; + this.bufrCode = bufrCode; + } + + public static CloudAmount fromInt(final int code) { + switch (code) { + case 0: + return SKC; + case 1: + return FEW; + case 2: + return SCT; + case 3: + return BKN; + case 4: + return OVC; + case 8: + return ISOL; + case 10: + return OCNL; + case 12: + return FRQ; + case 14: + return LYR; + case 16: + return EMBD; + default: + throw new IllegalArgumentException("No value for code " + code); + } + } + + public String getCode() { + return code; + } + + public int getBufrCode() { + return bufrCode; + } + } + + enum CloudType { + CB("CB", 9), TCU("TCU", 32); + + private final String code; + private final int bufrCode; + + CloudType(final String code, final int bufrCode) { + this.code = code; + this.bufrCode = bufrCode; + } + + public static CloudType fromInt(final int code) { + switch (code) { + case 9: + return CB; + case 32: + return TCU; + default: + throw new IllegalArgumentException("No value for code " + code); + } + } + + public String getCode() { + return code; + } + + public int getBufrCode() { + return bufrCode; + } + } + + enum SeaSurfaceState { + CALM_GLASSY(0), + CALM_RIPPLED(1), + SMOOTH_WAVELETS(2), + SLIGHT(3), + MODERATE(4), + ROUGH(5), + VERY_ROUGH(6), + HIGH(7), + VERY_HIGH(8), + PHENOMENAL(9), + MISSING_VALUE(15); + + private final int code; + + SeaSurfaceState(final int code) { + this.code = code; + } + + public static SeaSurfaceState fromInt(final int code) { + switch (code) { + case 0: + return CALM_GLASSY; + case 1: + return CALM_RIPPLED; + case 2: + return SMOOTH_WAVELETS; + case 3: + return SLIGHT; + case 4: + return MODERATE; + case 5: + return ROUGH; + case 6: + return VERY_ROUGH; + case 7: + return HIGH; + case 8: + return VERY_HIGH; + case 9: + return PHENOMENAL; + case 15: + return MISSING_VALUE; + default: + throw new IllegalArgumentException("No value for code " + code); + } + } + + public int getCode() { + return this.code; + } + } + + enum RunwayDeposit { + CLEAR_AND_DRY(0), DAMP(1), WET_WITH_WATER_PATCHES(2), RIME_AND_FROST_COVERED(3), // (depth normally less than 1mm) + DRY_SNOW(4), WET_SNOW(5), SLUSH(6), ICE(7), COMPACT_OR_ROLLED_SNOW(8), FROZEN_RUTS_OR_RIDGES(9), MISSING_OR_NOT_REPORTED(15); + + private final int code; + + RunwayDeposit(final int code) { + this.code = code; + } + + public static RunwayDeposit fromInt(final int code) { + switch (code) { + case 0: + return CLEAR_AND_DRY; + case 1: + return DAMP; + case 2: + return WET_WITH_WATER_PATCHES; + case 3: + return RIME_AND_FROST_COVERED; + case 4: + return DRY_SNOW; + case 5: + return WET_SNOW; + case 6: + return SLUSH; + case 7: + return ICE; + case 8: + return COMPACT_OR_ROLLED_SNOW; + case 9: + return FROZEN_RUTS_OR_RIDGES; + case 15: + return MISSING_OR_NOT_REPORTED; + default: + throw new IllegalArgumentException("No value for code " + code); + } + } + + public int getCode() { + return this.code; + } + } + + enum RunwayContamination { + PCT_COVERED_LESS_THAN_10(1), PCT_COVERED_11_25(2), PCT_COVERED_26_50(5), PCT_COVERED_51_100(9), MISSING_OR_NOT_REPORTED(15); + + private final int code; + + RunwayContamination(final int code) { + this.code = code; + } + + public static RunwayContamination fromInt(final int code) { + switch (code) { + case 1: + return PCT_COVERED_LESS_THAN_10; + case 2: + return PCT_COVERED_11_25; + case 5: + return PCT_COVERED_26_50; + case 9: + return PCT_COVERED_51_100; + case 15: + return MISSING_OR_NOT_REPORTED; + default: + throw new IllegalArgumentException("No value for code " + code); + } + } + + public int getCode() { + return this.code; + } + } + + enum BrakingAction { + POOR(91), MEDIUM_POOR(92), MEDIUM(93), MEDIUM_GOOD(94), GOOD(95); + + private final int code; + + BrakingAction(final int code) { + this.code = code; + } + + public static BrakingAction fromInt(final int code) { + switch (code) { + case 91: + return POOR; + case 92: + return MEDIUM_POOR; + case 93: + return MEDIUM; + case 94: + return MEDIUM_GOOD; + case 95: + return GOOD; + default: + return null; + } + } + + public int getCode() { + return this.code; + } + } + + enum TrendForecastChangeIndicator { + BECOMING(1), TEMPORARY_FLUCTUATIONS(2); + + private final int code; + + TrendForecastChangeIndicator(final int code) { + this.code = code; + } + + public static TrendForecastChangeIndicator fromInt(final int code) { + switch (code) { + case 1: + return BECOMING; + case 2: + return TEMPORARY_FLUCTUATIONS; + default: + throw new IllegalArgumentException("No value for code " + code); + } + } + + public int getCode() { + return this.code; + } + } + + enum TAFChangeIndicator { + BECOMING(1), + TEMPORARY_FLUCTUATIONS(2), + FROM(3), + PROBABILITY_30(4), + PROBABILITY_30_TEMPORARY_FLUCTUATIONS(5), + PROBABILITY_40(6), + PROBABILITY_40_TEMPORARY_FLUCTUATIONS(7); + + private final int code; + + TAFChangeIndicator(final int code) { + this.code = code; + } + + public static TAFChangeIndicator fromInt(final int code) { + switch (code) { + case 1: + return BECOMING; + case 2: + return TEMPORARY_FLUCTUATIONS; + case 3: + return FROM; + case 4: + return PROBABILITY_30; + case 5: + return PROBABILITY_30_TEMPORARY_FLUCTUATIONS; + case 6: + return PROBABILITY_40; + case 7: + return PROBABILITY_40_TEMPORARY_FLUCTUATIONS; + default: + throw new IllegalArgumentException("No value for code " + code); + } + } + + public int getCode() { + return this.code; + } + } + + enum ColorState { + BLU(2500, 8000), + WHT(1500, 5000), + GRN(700, 3700), + YLO1(500, 2500), + YLO2(300, 1600), + AMB(200, 800), + RED(200, 800, BELOW), + BLACK(-1, -1, null, true), + BLACKBLU(2500, 8000, null, true), + BLACKWHT(1500, 5000, null, true), + BLACKGRN(700, 3700, null, true), + BLACKYLO1(500, 2500, null, true), + BLACKYLO2(300, 1600, null, true), + BLACKAMB(200, 800, null, true), + BLACKRED(200, 800, BELOW, true); + + private final double minCloudHeight; + private final double minVisibility; + private final boolean unusable; + private final RelationalOperator operator; + + ColorState(final double cloudHeight, final double visibility) { + this(cloudHeight, visibility, null, false); + } + + ColorState(final double cloudHeight, final double visibility, final RelationalOperator operator) { + this(cloudHeight, visibility, operator, false); + } + + ColorState(final double cloudHeight, final double visibility, final RelationalOperator operator, final boolean unusable) { + this.minCloudHeight = cloudHeight; + this.minVisibility = visibility; + this.operator = operator; + this.unusable = unusable; + } + + public double getMinCloudHeight() { + return minCloudHeight; + } + + public double getMinVisibility() { + return minVisibility; + } + + public boolean isUnusable() { + return unusable; + } + + public RelationalOperator getOperator() { + return operator; + } + } + + enum PermissibleUsage {OPERATIONAL, NON_OPERATIONAL} + + enum PermissibleUsageReason {TEST, EXERCISE} + + //From: http://codes.wmo.int/49-2/SigWxPhenomena + enum AeronauticalSignificantWeatherPhenomenon { + EMBD_TS("EMBD_TS"), + EMBD_TSGR("EMBD_TSGR"), + FRQ_TS("FRQ_TS"), + FRQ_TSGR("FRQ_TSGR"), + HVY_DS("HVY_DS"), + HVY_SS("HVY_SS"), + OBSC_TS("OBSC_TS"), + OBSC_TSGR("OBSC_TSGR"), + RDOACT_CLD("RDOACT_CLD"), + SEV_ICE("SEV_ICE"), + SEV_ICE_FZRA("SEV_ICE_FZRA"), + SEV_MTW("SEV_MTW"), + SEV_TURB("SEV_TURB"), + SQL_TS("SQL_TS"), + SQL_TSGR("SQL_TSGR"), + TC("TC"), + VA("VA"); + + private final String text; + + AeronauticalSignificantWeatherPhenomenon(final String phen) { + this.text = phen; + } + + public String getText() { + return this.text; + } + + public AeronauticalSignificantWeatherPhenomenon fromString(final String phen) { + for (final AeronauticalSignificantWeatherPhenomenon ph : AeronauticalSignificantWeatherPhenomenon.values()) { + if (ph.getText().equals(phen)) { + return ph; + } + } + return null; + } + + } + + @Deprecated + enum SigmetAirmetReportStatus { + NORMAL(0, AviationWeatherMessage.ReportStatus.NORMAL), // + CANCELLATION(1, AviationWeatherMessage.ReportStatus.NORMAL); + + private final int code; + private final AviationWeatherMessage.ReportStatus reportStatus; + + SigmetAirmetReportStatus(final int code, final AviationWeatherMessage.ReportStatus reportStatus) { + this.code = code; + this.reportStatus = reportStatus; + } + + public static SigmetAirmetReportStatus fromInt(final int code) { + switch (code) { + case 0: + return NORMAL; + case 1: + return CANCELLATION; + default: + throw new IllegalArgumentException("No value for code " + code); + } + } + + public static SigmetAirmetReportStatus fromReportStatus(final AviationWeatherMessage.ReportStatus reportStatus, final boolean cancelMessage) { + requireNonNull(reportStatus, "reportStatus"); + return cancelMessage ? CANCELLATION : NORMAL; + } + + public int getCode() { + return this.code; + } + + public AviationWeatherMessage.ReportStatus getReportStatus() { + return reportStatus; + } + + public boolean isCancelMessage() { + return this == CANCELLATION; + } + } + + enum SigmetEvolvingConditionCollectionTimeIndicatorType { + OBSERVATION, FORECAST + } + + //From: http://codes.wmo.int/49-2/WeatherCausingVisibilityReduction + enum WeatherCausingVisibilityReduction { + DZ("DZ", "Drizzle"), + DU("DU", "Dust"), + PO("PO", "Dust/sand whirls"), + DS("DS", "Duststorm"), + FG("FG", "Fog"), + FC("FC", "Funnel cloud"), + GR("GR", "Hail"), + HZ("HZ", "Haze"), + PL("PL", "Ice Pellets"), + BR("BR", "Mist"), + RA("RA", "Rain"), + SA("SA", "Sand"), + SS("SS", "Sandstorm"), + GS("GS", "Small hail"), + FU("FU", "Smoke"), + SN("SN", "Snow"), + SG("SG", "Snow grams"), + SQ("SQ", "Squall"), + VA("VA", "Volcanic Ash"); + + private final String text; + private final String description; + + WeatherCausingVisibilityReduction(final String s, final String description) { + this.text = s; + this.description = description; + } + + public static WeatherCausingVisibilityReduction fromString(final String weather) { + for (final WeatherCausingVisibilityReduction ph : WeatherCausingVisibilityReduction.values()) { + if (ph.getText().equals(weather)) { + return ph; + } + } + return null; + } + + public String getText() { + return text; + } + + public String getDescription() { + return description; + } + } + + enum AirmetPhenomenonParamInfo { + NEEDS_OBSCURATION, NEEDS_WIND, NEEDS_CLOUDLEVELS + } + + //From: http://codes.wmo.int/49-2/AirWxPhenomena + enum AeronauticalAirmetWeatherPhenomenon { + BKN_CLD("BKN_CLD", AirmetPhenomenonParamInfo.NEEDS_CLOUDLEVELS), + FRQ_CB("FRQ_CB"), + FRQ_TCU("FRQ_TCU"), + ISOL_CB("ISOL_CB"), + ISOL_TCU("ISOL_TCU"), + ISOL_TS("ISOL_TS"), + ISOL_TSGR("ISOL_TSGR"), + MOD_ICE("MOD_ICE"), + MOD_MTW("MOD_MTW"), + MOD_TURB("MOD_TURB"), + MT_OBSC("MT_OBSC"), + OCNL_CB("OCNL_CB"), + OCNL_TS("OCNL_TS"), + OCNL_TSGR("OCNL_TSGR"), + OCNL_TCU("OCNL_TCU"), + OVC_CLD("OVC_CLD", AirmetPhenomenonParamInfo.NEEDS_CLOUDLEVELS), + SFC_VIS("SFC_VIS", AirmetPhenomenonParamInfo.NEEDS_OBSCURATION), + SFC_WIND("SFC_WIND", AirmetPhenomenonParamInfo.NEEDS_WIND); + + private final String text; + private final AirmetPhenomenonParamInfo info; //does parameter need extra info + + AeronauticalAirmetWeatherPhenomenon(final String phen) { + this.text = phen; + this.info = null; + } + + AeronauticalAirmetWeatherPhenomenon(final String phen, final AirmetPhenomenonParamInfo info) { + this.text = phen; + this.info = info; + } + + public String getText() { + return this.text; + } + + public Optional getInfo() { + return Optional.ofNullable(info); + } + + public AeronauticalAirmetWeatherPhenomenon fromString(final String phen) { + for (final AeronauticalAirmetWeatherPhenomenon ph : AeronauticalAirmetWeatherPhenomenon.values()) { + if (ph.getText().equals(phen)) { + return ph; + } + } + return null; + } + } + + enum SigmetPhenomenonType { + SIGMET("WS"), + TROPICAL_CYCLONE_SIGMET("WC"), + VOLCANIC_ASH_SIGMET("WV"); + + private String type; + + SigmetPhenomenonType(final String type) { + this.type = type; + } + + public String getType() { + return type; + } + } + + enum MessageType { + TAF, + METAR, + SPECI, + SIGMET, + GAFOR, + AIRMET, + TROPICAL_CYCLONE_ADVISORY, + VOLCANIC_ASH_ADVISORY, + BULLETIN, + GENERIC, + LOW_WIND, + WX_WARNING, + SPECIAL_AIR_REPORT, + WXREP, + SPACE_WEATHER_ADVISORY + } +} diff --git a/src/main/java/fi/fmi/avi/model/sigmet/SIGMET.java b/src/main/java/fi/fmi/avi/model/sigmet/SIGMET.java index b647fd6..5deb5a6 100644 --- a/src/main/java/fi/fmi/avi/model/sigmet/SIGMET.java +++ b/src/main/java/fi/fmi/avi/model/sigmet/SIGMET.java @@ -7,6 +7,9 @@ import java.util.Optional; public interface SIGMET extends SIGMETAIRMET { + + SigmetPhenomenonType getPhenomenonType(); + Optional getPhenomenon(); Optional getCancelledReference(); diff --git a/src/main/java/fi/fmi/avi/model/sigmet/immutable/SIGMETImpl.java b/src/main/java/fi/fmi/avi/model/sigmet/immutable/SIGMETImpl.java index a7f038d..a914fff 100644 --- a/src/main/java/fi/fmi/avi/model/sigmet/immutable/SIGMETImpl.java +++ b/src/main/java/fi/fmi/avi/model/sigmet/immutable/SIGMETImpl.java @@ -1,277 +1,267 @@ -package fi.fmi.avi.model.sigmet.immutable; - -import static java.util.Objects.requireNonNull; - -import java.io.Serializable; -import java.util.List; -import java.util.Objects; -import java.util.Optional; -import java.util.function.UnaryOperator; - -import org.inferred.freebuilder.FreeBuilder; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonPropertyOrder; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; - -import fi.fmi.avi.model.AirTrafficServicesUnitWeatherMessageBuilderHelper; -import fi.fmi.avi.model.Airspace; -import fi.fmi.avi.model.AviationWeatherMessageBuilderHelper; -import fi.fmi.avi.model.BuilderHelper; -import fi.fmi.avi.model.PartialOrCompleteTimeInstant; -import fi.fmi.avi.model.PartialOrCompleteTimePeriod; -import fi.fmi.avi.model.PhenomenonGeometry; -import fi.fmi.avi.model.PhenomenonGeometryWithHeight; -import fi.fmi.avi.model.SIGMETAIRMETBuilderHelper; -import fi.fmi.avi.model.UnitPropertyGroup; -import fi.fmi.avi.model.immutable.AirspaceImpl; -import fi.fmi.avi.model.immutable.PhenomenonGeometryImpl; -import fi.fmi.avi.model.immutable.PhenomenonGeometryWithHeightImpl; -import fi.fmi.avi.model.immutable.UnitPropertyGroupImpl; -import fi.fmi.avi.model.sigmet.SIGMET; -import fi.fmi.avi.model.sigmet.Reference; -import fi.fmi.avi.model.sigmet.VAInfo; - -@FreeBuilder -@JsonDeserialize(builder = SIGMETImpl.Builder.class) -@JsonInclude(JsonInclude.Include.NON_DEFAULT) -@JsonPropertyOrder({ "reportStatus", "cancelMessage", "issuingAirTrafficServicesUnit", "meteorologicalWatchOffice", - "sequenceNumber", "issueTime", - "validityPeriod", "airspace", "phenomenon", "analysisGeometries", "forecastGeometries", "volcano", - "volcanicAshMovedToFIR", "cancelledReport", "remarks", "permissibleUsage", "permissibleUsageReason", - "permissibleUsageSupplementary", "translated", - "translatedBulletinID", "translatedBulletinReceptionTime", "translationCentreDesignator", - "translationCentreName", "translationTime", "translatedTAC" }) -public abstract class SIGMETImpl implements SIGMET, Serializable { - private static final long serialVersionUID = -5959366555363410747L; - - public static Builder builder() { - return new Builder(); - } - - public static SIGMETImpl immutableCopyOf(final SIGMET sigmet) { - Objects.requireNonNull(sigmet); - if (sigmet instanceof SIGMETImpl) { - return (SIGMETImpl) sigmet; - } else { - return Builder.from(sigmet).build(); - } - } - - public static Optional immutableCopyOf(final Optional sigmet) { - Objects.requireNonNull(sigmet); - return sigmet.map(SIGMETImpl::immutableCopyOf); - } - - @Override - @JsonIgnore - @Deprecated - public SigmetAirmetReportStatus getStatus() { - return SIGMET.super.getStatus(); - } - - public abstract Builder toBuilder(); - - @Override - @JsonIgnore - public boolean areAllTimeReferencesComplete() { - if (!this.getValidityPeriod().isComplete()) { - return false; - } - if (this.getAnalysisGeometries().isPresent()) { - for (final PhenomenonGeometryWithHeight geometryWithHeight : this.getAnalysisGeometries().get()) { - if (geometryWithHeight.getTime().isPresent() - && !geometryWithHeight.getTime().get().getCompleteTime().isPresent()) { - return false; - } - } - } - if (this.getForecastGeometries().isPresent()) { - for (final PhenomenonGeometry geometry : this.getForecastGeometries().get()) { - if (geometry.getTime().isPresent() && !geometry.getTime().get().getCompleteTime().isPresent()) { - return false; - } - } - } - return !this.getCancelledReference().isPresent() - || (this.getCancelledReference().get().getValidityPeriod().isComplete()); - } - - public static class Builder extends SIGMETImpl_Builder { - - Builder() { - this.setTranslated(false); - this.setReportStatus(ReportStatus.NORMAL); - this.setCancelMessage(false); - } - - public static Builder from(final SIGMET value) { - if (value instanceof SIGMETImpl) { - return ((SIGMETImpl) value).toBuilder(); - } else { - final Builder builder = builder(); - AviationWeatherMessageBuilderHelper.copyFrom(builder, value, // - Builder::setReportStatus, // - Builder::setIssueTime, // - Builder::setRemarks, // - Builder::setPermissibleUsage, // - Builder::setPermissibleUsageReason, // - Builder::setPermissibleUsageSupplementary, // - Builder::setTranslated, // - Builder::setTranslatedBulletinID, // - Builder::setTranslatedBulletinReceptionTime, // - Builder::setTranslationCentreDesignator, // - Builder::setTranslationCentreName, // - Builder::setTranslationTime, // - Builder::setTranslatedTAC); - AirTrafficServicesUnitWeatherMessageBuilderHelper.copyFrom(builder, value, // - Builder::setIssuingAirTrafficServicesUnit, // - Builder::setMeteorologicalWatchOffice); - SIGMETAIRMETBuilderHelper.copyFrom(builder, value, // - Builder::setSequenceNumber, // - Builder::setValidityPeriod, // - Builder::setAirspace, // - Builder::setCancelMessage); - return builder// - .setPhenomenon(value.getPhenomenon())// - .setCancelledReference(SigmetReferenceImpl.immutableCopyOf(value.getCancelledReference()))// - .setAnalysisGeometries(value.getAnalysisGeometries()// - .map(analysisGeometries -> BuilderHelper.toImmutableList(analysisGeometries, - PhenomenonGeometryWithHeightImpl::immutableCopyOf)))// - .setForecastGeometries(value.getForecastGeometries()// - .map(forecastGeometries -> BuilderHelper.toImmutableList(forecastGeometries, - PhenomenonGeometryImpl::immutableCopyOf)))// - .setVAInfo(VAInfoImpl.immutableCopyOf(value.getVAInfo())); - } - } - - @Override - @JsonDeserialize(as = UnitPropertyGroupImpl.class) - public Builder setIssuingAirTrafficServicesUnit(final UnitPropertyGroup issuingAirTrafficServicesUnit) { - return super.setIssuingAirTrafficServicesUnit(issuingAirTrafficServicesUnit); - } - - @Override - @JsonDeserialize(contentAs = PhenomenonGeometryWithHeightImpl.class) - public Builder setAnalysisGeometries(final List analysis) { - return super.setAnalysisGeometries(analysis); - } - - @Override - @JsonDeserialize(contentAs = PhenomenonGeometryImpl.class) - public Builder setForecastGeometries(final List analysis) { - return super.setForecastGeometries(analysis); - } - - @Override - @JsonDeserialize(as = UnitPropertyGroupImpl.class) - public Builder setMeteorologicalWatchOffice(final UnitPropertyGroup meteorologicalWatchOffice) { - return super.setMeteorologicalWatchOffice(meteorologicalWatchOffice); - } - - @Override - @JsonDeserialize(as = SigmetReferenceImpl.class) - public Builder setCancelledReference(final Reference cancelledReference) { - return super.setCancelledReference(cancelledReference); - } - - @Override - @JsonDeserialize(as = PartialOrCompleteTimeInstant.class) - public Builder setIssueTime(final PartialOrCompleteTimeInstant issueTime) { - return super.setIssueTime(issueTime); - } - - @Override - @JsonDeserialize(as = PartialOrCompleteTimePeriod.class) - public Builder setValidityPeriod(final PartialOrCompleteTimePeriod validityPeriod) { - return super.setValidityPeriod(validityPeriod); - } - - @Override - @JsonDeserialize(as = VAInfoImpl.class) - @JsonProperty("VAInfo") - public Builder setVAInfo(final VAInfo vaInfo) { - return super.setVAInfo(vaInfo); - } - - @Override - @JsonIgnore - @JsonDeserialize(as = VAInfoImpl.class) - public Builder setVAInfo(final Optional vaInfo) { - return super.setVAInfo(vaInfo); - } - - @Override - @JsonDeserialize(as = AirspaceImpl.class) - public Builder setAirspace(final Airspace airspace) { - return super.setAirspace(airspace); - } - - @Deprecated - public Builder mapStatus(final UnaryOperator mapper) { - requireNonNull(mapper, "mapper"); - return setStatus(mapper.apply(getStatus())); - } - - /** - * Provides the current builder value of the status property. - * - * Note, this method is provided for backward compatibility with previous - * versions of the API. The status is no longer - * explicitly stored. This implementation uses - * {@link SigmetAirmetReportStatus#fromReportStatus(ReportStatus, boolean)} - * instead to determine the - * returned value on-the-fly. - * - * @return the message status - * - * @deprecated migrate to using a combination of {@link #getReportStatus()} and - * {@link #isCancelMessage()} instead - */ - @Deprecated - public SigmetAirmetReportStatus getStatus() { - return SigmetAirmetReportStatus.fromReportStatus(getReportStatus(), isCancelMessage()); - } - - /** - * Sets the SIGMET-specific message status. - * - * Note, this method is provided for backward compatibility with previous - * versions of the API. The status is no longer - * explicitly stored. Instead, this method sets other property values with the - * following logic: - *
- *
{@link fi.fmi.avi.model.AviationCodeListUser.SigmetAirmetReportStatus#CANCELLATION - * CANCELLATION}
- *
- * reportStatus = {@link fi.fmi.avi.model.AviationWeatherMessage.ReportStatus#NORMAL NORMAL}
- * cancelMessage = true
- *
- * - *
{@link fi.fmi.avi.model.AviationCodeListUser.SigmetAirmetReportStatus#NORMAL - * NORMAL}
- *
- * reportStatus = {@link fi.fmi.avi.model.AviationWeatherMessage.ReportStatus#NORMAL NORMAL}
- * cancelMessage = false
- *
- *
- * - * @param status - * the status to set - * - * @return builder - * - * @deprecated migrate to using a combination of - * {@link #setReportStatus(ReportStatus)} and - * {@link #setCancelMessage(boolean)} instead - */ - @Deprecated - public Builder setStatus(final SigmetAirmetReportStatus status) { - requireNonNull(status); - return setReportStatus(status.getReportStatus())// - .setCancelMessage(status.isCancelMessage()); - } - } -} +package fi.fmi.avi.model.sigmet.immutable; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import fi.fmi.avi.model.*; +import fi.fmi.avi.model.immutable.AirspaceImpl; +import fi.fmi.avi.model.immutable.PhenomenonGeometryImpl; +import fi.fmi.avi.model.immutable.PhenomenonGeometryWithHeightImpl; +import fi.fmi.avi.model.immutable.UnitPropertyGroupImpl; +import fi.fmi.avi.model.sigmet.Reference; +import fi.fmi.avi.model.sigmet.SIGMET; +import fi.fmi.avi.model.sigmet.VAInfo; +import org.inferred.freebuilder.FreeBuilder; + +import java.io.Serializable; +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.function.UnaryOperator; + +import static java.util.Objects.requireNonNull; + +@FreeBuilder +@JsonDeserialize(builder = SIGMETImpl.Builder.class) +@JsonInclude(JsonInclude.Include.NON_DEFAULT) +@JsonPropertyOrder({ "reportStatus", "cancelMessage", "issuingAirTrafficServicesUnit", "meteorologicalWatchOffice", + "sequenceNumber", "issueTime", + "validityPeriod", "airspace", "phenomenonType", "phenomenon", "analysisGeometries", "forecastGeometries", "volcano", + "volcanicAshMovedToFIR", "cancelledReport", "remarks", "permissibleUsage", "permissibleUsageReason", + "permissibleUsageSupplementary", "translated", + "translatedBulletinID", "translatedBulletinReceptionTime", "translationCentreDesignator", + "translationCentreName", "translationTime", "translatedTAC" }) +public abstract class SIGMETImpl implements SIGMET, Serializable { + private static final long serialVersionUID = -5959366555363410747L; + + public static Builder builder() { + return new Builder(); + } + + public static SIGMETImpl immutableCopyOf(final SIGMET sigmet) { + Objects.requireNonNull(sigmet); + if (sigmet instanceof SIGMETImpl) { + return (SIGMETImpl) sigmet; + } else { + return Builder.from(sigmet).build(); + } + } + + public static Optional immutableCopyOf(final Optional sigmet) { + Objects.requireNonNull(sigmet); + return sigmet.map(SIGMETImpl::immutableCopyOf); + } + + @Override + @JsonIgnore + @Deprecated + public SigmetAirmetReportStatus getStatus() { + return SIGMET.super.getStatus(); + } + + public abstract Builder toBuilder(); + + @Override + @JsonIgnore + public boolean areAllTimeReferencesComplete() { + if (!this.getValidityPeriod().isComplete()) { + return false; + } + if (this.getAnalysisGeometries().isPresent()) { + for (final PhenomenonGeometryWithHeight geometryWithHeight : this.getAnalysisGeometries().get()) { + if (geometryWithHeight.getTime().isPresent() + && !geometryWithHeight.getTime().get().getCompleteTime().isPresent()) { + return false; + } + } + } + if (this.getForecastGeometries().isPresent()) { + for (final PhenomenonGeometry geometry : this.getForecastGeometries().get()) { + if (geometry.getTime().isPresent() && !geometry.getTime().get().getCompleteTime().isPresent()) { + return false; + } + } + } + return !this.getCancelledReference().isPresent() + || (this.getCancelledReference().get().getValidityPeriod().isComplete()); + } + + public static class Builder extends SIGMETImpl_Builder { + + Builder() { + this.setTranslated(false); + this.setReportStatus(ReportStatus.NORMAL); + this.setCancelMessage(false); + } + + public static Builder from(final SIGMET value) { + if (value instanceof SIGMETImpl) { + return ((SIGMETImpl) value).toBuilder(); + } else { + final Builder builder = builder(); + AviationWeatherMessageBuilderHelper.copyFrom(builder, value, // + Builder::setReportStatus, // + Builder::setIssueTime, // + Builder::setRemarks, // + Builder::setPermissibleUsage, // + Builder::setPermissibleUsageReason, // + Builder::setPermissibleUsageSupplementary, // + Builder::setTranslated, // + Builder::setTranslatedBulletinID, // + Builder::setTranslatedBulletinReceptionTime, // + Builder::setTranslationCentreDesignator, // + Builder::setTranslationCentreName, // + Builder::setTranslationTime, // + Builder::setTranslatedTAC); + AirTrafficServicesUnitWeatherMessageBuilderHelper.copyFrom(builder, value, // + Builder::setIssuingAirTrafficServicesUnit, // + Builder::setMeteorologicalWatchOffice); + SIGMETAIRMETBuilderHelper.copyFrom(builder, value, // + Builder::setSequenceNumber, // + Builder::setValidityPeriod, // + Builder::setAirspace, // + Builder::setCancelMessage); + return builder// + .setPhenomenonType(value.getPhenomenonType())// + .setPhenomenon(value.getPhenomenon())// + .setCancelledReference(SigmetReferenceImpl.immutableCopyOf(value.getCancelledReference()))// + .setAnalysisGeometries(value.getAnalysisGeometries()// + .map(analysisGeometries -> BuilderHelper.toImmutableList(analysisGeometries, + PhenomenonGeometryWithHeightImpl::immutableCopyOf)))// + .setForecastGeometries(value.getForecastGeometries()// + .map(forecastGeometries -> BuilderHelper.toImmutableList(forecastGeometries, + PhenomenonGeometryImpl::immutableCopyOf)))// + .setVAInfo(VAInfoImpl.immutableCopyOf(value.getVAInfo())); + } + } + + @Override + @JsonDeserialize(as = UnitPropertyGroupImpl.class) + public Builder setIssuingAirTrafficServicesUnit(final UnitPropertyGroup issuingAirTrafficServicesUnit) { + return super.setIssuingAirTrafficServicesUnit(issuingAirTrafficServicesUnit); + } + + @Override + @JsonDeserialize(contentAs = PhenomenonGeometryWithHeightImpl.class) + public Builder setAnalysisGeometries(final List analysis) { + return super.setAnalysisGeometries(analysis); + } + + @Override + @JsonDeserialize(contentAs = PhenomenonGeometryImpl.class) + public Builder setForecastGeometries(final List analysis) { + return super.setForecastGeometries(analysis); + } + + @Override + @JsonDeserialize(as = UnitPropertyGroupImpl.class) + public Builder setMeteorologicalWatchOffice(final UnitPropertyGroup meteorologicalWatchOffice) { + return super.setMeteorologicalWatchOffice(meteorologicalWatchOffice); + } + + @Override + @JsonDeserialize(as = SigmetReferenceImpl.class) + public Builder setCancelledReference(final Reference cancelledReference) { + return super.setCancelledReference(cancelledReference); + } + + @Override + @JsonDeserialize(as = PartialOrCompleteTimeInstant.class) + public Builder setIssueTime(final PartialOrCompleteTimeInstant issueTime) { + return super.setIssueTime(issueTime); + } + + @Override + @JsonDeserialize(as = PartialOrCompleteTimePeriod.class) + public Builder setValidityPeriod(final PartialOrCompleteTimePeriod validityPeriod) { + return super.setValidityPeriod(validityPeriod); + } + + @Override + @JsonDeserialize(as = VAInfoImpl.class) + @JsonProperty("VAInfo") + public Builder setVAInfo(final VAInfo vaInfo) { + return super.setVAInfo(vaInfo); + } + + @Override + @JsonIgnore + @JsonDeserialize(as = VAInfoImpl.class) + public Builder setVAInfo(final Optional vaInfo) { + return super.setVAInfo(vaInfo); + } + + @Override + @JsonDeserialize(as = AirspaceImpl.class) + public Builder setAirspace(final Airspace airspace) { + return super.setAirspace(airspace); + } + + @Deprecated + public Builder mapStatus(final UnaryOperator mapper) { + requireNonNull(mapper, "mapper"); + return setStatus(mapper.apply(getStatus())); + } + + /** + * Provides the current builder value of the status property. + * + * Note, this method is provided for backward compatibility with previous + * versions of the API. The status is no longer + * explicitly stored. This implementation uses + * {@link SigmetAirmetReportStatus#fromReportStatus(ReportStatus, boolean)} + * instead to determine the + * returned value on-the-fly. + * + * @return the message status + * + * @deprecated migrate to using a combination of {@link #getReportStatus()} and + * {@link #isCancelMessage()} instead + */ + @Deprecated + public SigmetAirmetReportStatus getStatus() { + return SigmetAirmetReportStatus.fromReportStatus(getReportStatus(), isCancelMessage()); + } + + /** + * Sets the SIGMET-specific message status. + * + * Note, this method is provided for backward compatibility with previous + * versions of the API. The status is no longer + * explicitly stored. Instead, this method sets other property values with the + * following logic: + *
+ *
{@link fi.fmi.avi.model.AviationCodeListUser.SigmetAirmetReportStatus#CANCELLATION + * CANCELLATION}
+ *
+ * reportStatus = {@link fi.fmi.avi.model.AviationWeatherMessage.ReportStatus#NORMAL NORMAL}
+ * cancelMessage = true
+ *
+ * + *
{@link fi.fmi.avi.model.AviationCodeListUser.SigmetAirmetReportStatus#NORMAL + * NORMAL}
+ *
+ * reportStatus = {@link fi.fmi.avi.model.AviationWeatherMessage.ReportStatus#NORMAL NORMAL}
+ * cancelMessage = false
+ *
+ *
+ * + * @param status + * the status to set + * + * @return builder + * + * @deprecated migrate to using a combination of + * {@link #setReportStatus(ReportStatus)} and + * {@link #setCancelMessage(boolean)} instead + */ + @Deprecated + public Builder setStatus(final SigmetAirmetReportStatus status) { + requireNonNull(status); + return setReportStatus(status.getReportStatus())// + .setCancelMessage(status.isCancelMessage()); + } + } +} diff --git a/src/test/java/fi/fmi/avi/converter/json/JSONSigmetConverterTest.java b/src/test/java/fi/fmi/avi/converter/json/JSONSigmetConverterTest.java index 70152a2..fbde13b 100644 --- a/src/test/java/fi/fmi/avi/converter/json/JSONSigmetConverterTest.java +++ b/src/test/java/fi/fmi/avi/converter/json/JSONSigmetConverterTest.java @@ -1,136 +1,122 @@ -package fi.fmi.avi.converter.json; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertSame; -import static org.junit.Assert.assertTrue; - -import java.io.InputStream; -import java.time.ZonedDateTime; -import java.util.Collections; -import java.util.Objects; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; -import org.springframework.test.context.support.AnnotationConfigContextLoader; -import org.unitils.thirdparty.org.apache.commons.io.IOUtils; - -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.datatype.jdk8.Jdk8Module; -import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; - -import fi.fmi.avi.converter.AviMessageConverter; -import fi.fmi.avi.converter.ConversionHints; -import fi.fmi.avi.converter.ConversionResult; -import fi.fmi.avi.converter.json.conf.JSONConverter; -import fi.fmi.avi.model.Airspace; -import fi.fmi.avi.model.AviationCodeListUser; -import fi.fmi.avi.model.AviationWeatherMessage; -import fi.fmi.avi.model.Geometry; -import fi.fmi.avi.model.PartialOrCompleteTimeInstant; -import fi.fmi.avi.model.PartialOrCompleteTimePeriod; -import fi.fmi.avi.model.UnitPropertyGroup; -import fi.fmi.avi.model.immutable.AirspaceImpl; -import fi.fmi.avi.model.immutable.NumericMeasureImpl; -import fi.fmi.avi.model.immutable.PhenomenonGeometryImpl; -import fi.fmi.avi.model.immutable.PhenomenonGeometryWithHeightImpl; -import fi.fmi.avi.model.immutable.TacOrGeoGeometryImpl; -import fi.fmi.avi.model.immutable.UnitPropertyGroupImpl; -import fi.fmi.avi.model.sigmet.SIGMET; -import fi.fmi.avi.model.sigmet.SigmetAnalysisType; -import fi.fmi.avi.model.sigmet.SigmetIntensityChange; -import fi.fmi.avi.model.sigmet.immutable.SIGMETImpl; - -@RunWith(SpringJUnit4ClassRunner.class) -@ContextConfiguration(classes = JSONSigmetTestConfiguration.class, loader = AnnotationConfigContextLoader.class) -public class JSONSigmetConverterTest { - - @Autowired - private AviMessageConverter converter; - - public void testSIGMETParsing() throws Exception { - final InputStream is = JSONSigmetConverterTest.class.getResourceAsStream("sigmet1.json"); - Objects.requireNonNull(is); - final String input = IOUtils.toString(is, "UTF-8"); - is.close(); - final ConversionResult result = converter.convertMessage(input, - JSONConverter.JSON_STRING_TO_SIGMET_POJO, ConversionHints.EMPTY); - assertSame(ConversionResult.Status.SUCCESS, result.getStatus()); - } - - @Test - public void testSIGMETSerialization() throws Exception { - final ObjectMapper om = new ObjectMapper(); - om.registerModule(new Jdk8Module()); - om.registerModule(new JavaTimeModule()); - - final InputStream is = JSONSigmetConverterTest.class.getResourceAsStream("sigmet1.json"); - Objects.requireNonNull(is); - final String reference = IOUtils.toString(is, "UTF-8"); - is.close(); - - final SIGMETImpl.Builder builder = SIGMETImpl.builder(); - - final UnitPropertyGroup mwo = new UnitPropertyGroupImpl.Builder().setPropertyGroup("De Bilt", "EHDB", "MWO") - .build(); - final UnitPropertyGroup fir = new UnitPropertyGroupImpl.Builder() - .setPropertyGroup("AMSTERDAM FIR", "EHAA", "FIR").build(); - - final Airspace airspace = new AirspaceImpl.Builder().setDesignator("EHAA").setType(Airspace.AirspaceType.FIR) - .setName("AMSTERDAM").build(); - - final String geomString = "{ \"type\": \"Polygon\", \"exteriorRingPositions\":[5.0,52.0,6.0,53.0,4.0,54.0,5.0,52.0]}"; - final Geometry geom = om.readValue(geomString, Geometry.class); - final String fpaGeomString = "{ \"type\": \"Polygon\", \"exteriorRingPositions\":[5.0,53.0,6.0,54.0,4.0,55.0,5.0,53.0]}"; - final Geometry fpaGeom = om.readValue(fpaGeomString, Geometry.class); - - final PartialOrCompleteTimeInstant.Builder issueTimeBuilder = PartialOrCompleteTimeInstant.builder(); - issueTimeBuilder.setCompleteTime(ZonedDateTime.parse("2017-08-27T11:30:00Z")); - final PartialOrCompleteTimePeriod.Builder validPeriod = PartialOrCompleteTimePeriod.builder(); - validPeriod.setStartTime(PartialOrCompleteTimeInstant.of(ZonedDateTime.parse("2017-08-27T11:30:00Z"))); - validPeriod.setEndTime(PartialOrCompleteTimeInstant.of(ZonedDateTime.parse("2017-08-27T18:00:00Z"))); - - final PhenomenonGeometryWithHeightImpl.Builder geomBuilder = PhenomenonGeometryWithHeightImpl.builder(); - geomBuilder.setApproximateLocation(false); - geomBuilder.setGeometry(TacOrGeoGeometryImpl.of(geom)); - geomBuilder.setTime(PartialOrCompleteTimeInstant.of(ZonedDateTime.parse("2017-08-27T12:00:00Z"))); - geomBuilder.setLowerLimit(NumericMeasureImpl.of(10, "FL")); - geomBuilder.setUpperLimit(NumericMeasureImpl.of(35, "FL")); - geomBuilder.setIntensityChange(SigmetIntensityChange.NO_CHANGE); - geomBuilder.setAnalysisType(SigmetAnalysisType.OBSERVATION); - - final PhenomenonGeometryImpl.Builder fpGeomBuilder = PhenomenonGeometryImpl.builder(); - fpGeomBuilder.setApproximateLocation(false); - fpGeomBuilder.setGeometry(TacOrGeoGeometryImpl.of(fpaGeom)); - fpGeomBuilder.setTime(PartialOrCompleteTimeInstant.of(ZonedDateTime.parse("2017-08-27T18:00:00Z"))); - - builder.setReportStatus(AviationWeatherMessage.ReportStatus.NORMAL) - .setCancelMessage(false) - .setMeteorologicalWatchOffice(mwo) - .setIssuingAirTrafficServicesUnit(fir) - .setAirspace(airspace) - .setIssueTime(issueTimeBuilder.build()) - .setTranslated(true) - .setPermissibleUsage(AviationCodeListUser.PermissibleUsage.NON_OPERATIONAL) - .setPermissibleUsageReason(AviationCodeListUser.PermissibleUsageReason.EXERCISE) - .setSequenceNumber("1") - - .setValidityPeriod(validPeriod.build()) - .setPhenomenon(AviationCodeListUser.AeronauticalSignificantWeatherPhenomenon.EMBD_TS) - .setAnalysisGeometries(Collections.singletonList(geomBuilder.build())) - .setForecastGeometries(Collections.singletonList(fpGeomBuilder.build())); - - final SIGMET sigmet = builder.build(); - final ConversionResult result = converter.convertMessage(sigmet, - JSONConverter.SIGMET_POJO_TO_JSON_STRING, ConversionHints.EMPTY); - assertSame(ConversionResult.Status.SUCCESS, result.getStatus()); - assertTrue(result.getConvertedMessage().isPresent()); - - final JsonNode refRoot = om.readTree(reference); - final JsonNode convertedRoot = om.readTree(result.getConvertedMessage().get()); - assertEquals("constructed and parsed tree not equal", refRoot, convertedRoot); - } -} +package fi.fmi.avi.converter.json; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.datatype.jdk8.Jdk8Module; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import fi.fmi.avi.converter.AviMessageConverter; +import fi.fmi.avi.converter.ConversionHints; +import fi.fmi.avi.converter.ConversionResult; +import fi.fmi.avi.converter.json.conf.JSONConverter; +import fi.fmi.avi.model.*; +import fi.fmi.avi.model.immutable.*; +import fi.fmi.avi.model.sigmet.SIGMET; +import fi.fmi.avi.model.sigmet.SigmetAnalysisType; +import fi.fmi.avi.model.sigmet.SigmetIntensityChange; +import fi.fmi.avi.model.sigmet.immutable.SIGMETImpl; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.test.context.support.AnnotationConfigContextLoader; +import org.unitils.thirdparty.org.apache.commons.io.IOUtils; + +import java.io.InputStream; +import java.time.ZonedDateTime; +import java.util.Collections; +import java.util.Objects; + +import static org.junit.Assert.*; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(classes = JSONSigmetTestConfiguration.class, loader = AnnotationConfigContextLoader.class) +public class JSONSigmetConverterTest { + + @Autowired + private AviMessageConverter converter; + + public void testSIGMETParsing() throws Exception { + final InputStream is = JSONSigmetConverterTest.class.getResourceAsStream("sigmet1.json"); + Objects.requireNonNull(is); + final String input = IOUtils.toString(is, "UTF-8"); + is.close(); + final ConversionResult result = converter.convertMessage(input, + JSONConverter.JSON_STRING_TO_SIGMET_POJO, ConversionHints.EMPTY); + assertSame(ConversionResult.Status.SUCCESS, result.getStatus()); + } + + @Test + public void testSIGMETSerialization() throws Exception { + final ObjectMapper om = new ObjectMapper(); + om.registerModule(new Jdk8Module()); + om.registerModule(new JavaTimeModule()); + + final InputStream is = JSONSigmetConverterTest.class.getResourceAsStream("sigmet1.json"); + Objects.requireNonNull(is); + final String reference = IOUtils.toString(is, "UTF-8"); + is.close(); + + final SIGMETImpl.Builder builder = SIGMETImpl.builder(); + + final UnitPropertyGroup mwo = new UnitPropertyGroupImpl.Builder().setPropertyGroup("De Bilt", "EHDB", "MWO") + .build(); + final UnitPropertyGroup fir = new UnitPropertyGroupImpl.Builder() + .setPropertyGroup("AMSTERDAM FIR", "EHAA", "FIR").build(); + + final Airspace airspace = new AirspaceImpl.Builder().setDesignator("EHAA").setType(Airspace.AirspaceType.FIR) + .setName("AMSTERDAM").build(); + + final String geomString = "{ \"type\": \"Polygon\", \"exteriorRingPositions\":[5.0,52.0,6.0,53.0,4.0,54.0,5.0,52.0]}"; + final Geometry geom = om.readValue(geomString, Geometry.class); + final String fpaGeomString = "{ \"type\": \"Polygon\", \"exteriorRingPositions\":[5.0,53.0,6.0,54.0,4.0,55.0,5.0,53.0]}"; + final Geometry fpaGeom = om.readValue(fpaGeomString, Geometry.class); + + final PartialOrCompleteTimeInstant.Builder issueTimeBuilder = PartialOrCompleteTimeInstant.builder(); + issueTimeBuilder.setCompleteTime(ZonedDateTime.parse("2017-08-27T11:30:00Z")); + final PartialOrCompleteTimePeriod.Builder validPeriod = PartialOrCompleteTimePeriod.builder(); + validPeriod.setStartTime(PartialOrCompleteTimeInstant.of(ZonedDateTime.parse("2017-08-27T11:30:00Z"))); + validPeriod.setEndTime(PartialOrCompleteTimeInstant.of(ZonedDateTime.parse("2017-08-27T18:00:00Z"))); + + final PhenomenonGeometryWithHeightImpl.Builder geomBuilder = PhenomenonGeometryWithHeightImpl.builder(); + geomBuilder.setApproximateLocation(false); + geomBuilder.setGeometry(TacOrGeoGeometryImpl.of(geom)); + geomBuilder.setTime(PartialOrCompleteTimeInstant.of(ZonedDateTime.parse("2017-08-27T12:00:00Z"))); + geomBuilder.setLowerLimit(NumericMeasureImpl.of(10, "FL")); + geomBuilder.setUpperLimit(NumericMeasureImpl.of(35, "FL")); + geomBuilder.setIntensityChange(SigmetIntensityChange.NO_CHANGE); + geomBuilder.setAnalysisType(SigmetAnalysisType.OBSERVATION); + + final PhenomenonGeometryImpl.Builder fpGeomBuilder = PhenomenonGeometryImpl.builder(); + fpGeomBuilder.setApproximateLocation(false); + fpGeomBuilder.setGeometry(TacOrGeoGeometryImpl.of(fpaGeom)); + fpGeomBuilder.setTime(PartialOrCompleteTimeInstant.of(ZonedDateTime.parse("2017-08-27T18:00:00Z"))); + + builder.setReportStatus(AviationWeatherMessage.ReportStatus.NORMAL) + .setCancelMessage(false) + .setMeteorologicalWatchOffice(mwo) + .setIssuingAirTrafficServicesUnit(fir) + .setAirspace(airspace) + .setIssueTime(issueTimeBuilder.build()) + .setTranslated(true) + .setPermissibleUsage(AviationCodeListUser.PermissibleUsage.NON_OPERATIONAL) + .setPermissibleUsageReason(AviationCodeListUser.PermissibleUsageReason.EXERCISE) + .setSequenceNumber("1") + + .setValidityPeriod(validPeriod.build()) + .setPhenomenonType(AviationCodeListUser.SigmetPhenomenonType.SIGMET) + .setPhenomenon(AviationCodeListUser.AeronauticalSignificantWeatherPhenomenon.EMBD_TS) + .setAnalysisGeometries(Collections.singletonList(geomBuilder.build())) + .setForecastGeometries(Collections.singletonList(fpGeomBuilder.build())); + + final SIGMET sigmet = builder.build(); + final ConversionResult result = converter.convertMessage(sigmet, + JSONConverter.SIGMET_POJO_TO_JSON_STRING, ConversionHints.EMPTY); + assertSame(ConversionResult.Status.SUCCESS, result.getStatus()); + assertTrue(result.getConvertedMessage().isPresent()); + + final JsonNode refRoot = om.readTree(reference); + final JsonNode convertedRoot = om.readTree(result.getConvertedMessage().get()); + assertEquals("constructed and parsed tree not equal", refRoot, convertedRoot); + } +} diff --git a/src/test/java/fi/fmi/avi/converter/json/JSONVASigmetConverterTest.java b/src/test/java/fi/fmi/avi/converter/json/JSONVASigmetConverterTest.java index a3082ee..91a428c 100644 --- a/src/test/java/fi/fmi/avi/converter/json/JSONVASigmetConverterTest.java +++ b/src/test/java/fi/fmi/avi/converter/json/JSONVASigmetConverterTest.java @@ -1,180 +1,163 @@ -package fi.fmi.avi.converter.json; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertSame; -import static org.junit.Assert.assertTrue; - -import java.io.InputStream; -import java.time.ZonedDateTime; -import java.util.Arrays; -import java.util.Collections; -import java.util.Objects; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; -import org.springframework.test.context.support.AnnotationConfigContextLoader; -import org.unitils.thirdparty.org.apache.commons.io.IOUtils; - -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.datatype.jdk8.Jdk8Module; -import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; - -import fi.fmi.avi.converter.AviMessageConverter; -import fi.fmi.avi.converter.ConversionHints; -import fi.fmi.avi.converter.ConversionIssue; -import fi.fmi.avi.converter.ConversionResult; -import fi.fmi.avi.converter.json.conf.JSONConverter; -import fi.fmi.avi.model.Airspace; -import fi.fmi.avi.model.AviationCodeListUser; -import fi.fmi.avi.model.AviationWeatherMessage; -import fi.fmi.avi.model.Geometry; -import fi.fmi.avi.model.PartialOrCompleteTimeInstant; -import fi.fmi.avi.model.PartialOrCompleteTimePeriod; -import fi.fmi.avi.model.UnitPropertyGroup; -import fi.fmi.avi.model.immutable.AirspaceImpl; -import fi.fmi.avi.model.immutable.CoordinateReferenceSystemImpl; -import fi.fmi.avi.model.immutable.ElevatedPointImpl; -import fi.fmi.avi.model.immutable.NumericMeasureImpl; -import fi.fmi.avi.model.immutable.PhenomenonGeometryImpl; -import fi.fmi.avi.model.immutable.PhenomenonGeometryWithHeightImpl; -import fi.fmi.avi.model.immutable.TacOrGeoGeometryImpl; -import fi.fmi.avi.model.immutable.UnitPropertyGroupImpl; -import fi.fmi.avi.model.immutable.VolcanoDescriptionImpl; -import fi.fmi.avi.model.sigmet.SIGMET; -import fi.fmi.avi.model.sigmet.SigmetAnalysisType; -import fi.fmi.avi.model.sigmet.SigmetIntensityChange; -import fi.fmi.avi.model.sigmet.immutable.SIGMETImpl; -import fi.fmi.avi.model.sigmet.immutable.VAInfoImpl; - -@RunWith(SpringJUnit4ClassRunner.class) -@ContextConfiguration(classes = JSONVASigmetTestConfiguration.class, loader = AnnotationConfigContextLoader.class) -public class JSONVASigmetConverterTest { - - @Autowired - private AviMessageConverter converter; - - @Test - public void testSIGMETParsing() throws Exception { - final InputStream is = JSONVASigmetConverterTest.class.getResourceAsStream("vasigmet1.json"); - Objects.requireNonNull(is); - final String input = IOUtils.toString(is, "UTF-8"); - is.close(); - final ConversionResult result = converter.convertMessage(input, - JSONConverter.JSON_STRING_TO_SIGMET_POJO, ConversionHints.EMPTY); - for (final ConversionIssue iss : result.getConversionIssues()) { - System.err.println(" ISS:" + iss.getMessage() + " " + iss.getCause()); - } - assertSame(ConversionResult.Status.SUCCESS, result.getStatus()); - } - - @Test - public void testSIGMETParsingNOVAEXP() throws Exception { - final InputStream is = JSONVASigmetConverterTest.class.getResourceAsStream("vasigmet_novaexp.json"); - Objects.requireNonNull(is); - final String input = IOUtils.toString(is, "UTF-8"); - is.close(); - final ConversionResult result = converter.convertMessage(input, - JSONConverter.JSON_STRING_TO_SIGMET_POJO, ConversionHints.EMPTY); - for (final ConversionIssue iss : result.getConversionIssues()) { - System.err.println(" ISS:" + iss.getMessage() + " " + iss.getCause()); - } - assertSame(ConversionResult.Status.SUCCESS, result.getStatus()); - } - - @Test - public void testVASIGMETSerialization() throws Exception { - final ObjectMapper om = new ObjectMapper(); - om.registerModule(new Jdk8Module()); - om.registerModule(new JavaTimeModule()); - - final InputStream is = JSONVASigmetConverterTest.class.getResourceAsStream("vasigmet1.json"); - Objects.requireNonNull(is); - final String reference = IOUtils.toString(is, "UTF-8"); - is.close(); - - final SIGMETImpl.Builder builder = SIGMETImpl.builder(); - - final UnitPropertyGroup mwo = new UnitPropertyGroupImpl.Builder().setPropertyGroup("De Bilt", "EHDB", "MWO") - .build(); - final UnitPropertyGroup fir = new UnitPropertyGroupImpl.Builder().setPropertyGroup("AMSTERDAM", "EHAA", "FIR") - .build(); - - final Airspace airspace = new AirspaceImpl.Builder().setDesignator("EHAA").setType(Airspace.AirspaceType.FIR) - .setName("AMSTERDAM").build(); - - final String geomString = "{ \"type\": \"Polygon\", \"exteriorRingPositions\":[5.0,52.0,6.0,53.0,4.0,54.0,5.0,52.0]}"; - final Geometry geom = om.readValue(geomString, Geometry.class); - final String fpaGeomString = "{ \"type\": \"Polygon\", \"exteriorRingPositions\":[5.0,53.0,6.0,54.0,4.0,55.0,5.0,53.0]}"; - final Geometry fpaGeom = om.readValue(fpaGeomString, Geometry.class); - - final PhenomenonGeometryWithHeightImpl.Builder geomBuilder = PhenomenonGeometryWithHeightImpl.builder(); - geomBuilder.setGeometry(TacOrGeoGeometryImpl.of(geom)); - geomBuilder.setTime(PartialOrCompleteTimeInstant.of(ZonedDateTime.parse("2017-08-27T12:00:00Z"))); - geomBuilder.setLowerLimit(NumericMeasureImpl.of(10, "FL")); - geomBuilder.setUpperLimit(NumericMeasureImpl.of(35, "FL")); - geomBuilder.setApproximateLocation(false); - geomBuilder.setIntensityChange(SigmetIntensityChange.NO_CHANGE); - geomBuilder.setAnalysisType(SigmetAnalysisType.OBSERVATION); - - final PhenomenonGeometryImpl.Builder fpGeomBuilder = PhenomenonGeometryImpl.builder(); - fpGeomBuilder.setGeometry(TacOrGeoGeometryImpl.of(fpaGeom)); - fpGeomBuilder.setTime(PartialOrCompleteTimeInstant.of(ZonedDateTime.parse("2017-08-27T18:00:00Z"))); - fpGeomBuilder.setApproximateLocation(false); - - final PartialOrCompleteTimeInstant.Builder issueTimeBuilder = PartialOrCompleteTimeInstant.builder(); - issueTimeBuilder.setCompleteTime(ZonedDateTime.parse("2017-08-27T11:30:00Z")); - final PartialOrCompleteTimePeriod.Builder validPeriod = PartialOrCompleteTimePeriod.builder(); - validPeriod.setStartTime(PartialOrCompleteTimeInstant.of(ZonedDateTime.parse("2017-08-27T11:30:00Z"))); - validPeriod.setEndTime(PartialOrCompleteTimeInstant.of(ZonedDateTime.parse("2017-08-27T18:00:00Z"))); - - final VolcanoDescriptionImpl.Builder volcanoBuilder = new VolcanoDescriptionImpl.Builder(); - final ElevatedPointImpl.Builder gpBuilder = ElevatedPointImpl.builder(); - gpBuilder.addAllCoordinates(Arrays.stream(new Double[] { 52.0, 5.2 })); - gpBuilder.setCrs(CoordinateReferenceSystemImpl.wgs84()); - volcanoBuilder.setVolcanoPosition(gpBuilder.build()); - volcanoBuilder.setVolcanoName("GRIMSVOTN"); - - final VAInfoImpl.Builder vaInfoBuilder = new VAInfoImpl.Builder(); - vaInfoBuilder.setVolcano(volcanoBuilder.build()); - - builder.setReportStatus(AviationWeatherMessage.ReportStatus.NORMAL) - .setCancelMessage(false) - .setMeteorologicalWatchOffice(mwo) - .setIssuingAirTrafficServicesUnit(fir) - .setAirspace(airspace) - .setIssueTime(issueTimeBuilder.build()) - .setPermissibleUsage(AviationCodeListUser.PermissibleUsage.NON_OPERATIONAL) - .setPermissibleUsageReason(AviationCodeListUser.PermissibleUsageReason.EXERCISE) - .setSequenceNumber("1") - .setTranslated(false) - .setPhenomenon(AviationCodeListUser.AeronauticalSignificantWeatherPhenomenon.EMBD_TS) - .setValidityPeriod(validPeriod.build()) - - .setAnalysisGeometries(Collections.singletonList(geomBuilder.build())) - .setForecastGeometries(Collections.singletonList(fpGeomBuilder.build())) - .setVAInfo(vaInfoBuilder.build()); - - final SIGMET vaSigmet = builder.build(); - - final ConversionResult result = converter.convertMessage(vaSigmet, - JSONConverter.SIGMET_POJO_TO_JSON_STRING, ConversionHints.EMPTY); - assertSame(ConversionResult.Status.SUCCESS, result.getStatus()); - assertTrue(result.getConvertedMessage().isPresent()); - - final SIGMET refVaSigmet = om.readValue(reference, SIGMETImpl.class); - - final SIGMET newVaSigmet = om.readValue(result.getConvertedMessage().get(), SIGMETImpl.class); - - final JsonNode refTree = om.readTree(reference); - final JsonNode newTree = om.readTree(result.getConvertedMessage().get()); - - assertEquals("Strings do not match ", refVaSigmet, newVaSigmet); - - assertEquals("Strings do not match ", refTree, newTree); - - } -} +package fi.fmi.avi.converter.json; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.datatype.jdk8.Jdk8Module; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import fi.fmi.avi.converter.AviMessageConverter; +import fi.fmi.avi.converter.ConversionHints; +import fi.fmi.avi.converter.ConversionIssue; +import fi.fmi.avi.converter.ConversionResult; +import fi.fmi.avi.converter.json.conf.JSONConverter; +import fi.fmi.avi.model.*; +import fi.fmi.avi.model.immutable.*; +import fi.fmi.avi.model.sigmet.SIGMET; +import fi.fmi.avi.model.sigmet.SigmetAnalysisType; +import fi.fmi.avi.model.sigmet.SigmetIntensityChange; +import fi.fmi.avi.model.sigmet.immutable.SIGMETImpl; +import fi.fmi.avi.model.sigmet.immutable.VAInfoImpl; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.test.context.support.AnnotationConfigContextLoader; +import org.unitils.thirdparty.org.apache.commons.io.IOUtils; + +import java.io.InputStream; +import java.time.ZonedDateTime; +import java.util.Arrays; +import java.util.Collections; +import java.util.Objects; + +import static org.junit.Assert.*; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(classes = JSONVASigmetTestConfiguration.class, loader = AnnotationConfigContextLoader.class) +public class JSONVASigmetConverterTest { + + @Autowired + private AviMessageConverter converter; + + @Test + public void testSIGMETParsing() throws Exception { + final InputStream is = JSONVASigmetConverterTest.class.getResourceAsStream("vasigmet1.json"); + Objects.requireNonNull(is); + final String input = IOUtils.toString(is, "UTF-8"); + is.close(); + final ConversionResult result = converter.convertMessage(input, + JSONConverter.JSON_STRING_TO_SIGMET_POJO, ConversionHints.EMPTY); + for (final ConversionIssue iss : result.getConversionIssues()) { + System.err.println(" ISS:" + iss.getMessage() + " " + iss.getCause()); + } + assertSame(ConversionResult.Status.SUCCESS, result.getStatus()); + } + + @Test + public void testSIGMETParsingNOVAEXP() throws Exception { + final InputStream is = JSONVASigmetConverterTest.class.getResourceAsStream("vasigmet_novaexp.json"); + Objects.requireNonNull(is); + final String input = IOUtils.toString(is, "UTF-8"); + is.close(); + final ConversionResult result = converter.convertMessage(input, + JSONConverter.JSON_STRING_TO_SIGMET_POJO, ConversionHints.EMPTY); + for (final ConversionIssue iss : result.getConversionIssues()) { + System.err.println(" ISS:" + iss.getMessage() + " " + iss.getCause()); + } + assertSame(ConversionResult.Status.SUCCESS, result.getStatus()); + } + + @Test + public void testVASIGMETSerialization() throws Exception { + final ObjectMapper om = new ObjectMapper(); + om.registerModule(new Jdk8Module()); + om.registerModule(new JavaTimeModule()); + + final InputStream is = JSONVASigmetConverterTest.class.getResourceAsStream("vasigmet1.json"); + Objects.requireNonNull(is); + final String reference = IOUtils.toString(is, "UTF-8"); + is.close(); + + final SIGMETImpl.Builder builder = SIGMETImpl.builder(); + + final UnitPropertyGroup mwo = new UnitPropertyGroupImpl.Builder().setPropertyGroup("De Bilt", "EHDB", "MWO") + .build(); + final UnitPropertyGroup fir = new UnitPropertyGroupImpl.Builder().setPropertyGroup("AMSTERDAM", "EHAA", "FIR") + .build(); + + final Airspace airspace = new AirspaceImpl.Builder().setDesignator("EHAA").setType(Airspace.AirspaceType.FIR) + .setName("AMSTERDAM").build(); + + final String geomString = "{ \"type\": \"Polygon\", \"exteriorRingPositions\":[5.0,52.0,6.0,53.0,4.0,54.0,5.0,52.0]}"; + final Geometry geom = om.readValue(geomString, Geometry.class); + final String fpaGeomString = "{ \"type\": \"Polygon\", \"exteriorRingPositions\":[5.0,53.0,6.0,54.0,4.0,55.0,5.0,53.0]}"; + final Geometry fpaGeom = om.readValue(fpaGeomString, Geometry.class); + + final PhenomenonGeometryWithHeightImpl.Builder geomBuilder = PhenomenonGeometryWithHeightImpl.builder(); + geomBuilder.setGeometry(TacOrGeoGeometryImpl.of(geom)); + geomBuilder.setTime(PartialOrCompleteTimeInstant.of(ZonedDateTime.parse("2017-08-27T12:00:00Z"))); + geomBuilder.setLowerLimit(NumericMeasureImpl.of(10, "FL")); + geomBuilder.setUpperLimit(NumericMeasureImpl.of(35, "FL")); + geomBuilder.setApproximateLocation(false); + geomBuilder.setIntensityChange(SigmetIntensityChange.NO_CHANGE); + geomBuilder.setAnalysisType(SigmetAnalysisType.OBSERVATION); + + final PhenomenonGeometryImpl.Builder fpGeomBuilder = PhenomenonGeometryImpl.builder(); + fpGeomBuilder.setGeometry(TacOrGeoGeometryImpl.of(fpaGeom)); + fpGeomBuilder.setTime(PartialOrCompleteTimeInstant.of(ZonedDateTime.parse("2017-08-27T18:00:00Z"))); + fpGeomBuilder.setApproximateLocation(false); + + final PartialOrCompleteTimeInstant.Builder issueTimeBuilder = PartialOrCompleteTimeInstant.builder(); + issueTimeBuilder.setCompleteTime(ZonedDateTime.parse("2017-08-27T11:30:00Z")); + final PartialOrCompleteTimePeriod.Builder validPeriod = PartialOrCompleteTimePeriod.builder(); + validPeriod.setStartTime(PartialOrCompleteTimeInstant.of(ZonedDateTime.parse("2017-08-27T11:30:00Z"))); + validPeriod.setEndTime(PartialOrCompleteTimeInstant.of(ZonedDateTime.parse("2017-08-27T18:00:00Z"))); + + final VolcanoDescriptionImpl.Builder volcanoBuilder = new VolcanoDescriptionImpl.Builder(); + final ElevatedPointImpl.Builder gpBuilder = ElevatedPointImpl.builder(); + gpBuilder.addAllCoordinates(Arrays.stream(new Double[] { 52.0, 5.2 })); + gpBuilder.setCrs(CoordinateReferenceSystemImpl.wgs84()); + volcanoBuilder.setVolcanoPosition(gpBuilder.build()); + volcanoBuilder.setVolcanoName("GRIMSVOTN"); + + final VAInfoImpl.Builder vaInfoBuilder = new VAInfoImpl.Builder(); + vaInfoBuilder.setVolcano(volcanoBuilder.build()); + + builder.setReportStatus(AviationWeatherMessage.ReportStatus.NORMAL) + .setCancelMessage(false) + .setMeteorologicalWatchOffice(mwo) + .setIssuingAirTrafficServicesUnit(fir) + .setAirspace(airspace) + .setIssueTime(issueTimeBuilder.build()) + .setPermissibleUsage(AviationCodeListUser.PermissibleUsage.NON_OPERATIONAL) + .setPermissibleUsageReason(AviationCodeListUser.PermissibleUsageReason.EXERCISE) + .setSequenceNumber("1") + .setTranslated(false) + .setPhenomenonType(AviationCodeListUser.SigmetPhenomenonType.VOLCANIC_ASH_SIGMET) + .setPhenomenon(AviationCodeListUser.AeronauticalSignificantWeatherPhenomenon.VA) + .setValidityPeriod(validPeriod.build()) + + .setAnalysisGeometries(Collections.singletonList(geomBuilder.build())) + .setForecastGeometries(Collections.singletonList(fpGeomBuilder.build())) + .setVAInfo(vaInfoBuilder.build()); + + final SIGMET vaSigmet = builder.build(); + + final ConversionResult result = converter.convertMessage(vaSigmet, + JSONConverter.SIGMET_POJO_TO_JSON_STRING, ConversionHints.EMPTY); + assertSame(ConversionResult.Status.SUCCESS, result.getStatus()); + assertTrue(result.getConvertedMessage().isPresent()); + + final SIGMET refVaSigmet = om.readValue(reference, SIGMETImpl.class); + + final SIGMET newVaSigmet = om.readValue(result.getConvertedMessage().get(), SIGMETImpl.class); + + final JsonNode refTree = om.readTree(reference); + final JsonNode newTree = om.readTree(result.getConvertedMessage().get()); + + assertEquals("Strings do not match ", refVaSigmet, newVaSigmet); + + assertEquals("Strings do not match ", refTree, newTree); + + } +} diff --git a/src/test/java/fi/fmi/avi/model/sigmet/immutable/SigmetTest.java b/src/test/java/fi/fmi/avi/model/sigmet/immutable/SigmetTest.java index 0aa8798..264362e 100644 --- a/src/test/java/fi/fmi/avi/model/sigmet/immutable/SigmetTest.java +++ b/src/test/java/fi/fmi/avi/model/sigmet/immutable/SigmetTest.java @@ -1,37 +1,22 @@ package fi.fmi.avi.model.sigmet.immutable; -import static org.junit.Assert.assertEquals; - -import java.io.IOException; -import java.time.ZonedDateTime; -import java.util.Collections; - -import org.junit.Test; - import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; import com.fasterxml.jackson.datatype.jdk8.Jdk8Module; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; - -import fi.fmi.avi.model.Airspace; -import fi.fmi.avi.model.AviationCodeListUser; -import fi.fmi.avi.model.AviationWeatherMessage; -import fi.fmi.avi.model.Geometry; -import fi.fmi.avi.model.PartialOrCompleteTimeInstant; -import fi.fmi.avi.model.PartialOrCompleteTimePeriod; -import fi.fmi.avi.model.PhenomenonGeometry; -import fi.fmi.avi.model.PhenomenonGeometryWithHeight; -import fi.fmi.avi.model.TacOrGeoGeometry; -import fi.fmi.avi.model.immutable.AirspaceImpl; -import fi.fmi.avi.model.immutable.PhenomenonGeometryImpl; -import fi.fmi.avi.model.immutable.PhenomenonGeometryWithHeightImpl; -import fi.fmi.avi.model.immutable.TacGeometryImpl; -import fi.fmi.avi.model.immutable.TacOrGeoGeometryImpl; -import fi.fmi.avi.model.immutable.UnitPropertyGroupImpl; +import fi.fmi.avi.model.*; +import fi.fmi.avi.model.immutable.*; import fi.fmi.avi.model.sigmet.SIGMET; import fi.fmi.avi.model.sigmet.SigmetAnalysisType; import fi.fmi.avi.model.sigmet.SigmetIntensityChange; +import org.junit.Test; + +import java.io.IOException; +import java.time.ZonedDateTime; +import java.util.Collections; + +import static org.junit.Assert.assertEquals; public class SigmetTest { @@ -86,6 +71,7 @@ public SIGMET buildSigmet() throws IOException { .build()) .setAnalysisGeometries(Collections.singletonList(getAnalysis())) .setForecastGeometries(Collections.singletonList(getForecast())) + .setPhenomenonType(AviationCodeListUser.SigmetPhenomenonType.SIGMET) .setPhenomenon(AviationCodeListUser.AeronauticalSignificantWeatherPhenomenon.EMBD_TS) .setTranslated(false); return sm.build(); diff --git a/src/test/resources/fi/fmi/avi/converter/json/sigmet1.json b/src/test/resources/fi/fmi/avi/converter/json/sigmet1.json index 9970d35..7bd7c68 100644 --- a/src/test/resources/fi/fmi/avi/converter/json/sigmet1.json +++ b/src/test/resources/fi/fmi/avi/converter/json/sigmet1.json @@ -1,90 +1,91 @@ -{ - "reportStatus": "NORMAL", - "issuingAirTrafficServicesUnit": { - "name": "AMSTERDAM FIR", - "type": "FIR", - "designator": "EHAA" - }, - "meteorologicalWatchOffice": { - "name": "De Bilt", - "type": "MWO", - "designator": "EHDB" - }, - "sequenceNumber": "1", - "issueTime": { - "completeTime": "2017-08-27T11:30:00Z" - }, - "validityPeriod": { - "startTime": { - "completeTime": "2017-08-27T11:30:00Z" - }, - "endTime": { - "completeTime": "2017-08-27T18:00:00Z" - } - }, - "airspace": { - "designator": "EHAA", - "name": "AMSTERDAM", - "type": "FIR" - }, - "phenomenon": "EMBD_TS", - "analysisGeometries": [ - { - "time": { - "completeTime": "2017-08-27T12:00:00Z" - }, - "lowerLimit": { - "value": 10.0, - "uom": "FL" - }, - "upperLimit": { - "value": 35.0, - "uom": "FL" - }, - "analysisType": "OBSERVATION", - "intensityChange": "NO_CHANGE", - "approximateLocation": false, - "geometry": { - "geoGeometry": { - "type": "Polygon", - "exteriorRingPositions": [ - 5.0, - 52.0, - 6.0, - 53.0, - 4.0, - 54.0, - 5.0, - 52.0 - ] - } - } - } - ], - "forecastGeometries": [ - { - "time": { - "completeTime": "2017-08-27T18:00:00Z" - }, - "approximateLocation": false, - "geometry": { - "geoGeometry": { - "type": "Polygon", - "exteriorRingPositions": [ - 5.0, - 53.0, - 6.0, - 54.0, - 4.0, - 55.0, - 5.0, - 53.0 - ] - } - } - } - ], - "permissibleUsage": "NON_OPERATIONAL", - "permissibleUsageReason": "EXERCISE", - "translated": true +{ + "reportStatus": "NORMAL", + "issuingAirTrafficServicesUnit": { + "name": "AMSTERDAM FIR", + "type": "FIR", + "designator": "EHAA" + }, + "meteorologicalWatchOffice": { + "name": "De Bilt", + "type": "MWO", + "designator": "EHDB" + }, + "sequenceNumber": "1", + "issueTime": { + "completeTime": "2017-08-27T11:30:00Z" + }, + "validityPeriod": { + "startTime": { + "completeTime": "2017-08-27T11:30:00Z" + }, + "endTime": { + "completeTime": "2017-08-27T18:00:00Z" + } + }, + "airspace": { + "designator": "EHAA", + "name": "AMSTERDAM", + "type": "FIR" + }, + "phenomenonType": "SIGMET", + "phenomenon": "EMBD_TS", + "analysisGeometries": [ + { + "time": { + "completeTime": "2017-08-27T12:00:00Z" + }, + "lowerLimit": { + "value": 10.0, + "uom": "FL" + }, + "upperLimit": { + "value": 35.0, + "uom": "FL" + }, + "analysisType": "OBSERVATION", + "intensityChange": "NO_CHANGE", + "approximateLocation": false, + "geometry": { + "geoGeometry": { + "type": "Polygon", + "exteriorRingPositions": [ + 5.0, + 52.0, + 6.0, + 53.0, + 4.0, + 54.0, + 5.0, + 52.0 + ] + } + } + } + ], + "forecastGeometries": [ + { + "time": { + "completeTime": "2017-08-27T18:00:00Z" + }, + "approximateLocation": false, + "geometry": { + "geoGeometry": { + "type": "Polygon", + "exteriorRingPositions": [ + 5.0, + 53.0, + 6.0, + 54.0, + 4.0, + 55.0, + 5.0, + 53.0 + ] + } + } + } + ], + "permissibleUsage": "NON_OPERATIONAL", + "permissibleUsageReason": "EXERCISE", + "translated": true } \ No newline at end of file diff --git a/src/test/resources/fi/fmi/avi/converter/json/sigmetBulletin1.json b/src/test/resources/fi/fmi/avi/converter/json/sigmetBulletin1.json index 6764336..a5fcaaf 100644 --- a/src/test/resources/fi/fmi/avi/converter/json/sigmetBulletin1.json +++ b/src/test/resources/fi/fmi/avi/converter/json/sigmetBulletin1.json @@ -38,6 +38,7 @@ "completeTime": "2017-08-27T18:00:00Z" } }, + "phenomenonType": "SIGMET", "phenomenon": "EMBD_TS", "permissibleUsage": "NON_OPERATIONAL", "permissibleUsageReason": "EXERCISE", @@ -128,6 +129,7 @@ "name": "AMSTERDAM", "type": "FIR" }, + "phenomenonType": "SIGMET", "phenomenon": "EMBD_TS", "permissibleUsage": "NON_OPERATIONAL", "permissibleUsageReason": "EXERCISE", diff --git a/src/test/resources/fi/fmi/avi/converter/json/sigmet_moving.json b/src/test/resources/fi/fmi/avi/converter/json/sigmet_moving.json index e62fb37..0df7e1a 100644 --- a/src/test/resources/fi/fmi/avi/converter/json/sigmet_moving.json +++ b/src/test/resources/fi/fmi/avi/converter/json/sigmet_moving.json @@ -1,75 +1,76 @@ -{ - "reportStatus": "NORMAL", - "issuingAirTrafficServicesUnit": { - "name": "AMSTERDAM FIR", - "type": "FIR", - "designator": "EHAA" - }, - "meteorologicalWatchOffice": { - "name": "De Bilt", - "type": "MWO", - "designator": "EHDB" - }, - "sequenceNumber": "1", - "issueTime": { - "completeTime": "2017-08-27T11:30:00Z" - }, - "airspace": { - "designator": "EHAA", - "name": "AMSTERDAM", - "type": "FIR" - }, - "validityPeriod": { - "startTime": { - "completeTime": "2017-08-27T11:30:00Z" - }, - "endTime": { - "completeTime": "2017-08-27T18:00:00Z" - } - }, - "phenomenon": "EMBD_TS", - "permissibleUsage": "NON_OPERATIONAL", - "permissibleUsageReason": "EXERCISE", - "analysisType": "OBSERVATION", - "intensityChange": "NO_CHANGE", - "analysisGeometries": [ - { - "time": { - "completeTime": "2017-08-27T12:00:00Z" - }, - "lowerLimit": { - "value": 10.0, - "uom": "FL" - }, - "upperLimit": { - "value": 35.0, - "uom": "FL" - }, - "approximateLocation": false, - "geometry": { - "geoGeometry": { - "type": "Polygon", - "exteriorRingPositions": [ - 5.0, - 52.0, - 6.0, - 53.0, - 4.0, - 54.0, - 5.0, - 52.0 - ] - } - } - } - ], - "movingSpeed": { - "value": 10, - "uom": "[kn_i]" - }, - "movingDirection": { - "value": 180, - "uom": "deg" - }, - "translated": false +{ + "reportStatus": "NORMAL", + "issuingAirTrafficServicesUnit": { + "name": "AMSTERDAM FIR", + "type": "FIR", + "designator": "EHAA" + }, + "meteorologicalWatchOffice": { + "name": "De Bilt", + "type": "MWO", + "designator": "EHDB" + }, + "sequenceNumber": "1", + "issueTime": { + "completeTime": "2017-08-27T11:30:00Z" + }, + "airspace": { + "designator": "EHAA", + "name": "AMSTERDAM", + "type": "FIR" + }, + "validityPeriod": { + "startTime": { + "completeTime": "2017-08-27T11:30:00Z" + }, + "endTime": { + "completeTime": "2017-08-27T18:00:00Z" + } + }, + "phenomenonType": "SIGMET", + "phenomenon": "EMBD_TS", + "permissibleUsage": "NON_OPERATIONAL", + "permissibleUsageReason": "EXERCISE", + "analysisType": "OBSERVATION", + "intensityChange": "NO_CHANGE", + "analysisGeometries": [ + { + "time": { + "completeTime": "2017-08-27T12:00:00Z" + }, + "lowerLimit": { + "value": 10.0, + "uom": "FL" + }, + "upperLimit": { + "value": 35.0, + "uom": "FL" + }, + "approximateLocation": false, + "geometry": { + "geoGeometry": { + "type": "Polygon", + "exteriorRingPositions": [ + 5.0, + 52.0, + 6.0, + 53.0, + 4.0, + 54.0, + 5.0, + 52.0 + ] + } + } + } + ], + "movingSpeed": { + "value": 10, + "uom": "[kn_i]" + }, + "movingDirection": { + "value": 180, + "uom": "deg" + }, + "translated": false } \ No newline at end of file diff --git a/src/test/resources/fi/fmi/avi/converter/json/vasigmet1.json b/src/test/resources/fi/fmi/avi/converter/json/vasigmet1.json index a9137c3..419e467 100644 --- a/src/test/resources/fi/fmi/avi/converter/json/vasigmet1.json +++ b/src/test/resources/fi/fmi/avi/converter/json/vasigmet1.json @@ -1,109 +1,110 @@ -{ - "reportStatus": "NORMAL", - "issuingAirTrafficServicesUnit": { - "name": "AMSTERDAM", - "type": "FIR", - "designator": "EHAA" - }, - "meteorologicalWatchOffice": { - "name": "De Bilt", - "type": "MWO", - "designator": "EHDB" - }, - "sequenceNumber": "1", - "issueTime": { - "completeTime": "2017-08-27T11:30:00Z" - }, - "validityPeriod": { - "startTime": { - "completeTime": "2017-08-27T11:30:00Z" - }, - "endTime": { - "completeTime": "2017-08-27T18:00:00Z" - } - }, - "airspace": { - "designator": "EHAA", - "name": "AMSTERDAM", - "type": "FIR" - }, - "phenomenon": "EMBD_TS", - "permissibleUsage": "NON_OPERATIONAL", - "permissibleUsageReason": "EXERCISE", - "analysisGeometries": [ - { - "time": { - "completeTime": "2017-08-27T12:00:00Z" - }, - "lowerLimit": { - "value": 10.0, - "uom": "FL" - }, - "upperLimit": { - "value": 35.0, - "uom": "FL" - }, - "intensityChange": "NO_CHANGE", - "analysisType": "OBSERVATION", - "approximateLocation": false, - "geometry": { - "geoGeometry": { - "type": "Polygon", - "exteriorRingPositions": [ - 5.0, - 52.0, - 6.0, - 53.0, - 4.0, - 54.0, - 5.0, - 52.0 - ] - } - } - } - ], - "forecastGeometries": [ - { - "time": { - "completeTime": "2017-08-27T18:00:00Z" - }, - "approximateLocation": false, - "geometry": { - "geoGeometry": { - "type": "Polygon", - "exteriorRingPositions": [ - 5.0, - 53.0, - 6.0, - 54.0, - 4.0, - 55.0, - 5.0, - 53.0 - ] - } - } - } - ], - "VAInfo": { - "volcano": { - "volcanoPosition": { - "type": "ElevatedPoint", - "crs": { - "name": "http://www.opengis.net/def/crs/EPSG/0/4326", - "dimension": 2, - "axisLabels": [ - "Lat", - "Lon" - ] - }, - "coordinates": [ - 52.0, - 5.2 - ] - }, - "volcanoName": "GRIMSVOTN" - } - } +{ + "reportStatus": "NORMAL", + "issuingAirTrafficServicesUnit": { + "name": "AMSTERDAM", + "type": "FIR", + "designator": "EHAA" + }, + "meteorologicalWatchOffice": { + "name": "De Bilt", + "type": "MWO", + "designator": "EHDB" + }, + "sequenceNumber": "1", + "issueTime": { + "completeTime": "2017-08-27T11:30:00Z" + }, + "validityPeriod": { + "startTime": { + "completeTime": "2017-08-27T11:30:00Z" + }, + "endTime": { + "completeTime": "2017-08-27T18:00:00Z" + } + }, + "airspace": { + "designator": "EHAA", + "name": "AMSTERDAM", + "type": "FIR" + }, + "phenomenonType": "VOLCANIC_ASH_SIGMET", + "phenomenon": "VA", + "permissibleUsage": "NON_OPERATIONAL", + "permissibleUsageReason": "EXERCISE", + "analysisGeometries": [ + { + "time": { + "completeTime": "2017-08-27T12:00:00Z" + }, + "lowerLimit": { + "value": 10.0, + "uom": "FL" + }, + "upperLimit": { + "value": 35.0, + "uom": "FL" + }, + "intensityChange": "NO_CHANGE", + "analysisType": "OBSERVATION", + "approximateLocation": false, + "geometry": { + "geoGeometry": { + "type": "Polygon", + "exteriorRingPositions": [ + 5.0, + 52.0, + 6.0, + 53.0, + 4.0, + 54.0, + 5.0, + 52.0 + ] + } + } + } + ], + "forecastGeometries": [ + { + "time": { + "completeTime": "2017-08-27T18:00:00Z" + }, + "approximateLocation": false, + "geometry": { + "geoGeometry": { + "type": "Polygon", + "exteriorRingPositions": [ + 5.0, + 53.0, + 6.0, + 54.0, + 4.0, + 55.0, + 5.0, + 53.0 + ] + } + } + } + ], + "VAInfo": { + "volcano": { + "volcanoPosition": { + "type": "ElevatedPoint", + "crs": { + "name": "http://www.opengis.net/def/crs/EPSG/0/4326", + "dimension": 2, + "axisLabels": [ + "Lat", + "Lon" + ] + }, + "coordinates": [ + 52.0, + 5.2 + ] + }, + "volcanoName": "GRIMSVOTN" + } + } } \ No newline at end of file diff --git a/src/test/resources/fi/fmi/avi/converter/json/vasigmet_novaexp.json b/src/test/resources/fi/fmi/avi/converter/json/vasigmet_novaexp.json index 6224c83..b222b56 100644 --- a/src/test/resources/fi/fmi/avi/converter/json/vasigmet_novaexp.json +++ b/src/test/resources/fi/fmi/avi/converter/json/vasigmet_novaexp.json @@ -1,96 +1,97 @@ -{ - "reportStatus": "NORMAL", - "issuingAirTrafficServicesUnit": { - "name": "AMSTERDAM", - "type": "FIR", - "designator": "EHAA" - }, - "meteorologicalWatchOffice": { - "name": "De Bilt", - "type": "MWO", - "designator": "EHDB" - }, - "sequenceNumber": "1", - "issueTime": { - "completeTime": "2017-08-27T11:30:00Z" - }, - "validityPeriod": { - "startTime": { - "completeTime": "2017-08-27T11:30:00Z" - }, - "endTime": { - "completeTime": "2017-08-27T18:00:00Z" - } - }, - "airspace": { - "designator": "EHAA", - "name": "AMSTERDAM", - "type": "FIR" - }, - "phenomenon": "EMBD_TS", - "permissibleUsage": "NON_OPERATIONAL", - "permissibleUsageReason": "EXERCISE", - "analysisGeometries": [ - { - "time": { - "completeTime": "2017-08-27T12:00:00Z" - }, - "lowerLimit": { - "value": 10.0, - "uom": "FL" - }, - "upperLimit": { - "value": 35.0, - "uom": "FL" - }, - "intensityChange": "NO_CHANGE", - "analysisType": "OBSERVATION", - "approximateLocation": false, - "geometry": { - "geoGeometry": { - "type": "Polygon", - "exteriorRingPositions": [ - 5.0, - 52.0, - 6.0, - 53.0, - 4.0, - 54.0, - 5.0, - 52.0 - ] - } - } - } - ], - "forecastGeometries": [ - { - "time": { - "completeTime": "2017-08-27T18:00:00Z" - }, - "approximateLocation": false, - "geometry": {}, - "noVolcanicAshExpected": true - } - ], - "VAInfo": { - "volcano": { - "volcanoPosition": { - "type": "ElevatedPoint", - "crs": { - "name": "http://www.opengis.net/def/crs/EPSG/0/4326", - "dimension": 2, - "axisLabels": [ - "Lat", - "Lon" - ] - }, - "coordinates": [ - 52.0, - 5.2 - ] - }, - "volcanoName": "GRIMSVOTN" - } - } +{ + "reportStatus": "NORMAL", + "issuingAirTrafficServicesUnit": { + "name": "AMSTERDAM", + "type": "FIR", + "designator": "EHAA" + }, + "meteorologicalWatchOffice": { + "name": "De Bilt", + "type": "MWO", + "designator": "EHDB" + }, + "sequenceNumber": "1", + "issueTime": { + "completeTime": "2017-08-27T11:30:00Z" + }, + "validityPeriod": { + "startTime": { + "completeTime": "2017-08-27T11:30:00Z" + }, + "endTime": { + "completeTime": "2017-08-27T18:00:00Z" + } + }, + "airspace": { + "designator": "EHAA", + "name": "AMSTERDAM", + "type": "FIR" + }, + "phenomenonType": "VOLCANIC_ASH_SIGMET", + "phenomenon": "VA", + "permissibleUsage": "NON_OPERATIONAL", + "permissibleUsageReason": "EXERCISE", + "analysisGeometries": [ + { + "time": { + "completeTime": "2017-08-27T12:00:00Z" + }, + "lowerLimit": { + "value": 10.0, + "uom": "FL" + }, + "upperLimit": { + "value": 35.0, + "uom": "FL" + }, + "intensityChange": "NO_CHANGE", + "analysisType": "OBSERVATION", + "approximateLocation": false, + "geometry": { + "geoGeometry": { + "type": "Polygon", + "exteriorRingPositions": [ + 5.0, + 52.0, + 6.0, + 53.0, + 4.0, + 54.0, + 5.0, + 52.0 + ] + } + } + } + ], + "forecastGeometries": [ + { + "time": { + "completeTime": "2017-08-27T18:00:00Z" + }, + "approximateLocation": false, + "geometry": {}, + "noVolcanicAshExpected": true + } + ], + "VAInfo": { + "volcano": { + "volcanoPosition": { + "type": "ElevatedPoint", + "crs": { + "name": "http://www.opengis.net/def/crs/EPSG/0/4326", + "dimension": 2, + "axisLabels": [ + "Lat", + "Lon" + ] + }, + "coordinates": [ + 52.0, + 5.2 + ] + }, + "volcanoName": "GRIMSVOTN" + } + } } \ No newline at end of file