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.registry; 015 016import com.fasterxml.jackson.annotation.JsonRawValue; 017 018import com.fasterxml.jackson.core.JsonParser; 019import com.fasterxml.jackson.databind.DeserializationContext; 020import com.fasterxml.jackson.databind.JsonDeserializer; 021 022import com.fasterxml.jackson.databind.JsonNode; 023 024import com.fasterxml.jackson.databind.annotation.JsonDeserialize; 025 026import lombok.Data; 027import lombok.NoArgsConstructor; 028 029import org.gbif.api.annotation.Experimental; 030import org.gbif.api.model.common.DOI; 031import org.gbif.api.model.registry.eml.Collection; 032import org.gbif.api.model.registry.eml.DataDescription; 033import org.gbif.api.model.registry.eml.KeywordCollection; 034import org.gbif.api.model.registry.eml.Project; 035import org.gbif.api.model.registry.eml.SamplingDescription; 036import org.gbif.api.model.registry.eml.TaxonomicCoverages; 037import org.gbif.api.model.registry.eml.curatorial.CuratorialUnitComposite; 038import org.gbif.api.model.registry.eml.geospatial.GeospatialCoverage; 039import org.gbif.api.model.registry.eml.temporal.TemporalCoverage; 040import org.gbif.api.util.HttpURI; 041import org.gbif.api.vocabulary.Country; 042import org.gbif.api.vocabulary.DatasetSubtype; 043import org.gbif.api.vocabulary.DatasetType; 044import org.gbif.api.vocabulary.Language; 045import org.gbif.api.vocabulary.License; 046import org.gbif.api.vocabulary.MaintenanceUpdateFrequency; 047 048import java.io.IOException; 049import java.net.URI; 050import java.util.ArrayList; 051import java.util.Date; 052import java.util.HashSet; 053import java.util.List; 054import java.util.Objects; 055import java.util.Set; 056import java.util.StringJoiner; 057import java.util.UUID; 058 059import jakarta.annotation.Nullable; 060import jakarta.validation.Valid; 061import jakarta.validation.constraints.Min; 062import jakarta.validation.constraints.NotNull; 063import jakarta.validation.constraints.Null; 064import jakarta.validation.constraints.Size; 065 066import io.swagger.v3.oas.annotations.media.Schema; 067 068/** 069 * A GBIF dataset which provides occurrence data, checklist data, sampling event data or metadata. 070 * This Dataset class is covering all the GBIF metadata profile v1.3, but only a few properties are kept in the 071 * database table: 072 * <ul> 073 * <li>key</li> 074 * <li>parentDatasetKey</li> 075 * <li>duplicateOfDatasetKey</li> 076 * <li>version</li> 077 * <li>installationKey</li> 078 * <li>publishingOrganizationKey</li> 079 * <li>publishingOrganizationName</li> 080 * <li>networkKeys</li> 081 * <li>license</li> 082 * <li>maintenanceUpdateFrequency</li> 083 * <li>external</li> 084 * <li>numConstituents</li> 085 * <li>type</li> 086 * <li>subtype</li> 087 * <li>title</li> 088 * <li>alias</li> 089 * <li>abbreviation</li> 090 * <li>description</li> 091 * <li>language</li> 092 * <li>homepage</li> 093 * <li>logoUrl</li> 094 * <li>citation</li> 095 * <li>rights</li> 096 * <li>lockedForAutoUpdate</li> 097 * <li>createdBy</li> 098 * <li>modifiedBy</li> 099 * <li>created</li> 100 * <li>modified</li> 101 * <li>deleted</li> 102 * </ul> 103 * 104 * @see <a href="http://rs.gbif.org/schema/eml-gbif-profile/dev/eml.xsd">GBIF EML Profile XML Schema</a> 105 */ 106@SuppressWarnings({"unused", "LombokSetterMayBeUsed", "LombokGetterMayBeUsed"}) 107public class Dataset 108 implements NetworkEntity, 109 Contactable, 110 Endpointable, 111 MachineTaggable, 112 Taggable, 113 Identifiable, 114 Commentable, 115 LenientEquals<Dataset> { 116 117 @Schema( 118 description = "Unique GBIF key for the dataset. This is used in the" + 119 "GBIF API, but outside GBIF it is best to refer to a dataset by its DOI.", 120 accessMode = Schema.AccessMode.READ_ONLY 121 ) 122 private UUID key; 123 124 @Schema( 125 description = "If set, this dataset is a sub-dataset of the parent." 126 ) 127 private UUID parentDatasetKey; 128 129 @Schema( 130 description = "A dataset of which this dataset is a duplicate. Typically, " + 131 "this means this dataset is an old version of the duplicated dataset, " + 132 "which has replaced this dataset. Therefore **this link is usually found " + 133 "on deleted datasets**." 134 ) 135 private UUID duplicateOfDatasetKey; 136 137 @Schema( 138 description = "The installation providing access to the source dataset.\n\n" + 139 "*(NB Not required for updates.)*" 140 ) 141 private UUID installationKey; 142 143 @Schema( 144 description = "The publishing organization publishing this dataset.\n\n" + 145 "*(NB Not required for updates.)*" 146 ) 147 private UUID publishingOrganizationKey; 148 149 @Schema( 150 description = "The publishing organization name.\n\n" + 151 "*(NB Not required for updates.)*" 152 ) 153 private String publishingOrganizationName; 154 155 @Schema( 156 description = "A list of GBIF Networks to which this dataset belongs." 157 ) 158 private List<UUID> networkKeys; 159 160 @Schema( 161 description = "The primary Digital Object Identifier (DOI) for this dataset.", 162 implementation = String.class, 163 pattern = "(10(?:\\.[0-9]+)+)" + "/(.+)" 164 ) 165 private DOI doi; 166 167 @Schema( 168 description = "The version of the published dataset." 169 ) 170 private String version; 171 172 @Schema( 173 description = "Not currently used." 174 ) 175 private boolean external; 176 177 @Schema( 178 description = "If set, the number of sub-datasets of this parent dataset." 179 ) 180 private int numConstituents; 181 182 @Schema( 183 description = "The primary type of the dataset.\n\n" + 184 "*(NB Not required for updates.)*" 185 ) 186 private DatasetType type; 187 188 @Schema( 189 description = "The sub-type of the dataset." 190 ) 191 private DatasetSubtype subtype; 192 193 @Schema( 194 description = "Concise name of the dataset." 195 ) 196 private String shortName; 197 198 @Schema( 199 description = "The title of the dataset.\n\n" + 200 "*(NB Not required for updates.)*" 201 ) 202 private String title; 203 204 @Schema( 205 description = "An alias for this dataset. Rarely used." 206 ) 207 private String alias; 208 209 @Schema( 210 description = "An abbreviation for this dataset. Rarely used." 211 ) 212 private String abbreviation; 213 214 @Schema( 215 description = "A description of the dataset." 216 ) 217 private String description; 218 219 @Schema( 220 description = "The language of the dataset metadata.\n\n" + 221 "*(NB Not required for updates.)*" 222 ) 223 private Language language = Language.ENGLISH; // sensible default as it is not null 224 225 @Schema( 226 description = "A homepage with further details on the dataset." 227 ) 228 private URI homepage; 229 230 @Schema( 231 description = "A logo for the dataset, accessible over HTTP." 232 ) 233 private URI logoUrl; 234 235 @Schema( 236 description = "The citation recommended by GBIF for use when citing this dataset." 237 ) 238 private Citation citation = new Citation(); 239 240 @Schema( 241 description = "Contacts use to generate a citation." 242 ) 243 private List<CitationContact> contactsCitation = new ArrayList<>(); 244 245 @Schema( 246 description = "Intellectual property rights applied to this dataset.\n\n" + 247 "*Rarely used, see `license` instead.*" 248 ) 249 private String rights; 250 251 @Schema( 252 description = "If true, any new or updated metadata is ignored.\n\n" + 253 "This is generally used when the publisher has technical problems or " + 254 "limitations with their publication system.", 255 accessMode = Schema.AccessMode.READ_ONLY 256 ) 257 private boolean lockedForAutoUpdate; 258 259 @Schema( 260 description = "The GBIF username of the creator of the dataset.", 261 accessMode = Schema.AccessMode.READ_ONLY 262 ) 263 private String createdBy; 264 265 @Schema( 266 description = "The GBIF username of the last user to modify the dataset.", 267 accessMode = Schema.AccessMode.READ_ONLY 268 ) 269 private String modifiedBy; 270 271 @Schema( 272 description = "Timestamp of when the dataset was created.", 273 accessMode = Schema.AccessMode.READ_ONLY 274 ) 275 private Date created; 276 277 @Schema( 278 description = "Timestamp of when the dataset was modified.", 279 accessMode = Schema.AccessMode.READ_ONLY 280 ) 281 private Date modified; 282 283 @Schema( 284 description = "If present, the dataset was deleted at this time. " + 285 "It is possible for it to be restored in the future.", 286 accessMode = Schema.AccessMode.READ_ONLY 287 ) 288 private Date deleted; 289 290 @Schema( 291 description = "A list of contacts associated with this dataset.", 292 accessMode = Schema.AccessMode.READ_ONLY 293 ) 294 private List<Contact> contacts = new ArrayList<>(); 295 296 @Schema( 297 description = "A list of endpoints associated with this dataset.", 298 accessMode = Schema.AccessMode.READ_ONLY 299 ) 300 private List<Endpoint> endpoints = new ArrayList<>(); 301 302 @Schema( 303 description = "A list of machine tags associated with this dataset.", 304 accessMode = Schema.AccessMode.READ_ONLY 305 ) 306 private List<MachineTag> machineTags = new ArrayList<>(); 307 308 @Schema( 309 description = "A list of tags associated with this dataset.", 310 accessMode = Schema.AccessMode.READ_ONLY 311 ) 312 private List<Tag> tags = new ArrayList<>(); 313 314 @Schema( 315 description = "A list of identifiers associated with this dataset.", 316 accessMode = Schema.AccessMode.READ_ONLY 317 ) 318 private List<Identifier> identifiers = new ArrayList<>(); 319 320 @Schema( 321 description = "A list of comments associated with this dataset.", 322 accessMode = Schema.AccessMode.READ_ONLY 323 ) 324 private List<Comment> comments = new ArrayList<>(); 325 326 // EML specific properties which are not persisted on the dataset table! 327 @Schema( 328 description = "Citations retrieved from this dataset's metadata documents.", 329 accessMode = Schema.AccessMode.READ_ONLY 330 ) 331 private List<Citation> bibliographicCitations = new ArrayList<>(); 332 333 @Schema( 334 description = "Curatorial unit information retrieved from this dataset's metadata documents.", 335 accessMode = Schema.AccessMode.READ_ONLY 336 ) 337 private List<CuratorialUnitComposite> curatorialUnits = new ArrayList<>(); 338 339 @Schema( 340 description = "Taxonomic coverage information retrieved from this dataset's metadata documents.", 341 accessMode = Schema.AccessMode.READ_ONLY 342 ) 343 private List<TaxonomicCoverages> taxonomicCoverages = new ArrayList<>(); 344 345 @Schema( 346 description = "Geographic coverage description retrieved from this dataset's metadata documents.", 347 accessMode = Schema.AccessMode.READ_ONLY 348 ) 349 private String geographicCoverageDescription; 350 351 @Schema( 352 description = "Geospatial coverage information retrieved from this dataset's metadata documents.", 353 accessMode = Schema.AccessMode.READ_ONLY 354 ) 355 private List<GeospatialCoverage> geographicCoverages = new ArrayList<>(); 356 357 @Schema( 358 description = "Temporal coverage information retrieved from this dataset's metadata documents.", 359 accessMode = Schema.AccessMode.READ_ONLY 360 ) 361 private List<TemporalCoverage> temporalCoverages = new ArrayList<>(); 362 363 @Schema( 364 description = "Keyword collections retrieved from this dataset's metadata documents.", 365 accessMode = Schema.AccessMode.READ_ONLY 366 ) 367 private List<KeywordCollection> keywordCollections = new ArrayList<>(); 368 369 @Schema( 370 description = "Project information retrieved from this dataset's metadata documents.", 371 accessMode = Schema.AccessMode.READ_ONLY 372 ) 373 private Project project; 374 375 @Schema( 376 description = "Sampling description retrieved from this dataset's metadata documents.", 377 accessMode = Schema.AccessMode.READ_ONLY 378 ) 379 private SamplingDescription samplingDescription; 380 381 @Schema( 382 description = "Country coverage information retrieved from this dataset's metadata documents.", 383 accessMode = Schema.AccessMode.READ_ONLY 384 ) 385 private Set<Country> countryCoverage = new HashSet<>(); 386 387 @Schema( 388 description = "Collection information retrieved from this dataset's metadata documents.", 389 accessMode = Schema.AccessMode.READ_ONLY 390 ) 391 private List<Collection> collections = new ArrayList<>(); 392 393 @Schema( 394 description = "Data description information retrieved from this dataset's metadata documents.", 395 accessMode = Schema.AccessMode.READ_ONLY 396 ) 397 private List<DataDescription> dataDescriptions = new ArrayList<>(); 398 399 @Schema( 400 description = "Data language information retrieved from this dataset's metadata documents.", 401 accessMode = Schema.AccessMode.READ_ONLY 402 ) 403 private Language dataLanguage; 404 405 @Schema( 406 description = "Purpose information retrieved from this dataset's metadata documents.", 407 accessMode = Schema.AccessMode.READ_ONLY 408 ) 409 private String purpose; 410 411 @Schema( 412 description = "An overview of the background and context for the dataset.", 413 accessMode = Schema.AccessMode.READ_ONLY 414 ) 415 private String introduction; 416 417 @Schema( 418 description = "A high level overview of interpretation, structure, and content of the dataset.", 419 accessMode = Schema.AccessMode.READ_ONLY 420 ) 421 private String gettingStarted; 422 423 @Schema( 424 description = "Text that acknowledges funders and other key contributors.", 425 accessMode = Schema.AccessMode.READ_ONLY 426 ) 427 private String acknowledgements; 428 429 @Schema( 430 description = "Additional information retrieved from this dataset's metadata documents.", 431 accessMode = Schema.AccessMode.READ_ONLY 432 ) 433 private String additionalInfo; 434 435 @Schema( 436 description = "The publication date retrieved from this dataset's metadata documents.", 437 accessMode = Schema.AccessMode.READ_ONLY 438 ) 439 private Date pubDate; 440 441 @Schema( 442 description = "The maintenance update frequency retrieved from this dataset's metadata documents.", 443 accessMode = Schema.AccessMode.READ_ONLY 444 ) 445 private MaintenanceUpdateFrequency maintenanceUpdateFrequency; 446 447 @Schema( 448 description = "The maintenance description retrieved from this dataset's metadata documents.", 449 accessMode = Schema.AccessMode.READ_ONLY 450 ) 451 private String maintenanceDescription; 452 453 @Schema( 454 description = "The data and metadata license retrieved from this dataset's metadata documents.", 455 accessMode = Schema.AccessMode.READ_ONLY 456 ) 457 private License license; 458 459 @Schema( 460 description = "Basic metadata of the Darwin Core Archive (DwC-A) associated with this dataset.", 461 accessMode = Schema.AccessMode.READ_ONLY 462 ) 463 private DwcA dwca; 464 465 @Schema( 466 description = "Category of this dataset.", 467 accessMode = Schema.AccessMode.READ_ONLY 468 ) 469 private Set<String> category; 470 471 @Override 472 public UUID getKey() { 473 return key; 474 } 475 476 /** 477 * Persisted in the database table. 478 */ 479 @Override 480 public void setKey(UUID key) { 481 this.key = key; 482 } 483 484 @Nullable 485 public String getVersion() { 486 return version; 487 } 488 489 public void setVersion(String version) { 490 this.version = version; 491 } 492 493 @Override 494 public String getTitle() { 495 return title; 496 } 497 498 /** 499 * Persisted in the database table. 500 */ 501 @Override 502 public void setTitle(String title) { 503 this.title = title; 504 } 505 506 @Override 507 @Nullable 508 public String getDescription() { 509 return description; 510 } 511 512 /** 513 * Persisted in the database table. 514 */ 515 @Override 516 public void setDescription(String description) { 517 this.description = description; 518 } 519 520 @Override 521 public Date getCreated() { 522 return created; 523 } 524 525 /** 526 * Autoassigned in the database table, ignored when persisted. 527 */ 528 @Override 529 public void setCreated(Date created) { 530 this.created = created; 531 } 532 533 @Override 534 public Date getModified() { 535 return modified; 536 } 537 538 /** 539 * Persisted in the database table. 540 */ 541 @Override 542 public void setModified(Date modified) { 543 this.modified = modified; 544 } 545 546 @Override 547 @Nullable 548 public Date getDeleted() { 549 return deleted; 550 } 551 552 /** 553 * Persisted in the database table. 554 */ 555 @Override 556 public void setDeleted(Date deleted) { 557 this.deleted = deleted; 558 } 559 560 @Nullable 561 public UUID getParentDatasetKey() { 562 return parentDatasetKey; 563 } 564 565 /** 566 * Persisted in the database table. 567 */ 568 public void setParentDatasetKey(UUID parentDatasetKey) { 569 this.parentDatasetKey = parentDatasetKey; 570 } 571 572 /** 573 * If a dataset is registered with GBIF through more than one place we'll mark all but one as a duplicate by pointing 574 * it to the canonical dataset. That is done using this field. If it is {@code null} then this is not a known 575 * duplicate. 576 */ 577 @Nullable 578 public UUID getDuplicateOfDatasetKey() { 579 return duplicateOfDatasetKey; 580 } 581 582 /** 583 * Persisted in the database table. 584 */ 585 public void setDuplicateOfDatasetKey(UUID duplicateOfDatasetKey) { 586 this.duplicateOfDatasetKey = duplicateOfDatasetKey; 587 } 588 589 @NotNull 590 public UUID getInstallationKey() { 591 return installationKey; 592 } 593 594 /** 595 * Persisted in the database table. 596 */ 597 public void setInstallationKey(UUID installationKey) { 598 this.installationKey = installationKey; 599 } 600 601 @NotNull 602 public UUID getPublishingOrganizationKey() { 603 return publishingOrganizationKey; 604 } 605 606 /** 607 * Persisted in the database table. 608 */ 609 public void setPublishingOrganizationKey(UUID publishingOrganizationKey) { 610 this.publishingOrganizationKey = publishingOrganizationKey; 611 } 612 613 @Nullable 614 public String getPublishingOrganizationName() { 615 return publishingOrganizationName; 616 } 617 618 public void setPublishingOrganizationName(String publishingOrganizationName) { 619 this.publishingOrganizationName = publishingOrganizationName; 620 } 621 622 /** 623 * Networks in which this dataset is a constituent. 624 */ 625 public List<UUID> getNetworkKeys() { 626 return networkKeys; 627 } 628 629 public void setNetworkKeys(List<UUID> networkKeys) { 630 this.networkKeys = networkKeys; 631 } 632 633 /** 634 * Persisted in the database table. 635 * 636 * @return the frequency with which changes are made to the dataset 637 */ 638 @Nullable 639 public MaintenanceUpdateFrequency getMaintenanceUpdateFrequency() { 640 return maintenanceUpdateFrequency; 641 } 642 /** 643 * Persisted in the database table. 644 */ 645 public void setMaintenanceUpdateFrequency(MaintenanceUpdateFrequency maintenanceUpdateFrequency) { 646 this.maintenanceUpdateFrequency = maintenanceUpdateFrequency; 647 } 648 649 /** 650 * A description of the maintenance frequency of this resource. 651 * 652 * @return the description of the maintenance frequency of this resource 653 */ 654 public String getMaintenanceDescription() { 655 return maintenanceDescription; 656 } 657 658 public void setMaintenanceDescription(String maintenanceDescription) { 659 this.maintenanceDescription = maintenanceDescription; 660 } 661 662 /** 663 * Persisted in the database table. 664 * </br> 665 * Note for backwards compatibility, we cannot apply @NotNull to license. Otherwise existing users of our API 666 * would have to ensure Dataset objects always populate license. 667 * </br> 668 * In the Registry DB, Dataset.license defaults to CC-BY 4.0. Therefore license must be excluded from lenientEquals 669 * method. 670 * 671 * @return the License applied to the dataset 672 * 673 * @see <a href="http://dev.gbif.org/issues/browse/POR-3133">POR-3133</a> 674 */ 675 public License getLicense() { 676 return license; 677 } 678 679 /** 680 * Persisted in the database table. Can be interpreted from EML.intellectualRights using machine readable format: 681 * <pre> 682 * {@code 683 * <intellectualRights> 684 * <para>This work is licensed under a <ulink url="http://creativecommons.org/licenses/by/4.0/legalcode"><citetitle>Creative Commons Attribution (CC-BY) 4.0 License</citetitle></ulink>.</para> 685 * </intellectualRights> 686 * } 687 * </pre> 688 */ 689 public void setLicense(License license) { 690 this.license = license; 691 } 692 693 /** 694 * @return the primary DOI for this dataset regardless if issued by GBIF or publisher 695 */ 696 public DOI getDoi() { 697 return doi; 698 } 699 700 public void setDoi(DOI doi) { 701 this.doi = doi; 702 } 703 704 public boolean isExternal() { 705 return external; 706 } 707 708 /** 709 * Persisted in the database table. 710 */ 711 public void setExternal(boolean external) { 712 this.external = external; 713 } 714 715 @Min(0) 716 public int getNumConstituents() { 717 return numConstituents; 718 } 719 720 /** 721 * Not persisted in the database table, but calculated on the fly. 722 */ 723 public void setNumConstituents(int numConstituents) { 724 this.numConstituents = numConstituents; 725 } 726 727 @NotNull 728 public DatasetType getType() { 729 return type; 730 } 731 732 /** 733 * Persisted in the database table. 734 */ 735 public void setType(DatasetType type) { 736 this.type = type; 737 } 738 739 @Nullable 740 public DatasetSubtype getSubtype() { 741 return subtype; 742 } 743 744 /** 745 * Persisted in the database table. 746 */ 747 public void setSubtype(DatasetSubtype subtype) { 748 this.subtype = subtype; 749 } 750 751 @Nullable 752 public String getShortName() { 753 return shortName; 754 } 755 756 public void setShortName(String shortName) { 757 this.shortName = shortName; 758 } 759 760 /** 761 * TODO: Document what this is 762 */ 763 @Nullable 764 @Size(min = 2, max = 50) 765 public String getAlias() { 766 return alias; 767 } 768 769 /** 770 * Persisted in the database table. 771 */ 772 public void setAlias(String alias) { 773 this.alias = alias; 774 } 775 776 /** 777 * TODO: Document what this is 778 * TODO: are both alias & abbreviation needed? 779 */ 780 @Nullable 781 @Size(min = 1, max = 50) 782 public String getAbbreviation() { 783 return abbreviation; 784 } 785 786 /** 787 * Persisted in the database table. 788 */ 789 public void setAbbreviation(String abbreviation) { 790 this.abbreviation = abbreviation; 791 } 792 793 @NotNull 794 public Language getLanguage() { 795 return language; 796 } 797 798 /** 799 * Persisted in the database table. 800 */ 801 public void setLanguage(Language language) { 802 this.language = language; 803 } 804 805 @HttpURI 806 @Nullable 807 public URI getHomepage() { 808 return homepage; 809 } 810 811 /** 812 * Persisted in the database table. 813 */ 814 public void setHomepage(URI homepage) { 815 this.homepage = homepage; 816 } 817 818 @HttpURI 819 @Nullable 820 public URI getLogoUrl() { 821 return logoUrl; 822 } 823 824 /** 825 * Persisted in the database table. 826 */ 827 public void setLogoUrl(URI logoUrl) { 828 this.logoUrl = logoUrl; 829 } 830 831 /** 832 * The exact form of how to cite this dataset. 833 */ 834 @Nullable 835 @Valid 836 public Citation getCitation() { 837 return citation; 838 } 839 840 /** 841 * Persisted in the database table. 842 */ 843 public void setCitation(Citation citation) { 844 this.citation = citation; 845 } 846 847 /** 848 * A generated list of contacts used in the citation text when it is generated by the GBIF API. 849 */ 850 @Nullable 851 public List<CitationContact> getContactsCitation() { 852 return contactsCitation; 853 } 854 855 public void setContactsCitation(List<CitationContact> contactsCitation) { 856 this.contactsCitation = contactsCitation; 857 } 858 859 /** 860 * Any kind of (copy)rights/IPR statements that apply to the datasets data. 861 */ 862 @Nullable 863 @Size(min = 1) 864 public String getRights() { 865 return rights; 866 } 867 868 /** 869 * Persisted in the database table. 870 */ 871 public void setRights(String rights) { 872 this.rights = rights; 873 } 874 875 public boolean isLockedForAutoUpdate() { 876 return lockedForAutoUpdate; 877 } 878 879 /** 880 * Persisted in the database table. 881 */ 882 public void setLockedForAutoUpdate(boolean lockedForAutoUpdate) { 883 this.lockedForAutoUpdate = lockedForAutoUpdate; 884 } 885 886 @Override 887 public String getCreatedBy() { 888 return createdBy; 889 } 890 891 /** 892 * Persisted in the database table. 893 */ 894 @Override 895 public void setCreatedBy(String createdBy) { 896 this.createdBy = createdBy; 897 } 898 899 @Override 900 public String getModifiedBy() { 901 return modifiedBy; 902 } 903 904 /** 905 * Persisted in the database table. 906 */ 907 @Override 908 public void setModifiedBy(String modifiedBy) { 909 this.modifiedBy = modifiedBy; 910 } 911 912 @Override 913 public List<Contact> getContacts() { 914 return contacts; 915 } 916 917 @Override 918 public void setContacts(List<Contact> contacts) { 919 this.contacts = contacts; 920 } 921 922 @Override 923 public List<Endpoint> getEndpoints() { 924 return endpoints; 925 } 926 927 @Override 928 public void setEndpoints(List<Endpoint> endpoints) { 929 this.endpoints = endpoints; 930 } 931 932 @Override 933 public void addEndpoint(Endpoint endpoint) { 934 endpoints.add(endpoint); 935 } 936 937 @Override 938 public List<MachineTag> getMachineTags() { 939 return machineTags; 940 } 941 942 @Override 943 public void setMachineTags(List<MachineTag> machineTags) { 944 this.machineTags = machineTags; 945 } 946 947 @Override 948 public void addMachineTag(MachineTag machineTag) { 949 machineTags.add(machineTag); 950 } 951 952 @Override 953 public List<Tag> getTags() { 954 return tags; 955 } 956 957 @Override 958 public void setTags(List<Tag> tags) { 959 this.tags = tags; 960 } 961 962 @Override 963 public List<Identifier> getIdentifiers() { 964 return identifiers; 965 } 966 967 @Override 968 public void setIdentifiers(List<Identifier> identifiers) { 969 this.identifiers = identifiers; 970 } 971 972 @Override 973 public List<Comment> getComments() { 974 return comments; 975 } 976 977 @Override 978 public void setComments(List<Comment> comments) { 979 this.comments = comments; 980 } 981 982 public List<Citation> getBibliographicCitations() { 983 return bibliographicCitations; 984 } 985 986 public void setBibliographicCitations(List<Citation> bibliographicCitations) { 987 this.bibliographicCitations = bibliographicCitations; 988 } 989 990 public List<CuratorialUnitComposite> getCuratorialUnits() { 991 return curatorialUnits; 992 } 993 994 public void setCuratorialUnits(List<CuratorialUnitComposite> curatorialUnits) { 995 this.curatorialUnits = curatorialUnits; 996 } 997 998 public List<TaxonomicCoverages> getTaxonomicCoverages() { 999 return taxonomicCoverages; 1000 } 1001 1002 public void setTaxonomicCoverages(List<TaxonomicCoverages> taxonomicCoverages) { 1003 this.taxonomicCoverages = taxonomicCoverages; 1004 } 1005 1006 public String getGeographicCoverageDescription() { 1007 return geographicCoverageDescription; 1008 } 1009 1010 public void setGeographicCoverageDescription(String geographicCoverageDescription) { 1011 this.geographicCoverageDescription = geographicCoverageDescription; 1012 } 1013 1014 public List<GeospatialCoverage> getGeographicCoverages() { 1015 return geographicCoverages; 1016 } 1017 1018 public void setGeographicCoverages(List<GeospatialCoverage> geographicCoverages) { 1019 this.geographicCoverages = geographicCoverages; 1020 } 1021 1022 public List<TemporalCoverage> getTemporalCoverages() { 1023 return temporalCoverages; 1024 } 1025 1026 public void setTemporalCoverages(List<TemporalCoverage> temporalCoverages) { 1027 this.temporalCoverages = temporalCoverages; 1028 } 1029 1030 public List<KeywordCollection> getKeywordCollections() { 1031 return keywordCollections; 1032 } 1033 1034 public void setKeywordCollections(List<KeywordCollection> keywordCollections) { 1035 this.keywordCollections = keywordCollections; 1036 } 1037 1038 public Project getProject() { 1039 return project; 1040 } 1041 1042 public void setProject(Project project) { 1043 this.project = project; 1044 } 1045 1046 public SamplingDescription getSamplingDescription() { 1047 return samplingDescription; 1048 } 1049 1050 public void setSamplingDescription(SamplingDescription samplingDescription) { 1051 this.samplingDescription = samplingDescription; 1052 } 1053 1054 public Set<Country> getCountryCoverage() { 1055 return countryCoverage; 1056 } 1057 1058 public void setCountryCoverage(Set<Country> countryCoverage) { 1059 this.countryCoverage = countryCoverage; 1060 } 1061 1062 public List<Collection> getCollections() { 1063 return collections; 1064 } 1065 1066 public void setCollections(List<Collection> collections) { 1067 this.collections = collections; 1068 } 1069 1070 public List<DataDescription> getDataDescriptions() { 1071 return dataDescriptions; 1072 } 1073 1074 public void setDataDescriptions(List<DataDescription> dataDescriptions) { 1075 this.dataDescriptions = dataDescriptions; 1076 } 1077 1078 public Language getDataLanguage() { 1079 return dataLanguage; 1080 } 1081 1082 public void setDataLanguage(Language dataLanguage) { 1083 this.dataLanguage = dataLanguage; 1084 } 1085 1086 public String getPurpose() { 1087 return purpose; 1088 } 1089 1090 public void setPurpose(String purpose) { 1091 this.purpose = purpose; 1092 } 1093 1094 @Nullable 1095 public String getIntroduction() { 1096 return introduction; 1097 } 1098 1099 public void setIntroduction(String introduction) { 1100 this.introduction = introduction; 1101 } 1102 1103 @Nullable 1104 public String getGettingStarted() { 1105 return gettingStarted; 1106 } 1107 1108 public void setGettingStarted(String gettingStarted) { 1109 this.gettingStarted = gettingStarted; 1110 } 1111 1112 @Nullable 1113 public String getAcknowledgements() { 1114 return acknowledgements; 1115 } 1116 1117 public void setAcknowledgements(String acknowledgements) { 1118 this.acknowledgements = acknowledgements; 1119 } 1120 1121 public String getAdditionalInfo() { 1122 return additionalInfo; 1123 } 1124 1125 public void setAdditionalInfo(String additionalInfo) { 1126 this.additionalInfo = additionalInfo; 1127 } 1128 1129 public Date getPubDate() { 1130 return pubDate; 1131 } 1132 1133 public void setPubDate(Date pubDate) { 1134 this.pubDate = pubDate; 1135 } 1136 1137 @Nullable 1138 @Valid 1139 public DwcA getDwca() { 1140 return dwca; 1141 } 1142 1143 public void setDwca(DwcA dwca) { 1144 this.dwca = dwca; 1145 } 1146 1147 public Set<String> getCategory() { 1148 return category; 1149 } 1150 1151 public void setCategory(Set<String> category) { 1152 this.category = category; 1153 } 1154 1155 @Override 1156 public boolean equals(Object o) { 1157 if (this == o) { 1158 return true; 1159 } 1160 if (o == null || getClass() != o.getClass()) { 1161 return false; 1162 } 1163 Dataset dataset = (Dataset) o; 1164 return external == dataset.external 1165 && numConstituents == dataset.numConstituents 1166 && lockedForAutoUpdate == dataset.lockedForAutoUpdate 1167 && Objects.equals(key, dataset.key) 1168 && Objects.equals(parentDatasetKey, dataset.parentDatasetKey) 1169 && Objects.equals(duplicateOfDatasetKey, dataset.duplicateOfDatasetKey) 1170 && Objects.equals(installationKey, dataset.installationKey) 1171 && Objects.equals(publishingOrganizationKey, dataset.publishingOrganizationKey) 1172 && Objects.equals(publishingOrganizationName, dataset.publishingOrganizationName) 1173 && Objects.equals(networkKeys, dataset.networkKeys) 1174 && Objects.equals(doi, dataset.doi) 1175 && Objects.equals(version, dataset.version) 1176 && type == dataset.type 1177 && subtype == dataset.subtype 1178 && Objects.equals(shortName, dataset.shortName) 1179 && Objects.equals(title, dataset.title) 1180 && Objects.equals(alias, dataset.alias) 1181 && Objects.equals(abbreviation, dataset.abbreviation) 1182 && Objects.equals(description, dataset.description) 1183 && language == dataset.language 1184 && Objects.equals(homepage, dataset.homepage) 1185 && Objects.equals(logoUrl, dataset.logoUrl) 1186 && Objects.equals(citation, dataset.citation) 1187 && Objects.equals(contactsCitation, dataset.contactsCitation) 1188 && Objects.equals(rights, dataset.rights) 1189 && Objects.equals(createdBy, dataset.createdBy) 1190 && Objects.equals(modifiedBy, dataset.modifiedBy) 1191 && Objects.equals(created, dataset.created) 1192 && Objects.equals(modified, dataset.modified) 1193 && Objects.equals(deleted, dataset.deleted) 1194 && Objects.equals(contacts, dataset.contacts) 1195 && Objects.equals(endpoints, dataset.endpoints) 1196 && Objects.equals(machineTags, dataset.machineTags) 1197 && Objects.equals(tags, dataset.tags) 1198 && Objects.equals(identifiers, dataset.identifiers) 1199 && Objects.equals(comments, dataset.comments) 1200 && Objects.equals(bibliographicCitations, dataset.bibliographicCitations) 1201 && Objects.equals(curatorialUnits, dataset.curatorialUnits) 1202 && Objects.equals(taxonomicCoverages, dataset.taxonomicCoverages) 1203 && Objects.equals(geographicCoverageDescription, dataset.geographicCoverageDescription) 1204 && Objects.equals(geographicCoverages, dataset.geographicCoverages) 1205 && Objects.equals(temporalCoverages, dataset.temporalCoverages) 1206 && Objects.equals(keywordCollections, dataset.keywordCollections) 1207 && Objects.equals(project, dataset.project) 1208 && Objects.equals(samplingDescription, dataset.samplingDescription) 1209 && Objects.equals(countryCoverage, dataset.countryCoverage) 1210 && Objects.equals(collections, dataset.collections) 1211 && Objects.equals(dataDescriptions, dataset.dataDescriptions) 1212 && dataLanguage == dataset.dataLanguage 1213 && Objects.equals(purpose, dataset.purpose) 1214 && Objects.equals(introduction, dataset.introduction) 1215 && Objects.equals(gettingStarted, dataset.gettingStarted) 1216 && Objects.equals(acknowledgements, dataset.acknowledgements) 1217 && Objects.equals(additionalInfo, dataset.additionalInfo) 1218 && Objects.equals(pubDate, dataset.pubDate) 1219 && maintenanceUpdateFrequency == dataset.maintenanceUpdateFrequency 1220 && Objects.equals(maintenanceDescription, dataset.maintenanceDescription) 1221 && license == dataset.license 1222 && Objects.equals(dwca, dataset.dwca) 1223 && Objects.equals(category, dataset.category); 1224 } 1225 1226 @Override 1227 public int hashCode() { 1228 return Objects.hash( 1229 key, 1230 parentDatasetKey, 1231 duplicateOfDatasetKey, 1232 installationKey, 1233 publishingOrganizationKey, 1234 publishingOrganizationName, 1235 networkKeys, 1236 doi, 1237 version, 1238 external, 1239 numConstituents, 1240 type, 1241 subtype, 1242 shortName, 1243 title, 1244 alias, 1245 abbreviation, 1246 description, 1247 language, 1248 homepage, 1249 logoUrl, 1250 citation, 1251 contactsCitation, 1252 rights, 1253 lockedForAutoUpdate, 1254 createdBy, 1255 modifiedBy, 1256 created, 1257 modified, 1258 deleted, 1259 contacts, 1260 endpoints, 1261 machineTags, 1262 tags, 1263 identifiers, 1264 comments, 1265 bibliographicCitations, 1266 curatorialUnits, 1267 taxonomicCoverages, 1268 geographicCoverageDescription, 1269 geographicCoverages, 1270 temporalCoverages, 1271 keywordCollections, 1272 project, 1273 samplingDescription, 1274 countryCoverage, 1275 collections, 1276 dataDescriptions, 1277 dataLanguage, 1278 purpose, 1279 introduction, 1280 gettingStarted, 1281 acknowledgements, 1282 additionalInfo, 1283 pubDate, 1284 maintenanceUpdateFrequency, 1285 maintenanceDescription, 1286 license, 1287 dwca, 1288 category); 1289 } 1290 1291 @Override 1292 public String toString() { 1293 return new StringJoiner(", ", Dataset.class.getSimpleName() + "[", "]") 1294 .add("key=" + key) 1295 .add("parentDatasetKey=" + parentDatasetKey) 1296 .add("duplicateOfDatasetKey=" + duplicateOfDatasetKey) 1297 .add("installationKey=" + installationKey) 1298 .add("publishingOrganizationKey=" + publishingOrganizationKey) 1299 .add("publishingOrganizationName=" + publishingOrganizationName) 1300 .add("networkKeys=" + networkKeys) 1301 .add("doi=" + doi) 1302 .add("version='" + version + "'") 1303 .add("external=" + external) 1304 .add("numConstituents=" + numConstituents) 1305 .add("type=" + type) 1306 .add("subtype=" + subtype) 1307 .add("shortName='" + shortName + "'") 1308 .add("title='" + title + "'") 1309 .add("alias='" + alias + "'") 1310 .add("abbreviation='" + abbreviation + "'") 1311 .add("description='" + description + "'") 1312 .add("language=" + language) 1313 .add("homepage=" + homepage) 1314 .add("logoUrl=" + logoUrl) 1315 .add("citation=" + citation) 1316 .add("contactsCitation=" + contactsCitation) 1317 .add("rights='" + rights + "'") 1318 .add("lockedForAutoUpdate=" + lockedForAutoUpdate) 1319 .add("createdBy='" + createdBy + "'") 1320 .add("modifiedBy='" + modifiedBy + "'") 1321 .add("created=" + created) 1322 .add("modified=" + modified) 1323 .add("deleted=" + deleted) 1324 .add("contacts=" + contacts) 1325 .add("endpoints=" + endpoints) 1326 .add("machineTags=" + machineTags) 1327 .add("tags=" + tags) 1328 .add("identifiers=" + identifiers) 1329 .add("comments=" + comments) 1330 .add("bibliographicCitations=" + bibliographicCitations) 1331 .add("curatorialUnits=" + curatorialUnits) 1332 .add("taxonomicCoverages=" + taxonomicCoverages) 1333 .add("geographicCoverageDescription='" + geographicCoverageDescription + "'") 1334 .add("geographicCoverages=" + geographicCoverages) 1335 .add("temporalCoverages=" + temporalCoverages) 1336 .add("keywordCollections=" + keywordCollections) 1337 .add("project=" + project) 1338 .add("samplingDescription=" + samplingDescription) 1339 .add("countryCoverage=" + countryCoverage) 1340 .add("collections=" + collections) 1341 .add("dataDescriptions=" + dataDescriptions) 1342 .add("dataLanguage=" + dataLanguage) 1343 .add("purpose='" + purpose + "'") 1344 .add("introduction='" + introduction + "'") 1345 .add("gettingStarted='" + gettingStarted + "'") 1346 .add("acknowledgements='" + acknowledgements + "'") 1347 .add("additionalInfo='" + additionalInfo + "'") 1348 .add("pubDate=" + pubDate) 1349 .add("maintenanceUpdateFrequency=" + maintenanceUpdateFrequency) 1350 .add("maintenanceDescription='" + maintenanceDescription + "'") 1351 .add("license=" + license) 1352 .add("dwca=" + dwca) 1353 .add("category=" + category) 1354 .toString(); 1355 } 1356 1357 /** 1358 * Only checks the persisted properties, excluding the server controlled fields (key, created, license etc). 1359 * Does not include the nested properties. 1360 */ 1361 @Override 1362 public boolean lenientEquals(Dataset other) { 1363 if (this == other) { 1364 return true; 1365 } 1366 if (other == null) return false; 1367 return Objects.equals(this.parentDatasetKey, other.parentDatasetKey) 1368 && Objects.equals(this.duplicateOfDatasetKey, other.duplicateOfDatasetKey) 1369 && Objects.equals(this.installationKey, other.installationKey) 1370 && Objects.equals(this.publishingOrganizationKey, other.publishingOrganizationKey) 1371 && Objects.equals(this.publishingOrganizationName, other.publishingOrganizationName) 1372 && Objects.equals(this.doi, other.doi) 1373 && Objects.equals(this.external, other.external) 1374 && Objects.equals(this.type, other.type) 1375 && Objects.equals(this.subtype, other.subtype) 1376 && Objects.equals(this.title, other.title) 1377 && Objects.equals(this.alias, other.alias) 1378 && Objects.equals(this.abbreviation, other.abbreviation) 1379 && Objects.equals(this.description, other.description) 1380 && Objects.equals(this.language, other.language) 1381 && Objects.equals(this.homepage, other.homepage) 1382 && Objects.equals(this.logoUrl, other.logoUrl) 1383 && Objects.equals(this.citation, other.citation) 1384 && Objects.equals(this.rights, other.rights) 1385 && Objects.equals(this.lockedForAutoUpdate, other.lockedForAutoUpdate) 1386 && Objects.equals(this.deleted, other.deleted) 1387 && Objects.equals(this.maintenanceUpdateFrequency, other.maintenanceUpdateFrequency) 1388 && Objects.equals(this.maintenanceDescription, other.maintenanceDescription) 1389 && Objects.equals(this.dwca, other.dwca) 1390 && Objects.equals(this.category, other.category); 1391 } 1392 1393 /** 1394 * Metadata of dataset that has been published as a Darwin Core Archive (DwC-A). 1395 */ 1396 @NoArgsConstructor 1397 @Data 1398 public static class DwcA { 1399 @Schema( 1400 description = "This attribute, within the <core>, indicates the specific " + 1401 "type of data being represented in the core data file.**." 1402 ) 1403 private String coreType; 1404 1405 @Schema( 1406 description = "This attribute, within the <extensions>, indicates the specific " + 1407 "type of data being represented in the associated extension data file.**." 1408 ) 1409 private List<String> extensions; 1410 1411 @Schema( 1412 description = "Timestamp of when the dataset DwcA metadata was modified.", 1413 accessMode = Schema.AccessMode.READ_ONLY 1414 ) 1415 @Null(groups = {PrePersist.class}) 1416 private Date modified; 1417 1418 1419 public String getCoreType() { 1420 return coreType; 1421 } 1422 1423 public void setCoreType(String coreType) { 1424 this.coreType = coreType; 1425 } 1426 1427 @Nullable 1428 public List<String> getExtensions() { 1429 return extensions; 1430 } 1431 1432 public void setExtensions(List<String> extensions) { 1433 this.extensions = extensions; 1434 } 1435 1436 @Nullable 1437 public Date getModified() { 1438 return modified; 1439 } 1440 1441 public void setModified(Date modified) { 1442 this.modified = modified; 1443 } 1444 } 1445 1446 /** 1447 * Metadata of dataset that has been published as a <a href="https://specs.frictionlessdata.io/data-package/">DataPackage</a>. 1448 */ 1449 @NoArgsConstructor 1450 @Data 1451 @Experimental 1452 public static class DataPackage { 1453 1454 /** 1455 * Custom deserializer to capture raw JSON string. 1456 */ 1457 public static class RawJsonDeserializer extends JsonDeserializer<String> { 1458 1459 public RawJsonDeserializer() { 1460 // Jackson requires this 1461 } 1462 1463 @Override 1464 public String deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { 1465 JsonNode node = p.readValueAsTree(); 1466 return node.toString(); // store the raw JSON as a string 1467 } 1468 } 1469 1470 @Schema( 1471 description = "The content of the <a href=\"https://specs.frictionlessdata.io/schemas/data-package.json\">datapackage.json</a> file." 1472 ) 1473 @JsonDeserialize(using = RawJsonDeserializer.class) 1474 @JsonRawValue 1475 private String metadata; 1476 1477 @Schema( 1478 description = "Timestamp of when the dataset datapackage metadata was modified.", 1479 accessMode = Schema.AccessMode.READ_ONLY 1480 ) 1481 @Null(groups = {PrePersist.class}) 1482 private Date modified; 1483 1484 1485 @Schema( 1486 description = "Unique GBIF key for the dataset.", 1487 accessMode = Schema.AccessMode.READ_ONLY 1488 ) 1489 private UUID datasetKey; 1490 1491 @Schema( 1492 description = "Unique GBIF key for the dataset endpoint.", 1493 accessMode = Schema.AccessMode.READ_ONLY 1494 ) 1495 private Integer endpointKey; 1496 1497 @NotNull 1498 public String getMetadata() { 1499 return metadata; 1500 } 1501 1502 public void setMetadata(String metadata) { 1503 this.metadata = metadata; 1504 } 1505 1506 @Nullable 1507 public Date getModified() { 1508 return modified; 1509 } 1510 1511 public void setModified(Date modified) { 1512 this.modified = modified; 1513 } 1514 1515 @NotNull 1516 public UUID getDatasetKey() { 1517 return datasetKey; 1518 } 1519 1520 public void setDatasetKey(UUID datasetKey) { 1521 this.datasetKey = datasetKey; 1522 } 1523 1524 @NotNull 1525 public Integer getEndpointKey() { 1526 return endpointKey; 1527 } 1528 1529 public void setEndpointKey(Integer endpointKey) { 1530 this.endpointKey = endpointKey; 1531 } 1532 } 1533}