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 scientific name the type associated acceptedNubKey.
216   */
217  acceptedScientificName(DwcTerm.GROUP_TAXON),
218
219  /**
220   * Scientific name as provided by the source.
221   */
222  verbatimScientificName(DwcTerm.GROUP_TAXON),
223
224  /**
225   * The scientific name the type status of this specimen applies to.
226   * Term proposed in Darwin Core, but not yet ratified.
227   */
228  typifiedName(DwcTerm.GROUP_IDENTIFICATION),
229
230  /**
231   * The kind of protocol used when the record was last crawled by GBIF.
232   * See <a href="http://gbif.github.io/gbif-api/apidocs/org/gbif/api/vocabulary/EndpointType.html">EndpointType enumeration</a> for possible values.
233   */
234  protocol(GbifTerm.GROUP_CRAWLING),
235
236  /**
237   * The date this record was last parsed from raw xml/json into a verbatim GBIF record.
238   */
239  lastParsed(GbifTerm.GROUP_CRAWLING),
240
241  /**
242   * The date this record was last crawled/harvested by GBIF from the endpoint.
243   */
244  lastCrawled(GbifTerm.GROUP_CRAWLING),
245
246  // Species Profile checklist extension
247  isMarine(GbifTerm.GROUP_SPECIES_PROFILE_EXTENSION),
248  isTerrestrial(GbifTerm.GROUP_SPECIES_PROFILE_EXTENSION),
249  isFreshwater(GbifTerm.GROUP_SPECIES_PROFILE_EXTENSION),
250  isHybrid(GbifTerm.GROUP_SPECIES_PROFILE_EXTENSION),
251  isExtinct(GbifTerm.GROUP_SPECIES_PROFILE_EXTENSION),
252  livingPeriod(GbifTerm.GROUP_SPECIES_PROFILE_EXTENSION, "timePeriod"),
253  lifeForm(GbifTerm.GROUP_SPECIES_PROFILE_EXTENSION),
254  ageInDays(GbifTerm.GROUP_SPECIES_PROFILE_EXTENSION),
255  sizeInMillimeter(GbifTerm.GROUP_SPECIES_PROFILE_EXTENSION),
256  massInGram(GbifTerm.GROUP_SPECIES_PROFILE_EXTENSION, "weightInGram"),
257
258  // Vernacular Name checklist extension
259  organismPart(GbifTerm.GROUP_VERNACULAR_NAME_EXTENSION),
260  isPlural(GbifTerm.GROUP_VERNACULAR_NAME_EXTENSION),
261  isPreferredName(GbifTerm.GROUP_VERNACULAR_NAME_EXTENSION),
262
263  // Distribution checklist extension
264  appendixCITES(GbifTerm.GROUP_SPECIES_DISTRIBUTION_EXTENSION),
265  numberOfOccurrences(GbifTerm.GROUP_SPECIES_DISTRIBUTION_EXTENSION),
266
267  /**
268   * Boolean indicating if the publishing country is different
269   */
270  repatriated(DwcTerm.GROUP_OCCURRENCE),
271
272  // Calculated relative organism quantity, based on organism and sample measure types
273  relativeOrganismQuantity(DwcTerm.GROUP_MATERIAL_SAMPLE),
274
275  // The type for event records
276  @Vocabulary eventType(DwcTerm.GROUP_EVENT);
277
278  private static final String PREFIX = "gbif";
279  private static final String NS = "http://rs.gbif.org/terms/1.0/";
280  private static final URI NS_URI = URI.create(NS);
281
282  public static final String GROUP_CRAWLING = "Crawling";
283  public static final String GROUP_DATASET = "Dataset";
284  public static final String GROUP_ROW_TYPE = "RowType";
285  public static final String GROUP_SPECIES_DISTRIBUTION_EXTENSION = "SpeciesDistribution";
286  public static final String GROUP_SPECIES_PROFILE_EXTENSION = "SpeciesProfile";
287  public static final String GROUP_VERNACULAR_NAME_EXTENSION = "VernacularName";
288
289  /**
290   * Lists all GBIF term groups.
291   */
292  public static final String[] GROUPS = {GROUP_CRAWLING, GROUP_DATASET, DwcTerm.GROUP_OCCURRENCE, GROUP_ROW_TYPE,
293    GROUP_SPECIES_DISTRIBUTION_EXTENSION, GROUP_SPECIES_PROFILE_EXTENSION, DwcTerm.GROUP_TAXON,
294    GROUP_VERNACULAR_NAME_EXTENSION, DwcTerm.GROUP_LOCATION};
295
296  /**
297   * Lists all GBIF terms in taxon group.
298   */
299  public static final GbifTerm[] TAXONOMIC_TERMS =
300  {GbifTerm.taxonKey, GbifTerm.acceptedTaxonKey, GbifTerm.kingdomKey, GbifTerm.phylumKey, GbifTerm.classKey,
301   GbifTerm.orderKey, GbifTerm.familyKey, GbifTerm.genusKey, GbifTerm.subgenusKey, GbifTerm.speciesKey,
302   GbifTerm.species, GbifTerm.canonicalName, GbifTerm.nameType, GbifTerm.acceptedScientificName,
303   GbifTerm.verbatimScientificName};
304
305  private final String groupName;
306  private final boolean isDeprecated;
307  public final String[] normAlts;
308
309  GbifTerm(String groupName, String... alternatives) {
310    this.groupName = groupName;
311    this.normAlts = alternatives;
312    boolean deprecatedAnnotationPresent = false;
313    try {
314      deprecatedAnnotationPresent = GbifTerm.class.getField(this.name()).isAnnotationPresent(Deprecated.class);
315    } catch (NoSuchFieldException ignore) { }
316    this.isDeprecated = deprecatedAnnotationPresent;
317  }
318
319  /**
320   * The simple term name without a namespace.
321   * For example taxonKey.
322   *
323   * @return simple term name
324   */
325  @Override
326  public String simpleName() {
327    return name();
328  }
329
330  /**
331   * Array of alternative simple names in use for the term.
332   *
333   * @return simple term name
334   */
335  @Override
336  public String[] alternativeNames() {
337    return normAlts;
338  }
339
340  /**
341   * The optional group the term is grouped in.
342   * For example Occurrence, Taxon, etc.
343   */
344  public String getGroup() {
345    return groupName;
346  }
347
348
349  /**
350   * List all terms that belong to a given group.
351   *
352   * @param group the group to list terms for
353   * @return the list of GBIF terms in the given group
354   */
355  public static List<GbifTerm> listByGroup(String group) {
356    List<GbifTerm> terms = new ArrayList<GbifTerm>();
357    for (GbifTerm t : GbifTerm.values()) {
358      if (t.getGroup().equalsIgnoreCase(group)) {
359        terms.add(t);
360      }
361    }
362    return terms;
363  }
364
365  @Override
366  public String toString() {
367    return prefixedName();
368  }
369
370  @Override
371  public boolean isClass() {
372    return Character.isUpperCase(simpleName().charAt(0));
373  }
374
375  @Override
376  public String prefix() {
377    return PREFIX;
378  }
379
380  @Override
381  public URI namespace() {
382    return NS_URI;
383  }
384
385  /**
386   *
387   * @return true if the Term is annotated with @Deprecated.
388   */
389  public boolean isDeprecated(){
390    return isDeprecated;
391  }
392
393}