001/*
002 * Copyright 2021 Global Biodiversity Information Facility (GBIF)
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package org.gbif.dwc.terms;
017
018import java.io.Serializable;
019import java.net.URI;
020import java.util.ArrayList;
021import java.util.List;
022
023public enum GbifTerm implements Term, AlternativeNames, Serializable {
024  // row types
025
026  /**
027   * The <a href="http://rs.gbif.org/terms/1.0/Description">GBIF Taxon Description</a>
028   * extension row type.
029   */
030  Description(GbifTerm.GROUP_ROW_TYPE),
031
032  /**
033   * The <a href="http://rs.gbif.org/terms/1.0/Distribution">GBIF Species Distribution</a>
034   * extension row type.
035   */
036  Distribution(GbifTerm.GROUP_ROW_TYPE),
037
038  /**
039   * The <a href="http://rs.gbif.org/terms/1.0/Identifier">GBIF Alternative Identifiers</a>
040   * extension row type.
041   */
042  Identifier(GbifTerm.GROUP_ROW_TYPE),
043
044  /**
045   * The deprecated <a href="http://rs.gbif.org/terms/1.0/Image">GBIF Simple Images</a>
046   * extension row type.
047   */
048  Image(GbifTerm.GROUP_ROW_TYPE, "Images"),
049
050  /**
051   * The <a href="http://rs.gbif.org/terms/1.0/References">GBIF Literature References</a>
052   * extension row type.
053   */
054  Reference(GbifTerm.GROUP_ROW_TYPE, "References"),
055
056  /**
057   * The <a href="http://rs.gbif.org/terms/1.0/SpeciesProfile">GBIF Species Profile</a>
058   * extension row type.
059   */
060  SpeciesProfile(GbifTerm.GROUP_ROW_TYPE, "SpeciesMiniProfile", "SpeciesInfo", "SpeciesData", "SpeciesFactsheet"),
061
062  /**
063   * The <a href="http://rs.gbif.org/terms/1.0/TypesAndSpecimen">GBIF Types and Specimen</a>
064   * extension row type.
065   */
066  TypesAndSpecimen(GbifTerm.GROUP_ROW_TYPE, "Specimen", "Types", "TypeDesignation"),
067
068  /**
069   * The <a href="http://rs.gbif.org/terms/1.0/VernacularNames">GBIF Vernacular Names</a>
070   * extension row type.
071   */
072  VernacularName(GbifTerm.GROUP_ROW_TYPE, "VernacularNames", "Vernacular", "Vernaculars"),
073
074  /**
075   * The <a href="http://rs.gbif.org/terms/1.0/Multimedia">GBIF Simple Multimedia</a>
076   * extension row type.
077   */
078  Multimedia(GbifTerm.GROUP_ROW_TYPE),
079
080  /**
081   * The UUID key for the dataset registered in GBIF.
082   */
083  datasetKey(GbifTerm.GROUP_DATASET),
084
085  /**
086   * The ISO 3166 2-letter code of the country of the organization that publishes the dataset to which the occurrence belongs.
087   */
088  publishingCountry(GbifTerm.GROUP_DATASET),
089
090  /**
091   * Numerical, stable identifier assigned by GBIF to an Occurrence record.
092   */
093  gbifID(DwcTerm.GROUP_OCCURRENCE),
094
095  /**
096   * Timestamp of the last time the record was (re)interpreted by GBIF.
097   */
098  lastInterpreted(DwcTerm.GROUP_OCCURRENCE),
099
100  /**
101   * The uncertainty radius for the latitude and longitude in decimal degrees.
102   */
103  @Deprecated
104  coordinateAccuracy(DwcTerm.GROUP_OCCURRENCE),
105
106  /**
107   * Elevation in metres above sea level (altitude).
108   * <p>
109   * The elevation is the absolute vertical position of the observed location (z-coordinate).
110   * If depth is given or not will not impact the 3-dimensional position.
111   * For example a location 100m below the surface of a lake in 2000m altitude has a depth of 100 and
112   * an elevation of 1900.
113   * </p>
114   * <p>
115   * If minimum and maximum values are given the elevation is calculated using the equation:
116   * <code>(minimumElevationInMeters + maximumElevationInMeters) / 2</code>.
117   * For consistency and ease of use GBIF decided to always use a value in metres plus its accuracy instead of
118   * min/max values which are sometimes used in Darwin Core. See also depth & distanceAboveSurface.
119   * </p>
120   */
121  elevation(DwcTerm.GROUP_LOCATION),
122
123  /**
124   * Elevation accuracy is the uncertainty for the elevation in metres.
125   * <p>
126   * The elevation accuracy is calculated using the equation: <code>(maximumElevationInMeters - minimumElevationInMeters) / 2</code>
127   * in case a minimum and maximum verbatim value is given.
128   * </p>
129   */
130  elevationAccuracy(DwcTerm.GROUP_LOCATION),
131
132  /**
133   * Depth in metres below the surface.
134   * <p>
135   * Complimentary and relative to elevation, depth indicates the distance to the earth surface, whether that is water
136   * or ground.
137   * For example a location 100m below the surface of a lake in 2000m altitude has a depth of 100 and
138   * an elevation of 1900.
139   * </p>
140   * <p>
141   * The depth is calculated using the equation: <code>(minimumDepthInMeters + maximumDepthInMeters) / 2</code>.
142   * For consistency and ease of use GBIF decided to always use a value in meters plus it's accuracy instead of
143   * min/max values which are sometimes used in Darwin Core. See also elevation & distanceAboveSurface.
144   * </p>
145   */
146  depth(DwcTerm.GROUP_LOCATION),
147
148  /**
149   * Depth accuracy is the uncertainty for the depth in metres.
150   * <p>
151   * The depth accuracy is calculated using the equation: <code>(maximumDepthInMeters - minimumDepthInMeters) / 2</code>
152   * in case a minimum and maximum verbatim value is given.
153   * </p>
154   */
155  depthAccuracy(DwcTerm.GROUP_LOCATION),
156
157  /**
158   * Replaced by Darwin Core terms <a href="http://rs.tdwg.org/dwc/terms/minimumDistanceAboveSurfaceInMeters">dwc:minimumDistanceAboveSurfaceInMeters</a>
159   * and <a href="http://rs.tdwg.org/dwc/terms/maximumDistanceAboveSurfaceInMeters">dwc:maximumDistanceAboveSurfaceInMeters</a>.
160   */
161  @Deprecated
162  distanceAboveSurface(DwcTerm.GROUP_LOCATION),
163
164  /**
165   * Replaced by Darwin Core terms <a href="http://rs.tdwg.org/dwc/terms/minimumDistanceAboveSurfaceInMeters">dwc:minimumDistanceAboveSurfaceInMeters</a>
166   * and <a href="http://rs.tdwg.org/dwc/terms/maximumDistanceAboveSurfaceInMeters">dwc:maximumDistanceAboveSurfaceInMeters</a>.
167   */
168  @Deprecated
169  distanceAboveSurfaceAccuracy(DwcTerm.GROUP_LOCATION),
170
171  /**
172   * The distance in metres from a known centroid, e.g. a country centroid.
173   */
174  distanceFromCentroidInMeters(DwcTerm.GROUP_LOCATION),
175
176  /**
177   * Any issue found during processing and interpretation or the record.
178   * See <a href="https://gbif.github.io/gbif-api/apidocs/org/gbif/api/vocabulary/OccurrenceIssue.html">OccurrenceIssue enumeration</a> for possible values.
179   */
180  issue(DwcTerm.GROUP_OCCURRENCE),
181
182  /**
183   * The media type given as Dublin Core type values, in particular StillImage, MovingImage or Sound.
184   */
185  mediaType(DwcTerm.GROUP_OCCURRENCE),
186
187  // experimental Occurrence properties
188  infraspecificMarker(DwcTerm.GROUP_OCCURRENCE),
189
190  // Types and Specimen checklist extension
191  typeDesignatedBy(DwcTerm.GROUP_OCCURRENCE),
192  typeDesignationType(DwcTerm.GROUP_OCCURRENCE),
193
194  /**
195   * Boolean indicating that a valid latitude and longitude exists.
196   * Even if existing it might still have issues, see hasGeospatialIssues and issue.
197   */
198  hasCoordinate(DwcTerm.GROUP_OCCURRENCE),
199
200  /**
201   * Boolean indicating that some spatial validation rule has not passed.
202   * Primarily used to indicate that the record should not be displayed on a map.
203   */
204  hasGeospatialIssues(DwcTerm.GROUP_OCCURRENCE),
205
206  /**
207   * The GBIF backbone key.
208   * <p>
209   * The best matching, accepted GBIF backbone name usage representing this occurrence.
210   * In case the verbatim scientific name and its classification can only be matched to a higher rank this will
211   * represent the lowest matching rank. In the worst case this could just be for example Animalia.
212   * </p>
213   * <p>
214   * In contrast dwc:taxonID is only used for the source ids similar to occurrenceID
215   * </p>
216   */
217  taxonKey(DwcTerm.GROUP_TAXON),
218
219
220  /**
221   * The GBIF backbone key of the accepted taxon key.
222   */
223  acceptedTaxonKey(DwcTerm.GROUP_TAXON),
224
225  /**
226   * The key to the accepted kingdom in the GBIF backbone.
227   */
228  kingdomKey(DwcTerm.GROUP_TAXON),
229
230  /**
231   * The key to the accepted phylum in the GBIF backbone.
232   */
233  phylumKey(DwcTerm.GROUP_TAXON),
234
235  /**
236   * The key to the accepted class in the GBIF backbone.
237   */
238  classKey(DwcTerm.GROUP_TAXON),
239
240  /**
241   * The key to the accepted order in the GBIF backbone.
242   */
243  orderKey(DwcTerm.GROUP_TAXON),
244
245  /**
246   * The key to the accepted family in the GBIF backbone.
247   */
248  familyKey(DwcTerm.GROUP_TAXON),
249
250  /**
251   * The key to the accepted genus in the GBIF backbone.
252   */
253  genusKey(DwcTerm.GROUP_TAXON),
254
255  /**
256   * The key to the accepted subgenus in the GBIF backbone.
257   */
258  subgenusKey(DwcTerm.GROUP_TAXON),
259
260  /**
261   * The backbone key to the accepted species.
262   * In case the taxonKey is of a higher rank than species (e.g. genus) speciesKey is null.
263   * In case taxonKey represents an infraspecific taxon the speciesKey points to the species
264   * the infraspecies is classified as. In case of taxonKey being a species the speciesKey is the same.
265   */
266  speciesKey(DwcTerm.GROUP_TAXON),
267
268  /**
269   * The canonical name without authorship of the accepted species.
270   */
271  species(DwcTerm.GROUP_TAXON),
272
273  // experimental Taxon properties
274  canonicalName(DwcTerm.GROUP_TAXON),
275  nameType(DwcTerm.GROUP_TAXON),
276
277  /**
278   * The scientific name the type associated acceptedNubKey.
279   */
280  acceptedScientificName(DwcTerm.GROUP_TAXON),
281
282  /**
283   * Scientific name as provided by the source.
284   */
285  verbatimScientificName(DwcTerm.GROUP_TAXON),
286
287  /**
288   * The scientific name the type status of this specimen applies to.
289   * Term proposed in Darwin Core, but not yet ratified.
290   */
291  typifiedName(DwcTerm.GROUP_IDENTIFICATION),
292
293  /**
294   * The kind of protocol used when the record was last crawled by GBIF.
295   * See <a href="http://gbif.github.io/gbif-api/apidocs/org/gbif/api/vocabulary/EndpointType.html">EndpointType enumeration</a> for possible values.
296   */
297  protocol(GbifTerm.GROUP_CRAWLING),
298
299  /**
300   * The date this record was last parsed from raw xml/json into a verbatim GBIF record.
301   */
302  lastParsed(GbifTerm.GROUP_CRAWLING),
303
304  /**
305   * The date this record was last crawled/harvested by GBIF from the endpoint.
306   */
307  lastCrawled(GbifTerm.GROUP_CRAWLING),
308
309  // Species Profile checklist extension
310  isMarine(GbifTerm.GROUP_SPECIES_PROFILE_EXTENSION),
311  isTerrestrial(GbifTerm.GROUP_SPECIES_PROFILE_EXTENSION),
312  isFreshwater(GbifTerm.GROUP_SPECIES_PROFILE_EXTENSION),
313  isHybrid(GbifTerm.GROUP_SPECIES_PROFILE_EXTENSION),
314  isExtinct(GbifTerm.GROUP_SPECIES_PROFILE_EXTENSION),
315  livingPeriod(GbifTerm.GROUP_SPECIES_PROFILE_EXTENSION, "timePeriod"),
316  lifeForm(GbifTerm.GROUP_SPECIES_PROFILE_EXTENSION),
317  ageInDays(GbifTerm.GROUP_SPECIES_PROFILE_EXTENSION),
318  sizeInMillimeter(GbifTerm.GROUP_SPECIES_PROFILE_EXTENSION),
319  massInGram(GbifTerm.GROUP_SPECIES_PROFILE_EXTENSION, "weightInGram"),
320
321  // Vernacular Name checklist extension
322  organismPart(GbifTerm.GROUP_VERNACULAR_NAME_EXTENSION),
323  isPlural(GbifTerm.GROUP_VERNACULAR_NAME_EXTENSION),
324  isPreferredName(GbifTerm.GROUP_VERNACULAR_NAME_EXTENSION),
325
326  // Distribution checklist extension
327  appendixCITES(GbifTerm.GROUP_SPECIES_DISTRIBUTION_EXTENSION),
328  numberOfOccurrences(GbifTerm.GROUP_SPECIES_DISTRIBUTION_EXTENSION),
329
330  /** Boolean indicating if the publishing country is different to the location country. */
331  repatriated(DwcTerm.GROUP_OCCURRENCE),
332
333  /** Calculated relative organism quantity, based on organism and sample measure types */
334  relativeOrganismQuantity(DwcTerm.GROUP_MATERIAL_SAMPLE),
335
336  projectId(DwcTerm.GROUP_OCCURRENCE),
337
338  /** Flag occurrence when associatedSequences/extension exists */
339  isSequenced(DwcTerm.GROUP_OCCURRENCE),
340
341  /** GBIF region based on country code */
342  gbifRegion(DwcTerm.GROUP_LOCATION),
343
344  /** GBIF region based on publishing country code */
345  publishedByGbifRegion(DwcTerm.GROUP_LOCATION);
346
347  private static final String PREFIX = "gbif";
348  private static final String NS = "http://rs.gbif.org/terms/1.0/";
349  private static final URI NS_URI = URI.create(NS);
350
351  public static final String GROUP_CRAWLING = "Crawling";
352  public static final String GROUP_DATASET = "Dataset";
353  public static final String GROUP_ROW_TYPE = "RowType";
354  public static final String GROUP_SPECIES_DISTRIBUTION_EXTENSION = "SpeciesDistribution";
355  public static final String GROUP_SPECIES_PROFILE_EXTENSION = "SpeciesProfile";
356  public static final String GROUP_VERNACULAR_NAME_EXTENSION = "VernacularName";
357
358  /**
359   * Lists all GBIF term groups.
360   */
361  public static final String[] GROUPS = {GROUP_CRAWLING, GROUP_DATASET, DwcTerm.GROUP_OCCURRENCE, GROUP_ROW_TYPE,
362    GROUP_SPECIES_DISTRIBUTION_EXTENSION, GROUP_SPECIES_PROFILE_EXTENSION, DwcTerm.GROUP_TAXON,
363    GROUP_VERNACULAR_NAME_EXTENSION, DwcTerm.GROUP_LOCATION};
364
365  /**
366   * Lists all GBIF terms in taxon group.
367   */
368  public static final GbifTerm[] TAXONOMIC_TERMS =
369  {GbifTerm.taxonKey, GbifTerm.acceptedTaxonKey, GbifTerm.kingdomKey, GbifTerm.phylumKey, GbifTerm.classKey,
370   GbifTerm.orderKey, GbifTerm.familyKey, GbifTerm.genusKey, GbifTerm.subgenusKey, GbifTerm.speciesKey,
371   GbifTerm.species, GbifTerm.canonicalName, GbifTerm.nameType, GbifTerm.acceptedScientificName,
372   GbifTerm.verbatimScientificName};
373
374  private final String groupName;
375  private final boolean isDeprecated;
376  public final String[] normAlts;
377
378  GbifTerm(String groupName, String... alternatives) {
379    this.groupName = groupName;
380    this.normAlts = alternatives;
381    boolean deprecatedAnnotationPresent = false;
382    try {
383      deprecatedAnnotationPresent = GbifTerm.class.getField(this.name()).isAnnotationPresent(Deprecated.class);
384    } catch (NoSuchFieldException ignore) { }
385    this.isDeprecated = deprecatedAnnotationPresent;
386  }
387
388  /**
389   * The simple term name without a namespace.
390   * For example taxonKey.
391   *
392   * @return simple term name
393   */
394  @Override
395  public String simpleName() {
396    return name();
397  }
398
399  /**
400   * Array of alternative simple names in use for the term.
401   *
402   * @return simple term name
403   */
404  @Override
405  public String[] alternativeNames() {
406    return normAlts;
407  }
408
409  /**
410   * The optional group the term is grouped in.
411   * For example Occurrence, Taxon, etc.
412   */
413  public String getGroup() {
414    return groupName;
415  }
416
417
418  /**
419   * List all terms that belong to a given group.
420   *
421   * @param group the group to list terms for
422   * @return the list of GBIF terms in the given group
423   */
424  public static List<GbifTerm> listByGroup(String group) {
425    List<GbifTerm> terms = new ArrayList<GbifTerm>();
426    for (GbifTerm t : GbifTerm.values()) {
427      if (t.getGroup().equalsIgnoreCase(group)) {
428        terms.add(t);
429      }
430    }
431    return terms;
432  }
433
434  @Override
435  public String toString() {
436    return prefixedName();
437  }
438
439  @Override
440  public boolean isClass() {
441    return Character.isUpperCase(simpleName().charAt(0));
442  }
443
444  @Override
445  public String prefix() {
446    return PREFIX;
447  }
448
449  @Override
450  public URI namespace() {
451    return NS_URI;
452  }
453
454  /**
455   *
456   * @return true if the Term is annotated with @Deprecated.
457   */
458  public boolean isDeprecated(){
459    return isDeprecated;
460  }
461
462}