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  private static final String PREFIX = "gbif";
276  private static final String NS = "http://rs.gbif.org/terms/1.0/";
277  private static final URI NS_URI = URI.create(NS);
278
279  public static final String GROUP_CRAWLING = "Crawling";
280  public static final String GROUP_DATASET = "Dataset";
281  public static final String GROUP_ROW_TYPE = "RowType";
282  public static final String GROUP_SPECIES_DISTRIBUTION_EXTENSION = "SpeciesDistribution";
283  public static final String GROUP_SPECIES_PROFILE_EXTENSION = "SpeciesProfile";
284  public static final String GROUP_VERNACULAR_NAME_EXTENSION = "VernacularName";
285
286  /**
287   * Lists all GBIF term groups.
288   */
289  public static final String[] GROUPS = {GROUP_CRAWLING, GROUP_DATASET, DwcTerm.GROUP_OCCURRENCE, GROUP_ROW_TYPE,
290    GROUP_SPECIES_DISTRIBUTION_EXTENSION, GROUP_SPECIES_PROFILE_EXTENSION, DwcTerm.GROUP_TAXON,
291    GROUP_VERNACULAR_NAME_EXTENSION, DwcTerm.GROUP_LOCATION};
292
293  /**
294   * Lists all GBIF terms in taxon group.
295   */
296  public static final GbifTerm[] TAXONOMIC_TERMS =
297  {GbifTerm.taxonKey, GbifTerm.acceptedTaxonKey, GbifTerm.kingdomKey, GbifTerm.phylumKey, GbifTerm.classKey,
298   GbifTerm.orderKey, GbifTerm.familyKey, GbifTerm.genusKey, GbifTerm.subgenusKey, GbifTerm.speciesKey,
299   GbifTerm.species, GbifTerm.canonicalName, GbifTerm.nameType, GbifTerm.acceptedScientificName,
300   GbifTerm.verbatimScientificName};
301
302  private final String groupName;
303  private final boolean isDeprecated;
304  public final String[] normAlts;
305
306  GbifTerm(String groupName, String... alternatives) {
307    this.groupName = groupName;
308    this.normAlts = alternatives;
309    boolean deprecatedAnnotationPresent = false;
310    try {
311      deprecatedAnnotationPresent = GbifTerm.class.getField(this.name()).isAnnotationPresent(Deprecated.class);
312    } catch (NoSuchFieldException ignore) { }
313    this.isDeprecated = deprecatedAnnotationPresent;
314  }
315
316  /**
317   * The simple term name without a namespace.
318   * For example taxonKey.
319   *
320   * @return simple term name
321   */
322  @Override
323  public String simpleName() {
324    return name();
325  }
326
327  /**
328   * Array of alternative simple names in use for the term.
329   *
330   * @return simple term name
331   */
332  @Override
333  public String[] alternativeNames() {
334    return normAlts;
335  }
336
337  /**
338   * The optional group the term is grouped in.
339   * For example Occurrence, Taxon, etc.
340   */
341  public String getGroup() {
342    return groupName;
343  }
344
345
346  /**
347   * List all terms that belong to a given group.
348   *
349   * @param group the group to list terms for
350   * @return the list of GBIF terms in the given group
351   */
352  public static List<GbifTerm> listByGroup(String group) {
353    List<GbifTerm> terms = new ArrayList<GbifTerm>();
354    for (GbifTerm t : GbifTerm.values()) {
355      if (t.getGroup().equalsIgnoreCase(group)) {
356        terms.add(t);
357      }
358    }
359    return terms;
360  }
361
362  @Override
363  public String toString() {
364    return prefixedName();
365  }
366
367  @Override
368  public boolean isClass() {
369    return Character.isUpperCase(simpleName().charAt(0));
370  }
371
372  @Override
373  public String prefix() {
374    return PREFIX;
375  }
376
377  @Override
378  public URI namespace() {
379    return NS_URI;
380  }
381
382  /**
383   *
384   * @return true if the Term is annotated with @Deprecated.
385   */
386  public boolean isDeprecated(){
387    return isDeprecated;
388  }
389
390}