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