Project

General

Profile

Download (41.2 KB) Statistics
| Branch: | Tag: | Revision:
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.Transient;
19
import javax.validation.constraints.NotNull;
20
import javax.xml.bind.annotation.XmlAccessType;
21
import javax.xml.bind.annotation.XmlAccessorType;
22
import javax.xml.bind.annotation.XmlAttribute;
23
import javax.xml.bind.annotation.XmlType;
24

    
25
import org.apache.commons.lang.StringUtils;
26
import org.apache.log4j.Logger;
27
import org.hibernate.annotations.Type;
28
import org.hibernate.envers.Audited;
29
import org.hibernate.search.annotations.Indexed;
30

    
31
import eu.etaxonomy.cdm.common.CdmUtils;
32
import eu.etaxonomy.cdm.model.common.DefinedTermBase;
33
import eu.etaxonomy.cdm.model.common.Language;
34
import eu.etaxonomy.cdm.model.common.OrderedTermBase;
35
import eu.etaxonomy.cdm.model.common.Representation;
36
import eu.etaxonomy.cdm.model.common.TermType;
37
import eu.etaxonomy.cdm.model.common.TermVocabulary;
38
import eu.etaxonomy.cdm.strategy.exceptions.UnknownCdmTypeException;
39

    
40
/**
41
 * The class representing the taxonomical ranks (like "Family", "Genus" or
42
 * "Species") used for {@link TaxonNameBase taxon names} across all {@link NomenclaturalCode nomenclatural codes}
43
 * for bacteria (ICNB), viruses (ICVCN), plants and fungi (ICBN),
44
 * cultivars (ICNCP) and animals (ICZN).
45
 * <P>
46
 * A standard (ordered) list of taxonomical rank instances will be automatically
47
 * created as the project starts. But this class allows to extend this standard
48
 * list by creating new instances of additional taxonomical ranks if needed.
49
 * <P>
50
 * This class corresponds to: <ul>
51
 * <li> TaxonRankTerm according to the TDWG ontology
52
 * <li> TaxonomicRankEnum according to the TCS
53
 * <li> Rank according to the ABCD schema
54
 * </ul>
55
 *
56
 * @author m.doering
57
 * @version 1.0
58
 * @created 08-Nov-2007 13:06:46
59
 */
60
@XmlAccessorType(XmlAccessType.FIELD)
61
@XmlType(name = "Rank")
62
@Entity
63
@Indexed(index = "eu.etaxonomy.cdm.model.common.DefinedTermBase")
64
@Audited
65
public class Rank extends OrderedTermBase<Rank> {
66
    private static final long serialVersionUID = -8648081681348758485L;
67
    private static final Logger logger = Logger.getLogger(Rank.class);
68

    
69
    private static final UUID uuidEmpire = UUID.fromString("ac470211-1586-4b24-95ca-1038050b618d");
70
    private static final UUID uuidDomain = UUID.fromString("ffca6ec8-8b88-417b-a6a0-f7c992aac19b");
71
    private static final UUID uuidSuperkingdom = UUID.fromString("64223610-7625-4cfd-83ad-b797bf7f0edd");
72
    private static final UUID uuidKingdom = UUID.fromString("fbe7109d-66b3-498c-a697-c6c49c686162");
73
    private static final UUID uuidSubkingdom = UUID.fromString("a71bd9d8-f3ab-4083-afb5-d89315d71655");
74
    private static final UUID uuidInfrakingdom = UUID.fromString("1e37930c-86cf-44f6-90fd-7822928df260");
75
    private static final UUID uuidSuperphylum = UUID.fromString("0d0cecb1-e254-4607-b210-6801e7ecbb04");
76
    private static final UUID uuidPhylum = UUID.fromString("773430d2-76b4-438c-b817-97a543a33287");
77
    private static final UUID uuidSubphylum = UUID.fromString("23a9b6ff-9408-49c9-bd9e-7a2ca5ab4725");
78
    private static final UUID uuidInfraphylum = UUID.fromString("1701de3a-7693-42a5-a2d3-42697f944190");
79
    private static final UUID uuidSuperdivision = UUID.fromString("a735a48f-4fc8-49a7-ae0c-6a984f658131");
80
    private static final UUID uuidDivision = UUID.fromString("7e56f5cc-123a-4fd1-8cbb-6fd80358b581");
81
    private static final UUID uuidSubdivision = UUID.fromString("931c840f-7a6b-4d76-ad38-bfdd77d7b2e8");
82
    private static final UUID uuidInfradivision = UUID.fromString("c0ede273-be52-4dee-b411-66ee08d30c94");
83
    private static final UUID uuidSuperclass = UUID.fromString("e65b4e1a-21ec-428d-9b9f-e87721ab967c");
84
    private static final UUID uuidClass = UUID.fromString("f23d14c4-1d34-4ee6-8b4e-eee2eb9a3daf");
85
    private static final UUID uuidSubclass = UUID.fromString("8cb26733-e2f5-46cb-ab5c-f99254f877aa");
86
    private static final UUID uuidInfraclass = UUID.fromString("ad23cfda-879a-4021-8629-c54d27caf717");
87
    private static final UUID uuidSuperorder = UUID.fromString("c8c67a22-301a-4219-b882-4a49121232ff");
88
    private static final UUID uuidOrder = UUID.fromString("b0785a65-c1c1-4eb4-88c7-dbd3df5aaad1");
89
    private static final UUID uuidSuborder = UUID.fromString("768ad378-fa85-42ab-b668-763225832f57");
90
    private static final UUID uuidInfraorder = UUID.fromString("84099182-a6f5-47d7-8586-33c9e9955a10");
91
    private static final UUID uuidSectionZoology = UUID.fromString("691d371e-10d7-43f0-93db-3d7fa1a62c54");
92
    private static final UUID uuidSubsectionZoology = UUID.fromString("0ed32d28-adc4-4303-a9ca-68e2acd67e33");
93
    private static final UUID uuidSuperfamily = UUID.fromString("2cfa510a-dcea-4a03-b66a-b1528f9b0796");
94
    private static final UUID uuidFamily = UUID.fromString("af5f2481-3192-403f-ae65-7c957a0f02b6");
95
    private static final UUID uuidSubfamily = UUID.fromString("862526ee-7592-4760-a23a-4ff3641541c5");
96
    private static final UUID uuidInfrafamily = UUID.fromString("c3f2e3bb-6eef-4a26-9fb7-b14f4c8c5e4f");
97
    private static final UUID uuidSupertribe = UUID.fromString("11e94828-8c61-499b-87d6-1de35ce2c51c");
98
    private static final UUID uuidTribe = UUID.fromString("4aa6890b-0363-4899-8d7c-ee0cb78e6166");
99
    private static final UUID uuidSubtribe = UUID.fromString("ae41ecc5-5165-4126-9d24-79939ae5d822");
100
    private static final UUID uuidInfratribe = UUID.fromString("1ec02e8f-f2b7-4c65-af9f-b436b34c79a3");
101
    private static final UUID uuidSupragenericTaxon = UUID.fromString("1fdc0b93-c354-441a-8406-091e0303ff5c");
102
    public static final UUID uuidGenus = UUID.fromString("1b11c34c-48a8-4efa-98d5-84f7f66ef43a");
103
    private static final UUID uuidSubgenus = UUID.fromString("78786e16-2a70-48af-a608-494023b91904");
104
    private static final UUID uuidInfragenus = UUID.fromString("a9972969-82cd-4d54-b693-a096422f13fa");
105
    private static final UUID uuidSectionBotany = UUID.fromString("3edff68f-8527-49b5-bf91-7e4398bb975c");
106
    private static final UUID uuidSubsectionBotany = UUID.fromString("d20f5b61-d463-4448-8f8a-c1ff1f262f59");
107
    private static final UUID uuidSeries = UUID.fromString("d7381ecf-48f8-429b-9c54-f461656978cd");
108
    private static final UUID uuidSubseries = UUID.fromString("80c9a263-f4db-4a13-b6c2-b7fec1aa1200");
109
    private static final UUID uuidSpeciesAggregate = UUID.fromString("1ecae058-4217-4f75-9c27-6d8ba099ac7a");
110
    private static final UUID uuidSpeciesGroup = UUID.fromString("d1988a11-292b-46fa-8fb7-bc64ea6d8fc6");
111
    public static final UUID uuidInfragenericTaxon = UUID.fromString("41bcc6ac-37d3-4fd4-bb80-3cc5b04298b9");
112
    public static final UUID uuidSpecies = UUID.fromString("b301f787-f319-4ccc-a10f-b4ed3b99a86d");
113
    private static final UUID uuidSubspecificAggregate = UUID.fromString("72c248b9-027d-4402-b375-dd4f0850c9ad");
114
    private static final UUID uuidSubspecies = UUID.fromString("462a7819-8b00-4190-8313-88b5be81fad5");
115
    private static final UUID uuidInfraspecies = UUID.fromString("f28ebc9e-bd50-4194-9af1-42f5cb971a2c");
116
    private static final UUID uuidNatio = UUID.fromString("965f2f38-7f97-4270-ab5a-1999bf050a22");
117
    private static final UUID uuidVariety = UUID.fromString("d5feb6a5-af5c-45ef-9878-bb4f36aaf490");
118
    private static final UUID uuidBioVariety = UUID.fromString("a3a364cb-1a92-43fc-a717-3c44980a0991");
119
    private static final UUID uuidPathoVariety = UUID.fromString("2f4f4303-a099-47e3-9048-d749d735423b");
120
    private static final UUID uuidSubvariety = UUID.fromString("9a83862a-7aee-480c-a98d-4bceaf8712ca");
121
    private static final UUID uuidSubsubvariety = UUID.fromString("bff22f84-553a-4429-a4e7-c4b3796c3a18");
122

    
123
    private static final UUID uuidProles = UUID.fromString("8810d1ba-6a34-4ae3-a355-919ccd1cd1a5");
124
    private static final UUID uuidRace = UUID.fromString("196dee39-cfd8-4460-8bf0-88b83da27f62");
125
    private static final UUID uuidSublusus = UUID.fromString("1fafa596-a8e7-4e62-a378-3cc8cb3627ca");
126

    
127
    private static final UUID uuidConvar = UUID.fromString("2cc740c9-cebb-43c8-9b06-1bef79e6a56a");
128
    private static final UUID uuidForm = UUID.fromString("0461281e-458a-47b9-8d41-19a3d39356d5");
129
    private static final UUID uuidSpecialForm = UUID.fromString("bed20aee-2f5a-4635-9c02-eff06246d067");
130
    private static final UUID uuidSubform = UUID.fromString("47cfc5b0-0fb7-4ceb-b61d-e1dd8de8b569");
131
    private static final UUID uuidSubsubform = UUID.fromString("1c8ac389-4349-4ae0-87be-7239f6635068");
132
    public static final UUID uuidInfraspecificTaxon = UUID.fromString("eb75c27d-e154-4570-9d96-227b2df60474");
133
    private static final UUID uuidCandidate = UUID.fromString("ead9a1f5-dfd4-4de2-9121-70a47accb10b");
134
    private static final UUID uuidDenominationClass = UUID.fromString("49bdf74a-2170-40ed-8be2-887a0db517bf");
135
    private static final UUID uuidGrex = UUID.fromString("08dcb4ff-ac58-48a3-93af-efb3d836ac84");
136
    private static final UUID uuidGraftChimaera = UUID.fromString("6b4063bc-f934-4796-9bf3-0ef3aea5c1cb");
137
    private static final UUID uuidCultivarGroup = UUID.fromString("d763e7d3-e7de-4bb1-9d75-225ca6948659");
138
    private static final UUID uuidCultivar = UUID.fromString("5e98415b-dc6e-440b-95d6-ea33dbb39ad0");
139
    private static final UUID uuidUnknownRank = UUID.fromString("5c4d6755-2cf6-44ca-9220-cccf8881700b");
140

    
141
    private static Map<String, UUID> idInVocMap = null;
142
    private static Map<String, UUID> labelMap = null;
143

    
144
    protected static Map<UUID, Rank> termMap = null;
145

    
146
//*********************** Factory methods ********************************************/
147

    
148
//    /**
149
//     * Creates a new empty rank.
150
//     *
151
//     * @see #NewInstance(String, String, String)
152
//     */
153
//    private static Rank NewInstance(){
154
//        return new Rank();
155
//    }
156

    
157
    /**
158
     * Creates an additional rank with a description (in the {@link Language#DEFAULT() default language}),
159
     * a label and a label abbreviation.
160
     *
161
     * @param	term  		 the string (in the default language) describing the
162
     * 						 new rank to be created
163
     * @param	label  		 the string identifying the new rank to be created
164
     * @param	labelAbbrev  the string identifying (in abbreviated form) the
165
     * 						 new rank to be created
166
     * @see 				 #NewInstance()
167
     */
168
    public static Rank NewInstance(RankClass rankClass, String term, String label, String labelAbbrev){
169
        return new Rank(rankClass, term, label, labelAbbrev);
170
    }
171

    
172
    /**
173
     * The {@link RankClass rank class} of a rank. It is usually needed for correct formatting of a
174
     * rank by using e.g. isSupraGeneric(). Prior to v3.3 this was computed by comparison of ranks.
175
     */
176
    @XmlAttribute(name ="RankClass")
177
    @NotNull
178
    @Type(type = "eu.etaxonomy.cdm.hibernate.EnumUserType",
179
        parameters = {@org.hibernate.annotations.Parameter(name="enumClass", value="eu.etaxonomy.cdm.model.name.RankClass")}
180
    )
181
    private RankClass rankClass;
182

    
183

    
184
//********************************** Constructor *********************************/
185

    
186
      //for hibernate use only
187
      @Deprecated
188
      protected Rank() {
189
        super(TermType.Rank);
190
    }
191

    
192
    /**
193
     * Class constructor: creates an additional rank instance with a description
194
     * (in the {@link eu.etaxonomy.cdm.model.common.Language#DEFAULT() default language}), a label and a label abbreviation.
195
     *
196
     * @param	term  		 the string (in the default language) describing the
197
     * 						 new rank to be created
198
     * @param	label  		 the string identifying the new rank to be created
199
     * @param	labelAbbrev  the string identifying (in abbreviated form) the
200
     * 						 new rank to be created
201
     * @see 	#Rank()
202
     */
203
    protected Rank(RankClass rankClass, String term, String label, String labelAbbrev) {
204
        super(TermType.Rank, term, label, labelAbbrev);
205
        this.rankClass = rankClass;
206
    }
207

    
208

    
209
//********* METHODS **************************************/
210

    
211
    /* (non-Javadoc)
212
     * @see eu.etaxonomy.cdm.model.common.DefinedTermBase#resetTerms()
213
     */
214
    @Override
215
    public void resetTerms(){
216
        termMap = null;
217
    }
218

    
219

    
220

    
221
    protected static Rank getTermByUuid(UUID uuid){
222
        if (termMap == null || termMap.isEmpty()){
223
           return getTermByClassAndUUID(Rank.class, uuid);
224
        } else {
225
            return termMap.get(uuid);
226
        }
227
    }
228

    
229
    public static final Rank EMPIRE(){
230
      return getTermByUuid(uuidEmpire);
231
    }
232
    public static final Rank DOMAIN(){
233
          return getTermByUuid(uuidDomain);
234
    }
235
    public static final Rank SUPERKINGDOM(){
236
        return getTermByUuid(uuidSuperkingdom);
237
    }
238
    public static final Rank KINGDOM(){
239
        return getTermByUuid(uuidKingdom);
240
    }
241
    public static final Rank SUBKINGDOM(){
242
        return getTermByUuid(uuidSubkingdom);
243
    }
244
    public static final Rank INFRAKINGDOM(){
245
        return getTermByUuid(uuidInfrakingdom);
246
    }
247
    public static final Rank SUPERPHYLUM(){
248
        return getTermByUuid(uuidSuperphylum);
249
    }
250
    public static final Rank PHYLUM(){
251
        return getTermByUuid(uuidPhylum);
252
    }
253
    public static final Rank SUBPHYLUM(){
254
        return getTermByUuid(uuidSubphylum);
255
    }
256
    public static final Rank INFRAPHYLUM(){
257
        return getTermByUuid(uuidInfraphylum);
258
    }
259
    public static final Rank SUPERDIVISION(){
260
        return getTermByUuid(uuidSuperdivision);
261
    }
262
    public static final Rank DIVISION(){
263
        return getTermByUuid(uuidDivision);
264
    }
265
    public static final Rank SUBDIVISION(){
266
        return getTermByUuid(uuidSubdivision);
267
    }
268
    public static final Rank INFRADIVISION(){
269
        return getTermByUuid(uuidInfradivision);
270
    }
271
    public static final Rank SUPERCLASS(){
272
        return getTermByUuid(uuidSuperclass);
273
    }
274
    public static final Rank CLASS(){
275
        return getTermByUuid(uuidClass);
276
    }
277
    public static final Rank SUBCLASS(){
278
        return getTermByUuid(uuidSubclass);
279
    }
280
    public static final Rank INFRACLASS(){
281
        return getTermByUuid(uuidInfraclass);
282
    }
283
    public static final Rank SUPERORDER(){
284
        return getTermByUuid(uuidSuperorder);
285
    }
286
    public static final Rank ORDER(){
287
        return getTermByUuid(uuidOrder);
288
    }
289
    public static final Rank SUBORDER(){
290
        return getTermByUuid(uuidSuborder);
291
    }
292
    public static final Rank INFRAORDER(){
293
        return getTermByUuid(uuidInfraorder);
294
    }
295
    public static final Rank SUPERFAMILY(){
296
        return getTermByUuid(uuidSuperfamily);
297
    }
298
    public static final Rank FAMILY(){
299
        return getTermByUuid(uuidFamily);
300
    }
301
    public static final Rank SUBFAMILY(){
302
        return getTermByUuid(uuidSubfamily);
303
    }
304
    public static final Rank INFRAFAMILY(){
305
        return getTermByUuid(uuidInfrafamily);
306
    }
307
    public static final Rank SUPERTRIBE(){
308
        return getTermByUuid(uuidSupertribe);
309
    }
310
    public static final Rank TRIBE(){
311
        return getTermByUuid(uuidTribe);
312
    }
313
    public static final Rank SUBTRIBE(){
314
        return getTermByUuid(uuidSubtribe);
315
    }
316
    public static final Rank INFRATRIBE(){
317
        return getTermByUuid(uuidInfratribe);
318
    }
319
    public static final Rank SUPRAGENERICTAXON(){
320
        return getTermByUuid(uuidSupragenericTaxon);
321
    }
322
    public static final Rank GENUS(){
323
        return getTermByUuid(uuidGenus);
324
    }
325
    public static final Rank SUBGENUS(){
326
        return getTermByUuid(uuidSubgenus);
327
    }
328
    public static final Rank INFRAGENUS(){
329
        return getTermByUuid(uuidInfragenus);
330
    }
331
    public static final Rank SECTION_BOTANY(){
332
        return getTermByUuid(uuidSectionBotany);
333
    }
334
    public static final Rank SUBSECTION_BOTANY(){
335
        return getTermByUuid(uuidSubsectionBotany);
336
    }
337
    public static final Rank SECTION_ZOOLOGY(){
338
        return getTermByUuid(uuidSectionZoology);
339
    }
340
    public static final Rank SUBSECTION_ZOOLOGY(){
341
        return getTermByUuid(uuidSubsectionZoology);
342
    }
343
    public static final Rank SERIES(){
344
        return getTermByUuid(uuidSeries);
345
    }
346
    public static final Rank SUBSERIES(){
347
        return getTermByUuid(uuidSubseries);
348
    }
349
    public static final Rank SPECIESAGGREGATE(){
350
        return getTermByUuid(uuidSpeciesAggregate);
351
    }
352
    public static final Rank SPECIESGROUP(){
353
        return getTermByUuid(uuidSpeciesGroup);
354
    }
355
    /**
356
     * 'Unranked infrageneric'. An infrageneric rank which is on purpose not further defined.
357
     * This sometimes holds for names from the 19th century.
358
     */
359
    public static final Rank INFRAGENERICTAXON(){
360
        return getTermByUuid(uuidInfragenericTaxon);
361
    }
362
    public static final Rank SPECIES(){
363
        return getTermByUuid(uuidSpecies);
364
    }
365
    public static final Rank SUBSPECIFICAGGREGATE(){
366
        return getTermByUuid(uuidSubspecificAggregate);
367
    }
368
    public static final Rank SUBSPECIES(){
369
        return getTermByUuid(uuidSubspecies);
370
    }
371
    public static final Rank INFRASPECIES(){
372
        return getTermByUuid(uuidInfraspecies);
373
    }
374
    public static final Rank VARIETY(){
375
        return getTermByUuid(uuidVariety);
376
    }
377
    public static final Rank BIOVARIETY(){
378
        return getTermByUuid(uuidBioVariety);
379
    }
380
    public static final Rank PATHOVARIETY(){
381
        return getTermByUuid(uuidPathoVariety);
382
    }
383
    public static final Rank SUBVARIETY(){
384
        return getTermByUuid(uuidSubvariety);
385
    }
386
    public static final Rank SUBSUBVARIETY(){
387
        return getTermByUuid(uuidSubsubvariety );
388
    }
389
    public static final Rank PROLES(){
390
        return getTermByUuid(uuidProles);
391
    }
392
    public static final Rank RACE(){
393
        return getTermByUuid(uuidRace);
394
    }
395
    public static final Rank SUBLUSUS(){
396
        return getTermByUuid(uuidSublusus);
397
    }
398

    
399
    public static final Rank CONVAR(){
400
        return getTermByUuid(uuidConvar);
401
    }
402
    public static final Rank FORM(){
403
        return getTermByUuid(uuidForm);
404
    }
405
    public static final Rank SPECIALFORM(){
406
        return getTermByUuid(uuidSpecialForm);
407
    }
408
    public static final Rank SUBFORM(){
409
        return getTermByUuid(uuidSubform);
410
    }
411
    public static final Rank SUBSUBFORM(){
412
        return getTermByUuid(uuidSubsubform);
413
    }
414
    /**
415
     * 'Unranked infraspecific'. An infraspecific rank which is on purpose not further defined.
416
     * This sometimes holds for names from the 19th century.
417
     */
418
    public static final Rank INFRASPECIFICTAXON(){
419
        return getTermByUuid(uuidInfraspecificTaxon);
420
    }
421
    public static final Rank CANDIDATE(){
422
        return getTermByUuid(uuidCandidate);
423
    }
424
    public static final Rank DENOMINATIONCLASS(){
425
        return getTermByUuid(uuidDenominationClass);
426
    }
427
    public static final Rank GREX(){
428
        return getTermByUuid(uuidGrex);
429
    }
430
    public static final Rank GRAFTCHIMAERA(){
431
        return getTermByUuid(uuidGraftChimaera);
432
    }
433
    public static final Rank CULTIVARGROUP(){
434
        return getTermByUuid(uuidCultivarGroup);
435
    }
436
    public static final Rank CULTIVAR(){
437
        return getTermByUuid(uuidCultivar);
438
    }
439
    public static final Rank UNKNOWN_RANK(){
440
        return getTermByUuid(uuidUnknownRank);
441
    }
442
    public static final Rank NATIO(){
443
        return getTermByUuid(uuidNatio);
444
    }
445
    /**
446
     * @see #INFRASPECIFICTAXON()
447
     */
448
    public static final Rank UNRANKED_INFRASPECIFIC(){
449
        return getTermByUuid(uuidInfraspecificTaxon);
450
    }
451
    /**
452
     * @see #INFRAGENERICTAXON()
453
     */
454
    public static final Rank UNRANKED_INFRAGENERIC(){
455
        return getTermByUuid(uuidInfragenericTaxon);
456
    }
457

    
458
// ************************ GETTER / SETTER **********************************/
459

    
460
    public RankClass getRankClass() {
461
        return rankClass;
462
    }
463

    
464
    public void setRankClass(RankClass rankClass) {
465
        this.rankClass = rankClass;
466
    }
467

    
468
// ******************************** METHODS ***************************************/
469

    
470
    /**
471
     * Returns the boolean value indicating whether <i>this</i> rank is higher than
472
     * the genus rank (true) or not (false). Returns false if <i>this</i> rank is null.
473
     *
474
     * @see  #isGenus()
475
     * @see  #isInfraGeneric()
476
     * @see  #isSpecies()
477
     * @see  #isInfraSpecific()
478
     */
479
    @Transient
480
    public boolean isSupraGeneric(){
481
        return this.rankClass.equals(RankClass.Suprageneric); // (this.isHigher(Rank.GENUS()));
482
    }
483

    
484
    /**
485
     * Returns the boolean value indicating whether <i>this</i> rank is the genus rank
486
     * (true) or not (false). Returns false if <i>this</i> rank is null.
487
     *
488
     * @see  #isSupraGeneric()
489
     * @see  #isInfraGeneric()
490
     * @see  #isSpecies()
491
     * @see  #isInfraSpecific()
492
     */
493
    @Transient
494
    public boolean isGenus(){
495
        return this.rankClass.equals(RankClass.Genus); // (this.equals(Rank.GENUS()));
496
    }
497

    
498
    /**
499
     * Returns the boolean value indicating whether <i>this</i> rank is higher than the
500
     * species rank and lower than the genus rank (true) or not (false). Species groups or
501
     * aggregates are also handled as infrageneric ranks.
502
     * Returns false if <i>this</i> rank is null.
503
     *
504
     * @see  #isSupraGeneric()
505
     * @see  #isGenus()
506
     * @see  #isSpeciesAggregate()
507
     * @see  #isSpecies()
508
     * @see  #isInfraSpecific()
509
     */
510
    @Transient
511
    public boolean isInfraGeneric(){
512
        return this.rankClass.equals(RankClass.Infrageneric) || this.rankClass.equals(RankClass.SpeciesGroup) ; //(this.isLower(Rank.GENUS()) && this.isHigher(Rank.SPECIES()));
513
    }
514

    
515
    /**
516
     * Returns true if this rank indicates a rank that aggregates species
517
     * like species aggregates or species groups, false otherwise.
518
     * @return
519
     */
520
    @Transient
521
    public boolean isSpeciesAggregate(){
522
        return this.rankClass.equals(RankClass.SpeciesGroup); //(this.equals(Rank.SPECIESAGGREGATE()) || (this.isLower(Rank.SPECIESAGGREGATE()) && this.isHigher(Rank.SPECIES())));
523
    }
524

    
525
    /**
526
     * Returns the boolean value indicating whether <i>this</i> rank is the species
527
     * rank (true) or not (false). Returns false if <i>this</i> rank is null.
528
     *
529
     * @see  #isSupraGeneric()
530
     * @see  #isGenus()
531
     * @see  #isInfraGeneric()
532
     * @see  #isInfraSpecific()
533
     */
534
    @Transient
535
    public boolean isSpecies(){
536
        return this.rankClass.equals(RankClass.Species); //(this.equals(Rank.SPECIES()));
537
    }
538

    
539
    /**
540
     * Returns the boolean value indicating whether <i>this</i> rank is lower than the
541
     * species rank (true) or not (false). Returns false if <i>this</i> rank is null.
542
     *
543
     * @see  #isSupraGeneric()
544
     * @see  #isGenus()
545
     * @see  #isInfraGeneric()
546
     * @see  #isSpecies()
547
     */
548
    @Transient
549
    public boolean isInfraSpecific(){
550
        return this.rankClass.equals(RankClass.Infraspecific); // (this.isLower(Rank.SPECIES()));
551
    }
552

    
553

    
554
    /**
555
     * Returns the rank identified through a label or the identifier within the vocabulary
556
     * Preliminary implementation for BotanicalNameParser.
557
     *
558
     * @param	strRank	the string identifying the rank
559
     * @return  		the rank
560
     */
561
    public static Rank getRankByNameOrIdInVoc(String strRank) throws UnknownCdmTypeException{
562
        return getRankByNameOrIdInVoc(strRank, false);
563
    }
564

    
565
    /**
566
     * Returns the rank identified through a label or the identifier within the vocabulary
567
     * for a given nomenclatural code.
568
     * Preliminary implementation for BotanicalNameParser.
569
     *
570
     * @param	strRank	the string identifying the rank
571
     * @param   nc      the nomenclatural code
572
     * @return  		the rank
573
     */
574
    public static Rank getRankByNameOrIdInVoc(String strRank, NomenclaturalCode nc) throws UnknownCdmTypeException{
575
        return getRankByNameOrIdInVoc(strRank, nc, false);
576
    }
577

    
578
    // TODO
579
    // Preliminary implementation for BotanicalNameParser.
580
    // not yet complete
581
    /**
582
     * Returns the rank identified through a label or the identifier within the vocabulary.
583
     * Preliminary implementation for BotanicalNameParser.
584
     *
585
     * @param	strRank	the string identifying the rank
586
     * @param 	useUnknown 	if true the rank UNKNOWN_RANK is returned if the abbrev is
587
     * 			unknown or not yet implemented
588
     * @return  		the rank
589
     */
590
    public static Rank getRankByNameOrIdInVoc(String strRank, boolean useUnknown) throws UnknownCdmTypeException{
591
        try {
592
            return getRankByIdInVoc(strRank);
593
        } catch (UnknownCdmTypeException e) {
594
            return getRankByName(strRank, useUnknown);
595
        }
596
    }
597

    
598
    // TODO
599
    // Preliminary implementation for BotanicalNameParser.
600
    // not yet complete
601
    /**
602
     * Returns the rank identified through a label or the identifier within the vocabulary.
603
     * Preliminary implementation for BotanicalNameParser.
604
     *
605
     * @param	strRank	the string identifying the rank
606
     * @param   nc      the nomenclatural code
607
     * @param 	useUnknown 	if true the rank UNKNOWN_RANK is returned if the abbrev is
608
     * 			unknown or not yet implemented
609
     * @return  		the rank
610
     */
611
    public static Rank getRankByNameOrIdInVoc(String strRank, NomenclaturalCode nc, boolean useUnknown)
612
            throws UnknownCdmTypeException{
613
        try {
614
            return getRankByIdInVoc(strRank, nc);
615
        } catch (UnknownCdmTypeException e) {
616
            return getRankByName(strRank, nc, useUnknown);
617
        }
618
    }
619

    
620
    /**
621
     * Returns the rank identified through the vocabulary identifier.
622
     * Preliminary implementation for BotanicalNameParser.<BR>
623
     * Note: For abbrev = "[unranked]" the result is undefined.
624
     * It maybe the infrageneric unranked or the infraspecific unranked.
625
     * You need to define by context which one is correct.
626
     *
627
     * @param	abbrev	the string for the name abbreviation
628
     * @return  		the rank
629
     */
630
    public static Rank getRankByIdInVoc(String abbrev) throws UnknownCdmTypeException{
631
        return getRankByIdInVoc(abbrev, false);
632
    }
633

    
634
    /**
635
     * Returns the rank identified through an abbreviated name for a given nomenclatural code.
636
     * See also {@link #getRankByIdInVoc(String, boolean)}
637
     *
638
     * @param	abbrev	the string for the name abbreviation
639
     * @param	nc	    the nomenclatural code
640
     * @return  		the rank
641
     */
642
    public static Rank getRankByIdInVoc(String abbrev, NomenclaturalCode nc) throws UnknownCdmTypeException{
643
        return getRankByIdInVoc(abbrev, nc, false);
644
    }
645

    
646
    // TODO
647
    // Preliminary implementation for BotanicalNameParser.
648
    // not yet complete
649
    /**
650
     * Returns the rank identified through an abbreviated representation.
651
     * At the moment it uses the English abbreviations (being Latin because
652
     * we do not have Latin representations yet.
653
     * TODO
654
     * If no according abbreviation is available it throws either an UnknownCdmTypeException
655
     * or an #Rank.UNKNOWN() object depending on the useUnknown flag.
656
     *
657
     * @param	idInVoc		the string for the name abbreviation
658
     * @param 	useUnknown 	if true the rank UNKNOWN_RANK is returned if the abbrev is
659
     * 			unknown or not yet existent
660
     * @return  the rank
661
     */
662
    public static Rank getRankByIdInVoc(String idInVoc, boolean useUnknown) throws UnknownCdmTypeException{
663
        Rank result = null;
664
        if (idInVoc == null){
665
            throw new NullPointerException("idInVoc is NULL in getRankByIdInVoc");
666
        }
667
        if (StringUtils.isBlank(idInVoc)){
668
            //handle empty idInVoc as unknown
669
            idInVoc = "oijas34\u0155";
670
        }
671
        if (idInVocMap == null){
672
            return null;
673
        }
674
        idInVoc = normalizeSectionAndSubsection(idInVoc);
675
        idInVoc = normalizeSpecialForm(idInVoc);
676
        UUID uuid = idInVocMap.get(idInVoc);
677
        if (uuid != null ){
678
            result = getTermByUuid(uuid);
679
        }
680
        if (result != null){
681
            return result;
682
        }else {
683
            if (idInVoc == null){
684
                idInVoc = "(null)";
685
            }
686
            if (useUnknown){
687
                logger.info("Unknown rank name: " + idInVoc + ". Rank 'UNKNOWN_RANK' created instead");
688
                return Rank.UNKNOWN_RANK();
689
            }else{
690
                throw new UnknownCdmTypeException("Unknown rank abbreviation: " + idInVoc);
691
            }
692
        }
693
    }
694

    
695
    private static String normalizeSectionAndSubsection(String idInVoc) {
696
        if (idInVoc.equals("sect.")){
697
            return "sect.(bot.)";
698
        }else if (idInVoc.equals("subsect.")){
699
            return "subsect.(bot.)";
700
        }
701
        return idInVoc;
702
    }
703

    
704
    private static String normalizeSpecialForm(String idInVoc) {
705
        if (idInVoc.equals("f.sp.") || idInVoc.equals("f. sp.")){
706
            return "f.spec.";
707
        }
708
        return idInVoc;
709
    }
710

    
711
    // TODO
712
    // Preliminary implementation to cover Botany and Zoology.
713
    /**
714
     * Returns the rank identified through an abbreviated name for a given nomenclatural code.
715
     * Preliminary implementation for ICBN and ICZN.
716
     * See also {@link #getRankByIdInVoc(String, boolean)}
717

    
718
     *
719
     * @param	abbrev		the string for the name abbreviation
720
     * @param	nc	        the nomenclatural code
721
     * @param 	useUnknown 	if true the rank UNKNOWN_RANK is returned if the abbrev is
722
     * 			unknown or not yet implemented
723
     * @return  the rank
724
     */
725
    public static Rank getRankByIdInVoc(String abbrev, NomenclaturalCode nc, boolean useUnknown)
726
            throws UnknownCdmTypeException{
727

    
728
        if (nc != null && nc.equals(NomenclaturalCode.ICZN)) {
729
            if (abbrev != null){
730
                if (abbrev.equalsIgnoreCase("sect.")) {
731
                    return Rank.SECTION_ZOOLOGY();
732
                } else if (abbrev.equalsIgnoreCase("subsect.")) {
733
                    return Rank.SUBSECTION_ZOOLOGY();
734
                }
735
            }
736
        }
737
        return getRankByIdInVoc(abbrev, useUnknown);
738
    }
739

    
740
    // TODO
741
    // Preliminary implementation for BotanicalNameParser.
742
    // not yet complete
743
    /**
744
     * Returns the rank identified through a name.
745
     * Preliminary implementation for BotanicalNameParser.
746
     *
747
     * @param	rankName	the string for the name of the rank
748
     * @return  			the rank
749
     */
750
    public static Rank getRankByName(String rankName) throws UnknownCdmTypeException{
751
        return getRankByName(rankName, false);
752
    }
753

    
754

    
755
    // TODO
756
    // Preliminary implementation for ICBN and ICZN.
757
    // not yet complete
758
    /**
759
     * Returns the rank identified through a name for a given nomenclatural code.
760
     * Preliminary implementation for ICBN and ICZN.
761
     *
762
     * @param	rankName	the string for the name of the rank
763
     * @param	nc	        the nomenclatural code
764
     * @return  			the rank
765
     */
766
    public static Rank getRankByName(String rankName, NomenclaturalCode nc) throws UnknownCdmTypeException{
767
        return getRankByName(rankName, nc, false);
768
    }
769

    
770
    /**
771
     * Returns the rank identified through a name.
772
     * Preliminary implementation for BotanicalNameParser.
773
     * TODO At the moment we do not have Latin representations yet.
774
     *
775
     * @param	rankName	the string for the name of the rank
776
     * @param 	useUnknown 	if true the rank UNKNOWN_RANK is returned if the rank name is
777
     * 			unknown or not yet implemented
778
     * @return  			the rank
779
     */
780
    public static Rank getRankByName(String rankName, boolean useUnknown)
781
            throws UnknownCdmTypeException{
782
        if (rankName.equalsIgnoreCase("Regnum")){ return Rank.KINGDOM();
783
        }else if (rankName.equalsIgnoreCase("Subregnum")){ return Rank.SUBKINGDOM();
784
        }else if (rankName.equalsIgnoreCase("Phylum")){ return Rank.PHYLUM();
785
        }else if (rankName.equalsIgnoreCase("Subphylum")){ return Rank.SUBPHYLUM();
786
        }else if (rankName.equalsIgnoreCase("Divisio")){ return Rank.DIVISION();
787
        }else if (rankName.equalsIgnoreCase("Subdivisio")){ return Rank.SUBDIVISION();
788
        }else if (rankName.equalsIgnoreCase("Classis")){ return Rank.CLASS();
789
        }else if (rankName.equalsIgnoreCase("Subclassis")){ return Rank.SUBCLASS();
790
        }else if (rankName.equalsIgnoreCase("Superordo")){ return Rank.SUPERORDER();
791
        }else if (rankName.equalsIgnoreCase("Ordo")){ return Rank.ORDER();
792
        }else if (rankName.equalsIgnoreCase("Subordo")){ return Rank.SUBORDER();
793
        }else if (rankName.equalsIgnoreCase("Familia")){ return Rank.FAMILY();
794
        }else if (rankName.equalsIgnoreCase("Subfamilia")){ return Rank.SUBFAMILY();
795
        }else if (rankName.equalsIgnoreCase("Tribus")){ return Rank.TRIBE();
796
        }else if (rankName.equalsIgnoreCase("Subtribus")){ return Rank.SUBTRIBE();
797
        }else if (rankName.equalsIgnoreCase("Genus")){ return Rank.GENUS();
798
        }else if (rankName.equalsIgnoreCase("Subgenus")){ return Rank.SUBGENUS();
799
        }else if (rankName.equalsIgnoreCase("Sectio")){ return Rank.SECTION_BOTANY();
800
        }else if (rankName.equalsIgnoreCase("Subsectio")){ return Rank.SUBSECTION_BOTANY();
801
        }else if (rankName.equalsIgnoreCase("Series")){ return Rank.SERIES();
802
        }else if (rankName.equalsIgnoreCase("Subseries")){ return Rank.SUBSERIES();
803
        }else if (rankName.equalsIgnoreCase("Aggregate")){ return Rank.SPECIESAGGREGATE();
804
        }else if (rankName.equalsIgnoreCase("Speciesgroup")){ return Rank.SPECIESGROUP();
805
        }else if (rankName.equalsIgnoreCase("Species")){ return Rank.SPECIES();
806
        }else if (rankName.equalsIgnoreCase("Subspecies")){ return Rank.SUBSPECIES();
807
        }else if (rankName.equalsIgnoreCase("Convarietas")){ return Rank.CONVAR();
808
        }else if (rankName.equalsIgnoreCase("Varietas")){ return Rank.VARIETY();
809
        }else if (rankName.equalsIgnoreCase("Subvarietas")){ return Rank.SUBVARIETY();
810
        }else if (rankName.equalsIgnoreCase("Forma")){ return Rank.FORM();
811
        }else if (rankName.equalsIgnoreCase("Subforma")){ return Rank.SUBFORM();
812
        }else if (rankName.equalsIgnoreCase("Forma spec.")){ return Rank.SPECIALFORM();
813
        }else if (rankName.equalsIgnoreCase("tax.infragen.")){ return Rank.INFRAGENERICTAXON();
814
        }else if (rankName.equalsIgnoreCase("tax.infrasp.")){ return Rank.INFRASPECIFICTAXON();
815
        // old ranks
816
        }else if (rankName.equalsIgnoreCase("proles")){ return Rank.PROLES();
817
        }else if (rankName.equalsIgnoreCase("race")){ return Rank.RACE();
818
        }else if (rankName.equalsIgnoreCase("sublusus")){ return Rank.SUBLUSUS();
819

    
820
        }else if (rankName.equalsIgnoreCase("taxon")){ return Rank.INFRASPECIFICTAXON(); //to create the name put 'taxon' and the infraspeciesepi to the field unnamed namephrase
821

    
822
        }else{
823
            if (rankName == null){
824
                rankName = "(null)";  //see NPE above
825
            }
826
            if (useUnknown){
827
                logger.info("Unknown rank name: " + rankName+". Rank 'UNKNOWN_RANK' created instead");
828
                return Rank.UNKNOWN_RANK();
829
            }else{
830
                throw new UnknownCdmTypeException("Unknown rank name: " + rankName);
831
            }
832
        }
833
    }
834

    
835
    /**
836
     * Defines the rank according to the English name.
837
     * @param rankName English rank name.
838
     * @param nc Defines the handling of the section and subsection ranks. These are in different orders depending on the
839
     * nomenclatural code.
840
     * @param useUnknown if true, the "Unknown" rank is returned as a placeholder.
841
     * @return
842
     * @throws UnknownCdmTypeException never thrown if useUnknown is true
843
     */
844
    public static Rank getRankByEnglishName(String rankName, NomenclaturalCode nc, boolean useUnknown) throws UnknownCdmTypeException{
845
        Rank result = null;
846
        if (rankName == null){
847
            throw new NullPointerException("Abbrev is NULL in getRankByAbbreviation");
848
        }
849
        if (labelMap == null){
850
            return null;
851
        }
852
        //handle section and subsection (not unique representations)
853
        if (rankName.equalsIgnoreCase("Section")){
854
            if (nc != null && nc.equals(NomenclaturalCode.ICZN)){	return Rank.SECTION_ZOOLOGY();
855
            }else if (nc != null && nc.equals(NomenclaturalCode.ICNAFP)){return Rank.SECTION_BOTANY();
856
            }else{
857
                String errorWarning = "Section is only defined for ICZN and ICNAFP at the moment but here needed for " + ((nc == null)? "(null)": nc.toString());
858
                logger.warn(errorWarning);
859
                throw new UnknownCdmTypeException (errorWarning);
860
            }
861
        }else if (rankName.equalsIgnoreCase("Subsection")){
862
            if (nc != null && nc.equals(NomenclaturalCode.ICZN)){ return Rank.SUBSECTION_ZOOLOGY();
863
            }else if (nc != null && nc.equals(NomenclaturalCode.ICNAFP)){ return Rank.SUBSECTION_BOTANY();
864
            }else{
865
                String errorWarning = "Subsection is only defined for ICZN and ICBN at the moment but here needed for " + ((nc == null)? "(null)": nc.toString());
866
                logger.warn(errorWarning);
867
                throw new UnknownCdmTypeException (errorWarning);
868
            }
869
        }
870

    
871
        rankName = rankName.toLowerCase();
872

    
873
        UUID uuid = labelMap.get(rankName);
874
        if (uuid != null ){
875
            result = getTermByUuid(uuid);
876
        }
877
        if (result != null){
878
            return result;
879
        }else {
880
            if (rankName == null){
881
                rankName = "(null)";
882
            }
883
            if (useUnknown){
884
                logger.info("Unknown rank name: " + rankName + ". Rank 'UNKNOWN_RANK' created instead");
885
                return Rank.UNKNOWN_RANK();
886
            }else{
887
                throw new UnknownCdmTypeException("Unknown rank: " + rankName);
888
            }
889
        }
890
    }
891

    
892

    
893
    public static Rank getRankByName(String rankName, NomenclaturalCode nc, boolean useUnknown)
894
        throws UnknownCdmTypeException {
895

    
896
        if (nc.equals(NomenclaturalCode.ICZN)) {
897
            if (rankName.equalsIgnoreCase("Sectio")) { return Rank.SECTION_ZOOLOGY();
898
            }else if (rankName.equalsIgnoreCase("Subsectio")) { return Rank.SUBSECTION_ZOOLOGY();
899
            }
900
        }
901
        return getRankByName(rankName, useUnknown);
902
    }
903

    
904
    /**
905
     * Returns the abbreviated rank name for <i>this</i> rank according to the English representation
906
     * abbreviated label.
907
     * TODO Needs to be changed to Latin as soon as Latin representations are available.
908
     *
909
     * @return	the abbreviation string for <i>this</i> rank
910
     */
911
    public String getAbbreviation(){
912
        Language language = Language.getLanguageFromUuid(Language.uuidEnglish);
913
        String result = this.getRepresentation(language).getAbbreviatedLabel();
914
        if (result== null) {
915
            logger.warn("Abbreviation for this Rank " + this.toString() +  " not yet implemented");
916
            return "no abbreviation available.";
917
        }else{
918
            return result;
919
        }
920
    }
921
    @Transient
922
    public String getInfraGenericMarker() throws UnknownCdmTypeException{
923
        String result = null;
924
        if (! this.isInfraGeneric()){
925
            throw new IllegalStateException("An infrageneric marker is only available for a infrageneric rank but was asked for rank: " + this.toString());
926
        }else{
927
            result = this.getAbbreviation();
928
        }
929
        if (result == null){
930
            throw new UnknownCdmTypeException("Abbreviation for rank unknown: " + this.toString());
931
        }
932
        return result;
933
    }
934

    
935

    
936

    
937
    @Override
938
    public Rank readCsvLine(Class<Rank> termClass, List<String> csvLine, Map<UUID, DefinedTermBase> terms, boolean abbrevAsId) {
939
        Rank rank = super.readCsvLine(termClass, csvLine, terms, abbrevAsId);
940
        RankClass rankClass = RankClass.getByKey(csvLine.get(5));
941
        assert rankClass != null: "XXXXXXXXXXXXXXXXXXXXX  Rank class must not be null: " + csvLine ;
942
        rank.setRankClass(rankClass);
943
        return rank;
944
    }
945

    
946
    @Override
947
    protected void setDefaultTerms(TermVocabulary<Rank> termVocabulary) {
948
        termMap = new HashMap<UUID, Rank>();
949
        for (Rank term : termVocabulary.getTerms()){
950
            termMap.put(term.getUuid(), term);
951
            addRank(term);
952
        }
953
    }
954

    
955
    /**
956
     * @param term
957
     */
958
    private void addRank(Rank rank) {
959
        if (rank == null){
960
            logger.warn("rank is NULL");
961
            return;
962
        }
963
        if (rank.getUuid().equals(uuidSectionZoology) || rank.getUuid().equals(uuidSubsectionZoology )){
964
            //sect./subsect. is used for botanical sections, see also #getRankByAbbreviation(String, NomenclaturalCode, boolean)
965
            return;
966
        }
967
        Language lang = Language.DEFAULT();  //TODO should be Latin but at the moment we have only English representations
968
        Representation representation = rank.getRepresentation(lang);
969
        String abbrevLabel = representation.getAbbreviatedLabel();
970
        String label = representation.getLabel();
971

    
972
        //initialize maps
973
        if (idInVocMap == null){
974
            idInVocMap = new HashMap<String, UUID>();
975
        }
976
        if (labelMap == null){
977
            labelMap = new HashMap<String, UUID>();
978
        }
979
        labelMap.put(label.toLowerCase(), rank.getUuid());
980
        //add to map
981
        if (StringUtils.isBlank(abbrevLabel)){
982
            logger.info("Abbreviated label for rank is NULL or empty.Can't add rank to abbrevLabel map: " + CdmUtils.Nz(rank.getLabel()));
983
        }else{
984
            idInVocMap.put(abbrevLabel, rank.getUuid());
985
        }
986
    }
987

    
988

    
989
    /**
990
     * It is necessary to skip the vocabulary check, otherwise we would have
991
     * problems in some CacheStrategies, due to uninitialized Vocabularies.
992
     *
993
     * @see eu.etaxonomy.cdm.model.common.OrderedTermBase#compareTo(eu.etaxonomy.cdm.model.common.OrderedTermBase)
994
     */
995
    @Override
996
    public int compareTo(Rank orderedTerm) {
997
        return performCompareTo(orderedTerm, true);
998
    }
999

    
1000
}
(16-16/27)