package org.gbif.occurrence.common.interpretation; import org.gbif.api.vocabulary.OccurrenceIssue; import org.gbif.dwc.terms.DcTerm; import org.gbif.dwc.terms.DwcTerm; import org.gbif.dwc.terms.GbifTerm; import org.gbif.dwc.terms.Term; import java.util.Set; import com.google.common.collect.BiMap; import com.google.common.collect.ImmutableBiMap; import com.google.common.collect.ImmutableSet; /** * Definition and classification of all the {@link InterpretationRemark}. */ public class InterpretationRemarksDefinition { private static final Set<Term> TAXONOMY_TERMS = ImmutableSet.<Term>builder() .add(DwcTerm.kingdom) .add(DwcTerm.phylum) .add(DwcTerm.class_) .add(DwcTerm.order) .add(DwcTerm.family) .add(DwcTerm.genus) .add(DwcTerm.scientificName) .add(DwcTerm.scientificNameAuthorship) .add(GbifTerm.genericName) .add(DwcTerm.specificEpithet) .add(DwcTerm.infraspecificEpithet) .build(); private static final Set<Term> COORDINATES_TERMS = ImmutableSet.<Term>builder() .add(DwcTerm.decimalLatitude) .add(DwcTerm.decimalLongitude) .add(DwcTerm.verbatimLatitude) .add(DwcTerm.verbatimLatitude) .add(DwcTerm.verbatimCoordinates) .add(DwcTerm.geodeticDatum) .build(); /** * Mapping all OccurrenceIssue produced by the interpretation and its related data (severity, terms) */ public static final BiMap<OccurrenceIssue, InterpretationRemark> REMARKS_MAP = ImmutableBiMap.<OccurrenceIssue, InterpretationRemark>builder() // Errors .put(OccurrenceIssue.BASIS_OF_RECORD_INVALID, InterpretationRemark.of( OccurrenceIssue.BASIS_OF_RECORD_INVALID, InterpretationRemarkSeverity.ERROR, DwcTerm.basisOfRecord)) .put(OccurrenceIssue.COORDINATE_OUT_OF_RANGE, InterpretationRemark.of( OccurrenceIssue.COORDINATE_OUT_OF_RANGE, InterpretationRemarkSeverity.ERROR, COORDINATES_TERMS)) .put(OccurrenceIssue.TAXON_MATCH_NONE, InterpretationRemark.of( OccurrenceIssue.TAXON_MATCH_NONE, InterpretationRemarkSeverity.ERROR, TAXONOMY_TERMS)) .put(OccurrenceIssue.INTERPRETATION_ERROR, InterpretationRemark.of( OccurrenceIssue.INTERPRETATION_ERROR, InterpretationRemarkSeverity.ERROR)) // Warnings .put(OccurrenceIssue.ZERO_COORDINATE, InterpretationRemark.of( OccurrenceIssue.ZERO_COORDINATE, InterpretationRemarkSeverity.WARNING, COORDINATES_TERMS)) .put(OccurrenceIssue.PRESUMED_SWAPPED_COORDINATE, InterpretationRemark.of( OccurrenceIssue.PRESUMED_SWAPPED_COORDINATE, InterpretationRemarkSeverity.WARNING, COORDINATES_TERMS)) .put(OccurrenceIssue.PRESUMED_NEGATED_LONGITUDE, InterpretationRemark.of( OccurrenceIssue.PRESUMED_NEGATED_LONGITUDE, InterpretationRemarkSeverity.WARNING, COORDINATES_TERMS)) .put(OccurrenceIssue.PRESUMED_NEGATED_LATITUDE, InterpretationRemark.of( OccurrenceIssue.PRESUMED_NEGATED_LATITUDE, InterpretationRemarkSeverity.WARNING, COORDINATES_TERMS)) .put(OccurrenceIssue.COUNTRY_INVALID, InterpretationRemark.of( OccurrenceIssue.COUNTRY_INVALID, InterpretationRemarkSeverity.WARNING, DwcTerm.country, DwcTerm.countryCode)) .put(OccurrenceIssue.COUNTRY_MISMATCH, InterpretationRemark.of( OccurrenceIssue.COUNTRY_MISMATCH, InterpretationRemarkSeverity.WARNING, DwcTerm.country, DwcTerm.countryCode)) .put(OccurrenceIssue.COUNTRY_COORDINATE_MISMATCH, InterpretationRemark.of( OccurrenceIssue.COUNTRY_COORDINATE_MISMATCH, InterpretationRemarkSeverity.WARNING, ImmutableSet.<Term>builder().addAll(COORDINATES_TERMS).add(DwcTerm.country, DwcTerm.countryCode).build())) .put(OccurrenceIssue.COUNTRY_DERIVED_FROM_COORDINATES, InterpretationRemark.of( OccurrenceIssue.COUNTRY_DERIVED_FROM_COORDINATES, InterpretationRemarkSeverity.WARNING, ImmutableSet.<Term>builder().addAll(COORDINATES_TERMS).add(DwcTerm.country, DwcTerm.countryCode).build())) .put(OccurrenceIssue.GEODETIC_DATUM_ASSUMED_WGS84, InterpretationRemark.of( OccurrenceIssue.GEODETIC_DATUM_ASSUMED_WGS84, InterpretationRemarkSeverity.WARNING, DwcTerm.geodeticDatum)) .put(OccurrenceIssue.GEODETIC_DATUM_INVALID, InterpretationRemark.of( OccurrenceIssue.GEODETIC_DATUM_INVALID, InterpretationRemarkSeverity.WARNING, DwcTerm.geodeticDatum)) .put(OccurrenceIssue.COORDINATE_REPROJECTION_FAILED, InterpretationRemark.of( OccurrenceIssue.COORDINATE_REPROJECTION_FAILED, InterpretationRemarkSeverity.WARNING, COORDINATES_TERMS)) .put(OccurrenceIssue.COORDINATE_REPROJECTION_SUSPICIOUS, InterpretationRemark.of( OccurrenceIssue.COORDINATE_REPROJECTION_SUSPICIOUS, InterpretationRemarkSeverity.WARNING, COORDINATES_TERMS)) .put(OccurrenceIssue.TAXON_MATCH_FUZZY, InterpretationRemark.of( OccurrenceIssue.TAXON_MATCH_FUZZY, InterpretationRemarkSeverity.WARNING, TAXONOMY_TERMS)) .put(OccurrenceIssue.TAXON_MATCH_HIGHERRANK, InterpretationRemark.of( OccurrenceIssue.TAXON_MATCH_HIGHERRANK, InterpretationRemarkSeverity.WARNING, TAXONOMY_TERMS)) .put(OccurrenceIssue.COORDINATE_PRECISION_INVALID, InterpretationRemark.of( OccurrenceIssue.COORDINATE_PRECISION_INVALID, InterpretationRemarkSeverity.WARNING, DwcTerm.coordinatePrecision)) .put(OccurrenceIssue.COORDINATE_UNCERTAINTY_METERS_INVALID, InterpretationRemark.of( OccurrenceIssue.COORDINATE_UNCERTAINTY_METERS_INVALID, InterpretationRemarkSeverity.WARNING, DwcTerm.coordinateUncertaintyInMeters)) .put(OccurrenceIssue.RECORDED_DATE_MISMATCH, InterpretationRemark.of( OccurrenceIssue.RECORDED_DATE_MISMATCH, InterpretationRemarkSeverity.WARNING, DwcTerm.eventDate, DwcTerm.year, DwcTerm.month, DwcTerm.day)) .put(OccurrenceIssue.RECORDED_DATE_INVALID, InterpretationRemark.of( OccurrenceIssue.RECORDED_DATE_INVALID, InterpretationRemarkSeverity.WARNING, DwcTerm.eventDate, DwcTerm.year, DwcTerm.month, DwcTerm.day)) .put(OccurrenceIssue.RECORDED_DATE_UNLIKELY, InterpretationRemark.of( OccurrenceIssue.RECORDED_DATE_UNLIKELY, InterpretationRemarkSeverity.WARNING, DwcTerm.eventDate, DwcTerm.year, DwcTerm.month, DwcTerm.day)) .put(OccurrenceIssue.MODIFIED_DATE_INVALID, InterpretationRemark.of( OccurrenceIssue.MODIFIED_DATE_INVALID, InterpretationRemarkSeverity.WARNING, DcTerm.modified)) .put(OccurrenceIssue.MODIFIED_DATE_UNLIKELY, InterpretationRemark.of( OccurrenceIssue.MODIFIED_DATE_UNLIKELY, InterpretationRemarkSeverity.WARNING, DcTerm.modified)) .put(OccurrenceIssue.IDENTIFIED_DATE_UNLIKELY, InterpretationRemark.of( OccurrenceIssue.IDENTIFIED_DATE_UNLIKELY, InterpretationRemarkSeverity.WARNING, DwcTerm.dateIdentified)) .put(OccurrenceIssue.IDENTIFIED_DATE_INVALID, InterpretationRemark.of( OccurrenceIssue.IDENTIFIED_DATE_INVALID, InterpretationRemarkSeverity.WARNING, DwcTerm.dateIdentified)) .put(OccurrenceIssue.ELEVATION_NOT_METRIC, InterpretationRemark.of( OccurrenceIssue.ELEVATION_NOT_METRIC, InterpretationRemarkSeverity.WARNING, DwcTerm.minimumElevationInMeters, DwcTerm.maximumElevationInMeters)) .put(OccurrenceIssue.ELEVATION_UNLIKELY, InterpretationRemark.of( OccurrenceIssue.ELEVATION_UNLIKELY, InterpretationRemarkSeverity.WARNING, DwcTerm.minimumElevationInMeters, DwcTerm.maximumElevationInMeters)) .put(OccurrenceIssue.ELEVATION_MIN_MAX_SWAPPED, InterpretationRemark.of( OccurrenceIssue.ELEVATION_MIN_MAX_SWAPPED, InterpretationRemarkSeverity.WARNING, DwcTerm.minimumElevationInMeters, DwcTerm.maximumElevationInMeters)) .put(OccurrenceIssue.ELEVATION_NON_NUMERIC, InterpretationRemark.of( OccurrenceIssue.ELEVATION_NON_NUMERIC, InterpretationRemarkSeverity.WARNING, DwcTerm.minimumElevationInMeters, DwcTerm.maximumElevationInMeters)) .put(OccurrenceIssue.DEPTH_NOT_METRIC, InterpretationRemark.of( OccurrenceIssue.DEPTH_NOT_METRIC, InterpretationRemarkSeverity.WARNING, DwcTerm.minimumDepthInMeters, DwcTerm.maximumDepthInMeters)) .put(OccurrenceIssue.DEPTH_UNLIKELY, InterpretationRemark.of( OccurrenceIssue.DEPTH_UNLIKELY, InterpretationRemarkSeverity.WARNING, DwcTerm.minimumDepthInMeters, DwcTerm.maximumDepthInMeters)) .put(OccurrenceIssue.DEPTH_MIN_MAX_SWAPPED, InterpretationRemark.of( OccurrenceIssue.DEPTH_MIN_MAX_SWAPPED, InterpretationRemarkSeverity.WARNING, DwcTerm.minimumDepthInMeters, DwcTerm.maximumDepthInMeters)) .put(OccurrenceIssue.DEPTH_NON_NUMERIC, InterpretationRemark.of( OccurrenceIssue.DEPTH_NON_NUMERIC, InterpretationRemarkSeverity.WARNING, DwcTerm.minimumDepthInMeters, DwcTerm.maximumDepthInMeters)) .put(OccurrenceIssue.TYPE_STATUS_INVALID, InterpretationRemark.of( OccurrenceIssue.TYPE_STATUS_INVALID, InterpretationRemarkSeverity.WARNING, DwcTerm.typeStatus)) .put(OccurrenceIssue.REFERENCES_URI_INVALID, InterpretationRemark.of( OccurrenceIssue.REFERENCES_URI_INVALID, InterpretationRemarkSeverity.WARNING, DcTerm.references)) .put(OccurrenceIssue.INDIVIDUAL_COUNT_INVALID, InterpretationRemark.of( OccurrenceIssue.INDIVIDUAL_COUNT_INVALID, InterpretationRemarkSeverity.WARNING, DwcTerm.individualCount)) // Provided in Multimedia extension so we can't link them to a specific Term // We can also have multiple "media" but the error is attached to the Occurrence. // In other words, we can't link the error to the problematic media. .put(OccurrenceIssue.MULTIMEDIA_DATE_INVALID, InterpretationRemark.of( OccurrenceIssue.MULTIMEDIA_DATE_INVALID, InterpretationRemarkSeverity.WARNING)) .put(OccurrenceIssue.MULTIMEDIA_URI_INVALID, InterpretationRemark.of( OccurrenceIssue.MULTIMEDIA_URI_INVALID, InterpretationRemarkSeverity.WARNING)) // Info .put(OccurrenceIssue.COORDINATE_ROUNDED, InterpretationRemark.of( OccurrenceIssue.COORDINATE_ROUNDED, InterpretationRemarkSeverity.INFO, DwcTerm.decimalLatitude, DwcTerm.decimalLongitude)) .put(OccurrenceIssue.COORDINATE_REPROJECTED, InterpretationRemark.of( OccurrenceIssue.COORDINATE_REPROJECTED, InterpretationRemarkSeverity.INFO, COORDINATES_TERMS)) .build(); // Currently not used by occurrence-processor // COORDINATE_INVALID, // CONTINENT_INVALID, // CONTINENT_DERIVED_FROM_COORDINATES, // CONTINENT_COUNTRY_MISMATCH, // --------- /** * a Set containing all remarks */ public static final Set<InterpretationRemark> REMARKS = REMARKS_MAP.inverse().keySet(); /** * Get the terms related to an OccurrenceIssue or null if the OccurrenceIssue is not * linked to a specific set of fields (e.g. INTERPRETATION_ERROR) or the OccurrenceIssue is unknown. * @param occIssue * @return */ public static Set<Term> getRelatedTerms(OccurrenceIssue occIssue){ if(REMARKS_MAP.containsKey(occIssue)){ return REMARKS_MAP.get(occIssue).getRelatedTerms(); } return null; } }