001/* 002 * Licensed under the Apache License, Version 2.0 (the "License"); 003 * you may not use this file except in compliance with the License. 004 * You may obtain a copy of the License at 005 * 006 * http://www.apache.org/licenses/LICENSE-2.0 007 * 008 * Unless required by applicable law or agreed to in writing, software 009 * distributed under the License is distributed on an "AS IS" BASIS, 010 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 011 * See the License for the specific language governing permissions and 012 * limitations under the License. 013 */ 014package org.gbif.api.vocabulary; 015 016import org.gbif.api.util.AnnotationUtils; 017import org.gbif.dwc.terms.DcTerm; 018import org.gbif.dwc.terms.DwcTerm; 019import org.gbif.dwc.terms.Term; 020 021import java.util.Arrays; 022import java.util.Collections; 023import java.util.HashSet; 024import java.util.List; 025import java.util.Set; 026 027import org.apache.commons.lang3.ArrayUtils; 028 029import static org.gbif.api.vocabulary.InterpretationRemarkSeverity.ERROR; 030import static org.gbif.api.vocabulary.InterpretationRemarkSeverity.INFO; 031import static org.gbif.api.vocabulary.InterpretationRemarkSeverity.WARNING; 032 033/** 034 * An enumeration of validation rules for single occurrence records. 035 */ 036public enum OccurrenceIssue implements InterpretationRemark { 037 038 /** 039 * Coordinate is the exact 0°, 0° coordinate, often indicating a bad null coordinate. 040 */ 041 ZERO_COORDINATE(WARNING, TermsGroup.COORDINATES_TERMS_NO_DATUM), 042 043 /** 044 * Coordinate has a latitude and/or longitude value beyond the maximum (or minimum) decimal value. 045 */ 046 COORDINATE_OUT_OF_RANGE(WARNING, TermsGroup.COORDINATES_TERMS_NO_DATUM), 047 048 /** 049 * Coordinate value is given in some form but GBIF is unable to interpret it. 050 */ 051 COORDINATE_INVALID(WARNING, TermsGroup.COORDINATES_TERMS_NO_DATUM), 052 053 /** 054 * Original coordinate modified by rounding to 5 decimals. 055 */ 056 COORDINATE_ROUNDED(INFO, TermsGroup.COORDINATES_TERMS_NO_DATUM), 057 058 /** 059 * The geodetic datum given could not be interpreted. 060 */ 061 GEODETIC_DATUM_INVALID(WARNING, DwcTerm.geodeticDatum), 062 063 /** 064 * Indicating that the interpreted coordinates assume they are based on WGS84 datum as the datum 065 * was either not indicated or interpretable. See GEODETIC_DATUM_INVALID. 066 */ 067 GEODETIC_DATUM_ASSUMED_WGS84(INFO, DwcTerm.geodeticDatum), 068 069 /** 070 * The original coordinate was successfully reprojected from a different geodetic datum to WGS84. 071 */ 072 COORDINATE_REPROJECTED(INFO, TermsGroup.COORDINATES_TERMS), 073 074 /** 075 * The given decimal latitude and longitude could not be reprojected to WGS84 based on the 076 * provided datum. 077 */ 078 COORDINATE_REPROJECTION_FAILED(WARNING, TermsGroup.COORDINATES_TERMS), 079 080 /** 081 * Indicates successful coordinate reprojection according to provided datum, but which results in 082 * a datum shift larger than 0.1 decimal degrees. 083 */ 084 COORDINATE_REPROJECTION_SUSPICIOUS(WARNING, TermsGroup.COORDINATES_TERMS), 085 086 /** 087 * Indicates an invalid or very unlikely coordinate accuracy derived from precision or uncertainty 088 * in meters. 089 */ 090 @Deprecated //see POR-3061 091 COORDINATE_ACCURACY_INVALID(WARNING), 092 093 /** 094 * Indicates an invalid or very unlikely coordinatePrecision 095 */ 096 COORDINATE_PRECISION_INVALID(WARNING, DwcTerm.coordinatePrecision), 097 098 /** 099 * Indicates an invalid or very unlikely dwc:uncertaintyInMeters. 100 */ 101 COORDINATE_UNCERTAINTY_METERS_INVALID(WARNING, DwcTerm.coordinateUncertaintyInMeters), 102 103 /** 104 * There is a mismatch between coordinate uncertainty in meters and coordinate precision. 105 */ 106 @Deprecated //see POR-1804 107 COORDINATE_PRECISION_UNCERTAINTY_MISMATCH(WARNING), 108 109 /** 110 * The Footprint Spatial Reference System given could not be interpreted. 111 */ 112 FOOTPRINT_SRS_INVALID(WARNING, DwcTerm.footprintSRS), 113 114 /** 115 * The Footprint Well-Known-Text conflicts with the interpreted coordinates 116 * (Decimal Latitude, Decimal Longitude etc). 117 */ 118 FOOTPRINT_WKT_MISMATCH(WARNING, DwcTerm.footprintWKT), 119 120 /** 121 * The Footprint Well-Known-Text given could not be interpreted. 122 */ 123 FOOTPRINT_WKT_INVALID(WARNING, DwcTerm.footprintWKT), 124 125 /** 126 * The interpreted occurrence coordinates fall outside of the indicated country. 127 */ 128 COUNTRY_COORDINATE_MISMATCH(WARNING, TermsGroup.COORDINATES_COUNTRY_TERMS), 129 130 /** 131 * Interpreted country for dwc:country and dwc:countryCode contradict each other. 132 */ 133 COUNTRY_MISMATCH(WARNING, TermsGroup.COUNTRY_TERMS), 134 135 /** 136 * Uninterpretable country values found. 137 */ 138 COUNTRY_INVALID(WARNING, TermsGroup.COUNTRY_TERMS), 139 140 /** 141 * The interpreted country is based on the coordinates, not the verbatim string information. 142 */ 143 COUNTRY_DERIVED_FROM_COORDINATES(WARNING, TermsGroup.COORDINATES_COUNTRY_TERMS), 144 145 /** 146 * The interpreted occurrence coordinates fall outside of the indicated continent. 147 */ 148 CONTINENT_COORDINATE_MISMATCH(WARNING), 149 150 /** 151 * The interpreted continent and country do not match. 152 */ 153 CONTINENT_COUNTRY_MISMATCH(WARNING), 154 155 /** 156 * Uninterpretable continent values found. 157 */ 158 CONTINENT_INVALID(WARNING), 159 160 /** 161 * The interpreted continent is based on the country, not the verbatim string information. 162 */ 163 CONTINENT_DERIVED_FROM_COUNTRY(WARNING), 164 165 /** 166 * The interpreted continent is based on the coordinates, not the verbatim string information. 167 */ 168 CONTINENT_DERIVED_FROM_COORDINATES(WARNING), 169 170 /** 171 * Latitude and longitude appear to be swapped. 172 */ 173 PRESUMED_SWAPPED_COORDINATE(WARNING, TermsGroup.COORDINATES_TERMS_NO_DATUM), 174 175 /** 176 * Longitude appears to be negated, e.g. 32.3 instead of -32.3 177 */ 178 PRESUMED_NEGATED_LONGITUDE(WARNING, TermsGroup.COORDINATES_TERMS_NO_DATUM), 179 180 /** 181 * Latitude appears to be negated, e.g. 32.3 instead of -32.3 182 */ 183 PRESUMED_NEGATED_LATITUDE(WARNING, TermsGroup.COORDINATES_TERMS_NO_DATUM), 184 185 /** 186 * The recorded date specified as the eventDate string and the individual year, month, day and/or 187 * startDayOfYear, endDayOfYear are contradictory. 188 */ 189 RECORDED_DATE_MISMATCH(WARNING, TermsGroup.RECORDED_DATE_TERMS), 190 191 /** 192 * A (partial) invalid date is given, such as a non-existent date, zero month, etc. 193 */ 194 RECORDED_DATE_INVALID(WARNING, TermsGroup.RECORDED_DATE_TERMS), 195 196 /** 197 * The recorded date is highly unlikely, falling either into the future or representing a very old 198 * date before 1600 thus predating modern taxonomy. 199 */ 200 RECORDED_DATE_UNLIKELY(WARNING, TermsGroup.RECORDED_DATE_TERMS), 201 202 /** 203 * Matching to the taxonomic backbone can only be done using a fuzzy, non-exact match. 204 */ 205 TAXON_MATCH_FUZZY(WARNING, TermsGroup.TAXONOMY_TERMS), 206 207 /** 208 * Matching to the taxonomic backbone can only be done on a higher rank and not the scientific 209 * name. 210 */ 211 TAXON_MATCH_HIGHERRANK(WARNING, TermsGroup.TAXONOMY_TERMS), 212 213 /** 214 * Matching to the taxonomic backbone can only be done on a species level, 215 * but the occurrence was in fact considered a broader species aggregate/complex. 216 * @see <a href="https://github.com/gbif/portal-feedback/issues/2935">gbif/portal-feedback#2935</a> 217 */ 218 TAXON_MATCH_AGGREGATE(WARNING, TermsGroup.TAXONOMY_TERMS), 219 220 /** 221 * The scientificNameID was not used when mapping the record to the GBIF backbone. This may indicate one of 222 * <ul> 223 * <li>The ID uses a pattern not configured for use by GBIF</li> 224 * <li>The ID did not uniquely(!) identify a concept in the checklist</li> 225 * <li>The ID found a concept in the checklist which did not map to the backbone</li> 226 * <li>A different ID was used, or the record names were used as no ID lookup successfully linked to the backbone</li> 227 * </ul> 228 * @see <a href="https://github.com/gbif/pipelines/issues/217">gbif/pipelines#217</a> 229 */ 230 TAXON_MATCH_SCIENTIFIC_NAME_ID_IGNORED(INFO, DwcTerm.scientificNameID), 231 232 /** 233 * The taxonConceptID was not used when mapping the record to the GBIF backbone. This may indicate one of 234 * <ul> 235 * <li>The ID uses a pattern not configured for use by GBIF</li> 236 * <li>The ID did not uniquely(!) identify a concept in the checklist</li> 237 * <li>The ID found a concept in the checklist which did not map to the backbone</li> 238 * <li>A different ID was used, or the record names were used as no ID lookup successfully linked to the backbone</li> 239 * </ul> 240 * @see <a href="https://github.com/gbif/pipelines/issues/217">gbif/pipelines#217</a> 241 */ 242 TAXON_MATCH_TAXON_CONCEPT_ID_IGNORED(INFO, DwcTerm.taxonConceptID), 243 244 /** 245 * The taxonID was not used when mapping the record to the GBIF backbone. This may indicate one of 246 * <ul> 247 * <li>The ID uses a pattern not configured for use by GBIF</li> 248 * <li>The ID did not uniquely(!) identify a concept in the checklist</li> 249 * <li>The ID found a concept in the checklist which did not map to the backbone</li> 250 * <li>A different ID was used, or the record names were used as no ID lookup successfully linked to the backbone</li> 251 * </ul> 252 * @see <a href="https://github.com/gbif/pipelines/issues/217">gbif/pipelines#217</a> 253 */ 254 TAXON_MATCH_TAXON_ID_IGNORED(INFO, DwcTerm.taxonID), 255 256 /** 257 * The scientificNameID matched a known pattern, but it was not found in the associated checklist. 258 * The backbone lookup was performed using either the names or a different ID on the record. 259 * This may indicate a poorly formatted identifier or may be caused by a newly created ID that 260 * isn't yet known in the version of the published checklist. 261 * @see <a href="https://github.com/gbif/pipelines/issues/217">gbif/pipelines#217</a> 262 */ 263 SCIENTIFIC_NAME_ID_NOT_FOUND(WARNING, DwcTerm.scientificNameID), 264 265 /** 266 * The taxonConceptID matched a known pattern, but it was not found in the associated checklist. 267 * The backbone lookup was performed using either the names or a different ID on the record. 268 * This may indicate a poorly formatted identifier or may be caused by a newly created ID that isn't yet 269 * known in the version of the published checklist. 270 * @see <a href="https://github.com/gbif/pipelines/issues/217">gbif/pipelines#217</a> 271 */ 272 TAXON_CONCEPT_ID_NOT_FOUND(WARNING, DwcTerm.taxonConceptID), 273 274 /** 275 * The taxonID matched a known pattern, but it was not found in the associated checklist. 276 * The backbone lookup was performed using either the names or a different ID on the record. 277 * This may indicate a poorly formatted identifier or may be caused by a newly created ID that isn't yet 278 * known in the version of the published checklist. 279 * @see <a href="https://github.com/gbif/pipelines/issues/217">gbif/pipelines#217</a> 280 */ 281 TAXON_ID_NOT_FOUND(WARNING, DwcTerm.taxonID), 282 283 /** 284 * The scientificName provided in the occurrence record does not precisely match the name in the registered checklist 285 * when using the scientificNameID, taxonID or taxonConceptID to look it up. Publishers are advised to check the IDs 286 * are correct, or update the formatting of the names on their records. 287 * @see <a href="https://github.com/gbif/pipelines/issues/217">gbif/pipelines#217</a> 288 */ 289 SCIENTIFIC_NAME_AND_ID_INCONSISTENT(WARNING, DwcTerm.scientificNameID, DwcTerm.taxonID, DwcTerm.taxonConceptID, DwcTerm.scientificName), 290 291 /** 292 * Matching to the taxonomic backbone cannot be done because there was no match at all, or several 293 * matches with too little information to keep them apart (potentially homonyms). 294 */ 295 TAXON_MATCH_NONE(WARNING, TermsGroup.TAXONOMY_TERMS), 296 297 /** 298 * The GBIF Backbone concept was found using the scientificNameID, taxonID or taxonConceptID, but it differs from what would 299 * have been found if the classification names on the record were used. This may indicate a gap in the GBIF backbone, 300 * a poor mapping between the checklist and the backbone, or a mismatch between the classification names and the 301 * declared IDs (scientificNameID or taxonConceptID) on the occurrence record itself. 302 * @see <a href="https://github.com/gbif/pipelines/issues/217">gbif/pipelines#217</a> 303 */ 304 TAXON_MATCH_NAME_AND_ID_AMBIGUOUS(WARNING, TermsGroup.TAXONOMY_TERMS), 305 306 /** 307 * Set if supplied depth is not given in the metric system, for example using feet instead of 308 * meters 309 */ 310 DEPTH_NOT_METRIC(WARNING, DwcTerm.minimumDepthInMeters, DwcTerm.maximumDepthInMeters), 311 312 /** 313 * Set if depth is larger than 11,000m or negative. 314 */ 315 DEPTH_UNLIKELY(WARNING, DwcTerm.minimumDepthInMeters, DwcTerm.maximumDepthInMeters), 316 317 /** 318 * Set if supplied minimum depth > maximum depth 319 */ 320 DEPTH_MIN_MAX_SWAPPED(WARNING, DwcTerm.minimumDepthInMeters, DwcTerm.maximumDepthInMeters), 321 322 /** 323 * Set if depth is a non-numeric value 324 */ 325 DEPTH_NON_NUMERIC(WARNING, DwcTerm.minimumDepthInMeters, DwcTerm.maximumDepthInMeters), 326 327 /** 328 * Set if elevation is above the troposphere (17km) or below 11km (Mariana Trench). 329 */ 330 ELEVATION_UNLIKELY(WARNING, DwcTerm.minimumElevationInMeters, DwcTerm.maximumElevationInMeters), 331 332 /** 333 * Set if supplied minimum elevation > maximum elevation 334 */ 335 ELEVATION_MIN_MAX_SWAPPED(WARNING, DwcTerm.minimumElevationInMeters, 336 DwcTerm.maximumElevationInMeters), 337 338 /** 339 * Set if supplied elevation is not given in the metric system, for example using feet instead of 340 * meters 341 */ 342 ELEVATION_NOT_METRIC(WARNING, DwcTerm.minimumElevationInMeters, DwcTerm.maximumElevationInMeters), 343 344 /** 345 * Set if elevation is a non-numeric value 346 */ 347 ELEVATION_NON_NUMERIC(WARNING, DwcTerm.minimumElevationInMeters, 348 DwcTerm.maximumElevationInMeters), 349 350 /** 351 * A (partial) invalid date is given for dc:modified, such as a nonexistent date, zero month, etc. 352 */ 353 MODIFIED_DATE_INVALID(WARNING, DcTerm.modified), 354 355 /** 356 * The date given for dc:modified is in the future or predates Unix time (1970). 357 */ 358 MODIFIED_DATE_UNLIKELY(WARNING, DcTerm.modified), 359 360 /** 361 * The date given for dwc:dateIdentified is in the future or before Linnean times (1700). 362 */ 363 IDENTIFIED_DATE_UNLIKELY(WARNING, DwcTerm.dateIdentified), 364 365 /** 366 * The date given for dwc:dateIdentified is invalid and can't be interpreted at all. 367 */ 368 IDENTIFIED_DATE_INVALID(WARNING, DwcTerm.dateIdentified), 369 370 /** 371 * The given basis of record is impossible to interpret or significantly different from the 372 * recommended vocabulary. 373 */ 374 BASIS_OF_RECORD_INVALID(WARNING, DwcTerm.basisOfRecord), 375 376 /** 377 * The given type status is impossible to interpret or significantly different from the 378 * recommended vocabulary. 379 */ 380 TYPE_STATUS_INVALID(WARNING, DwcTerm.typeStatus), 381 382 /** 383 * The given type status contains some words that express uncertainty. 384 */ 385 SUSPECTED_TYPE(WARNING, DwcTerm.typeStatus), 386 /** 387 * An invalid date is given for dc:created of a multimedia object. 388 */ 389 MULTIMEDIA_DATE_INVALID(WARNING), 390 391 /** 392 * An invalid URI is given for a multimedia object. 393 */ 394 MULTIMEDIA_URI_INVALID(WARNING), 395 396 /** 397 * An invalid URI is given for dc:references. 398 */ 399 REFERENCES_URI_INVALID(WARNING, DcTerm.references), 400 401 /** 402 * An error occurred during interpretation, leaving the record interpretation incomplete. 403 */ 404 INTERPRETATION_ERROR(ERROR), 405 406 /** 407 * The individual count value is not a positive integer 408 */ 409 INDIVIDUAL_COUNT_INVALID(WARNING, DwcTerm.individualCount), 410 411 /** 412 * Example: individual count value > 0, but occurrence status is absent. 413 */ 414 INDIVIDUAL_COUNT_CONFLICTS_WITH_OCCURRENCE_STATUS(WARNING, DwcTerm.individualCount), 415 416 /** 417 * Occurrence status value can't be assigned to {@link OccurrenceStatus} 418 */ 419 OCCURRENCE_STATUS_UNPARSABLE(WARNING, DwcTerm.occurrenceStatus), 420 421 /** 422 * Occurrence status was inferred from the individual count value 423 */ 424 OCCURRENCE_STATUS_INFERRED_FROM_INDIVIDUAL_COUNT(WARNING, DwcTerm.occurrenceStatus), 425 426 /** 427 * Occurrence status was inferred from basis of records 428 */ 429 OCCURRENCE_STATUS_INFERRED_FROM_BASIS_OF_RECORD(WARNING, DwcTerm.occurrenceStatus), 430 431 /** 432 * The date given for dwc:georeferencedDate is in the future or before Linnean times (1700). 433 */ 434 GEOREFERENCED_DATE_UNLIKELY(WARNING, DwcTerm.georeferencedDate), 435 436 /** 437 * The date given for dwc:georeferencedDate is invalid and can't be interpreted at all. 438 */ 439 GEOREFERENCED_DATE_INVALID(WARNING, DwcTerm.georeferencedDate), 440 441 /** 442 * The given institution matches with more than 1 GRSciColl institution. 443 */ 444 AMBIGUOUS_INSTITUTION(INFO, TermsGroup.INSTITUTION_TERMS), 445 446 /** 447 * The given collection matches with more than 1 GRSciColl collection. 448 */ 449 AMBIGUOUS_COLLECTION(INFO, TermsGroup.COLLECTION_TERMS), 450 451 /** 452 * The given institution couldn't be matched with any GRSciColl institution. 453 */ 454 INSTITUTION_MATCH_NONE(INFO, TermsGroup.INSTITUTION_TERMS), 455 456 /** 457 * The given collection couldn't be matched with any GRSciColl collection. 458 */ 459 COLLECTION_MATCH_NONE(INFO, TermsGroup.COLLECTION_TERMS), 460 461 /** 462 * The given institution was fuzzily matched to a GRSciColl institution. This can happen when 463 * either the code or the ID don't match or when the institution name is used instead of the code. 464 */ 465 INSTITUTION_MATCH_FUZZY(INFO, TermsGroup.INSTITUTION_TERMS), 466 467 /** 468 * The given collection was fuzzily matched to a GRSciColl collection. This can happen when either 469 * the code or the ID don't match or when the collection name is used instead of the code. 470 */ 471 COLLECTION_MATCH_FUZZY(INFO, TermsGroup.COLLECTION_TERMS), 472 473 /** The collection matched doesn't belong to the institution matched. */ 474 INSTITUTION_COLLECTION_MISMATCH( 475 INFO, ArrayUtils.addAll(TermsGroup.INSTITUTION_TERMS, TermsGroup.INSTITUTION_TERMS)), 476 477 /** 478 * The given owner institution is different than the given institution. Therefore we assume it 479 * could be on loan and we don't link it to the occurrence. 480 * 481 * Deprecated by {@link #DIFFERENT_OWNER_INSTITUTION}. 482 */ 483 @Deprecated 484 POSSIBLY_ON_LOAN(INFO, TermsGroup.INSTITUTION_TERMS), 485 486 /** 487 * The given owner institution is different than the given institution. Therefore we assume it 488 * doesn't belong to the institution and we don't link it to the occurrence. 489 */ 490 DIFFERENT_OWNER_INSTITUTION(INFO, TermsGroup.INSTITUTION_TERMS); 491 492 /** 493 * Simple helper nested class to allow grouping of Term mostly to increase readability of this 494 * class. 495 */ 496 private static class TermsGroup { 497 498 static final Term[] COORDINATES_TERMS_NO_DATUM = { 499 DwcTerm.decimalLatitude, 500 DwcTerm.decimalLongitude, 501 DwcTerm.verbatimLatitude, 502 DwcTerm.verbatimLongitude, 503 DwcTerm.verbatimCoordinates 504 }; 505 506 static final Term[] COORDINATES_TERMS = { 507 DwcTerm.decimalLatitude, 508 DwcTerm.decimalLongitude, 509 DwcTerm.verbatimLatitude, 510 DwcTerm.verbatimLongitude, 511 DwcTerm.verbatimCoordinates, 512 DwcTerm.geodeticDatum 513 }; 514 515 static final Term[] COUNTRY_TERMS = { 516 DwcTerm.country, 517 DwcTerm.countryCode 518 }; 519 520 static final Term[] COORDINATES_COUNTRY_TERMS = { 521 DwcTerm.decimalLatitude, 522 DwcTerm.decimalLongitude, 523 DwcTerm.verbatimLatitude, 524 DwcTerm.verbatimLongitude, 525 DwcTerm.verbatimCoordinates, 526 DwcTerm.geodeticDatum, 527 DwcTerm.country, 528 DwcTerm.countryCode 529 }; 530 531 static final Term[] RECORDED_DATE_TERMS = { 532 DwcTerm.eventDate, 533 DwcTerm.year, DwcTerm.month, DwcTerm.day, 534 DwcTerm.startDayOfYear, DwcTerm.endDayOfYear 535 }; 536 537 static final Term[] TAXONOMY_TERMS = { 538 DwcTerm.kingdom, 539 DwcTerm.phylum, 540 DwcTerm.class_, 541 DwcTerm.order, 542 DwcTerm.family, 543 DwcTerm.genus, 544 DwcTerm.scientificName, 545 DwcTerm.scientificNameAuthorship, 546 DwcTerm.genericName, 547 DwcTerm.specificEpithet, 548 DwcTerm.infraspecificEpithet, 549 DwcTerm.scientificNameID, 550 DwcTerm.taxonConceptID, 551 }; 552 553 static final Term[] INSTITUTION_TERMS = { 554 DwcTerm.institutionCode, DwcTerm.institutionID, DwcTerm.ownerInstitutionCode 555 }; 556 557 static final Term[] COLLECTION_TERMS = {DwcTerm.collectionCode, DwcTerm.collectionID}; 558 } 559 560 private final Set<Term> relatedTerms; 561 private final InterpretationRemarkSeverity severity; 562 private final boolean isDeprecated; 563 564 /** 565 * {@link OccurrenceIssue} not linked to any specific {@link Term}. 566 */ 567 OccurrenceIssue(InterpretationRemarkSeverity severity) { 568 this.severity = severity; 569 this.relatedTerms = Collections.emptySet(); 570 this.isDeprecated = AnnotationUtils.isFieldDeprecated(OccurrenceIssue.class, this.name()); 571 } 572 573 /** 574 * {@link OccurrenceIssue} linked to the provided {@link Term}. 575 */ 576 OccurrenceIssue(InterpretationRemarkSeverity severity, Term... relatedTerms) { 577 this.severity = severity; 578 this.relatedTerms = Collections.unmodifiableSet(new HashSet<>(Arrays.asList(relatedTerms))); 579 this.isDeprecated = AnnotationUtils.isFieldDeprecated(OccurrenceIssue.class, this.name()); 580 } 581 582 @Override 583 public String getId() { 584 return name(); 585 } 586 587 @Override 588 public Set<Term> getRelatedTerms() { 589 return relatedTerms; 590 } 591 592 @Override 593 public InterpretationRemarkSeverity getSeverity() { 594 return severity; 595 } 596 597 @Override 598 public boolean isDeprecated() { 599 return isDeprecated; 600 } 601 602 /** 603 * All issues that indicate problems with the coordinates and thus should not be shown on maps. 604 */ 605 public static final List<OccurrenceIssue> GEOSPATIAL_RULES = 606 Collections.unmodifiableList( 607 Arrays.asList( 608 ZERO_COORDINATE, 609 COORDINATE_OUT_OF_RANGE, 610 COORDINATE_INVALID, 611 COUNTRY_COORDINATE_MISMATCH, 612 PRESUMED_SWAPPED_COORDINATE, 613 PRESUMED_NEGATED_LONGITUDE, 614 PRESUMED_NEGATED_LATITUDE)); 615}