added ranks proles, race and sublusus #2793 and updated TermUpdater
[cdmlib.git] / cdmlib-model / src / main / java / eu / etaxonomy / cdm / model / name / Rank.java
1 /**
2 * Copyright (C) 2007 EDIT
3 * European Distributed Institute of Taxonomy
4 * http://www.e-taxonomy.eu
5 *
6 * The contents of this file are subject to the Mozilla Public License Version 1.1
7 * See LICENSE.TXT at the top of this package for the full license terms.
8 */
9
10 package eu.etaxonomy.cdm.model.name;
11
12 import java.util.HashMap;
13 import java.util.List;
14 import java.util.Map;
15 import java.util.UUID;
16
17 import javax.persistence.Entity;
18 import javax.persistence.Enumerated;
19 import javax.persistence.Transient;
20 import javax.validation.constraints.NotNull;
21 import javax.xml.bind.annotation.XmlAccessType;
22 import javax.xml.bind.annotation.XmlAccessorType;
23 import javax.xml.bind.annotation.XmlAttribute;
24 import javax.xml.bind.annotation.XmlType;
25
26 import org.apache.log4j.Logger;
27 import org.hibernate.envers.Audited;
28 import org.hibernate.search.annotations.Indexed;
29
30 import eu.etaxonomy.cdm.common.CdmUtils;
31 import eu.etaxonomy.cdm.model.common.DefinedTermBase;
32 import eu.etaxonomy.cdm.model.common.Language;
33 import eu.etaxonomy.cdm.model.common.OrderedTermBase;
34 import eu.etaxonomy.cdm.model.common.Representation;
35 import eu.etaxonomy.cdm.model.common.TermType;
36 import eu.etaxonomy.cdm.model.common.TermVocabulary;
37 import eu.etaxonomy.cdm.strategy.exceptions.UnknownCdmTypeException;
38
39 /**
40 * The class representing the taxonomical ranks (like "Family", "Genus" or
41 * "Species") used for {@link TaxonNameBase taxon names} across all {@link NomenclaturalCode nomenclatural codes}
42 * for bacteria (ICNB), viruses (ICVCN), plants and fungi (ICBN),
43 * cultivars (ICNCP) and animals (ICZN).
44 * <P>
45 * A standard (ordered) list of taxonomical rank instances will be automatically
46 * created as the project starts. But this class allows to extend this standard
47 * list by creating new instances of additional taxonomical ranks if needed.
48 * <P>
49 * This class corresponds to: <ul>
50 * <li> TaxonRankTerm according to the TDWG ontology
51 * <li> TaxonomicRankEnum according to the TCS
52 * <li> Rank according to the ABCD schema
53 * </ul>
54 *
55 * @author m.doering
56 * @version 1.0
57 * @created 08-Nov-2007 13:06:46
58 */
59 @XmlAccessorType(XmlAccessType.FIELD)
60 @XmlType(name = "Rank")
61 @Entity
62 @Indexed(index = "eu.etaxonomy.cdm.model.common.DefinedTermBase")
63 @Audited
64 public class Rank extends OrderedTermBase<Rank> {
65 private static final long serialVersionUID = -8648081681348758485L;
66 private static final Logger logger = Logger.getLogger(Rank.class);
67
68 private static final UUID uuidEmpire = UUID.fromString("ac470211-1586-4b24-95ca-1038050b618d");
69 private static final UUID uuidDomain = UUID.fromString("ffca6ec8-8b88-417b-a6a0-f7c992aac19b");
70 private static final UUID uuidSuperkingdom = UUID.fromString("64223610-7625-4cfd-83ad-b797bf7f0edd");
71 private static final UUID uuidKingdom = UUID.fromString("fbe7109d-66b3-498c-a697-c6c49c686162");
72 private static final UUID uuidSubkingdom = UUID.fromString("a71bd9d8-f3ab-4083-afb5-d89315d71655");
73 private static final UUID uuidInfrakingdom = UUID.fromString("1e37930c-86cf-44f6-90fd-7822928df260");
74 private static final UUID uuidSuperphylum = UUID.fromString("0d0cecb1-e254-4607-b210-6801e7ecbb04");
75 private static final UUID uuidPhylum = UUID.fromString("773430d2-76b4-438c-b817-97a543a33287");
76 private static final UUID uuidSubphylum = UUID.fromString("23a9b6ff-9408-49c9-bd9e-7a2ca5ab4725");
77 private static final UUID uuidInfraphylum = UUID.fromString("1701de3a-7693-42a5-a2d3-42697f944190");
78 private static final UUID uuidSuperdivision = UUID.fromString("a735a48f-4fc8-49a7-ae0c-6a984f658131");
79 private static final UUID uuidDivision = UUID.fromString("7e56f5cc-123a-4fd1-8cbb-6fd80358b581");
80 private static final UUID uuidSubdivision = UUID.fromString("931c840f-7a6b-4d76-ad38-bfdd77d7b2e8");
81 private static final UUID uuidInfradivision = UUID.fromString("c0ede273-be52-4dee-b411-66ee08d30c94");
82 private static final UUID uuidSuperclass = UUID.fromString("e65b4e1a-21ec-428d-9b9f-e87721ab967c");
83 private static final UUID uuidClass = UUID.fromString("f23d14c4-1d34-4ee6-8b4e-eee2eb9a3daf");
84 private static final UUID uuidSubclass = UUID.fromString("8cb26733-e2f5-46cb-ab5c-f99254f877aa");
85 private static final UUID uuidInfraclass = UUID.fromString("ad23cfda-879a-4021-8629-c54d27caf717");
86 private static final UUID uuidSuperorder = UUID.fromString("c8c67a22-301a-4219-b882-4a49121232ff");
87 private static final UUID uuidOrder = UUID.fromString("b0785a65-c1c1-4eb4-88c7-dbd3df5aaad1");
88 private static final UUID uuidSuborder = UUID.fromString("768ad378-fa85-42ab-b668-763225832f57");
89 private static final UUID uuidInfraorder = UUID.fromString("84099182-a6f5-47d7-8586-33c9e9955a10");
90 private static final UUID uuidSectionZoology = UUID.fromString("691d371e-10d7-43f0-93db-3d7fa1a62c54");
91 private static final UUID uuidSubsectionZoology = UUID.fromString("0ed32d28-adc4-4303-a9ca-68e2acd67e33");
92 private static final UUID uuidSuperfamily = UUID.fromString("2cfa510a-dcea-4a03-b66a-b1528f9b0796");
93 private static final UUID uuidFamily = UUID.fromString("af5f2481-3192-403f-ae65-7c957a0f02b6");
94 private static final UUID uuidSubfamily = UUID.fromString("862526ee-7592-4760-a23a-4ff3641541c5");
95 private static final UUID uuidInfrafamily = UUID.fromString("c3f2e3bb-6eef-4a26-9fb7-b14f4c8c5e4f");
96 private static final UUID uuidSupertribe = UUID.fromString("11e94828-8c61-499b-87d6-1de35ce2c51c");
97 private static final UUID uuidTribe = UUID.fromString("4aa6890b-0363-4899-8d7c-ee0cb78e6166");
98 private static final UUID uuidSubtribe = UUID.fromString("ae41ecc5-5165-4126-9d24-79939ae5d822");
99 private static final UUID uuidInfratribe = UUID.fromString("1ec02e8f-f2b7-4c65-af9f-b436b34c79a3");
100 private static final UUID uuidSupragenericTaxon = UUID.fromString("1fdc0b93-c354-441a-8406-091e0303ff5c");
101 public static final UUID uuidGenus = UUID.fromString("1b11c34c-48a8-4efa-98d5-84f7f66ef43a");
102 private static final UUID uuidSubgenus = UUID.fromString("78786e16-2a70-48af-a608-494023b91904");
103 private static final UUID uuidInfragenus = UUID.fromString("a9972969-82cd-4d54-b693-a096422f13fa");
104 private static final UUID uuidSectionBotany = UUID.fromString("3edff68f-8527-49b5-bf91-7e4398bb975c");
105 private static final UUID uuidSubsectionBotany = UUID.fromString("d20f5b61-d463-4448-8f8a-c1ff1f262f59");
106 private static final UUID uuidSeries = UUID.fromString("d7381ecf-48f8-429b-9c54-f461656978cd");
107 private static final UUID uuidSubseries = UUID.fromString("80c9a263-f4db-4a13-b6c2-b7fec1aa1200");
108 private static final UUID uuidSpeciesAggregate = UUID.fromString("1ecae058-4217-4f75-9c27-6d8ba099ac7a");
109 private static final UUID uuidSpeciesGroup = UUID.fromString("d1988a11-292b-46fa-8fb7-bc64ea6d8fc6");
110 public static final UUID uuidInfragenericTaxon = UUID.fromString("41bcc6ac-37d3-4fd4-bb80-3cc5b04298b9");
111 public static final UUID uuidSpecies = UUID.fromString("b301f787-f319-4ccc-a10f-b4ed3b99a86d");
112 private static final UUID uuidSubspecificAggregate = UUID.fromString("72c248b9-027d-4402-b375-dd4f0850c9ad");
113 private static final UUID uuidSubspecies = UUID.fromString("462a7819-8b00-4190-8313-88b5be81fad5");
114 private static final UUID uuidInfraspecies = UUID.fromString("f28ebc9e-bd50-4194-9af1-42f5cb971a2c");
115 private static final UUID uuidNatio = UUID.fromString("965f2f38-7f97-4270-ab5a-1999bf050a22");
116 private static final UUID uuidVariety = UUID.fromString("d5feb6a5-af5c-45ef-9878-bb4f36aaf490");
117 private static final UUID uuidBioVariety = UUID.fromString("a3a364cb-1a92-43fc-a717-3c44980a0991");
118 private static final UUID uuidPathoVariety = UUID.fromString("2f4f4303-a099-47e3-9048-d749d735423b");
119 private static final UUID uuidSubvariety = UUID.fromString("9a83862a-7aee-480c-a98d-4bceaf8712ca");
120 private static final UUID uuidSubsubvariety = UUID.fromString("bff22f84-553a-4429-a4e7-c4b3796c3a18");
121
122 private static final UUID uuidProles = UUID.fromString("8810d1ba-6a34-4ae3-a355-919ccd1cd1a5");
123 private static final UUID uuidRace = UUID.fromString("196dee39-cfd8-4460-8bf0-88b83da27f62");
124 private static final UUID uuidSublusus = UUID.fromString("1fafa596-a8e7-4e62-a378-3cc8cb3627ca");
125
126 private static final UUID uuidConvar = UUID.fromString("2cc740c9-cebb-43c8-9b06-1bef79e6a56a");
127 private static final UUID uuidForm = UUID.fromString("0461281e-458a-47b9-8d41-19a3d39356d5");
128 private static final UUID uuidSpecialForm = UUID.fromString("bed20aee-2f5a-4635-9c02-eff06246d067");
129 private static final UUID uuidSubform = UUID.fromString("47cfc5b0-0fb7-4ceb-b61d-e1dd8de8b569");
130 private static final UUID uuidSubsubform = UUID.fromString("1c8ac389-4349-4ae0-87be-7239f6635068");
131 public static final UUID uuidInfraspecificTaxon = UUID.fromString("eb75c27d-e154-4570-9d96-227b2df60474");
132 private static final UUID uuidCandidate = UUID.fromString("ead9a1f5-dfd4-4de2-9121-70a47accb10b");
133 private static final UUID uuidDenominationClass = UUID.fromString("49bdf74a-2170-40ed-8be2-887a0db517bf");
134 private static final UUID uuidGrex = UUID.fromString("08dcb4ff-ac58-48a3-93af-efb3d836ac84");
135 private static final UUID uuidGraftChimaera = UUID.fromString("6b4063bc-f934-4796-9bf3-0ef3aea5c1cb");
136 private static final UUID uuidCultivarGroup = UUID.fromString("d763e7d3-e7de-4bb1-9d75-225ca6948659");
137 private static final UUID uuidCultivar = UUID.fromString("5e98415b-dc6e-440b-95d6-ea33dbb39ad0");
138 private static final UUID uuidUnknownRank = UUID.fromString("5c4d6755-2cf6-44ca-9220-cccf8881700b");
139
140 private static Map<String, UUID> abbrevMap = null;
141 private static Map<String, UUID> labelMap = null;
142
143 protected static Map<UUID, Rank> termMap = null;
144
145 //*********************** Factory methods ********************************************/
146
147 // /**
148 // * Creates a new empty rank.
149 // *
150 // * @see #NewInstance(String, String, String)
151 // */
152 // private static Rank NewInstance(){
153 // return new Rank();
154 // }
155
156 /**
157 * Creates an additional rank with a description (in the {@link Language#DEFAULT() default language}),
158 * a label and a label abbreviation.
159 *
160 * @param term the string (in the default language) describing the
161 * new rank to be created
162 * @param label the string identifying the new rank to be created
163 * @param labelAbbrev the string identifying (in abbreviated form) the
164 * new rank to be created
165 * @see #NewInstance()
166 */
167 public static Rank NewInstance(RankClass rankClass, String term, String label, String labelAbbrev){
168 return new Rank(rankClass, term, label, labelAbbrev);
169 }
170
171 /**
172 * The {@link RankClass rank class} of a rank. It is usually needed for correct formatting of a
173 * rank by using e.g. isSupraGeneric(). Prior to v3.3 this was computed by comparison of ranks.
174 */
175 @XmlAttribute(name ="RankClass")
176 @NotNull
177 @Enumerated //TODO use UserType
178 private RankClass rankClass;
179
180
181 // ********************* CONSTRUCTORS ************************************+/
182
183 //for hibernate use only
184 protected Rank() {}
185
186 /**
187 * Class constructor: creates an additional rank instance with a description
188 * (in the {@link eu.etaxonomy.cdm.model.common.Language#DEFAULT() default language}), a label and a label abbreviation.
189 *
190 * @param term the string (in the default language) describing the
191 * new rank to be created
192 * @param label the string identifying the new rank to be created
193 * @param labelAbbrev the string identifying (in abbreviated form) the
194 * new rank to be created
195 * @see #Rank()
196 */
197 protected Rank(RankClass rankClass, String term, String label, String labelAbbrev) {
198 super(TermType.Rank, term, label, labelAbbrev);
199 this.rankClass = rankClass;
200 }
201
202
203 //********* METHODS **************************************/
204
205 /* (non-Javadoc)
206 * @see eu.etaxonomy.cdm.model.common.DefinedTermBase#resetTerms()
207 */
208 @Override
209 public void resetTerms(){
210 termMap = null;
211 }
212
213
214
215 protected static Rank getTermByUuid(UUID uuid){
216 if (termMap == null){
217 return null; //better return null then initialize the termMap in an unwanted way
218 }
219 return (Rank)termMap.get(uuid);
220 }
221
222 public static final Rank EMPIRE(){
223 return getTermByUuid(uuidEmpire);
224 }
225 public static final Rank DOMAIN(){
226 return getTermByUuid(uuidDomain);
227 }
228 public static final Rank SUPERKINGDOM(){
229 return getTermByUuid(uuidSuperkingdom);
230 }
231 public static final Rank KINGDOM(){
232 return getTermByUuid(uuidKingdom);
233 }
234 public static final Rank SUBKINGDOM(){
235 return getTermByUuid(uuidSubkingdom);
236 }
237 public static final Rank INFRAKINGDOM(){
238 return getTermByUuid(uuidInfrakingdom);
239 }
240 public static final Rank SUPERPHYLUM(){
241 return getTermByUuid(uuidSuperphylum);
242 }
243 public static final Rank PHYLUM(){
244 return getTermByUuid(uuidPhylum);
245 }
246 public static final Rank SUBPHYLUM(){
247 return getTermByUuid(uuidSubphylum);
248 }
249 public static final Rank INFRAPHYLUM(){
250 return getTermByUuid(uuidInfraphylum);
251 }
252 public static final Rank SUPERDIVISION(){
253 return getTermByUuid(uuidSuperdivision);
254 }
255 public static final Rank DIVISION(){
256 return getTermByUuid(uuidDivision);
257 }
258 public static final Rank SUBDIVISION(){
259 return getTermByUuid(uuidSubdivision);
260 }
261 public static final Rank INFRADIVISION(){
262 return getTermByUuid(uuidInfradivision);
263 }
264 public static final Rank SUPERCLASS(){
265 return getTermByUuid(uuidSuperclass);
266 }
267 public static final Rank CLASS(){
268 return getTermByUuid(uuidClass);
269 }
270 public static final Rank SUBCLASS(){
271 return getTermByUuid(uuidSubclass);
272 }
273 public static final Rank INFRACLASS(){
274 return getTermByUuid(uuidInfraclass);
275 }
276 public static final Rank SUPERORDER(){
277 return getTermByUuid(uuidSuperorder);
278 }
279 public static final Rank ORDER(){
280 return getTermByUuid(uuidOrder);
281 }
282 public static final Rank SUBORDER(){
283 return getTermByUuid(uuidSuborder);
284 }
285 public static final Rank INFRAORDER(){
286 return getTermByUuid(uuidInfraorder);
287 }
288 public static final Rank SUPERFAMILY(){
289 return getTermByUuid(uuidSuperfamily);
290 }
291 public static final Rank FAMILY(){
292 return getTermByUuid(uuidFamily);
293 }
294 public static final Rank SUBFAMILY(){
295 return getTermByUuid(uuidSubfamily);
296 }
297 public static final Rank INFRAFAMILY(){
298 return getTermByUuid(uuidInfrafamily);
299 }
300 public static final Rank SUPERTRIBE(){
301 return getTermByUuid(uuidSupertribe);
302 }
303 public static final Rank TRIBE(){
304 return getTermByUuid(uuidTribe);
305 }
306 public static final Rank SUBTRIBE(){
307 return getTermByUuid(uuidSubtribe);
308 }
309 public static final Rank INFRATRIBE(){
310 return getTermByUuid(uuidInfratribe);
311 }
312 public static final Rank SUPRAGENERICTAXON(){
313 return getTermByUuid(uuidSupragenericTaxon);
314 }
315 public static final Rank GENUS(){
316 return getTermByUuid(uuidGenus);
317 }
318 public static final Rank SUBGENUS(){
319 return getTermByUuid(uuidSubgenus);
320 }
321 public static final Rank INFRAGENUS(){
322 return getTermByUuid(uuidInfragenus);
323 }
324 public static final Rank SECTION_BOTANY(){
325 return getTermByUuid(uuidSectionBotany);
326 }
327 public static final Rank SUBSECTION_BOTANY(){
328 return getTermByUuid(uuidSubsectionBotany);
329 }
330 public static final Rank SECTION_ZOOLOGY(){
331 return getTermByUuid(uuidSectionZoology);
332 }
333 public static final Rank SUBSECTION_ZOOLOGY(){
334 return getTermByUuid(uuidSubsectionZoology);
335 }
336 public static final Rank SERIES(){
337 return getTermByUuid(uuidSeries);
338 }
339 public static final Rank SUBSERIES(){
340 return getTermByUuid(uuidSubseries);
341 }
342 public static final Rank SPECIESAGGREGATE(){
343 return getTermByUuid(uuidSpeciesAggregate);
344 }
345 public static final Rank SPECIESGROUP(){
346 return getTermByUuid(uuidSpeciesGroup);
347 }
348 /**
349 * 'Unranked infrageneric'. An infrageneric rank which is on purpose not further defined.
350 * This sometimes holds for names from the 19th century.
351 */
352 public static final Rank INFRAGENERICTAXON(){
353 return getTermByUuid(uuidInfragenericTaxon);
354 }
355 public static final Rank SPECIES(){
356 return getTermByUuid(uuidSpecies);
357 }
358 public static final Rank SUBSPECIFICAGGREGATE(){
359 return getTermByUuid(uuidSubspecificAggregate);
360 }
361 public static final Rank SUBSPECIES(){
362 return getTermByUuid(uuidSubspecies);
363 }
364 public static final Rank INFRASPECIES(){
365 return getTermByUuid(uuidInfraspecies);
366 }
367 public static final Rank VARIETY(){
368 return getTermByUuid(uuidVariety);
369 }
370 public static final Rank BIOVARIETY(){
371 return getTermByUuid(uuidBioVariety);
372 }
373 public static final Rank PATHOVARIETY(){
374 return getTermByUuid(uuidPathoVariety);
375 }
376 public static final Rank SUBVARIETY(){
377 return getTermByUuid(uuidSubvariety);
378 }
379 public static final Rank SUBSUBVARIETY(){
380 return getTermByUuid(uuidSubsubvariety );
381 }
382 public static final Rank PROLES(){
383 return getTermByUuid(uuidProles);
384 }
385 public static final Rank RACE(){
386 return getTermByUuid(uuidRace);
387 }
388 public static final Rank SUBLUSUS(){
389 return getTermByUuid(uuidSublusus);
390 }
391
392 public static final Rank CONVAR(){
393 return getTermByUuid(uuidConvar);
394 }
395 public static final Rank FORM(){
396 return getTermByUuid(uuidForm);
397 }
398 public static final Rank SPECIALFORM(){
399 return getTermByUuid(uuidSpecialForm);
400 }
401 public static final Rank SUBFORM(){
402 return getTermByUuid(uuidSubform);
403 }
404 public static final Rank SUBSUBFORM(){
405 return getTermByUuid(uuidSubsubform);
406 }
407 /**
408 * 'Unranked infraspecific'. An infraspecific rank which is on purpose not further defined.
409 * This sometimes holds for names from the 19th century.
410 */
411 public static final Rank INFRASPECIFICTAXON(){
412 return getTermByUuid(uuidInfraspecificTaxon);
413 }
414 public static final Rank CANDIDATE(){
415 return getTermByUuid(uuidCandidate);
416 }
417 public static final Rank DENOMINATIONCLASS(){
418 return getTermByUuid(uuidDenominationClass);
419 }
420 public static final Rank GREX(){
421 return getTermByUuid(uuidGrex);
422 }
423 public static final Rank GRAFTCHIMAERA(){
424 return getTermByUuid(uuidGraftChimaera);
425 }
426 public static final Rank CULTIVARGROUP(){
427 return getTermByUuid(uuidCultivarGroup);
428 }
429 public static final Rank CULTIVAR(){
430 return getTermByUuid(uuidCultivar);
431 }
432 public static final Rank UNKNOWN_RANK(){
433 return getTermByUuid(uuidUnknownRank);
434 }
435 public static final Rank NATIO(){
436 return getTermByUuid(uuidNatio);
437 }
438 /**
439 * @see #INFRASPECIFICTAXON()
440 */
441 public static final Rank UNRANKED_INFRASPECIFIC(){
442 return getTermByUuid(uuidInfraspecificTaxon);
443 }
444 /**
445 * @see #INFRAGENERICTAXON()
446 */
447 public static final Rank UNRANKED_INFRAGENERIC(){
448 return getTermByUuid(uuidInfragenericTaxon);
449 }
450
451 // ************************ GETTER / SETTER **********************************/
452
453 public RankClass getRankClass() {
454 return rankClass;
455 }
456
457 public void setRankClass(RankClass rankClass) {
458 this.rankClass = rankClass;
459 }
460
461 // ******************************** METHODS ***************************************/
462
463 /**
464 * Returns the boolean value indicating whether <i>this</i> rank is higher than
465 * the genus rank (true) or not (false). Returns false if <i>this</i> rank is null.
466 *
467 * @see #isGenus()
468 * @see #isInfraGeneric()
469 * @see #isSpecies()
470 * @see #isInfraSpecific()
471 */
472 @Transient
473 public boolean isSupraGeneric(){
474 return this.rankClass.equals(RankClass.Suprageneric); // (this.isHigher(Rank.GENUS()));
475 }
476
477 /**
478 * Returns the boolean value indicating whether <i>this</i> rank is the genus rank
479 * (true) or not (false). Returns false if <i>this</i> rank is null.
480 *
481 * @see #isSupraGeneric()
482 * @see #isInfraGeneric()
483 * @see #isSpecies()
484 * @see #isInfraSpecific()
485 */
486 @Transient
487 public boolean isGenus(){
488 return this.rankClass.equals(RankClass.Genus); // (this.equals(Rank.GENUS()));
489 }
490
491 /**
492 * Returns the boolean value indicating whether <i>this</i> rank is higher than the
493 * species rank and lower than the genus rank (true) or not (false). Species groups or
494 * aggregates are also handled as infrageneric ranks.
495 * Returns false if <i>this</i> rank is null.
496 *
497 * @see #isSupraGeneric()
498 * @see #isGenus()
499 * @see #isSpeciesAggregate()
500 * @see #isSpecies()
501 * @see #isInfraSpecific()
502 */
503 @Transient
504 public boolean isInfraGeneric(){
505 return this.rankClass.equals(RankClass.Infrageneric) || this.rankClass.equals(RankClass.SpeciesGroup) ; //(this.isLower(Rank.GENUS()) && this.isHigher(Rank.SPECIES()));
506 }
507
508 /**
509 * Returns true if this rank indicates a rank that aggregates species
510 * like species aggregates or species groups, false otherwise. This methods
511 * currently returns false for all user defined ranks.
512 * @return
513 */
514 @Transient
515 public boolean isSpeciesAggregate(){
516 return this.rankClass.equals(RankClass.SpeciesGroup); //(this.equals(Rank.SPECIESAGGREGATE()) || (this.isLower(Rank.SPECIESAGGREGATE()) && this.isHigher(Rank.SPECIES())));
517 }
518
519 /**
520 * Returns the boolean value indicating whether <i>this</i> rank is the species
521 * rank (true) or not (false). Returns false if <i>this</i> rank is null.
522 *
523 * @see #isSupraGeneric()
524 * @see #isGenus()
525 * @see #isInfraGeneric()
526 * @see #isInfraSpecific()
527 */
528 @Transient
529 public boolean isSpecies(){
530 return this.rankClass.equals(RankClass.Species); //(this.equals(Rank.SPECIES()));
531 }
532
533 /**
534 * Returns the boolean value indicating whether <i>this</i> rank is lower than the
535 * species rank (true) or not (false). Returns false if <i>this</i> rank is null.
536 *
537 * @see #isSupraGeneric()
538 * @see #isGenus()
539 * @see #isInfraGeneric()
540 * @see #isSpecies()
541 */
542 @Transient
543 public boolean isInfraSpecific(){
544 return this.rankClass.equals(RankClass.Infraspecific); // (this.isLower(Rank.SPECIES()));
545 }
546
547
548 /**
549 * Returns the rank identified through a name (abbreviated or not).
550 * Preliminary implementation for BotanicalNameParser.
551 *
552 * @param strRank the string identifying the rank
553 * @return the rank
554 */
555 public static Rank getRankByNameOrAbbreviation(String strRank) throws UnknownCdmTypeException{
556 return getRankByNameOrAbbreviation(strRank, false);
557 }
558
559 /**
560 * Returns the rank identified through a name (abbreviated or not) for a given nomenclatural code.
561 * Preliminary implementation for BotanicalNameParser.
562 *
563 * @param strRank the string identifying the rank
564 * @param nc the nomenclatural code
565 * @return the rank
566 */
567 public static Rank getRankByNameOrAbbreviation(String strRank, NomenclaturalCode nc)
568 throws UnknownCdmTypeException{
569 return getRankByNameOrAbbreviation(strRank, nc, false);
570 }
571
572 // TODO
573 // Preliminary implementation for BotanicalNameParser.
574 // not yet complete
575 /**
576 * Returns the rank identified through a name (abbreviated or not).
577 * Preliminary implementation for BotanicalNameParser.
578 *
579 * @param strRank the string identifying the rank
580 * @param useUnknown if true the rank UNKNOWN_RANK is returned if the abbrev is
581 * unknown or not yet implemented
582 * @return the rank
583 */
584 public static Rank getRankByNameOrAbbreviation(String strRank, boolean useUnknown)
585 throws UnknownCdmTypeException{
586 try {
587 return getRankByAbbreviation(strRank);
588 } catch (UnknownCdmTypeException e) {
589 return getRankByName(strRank, useUnknown);
590 }
591 }
592
593 // TODO
594 // Preliminary implementation for BotanicalNameParser.
595 // not yet complete
596 /**
597 * Returns the rank identified through a name (abbreviated or not).
598 * Preliminary implementation for BotanicalNameParser.
599 *
600 * @param strRank the string identifying the rank
601 * @param nc the nomenclatural code
602 * @param useUnknown if true the rank UNKNOWN_RANK is returned if the abbrev is
603 * unknown or not yet implemented
604 * @return the rank
605 */
606 public static Rank getRankByNameOrAbbreviation(String strRank, NomenclaturalCode nc, boolean useUnknown)
607 throws UnknownCdmTypeException{
608 try {
609 return getRankByAbbreviation(strRank, nc);
610 } catch (UnknownCdmTypeException e) {
611 return getRankByName(strRank, nc, useUnknown);
612 }
613 }
614
615 /**
616 * Returns the rank identified through an abbreviated name.
617 * Preliminary implementation for BotanicalNameParser.<BR>
618 * Note: For abbrev = "[unranked]" the result is undefined.
619 * It maybe the infrageneric unranked or the infraspecific unranked.
620 * You need to define by context which one is correct.
621 *
622 * @param abbrev the string for the name abbreviation
623 * @return the rank
624 */
625 public static Rank getRankByAbbreviation(String abbrev)
626 throws UnknownCdmTypeException{
627 return getRankByAbbreviation(abbrev, false);
628 }
629
630 /**
631 * Returns the rank identified through an abbreviated name for a given nomenclatural code.
632 * See also {@link #getRankByAbbreviation(String, boolean)}
633 *
634 * @param abbrev the string for the name abbreviation
635 * @param nc the nomenclatural code
636 * @return the rank
637 */
638 public static Rank getRankByAbbreviation(String abbrev, NomenclaturalCode nc) throws UnknownCdmTypeException{
639 return getRankByAbbreviation(abbrev, nc, false);
640 }
641
642 // TODO
643 // Preliminary implementation for BotanicalNameParser.
644 // not yet complete
645 /**
646 * Returns the rank identified through an abbreviated representation.
647 * At the moment it uses the English abbreviations (being Latin because
648 * we do not have Latin representations yet.
649 * TODO
650 * If no according abbreviation is available it throws either an UnknownCdmTypeException
651 * or an #Rank.UNKNOWN() object depending on the useUnknown flag.
652 *
653 * @param abbrev the string for the name abbreviation
654 * @param useUnknown if true the rank UNKNOWN_RANK is returned if the abbrev is
655 * unknown or not yet existent
656 * @return the rank
657 */
658 public static Rank getRankByAbbreviation(String abbrev, boolean useUnknown) throws UnknownCdmTypeException{
659 Rank result = null;
660 if (abbrev == null){
661 throw new NullPointerException("Abbrev is NULL in getRankByAbbreviation");
662 }
663 if (abbrev.trim().equals("")){
664 //handle empty abbrev as unknown
665 abbrev = "oija�m��";
666 }
667 if (abbrevMap == null){
668 return null;
669 }
670 UUID uuid = abbrevMap.get(abbrev);
671 if (uuid != null ){
672 result = getTermByUuid(uuid);
673 }
674 if (result != null){
675 return result;
676 }else {
677 if (abbrev == null){
678 abbrev = "(null)";
679 }
680 if (useUnknown){
681 logger.info("Unknown rank name: " + abbrev + ". Rank 'UNKNOWN_RANK' created instead");
682 return Rank.UNKNOWN_RANK();
683 }else{
684 throw new UnknownCdmTypeException("Unknown rank abbreviation: " + abbrev);
685 }
686 }
687 }
688
689 // TODO
690 // Preliminary implementation to cover Botany and Zoology.
691 /**
692 * Returns the rank identified through an abbreviated name for a given nomenclatural code.
693 * Preliminary implementation for ICBN and ICZN.
694 * See also {@link #getRankByAbbreviation(String, boolean)}
695
696 *
697 * @param abbrev the string for the name abbreviation
698 * @param nc the nomenclatural code
699 * @param useUnknown if true the rank UNKNOWN_RANK is returned if the abbrev is
700 * unknown or not yet implemented
701 * @return the rank
702 */
703 public static Rank getRankByAbbreviation(String abbrev, NomenclaturalCode nc, boolean useUnknown)
704 throws UnknownCdmTypeException{
705
706 if (nc != null && nc.equals(NomenclaturalCode.ICZN)) {
707 if (abbrev != null){
708 if (abbrev.equalsIgnoreCase("sect.")) {
709 return Rank.SECTION_ZOOLOGY();
710 } else if (abbrev.equalsIgnoreCase("subsect.")) {
711 return Rank.SUBSECTION_ZOOLOGY();
712 }
713 }
714 }
715 return getRankByAbbreviation(abbrev, useUnknown);
716 }
717
718 // TODO
719 // Preliminary implementation for BotanicalNameParser.
720 // not yet complete
721 /**
722 * Returns the rank identified through a name.
723 * Preliminary implementation for BotanicalNameParser.
724 *
725 * @param rankName the string for the name of the rank
726 * @return the rank
727 */
728 public static Rank getRankByName(String rankName) throws UnknownCdmTypeException{
729 return getRankByName(rankName, false);
730 }
731
732
733 // TODO
734 // Preliminary implementation for ICBN and ICZN.
735 // not yet complete
736 /**
737 * Returns the rank identified through a name for a given nomenclatural code.
738 * Preliminary implementation for ICBN and ICZN.
739 *
740 * @param rankName the string for the name of the rank
741 * @param nc the nomenclatural code
742 * @return the rank
743 */
744 public static Rank getRankByName(String rankName, NomenclaturalCode nc) throws UnknownCdmTypeException{
745 return getRankByName(rankName, nc, false);
746 }
747
748 /**
749 * Returns the rank identified through a name.
750 * Preliminary implementation for BotanicalNameParser.
751 * TODO At the moment we do not have Latin representations yet.
752 *
753 * @param rankName the string for the name of the rank
754 * @param useUnknown if true the rank UNKNOWN_RANK is returned if the rank name is
755 * unknown or not yet implemented
756 * @return the rank
757 */
758 public static Rank getRankByName(String rankName, boolean useUnknown)
759 throws UnknownCdmTypeException{
760 if (rankName.equalsIgnoreCase("Regnum")){ return Rank.KINGDOM();
761 }else if (rankName.equalsIgnoreCase("Subregnum")){ return Rank.SUBKINGDOM();
762 }else if (rankName.equalsIgnoreCase("Phylum")){ return Rank.PHYLUM();
763 }else if (rankName.equalsIgnoreCase("Subphylum")){ return Rank.SUBPHYLUM();
764 }else if (rankName.equalsIgnoreCase("Divisio")){ return Rank.DIVISION();
765 }else if (rankName.equalsIgnoreCase("Subdivisio")){ return Rank.SUBDIVISION();
766 }else if (rankName.equalsIgnoreCase("Classis")){ return Rank.CLASS();
767 }else if (rankName.equalsIgnoreCase("Subclassis")){ return Rank.SUBCLASS();
768 }else if (rankName.equalsIgnoreCase("Superordo")){ return Rank.SUPERORDER();
769 }else if (rankName.equalsIgnoreCase("Ordo")){ return Rank.ORDER();
770 }else if (rankName.equalsIgnoreCase("Subordo")){ return Rank.SUBORDER();
771 }else if (rankName.equalsIgnoreCase("Familia")){ return Rank.FAMILY();
772 }else if (rankName.equalsIgnoreCase("Subfamilia")){ return Rank.SUBFAMILY();
773 }else if (rankName.equalsIgnoreCase("Tribus")){ return Rank.TRIBE();
774 }else if (rankName.equalsIgnoreCase("Subtribus")){ return Rank.SUBTRIBE();
775 }else if (rankName.equalsIgnoreCase("Genus")){ return Rank.GENUS();
776 }else if (rankName.equalsIgnoreCase("Subgenus")){ return Rank.SUBGENUS();
777 }else if (rankName.equalsIgnoreCase("Sectio")){ return Rank.SECTION_BOTANY();
778 }else if (rankName.equalsIgnoreCase("Subsectio")){ return Rank.SUBSECTION_BOTANY();
779 }else if (rankName.equalsIgnoreCase("Series")){ return Rank.SERIES();
780 }else if (rankName.equalsIgnoreCase("Subseries")){ return Rank.SUBSERIES();
781 }else if (rankName.equalsIgnoreCase("Aggregate")){ return Rank.SPECIESAGGREGATE();
782 }else if (rankName.equalsIgnoreCase("Speciesgroup")){ return Rank.SPECIESGROUP();
783 }else if (rankName.equalsIgnoreCase("Species")){ return Rank.SPECIES();
784 }else if (rankName.equalsIgnoreCase("Subspecies")){ return Rank.SUBSPECIES();
785 }else if (rankName.equalsIgnoreCase("Convarietas")){ return Rank.CONVAR();
786 }else if (rankName.equalsIgnoreCase("Varietas")){ return Rank.VARIETY();
787 }else if (rankName.equalsIgnoreCase("Subvarietas")){ return Rank.SUBVARIETY();
788 }else if (rankName.equalsIgnoreCase("Forma")){ return Rank.FORM();
789 }else if (rankName.equalsIgnoreCase("Subforma")){ return Rank.SUBFORM();
790 }else if (rankName.equalsIgnoreCase("Forma spec.")){ return Rank.SPECIALFORM();
791 }else if (rankName.equalsIgnoreCase("tax.infragen.")){ return Rank.INFRAGENERICTAXON();
792 }else if (rankName.equalsIgnoreCase("tax.infrasp.")){ return Rank.INFRASPECIFICTAXON();
793 // old ranks
794 }else if (rankName.equalsIgnoreCase("proles")){ return Rank.INFRASPECIFICTAXON(); //to create the name put prol. and the infraspeciesepi to the field unnamed namephrase
795 }else if (rankName.equalsIgnoreCase("race")){ return Rank.INFRASPECIFICTAXON(); //to create the name put prol. and the infraspeciesepi to the field unnamed namephrase
796 }else if (rankName.equalsIgnoreCase("taxon")){ return Rank.INFRASPECIFICTAXON(); //to create the name put prol. and the infraspeciesepi to the field unnamed namephrase
797 }else if (rankName.equalsIgnoreCase("sublusus")){ return Rank.INFRASPECIFICTAXON(); //to create the name put prol. and the infraspeciesepi to the field unnamed namephrase
798
799 }else{
800 if (rankName == null){
801 rankName = "(null)"; //see NPE above
802 }
803 if (useUnknown){
804 logger.info("Unknown rank name: " + rankName+". Rank 'UNKNOWN_RANK' created instead");
805 return Rank.UNKNOWN_RANK();
806 }else{
807 throw new UnknownCdmTypeException("Unknown rank name: " + rankName);
808 }
809 }
810 }
811
812 /**
813 * Defines the rank according to the English name.
814 * @param rankName English rank name.
815 * @param nc Defines the handling of the section and subsection ranks. These are in different orders depending on the
816 * nomenclatural code.
817 * @param useUnknown if true, the "Unknown" rank is returned as a placeholder.
818 * @return
819 * @throws UnknownCdmTypeException never thrown if useUnknown is true
820 */
821 public static Rank getRankByEnglishName(String rankName, NomenclaturalCode nc, boolean useUnknown) throws UnknownCdmTypeException{
822 Rank result = null;
823 if (rankName == null){
824 throw new NullPointerException("Abbrev is NULL in getRankByAbbreviation");
825 }
826 if (labelMap == null){
827 return null;
828 }
829 //handle section and subsection (not unique representations)
830 if (rankName.equalsIgnoreCase("Section")){
831 if (nc != null && nc.equals(NomenclaturalCode.ICZN)){ return Rank.SECTION_ZOOLOGY();
832 }else if (nc != null && nc.equals(NomenclaturalCode.ICNAFP)){return Rank.SECTION_BOTANY();
833 }else{
834 String errorWarning = "Section is only defined for ICZN and ICNAFP at the moment but here needed for " + ((nc == null)? "(null)": nc.toString());
835 logger.warn(errorWarning);
836 throw new UnknownCdmTypeException (errorWarning);
837 }
838 }else if (rankName.equalsIgnoreCase("Subsection")){
839 if (nc != null && nc.equals(NomenclaturalCode.ICZN)){ return Rank.SUBSECTION_ZOOLOGY();
840 }else if (nc != null && nc.equals(NomenclaturalCode.ICNAFP)){ return Rank.SUBSECTION_BOTANY();
841 }else{
842 String errorWarning = "Subsection is only defined for ICZN and ICBN at the moment but here needed for " + ((nc == null)? "(null)": nc.toString());
843 logger.warn(errorWarning);
844 throw new UnknownCdmTypeException (errorWarning);
845 }
846 }
847
848 rankName = rankName.toLowerCase();
849
850 UUID uuid = labelMap.get(rankName);
851 if (uuid != null ){
852 result = getTermByUuid(uuid);
853 }
854 if (result != null){
855 return result;
856 }else {
857 if (rankName == null){
858 rankName = "(null)";
859 }
860 if (useUnknown){
861 logger.info("Unknown rank name: " + rankName + ". Rank 'UNKNOWN_RANK' created instead");
862 return Rank.UNKNOWN_RANK();
863 }else{
864 throw new UnknownCdmTypeException("Unknown rank: " + rankName);
865 }
866 }
867 }
868
869
870 public static Rank getRankByName(String rankName, NomenclaturalCode nc, boolean useUnknown)
871 throws UnknownCdmTypeException {
872
873 if (nc.equals(NomenclaturalCode.ICZN)) {
874 if (rankName.equalsIgnoreCase("Sectio")) { return Rank.SECTION_ZOOLOGY();
875 }else if (rankName.equalsIgnoreCase("Subsectio")) { return Rank.SUBSECTION_ZOOLOGY();
876 }
877 }
878 return getRankByName(rankName, useUnknown);
879 }
880
881 /**
882 * Returns the abbreviated rank name for <i>this</i> rank according to the English representation
883 * abbreviated label.
884 * TODO Needs to be changed to Latin as soon as Latin representations are available.
885 *
886 * @return the abbreviation string for <i>this</i> rank
887 */
888 public String getAbbreviation(){
889 Language language = Language.ENGLISH();
890 String result = this.getRepresentation(language).getAbbreviatedLabel();
891 if (result== null) {
892 logger.warn("Abbreviation for this Rank " + this.toString() + " not yet implemented");
893 return "no abbreviation available.";
894 }else{
895 return result;
896 }
897 }
898 @Transient
899 public String getInfraGenericMarker() throws UnknownCdmTypeException{
900 String result = null;
901 if (! this.isInfraGeneric()){
902 throw new IllegalStateException("An infrageneric marker is only available for a infrageneric rank but was asked for rank: " + this.toString());
903 }else{
904 result = this.getAbbreviation();
905 }
906 if (result == null){
907 throw new UnknownCdmTypeException("Abbreviation for rank unknown: " + this.toString());
908 }
909 return result;
910 }
911
912
913
914 @Override
915 public Rank readCsvLine(Class<Rank> termClass, List<String> csvLine, Map<UUID, DefinedTermBase> terms) {
916 Rank rank = super.readCsvLine(termClass, csvLine, terms);
917 RankClass rankClass = RankClass.byKey(csvLine.get(5));
918 assert rankClass != null: "XXXXXXXXXXXXXXXXXXXXX Rank class must not be null: " + csvLine ;
919 rank.setRankClass(rankClass);
920 return rank;
921 }
922
923 @Override
924 protected void setDefaultTerms(TermVocabulary<Rank> termVocabulary) {
925 termMap = new HashMap<UUID, Rank>();
926 for (Rank term : termVocabulary.getTerms()){
927 termMap.put(term.getUuid(), (Rank)term);
928 addRank(term);
929 }
930 }
931
932 /**
933 * @param term
934 */
935 private void addRank(Rank rank) {
936 if (rank == null){
937 logger.warn("rank is NULL");
938 return;
939 }
940 if (rank.getUuid().equals(uuidSectionZoology) || rank.getUuid().equals(uuidSubsectionZoology )){
941 //sect./subsect. is used for botanical sections, see also #getRankByAbbreviation(String, NomenclaturalCode, boolean)
942 return;
943 }
944 Language lang = Language.DEFAULT(); //TODO should be Latin but at the moment we have only English representations
945 Representation representation = rank.getRepresentation(lang);
946 String abbrevLabel = representation.getAbbreviatedLabel();
947 String label = representation.getLabel();
948 if (abbrevLabel == null){
949 logger.warn("Abbreviated label for rank is NULL.Can't add rank: " + CdmUtils.Nz(rank.getLabel()));
950 return;
951 }
952 //initialize maps
953 if (abbrevMap == null){
954 abbrevMap = new HashMap<String, UUID>();
955 }
956 if (labelMap == null){
957 labelMap = new HashMap<String, UUID>();
958 }
959 //add to map
960 abbrevMap.put(abbrevLabel, rank.getUuid());
961 labelMap.put(label.toLowerCase(), rank.getUuid());
962 }
963
964
965 /**
966 * It is necessary to skip the vocabulary check, otherwise we would have
967 * problems in some CacheStrategies, due to uninitialized Vocabularies.
968 *
969 * @see eu.etaxonomy.cdm.model.common.OrderedTermBase#compareTo(eu.etaxonomy.cdm.model.common.OrderedTermBase)
970 */
971 @Override
972 public int compareTo(Rank orderedTerm) {
973 return performCompareTo(orderedTerm, true);
974 }
975
976 }