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