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