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   * The distance in metres from a known centroid, e.g. a country centroid.
117   */
118  distanceFromCentroidInMeters(DwcTerm.GROUP_LOCATION),
119
120  /**
121   * Any issue found during processing and interpretation or the record.
122   * See <a href="http://gbif.github.io/gbif-api/apidocs/org/gbif/api/vocabulary/OccurrenceIssue.html">OccurrenceIssue enumeration</a> for possible values.
123   */
124  issue(DwcTerm.GROUP_OCCURRENCE),
125
126  /**
127   * The media type given as Dublin Core type values, in particular StillImage, MovingImage or Sound.
128   */
129  mediaType(DwcTerm.GROUP_OCCURRENCE),
130  // experimental Occurrence properties
131  verbatimLabel(DwcTerm.GROUP_OCCURRENCE),
132  infraspecificMarker(DwcTerm.GROUP_OCCURRENCE),
133  // Types and Specimen checklist extension
134  typeDesignatedBy(DwcTerm.GROUP_OCCURRENCE),
135  typeDesignationType(DwcTerm.GROUP_OCCURRENCE),
136
137  /**
138   * Boolean indicating that a valid latitude and longitude exists.
139   * Even if existing it might still have issues, see hasGeospatialIssues and issue.
140   */
141  hasCoordinate(DwcTerm.GROUP_OCCURRENCE),
142
143  /**
144   * Boolean indicating that some spatial validation rule has not passed.
145   * Primarily used to indicate that the record should not be displayed on a map.
146   */
147  hasGeospatialIssues(DwcTerm.GROUP_OCCURRENCE),
148
149  /**
150   * The GBIF backbone key.
151   * <p>
152   * The best matching, accepted GBIF backbone name usage representing this occurrence.
153   * In case the verbatim scientific name and its classification can only be matched to a higher rank this will
154   * represent the lowest matching rank. In the worst case this could just be for example Animalia.
155   * </p>
156   * <p>
157   * In contrast dwc:taxonID is only used for the source ids similar to occurrenceID
158   * </p>
159   */
160  taxonKey(DwcTerm.GROUP_TAXON),
161
162
163  /**
164   * The GBIF backbone key of the accepted taxon key.
165   */
166  acceptedTaxonKey(DwcTerm.GROUP_TAXON),
167
168  /**
169   * The key to the accepted kingdom in the GBIF backbone.
170   */
171  kingdomKey(DwcTerm.GROUP_TAXON),
172
173  /**
174   * The key to the accepted phylum in the GBIF backbone.
175   */
176  phylumKey(DwcTerm.GROUP_TAXON),
177
178  /**
179   * The key to the accepted class in the GBIF backbone.
180   */
181  classKey(DwcTerm.GROUP_TAXON),
182
183  /**
184   * The key to the accepted order in the GBIF backbone.
185   */
186  orderKey(DwcTerm.GROUP_TAXON),
187
188  /**
189   * The key to the accepted family in the GBIF backbone.
190   */
191  familyKey(DwcTerm.GROUP_TAXON),
192
193  /**
194   * The key to the accepted genus in the GBIF backbone.
195   */
196  genusKey(DwcTerm.GROUP_TAXON),
197
198  /**
199   * The key to the accepted subgenus in the GBIF backbone.
200   */
201  subgenusKey(DwcTerm.GROUP_TAXON),
202
203  /**
204   * The backbone key to the accepted species.
205   * In case the taxonKey is of a higher rank than species (e.g. genus) speciesKey is null.
206   * In case taxonKey represents an infraspecific taxon the speciesKey points to the species
207   * the infraspecies is classified as. In case of taxonKey being a species the speciesKey is the same.
208   */
209  speciesKey(DwcTerm.GROUP_TAXON),
210
211  /**
212   * The canonical name without authorship of the accepted species.
213   */
214  species(DwcTerm.GROUP_TAXON),
215  // experimental Taxon properties
216  canonicalName(DwcTerm.GROUP_TAXON),
217  nameType(DwcTerm.GROUP_TAXON),
218
219  /**
220   * The scientific name the type associated acceptedNubKey.
221   */
222  acceptedScientificName(DwcTerm.GROUP_TAXON),
223
224  /**
225   * Scientific name as provided by the source.
226   */
227  verbatimScientificName(DwcTerm.GROUP_TAXON),
228
229  /**
230   * The scientific name the type status of this specimen applies to.
231   * Term proposed in Darwin Core, but not yet ratified.
232   */
233  typifiedName(DwcTerm.GROUP_IDENTIFICATION),
234
235  /**
236   * The kind of protocol used when the record was last crawled by GBIF.
237   * See <a href="http://gbif.github.io/gbif-api/apidocs/org/gbif/api/vocabulary/EndpointType.html">EndpointType enumeration</a> for possible values.
238   */
239  protocol(GbifTerm.GROUP_CRAWLING),
240
241  /**
242   * The date this record was last parsed from raw xml/json into a verbatim GBIF record.
243   */
244  lastParsed(GbifTerm.GROUP_CRAWLING),
245
246  /**
247   * The date this record was last crawled/harvested by GBIF from the endpoint.
248   */
249  lastCrawled(GbifTerm.GROUP_CRAWLING),
250
251  // Species Profile checklist extension
252  isMarine(GbifTerm.GROUP_SPECIES_PROFILE_EXTENSION),
253  isTerrestrial(GbifTerm.GROUP_SPECIES_PROFILE_EXTENSION),
254  isFreshwater(GbifTerm.GROUP_SPECIES_PROFILE_EXTENSION),
255  isHybrid(GbifTerm.GROUP_SPECIES_PROFILE_EXTENSION),
256  isExtinct(GbifTerm.GROUP_SPECIES_PROFILE_EXTENSION),
257  livingPeriod(GbifTerm.GROUP_SPECIES_PROFILE_EXTENSION, "timePeriod"),
258  lifeForm(GbifTerm.GROUP_SPECIES_PROFILE_EXTENSION),
259  ageInDays(GbifTerm.GROUP_SPECIES_PROFILE_EXTENSION),
260  sizeInMillimeter(GbifTerm.GROUP_SPECIES_PROFILE_EXTENSION),
261  massInGram(GbifTerm.GROUP_SPECIES_PROFILE_EXTENSION, "weightInGram"),
262
263  // Vernacular Name checklist extension
264  organismPart(GbifTerm.GROUP_VERNACULAR_NAME_EXTENSION),
265  isPlural(GbifTerm.GROUP_VERNACULAR_NAME_EXTENSION),
266  isPreferredName(GbifTerm.GROUP_VERNACULAR_NAME_EXTENSION),
267
268  // Distribution checklist extension
269  appendixCITES(GbifTerm.GROUP_SPECIES_DISTRIBUTION_EXTENSION),
270  numberOfOccurrences(GbifTerm.GROUP_SPECIES_DISTRIBUTION_EXTENSION),
271
272  /**
273   * Boolean indicating if the publishing country is different
274   */
275  repatriated(DwcTerm.GROUP_OCCURRENCE),
276
277  // Calculated relative organism quantity, based on organism and sample measure types
278  relativeOrganismQuantity(DwcTerm.GROUP_MATERIAL_SAMPLE),
279
280  // The type for event records
281  @Vocabulary eventType(DwcTerm.GROUP_EVENT),
282
283  projectId(DwcTerm.GROUP_OCCURRENCE);
284
285  private static final String PREFIX = "gbif";
286  private static final String NS = "http://rs.gbif.org/terms/1.0/";
287  private static final URI NS_URI = URI.create(NS);
288
289  public static final String GROUP_CRAWLING = "Crawling";
290  public static final String GROUP_DATASET = "Dataset";
291  public static final String GROUP_ROW_TYPE = "RowType";
292  public static final String GROUP_SPECIES_DISTRIBUTION_EXTENSION = "SpeciesDistribution";
293  public static final String GROUP_SPECIES_PROFILE_EXTENSION = "SpeciesProfile";
294  public static final String GROUP_VERNACULAR_NAME_EXTENSION = "VernacularName";
295
296  /**
297   * Lists all GBIF term groups.
298   */
299  public static final String[] GROUPS = {GROUP_CRAWLING, GROUP_DATASET, DwcTerm.GROUP_OCCURRENCE, GROUP_ROW_TYPE,
300    GROUP_SPECIES_DISTRIBUTION_EXTENSION, GROUP_SPECIES_PROFILE_EXTENSION, DwcTerm.GROUP_TAXON,
301    GROUP_VERNACULAR_NAME_EXTENSION, DwcTerm.GROUP_LOCATION};
302
303  /**
304   * Lists all GBIF terms in taxon group.
305   */
306  public static final GbifTerm[] TAXONOMIC_TERMS =
307  {GbifTerm.taxonKey, GbifTerm.acceptedTaxonKey, GbifTerm.kingdomKey, GbifTerm.phylumKey, GbifTerm.classKey,
308   GbifTerm.orderKey, GbifTerm.familyKey, GbifTerm.genusKey, GbifTerm.subgenusKey, GbifTerm.speciesKey,
309   GbifTerm.species, GbifTerm.canonicalName, GbifTerm.nameType, GbifTerm.acceptedScientificName,
310   GbifTerm.verbatimScientificName};
311
312  private final String groupName;
313  private final boolean isDeprecated;
314  public final String[] normAlts;
315
316  GbifTerm(String groupName, String... alternatives) {
317    this.groupName = groupName;
318    this.normAlts = alternatives;
319    boolean deprecatedAnnotationPresent = false;
320    try {
321      deprecatedAnnotationPresent = GbifTerm.class.getField(this.name()).isAnnotationPresent(Deprecated.class);
322    } catch (NoSuchFieldException ignore) { }
323    this.isDeprecated = deprecatedAnnotationPresent;
324  }
325
326  /**
327   * The simple term name without a namespace.
328   * For example taxonKey.
329   *
330   * @return simple term name
331   */
332  @Override
333  public String simpleName() {
334    return name();
335  }
336
337  /**
338   * Array of alternative simple names in use for the term.
339   *
340   * @return simple term name
341   */
342  @Override
343  public String[] alternativeNames() {
344    return normAlts;
345  }
346
347  /**
348   * The optional group the term is grouped in.
349   * For example Occurrence, Taxon, etc.
350   */
351  public String getGroup() {
352    return groupName;
353  }
354
355
356  /**
357   * List all terms that belong to a given group.
358   *
359   * @param group the group to list terms for
360   * @return the list of GBIF terms in the given group
361   */
362  public static List<GbifTerm> listByGroup(String group) {
363    List<GbifTerm> terms = new ArrayList<GbifTerm>();
364    for (GbifTerm t : GbifTerm.values()) {
365      if (t.getGroup().equalsIgnoreCase(group)) {
366        terms.add(t);
367      }
368    }
369    return terms;
370  }
371
372  @Override
373  public String toString() {
374    return prefixedName();
375  }
376
377  @Override
378  public boolean isClass() {
379    return Character.isUpperCase(simpleName().charAt(0));
380  }
381
382  @Override
383  public String prefix() {
384    return PREFIX;
385  }
386
387  @Override
388  public URI namespace() {
389    return NS_URI;
390  }
391
392  /**
393   *
394   * @return true if the Term is annotated with @Deprecated.
395   */
396  public boolean isDeprecated(){
397    return isDeprecated;
398  }
399
400}