001/*
002 * Licensed under the Apache License, Version 2.0 (the "License");
003 * you may not use this file except in compliance with the License.
004 * You may obtain a copy of the License at
005 *
006 *     http://www.apache.org/licenses/LICENSE-2.0
007 *
008 * Unless required by applicable law or agreed to in writing, software
009 * distributed under the License is distributed on an "AS IS" BASIS,
010 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
011 * See the License for the specific language governing permissions and
012 * limitations under the License.
013 */
014package org.gbif.api.model.occurrence.search;
015import com.fasterxml.jackson.annotation.*;
016
017import com.fasterxml.jackson.core.JacksonException;
018
019import com.fasterxml.jackson.databind.DeserializationContext;
020import com.fasterxml.jackson.databind.JsonDeserializer;
021
022import com.fasterxml.jackson.databind.KeyDeserializer;
023import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
024import com.fasterxml.jackson.databind.node.ObjectNode;
025import org.gbif.api.model.common.search.SearchParameter;
026import org.gbif.api.util.IsoDateInterval;
027import org.gbif.api.vocabulary.BasisOfRecord;
028import org.gbif.api.vocabulary.Continent;
029import org.gbif.api.vocabulary.Country;
030import org.gbif.api.vocabulary.EndpointType;
031import org.gbif.api.vocabulary.GbifRegion;
032import org.gbif.api.vocabulary.License;
033import org.gbif.api.vocabulary.MediaType;
034import org.gbif.api.vocabulary.OccurrenceIssue;
035import org.gbif.api.vocabulary.OccurrenceStatus;
036import org.gbif.api.vocabulary.TaxonomicStatus;
037
038import java.io.IOException;
039import java.io.Serializable;
040import java.lang.reflect.Field;
041import java.util.ArrayList;
042import java.util.Date;
043import java.util.List;
044import java.util.Objects;
045import java.util.Optional;
046import java.util.UUID;
047
048/**
049 * Supported query parameters by the occurrence search and download service.
050 * For download predicates only the numerical types support comparisons other than equals.
051 */
052@JsonDeserialize(as = OccurrenceSearchParameter.class, using = OccurrenceSearchParameter.OccurrenceSearchParameterDeserializer.class)
053public class OccurrenceSearchParameter implements SearchParameter, Serializable {
054
055  /**
056   * The dataset key as a UUID.
057   */
058  public final static OccurrenceSearchParameter DATASET_KEY = new OccurrenceSearchParameter("DATASET_KEY", UUID.class);
059
060  /**
061   * The checklist key to use for taxonomy matching.
062   */
063  public final static OccurrenceSearchParameter CHECKLIST_KEY = new OccurrenceSearchParameter("CHECKLIST_KEY", String.class);
064
065  /**
066   * The 4 digit year. A year of 98 will be 98 common era, not 1998.
067   * This parameter accepts comma separated range values, e.g.:
068   * <dl>
069   * <dt>*,1810</dt>
070   * <dd>Found before or equal to 1810</dd>
071   * <dt>1848,1933</dt>
072   * <dd>Year between 1848 and 1933</dd>
073   * </dl>
074   */
075  public final static OccurrenceSearchParameter YEAR = new OccurrenceSearchParameter("YEAR", Integer.class);
076
077  /**
078   * The month of the year, starting with 1 for January.
079   * A month query can be used to retrieve seasonal records when used without a year or a year range.
080   * This parameter accepts comma separated range values, e.g.:
081   * <dl>
082   * <dt>4,8</dt>
083   * <dd>Month between April and August</dd>
084   * </dl>
085   */
086  public final static OccurrenceSearchParameter MONTH = new OccurrenceSearchParameter("MONTH", Integer.class);
087
088  /**
089   * The day of the month.
090   * This parameter accepts comma separated range values, e.g.:
091   * <dl>
092   * <dt>24,28</dt>
093   * <dd>Day of the month between 24 and 28</dd>
094   * </dl>
095   */
096  public final static OccurrenceSearchParameter DAY = new OccurrenceSearchParameter("DAY", Integer.class);
097
098  /**
099   * The earliest integer day of the year on which the event occurred (1 for January 1, 365 for December 31, except in a
100   * leap year, in which case it is 366).
101   */
102  public final static OccurrenceSearchParameter START_DAY_OF_YEAR = new OccurrenceSearchParameter("START_DAY_OF_YEAR", Integer.class);
103
104  /**
105   * The latest integer day of the year on which the event occurred (1 for January 1, 365 for December 31, except in a
106   * leap year, in which case it is 366).
107   */
108  public final static OccurrenceSearchParameter END_DAY_OF_YEAR = new OccurrenceSearchParameter("END_DAY_OF_YEAR", Integer.class);
109
110  /**
111   * Event date (date the occurrence was recorded) in ISO 8601 formats:yyyy, yyyy-MM, yyyy-MM-dd and MM-dd.
112   * This parameter accepts comma separated range values, examples of valid ranges are:
113   * <dl>
114   * <dt>2001-02-11,2010-01-10</dt>
115   * <dd>Dates between 2001-02-11 and 2010-01-10</dd>
116   * <dt>2001-02,2010-01</dt>
117   * <dd>Dates between first day of 2001-02 and last day of 2010-01</dd>
118   * <dt>2001,2010</dt>
119   * <dd>Dates between first day of 2001 and last day of 2010</dd>
120   * <dt>2001,2010-01</dt>
121   * <dd>Dates between first day of 2001 and last day of 2010-01</dd>
122   * <dt>2001-01-10,2010</dt>
123   * <dd>Dates between 2001-01-10 and last day of 2010</dd>
124   * <dt>2001-01-10,*</dt>
125   * <dd>Dates after 2001-01-10</dd>
126   * <dt>*,2001-01-10</dt>
127   * <dd>Dates before 2001-01-10</dd>
128   * <dt>*</dt>
129   * <dd>all dates</dd>
130   * </dl>
131   */
132  public final static OccurrenceSearchParameter EVENT_DATE = new OccurrenceSearchParameter("EVENT_DATE", IsoDateInterval.class);
133
134  /**
135   * Lower limit for the range of the event date (date the occurrence was recorded).
136   *
137   * Included for backward compatibility as it mimicks the previous search behaviour:
138   * https://github.com/gbif/occurrence/issues/346
139   */
140  @Deprecated
141  public final static OccurrenceSearchParameter EVENT_DATE_GTE = new OccurrenceSearchParameter("EVENT_DATE_GTE", Date.class);
142
143  /**
144   * An identifier for the set of information associated with an Event (something that occurs at a place and time).
145   * Maybe a global unique identifier or an identifier specific to the data set.
146   */
147  public final static OccurrenceSearchParameter EVENT_ID = new OccurrenceSearchParameter("EVENT_ID", String.class);
148
149  /**
150   * An identifier for the broader Event that groups this and potentially other Events.
151   */
152  public final static OccurrenceSearchParameter PARENT_EVENT_ID = new OccurrenceSearchParameter("PARENT_EVENT_ID", String.class);
153
154  /**
155   * An identifier for an Event and its children events.
156   */
157  public final static OccurrenceSearchParameter EVENT_ID_HIERARCHY = new OccurrenceSearchParameter("EVENT_ID_HIERARCHY", String.class);
158
159  /**
160   * The name of, reference to, or description of the method or protocol used during an Event.
161   */
162  public final static OccurrenceSearchParameter SAMPLING_PROTOCOL = new OccurrenceSearchParameter("SAMPLING_PROTOCOL", String.class);
163
164  /**
165   * A list (concatenated and separated) of previous assignments of names to the organism.
166   */
167  public final static OccurrenceSearchParameter PREVIOUS_IDENTIFICATIONS = new OccurrenceSearchParameter("PREVIOUS_IDENTIFICATIONS", String.class);
168
169  /**
170   * Last interpreted date in ISO 8601 formats:yyyy, yyyy-MM, yyyy-MM-dd and MM-dd.
171   * This parameter accepts comma separated range values, examples of valid ranges are:
172   * <dl>
173   * <dt>2001-02-11,2010-01-10</dt>
174   * <dd>Dates between 2001-02-11 and 2010-01-10</dd>
175   * <dt>2001-02,2010-01</dt>
176   * <dd>Dates between first day of 2001-02 and last day of 2010-01</dd>
177   * <dt>2001,2010</dt>
178   * <dd>Dates between first day of 2001 and last day of 2010</dd>
179   * <dt>2001,2010-01</dt>
180   * <dd>Dates between first day of 2001 and last day of 2010-01</dd>
181   * <dt>2001-01-10,2010</dt>
182   * <dd>Dates between 2001-01-10 and last day of 2010</dd>
183   * <dt>2001-01-10,*</dt>
184   * <dd>Dates after 2001-01-10</dd>
185   * <dt>*,2001-01-10</dt>
186   * <dd>Dates before 2001-01-10</dd>
187   * <dt>*</dt>
188   * <dd>all dates</dd>
189   * </dl>
190   */
191  public final static OccurrenceSearchParameter LAST_INTERPRETED = new OccurrenceSearchParameter("LAST_INTERPRETED", Date.class);
192
193
194  /**
195   * Modified date in ISO 8601 formats:yyyy, yyyy-MM, yyyy-MM-dd and MM-dd.
196   * This parameter accepts comma separated range values, examples of valid ranges are:
197   * <dl>
198   * <dt>2001-02-11,2010-01-10</dt>
199   * <dd>Dates between 2001-02-11 and 2010-01-10</dd>
200   * <dt>2001-02,2010-01</dt>
201   * <dd>Dates between first day of 2001-02 and last day of 2010-01</dd>
202   * <dt>2001,2010</dt>
203   * <dd>Dates between first day of 2001 and last day of 2010</dd>
204   * <dt>2001,2010-01</dt>
205   * <dd>Dates between first day of 2001 and last day of 2010-01</dd>
206   * <dt>2001-01-10,2010</dt>
207   * <dd>Dates between 2001-01-10 and last day of 2010</dd>
208   * <dt>2001-01-10,*</dt>
209   * <dd>Dates after 2001-01-10</dd>
210   * <dt>*,2001-01-10</dt>
211   * <dd>Dates before 2001-01-10</dd>
212   * <dt>*</dt>
213   * <dd>all dates</dd>
214   * </dl>
215   */
216  public final static OccurrenceSearchParameter MODIFIED = new OccurrenceSearchParameter("MODIFIED", Date.class);
217
218  /**
219   * Latitude in decimals between -90 and 90 based on WGS 84.
220   */
221  public final static OccurrenceSearchParameter DECIMAL_LATITUDE = new OccurrenceSearchParameter("DECIMAL_LATITUDE", Double.class);
222
223  /**
224   * Longitude in decimals between -180 and 180 based on WGS 84.
225   */
226  public final static OccurrenceSearchParameter DECIMAL_LONGITUDE = new OccurrenceSearchParameter("DECIMAL_LONGITUDE", Double.class);
227
228  /**
229   * The uncertainty of the coordinate in meters.
230   * This parameter accepts comma separated range values, e.g.:
231   * <dl>
232   * <dt>*,100</dt>
233   * <dd>Uncertainty below or equals 100m</dd>
234   * <dt>10000,*</dt>
235   * <dd>Uncertainty above or equals 10,000m</dd>
236   * <dt>1000,5000</dt>
237   * <dd>Uncertainty between or equals 1000m and 5000m
238   * </dd>
239   * </dl>
240   */
241  public final static OccurrenceSearchParameter COORDINATE_UNCERTAINTY_IN_METERS = new OccurrenceSearchParameter("COORDINATE_UNCERTAINTY_IN_METERS", Double.class);
242
243  /**
244   * Country the occurrence was recorded in.
245   */
246  public final static OccurrenceSearchParameter COUNTRY = new OccurrenceSearchParameter("COUNTRY", Country.class);
247
248  /**
249   * GBIF region based on country
250   */
251  public final static OccurrenceSearchParameter GBIF_REGION = new OccurrenceSearchParameter("GBIF_REGION", GbifRegion.class);
252
253  /**
254   * Continent the occurrence was recorded in.
255   */
256  public final static OccurrenceSearchParameter CONTINENT = new OccurrenceSearchParameter("CONTINENT", Continent.class);
257
258  /**
259   * The country of the organization that publishes the dataset the occurrence belongs to.
260   */
261  public final static OccurrenceSearchParameter PUBLISHING_COUNTRY = new OccurrenceSearchParameter("PUBLISHING_COUNTRY", Country.class);
262
263  /**
264   * GBIF region based on publishibg country
265   */
266  public final static OccurrenceSearchParameter PUBLISHED_BY_GBIF_REGION = new OccurrenceSearchParameter("PUBLISHED_BY_GBIF_REGION", GbifRegion.class);
267
268  /**
269   * Altitude/elevation in meters above sea level.
270   * This parameter accepts comma separated range values, e.g.:
271   * <dl>
272   * <dt>*,100</dt>
273   * <dd>Altitude below or equals 100m</dd>
274   * <dt>100,*</dt>
275   * <dd>Altitude above or equals 100m</dd>
276   * <dt>-2,8.8</dt>
277   * <dd>Altitude between or equals -2m and 8.8m</dd>
278   * </dl>
279   */
280  public final static OccurrenceSearchParameter ELEVATION = new OccurrenceSearchParameter("ELEVATION", Double.class);
281
282  /**
283   * Depth in meters relative to altitude. For example 10 meters below a lake surface with given altitude.
284   * This parameter accepts comma separated range values, e.g.:
285   * <dl>
286   * <dt>*,10</dt>
287   * <dd>Depth below or equals 10m</dd>
288   * <dt>100,*</dt>
289   * <dd>Depth above or equals 100m</dd>
290   * <dt>12.1,28.8</dt>
291   * <dd>Depth between or equals 12.1m and 28.8m</dd>
292   * </dl>
293   */
294  public final static OccurrenceSearchParameter DEPTH = new OccurrenceSearchParameter("DEPTH", Double.class);
295
296  /**
297   * An identifier of any form assigned by the source to identify the institution
298   * the record belongs to. Not guaranteed to be unique.
299   */
300  public final static OccurrenceSearchParameter INSTITUTION_CODE = new OccurrenceSearchParameter("INSTITUTION_CODE", String.class);
301
302  /**
303   * An identifier of any form assigned by the source to identify the physical collection or digital dataset
304   * uniquely within the context of an institution.
305   */
306  public final static OccurrenceSearchParameter COLLECTION_CODE = new OccurrenceSearchParameter("COLLECTION_CODE", String.class);
307
308  /**
309   * An identifier of any form assigned by the source within a physical collection or digital dataset for the record
310   * which may not be unique, but should be fairly unique in combination with the institution and collection code.
311   */
312  public final static OccurrenceSearchParameter CATALOG_NUMBER = new OccurrenceSearchParameter("CATALOG_NUMBER", String.class);
313
314  /**
315   * The person who recorded the occurrence.
316   */
317  public final static OccurrenceSearchParameter RECORDED_BY = new OccurrenceSearchParameter("RECORDED_BY", String.class);
318
319  /**
320   * The person who identified the occurrence.
321   */
322  public final static OccurrenceSearchParameter IDENTIFIED_BY = new OccurrenceSearchParameter("IDENTIFIED_BY", String.class);
323
324  /**
325   * An identifier given to the Occurrence at the time it was recorded.
326   */
327  public final static OccurrenceSearchParameter RECORD_NUMBER = new OccurrenceSearchParameter("RECORD_NUMBER", String.class);
328
329  /**
330   * A basis of record enumeration value.
331   */
332  public final static OccurrenceSearchParameter BASIS_OF_RECORD = new OccurrenceSearchParameter("BASIS_OF_RECORD", BasisOfRecord.class);
333
334  /**
335   * The sex of the biological individual(s) represented in the occurrence.
336   */
337  public final static OccurrenceSearchParameter SEX = new OccurrenceSearchParameter("SEX", String.class);
338
339  /**
340   * Presents of associated sequences or an extension
341   */
342  public final static OccurrenceSearchParameter IS_SEQUENCED = new OccurrenceSearchParameter("IS_SEQUENCED", Boolean.class);
343
344  /**
345   * A taxon key from the GBIF backbone. All included and synonym taxa are included in the search, so a search for
346   * aves with taxonKey=212 will match all birds, no matter which species.
347   */
348  public final static OccurrenceSearchParameter TAXON_KEY = new OccurrenceSearchParameter("TAXON_KEY", String.class);
349
350  /**
351   * A taxon key from the GBIF backbone for the name usage of the currently valid or accepted taxon.
352   */
353  public final static OccurrenceSearchParameter ACCEPTED_TAXON_KEY = new OccurrenceSearchParameter("ACCEPTED_TAXON_KEY", String.class);
354
355  /**
356   * A kingdom key from the GBIF backbone.
357   */
358  public final static OccurrenceSearchParameter KINGDOM_KEY = new OccurrenceSearchParameter("KINGDOM_KEY", String.class);
359
360  /**
361   * A phylum key from the GBIF backbone.
362   */
363  public final static OccurrenceSearchParameter PHYLUM_KEY = new OccurrenceSearchParameter("PHYLUM_KEY", String.class);
364
365  /**
366   * A class key from the GBIF backbone.
367   */
368  public final static OccurrenceSearchParameter CLASS_KEY = new OccurrenceSearchParameter("CLASS_KEY", String.class);
369
370  /**
371   * A order key from the GBIF backbone.
372   */
373  public final static OccurrenceSearchParameter ORDER_KEY = new OccurrenceSearchParameter("ORDER_KEY", String.class);
374
375  /**
376   * A family key from the GBIF backbone.
377   */
378  public final static OccurrenceSearchParameter FAMILY_KEY = new OccurrenceSearchParameter("FAMILY_KEY", String.class);
379
380  /**
381   * A genus key from the GBIF backbone.
382   */
383  public final static OccurrenceSearchParameter GENUS_KEY = new OccurrenceSearchParameter("GENUS_KEY", String.class);
384
385  /**
386   * A subgenus key from the GBIF backbone.
387   */
388  public final static OccurrenceSearchParameter SUBGENUS_KEY = new OccurrenceSearchParameter("SUBGENUS_KEY", String.class);
389
390  /**
391   * A species key from the GBIF backbone.
392   */
393  public final static OccurrenceSearchParameter SPECIES_KEY = new OccurrenceSearchParameter("SPECIES_KEY", String.class);
394
395  /**
396   * Searches the interpreted, full scientific name of the occurrence.
397   */
398  public final static OccurrenceSearchParameter SCIENTIFIC_NAME = new OccurrenceSearchParameter("SCIENTIFIC_NAME", String.class);
399
400  /**
401   * Scientific name as provided byt the source.
402   */
403  public final static OccurrenceSearchParameter VERBATIM_SCIENTIFIC_NAME = new OccurrenceSearchParameter("VERBATIM_SCIENTIFIC_NAME", String.class);
404
405  /**
406   * Verbatim identifier for the set of taxon information. Maybe a global unique identifier or an identifier specific to
407   * the data set.
408   */
409  public final static OccurrenceSearchParameter TAXON_ID = new OccurrenceSearchParameter("TAXON_ID", String.class);
410
411  /**
412   * An identifier for the taxonomic concept to which the record refers - not for the nomenclatural details of a taxon.
413   */
414  public final static OccurrenceSearchParameter TAXON_CONCEPT_ID = new OccurrenceSearchParameter("TAXON_CONCEPT_ID", String.class);
415
416  /**
417   * The status of the use of the  GBIF Backbone taxonKey.
418   */
419  public final static OccurrenceSearchParameter TAXONOMIC_STATUS = new OccurrenceSearchParameter("TAXONOMIC_STATUS", TaxonomicStatus.class);
420
421  /**
422   * Searches for occurrence records which contain a value on its coordinate fields (latitude and longitude).
423   * HAS_COORDINATE=true searches for occurrence records with a coordinate value.
424   * HAS_COORDINATE=false searches for occurrence records without a coordinate value.
425   */
426  public final static OccurrenceSearchParameter HAS_COORDINATE = new OccurrenceSearchParameter("HAS_COORDINATE", Boolean.class);
427
428  /**
429   * Geometry in <a href="https://en.wikipedia.org/wiki/Well-known_text">Well Known Text</a> (WKT) format.
430   * E.g.: POLYGON ((30.0 10.0, 10.12 20.23, 20 40, 40 40, 30 10)).
431   * Multi geometries like MULTIPOLYGON are not supported and multiple parameters should be used instead.
432   * Valid geometries are:
433   * <ul>
434   * <li>POINT</li>
435   * <li>LINESTRING</li>
436   * <li>POLYGON</li>
437   * <li>LINEARRING</li>
438   * </ul>
439   */
440  public final static OccurrenceSearchParameter GEOMETRY = new OccurrenceSearchParameter("GEOMETRY", String.class);
441
442  /**
443   * Use in combination of LATITUDE and LONGITUDE parameters matches within a given distance.
444   * E.g.: geo_distance=100m,40,90 geo_distance=100km,40,90 geo_distance=100mi,40,90.
445   * See supported units in {@link org.gbif.api.model.occurrence.geo.DistanceUnit}.
446   */
447  public final static OccurrenceSearchParameter GEO_DISTANCE = new OccurrenceSearchParameter("GEO_DISTANCE", String.class);
448
449  /**
450   * The distance from a known centroid, e.g. a country centroid.
451   */
452  public final static OccurrenceSearchParameter DISTANCE_FROM_CENTROID_IN_METERS = new OccurrenceSearchParameter("DISTANCE_FROM_CENTROID_IN_METERS", Double.class);
453
454  /**
455   * Includes/excludes occurrence records which contain geospatial issues for their coordinate.
456   * See {@link org.gbif.api.vocabulary.OccurrenceIssue#GEOSPATIAL_RULES}
457   * HAS_GEOSPATIAL_ISSUE=true include records with spatial issues.
458   * HAS_GEOSPATIAL_ISSUE=false exclude records with spatial issues.
459   * The absence of this parameter returns any record with or without spatial issues.
460   */
461  public final static OccurrenceSearchParameter HAS_GEOSPATIAL_ISSUE = new OccurrenceSearchParameter("HAS_GEOSPATIAL_ISSUE", Boolean.class);
462
463  /**
464   * Searches occurrence for those that have a specific issue.
465   */
466  public final static OccurrenceSearchParameter ISSUE = new OccurrenceSearchParameter("ISSUE", OccurrenceIssue.class);
467
468  /**
469   * Searches occurrence for those that have a specific taxonomic issue. This is separated out from the general issue
470   * field as taxonomic issues will be tied to a specific checklist.
471   */
472  public final static OccurrenceSearchParameter TAXONOMIC_ISSUE = new OccurrenceSearchParameter("TAXONOMIC_ISSUE", String.class);
473
474  /**
475   * Nomenclatural type (type status, typified scientific name, publication) applied to the subject.
476   */
477  public final static OccurrenceSearchParameter TYPE_STATUS = new OccurrenceSearchParameter("TYPE_STATUS", String.class);
478
479  /**
480   * The kind of media object.
481   * Recommended terms from the DCMI Type Vocabulary are StillImage, Sound or MovingImage for GBIF to index and show the
482   * media files.
483   */
484  public final static OccurrenceSearchParameter MEDIA_TYPE = new OccurrenceSearchParameter("MEDIA_TYPE", MediaType.class);
485
486  /**
487   *  An identifier for the Occurrence (as opposed to a particular digital record of the occurrence).
488   *  In the absence of a persistent global unique identifier, construct one from a combination of identifiers in the
489   *  record that will most closely make the occurrenceID globally unique.
490   */
491  public final static OccurrenceSearchParameter OCCURRENCE_ID = new OccurrenceSearchParameter("OCCURRENCE_ID", String.class);
492
493  /**
494   * The process by which the biological individual(s) represented in the Occurrence became established at the location.
495   */
496  public final static OccurrenceSearchParameter ESTABLISHMENT_MEANS = new OccurrenceSearchParameter("ESTABLISHMENT_MEANS", String.class);
497
498  /**
499   * Provides the controlled vocabulary for information about degree to which an Organism survives, reproduces, and expands its range at the given place and time.
500   */
501  public final static OccurrenceSearchParameter DEGREE_OF_ESTABLISHMENT = new OccurrenceSearchParameter("DEGREE_OF_ESTABLISHMENT", String.class);
502
503  /**
504   * Provides the controlled vocabulary for information about the process by which an Organism came to be in a given place at a given time.
505   * The pathway of an organism or organisms have been introduced to a given place and time.
506   */
507  public final static OccurrenceSearchParameter PATHWAY = new OccurrenceSearchParameter("PATHWAY", String.class);
508
509  /**
510   * Searches for records whose publishing country is different to the country where the record was recorded in.
511   */
512  public final static OccurrenceSearchParameter REPATRIATED = new OccurrenceSearchParameter("REPATRIATED", Boolean.class);
513
514  /**
515   * An identifier for the Organism instance (as opposed to a particular digital record of the Organism).
516   * May be a globally unique identifier or an identifier specific to the data set.
517   */
518  public final static OccurrenceSearchParameter ORGANISM_ID = new OccurrenceSearchParameter("ORGANISM_ID", String.class);
519
520  /**
521   * The name of the next smaller administrative region than country in which the Location occurs.
522   */
523  public final static OccurrenceSearchParameter STATE_PROVINCE = new OccurrenceSearchParameter("STATE_PROVINCE", String.class);
524
525  /**
526   * The name of the water body in which the Location occurs.
527   */
528  public final static OccurrenceSearchParameter WATER_BODY = new OccurrenceSearchParameter("WATER_BODY", String.class);
529
530  /**
531   * The specific description of the place.
532   * It may contain information modified from the original to correct perceived errors or standardize the description.
533   */
534  public final static OccurrenceSearchParameter LOCALITY = new OccurrenceSearchParameter("LOCALITY", String.class);
535
536  /**
537   * Protocol used to provide the occurrence record.
538   */
539  public final static OccurrenceSearchParameter PROTOCOL = new OccurrenceSearchParameter("PROTOCOL", EndpointType.class);
540
541  /**
542   * The license applied to the dataset.
543   */
544  public final static OccurrenceSearchParameter LICENSE = new OccurrenceSearchParameter("LICENSE", License.class);
545
546  /**
547   * The owning organizations uuid key.
548   */
549  public final static OccurrenceSearchParameter PUBLISHING_ORG = new OccurrenceSearchParameter("PUBLISHING_ORG", UUID.class);
550
551  /**
552   * The GBIF network that the publishing organisation belongs to.
553   */
554  public final static OccurrenceSearchParameter NETWORK_KEY = new OccurrenceSearchParameter("NETWORK_KEY", UUID.class);
555
556  /**
557   * The technical installation key that hosts/publishes this record.
558   */
559  public final static OccurrenceSearchParameter INSTALLATION_KEY = new OccurrenceSearchParameter("INSTALLATION_KEY", UUID.class);
560
561  /**
562   * The organization key of the installation that hosts this record.
563   */
564  public final static OccurrenceSearchParameter HOSTING_ORGANIZATION_KEY = new OccurrenceSearchParameter("HOSTING_ORGANIZATION_KEY", UUID.class);
565
566  /**
567   * Crawl attempt that harvested this record.
568   */
569  public final static OccurrenceSearchParameter CRAWL_ID = new OccurrenceSearchParameter("CRAWL_ID", Integer.class);
570
571  /**
572   * GBIF ProjectId.
573   */
574  public final static OccurrenceSearchParameter PROJECT_ID = new OccurrenceSearchParameter("PROJECT_ID", String.class);
575
576  /**
577   * GBIF Programme Acronym.
578   */
579  public final static OccurrenceSearchParameter PROGRAMME = new OccurrenceSearchParameter("PROGRAMME", String.class);
580
581  /**
582   * A number or enumeration value for the quantity of organisms.
583   */
584  public final static OccurrenceSearchParameter ORGANISM_QUANTITY = new OccurrenceSearchParameter("ORGANISM_QUANTITY", Double.class);
585
586  /**
587   * The type of quantification system used for the quantity of organisms.
588   */
589  public final static OccurrenceSearchParameter ORGANISM_QUANTITY_TYPE = new OccurrenceSearchParameter("ORGANISM_QUANTITY_TYPE", String.class);
590
591  /**
592   * The unit of measurement of the size (time duration, length, area, or volume) of a sample in a sampling event.
593   */
594  public final static OccurrenceSearchParameter SAMPLE_SIZE_UNIT = new OccurrenceSearchParameter("SAMPLE_SIZE_UNIT", String.class);
595
596  /**
597   * A numeric value for a measurement of the size (time duration, length, area, or volume) of a sample in a sampling event.
598   */
599  public final static OccurrenceSearchParameter SAMPLE_SIZE_VALUE = new OccurrenceSearchParameter("SAMPLE_SIZE_VALUE", Double.class);
600
601  /**
602   * Calculated organismQuantity relative to the sampleSizeValue i.e. -> organismQuantity / sampleSizeValue.
603   */
604  public final static OccurrenceSearchParameter RELATIVE_ORGANISM_QUANTITY = new OccurrenceSearchParameter("RELATIVE_ORGANISM_QUANTITY", Double.class);
605
606  /**
607   * Collection key. It links to the collection to which this record belongs.
608   */
609  public final static OccurrenceSearchParameter COLLECTION_KEY = new OccurrenceSearchParameter("COLLECTION_KEY", String.class);
610
611  /**
612   * Institution key. It links to the institution that maintains, recorded or digitized  this record.
613   */
614  public final static OccurrenceSearchParameter INSTITUTION_KEY = new OccurrenceSearchParameter("INSTITUTION_KEY", String.class);
615
616  /**
617   * Agent identifiers from GbifTerm.recordedByID
618   */
619  public final static OccurrenceSearchParameter RECORDED_BY_ID = new OccurrenceSearchParameter("RECORDED_BY_ID", String.class);
620
621  /**
622   * Agent identifiers from GbifTerm.identifiedByID
623   */
624  public final static OccurrenceSearchParameter IDENTIFIED_BY_ID = new OccurrenceSearchParameter("IDENTIFIED_BY_ID", String.class);
625
626  /**
627   * An occurrence status enumeration value.
628   */
629  public final static OccurrenceSearchParameter OCCURRENCE_STATUS = new OccurrenceSearchParameter("OCCURRENCE_STATUS", OccurrenceStatus.class);
630
631  /**
632   * A <a href="https://gadm.org">GADM</a> identifier at any level.
633   */
634  public final static OccurrenceSearchParameter GADM_GID = new OccurrenceSearchParameter("GADM_GID", String.class);
635
636  /**
637   * A <a href="https://gadm.org">GADM</a> country, island or territory (level zero) identifier.
638   */
639  public final static OccurrenceSearchParameter GADM_LEVEL_0_GID = new OccurrenceSearchParameter("GADM_LEVEL_0_GID", String.class);
640
641  /**
642   * A <a href="https://gadm.org">GADM</a> first-level identifier.
643   */
644  public final static OccurrenceSearchParameter GADM_LEVEL_1_GID = new OccurrenceSearchParameter("GADM_LEVEL_1_GID", String.class);
645
646  /**
647   * A <a href="https://gadm.org">GADM</a> second-level identifier.
648   */
649  public final static OccurrenceSearchParameter GADM_LEVEL_2_GID = new OccurrenceSearchParameter("GADM_LEVEL_2_GID", String.class);
650
651  /**
652   * A <a href="https://gadm.org">GADM</a> third-level identifier.
653   */
654  public final static OccurrenceSearchParameter GADM_LEVEL_3_GID = new OccurrenceSearchParameter("GADM_LEVEL_3_GID", String.class);
655
656  /**
657   * The life stage of an occurrence.
658   */
659  public final static OccurrenceSearchParameter LIFE_STAGE = new OccurrenceSearchParameter("LIFE_STAGE", String.class);
660
661  /**
662   * Searches for occurrences that are clustered.
663   */
664  public final static OccurrenceSearchParameter IS_IN_CLUSTER = new OccurrenceSearchParameter("IS_IN_CLUSTER", Boolean.class);
665
666  /**
667   * Searches for occurrences that have a particular DwC-A extension.
668   */
669  public final static OccurrenceSearchParameter DWCA_EXTENSION = new OccurrenceSearchParameter("DWCA_EXTENSION", String.class);
670
671  /**
672   * Searches for occurrences that have a IUCN Red List Category.
673   */
674  public final static OccurrenceSearchParameter IUCN_RED_LIST_CATEGORY = new OccurrenceSearchParameter("IUCN_RED_LIST_CATEGORY", String.class);
675
676  /**
677   * The dwc dataset id.
678   */
679  public final static OccurrenceSearchParameter DATASET_ID = new OccurrenceSearchParameter("DATASET_ID", String.class);
680
681  /**
682   * The dwc dataset name.
683   */
684  public final static OccurrenceSearchParameter DATASET_NAME = new OccurrenceSearchParameter("DATASET_NAME", String.class);
685
686  /**
687   * Other catalog numbers associated to an occurrence.
688   */
689  public final static OccurrenceSearchParameter OTHER_CATALOG_NUMBERS = new OccurrenceSearchParameter("OTHER_CATALOG_NUMBERS", String.class);
690
691  /**
692   * Preparations methods of an occurrence.
693   */
694  public final static OccurrenceSearchParameter PREPARATIONS = new OccurrenceSearchParameter("PREPARATIONS", String.class);
695
696  /**
697   * The name of the island on or near which the location occurs.
698   */
699  public final static OccurrenceSearchParameter ISLAND = new OccurrenceSearchParameter("ISLAND", String.class);
700
701  /**
702   * The name of the island group in which the location occurs.
703   */
704  public final static OccurrenceSearchParameter ISLAND_GROUP = new OccurrenceSearchParameter("ISLAND_GROUP", String.class);
705
706  /**
707   * A list (concatenated and separated) of names of people, groups, or organizations who determined the georeference
708   * (spatial representation) for the location.
709   */
710  public final static OccurrenceSearchParameter GEOREFERENCED_BY = new OccurrenceSearchParameter("GEOREFERENCED_BY", String.class);
711
712  /**
713   * A list (concatenated and separated) of geographic names less specific than the information captured in the locality
714   * term.
715   */
716  public final static OccurrenceSearchParameter HIGHER_GEOGRAPHY = new OccurrenceSearchParameter("HIGHER_GEOGRAPHY", String.class);
717
718  /**
719   *    An identifier given to the event in the field. Often serves as a link between field notes and the event.
720   */
721  public final static OccurrenceSearchParameter FIELD_NUMBER = new OccurrenceSearchParameter("FIELD_NUMBER", String.class);
722
723  /**
724   * The full name of the earliest possible geochronologic eon or lowest chrono-stratigraphic eonothem or the informal
725   * name ("Precambrian") attributable to the stratigraphic horizon from which the MaterialEntity was collected.
726   */
727  public final static OccurrenceSearchParameter EARLIEST_EON_OR_LOWEST_EONOTHEM = new OccurrenceSearchParameter("EARLIEST_EON_OR_LOWEST_EONOTHEM", String.class);
728
729  /**
730   * The full name of the latest possible geochronologic eon or highest chrono-stratigraphic eonothem or the informal
731   * name ("Precambrian") attributable to the stratigraphic horizon from which the MaterialEntity was collected.
732   */
733  public final static OccurrenceSearchParameter LATEST_EON_OR_HIGHEST_EONOTHEM = new OccurrenceSearchParameter("LATEST_EON_OR_HIGHEST_EONOTHEM", String.class);
734
735  /**
736   * The full name of the earliest possible geochronologic era or lowest chronostratigraphic erathem attributable to the
737   * stratigraphic horizon from which the MaterialEntity was collected.
738   */
739  public final static OccurrenceSearchParameter EARLIEST_ERA_OR_LOWEST_ERATHEM = new OccurrenceSearchParameter("EARLIEST_ERA_OR_LOWEST_ERATHEM", String.class);
740
741  /**
742   * The full name of the latest possible geochronologic era or highest chronostratigraphic erathem attributable to the
743   * stratigraphic horizon from which the MaterialEntity was collected.
744   */
745  public final static OccurrenceSearchParameter LATEST_ERA_OR_HIGHEST_ERATHEM = new OccurrenceSearchParameter("LATEST_ERA_OR_HIGHEST_ERATHEM", String.class);
746
747  /**
748   * The full name of the earliest possible geochronologic period or lowest chronostratigraphic system attributable to
749   * the stratigraphic horizon from which the MaterialEntity was collected.
750   */
751  public final static OccurrenceSearchParameter EARLIEST_PERIOD_OR_LOWEST_SYSTEM = new OccurrenceSearchParameter("EARLIEST_PERIOD_OR_LOWEST_SYSTEM", String.class);
752
753  /**
754   * The full name of the latest possible geochronologic period or highest chronostratigraphic system attributable to
755   * the stratigraphic horizon from which the MaterialEntity was collected.
756   */
757  public final static OccurrenceSearchParameter LATEST_PERIOD_OR_HIGHEST_SYSTEM = new OccurrenceSearchParameter("LATEST_PERIOD_OR_HIGHEST_SYSTEM", String.class);
758
759  /**
760   * The full name of the earliest possible geochronologic epoch or lowest chronostratigraphic series attributable to
761   * the stratigraphic horizon from which the MaterialEntity was collected.
762   */
763  public final static OccurrenceSearchParameter EARLIEST_EPOCH_OR_LOWEST_SERIES = new OccurrenceSearchParameter("EARLIEST_EPOCH_OR_LOWEST_SERIES", String.class);
764
765  /**
766   * The full name of the latest possible geochronologic epoch or highest chronostratigraphic series attributable to the
767   * stratigraphic horizon from which the MaterialEntity was collected.
768   */
769  public final static OccurrenceSearchParameter LATEST_EPOCH_OR_HIGHEST_SERIES = new OccurrenceSearchParameter("LATEST_EPOCH_OR_HIGHEST_SERIES", String.class);
770
771  /**
772   * The full name of the earliest possible geochronologic age or lowest chronostratigraphic stage attributable to the
773   * stratigraphic horizon from which the MaterialEntity was collected.
774   */
775  public final static OccurrenceSearchParameter EARLIEST_AGE_OR_LOWEST_STAGE = new OccurrenceSearchParameter("EARLIEST_AGE_OR_LOWEST_STAGE", String.class);
776
777  /**
778   * The full name of the latest possible geochronologic age or highest chronostratigraphic stage attributable to the
779   * stratigraphic horizon from which the MaterialEntity was collected.
780   */
781  public final static OccurrenceSearchParameter LATEST_AGE_OR_HIGHEST_STAGE = new OccurrenceSearchParameter("LATEST_AGE_OR_HIGHEST_STAGE", String.class);
782
783  /**
784   * The full name of the lowest possible geological biostratigraphic zone of the stratigraphic horizon from which the
785   * MaterialEntity was collected.
786   */
787  public final static OccurrenceSearchParameter LOWEST_BIOSTRATIGRAPHIC_ZONE = new OccurrenceSearchParameter("LOWEST_BIOSTRATIGRAPHIC_ZONE", String.class);
788
789  /**
790   * The full name of the highest possible geological biostratigraphic zone of the stratigraphic horizon from which the
791   * MaterialEntity was collected.
792   */
793  public final static OccurrenceSearchParameter HIGHEST_BIOSTRATIGRAPHIC_ZONE = new OccurrenceSearchParameter("HIGHEST_BIOSTRATIGRAPHIC_ZONE", String.class);
794
795  /**
796   * The full name of the lithostratigraphic group from which the MaterialEntity was collected.
797   */
798  public final static OccurrenceSearchParameter GROUP = new OccurrenceSearchParameter("GROUP", String.class);
799
800  /**
801   * The full name of the lithostratigraphic formation from which the MaterialEntity was collected.
802   */
803  public final static OccurrenceSearchParameter FORMATION = new OccurrenceSearchParameter("FORMATION", String.class);
804
805  /**
806   * The full name of the lithostratigraphic member from which the MaterialEntity was collected.
807   */
808  public final static OccurrenceSearchParameter MEMBER = new OccurrenceSearchParameter("MEMBER", String.class);
809
810  /**
811   * The full name of the lithostratigraphic bed from which the MaterialEntity was collected.
812   */
813  public final static OccurrenceSearchParameter BED = new OccurrenceSearchParameter("BED", String.class);
814
815  /**
816   * A list (concatenated and separated) of identifiers (publication, global unique identifier, URI) of
817   * genetic sequence information associated with the material entity.
818   */
819  public final static OccurrenceSearchParameter ASSOCIATED_SEQUENCES = new OccurrenceSearchParameter("ASSOCIATED_SEQUENCES", String.class);
820
821  /**
822   * Unique GBIF key for the occurrence.
823   */
824  public final static OccurrenceSearchParameter GBIF_ID = new OccurrenceSearchParameter("GBIF_ID", String.class);
825
826  /**
827   * Geological time of an occurrence that searchs in the chronostratigraphy fields.
828   */
829  public final static OccurrenceSearchParameter GEOLOGICAL_TIME = new OccurrenceSearchParameter("GEOLOGICAL_TIME", String.class);
830
831  /**
832   * Searches in the lithostratigraphy fields(bed, formation, group, member).
833   */
834  public final static OccurrenceSearchParameter LITHOSTRATIGRAPHY = new OccurrenceSearchParameter("LITHOSTRATIGRAPHY", String.class);
835
836  /**
837   * Searches in the biostratigraphy fields(lowest and highest biostratigraphy).
838   */
839  public final static OccurrenceSearchParameter BIOSTRATIGRAPHY = new OccurrenceSearchParameter("BIOSTRATIGRAPHY", String.class);
840
841  /**
842   * @return the data type expected for the value of the respective search parameter
843   */
844  public final static OccurrenceSearchParameter DNA_SEQUENCE_ID = new OccurrenceSearchParameter("DNA_SEQUENCE_ID", String.class);
845
846
847  public static OccurrenceSearchParameter[] values(){
848
849    Field[] values = OccurrenceSearchParameter.class.getFields();
850    List<OccurrenceSearchParameter> c = new ArrayList<>();
851    for (Field field: values) {
852      try {
853        c.add((OccurrenceSearchParameter) field.get(OccurrenceSearchParameter.class));
854      } catch (IllegalAccessException e) {
855        throw new RuntimeException(e);
856      }
857    }
858    return c.toArray(new OccurrenceSearchParameter[0]);
859  }
860
861  private Class<?> type;
862  private String name;
863
864  public OccurrenceSearchParameter() {}
865
866  public OccurrenceSearchParameter(String name, Class<?> type) {
867    this.name = name;
868    this.type = type;
869  }
870
871  @Override
872  public String name() {
873    return this.name;
874  }
875
876  public Class<?> getType() {
877    return type;
878  }
879
880  public String getName() {
881    return name;
882  }
883
884  @Override
885  public Class<?> type() {
886    return this.type;
887  }
888
889  @Override
890  public String toString() {
891    return name;
892  }
893
894  @Override
895  public boolean equals(Object o) {
896    if (this == o) return true;
897    if (o == null || getClass() != o.getClass()) return false;
898    OccurrenceSearchParameter that = (OccurrenceSearchParameter) o;
899    return Objects.equals(type, that.type) && Objects.equals(name, that.name);
900  }
901
902  @JsonValue
903  public String getSerializedValue() {
904    return name;
905  }
906
907  @Override
908  public int hashCode() {
909    return Objects.hash(type, name);
910  }
911
912  /**
913   * Lookup a parameter by its name.
914   * @param name the name of the parameter
915   * @return the parameter if found, otherwise empty
916   */
917  public static Optional<OccurrenceSearchParameter> lookup(String name) {
918    String normedType = name.toUpperCase().replaceAll("[. _-]", "");
919    java.lang.reflect.Field[] values = OccurrenceSearchParameter.class.getFields();
920    for (Field field: values) {
921
922      String fieldName = field.getName();
923      String normedVal = fieldName.replaceAll("[. _-]", "");
924      if (normedType.equals(normedVal)) {
925        try {
926          return Optional.of((OccurrenceSearchParameter) field.get(OccurrenceSearchParameter.class));
927        } catch (IllegalAccessException e) {
928          throw new RuntimeException(e);
929        }
930      }
931    }
932    return Optional.empty();
933  }
934
935  public static class OccurrenceSearchParameterKeyDeserializer extends KeyDeserializer {
936
937    @Override
938    public Object deserializeKey(String value, DeserializationContext deserializationContext) throws IOException {
939      Field[] values = OccurrenceSearchParameter.class.getFields();
940      try {
941        for (Field field: values) {
942          if (field.getName().equalsIgnoreCase(value)) {
943            return (OccurrenceSearchParameter) field.get(OccurrenceSearchParameter.class);
944          }
945        }
946      } catch (IllegalAccessException e) {
947        // DO NOTHING
948      }
949      return null;
950    }
951  }
952
953  public static class OccurrenceSearchParameterDeserializer extends JsonDeserializer<OccurrenceSearchParameter> {
954
955    @Override
956    public OccurrenceSearchParameter deserialize(com.fasterxml.jackson.core.JsonParser jsonParser, com.fasterxml.jackson.databind.DeserializationContext deserializationContext) throws IOException, JacksonException {
957
958      Field[] values = OccurrenceSearchParameter.class.getFields();
959      try {
960        String value = jsonParser.getText();
961        for (Field field: values) {
962          if (field.getName().equalsIgnoreCase(value)) {
963            return (OccurrenceSearchParameter) field.get(OccurrenceSearchParameter.class);
964          }
965        }
966
967      } catch (IllegalAccessException e) {
968        // DO NOTHING
969      }
970
971      try {
972        ObjectNode node = jsonParser.getCodec().readTree(jsonParser);
973        String value = node.get("name").asText();
974        for (Field field: values) {
975          if (field.getName().equalsIgnoreCase(value)) {
976            return (OccurrenceSearchParameter) field.get(OccurrenceSearchParameter.class);
977          }
978        }
979      } catch (Exception e) {
980        // DO NOTHING
981      }
982
983      return null;
984    }
985  }
986}