2 * Copyright (C) 2007 EDIT
3 * European Distributed Institute of Taxonomy
4 * http://www.e-taxonomy.eu
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.
10 package eu
.etaxonomy
.cdm
.model
.name
;
13 import java
.util
.HashMap
;
14 import java
.util
.List
;
16 import java
.util
.UUID
;
18 import javax
.persistence
.Entity
;
19 import javax
.persistence
.Transient
;
20 import javax
.xml
.bind
.annotation
.XmlAccessType
;
21 import javax
.xml
.bind
.annotation
.XmlAccessorType
;
22 import javax
.xml
.bind
.annotation
.XmlType
;
24 import org
.apache
.commons
.lang
.StringUtils
;
25 import org
.apache
.log4j
.Logger
;
26 import org
.hibernate
.envers
.Audited
;
27 import org
.hibernate
.search
.annotations
.Indexed
;
29 import eu
.etaxonomy
.cdm
.model
.common
.DefinedTermBase
;
30 import eu
.etaxonomy
.cdm
.model
.common
.RelationshipTermBase
;
31 import eu
.etaxonomy
.cdm
.model
.common
.TermType
;
32 import eu
.etaxonomy
.cdm
.model
.common
.TermVocabulary
;
35 * The class representing the categories of {@link NameRelationship taxon name relationships} between
36 * two {@link TaxonNameBase taxon names}. These name relationship types are
37 * based on the concrete {@link NomenclaturalCode nomenclatural code} governing
38 * the taxon names involved in the name relationship or on decisions taken by
39 * the competent authorities; they do not depend on the use made of these
40 * taxon names in a particular reference or in a particular taxonomic treatment.
41 * Most relationships are to be understood as 'is .... of': for instance
42 * <i>Linum radiola</i> L. is a replaced synonym of <i>Radiola linoides</i> Roth or
43 * <i>Astragalus rhizanthus</i> Boiss. is a later homonym of
44 * <i>Astragalus rhizanthus</i> Royle.
46 * A standard (ordered) list of name relationship type instances will be
47 * automatically created as the project starts. But this class allows to extend
48 * this standard list by creating new instances of additional name relationship
51 * This class corresponds partially to: <ul>
52 * <li> TaxonRelationshipTerm and NomenclaturalNoteTypeTerm according to the TDWG ontology
53 * <li> RelationshipType and NomenclaturalNoteType according to the TCS
57 * @created 08-Nov-2007 13:06:38
59 @XmlAccessorType(XmlAccessType
.FIELD
)
60 @XmlType(name
= "NameRelationshipType")
62 @Indexed(index
= "eu.etaxonomy.cdm.model.common.DefinedTermBase")
64 public class NameRelationshipType
extends RelationshipTermBase
<NameRelationshipType
> {
65 private static final long serialVersionUID
= 8504916205254159334L;
67 static Logger logger
= Logger
.getLogger(NameRelationshipType
.class);
69 private static final UUID uuidOrthographicVariant
= UUID
.fromString("eeaea868-c4c1-497f-b9fe-52c9fc4aca53");
70 private static final UUID uuidMisspelling
= UUID
.fromString("c6f9afcb-8287-4a2b-a6f6-4da3a073d5de");
71 private static final UUID uuidEmendation
= UUID
.fromString("6e23ad45-3f2a-462b-ad87-d2389cd6e26c");
72 private static final UUID uuidLaterHomonym
= UUID
.fromString("80f06f65-58e0-4209-b811-cb40ad7220a6");
73 private static final UUID uuidTreatedAsLaterHomonym
= UUID
.fromString("2990a884-3302-4c8b-90b2-dfd31aaa2778");
74 private static final UUID uuidAlternativeName
= UUID
.fromString("049c6358-1094-4765-9fae-c9972a0e7780");
75 private static final UUID uuidBasionym
= UUID
.fromString("25792738-98de-4762-bac1-8c156faded4a");
76 private static final UUID uuidReplacedSynonym
= UUID
.fromString("71c67c38-d162-445b-b0c2-7aba56106696");
77 private static final UUID uuidConservedAgainst
= UUID
.fromString("e6439f95-bcac-4ebb-a8b5-69fa5ce79e6a");
78 private static final UUID uuidValidatedByName
= UUID
.fromString("a176c9ad-b4c2-4c57-addd-90373f8270eb");
79 private static final UUID uuidLaterValidatedByName
= UUID
.fromString("a25ee4c1-863a-4dab-9499-290bf9b89639");
80 private static final UUID uuidBlockingNameFor
= UUID
.fromString("1dab357f-2e12-4511-97a4-e5153589e6a6");
81 private static final UUID uuidLaterIsonym
= UUID
.fromString("29ab238d-598d-45b9-addd-003cf39ccc3e");
82 private static final UUID uuidOriginalSpellingFor
= UUID
.fromString("264d2be4-e378-4168-9760-a9512ffbddc4");
85 public static NameRelationshipType
NewInstance(String term
, String label
, String labelAbbrev
, boolean symmetric
, boolean transitive
) {
86 return new NameRelationshipType(term
, label
, labelAbbrev
, symmetric
, transitive
);
90 protected static Map
<UUID
, NameRelationshipType
> termMap
= null;
92 protected static NameRelationshipType
findTermByUuid(UUID uuid
){
96 return (NameRelationshipType
)termMap
.get(uuid
);
100 //********************************** Constructor *********************************/
102 //for hibernate use only
104 protected NameRelationshipType() {
105 super(TermType
.NameRelationshipType
);
109 * Class constructor: creates an additional name relationship type
110 * instance with a description, a label, a label abbreviation and the flags
111 * indicating whether <i>this</i> new name relationship type is symmetric and/or
114 * @param term the string (in the default language) describing the
115 * new name relationship type to be created
116 * @param label the string identifying the new name relationship
118 * @param labelAbbrev the string identifying (in abbreviated form) the
119 * new name relationship type to be created
120 * @param symmetric the boolean indicating whether the new name
121 * relationship type to be created is symmetric
122 * @param transitive the boolean indicating whether the new name
123 * relationship type to be created is transitive
124 * @see #NameRelationshipType()
126 private NameRelationshipType(String term
, String label
, String labelAbbrev
, boolean symmetric
, boolean transitive
) {
127 super(TermType
.NameRelationshipType
, term
, label
, labelAbbrev
, symmetric
, transitive
);
132 //************************** METHODS ********************************
135 * @see eu.etaxonomy.cdm.model.common.DefinedTermBase#resetTerms()
138 public void resetTerms(){
142 // TODO this method should be moved to consistency proof classes
144 * Returns the boolean value indicating whether the nomenclatural status
145 * type of the {@link eu.etaxonomy.cdm.model.common.RelationshipBase#getRelatedFrom() first taxon name}
146 * involved in a name relationship with <i>this</i> name relationship type should
147 * be "invalid" (true) or not (false). Returns false if <i>this</i> name
148 * relationship status type is null.
150 * @see #isLegitimateType()
151 * @see #isIllegitimateType()
152 * @see NomenclaturalStatusType#isInvalidType()
153 * @see eu.etaxonomy.cdm.model.common.RelationshipBase#getRelatedFrom()
156 public boolean isInvalidType(){
157 if (this.equals(VALIDATED_BY_NAME()) ||
158 this.equals(LATER_VALIDATED_BY_NAME())
166 // TODO this method should be moved to consistency proof classes
168 * Returns the boolean value indicating whether the nomenclatural status
169 * type of the {@link eu.etaxonomy.cdm.model.common.RelationshipBase#getRelatedFrom() first taxon name}
170 * involved in a name relationship with <i>this</i> name relationship type should
171 * be "legitimate" (true) or not (false). Returns false if <i>this</i> name
172 * relationship status type is null.
174 * @see #isInvalidType()
175 * @see #isIllegitimateType()
176 * @see NomenclaturalStatusType#isLegitimateType()
177 * @see eu.etaxonomy.cdm.model.common.RelationshipBase#getRelatedFrom()
180 public boolean isLegitimateType(){
181 if (this.equals(BASIONYM()) ||
182 this.equals(REPLACED_SYNONYM()) ||
183 this.equals(ALTERNATIVE_NAME()) ||
184 this.equals(CONSERVED_AGAINST())
192 // TODO this method should be moved to consistency proof classes
194 * Returns the boolean value indicating whether the nomenclatural status
195 * type of the {@link eu.etaxonomy.cdm.model.common.RelationshipBase#getRelatedFrom() first taxon name}
196 * involved in a name relationship with <i>this</i> name relationship type should
197 * be "illegitimate" (true) or not (false). Returns false if <i>this</i> name
198 * relationship status type is null.
200 * @see #isInvalidType()
201 * @see #isLegitimateType()
202 * @see NomenclaturalStatusType#isIllegitimateType()
203 * @see eu.etaxonomy.cdm.model.common.RelationshipBase#getRelatedFrom()
206 public boolean isIllegitimateType(){
207 //TODO: implement isX method. Maybe as persistent class attribute?
208 //TODO: RejectedInFavour,
209 if (this.equals(LATER_HOMONYM()) ||
210 this.equals(TREATED_AS_LATER_HOMONYM())
219 public boolean isBasionymRelation(){
220 if (BASIONYM() == null){
221 throw new IllegalStateException("NameRelationships have not been initialized yet. Please initialize DefinedTerms first");
223 return this.equals(BASIONYM());
227 public boolean isReplacedSynonymRelation(){
228 if (REPLACED_SYNONYM() == null){
229 throw new IllegalStateException("NameRelationships have not been initialized yet. Please initialize DefinedTerms first");
231 return this.equals(REPLACED_SYNONYM());
236 * Returns the "orthographic variant" name relationship type. The first
237 * {@link TaxonNameBase taxon name} involved in such a relationship is an
238 * orthographic variant of the second taxon name. The two {@link TaxonNameBase taxon names}
239 * involved in such a relationship must have the same {@link NonViralName#getAuthorshipCache() authorship}
240 * and {@link Rank rank}, belong to the same {@link HomotypicalGroup homotypical group} and their name parts
241 * must be almost identical (so one usually does not differentiate them).<BR>
242 * For instance <i>Angelica silvestris</i> L. is an orthographic variant of
243 * <i>Angelica sylvestris</i> L.<BR>
244 * This type is symmetric and transitive but usually orthographic variant relationships should be organized
245 * in a star schema with the correct variant in the middle and other variants pointing to it.
246 * @see #ORIGINAL_SPELLING()()
248 public static final NameRelationshipType
ORTHOGRAPHIC_VARIANT(){
249 return findTermByUuid(uuidOrthographicVariant
);
253 * Returns the {@link TaxonNameBase taxon name} as it is spelled in the original
254 * publication of the given name. The first (left) name in the relationship takes the role
255 * of the original spelling whereas the second (right) name takes the role of the
256 * current/correct spelling.<BR>
257 * Original spelling is a specialization of {@link #ORTHOGRAPHIC_VARIANT()}.
259 * @see #ORTHOGRAPHIC_VARIANT()
260 * @see #MISSPELLING()
262 public static final NameRelationshipType
ORIGINAL_SPELLING(){
263 return findTermByUuid(uuidOriginalSpellingFor
);
267 * Returns the "misspelling" name relationship type. The first
268 * {@link TaxonNameBase taxon name} involved in such a relationship is a
269 * misspelling of the second taxon name. The two {@link TaxonNameBase taxon names}
270 * involved in such a relationship must have the same {@link NonViralName#getAuthorshipCache() authorship}
271 * and {@link Rank rank}, belong to the same {@link HomotypicalGroup homotypical group} and their name parts
272 * must be almost identical (so one usually does not differentiate them).<BR>
273 * For instance <i>Anhelica silvestris</i> L. is a misspelling of
274 * <i>Angelica silvestris</i> L.<BR>
275 * A misspelling is always accicentally (not on purpose). Therefore misspellings are a
276 * subset of {@link #ORTHOGRAPHIC_VARIANT orthographic variants} and are complementary to
277 * emendations. A misspelling is always an {@link #ORTHOGRAPHIC_VARIANT orthographic variant}, too.
278 * This type is symmetric and transitive but usually the misspelling relationships should be organized
279 * in a star schema with the correct variant in the middle and the misspellings pointing to it.
280 * @see #ORTHOGRAPHIC_VARIANT()
281 * @see #ORIGINAL_SPELLING()
283 public static final NameRelationshipType
MISSPELLING(){
284 return findTermByUuid(uuidMisspelling
);
287 * Returns the "emendation" name relationship type. The first
288 * {@link TaxonNameBase taxon name} involved in such a relationship is a
289 * misspelling of the second taxon name. The two {@link TaxonNameBase taxon names}
290 * involved in such a relationship must have the same {@link NonViralName#getAuthorshipCache() authorship}
291 * and {@link Rank rank}, belong to the same {@link HomotypicalGroup homotypical group} and their name parts
292 * must be almost identical (so one usually does not differentiate them).<BR>
293 * For instance <i>Angelica silvestris</i> L. is a emendation of
294 * <i>Angelica sylvestris</i> L.<BR>
295 * The name corrected by an emendation has originally been used on purpose (not accidentially)
296 * Therefore emendations are a subset of {@link #ORTHOGRAPHIC_VARIANT orthographic variants} and are
297 * complementary to {@link #MISSPELLING missepllings}. An emendation is always an
298 * {@link #ORTHOGRAPHIC_VARIANT orthographic variant}, too.<BR>
299 * This type is symmetric and transitive but usually the misspelling relationships should be organized
300 * in a star schema with the correct variant in the middle and the misspellings pointing to it.
302 public static final NameRelationshipType
EMENDATION(){
303 return findTermByUuid(uuidEmendation
);
306 * Returns the "later homonym" name relationship type. The first
307 * {@link TaxonNameBase taxon name} involved in such a relationship should
308 * have been published after the second taxon name. The two {@link TaxonNameBase taxon names}
309 * involved in such a relationship must belong to different
310 * {@link HomotypicalGroup homotypical groups}, have in general different
311 * {@link NonViralName#getAuthorshipCache() authorship} and their name parts (excluding infraspecific
312 * {@link Rank ranks}) must be (almost) identical, so one could be mistaken for
313 * the other one. The first taxon name is "illegitimate" and the second one
314 * is "legitimate" (this corresponds to "invalid" and "valid" in case of
315 * {@link ZoologicalName zoological names}).<BR>
316 * For instance <i>Astragalus rhizanthus</i> Boiss. is a later homonym of
317 * <i>Astragalus rhizanthus</i> Royle.<BR>
318 * This type is not symmetric but transitive.
320 * @see NomenclaturalStatusType#isIllegitimateType()
321 * @see NomenclaturalStatusType#isLegitimateType()
323 public static final NameRelationshipType
LATER_HOMONYM(){
324 return findTermByUuid(uuidLaterHomonym
);
329 * Returns the "treated as later homonym" name relationship type. The first
330 * {@link TaxonNameBase taxon name} involved in such a relationship is
331 * treated as an homonym although it has been published before the second
332 * taxon name. The two taxon names involved must belong to different
333 * {@link HomotypicalGroup homotypical groups} and their name parts (excluding
334 * {@link Rank#isInfraSpecific() infraspecific ranks} and {@link NonViralName#getAuthorshipCache() authorship}) must be
335 * almost identical (so one could be mistaken for the other). The first
336 * taxon name is "illegitimate" and the second one is "legitimate" (this
337 * corresponds to "invalid" and "valid" in case of {@link ZoologicalName zoological names}).<BR>
338 * This type is not symmetric but transitive.
340 * @see #LATER_HOMONYM()
341 * @see NomenclaturalStatusType#isIllegitimateType()
342 * @see NomenclaturalStatusType#isLegitimateType()
344 public static final NameRelationshipType
TREATED_AS_LATER_HOMONYM(){
345 return findTermByUuid(uuidTreatedAsLaterHomonym
);
349 * Returns the "later isonym" name relationship type where the first
350 * {@link TaxonNameBase taxon name} involved has been published after the second taxon name.<BR>
351 * In contrast to the {@link #LATER_HOMONYM() later homonym} relationship the two
352 * {@link TaxonNameBase taxon names} involved have the type(s) so they belong to the
353 * same {@link HomotypicalGroup homotypical groups}. As later homonyms they have in general
354 * different {@link NonViralName#getAuthorshipCache() authorship} and their name parts
355 * must be (almost) identical, so one could be mistaken for the other one.<BR>
356 * Later isonyms are validly published names but with a wrong citation. So there are rather errors
357 * then independent names.<BR>
358 * Isonyms are handled in Article 6, Note 2 of the ICNAFP (Melbourne Code):
359 * <code>When the same name, based on the same type, has been published independently at different
360 * times perhaps by different authors, then only the earliest of these �isonyms� has
361 * nomenclatural status. The name is always to be cited from its original
362 * place of valid publication, and later isonyms may be disregarded (but see Art. 14.15).</code>
364 * See discussion at: <a href=http://dev.e-taxonomy.eu/trac/ticket/2901>#2901</a>
367 public static final NameRelationshipType
LATER_ISONYM(){
368 return findTermByUuid(uuidLaterIsonym
);
372 * Returns the "alternative name" name relationship type. Both {@link TaxonNameBase taxon names}
373 * involved in such a relationship are family names. The first one is a
374 * classical name long in use, in some cases, even before 1753 and is considered as
375 * {@link NomenclaturalStatusType#VALID() valid} and also {@link NomenclaturalStatusType#isLegitimateType() legitimate}
376 * although it does not follow the rules for family names (see Article 18 of
377 * the ICBN). An alternative name is typified by the type of the name
378 * it is alternative to (so both must belong to the same
379 * {@link HomotypicalGroup homotypical group}).<BR>
380 * For instance <i>Cruciferae</i> Adans is an alternative name to
381 * <i>Brassicaceae</i> Lindl.<BR>
382 * This type is neither symmetric nor transitive.
384 public static final NameRelationshipType
ALTERNATIVE_NAME(){
385 return findTermByUuid(uuidAlternativeName
);
388 * Returns the "basionym" name relationship type. The first {@link TaxonNameBase taxon name}
389 * involved in such a relationship is the "basionym" of the second taxon
390 * name. Both taxon names belong to the same {@link HomotypicalGroup homotypical group}).
391 * The basionym is the epithet-bringing taxon name (first taxon name
392 * ever validly published given to the same {@link Rank#isInfraGeneric() infrageneric}
393 * taxon, the epithet of which is the same as in the second taxon name
394 * originated through a reclassification).<BR>
395 * According to the ICBN the author of the basionym must be mentioned in the
396 * later taxon name (by placing it in parentheses before the authority of
397 * the new combination). For instance <i>Pinus abies</i> L. is the basionym of
398 * <i>Picea abies</i> (L.) H. Karst.<BR>
399 * This type is neither symmetric nor transitive.
401 public static final NameRelationshipType
BASIONYM(){
402 return findTermByUuid(uuidBasionym
);
405 * Returns the "replaced synonym" name relationship type. The first
406 * {@link TaxonNameBase taxon name} involved in such a relationship is the
407 * "replaced synonym" of the second taxon name. Both taxon names belong to
408 * the same {@link HomotypicalGroup homotypical group}. The replaced synonym is the
409 * first taxon name ever validly published given to the same
410 * {@link Rank#isInfraGeneric() infrageneric} taxon that is either itself a
411 * "later homonym" or the epithet of which could not be used in the new
412 * taxon name originated through a reclassification. A new epithet must be
413 * proposed if the use of the original epithet leads to an already existing
414 * taxon name (for another taxon) or in botany to autonyms (since the ICBN
415 * does not allow such names where epithet and genus name are the same).<BR>
416 * For instance <i>Spartium biflorum</i> Desf. is the replaced synonym of
417 * of <i>Cytisus fontanesii</i> Spach ("novum" taxon name) because at the time
418 * of reclassification a taxon name <i>Cytisus biflorum</i> had been already
419 * published by L'H�r.<BR>
420 * This type is neither symmetric nor transitive.
423 * @see #LATER_HOMONYM()
424 * @see NomenclaturalStatusType#NOVUM()
426 public static final NameRelationshipType
REPLACED_SYNONYM(){
427 return findTermByUuid(uuidReplacedSynonym
);
430 * Returns the "conserved against" name relationship type. Both {@link TaxonNameBase taxon names}
431 * involved in such a relationship belong to the same {@link HomotypicalGroup homotypical group}.
432 * Competent authorities decided, regardless of the general
433 * nomenclatural rules, to handle the first one as the "legitimate"
434 * one and the second taxon name as "illegitimate" (this corresponds to
435 * "valid" and "invalid" in case of {@link ZoologicalName zoological names}).<BR>
436 * For instance <i>Cephaloziella</i> (Spruce) Schiffn. is conserved against
437 * <i>Dichiton</i> Mont.<BR>
438 * This type is neither symmetric nor transitive.
440 * @see NomenclaturalStatusType#CONSERVED()
441 * @see NomenclaturalStatusType#REJECTED()
442 * @see NomenclaturalStatusType#isLegitimateType()
443 * @see NomenclaturalStatusType#isIllegitimateType()
445 public static final NameRelationshipType
CONSERVED_AGAINST(){
446 return findTermByUuid(uuidConservedAgainst
);
449 * Returns the "validated by name" name relationship type. The two
450 * {@link TaxonNameBase taxon names} involved in such a relationship were published
451 * in order to define the same taxonomical group but the first
452 * (earlier) taxon name was invalidly published whereas the second (later)
453 * taxon name is the one which was validly published for the first time.<BR>
454 * This type is neither symmetric nor transitive.
456 * @see NomenclaturalStatusType#isInvalidType()
457 * @see NomenclaturalStatusType#VALID()
459 public static final NameRelationshipType
VALIDATED_BY_NAME(){
460 return findTermByUuid(uuidValidatedByName
);
463 * Returns the "later validated by name" name relationship type. The two
464 * {@link TaxonNameBase taxon names} involved in such a relationship were published
465 * in order to define the same taxonomical group but the first
466 * (earlier) taxon name was invalidly published whereas the second (later)
467 * taxon name is the one which was validly published for the first time.<BR>
468 * This type is neither symmetric nor transitive.
470 * @see NomenclaturalStatusType#isInvalidType()
471 * @see NomenclaturalStatusType#VALID()
473 public static final NameRelationshipType
LATER_VALIDATED_BY_NAME(){
474 return findTermByUuid(uuidLaterValidatedByName
);
477 * Returns the "blocking name" name relationship type. The first
478 * {@link TaxonNameBase taxon name} involved in such a relationship is the
479 * "blocking name" for the second taxon name. Both taxon names belong to
480 * different {@link HomotypicalGroup homotypical groups}). The blocking taxon name is the
481 * {@link Rank#isInfraGeneric() infrageneric} taxon name, already published at the time of
482 * reclassification, which makes illegitim (because of homonymy) the use of
483 * the epithet in the second taxon name originated through a reclassification.
484 * Therefore a "replaced synonym" name relationship arises.<BR>
485 * For instance <i>Cytisus biflorum</i> L'H�r. is the blocking name for
486 * <i>Cytisus fontanesii</i> Spach ("novum" taxon name) when reclassifying
487 * <i>Spartium biflorum</i> Desf. from <i>Spartium</i> to <i>Cytisus</i>.<BR>
488 * This type is neither symmetric nor transitive.
490 * @see #REPLACED_SYNONYM()
491 * @see #LATER_HOMONYM()
492 * @see NomenclaturalStatusType#NOVUM()
494 public static final NameRelationshipType
BLOCKING_NAME_FOR(){
495 return findTermByUuid(uuidBlockingNameFor
);
499 protected void setDefaultTerms(TermVocabulary
<NameRelationshipType
> termVocabulary
) {
500 termMap
= new HashMap
<UUID
, NameRelationshipType
>();
501 for (NameRelationshipType term
: termVocabulary
.getTerms()){
502 termMap
.put(term
.getUuid(), term
);
507 public NameRelationshipType
readCsvLine(Class
<NameRelationshipType
> termClass
, List
<String
> csvLine
, Map
<UUID
,DefinedTermBase
> terms
, boolean abbrevAsId
) {
508 NameRelationshipType result
= super.readCsvLine(termClass
, csvLine
, terms
, abbrevAsId
);
509 String kindOfString
= csvLine
.get(10).trim();
510 if (StringUtils
.isNotBlank(kindOfString
)){
511 UUID uuidKindOf
= UUID
.fromString(kindOfString
);
512 DefinedTermBase
<?
> kindOf
= terms
.get(uuidKindOf
);
513 result
.setKindOf((NameRelationshipType
)kindOf
);