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.vocabulary; 015 016import java.util.Arrays; 017import java.util.Collections; 018import java.util.HashMap; 019import java.util.HashSet; 020import java.util.List; 021import java.util.Map; 022import java.util.Set; 023 024import io.swagger.v3.oas.annotations.ExternalDocumentation; 025import io.swagger.v3.oas.annotations.media.Schema; 026 027/** 028 * An ordered taxonomic rank enumeration with the most frequently used values. 029 * Several static methods, lists, sets and maps are provided to help with ordering and lookup from strings. 030 * 031 * Deprecated. 032 * Please use the name parser enum instead. 033 * https://github.com/gbif/name-parser/blob/master/name-parser-api/src/main/java/org/gbif/nameparser/api/Rank.java 034 */ 035@Schema( 036 externalDocs = @ExternalDocumentation( 037 description = "Darwin Core definition", 038 url = "https://rs.tdwg.org/dwc/terms/taxonRank" 039 ) 040) 041@SuppressWarnings("unused") 042// use name parser enum instead: 043// https://github.com/gbif/name-parser/blob/master/name-parser-api/src/main/java/org/gbif/nameparser/api/Rank.java 044@Deprecated 045public enum Rank { 046 047 DOMAIN("dom."), 048 049 SUPERKINGDOM("superreg."), 050 051 KINGDOM("reg."), 052 053 SUBKINGDOM("subreg."), 054 055 INFRAKINGDOM("infrareg."), 056 057 SUPERPHYLUM("superphyl."), 058 059 PHYLUM("phyl."), 060 061 SUBPHYLUM("subphyl."), 062 063 INFRAPHYLUM("infraphyl."), 064 065 SUPERCLASS("supercl."), 066 067 CLASS("cl."), 068 069 SUBCLASS("subcl."), 070 071 INFRACLASS("infracl."), 072 073 PARVCLASS("parvcl."), 074 075 SUPERLEGION("superleg."), 076 077 /** 078 * Sometimes used in zoology, e.g. for birds and mammals 079 */ 080 LEGION("leg."), 081 082 SUBLEGION("subleg."), 083 084 INFRALEGION("infraleg."), 085 086 SUPERCOHORT("supercohort"), 087 088 /** 089 * Sometimes used in zoology, e.g. for birds and mammals 090 */ 091 COHORT("cohort"), 092 093 SUBCOHORT("subcohort"), 094 095 INFRACOHORT("infracohort"), 096 097 MAGNORDER("magnord."), 098 099 SUPERORDER("superord."), 100 101 GRANDORDER("grandord."), 102 103 ORDER("ord."), 104 105 SUBORDER("subord."), 106 107 INFRAORDER("infraord."), 108 109 PARVORDER("parvord."), 110 111 SUPERFAMILY("superfam."), 112 113 FAMILY("fam."), 114 115 SUBFAMILY("subfam."), 116 117 INFRAFAMILY("infrafam."), 118 119 SUPERTRIBE("supertrib."), 120 121 TRIBE("trib."), 122 123 SUBTRIBE("subtrib."), 124 125 INFRATRIBE("infratrib."), 126 127 /** 128 * Used for any other unspecific rank above genera. 129 */ 130 SUPRAGENERIC_NAME("supragen."), 131 132 GENUS("gen."), 133 134 SUBGENUS("subgen."), 135 136 INFRAGENUS("infragen."), 137 138 SECTION("sect."), 139 140 SUBSECTION("subsect."), 141 142 SERIES("ser."), 143 144 SUBSERIES("subser."), 145 146 /** 147 * used for any other unspecific rank below genera and above species. 148 */ 149 INFRAGENERIC_NAME("infrageneric"), 150 151 /** 152 * A loosely defined group of species. 153 * Zoology: Aggregate - a group of species, other than a subgenus, within a genus. An aggregate may be denoted by a group name interpolated in parentheses. 154 * The Berlin/MoreTax model notes: [these] aren't taxonomic ranks but cirumscriptions because on the one hand they are necessary for the concatenation 155 * of the fullname and on the other hand they are necessary for distinguishing the aggregate or species group from the microspecies. 156 */ 157 SPECIES_AGGREGATE("agg."), 158 159 SPECIES("sp."), 160 161 /** 162 * used for any other unspecific rank below species. 163 */ 164 INFRASPECIFIC_NAME("infrasp."), 165 166 /** 167 * The term grex has been coined to expand botanical nomenclature to describe hybrids of orchids. 168 * Grex names are one of the three categories of plant names governed by the International Code of Nomenclature for Cultivated Plants 169 * Within a grex the Groups category can be used to refer to plants by their shared characteristics (rather than by their parentage), 170 * and individual orchid plants can be selected (and propagated) and named as cultivars 171 * https://en.wikipedia.org/wiki/Grex_(horticulture) 172 */ 173 GREX("grex"), 174 175 SUBSPECIES("subsp."), 176 177 /** 178 * Rank in use from the code for cultivated plants. 179 * It does not use a classic rank marker but indicated the Group rank after the actual groups name 180 * For example Rhododendron boothii Mishmiense Group 181 * or Primula Border Auricula Group 182 * 183 * Sometimes authors also used the words "sort", "type", "selections" or "hybrids" instead of Group which is not legal according to the code. 184 */ 185 CULTIVAR_GROUP, 186 187 /** 188 * A group of cultivars. These can be roughly comparable to cultivar groups, but convarieties, unlike cultivar groups, 189 * do not necessarily contain named varieties, and convarieties are members of traditional "Linnaean" ranks. 190 * The ICNCP replaced this term with the term cultivar-group, and convarieties should not be used in modern cultivated plant taxonomy. 191 * 192 * From Spooner et al., Horticultural Reviews 28 (2003): 1-60 193 */ 194 CONVARIETY("convar."), 195 196 /** 197 * used also for any other unspecific rank below subspecies. 198 */ 199 INFRASUBSPECIFIC_NAME("infrasubsp."), 200 201 /** 202 * Botanical legacy rank 203 */ 204 205 PROLES("prol."), 206 207 /** 208 * Botanical legacy rank 209 */ 210 RACE("race"), 211 212 /** 213 * Zoological legacy rank 214 */ 215 NATIO("natio"), 216 217 /** 218 * Zoological legacy rank 219 */ 220 ABERRATION("ab."), 221 222 /** 223 * Zoological legacy rank 224 */ 225 MORPH("morph"), 226 227 VARIETY("var."), 228 229 SUBVARIETY("subvar."), 230 231 FORM("f."), 232 233 SUBFORM("subf."), 234 235 /** 236 * Microbial rank based on pathogenic reactions in one or more hosts. 237 * For recommendations on designating pathovars and use of designations when reviving names see 238 * Dye et al. (1980) Standards for naming pathovars of phytopathogenic bacteria and a list of pathovar names and pathotype strains. 239 * Rev. Plant Pathol. 59:153–168. 240 * See <a href="http://www.ncbi.nlm.nih.gov/books/NBK8812/table/A844/?report=objectonly">Bacteriological Code</a> 241 * See <a href="http://www.isppweb.org/about_tppb_naming.asp">International Standards for Naming Pathovars of Phytopathogenic Bacteria</a> 242 * See <a href="http://sipav.org/main/jpp/index.php/jpp/article/view/682">Demystifying the nomenclature of bacterial plant pathogens</a> 243 * See <a href="http://link.springer.com/chapter/10.1007/978-94-009-3555-6_171">Problems with the Pathovar Concept</a> 244 * For example Pseudomonas syringae pv. lachrymans 245 */ 246 PATHOVAR("pv."), 247 248 /** 249 * Microbial rank based on biochemical or physiological properties. 250 * See <a href="http://www.ncbi.nlm.nih.gov/books/NBK8812/table/A844/?report=objectonly">Bacteriological Code</a> 251 * For example Francisella tularensis biovar tularensis 252 */ 253 BIOVAR("biovar"), 254 255 /** 256 * Microbial rank based on production or amount of production of a particular chemical. 257 * See <a href="http://www.ncbi.nlm.nih.gov/books/NBK8812/table/A844/?report=objectonly">Bacteriological Code</a> 258 * For example Vibrio alginolyticus chemovar iophagus 259 */ 260 CHEMOVAR("chemovar"), 261 262 /** 263 * Microbial rank based on morphological characterislics. 264 * See <a href="http://www.ncbi.nlm.nih.gov/books/NBK8812/table/A844/?report=objectonly">Bacteriological Code</a> 265 * For example Acinetobacter junii morphovar I 266 */ 267 MORPHOVAR("morphovar"), 268 269 /** 270 * Microbial infrasubspecific rank based on reactions to bacteriophage. 271 * See <a href="http://www.ncbi.nlm.nih.gov/books/NBK8812/table/A844/?report=objectonly">Bacteriological Code</a> 272 * For example Staphyloccocus aureus phagovar 42D 273 */ 274 PHAGOVAR("phagovar"), 275 276 /** 277 * Microbial infrasubspecific rank based on antigenic characteristics. 278 * See <a href="http://www.ncbi.nlm.nih.gov/books/NBK8812/table/A844/?report=objectonly">Bacteriological Code</a> 279 * For example Salmonella enterica serovar Dublin 280 */ 281 SEROVAR("serovar"), 282 283 /** 284 * Microbial infrasubspecific rank based on chemical constitution. 285 * See <a href="http://www.ncbi.nlm.nih.gov/books/NBK8812/table/A844/?report=objectonly">Bacteriological Code</a> 286 * For example Thymus vulgaris ct. geraniol 287 */ 288 CHEMOFORM("chemoform"), 289 290 /** 291 * Microbial infrasubspecific rank. 292 * A parasitic, symbiotic, or commensal microorganism distinguished primarily by adaptation to a particular host or habitat. 293 * Named preferably by the scientific name of the host in the genitive. 294 * See <a href="http://www.ncbi.nlm.nih.gov/books/NBK8812/table/A844/?report=objectonly">Bacteriological Code</a> 295 * For example Puccinia graminis f. sp. avenae 296 */ 297 FORMA_SPECIALIS("f.sp."), 298 299 CULTIVAR("cv."), 300 301 /** 302 * A microbial strain. 303 */ 304 STRAIN("strain"), 305 306 /** 307 * Any other rank we cannot map to this enumeration 308 */ 309 OTHER, 310 311 UNRANKED; 312 313 /** 314 * All main Linnean ranks ordered. 315 */ 316 public static final List<Rank> LINNEAN_RANKS = Collections.unmodifiableList( 317 Arrays.asList( 318 KINGDOM, 319 PHYLUM, 320 CLASS, 321 ORDER, 322 FAMILY, 323 GENUS, 324 SPECIES 325 )); 326 327 /** 328 * An ordered list of all ranks that appear in Darwin Core with their own term. 329 */ 330 public static final List<Rank> DWC_RANKS = Collections.unmodifiableList( 331 Arrays.asList( 332 KINGDOM, 333 PHYLUM, 334 CLASS, 335 ORDER, 336 FAMILY, 337 GENUS, 338 SUBGENUS, 339 SPECIES 340 )); 341 342 /** 343 * A set of ranks which cannot clearly be compared to any other rank as they represent rank "ranges". 344 * For example a subgeneric rank is anything below genus, 345 * so one cannot say if its higher or lower than a species for example. 346 */ 347 private static final Set<Rank> UNCOMPARABLE_RANKS = Collections.unmodifiableSet( 348 new HashSet<>(Arrays.asList( 349 INFRAGENERIC_NAME, 350 INFRASPECIFIC_NAME, 351 INFRASUBSPECIFIC_NAME, 352 OTHER, 353 UNRANKED 354 ))); 355 356 private static final Set<Rank> LEGACY_RANKS = Collections.unmodifiableSet( 357 new HashSet<>(Arrays.asList( 358 MORPH, 359 ABERRATION, 360 NATIO, 361 RACE, 362 PROLES, 363 CONVARIETY 364 ))); 365 366 private static final Map<Rank, NomenclaturalCode> RANK2CODE; 367 368 static { 369 Map<Rank, NomenclaturalCode> rank2code = new HashMap<>(); 370 rank2code.put(PARVCLASS, NomenclaturalCode.ZOOLOGICAL); 371 rank2code.put(MAGNORDER, NomenclaturalCode.ZOOLOGICAL); 372 rank2code.put(GRANDORDER, NomenclaturalCode.ZOOLOGICAL); 373 rank2code.put(PARVORDER, NomenclaturalCode.ZOOLOGICAL); 374 rank2code.put(SUPERLEGION, NomenclaturalCode.ZOOLOGICAL); 375 rank2code.put(LEGION, NomenclaturalCode.ZOOLOGICAL); 376 rank2code.put(SUBLEGION, NomenclaturalCode.ZOOLOGICAL); 377 rank2code.put(INFRALEGION, NomenclaturalCode.ZOOLOGICAL); 378 rank2code.put(SUPERCOHORT, NomenclaturalCode.ZOOLOGICAL); 379 rank2code.put(COHORT, NomenclaturalCode.ZOOLOGICAL); 380 rank2code.put(SUBCOHORT, NomenclaturalCode.ZOOLOGICAL); 381 rank2code.put(INFRACOHORT, NomenclaturalCode.ZOOLOGICAL); 382 rank2code.put(MORPH, NomenclaturalCode.ZOOLOGICAL); 383 rank2code.put(ABERRATION, NomenclaturalCode.ZOOLOGICAL); 384 rank2code.put(NATIO, NomenclaturalCode.ZOOLOGICAL); 385 386 rank2code.put(RACE, NomenclaturalCode.BOTANICAL); 387 rank2code.put(PROLES, NomenclaturalCode.BOTANICAL); 388 rank2code.put(SECTION, NomenclaturalCode.BOTANICAL); 389 rank2code.put(SUBSECTION, NomenclaturalCode.BOTANICAL); 390 rank2code.put(SERIES, NomenclaturalCode.BOTANICAL); 391 rank2code.put(SUBSERIES, NomenclaturalCode.BOTANICAL); 392 393 rank2code.put(CULTIVAR, NomenclaturalCode.CULTIVARS); 394 rank2code.put(CULTIVAR_GROUP, NomenclaturalCode.CULTIVARS); 395 rank2code.put(CONVARIETY, NomenclaturalCode.CULTIVARS); 396 rank2code.put(GREX, NomenclaturalCode.CULTIVARS); 397 398 rank2code.put(PATHOVAR, NomenclaturalCode.BACTERIAL); 399 rank2code.put(BIOVAR, NomenclaturalCode.BACTERIAL); 400 rank2code.put(CHEMOVAR, NomenclaturalCode.BACTERIAL); 401 rank2code.put(MORPHOVAR, NomenclaturalCode.BACTERIAL); 402 rank2code.put(PHAGOVAR, NomenclaturalCode.BACTERIAL); 403 rank2code.put(SEROVAR, NomenclaturalCode.BACTERIAL); 404 rank2code.put(CHEMOFORM, NomenclaturalCode.BACTERIAL); 405 rank2code.put(FORMA_SPECIALIS, NomenclaturalCode.BACTERIAL); 406 407 RANK2CODE = Collections.unmodifiableMap(rank2code); 408 } 409 410 private final String marker; 411 412 Rank() { 413 this(null); 414 } 415 416 Rank(String marker) { 417 this.marker = marker; 418 } 419 420 public String getMarker() { 421 return marker; 422 } 423 424 /** 425 * @return true for infraspecific ranks. 426 */ 427 public boolean isInfraspecific() { 428 return this != SPECIES && isSpeciesOrBelow(); 429 } 430 431 /** 432 * @return true for infra subspecific ranks. 433 */ 434 public boolean isInfrasubspecific() { 435 return ordinal() > SUBSPECIES.ordinal() && notOtherOrUnknown(); 436 } 437 438 /** 439 * @return true for rank is below genus. Also incluse species and infraspecific ranks 440 */ 441 public boolean isInfrageneric() { 442 return ordinal() > GENUS.ordinal() && notOtherOrUnknown(); 443 } 444 445 /** 446 * @return true for real infrageneric ranks with an infragenericEpithet below genus and above species aggregate. 447 */ 448 public boolean isInfragenericStrictly() { 449 return isInfrageneric() && ordinal() < SPECIES_AGGREGATE.ordinal(); 450 } 451 452 /** 453 * True for all mayor Linnéan ranks, ie kingdom,phylum,class,order,family,genus and species. 454 */ 455 public boolean isLinnean() { 456 for (Rank r : LINNEAN_RANKS) { 457 if (r == this) { 458 return true; 459 } 460 } 461 return false; 462 } 463 464 public boolean isSpeciesOrBelow() { 465 return ordinal() >= SPECIES.ordinal() && notOtherOrUnknown(); 466 } 467 468 public boolean isSpeciesAggregateOrBelow() { 469 return ordinal() >= SPECIES_AGGREGATE.ordinal() && notOtherOrUnknown(); 470 } 471 472 public boolean notOtherOrUnknown() { 473 return this != OTHER && this != UNRANKED; 474 } 475 476 /** 477 * @return true if the rank is above genus. 478 */ 479 public boolean isSuprageneric() { 480 return ordinal() < GENUS.ordinal(); 481 } 482 483 /** 484 * @return true if the rank is above rank species. 485 */ 486 public boolean isSupraspecific() { 487 return ordinal() < SPECIES.ordinal(); 488 } 489 490 /** 491 * True for names of informal ranks that represent a range of ranks really and therefore cannot safely be compared to 492 * other ranks in all cases. 493 * Example ranks are INFRASPECIFIC_NAME or INFRAGENERIC_NAME 494 * 495 * @return true if uncomparable 496 */ 497 public boolean isUncomparable() { 498 return UNCOMPARABLE_RANKS.contains(this); 499 } 500 501 /** 502 * @return true if the rank is considered a legacy rank not used anymore in current nomenclature. 503 */ 504 public boolean isLegacy() { 505 return LEGACY_RANKS.contains(this); 506 } 507 508 /** 509 * @return the nomenclatural code if the rank is restricted to just one code or null otherwise 510 */ 511 public NomenclaturalCode isRestrictedToCode() { 512 return RANK2CODE.get(this); 513 } 514 515 /** 516 * @return true if this rank is higher than the given other 517 */ 518 public boolean higherThan(Rank other) { 519 return ordinal() < other.ordinal(); 520 } 521}