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.collections; 015 016import com.fasterxml.jackson.annotation.JsonIgnore; 017 018import lombok.EqualsAndHashCode; 019import lombok.ToString; 020 021import org.gbif.api.model.registry.Comment; 022import org.gbif.api.model.registry.Identifier; 023import org.gbif.api.model.registry.LenientEquals; 024import org.gbif.api.model.registry.MachineTag; 025import org.gbif.api.model.registry.PrePersist; 026import org.gbif.api.model.registry.Tag; 027import org.gbif.api.util.HttpURI; 028import org.gbif.api.util.LenientEqualsUtils; 029import org.gbif.api.util.validators.email.ValidEmail; 030import org.gbif.api.vocabulary.collections.Discipline; 031import org.gbif.api.vocabulary.collections.InstitutionGovernance; 032import org.gbif.api.vocabulary.collections.InstitutionType; 033import org.gbif.api.vocabulary.collections.MasterSourceType; 034 035import java.math.BigDecimal; 036import java.net.URI; 037import java.util.ArrayList; 038import java.util.Date; 039import java.util.List; 040import java.util.Objects; 041import java.util.StringJoiner; 042import java.util.UUID; 043 044import javax.annotation.Nullable; 045import javax.validation.Valid; 046import javax.validation.constraints.NotNull; 047import javax.validation.constraints.Size; 048 049import io.swagger.v3.oas.annotations.Hidden; 050import io.swagger.v3.oas.annotations.media.Schema; 051 052/** 053 * The owner or location of collection. Usually an established organization or foundation, 054 * especially one dedicated to education, public service, or culture. 055 */ 056@SuppressWarnings("unused") 057@ToString 058@EqualsAndHashCode 059public class Institution implements CollectionEntity, LenientEquals<Institution> { 060 061 @Schema( 062 description = "Unique GBIF key for the institution.", 063 accessMode = Schema.AccessMode.READ_ONLY) 064 private UUID key; 065 066 @Schema( 067 description = 068 "Code used to identify the institution.\n\n" + "*(NB Not required for updates.)*") 069 @Sourceable(masterSources = MasterSourceType.IH) 070 private String code; 071 072 @Schema( 073 description = "Name or title of the institution.\n\n" + "*(NB Not required for updates.)*") 074 @Sourceable(masterSources = {MasterSourceType.GBIF_REGISTRY, MasterSourceType.IH}) 075 private String name; 076 077 @Schema(description = "Description of the institution.") 078 @Sourceable(masterSources = MasterSourceType.GBIF_REGISTRY) 079 private String description; 080 081 @Schema(description = "Type of the institution, describing its main activity.") 082 private InstitutionType type; 083 084 @Schema(description = "Whether the institution is active or operational.") 085 @Sourceable(masterSources = {MasterSourceType.GBIF_REGISTRY, MasterSourceType.IH}) 086 private boolean active; 087 088 @Schema(description = "Email addresses associated with the institution.") 089 @Sourceable(masterSources = {MasterSourceType.GBIF_REGISTRY, MasterSourceType.IH}) 090 private List<@ValidEmail String> email = new ArrayList<>(); 091 092 @Schema(description = "Telephone numbers associated with the instutiton.") 093 @Sourceable(masterSources = {MasterSourceType.GBIF_REGISTRY, MasterSourceType.IH}) 094 private List<String> phone = new ArrayList<>(); 095 096 @Schema(description = "The institution's WWW homepage.") 097 @Sourceable(masterSources = {MasterSourceType.GBIF_REGISTRY, MasterSourceType.IH}) 098 private URI homepage; 099 100 @Schema(description = "A URL for the main interactive catalogue of the institution.") 101 private URI catalogUrl; 102 103 @Schema(description = "A URL for a machine-readable API for the institution catalogue.") 104 private URI apiUrl; 105 106 @Schema( 107 description = 108 "The mechanisms, processes and relations by which an " 109 + "institution is controlled and directed.") 110 private InstitutionGovernance institutionalGovernance; 111 112 @Schema( 113 description = 114 "The academic or research disciplines to which an " + "institution is dedicated.") 115 private List<Discipline> disciplines = new ArrayList<>(); 116 117 @Schema(description = "The latitude of the institution.") 118 @Sourceable(masterSources = {MasterSourceType.GBIF_REGISTRY, MasterSourceType.IH}) 119 private BigDecimal latitude; 120 121 @Schema(description = "The longitude of the institution.") 122 @Sourceable(masterSources = {MasterSourceType.GBIF_REGISTRY, MasterSourceType.IH}) 123 private BigDecimal longitude; 124 125 @Schema(description = "The postal address of the institution.") 126 @Sourceable(masterSources = MasterSourceType.IH) 127 private Address mailingAddress; 128 129 @Schema(description = "The address of the location of the institution.") 130 @Sourceable(masterSources = {MasterSourceType.GBIF_REGISTRY, MasterSourceType.IH}) 131 private Address address; 132 133 @Schema(description = "Additional names by which the institution is known.") 134 private List<String> additionalNames = new ArrayList<>(); 135 136 @Schema(description = "The date the institution was founded or established.") 137 @Sourceable(masterSources = MasterSourceType.IH) 138 private Integer foundingDate; 139 140 @Schema( 141 description = 142 "A description of the geographic range of the activities " 143 + "performed by the institution.") 144 private String geographicDescription; 145 146 @Schema( 147 description = 148 "A description of the taxonomic range of the activities " 149 + "performed by the institution.") 150 private String taxonomicDescription; 151 152 @Schema(description = "An estimate of the number of specimens hosted by the institution.") 153 private Integer numberSpecimens; 154 155 @Schema(description = "Whether this institution record was imported from *Index Herbariorum*.") 156 @Sourceable(masterSources = MasterSourceType.IH) 157 private boolean indexHerbariorumRecord; 158 159 @Schema(description = "A URL to a logo for the institution.") 160 @Sourceable(masterSources = MasterSourceType.GBIF_REGISTRY) 161 private URI logoUrl; 162 163 @Schema(description = "The CITES permit number for the institution.") 164 private String citesPermitNumber; 165 166 @Schema( 167 description = 168 "The GBIF username of the creator of the institution entity in " + "the GBIF registry.", 169 accessMode = Schema.AccessMode.READ_ONLY) 170 private String createdBy; 171 172 @Schema( 173 description = 174 "The GBIF username of the last user to modify the institution " 175 + "entity in the GBIF registry.", 176 accessMode = Schema.AccessMode.READ_ONLY) 177 private String modifiedBy; 178 179 @Schema( 180 description = 181 "Timestamp of when the institution entity was created in the GBIF " + "registry.", 182 accessMode = Schema.AccessMode.READ_ONLY) 183 private Date created; 184 185 @Schema( 186 description = 187 "Timestamp of when the institution entity was modified in the GBIF " + "registry.", 188 accessMode = Schema.AccessMode.READ_ONLY) 189 private Date modified; 190 191 @Schema( 192 description = 193 "If present, the institution was deleted at this time. " 194 + "It is possible for it to be restored in the future.", 195 accessMode = Schema.AccessMode.READ_ONLY) 196 private Date deleted; 197 198 @Schema( 199 description = "A list of tags associated with this institution.", 200 accessMode = Schema.AccessMode.READ_ONLY) 201 private List<Tag> tags = new ArrayList<>(); 202 203 @Schema( 204 description = "A list of identifiers associated with this institution.", 205 accessMode = Schema.AccessMode.READ_ONLY) 206 @Sourceable(masterSources = MasterSourceType.IH, sourceableParts = "IH_IRN") 207 private List<Identifier> identifiers = new ArrayList<>(); 208 209 @Schema(description = "A list of contact people for this institution.") 210 @Sourceable(masterSources = {MasterSourceType.GBIF_REGISTRY, MasterSourceType.IH}) 211 private List<Contact> contactPersons = new ArrayList<>(); 212 213 @Schema( 214 description = "A list of machine tags associated with this institution.", 215 accessMode = Schema.AccessMode.READ_ONLY) 216 private List<MachineTag> machineTags = new ArrayList<>(); 217 218 @Schema(description = "Alternative codes for this institution.") 219 private List<AlternativeCode> alternativeCodes = new ArrayList<>(); 220 221 @Schema( 222 description = "A list of comments associated with this institution.", 223 accessMode = Schema.AccessMode.READ_ONLY) 224 private List<Comment> comments = new ArrayList<>(); 225 226 @Schema( 227 description = "Mapping of a GRSciColl institution to occurrence records", 228 accessMode = Schema.AccessMode.READ_ONLY) 229 private List<OccurrenceMapping> occurrenceMappings = new ArrayList<>(); 230 231 @Schema(description = "A collection record that replaces this collection.") 232 private UUID replacedBy; 233 234 @Schema( 235 description = 236 "Indicates if the institution was converted to a collection and specifies the UUID key of that collection") 237 private UUID convertedToCollection; 238 239 @Schema(description = "The primary source of this institution record.") 240 private MasterSourceType masterSource; 241 242 @Schema( 243 description = 244 "Information to assist the synchronization of the master source " 245 + "record with the record in the GBIF registry.") 246 private MasterSourceMetadata masterSourceMetadata; 247 248 @Schema(description = "Whether the institution is shown on the NHC portal.") 249 private Boolean displayOnNHCPortal; 250 251 @Schema(description = "An estimate of the number of occurrences linked to the institution.") 252 private Integer occurrenceCount; 253 254 @Schema(description = "An estimate of the number of type specimens linked to the institution.") 255 private Integer typeSpecimenCount; 256 257 /** GBIF unique identifier. */ 258 @Override 259 public UUID getKey() { 260 return key; 261 } 262 263 @Override 264 public void setKey(UUID key) { 265 this.key = key; 266 } 267 268 /** Code used to identify the collection. */ 269 @NotNull(groups = PrePersist.class) 270 @Override 271 public String getCode() { 272 return code; 273 } 274 275 @Override 276 public void setCode(String code) { 277 this.code = code; 278 } 279 280 /** Name or title of an institution. */ 281 @NotNull 282 @Override 283 public String getName() { 284 return name; 285 } 286 287 @Override 288 public void setName(String name) { 289 this.name = name; 290 } 291 292 /** Textual description of institution. */ 293 @Nullable 294 @Size(min = 1) 295 @Override 296 public String getDescription() { 297 return description; 298 } 299 300 @Override 301 public void setDescription(String description) { 302 this.description = description; 303 } 304 305 /** Describes the main activity of an institution. */ 306 public InstitutionType getType() { 307 return type; 308 } 309 310 public void setType(InstitutionType type) { 311 this.type = type; 312 } 313 314 /** Is the institution active/operational?. */ 315 @Override 316 public boolean isActive() { 317 return active; 318 } 319 320 @Override 321 public void setActive(boolean active) { 322 this.active = active; 323 } 324 325 @Override 326 public List<String> getEmail() { 327 return email; 328 } 329 330 @Override 331 public void setEmail(List<String> email) { 332 this.email = email; 333 } 334 335 @Override 336 public List<String> getPhone() { 337 return phone; 338 } 339 340 @Override 341 public void setPhone(List<String> phone) { 342 this.phone = phone; 343 } 344 345 /** URL to the home page of an institution. */ 346 @HttpURI 347 @Nullable 348 public URI getHomepage() { 349 return homepage; 350 } 351 352 public void setHomepage(URI homepage) { 353 this.homepage = homepage; 354 } 355 356 /** URL to the main catalogue of an institution. */ 357 @HttpURI 358 @Nullable 359 public URI getCatalogUrl() { 360 return catalogUrl; 361 } 362 363 public void setCatalogUrl(URI catalogUrl) { 364 this.catalogUrl = catalogUrl; 365 } 366 367 /** Machine-consumable endpoint of an institution and probably its collections. */ 368 @HttpURI 369 @Nullable 370 public URI getApiUrl() { 371 return apiUrl; 372 } 373 374 public void setApiUrl(URI apiUrl) { 375 this.apiUrl = apiUrl; 376 } 377 378 /** Governance nature of an institution. */ 379 public InstitutionGovernance getInstitutionalGovernance() { 380 return institutionalGovernance; 381 } 382 383 public void setInstitutionalGovernance(InstitutionGovernance institutionalGovernance) { 384 this.institutionalGovernance = institutionalGovernance; 385 } 386 387 /** Activities to which an institution is dedicated. */ 388 public List<Discipline> getDisciplines() { 389 return disciplines; 390 } 391 392 public void setDisciplines(List<Discipline> disciplines) { 393 this.disciplines = disciplines; 394 } 395 396 /** Decimal latitude of where this institution is located. */ 397 public BigDecimal getLatitude() { 398 return latitude; 399 } 400 401 public void setLatitude(BigDecimal latitude) { 402 this.latitude = latitude; 403 } 404 405 /** Decimal longitude of where this institution is located. */ 406 public BigDecimal getLongitude() { 407 return longitude; 408 } 409 410 public void setLongitude(BigDecimal longitude) { 411 this.longitude = longitude; 412 } 413 414 @Nullable 415 @Valid 416 @Override 417 public Address getMailingAddress() { 418 return mailingAddress; 419 } 420 421 @Override 422 public void setMailingAddress(Address mailingAddress) { 423 this.mailingAddress = mailingAddress; 424 } 425 426 @Nullable 427 @Valid 428 @Override 429 public Address getAddress() { 430 return address; 431 } 432 433 @Override 434 public void setAddress(Address address) { 435 this.address = address; 436 } 437 438 /** Alternative names of institution. */ 439 public List<String> getAdditionalNames() { 440 return additionalNames; 441 } 442 443 public void setAdditionalNames(List<String> additionalNames) { 444 this.additionalNames = additionalNames; 445 } 446 447 /** Date when the institution was founded or established. */ 448 public Integer getFoundingDate() { 449 return foundingDate; 450 } 451 452 public void setFoundingDate(Integer foundingDate) { 453 this.foundingDate = foundingDate; 454 } 455 456 /** Geographical coverage of the activities performed by an institution. */ 457 public String getGeographicDescription() { 458 return geographicDescription; 459 } 460 461 public void setGeographicDescription(String geographicDescription) { 462 this.geographicDescription = geographicDescription; 463 } 464 465 /** Taxonomic description of the collections maintained by an institution. */ 466 public String getTaxonomicDescription() { 467 return taxonomicDescription; 468 } 469 470 public void setTaxonomicDescription(String taxonomicDescription) { 471 this.taxonomicDescription = taxonomicDescription; 472 } 473 474 /** Estimated number of specimens hosted by an institution. */ 475 public Integer getNumberSpecimens() { 476 return numberSpecimens; 477 } 478 479 public void setNumberSpecimens(Integer numberSpecimens) { 480 this.numberSpecimens = numberSpecimens; 481 } 482 483 /** Was the institution record imported form Index Herbariorum. */ 484 public boolean isIndexHerbariorumRecord() { 485 return indexHerbariorumRecord; 486 } 487 488 public void setIndexHerbariorumRecord(boolean indexHerbariorumRecord) { 489 this.indexHerbariorumRecord = indexHerbariorumRecord; 490 } 491 492 /** Logo/Image that identifies the institution. */ 493 @HttpURI 494 @Nullable 495 public URI getLogoUrl() { 496 return logoUrl; 497 } 498 499 public void setLogoUrl(URI logoUrl) { 500 this.logoUrl = logoUrl; 501 } 502 503 /** 504 * CITES (see http://ec.europa.eu/environment/cites/info_permits_en.htm) licence given for this 505 * collection. 506 */ 507 public String getCitesPermitNumber() { 508 return citesPermitNumber; 509 } 510 511 public void setCitesPermitNumber(String citesPermitNumber) { 512 this.citesPermitNumber = citesPermitNumber; 513 } 514 515 @Override 516 public String getCreatedBy() { 517 return createdBy; 518 } 519 520 @Override 521 public void setCreatedBy(String createdBy) { 522 this.createdBy = createdBy; 523 } 524 525 @Override 526 public String getModifiedBy() { 527 return modifiedBy; 528 } 529 530 @Override 531 public void setModifiedBy(String modifiedBy) { 532 this.modifiedBy = modifiedBy; 533 } 534 535 @Override 536 public Date getCreated() { 537 return created; 538 } 539 540 @Override 541 public void setCreated(Date created) { 542 this.created = created; 543 } 544 545 @Override 546 public Date getModified() { 547 return modified; 548 } 549 550 @Override 551 public void setModified(Date modified) { 552 this.modified = modified; 553 } 554 555 @Override 556 public Date getDeleted() { 557 return deleted; 558 } 559 560 @Override 561 public void setDeleted(Date deleted) { 562 this.deleted = deleted; 563 } 564 565 @Override 566 public List<Identifier> getIdentifiers() { 567 return identifiers; 568 } 569 570 @Override 571 public void setIdentifiers(List<Identifier> identifiers) { 572 this.identifiers = identifiers; 573 } 574 575 @Override 576 public List<Tag> getTags() { 577 return tags; 578 } 579 580 @Override 581 public void setTags(List<Tag> tags) { 582 this.tags = tags; 583 } 584 585 @Valid 586 @Override 587 public List<Contact> getContactPersons() { 588 return contactPersons; 589 } 590 591 @Override 592 public void setContactPersons(List<Contact> contactPersons) { 593 this.contactPersons = contactPersons; 594 } 595 596 @Override 597 public @NotNull List<MachineTag> getMachineTags() { 598 return machineTags; 599 } 600 601 @Override 602 public void setMachineTags(List<MachineTag> machineTags) { 603 this.machineTags = machineTags; 604 } 605 606 @Override 607 public void addMachineTag(MachineTag machineTag) { 608 this.machineTags.add(machineTag); 609 } 610 611 /** Alternative codes for an institution. */ 612 @Override 613 public List<AlternativeCode> getAlternativeCodes() { 614 return alternativeCodes; 615 } 616 617 @Override 618 public void setAlternativeCodes(List<AlternativeCode> alternativeCodes) { 619 this.alternativeCodes = alternativeCodes; 620 } 621 622 @Override 623 public List<Comment> getComments() { 624 return comments; 625 } 626 627 @Override 628 public void setComments(List<Comment> comments) { 629 this.comments = comments; 630 } 631 632 @Override 633 public List<OccurrenceMapping> getOccurrenceMappings() { 634 return occurrenceMappings; 635 } 636 637 @Override 638 public void setOccurrenceMappings(List<OccurrenceMapping> occurrenceMappings) { 639 this.occurrenceMappings = occurrenceMappings; 640 } 641 642 @Override 643 public UUID getReplacedBy() { 644 return replacedBy; 645 } 646 647 @Override 648 public void setReplacedBy(UUID replacedBy) { 649 this.replacedBy = replacedBy; 650 } 651 652 public UUID getConvertedToCollection() { 653 return convertedToCollection; 654 } 655 656 public void setConvertedToCollection(UUID convertedToCollection) { 657 this.convertedToCollection = convertedToCollection; 658 } 659 660 @Override 661 public MasterSourceType getMasterSource() { 662 return masterSource; 663 } 664 665 @Override 666 public void setMasterSource(MasterSourceType masterSource) { 667 this.masterSource = masterSource; 668 } 669 670 @Override 671 public MasterSourceMetadata getMasterSourceMetadata() { 672 return masterSourceMetadata; 673 } 674 675 @Override 676 public void setMasterSourceMetadata(MasterSourceMetadata masterSourceMetadata) { 677 this.masterSourceMetadata = masterSourceMetadata; 678 } 679 680 @Override 681 public Boolean getDisplayOnNHCPortal() { 682 return displayOnNHCPortal; 683 } 684 685 @Override 686 public void setDisplayOnNHCPortal(Boolean displayOnNHCPortal) { 687 this.displayOnNHCPortal = displayOnNHCPortal; 688 } 689 690 public Integer getOccurrenceCount() { 691 return occurrenceCount; 692 } 693 694 public void setOccurrenceCount(Integer occurrenceCount) { 695 this.occurrenceCount = occurrenceCount; 696 } 697 698 public Integer getTypeSpecimenCount() { 699 return typeSpecimenCount; 700 } 701 702 public void setTypeSpecimenCount(Integer typeSpecimenCount) { 703 this.typeSpecimenCount = typeSpecimenCount; 704 } 705 706 @Hidden 707 @JsonIgnore 708 public String getCountry() { 709 if (address != null && address.getCountry() != null) { 710 return address.getCountry().getIso2LetterCode(); 711 } else if (mailingAddress != null && mailingAddress.getCountry() != null) { 712 return mailingAddress.getCountry().getIso2LetterCode(); 713 } 714 return null; 715 } 716 717 @Hidden 718 @JsonIgnore 719 public String getCity() { 720 if (address != null && address.getCity() != null) { 721 return address.getCity(); 722 } else if (mailingAddress != null && mailingAddress.getCity() != null) { 723 return mailingAddress.getCity(); 724 } 725 return null; 726 } 727 728 @Hidden 729 @JsonIgnore 730 public String getProvince() { 731 if (address != null && address.getProvince() != null) { 732 return address.getProvince(); 733 } else if (mailingAddress != null && mailingAddress.getProvince() != null) { 734 return mailingAddress.getProvince(); 735 } 736 return null; 737 } 738 739 @Override 740 public boolean lenientEquals(Institution other) { 741 if (this == other) { 742 return true; 743 } 744 return active == other.active 745 && indexHerbariorumRecord == other.indexHerbariorumRecord 746 && Objects.equals(key, other.key) 747 && Objects.equals(code, other.code) 748 && Objects.equals(name, other.name) 749 && Objects.equals(description, other.description) 750 && type == other.type 751 && Objects.equals(email, other.email) 752 && Objects.equals(phone, other.phone) 753 && Objects.equals(homepage, other.homepage) 754 && Objects.equals(catalogUrl, other.catalogUrl) 755 && Objects.equals(apiUrl, other.apiUrl) 756 && institutionalGovernance == other.institutionalGovernance 757 && Objects.equals(disciplines, other.disciplines) 758 && Objects.equals(latitude, other.latitude) 759 && Objects.equals(longitude, other.longitude) 760 && LenientEqualsUtils.lenientEquals(mailingAddress, other.mailingAddress) 761 && LenientEqualsUtils.lenientEquals(address, other.address) 762 && Objects.equals(additionalNames, other.additionalNames) 763 && Objects.equals(foundingDate, other.foundingDate) 764 && Objects.equals(geographicDescription, other.geographicDescription) 765 && Objects.equals(numberSpecimens, other.numberSpecimens) 766 && Objects.equals(taxonomicDescription, other.taxonomicDescription) 767 && Objects.equals(logoUrl, other.logoUrl) 768 && Objects.equals(citesPermitNumber, other.citesPermitNumber) 769 && Objects.equals(deleted, other.deleted) 770 && Objects.equals(alternativeCodes, other.alternativeCodes) 771 && Objects.equals(comments, other.comments) 772 && Objects.equals(occurrenceMappings, other.occurrenceMappings) 773 && Objects.equals(replacedBy, other.replacedBy) 774 && Objects.equals(convertedToCollection, other.convertedToCollection) 775 && Objects.equals(masterSource, other.masterSource) 776 && Objects.equals(masterSourceMetadata, other.masterSourceMetadata) 777 && Objects.equals(displayOnNHCPortal, other.displayOnNHCPortal); 778 } 779}