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.model.checklistbank; 015 016import org.gbif.api.model.Constants; 017import org.gbif.api.model.common.LinneanClassification; 018import org.gbif.api.model.common.LinneanClassificationKeys; 019import org.gbif.api.util.ClassificationUtils; 020import org.gbif.api.vocabulary.NameType; 021import org.gbif.api.vocabulary.NameUsageIssue; 022import org.gbif.api.vocabulary.NomenclaturalStatus; 023import org.gbif.api.vocabulary.Origin; 024import org.gbif.api.vocabulary.Rank; 025import org.gbif.api.vocabulary.TaxonomicStatus; 026 027import java.net.URI; 028import java.util.Date; 029import java.util.EnumSet; 030import java.util.HashSet; 031import java.util.LinkedHashMap; 032import java.util.Objects; 033import java.util.Set; 034import java.util.StringJoiner; 035import java.util.UUID; 036 037import javax.annotation.Nullable; 038import javax.validation.constraints.NotNull; 039 040import com.fasterxml.jackson.annotation.JsonIgnore; 041import com.fasterxml.jackson.annotation.JsonProperty; 042 043import io.swagger.v3.oas.annotations.media.Schema; 044 045/** 046 * A usage of a <em>scientific name</em> according to one particular Checklist including the GBIF Taxonomic Backbone, 047 * the NUB. It is shown as species in the portal and API. 048 * <br> 049 * Backbone (NUB) usages have key==nubKey. Backbone usages can also be detected by either the NameUsage.isNub() method 050 * or by manually comparing the datasetKey with the fixed backbone datasetKey, see Constants.NUB_DATASET_KEY. 051 * <br> 052 * Name usages from other checklists with names that also exist in the backbone will have a nubKey that points to the related usage in the NUB. 053 * <br> 054 * To store not eagerly loaded subresources such as vernacular names or synonyms with a usage please use 055 * the {@link NameUsageContainer} class. 056 */ 057@SuppressWarnings("unused") 058@Deprecated 059public class NameUsage implements LinneanClassification, LinneanClassificationKeys { 060 061 private Integer key; 062 private Integer nubKey; 063 private Integer nameKey; 064 private String taxonID; 065 private Integer sourceTaxonKey; 066 // for LinneanClassification 067 private String kingdom; 068 private String phylum; 069 @JsonProperty("class") 070 private String clazz; 071 private String order; 072 private String family; 073 private String genus; 074 private String subgenus; 075 private String species; 076 // for LinneanClassificationKeys 077 private Integer kingdomKey; 078 private Integer phylumKey; 079 private Integer classKey; 080 private Integer orderKey; 081 private Integer familyKey; 082 private Integer genusKey; 083 private Integer subgenusKey; 084 private Integer speciesKey; 085 086 private UUID datasetKey; 087 private UUID constituentKey; 088 private Integer parentKey; 089 private String parent; 090 private Integer proParteKey; 091 private Integer acceptedKey; 092 private String accepted; 093 private Integer basionymKey; 094 private String basionym; 095 096 private String scientificName; 097 private String canonicalName; 098 private String vernacularName; 099 private String authorship; 100 private NameType nameType; 101 private Rank rank; 102 private Origin origin; 103 private TaxonomicStatus taxonomicStatus; 104 private Set<NomenclaturalStatus> nomenclaturalStatus = new HashSet<>(); 105 private String remarks; 106 private String publishedIn; 107 private String accordingTo; 108 109 private int numDescendants; 110 private URI references; 111 112 private Date modified; 113 private Date deleted; 114 private Date lastCrawled; 115 private Date lastInterpreted; 116 private Set<NameUsageIssue> issues = EnumSet.noneOf(NameUsageIssue.class); 117 118 public NameUsage() {} 119 120 public NameUsage(NameUsage other) { 121 this.key = other.key; 122 this.nubKey = other.nubKey; 123 this.nameKey = other.nameKey; 124 this.taxonID = other.taxonID; 125 this.sourceTaxonKey = other.sourceTaxonKey; 126 this.kingdom = other.kingdom; 127 this.phylum = other.phylum; 128 this.clazz = other.clazz; 129 this.order = other.order; 130 this.family = other.family; 131 this.genus = other.genus; 132 this.subgenus = other.subgenus; 133 this.species = other.species; 134 this.kingdomKey = other.kingdomKey; 135 this.phylumKey = other.phylumKey; 136 this.classKey = other.classKey; 137 this.orderKey = other.orderKey; 138 this.familyKey = other.familyKey; 139 this.genusKey = other.genusKey; 140 this.subgenusKey = other.subgenusKey; 141 this.speciesKey = other.speciesKey; 142 this.datasetKey = other.datasetKey; 143 this.constituentKey = other.constituentKey; 144 this.parentKey = other.parentKey; 145 this.parent = other.parent; 146 this.proParteKey = other.proParteKey; 147 this.acceptedKey = other.acceptedKey; 148 this.accepted = other.accepted; 149 this.basionymKey = other.basionymKey; 150 this.basionym = other.basionym; 151 this.scientificName = other.scientificName; 152 this.canonicalName = other.canonicalName; 153 this.vernacularName = other.vernacularName; 154 this.authorship = other.authorship; 155 this.nameType = other.nameType; 156 this.rank = other.rank; 157 this.origin = other.origin; 158 this.taxonomicStatus = other.taxonomicStatus; 159 this.nomenclaturalStatus = other.nomenclaturalStatus; 160 this.remarks = other.remarks; 161 this.publishedIn = other.publishedIn; 162 this.accordingTo = other.accordingTo; 163 this.numDescendants = other.numDescendants; 164 this.references = other.references; 165 this.modified = other.modified; 166 this.deleted = other.deleted; 167 this.lastCrawled = other.lastCrawled; 168 this.lastInterpreted = other.lastInterpreted; 169 this.issues = other.issues; 170 } 171 172 /** 173 * @return the name key for retrieving a parsed name object 174 */ 175 @Schema(description = "The key for retrieving a parsed name object.\n\n" + 176 "*You are more likely to need the `key` or `nubKey` properties*") 177 public Integer getNameKey() { 178 return nameKey; 179 } 180 181 public void setNameKey(Integer nameKey) { 182 this.nameKey = nameKey; 183 } 184 185 /** 186 * For backbone taxa the source taxon key refers to the original name usage that was used during backbone building 187 * and is the primary reason that this taxon exists in the backbone. 188 * <br/> 189 * All backbone name usages are built from several underlying checklist usages, 190 * but these are sorted by priority and the usage key for the highest priority one becomes the sourceTaxonKey 191 * for a backbone usage. 192 * <br/> 193 * Some backbone usages do not have any source record altogether. 194 * For example if there is a subspecies found, but no matching parent species, 195 * the missing species will be created nevertheless and has no primary source. 196 * 197 * @return The key of the name usage this backbone taxon is derived from. 198 */ 199 @Nullable 200 @Schema(description = "The key of the name usage from which this backbone taxon derives.\n" + 201 "\n" + 202 "For backbone taxa the source taxon key refers to the original name usage that was used during " + 203 "backbone building and is the primary reason that this taxon exists in the backbone.\n" + 204 "\n" + 205 "All backbone name usages are built from several underlying checklist usages, but these are sorted by priority " + 206 "and the usage key for the highest priority one becomes the sourceTaxonKey for a backbone usage.\n" + 207 "\n" + 208 "Some backbone usages do not have any source record at all; for example if there is a subspecies found, but no matching " + 209 "parent species, the missing species will be created nevertheless and has no primary source.") 210 public Integer getSourceTaxonKey() { 211 return sourceTaxonKey; 212 } 213 214 public void setSourceTaxonKey(Integer sourceTaxonKey) { 215 this.sourceTaxonKey = sourceTaxonKey; 216 } 217 218 /** 219 * @return the scientific name of the accepted name 220 */ 221 @Schema(description = "The scientific name of the accepted name.") 222 public String getAccepted() { 223 return accepted; 224 } 225 226 /** 227 * Sets the scientific name of the basionym, i.e. original name usage. 228 */ 229 public void setAccepted(String accepted) { 230 this.accepted = accepted; 231 } 232 233 /** 234 * @return the name usage key of the accepted name 235 */ 236 @Schema(description = "The name usage key of the accepted name.") 237 public Integer getAcceptedKey() { 238 return acceptedKey; 239 } 240 241 /** 242 * Sets the usage key for the accepted name. 243 */ 244 public void setAcceptedKey(Integer acceptedKey) { 245 this.acceptedKey = acceptedKey; 246 } 247 248 /** 249 * The taxon concept reference is usually a reference to some publication or author and year. 250 * <br> 251 * The dwc:taxonAccordingTo reference is usually appended to the scientific name to further qualify the concept 252 * with "sensu" or "sec." being used for concatenation. E.g. "Acer nigrum sec. Gleason Cronquist 1991". 253 * <br> 254 * In the case of backbone taxa this refers to the primary checklist the name was found in. 255 * 256 * @return the taxon concept reference 257 */ 258 @Schema(description = "The taxon concept reference.\n\n" + 259 "This is usually a reference to some publication or an author and year.\n\n" + 260 "The Darwin Core `taxonAccordingTo` reference is usually appended to the scientific name to further qualify " + 261 "the concept with “sensu” or “sec.” being used for concatenation; for example “_Acer nigrum_ sec. Gleason Cronquist 1991”.\n\n" + 262 "In the case of backbone taxa, this refers to the primary checklist in which the name was found.") 263 @Nullable 264 public String getAccordingTo() { 265 return accordingTo; 266 } 267 268 /** 269 * @param accordingTo the accordingTo to set 270 */ 271 public void setAccordingTo(String accordingTo) { 272 this.accordingTo = accordingTo; 273 } 274 275 /** 276 * Returns the authorship information for the scientific name. 277 * 278 * @return the authorship 279 */ 280 @Schema(description = "The authorship for the scientific name.") 281 @Nullable 282 public String getAuthorship() { 283 return authorship; 284 } 285 286 /** 287 * @param authorship the authorship to set 288 */ 289 public void setAuthorship(String authorship) { 290 this.authorship = authorship; 291 } 292 293 /** 294 * @return the scientific name of the basionym 295 */ 296 @Schema(description = "The scientific name of the basionym.") 297 public String getBasionym() { 298 return basionym; 299 } 300 301 /** 302 * sets the basionym name. 303 */ 304 public void setBasionym(String basionym) { 305 this.basionym = basionym; 306 } 307 308 /** 309 * Returns the earlier name (basionym) for this scientific name. Return null if the basionym does not exist. 310 * 311 * @return the basionymKey 312 */ 313 @Schema(description = "The name usage key of the basionym.") 314 @Nullable 315 public Integer getBasionymKey() { 316 return basionymKey; 317 } 318 319 /** 320 * @param basionymKey the basionymKey to set 321 */ 322 public void setBasionymKey(Integer basionymKey) { 323 this.basionymKey = basionymKey; 324 } 325 326 /** 327 * @return the canonicalName 328 */ 329 @Schema(description = "The canonical name; the name without authorship or references.") 330 @Nullable 331 public String getCanonicalName() { 332 return canonicalName; 333 } 334 335 /** 336 * @param canonicalName the canonicalName to set 337 */ 338 public void setCanonicalName(String canonicalName) { 339 this.canonicalName = canonicalName; 340 } 341 342 /** 343 * Returns the key of the checklist that "hosts" this name usage. 344 * 345 * @return the datasetKey 346 */ 347 @Schema(description = "The checklist that “hosts” this name usage.\n\n" + 348 "For a backbone name usage, this will be `d7dddbf4-2cf0-4f39-9b2a-bb099caae36c`.") 349 @NotNull 350 public UUID getDatasetKey() { 351 return datasetKey; 352 } 353 354 /** 355 * @param datasetKey the datasetKey to set 356 */ 357 public void setDatasetKey(UUID datasetKey) { 358 this.datasetKey = datasetKey; 359 } 360 361 /** 362 * Return the key that uniquely identifies this name usage. 363 * 364 * @return the key 365 */ 366 @Schema(description = "The name usage key that uniquely identifies this name usage.") 367 @NotNull 368 public Integer getKey() { 369 return key; 370 } 371 372 /** 373 * @param key the key to set 374 */ 375 public void setKey(Integer key) { 376 this.key = key; 377 } 378 379 /** 380 * @return the type of name string classified by CLB. 381 */ 382 @Schema(description = "The type of name string classified by Checklistbank.") 383 public NameType getNameType() { 384 return nameType; 385 } 386 387 /** 388 * @param nameType the type of name string 389 */ 390 public void setNameType(NameType nameType) { 391 this.nameType = nameType; 392 } 393 394 /** 395 * The status related to the conformance to the relevant rules of nomenclature. 396 * <blockquote> 397 * <p> 398 * <i>Example:</i> "invalid", "misapplied", "homotypic synonym", "accepted" 399 * </p> 400 * </blockquote> 401 * 402 * @return the set of known nomenclaturalStatus values 403 * 404 * @see <a href="http://rs.gbif.org/vocabulary/gbif/nomenclatural_status.xml">Nomenclatural Status GBIF 405 * Vocabulary</a> 406 */ 407 @Schema(description = "The nomenclatural statuses of this name usage.") 408 public Set<NomenclaturalStatus> getNomenclaturalStatus() { 409 return nomenclaturalStatus; 410 } 411 412 /** 413 * @param nomenclaturalStatus the nomenclaturalStatus to set 414 */ 415 public void setNomenclaturalStatus(Set<NomenclaturalStatus> nomenclaturalStatus) { 416 this.nomenclaturalStatus = nomenclaturalStatus; 417 } 418 419 /** 420 * @return the taxon key of the matching backbone name usage 421 */ 422 @Schema(description = "The taxon key of the matching backbone name usage.\n\n" + 423 "If this is equal to `key`, this name usage is a backbone name usage.") 424 @Nullable 425 public Integer getNubKey() { 426 return nubKey; 427 } 428 429 /** 430 * @param nubKey the nubKey to set 431 */ 432 public void setNubKey(Integer nubKey) { 433 this.nubKey = nubKey; 434 } 435 436 /** 437 * The number of all accepted taxonomic elements under this usage. 438 * 439 * @return the number of descendants 440 */ 441 @Schema(description = "A total count of all accepted taxonomic elements under this usage.") 442 public int getNumDescendants() { 443 return numDescendants; 444 } 445 446 /** 447 * @param numDescendants the n umber of descendants to set 448 */ 449 public void setNumDescendants(int numDescendants) { 450 this.numDescendants = numDescendants; 451 } 452 453 /** 454 * The origin of this name usage record, i.e. the reason why it exists. 455 * In most cases this is because the record existed explicitly in the checklist sources, but 456 * some usages are created de novo because they exist implicitly in the data. 457 * 458 * @return the name usage origin 459 * 460 * @see Origin 461 */ 462 @Schema(description = "The name usage origin.\n\n" + 463 "The origin of this name usage record, the reason it exists.\n\n" + 464 "In most cases this is because the record existed explicitly in the checklist sources, but some usages are " + 465 "created *de novo* because the exist implicitly in the data.") 466 @NotNull 467 public Origin getOrigin() { 468 return origin; 469 } 470 471 /** 472 * @param origin the origin to set 473 */ 474 public void setOrigin(Origin origin) { 475 this.origin = origin; 476 } 477 478 /** 479 * The scientific name of the parent. 480 * 481 * @return the parent name 482 */ 483 @Schema(description = "The scientific name of the parent.") 484 public String getParent() { 485 return parent; 486 } 487 488 /** 489 * @param parent the parent name to set 490 */ 491 public void setParent(String parent) { 492 this.parent = parent; 493 } 494 495 /** 496 * Returns the immediate parent. If this usage if for the highest taxonomic level, return null. 497 * 498 * @return the parentKey 499 */ 500 @Schema(description = "The name usage key of the immediate parent. Null for the highest taxonomic level.") 501 @Nullable 502 public Integer getParentKey() { 503 return parentKey; 504 } 505 506 /** 507 * @param parentKey the parentKey to set 508 */ 509 public void setParentKey(Integer parentKey) { 510 this.parentKey = parentKey; 511 } 512 513 /** 514 * Pro parte synonyms, i.e. a synonym with multiple accepted names, are grouped by a single, primary name usage key. 515 * 516 * @return the primary name usage key for a pro parte synonym or null 517 */ 518 @Schema(description = "The primary name usage key for a *pro parte* synonym.\n\n" + 519 "Synonyms with multiple accepted names are grouped by a single, primary name usage key.") 520 public Integer getProParteKey() { 521 return proParteKey; 522 } 523 524 /** 525 * Sets the pro parte usage key. 526 */ 527 public void setProParteKey(Integer proParteKey) { 528 this.proParteKey = proParteKey; 529 } 530 531 /** 532 * Original publication for this name usage. 533 * 534 * @return the publishedIn 535 */ 536 @Schema(description = "Original publication for this name usage.") 537 @Nullable 538 public String getPublishedIn() { 539 return publishedIn; 540 } 541 542 /** 543 * @param publishedIn the publishedIn to set 544 */ 545 public void setPublishedIn(String publishedIn) { 546 this.publishedIn = publishedIn; 547 } 548 549 /** 550 * Returns the rank for this usage. 551 * <blockquote> 552 * <p> 553 * <i>Example:</i> "Kingdom", "Genus" 554 * </p> 555 * </blockquote> 556 * 557 * @return the rank 558 */ 559 @Schema(description = "The rank for this usage.") 560 @Nullable 561 public Rank getRank() { 562 return rank; 563 } 564 565 /** 566 * @param rank the rank to set 567 */ 568 public void setRank(Rank rank) { 569 this.rank = rank; 570 } 571 572 /** 573 * The scientific name (with date and authorship information if applicable). 574 * <blockquote> 575 * <p> 576 * <i>Example:</i> "Coleoptera" (order), "Vespertilionidae" (family), "Manis" (genus), "Ctenomys sociabilis" (genus + 577 * specific name), "Ambystoma tigrinum diaboli" (genus + specific name + infraspecific name), 578 * "Quercus agrifolia var. oxyadenia (Torr.)" 579 * </p> 580 * </blockquote> 581 * 582 * @return the scientificName 583 */ 584 @Schema(description = "The scientific name, with date and authorship information if available.\n\n" + 585 "Examples: *Coleoptera* (order), *Vespertilionidae* (family), *Manis* (genus), *Ctenomys sociabilis* " + 586 "(genus + specificEpithet), *Ambystoma tigrinum diaboli* (zoology, genus + specific name + infraspecific name) " + 587 "*Quercus agrifolia* var. *oxyadenia* (Torr.) (botany, genus + specific epithet + infraspecific epithet + authorship)") 588 @NotNull 589 public String getScientificName() { 590 return scientificName; 591 } 592 593 /** 594 * @param scientificName the scientificName to set 595 */ 596 public void setScientificName(String scientificName) { 597 this.scientificName = scientificName; 598 } 599 600 /** 601 * Return the optional sub dataset key for this usage. 602 * 603 * @return the subDatasetKey or null 604 */ 605 @Schema(description = "The optional sub-dataset key for this usage.") 606 @Nullable 607 public UUID getConstituentKey() { 608 return constituentKey; 609 } 610 611 /** 612 * @param constituentKey to set 613 */ 614 public void setConstituentKey(UUID constituentKey) { 615 this.constituentKey = constituentKey; 616 } 617 618 /** 619 * A common or vernacular name for this usage. 620 * <blockquote> 621 * <p> 622 * <i>Example:</i> Andean Condor", "Condor Andino", "American Eagle", "Gänsegeier". 623 * </p> 624 * </blockquote> 625 * 626 * @return the vernacularName 627 */ 628 @Schema(description = "A common or vernacular name for this usage.") 629 @Nullable 630 public String getVernacularName() { 631 return vernacularName; 632 } 633 634 /** 635 * @param vernacularName the vernacularName to set 636 */ 637 public void setVernacularName(String vernacularName) { 638 this.vernacularName = vernacularName; 639 } 640 641 @Schema(description = "Kingdom.") 642 @Override 643 public String getKingdom() { 644 return kingdom; 645 } 646 647 @Override 648 public void setKingdom(String kingdom) { 649 this.kingdom = kingdom; 650 } 651 652 @Schema(description = "Phylum.") 653 @Override 654 public String getPhylum() { 655 return phylum; 656 } 657 658 @Override 659 public void setPhylum(String phylum) { 660 this.phylum = phylum; 661 } 662 663 @Schema(description = "Class.") 664 @Override 665 public String getClazz() { 666 return clazz; 667 } 668 669 @Override 670 public void setClazz(String clazz) { 671 this.clazz = clazz; 672 } 673 674 @Schema(description = "Order.") 675 @Override 676 public String getOrder() { 677 return order; 678 } 679 680 @Override 681 public void setOrder(String order) { 682 this.order = order; 683 } 684 685 @Schema(description = "Family.") 686 @Override 687 public String getFamily() { 688 return family; 689 } 690 691 @Override 692 public void setFamily(String family) { 693 this.family = family; 694 } 695 696 @Schema(description = "Genus.") 697 @Override 698 public String getGenus() { 699 return genus; 700 } 701 702 @Override 703 public void setGenus(String genus) { 704 this.genus = genus; 705 } 706 707 @Schema(description = "Subgenus.") 708 @Override 709 public String getSubgenus() { 710 return subgenus; 711 } 712 713 @Override 714 public void setSubgenus(String subgenus) { 715 this.subgenus = subgenus; 716 } 717 718 @Schema(description = "Species.") 719 @Override 720 public String getSpecies() { 721 return species; 722 } 723 724 @Override 725 public void setSpecies(String species) { 726 this.species = species; 727 } 728 729 @Schema(description = "Name usage key of the kingdom.") 730 @Override 731 public Integer getKingdomKey() { 732 return kingdomKey; 733 } 734 735 @Override 736 public void setKingdomKey(Integer kingdomKey) { 737 this.kingdomKey = kingdomKey; 738 } 739 740 @Schema(description = "Name usage key of the phylum.") 741 @Override 742 public Integer getPhylumKey() { 743 return phylumKey; 744 } 745 746 @Override 747 public void setPhylumKey(Integer phylumKey) { 748 this.phylumKey = phylumKey; 749 } 750 751 @Schema(description = "Name usage key of the class.") 752 @Override 753 public Integer getClassKey() { 754 return classKey; 755 } 756 757 @Override 758 public void setClassKey(Integer classKey) { 759 this.classKey = classKey; 760 } 761 762 @Schema(description = "Name usage key of the order.") 763 @Override 764 public Integer getOrderKey() { 765 return orderKey; 766 } 767 768 @Override 769 public void setOrderKey(Integer orderKey) { 770 this.orderKey = orderKey; 771 } 772 773 @Schema(description = "Name usage key of the family.") 774 @Override 775 public Integer getFamilyKey() { 776 return familyKey; 777 } 778 779 @Override 780 public void setFamilyKey(Integer familyKey) { 781 this.familyKey = familyKey; 782 } 783 784 @Schema(description = "Name usage key of the genus.") 785 @Override 786 public Integer getGenusKey() { 787 return genusKey; 788 } 789 790 @Override 791 public void setGenusKey(Integer genusKey) { 792 this.genusKey = genusKey; 793 } 794 795 @Schema(description = "Name usage key of the subgenus.") 796 @Override 797 public Integer getSubgenusKey() { 798 return subgenusKey; 799 } 800 801 @Override 802 public void setSubgenusKey(Integer subgenusKey) { 803 this.subgenusKey = subgenusKey; 804 } 805 806 @Schema(description = "Name usage key of the species.") 807 @Override 808 public Integer getSpeciesKey() { 809 return speciesKey; 810 } 811 812 @Override 813 public void setSpeciesKey(Integer speciesKey) { 814 this.speciesKey = speciesKey; 815 } 816 817 @Schema(description = "Remarks on the name usage.") 818 public String getRemarks() { 819 return remarks; 820 } 821 822 public void setRemarks(String remarks) { 823 this.remarks = remarks; 824 } 825 826 /** 827 * @return the canonicalName or scientific name in case its null 828 */ 829 @Nullable 830 @JsonIgnore 831 public String getCanonicalOrScientificName() { 832 return canonicalName == null ? scientificName : canonicalName; 833 } 834 835 /** 836 * A URI link or reference to the source of this record, the record's "homepage". 837 * <blockquote> 838 * <p> 839 * <i>Example:</i> https://www.catalogueoflife.org/data/taxon/4R5YN 840 * </p> 841 * </blockquote> 842 * 843 * @return the link 844 */ 845 @Schema(description = "A URI link or reference to the source of the record, the record's “homepage”.") 846 @Nullable 847 public URI getReferences() { 848 return references; 849 } 850 851 public void setReferences(URI references) { 852 this.references = references; 853 } 854 855 @Override 856 public String getHigherRank(Rank rank) { 857 return ClassificationUtils.getHigherRank(this, rank); 858 } 859 860 @Override 861 public Integer getHigherRankKey(Rank rank) { 862 return ClassificationUtils.getHigherRankKey(this, rank); 863 } 864 865 /** 866 * An ordered map with entries for all higher Linnean ranks down to the actual direct parent of this usage. 867 * The map starts with the highest rank, e.g. the kingdom and maps the name usage key to its canonical name. 868 * The name usage itself is never included, even though a higher rank might point to the usage itself. 869 * 870 * @return map of higher ranks 871 */ 872 @NotNull 873 @JsonIgnore 874 public LinkedHashMap<Integer, String> getHigherClassificationMap() { 875 return ClassificationUtils.getHigherClassificationMap(this, key, parentKey, parent); 876 } 877 878 /** 879 * The original taxonID of the name usage as found in the source. 880 * For backbone taxa and name usages with an origin different to SOURCE this is null. 881 */ 882 @Schema(description = "The original taxonID of the name usage as found in the source.\n\n" + 883 "For backbone taxa and name usages with an origin different to SOURCE this is null.") 884 @Nullable 885 public String getTaxonID() { 886 return taxonID; 887 } 888 889 /** 890 * The taxonomic status of the name usage. 891 * Can be null, but for all synonyms with an accepted name usage it is guaranteed to exist. 892 * 893 * @return the taxonomicStatus, can be null 894 */ 895 @Schema(description = "The taxonomic status of the name usage.\n\n" + 896 "Can be null, but for all synonyms with an accepted name usage it is guaranteed to exist.") 897 @Nullable 898 public TaxonomicStatus getTaxonomicStatus() { 899 return taxonomicStatus; 900 } 901 902 /** 903 * @param taxonomicStatus the taxonomicStatus to set 904 */ 905 public void setTaxonomicStatus(TaxonomicStatus taxonomicStatus) { 906 this.taxonomicStatus = taxonomicStatus; 907 } 908 909 /** 910 * The interpreted dc:modified from the verbatim source data. 911 * Ideally indicating when a record was last modified in the source. 912 */ 913 @Schema(description = "The interpreted dc:modified from the verbatim source data, ideally indicating when a record " + 914 "was last modified in the source.") 915 @Nullable 916 public Date getModified() { 917 return modified; 918 } 919 920 public void setModified(Date modified) { 921 this.modified = modified; 922 } 923 924 /** 925 * The date this record was deleted. 926 * Logical deletions only occur for backbone usages! 927 */ 928 @Schema(description = "The date this record was deleted.\n\n" + 929 "*Only backbone name usages are soft-deleted.*") 930 @Nullable 931 public Date getDeleted() { 932 return deleted; 933 } 934 935 public void setDeleted(Date deleted) { 936 this.deleted = deleted; 937 } 938 939 /** 940 * The date this record was last crawled during clb indexing. 941 */ 942 @Schema(description = "The date this record was last crawled (downloaded from the source) during Checklistbank indexing.") 943 @Nullable 944 public Date getLastCrawled() { 945 return lastCrawled; 946 } 947 948 public void setLastCrawled(Date lastCrawled) { 949 this.lastCrawled = lastCrawled; 950 } 951 952 /** 953 * The date this record was last interpreted during indexing. 954 * This includes matching to the backbone. 955 */ 956 @Schema(description = "The date this record was last interpreted during indexing. This includes matching to the backbone.") 957 @Nullable 958 public Date getLastInterpreted() { 959 return lastInterpreted; 960 } 961 962 public void setLastInterpreted(Date lastInterpreted) { 963 this.lastInterpreted = lastInterpreted; 964 } 965 966 @Schema(description = "Data quality issues found during Checklistbank interpretation.") 967 @NotNull 968 public Set<NameUsageIssue> getIssues() { 969 return issues; 970 } 971 972 public void setIssues(Set<NameUsageIssue> issues) { 973 Objects.requireNonNull(issues, "Issues cannot be null"); 974 this.issues = issues.isEmpty() ? EnumSet.noneOf(NameUsageIssue.class) : EnumSet.copyOf(issues); 975 } 976 977 public void addIssue(NameUsageIssue issue) { 978 Objects.requireNonNull(issue, "Issue needs to be specified"); 979 this.issues.add(issue); 980 } 981 982 @JsonIgnore 983 public boolean isNub() { 984 return datasetKey.equals(Constants.NUB_DATASET_KEY); 985 } 986 987 /** 988 * True for pro parte synonyms with multiple accepted usages. 989 * 990 * @return true if proParte, false otherwise 991 */ 992 @JsonIgnore 993 public boolean isProParte() { 994 return proParteKey != null; 995 } 996 997 /** 998 * Convenience method using the taxonomicStatus field. 999 * @return true if it's a synonym 1000 */ 1001 @JsonIgnore 1002 public boolean isSynonym() { 1003 return taxonomicStatus != null && taxonomicStatus.isSynonym(); 1004 } 1005 1006 public void setTaxonID(String taxonID) { 1007 this.taxonID = taxonID; 1008 } 1009 1010 @Override 1011 public boolean equals(Object o) { 1012 if (this == o) { 1013 return true; 1014 } 1015 if (o == null || getClass() != o.getClass()) { 1016 return false; 1017 } 1018 NameUsage nameUsage = (NameUsage) o; 1019 return numDescendants == nameUsage.numDescendants && 1020 Objects.equals(key, nameUsage.key) && 1021 Objects.equals(nubKey, nameUsage.nubKey) && 1022 Objects.equals(nameKey, nameUsage.nameKey) && 1023 Objects.equals(taxonID, nameUsage.taxonID) && 1024 Objects.equals(kingdom, nameUsage.kingdom) && 1025 Objects.equals(phylum, nameUsage.phylum) && 1026 Objects.equals(clazz, nameUsage.clazz) && 1027 Objects.equals(order, nameUsage.order) && 1028 Objects.equals(family, nameUsage.family) && 1029 Objects.equals(genus, nameUsage.genus) && 1030 Objects.equals(subgenus, nameUsage.subgenus) && 1031 Objects.equals(species, nameUsage.species) && 1032 Objects.equals(kingdomKey, nameUsage.kingdomKey) && 1033 Objects.equals(phylumKey, nameUsage.phylumKey) && 1034 Objects.equals(classKey, nameUsage.classKey) && 1035 Objects.equals(orderKey, nameUsage.orderKey) && 1036 Objects.equals(familyKey, nameUsage.familyKey) && 1037 Objects.equals(genusKey, nameUsage.genusKey) && 1038 Objects.equals(subgenusKey, nameUsage.subgenusKey) && 1039 Objects.equals(speciesKey, nameUsage.speciesKey) && 1040 Objects.equals(datasetKey, nameUsage.datasetKey) && 1041 Objects.equals(constituentKey, nameUsage.constituentKey) && 1042 Objects.equals(parentKey, nameUsage.parentKey) && 1043 Objects.equals(parent, nameUsage.parent) && 1044 Objects.equals(proParteKey, nameUsage.proParteKey) && 1045 Objects.equals(acceptedKey, nameUsage.acceptedKey) && 1046 Objects.equals(accepted, nameUsage.accepted) && 1047 Objects.equals(basionymKey, nameUsage.basionymKey) && 1048 Objects.equals(basionym, nameUsage.basionym) && 1049 Objects.equals(scientificName, nameUsage.scientificName) && 1050 Objects.equals(canonicalName, nameUsage.canonicalName) && 1051 Objects.equals(vernacularName, nameUsage.vernacularName) && 1052 Objects.equals(authorship, nameUsage.authorship) && 1053 nameType == nameUsage.nameType && 1054 rank == nameUsage.rank && 1055 origin == nameUsage.origin && 1056 taxonomicStatus == nameUsage.taxonomicStatus && 1057 Objects.equals(nomenclaturalStatus, nameUsage.nomenclaturalStatus) && 1058 Objects.equals(remarks, nameUsage.remarks) && 1059 Objects.equals(publishedIn, nameUsage.publishedIn) && 1060 Objects.equals(accordingTo, nameUsage.accordingTo) && 1061 Objects.equals(references, nameUsage.references) && 1062 Objects.equals(modified, nameUsage.modified) && 1063 Objects.equals(deleted, nameUsage.deleted) && 1064 Objects.equals(lastCrawled, nameUsage.lastCrawled) && 1065 Objects.equals(lastInterpreted, nameUsage.lastInterpreted) && 1066 Objects.equals(issues, nameUsage.issues); 1067 } 1068 1069 @Override 1070 public int hashCode() { 1071 return Objects 1072 .hash(key, nubKey, nameKey, taxonID, kingdom, phylum, clazz, order, family, genus, subgenus, 1073 species, kingdomKey, phylumKey, classKey, orderKey, familyKey, genusKey, subgenusKey, 1074 speciesKey, datasetKey, constituentKey, parentKey, parent, proParteKey, acceptedKey, 1075 accepted, basionymKey, basionym, scientificName, canonicalName, vernacularName, 1076 authorship, nameType, rank, origin, taxonomicStatus, nomenclaturalStatus, remarks, 1077 publishedIn, accordingTo, numDescendants, references, modified, deleted, lastCrawled, 1078 lastInterpreted, issues); 1079 } 1080 1081 @Override 1082 public String toString() { 1083 return new StringJoiner(", ", NameUsage.class.getSimpleName() + "[", "]") 1084 .add("key=" + key) 1085 .add("nubKey=" + nubKey) 1086 .add("nameKey=" + nameKey) 1087 .add("taxonID='" + taxonID + "'") 1088 .add("sourceTaxonKey=" + sourceTaxonKey) 1089 .add("kingdom='" + kingdom + "'") 1090 .add("phylum='" + phylum + "'") 1091 .add("clazz='" + clazz + "'") 1092 .add("order='" + order + "'") 1093 .add("family='" + family + "'") 1094 .add("genus='" + genus + "'") 1095 .add("subgenus='" + subgenus + "'") 1096 .add("species='" + species + "'") 1097 .add("kingdomKey=" + kingdomKey) 1098 .add("phylumKey=" + phylumKey) 1099 .add("classKey=" + classKey) 1100 .add("orderKey=" + orderKey) 1101 .add("familyKey=" + familyKey) 1102 .add("genusKey=" + genusKey) 1103 .add("subgenusKey=" + subgenusKey) 1104 .add("speciesKey=" + speciesKey) 1105 .add("datasetKey=" + datasetKey) 1106 .add("constituentKey=" + constituentKey) 1107 .add("parentKey=" + parentKey) 1108 .add("parent='" + parent + "'") 1109 .add("proParteKey=" + proParteKey) 1110 .add("acceptedKey=" + acceptedKey) 1111 .add("accepted='" + accepted + "'") 1112 .add("basionymKey=" + basionymKey) 1113 .add("basionym='" + basionym + "'") 1114 .add("scientificName='" + scientificName + "'") 1115 .add("canonicalName='" + canonicalName + "'") 1116 .add("vernacularName='" + vernacularName + "'") 1117 .add("authorship='" + authorship + "'") 1118 .add("nameType=" + nameType) 1119 .add("rank=" + rank) 1120 .add("origin=" + origin) 1121 .add("taxonomicStatus=" + taxonomicStatus) 1122 .add("nomenclaturalStatus=" + nomenclaturalStatus) 1123 .add("remarks='" + remarks + "'") 1124 .add("publishedIn='" + publishedIn + "'") 1125 .add("accordingTo='" + accordingTo + "'") 1126 .add("numDescendants=" + numDescendants) 1127 .add("references=" + references) 1128 .add("modified=" + modified) 1129 .add("deleted=" + deleted) 1130 .add("lastCrawled=" + lastCrawled) 1131 .add("lastInterpreted=" + lastInterpreted) 1132 .add("issues=" + issues) 1133 .toString(); 1134 } 1135}