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