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
;
12 import java
.lang
.reflect
.Method
;
13 import java
.util
.HashSet
;
14 import java
.util
.List
;
18 import javax
.persistence
.Column
;
19 import javax
.persistence
.Entity
;
20 import javax
.persistence
.FetchType
;
21 import javax
.persistence
.Inheritance
;
22 import javax
.persistence
.InheritanceType
;
23 import javax
.persistence
.ManyToMany
;
24 import javax
.persistence
.ManyToOne
;
25 import javax
.persistence
.OneToMany
;
26 import javax
.persistence
.Transient
;
27 import javax
.validation
.Valid
;
28 import javax
.validation
.constraints
.NotNull
;
29 import javax
.validation
.constraints
.Size
;
30 import javax
.xml
.bind
.annotation
.XmlAccessType
;
31 import javax
.xml
.bind
.annotation
.XmlAccessorType
;
32 import javax
.xml
.bind
.annotation
.XmlAttribute
;
33 import javax
.xml
.bind
.annotation
.XmlElement
;
34 import javax
.xml
.bind
.annotation
.XmlElementWrapper
;
35 import javax
.xml
.bind
.annotation
.XmlIDREF
;
36 import javax
.xml
.bind
.annotation
.XmlRootElement
;
37 import javax
.xml
.bind
.annotation
.XmlSchemaType
;
38 import javax
.xml
.bind
.annotation
.XmlType
;
40 import org
.apache
.log4j
.Logger
;
41 import org
.hibernate
.annotations
.Cascade
;
42 import org
.hibernate
.annotations
.CascadeType
;
43 import org
.hibernate
.annotations
.Index
;
44 import org
.hibernate
.annotations
.Table
;
45 import org
.hibernate
.envers
.Audited
;
46 import org
.hibernate
.search
.annotations
.Field
;
47 import org
.hibernate
.search
.annotations
.IndexedEmbedded
;
48 import org
.hibernate
.validator
.constraints
.NotEmpty
;
49 import org
.springframework
.util
.ReflectionUtils
;
51 import eu
.etaxonomy
.cdm
.model
.common
.IParsable
;
52 import eu
.etaxonomy
.cdm
.model
.common
.IReferencedEntity
;
53 import eu
.etaxonomy
.cdm
.model
.common
.IRelated
;
54 import eu
.etaxonomy
.cdm
.model
.common
.IdentifiableEntity
;
55 import eu
.etaxonomy
.cdm
.model
.common
.RelationshipBase
;
56 import eu
.etaxonomy
.cdm
.model
.description
.TaxonNameDescription
;
57 import eu
.etaxonomy
.cdm
.model
.occurrence
.Specimen
;
58 import eu
.etaxonomy
.cdm
.model
.reference
.INomenclaturalReference
;
59 import eu
.etaxonomy
.cdm
.model
.reference
.Reference
;
60 import eu
.etaxonomy
.cdm
.model
.taxon
.Synonym
;
61 import eu
.etaxonomy
.cdm
.model
.taxon
.Taxon
;
62 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonBase
;
63 import eu
.etaxonomy
.cdm
.strategy
.cache
.name
.CacheUpdate
;
64 import eu
.etaxonomy
.cdm
.strategy
.cache
.name
.INameCacheStrategy
;
65 import eu
.etaxonomy
.cdm
.strategy
.match
.IMatchable
;
66 import eu
.etaxonomy
.cdm
.strategy
.match
.Match
;
67 import eu
.etaxonomy
.cdm
.strategy
.match
.MatchMode
;
68 import eu
.etaxonomy
.cdm
.strategy
.match
.Match
.ReplaceMode
;
69 import eu
.etaxonomy
.cdm
.strategy
.merge
.Merge
;
70 import eu
.etaxonomy
.cdm
.strategy
.merge
.MergeMode
;
71 import eu
.etaxonomy
.cdm
.strategy
.parser
.ParserProblem
;
72 import eu
.etaxonomy
.cdm
.validation
.Level2
;
73 import eu
.etaxonomy
.cdm
.validation
.annotation
.NullOrNotEmpty
;
76 * The upmost (abstract) class for scientific taxon names regardless of any
77 * particular {@link NomenclaturalCode nomenclature code}. The scientific taxon name does not depend
78 * on the use made of it in a publication or a treatment
79 * ({@link eu.etaxonomy.cdm.model.taxon.TaxonBase taxon concept respectively potential taxon})
80 * as an {@link eu.etaxonomy.cdm.model.taxon.Taxon "accepted" respectively "correct" (taxon) name}
81 * or as a {@link eu.etaxonomy.cdm.model.taxon.Synonym synonym}.
83 * This class corresponds partially to: <ul>
84 * <li> TaxonName according to the TDWG ontology
85 * <li> ScientificName and CanonicalName according to the TCS
86 * <li> ScientificName according to the ABCD schema
91 * @created 08-Nov-2007 13:06:57
93 @XmlAccessorType(XmlAccessType
.FIELD
)
94 @XmlType(name
= "TaxonNameBase", propOrder
= {
96 "nomenclaturalMicroReference",
97 "nomenclaturalReference",
100 "protectedFullTitleCache",
103 "relationsFromThisName",
104 "relationsToThisName",
109 @XmlRootElement(name
= "TaxonNameBase")
112 @Inheritance(strategy
=InheritanceType
.SINGLE_TABLE
)
113 @Table(appliesTo
="TaxonNameBase", indexes
= { @Index(name
= "taxonNameBaseTitleCacheIndex", columnNames
= { "titleCache" }) })
114 public abstract class TaxonNameBase
<T
extends TaxonNameBase
<?
,?
>, S
extends INameCacheStrategy
> extends IdentifiableEntity
<S
> implements IReferencedEntity
, IParsable
, IRelated
, IMatchable
, Cloneable
{
115 private static final long serialVersionUID
= -4530368639601532116L;
116 private static final Logger logger
= Logger
.getLogger(TaxonNameBase
.class);
118 @XmlElement(name
= "FullTitleCache")
119 @Column(length
=330, name
="fullTitleCache")
120 @Match(value
=MatchMode
.CACHE
, cacheReplaceMode
=ReplaceMode
.ALL
)
121 @CacheUpdate(noUpdate
="titleCache")
122 @NotEmpty(groups
= Level2
.class)
124 protected String fullTitleCache
;
126 //if true titleCache will not be automatically generated/updated
127 @XmlElement(name
= "ProtectedFullTitleCache")
128 @CacheUpdate(value
="fullTitleCache", noUpdate
="titleCache")
129 private boolean protectedFullTitleCache
;
131 @XmlElementWrapper(name
= "Descriptions")
132 @XmlElement(name
= "Description")
133 @OneToMany(mappedBy
="taxonName", fetch
= FetchType
.LAZY
)
134 @Cascade({CascadeType
.SAVE_UPDATE
, CascadeType
.MERGE
, CascadeType
.DELETE
, CascadeType
.DELETE_ORPHAN
})
136 private Set
<TaxonNameDescription
> descriptions
= new HashSet
<TaxonNameDescription
>();
138 @XmlElement(name
= "AppendedPhrase")
139 @Field(index
= org
.hibernate
.search
.annotations
.Index
.TOKENIZED
)
140 @CacheUpdate(value
="nameCache")
143 private String appendedPhrase
;
145 @XmlElement(name
= "NomenclaturalMicroReference")
146 @Field(index
= org
.hibernate
.search
.annotations
.Index
.TOKENIZED
)
147 @CacheUpdate(noUpdate
="titleCache")
150 private String nomenclaturalMicroReference
;
153 @CacheUpdate(noUpdate
={"titleCache","fullTitleCache"})
154 private int parsingProblem
= 0;
157 @CacheUpdate(noUpdate
={"titleCache","fullTitleCache"})
158 private int problemStarts
= -1;
161 @CacheUpdate(noUpdate
={"titleCache","fullTitleCache"})
162 private int problemEnds
= -1;
164 @XmlElementWrapper(name
= "TypeDesignations")
165 @XmlElement(name
= "TypeDesignation")
167 @XmlSchemaType(name
= "IDREF")
168 @ManyToMany(fetch
= FetchType
.LAZY
)
169 @Cascade({CascadeType
.SAVE_UPDATE
, CascadeType
.MERGE
, CascadeType
.DELETE
, CascadeType
.DELETE_ORPHAN
})
171 private Set
<TypeDesignationBase
<?
>> typeDesignations
= new HashSet
<TypeDesignationBase
<?
>>();
173 @XmlElement(name
= "HomotypicalGroup")
175 @XmlSchemaType(name
= "IDREF")
176 @ManyToOne(fetch
= FetchType
.LAZY
)
177 @Cascade({CascadeType
.SAVE_UPDATE
, CascadeType
.MERGE
})
178 @Match(MatchMode
.IGNORE
)
179 @CacheUpdate(noUpdate
="titleCache")
181 private HomotypicalGroup homotypicalGroup
;
183 @XmlElementWrapper(name
= "RelationsFromThisName")
184 @XmlElement(name
= "RelationFromThisName")
185 @OneToMany(mappedBy
="relatedFrom", fetch
= FetchType
.LAZY
)
186 @Cascade({CascadeType
.SAVE_UPDATE
, CascadeType
.MERGE
, CascadeType
.DELETE_ORPHAN
})
187 @Merge(MergeMode
.RELATION
)
190 private Set
<NameRelationship
> relationsFromThisName
= new HashSet
<NameRelationship
>();
192 @XmlElementWrapper(name
= "RelationsToThisName")
193 @XmlElement(name
= "RelationToThisName")
195 @XmlSchemaType(name
= "IDREF")
196 @OneToMany(mappedBy
="relatedTo", fetch
= FetchType
.LAZY
)
197 @Cascade({CascadeType
.SAVE_UPDATE
, CascadeType
.MERGE
, CascadeType
.DELETE_ORPHAN
})
198 @Merge(MergeMode
.RELATION
)
201 private Set
<NameRelationship
> relationsToThisName
= new HashSet
<NameRelationship
>();
203 @XmlElementWrapper(name
= "NomenclaturalStatuses")
204 @XmlElement(name
= "NomenclaturalStatus")
205 @OneToMany(fetch
= FetchType
.LAZY
)
206 @Cascade({CascadeType
.SAVE_UPDATE
, CascadeType
.MERGE
,CascadeType
.DELETE
,CascadeType
.DELETE_ORPHAN
})
208 private Set
<NomenclaturalStatus
> status
= new HashSet
<NomenclaturalStatus
>();
210 @XmlElementWrapper(name
= "TaxonBases")
211 @XmlElement(name
= "TaxonBase")
213 @XmlSchemaType(name
= "IDREF")
214 @OneToMany(mappedBy
="name", fetch
= FetchType
.LAZY
)
216 private Set
<TaxonBase
> taxonBases
= new HashSet
<TaxonBase
>();
218 @XmlElement(name
= "Rank")
220 @XmlSchemaType(name
= "IDREF")
221 @ManyToOne(fetch
= FetchType
.EAGER
)
222 @CacheUpdate(value
="nameCache")
226 @XmlElement(name
= "NomenclaturalReference")
228 @XmlSchemaType(name
= "IDREF")
229 @ManyToOne(fetch
= FetchType
.LAZY
)
230 @Cascade({CascadeType
.SAVE_UPDATE
})
231 @CacheUpdate(noUpdate
="titleCache")
233 private Reference nomenclaturalReference
;
235 // ************* CONSTRUCTORS *************/
237 * Class constructor: creates a new empty taxon name.
239 * @see #TaxonNameBase(Rank)
240 * @see #TaxonNameBase(HomotypicalGroup)
241 * @see #TaxonNameBase(Rank, HomotypicalGroup)
243 public TaxonNameBase() {
247 * Class constructor: creates a new taxon name
248 * only containing its {@link Rank rank}.
250 * @param rank the rank to be assigned to <i>this</i> taxon name
251 * @see #TaxonNameBase()
252 * @see #TaxonNameBase(HomotypicalGroup)
253 * @see #TaxonNameBase(Rank, HomotypicalGroup)
255 public TaxonNameBase(Rank rank
) {
259 * Class constructor: creates a new taxon name
260 * only containing its {@link HomotypicalGroup homotypical group}.
261 * The new taxon name will be also added to the set of taxon names
262 * belonging to this homotypical group.
264 * @param homotypicalGroup the homotypical group to which <i>this</i> taxon name belongs
265 * @see #TaxonNameBase()
266 * @see #TaxonNameBase(Rank)
267 * @see #TaxonNameBase(Rank, HomotypicalGroup)
269 public TaxonNameBase(HomotypicalGroup homotypicalGroup
) {
270 this(null, homotypicalGroup
);
273 * Class constructor: creates a new taxon name
274 * only containing its {@link Rank rank} and
275 * its {@link HomotypicalGroup homotypical group}.
276 * The new taxon name will be also added to the set of taxon names
277 * belonging to this homotypical group.
279 * @param rank the rank to be assigned to <i>this</i> taxon name
280 * @param homotypicalGroup the homotypical group to which <i>this</i> taxon name belongs
281 * @see #TaxonNameBase()
282 * @see #TaxonNameBase(Rank)
283 * @see #TaxonNameBase(HomotypicalGroup)
285 public TaxonNameBase(Rank rank
, HomotypicalGroup homotypicalGroup
) {
288 if (homotypicalGroup
== null){
289 homotypicalGroup
= new HomotypicalGroup();
291 homotypicalGroup
.addTypifiedName(this);
294 abstract protected Map
<String
, java
.lang
.reflect
.Field
> getAllFields();
296 //********* METHODS **************************************/
299 * Returns the boolean value "false" since the components of <i>this</i> taxon name
300 * cannot follow the rules of a corresponding {@link NomenclaturalCode nomenclatural code}
301 * which is not defined for this class. The nomenclature code depends on
302 * the concrete name subclass ({@link BacterialName BacterialName},
303 * {@link BotanicalName BotanicalName}, {@link CultivarPlantName CultivarPlantName},
304 * {@link ZoologicalName ZoologicalName} or {@link ViralName ViralName})
305 * to which a taxon name belongs.
310 public abstract boolean isCodeCompliant();
312 public abstract String
generateFullTitle();
317 public List
<Object
> getTaggedName(){
318 return getCacheStrategy().getTaggedName(this);
322 public String
getFullTitleCache(){
323 if (protectedFullTitleCache
){
324 return this.fullTitleCache
;
326 if (fullTitleCache
== null ){
327 this.fullTitleCache
= getTruncatedCache(generateFullTitle());
329 return fullTitleCache
;
333 public void setFullTitleCache(String fullTitleCache
){
334 setFullTitleCache(fullTitleCache
, PROTECTED
);
337 public void setFullTitleCache(String fullTitleCache
, boolean protectCache
){
338 fullTitleCache
= getTruncatedCache(fullTitleCache
);
339 this.fullTitleCache
= fullTitleCache
;
340 this.setProtectedFullTitleCache(protectCache
);
344 public boolean isProtectedFullTitleCache() {
345 return protectedFullTitleCache
;
348 public void setProtectedFullTitleCache(boolean protectedFullTitleCache
) {
349 this.protectedFullTitleCache
= protectedFullTitleCache
;
353 * Returns the set of all {@link NameRelationship name relationships}
354 * in which <i>this</i> taxon name is involved. A taxon name can be both source
355 * in some name relationships or target in some others.
357 * @see #getRelationsToThisName()
358 * @see #getRelationsFromThisName()
359 * @see #addNameRelationship(NameRelationship)
360 * @see #addRelationshipToName(TaxonNameBase, NameRelationshipType, String)
361 * @see #addRelationshipFromName(TaxonNameBase, NameRelationshipType, String)
364 public Set
<NameRelationship
> getNameRelations() {
365 Set
<NameRelationship
> rels
= new HashSet
<NameRelationship
>();
366 rels
.addAll(getRelationsFromThisName());
367 rels
.addAll(getRelationsToThisName());
372 * Creates a new {@link NameRelationship#NameRelationship(TaxonNameBase, TaxonNameBase, NameRelationshipType, String) name relationship} from <i>this</i> taxon name to another taxon name
373 * and adds it both to the set of {@link #getRelationsFromThisName() relations from <i>this</i> taxon name} and
374 * to the set of {@link #getRelationsToThisName() relations to the other taxon name}.
376 * @param toName the taxon name of the target for this new name relationship
377 * @param type the type of this new name relationship
378 * @param ruleConsidered the string which specifies the rule on which this name relationship is based
379 * @see #getRelationsToThisName()
380 * @see #getNameRelations()
381 * @see #addRelationshipFromName(TaxonNameBase, NameRelationshipType, String)
382 * @see #addNameRelationship(NameRelationship)
384 public void addRelationshipToName(TaxonNameBase toName
, NameRelationshipType type
, String ruleConsidered
){
385 addRelationshipToName(toName
, type
, null, null, ruleConsidered
);
386 // NameRelationship rel = new NameRelationship(toName, this, type, ruleConsidered);
390 * Creates a new {@link NameRelationship#NameRelationship(TaxonNameBase, TaxonNameBase, NameRelationshipType, String) name relationship} from <i>this</i> taxon name to another taxon name
391 * and adds it both to the set of {@link #getRelationsFromThisName() relations from <i>this</i> taxon name} and
392 * to the set of {@link #getRelationsToThisName() relations to the other taxon name}.
394 * @param toName the taxon name of the target for this new name relationship
395 * @param type the type of this new name relationship
396 * @param ruleConsidered the string which specifies the rule on which this name relationship is based
398 * @see #getRelationsToThisName()
399 * @see #getNameRelations()
400 * @see #addRelationshipFromName(TaxonNameBase, NameRelationshipType, String)
401 * @see #addNameRelationship(NameRelationship)
403 public NameRelationship
addRelationshipToName(TaxonNameBase toName
, NameRelationshipType type
, Reference citation
, String microCitation
, String ruleConsidered
){
405 throw new NullPointerException("Null is not allowed as name for a name relationship");
407 NameRelationship rel
= new NameRelationship(toName
, this, type
, citation
, microCitation
, ruleConsidered
);
412 * Creates a new {@link NameRelationship#NameRelationship(TaxonNameBase, TaxonNameBase, NameRelationshipType, String) name relationship} from another taxon name to <i>this</i> taxon name
413 * and adds it both to the set of {@link #getRelationsToThisName() relations to <i>this</i> taxon name} and
414 * to the set of {@link #getRelationsFromThisName() relations from the other taxon name}.
416 * @param fromName the taxon name of the source for this new name relationship
417 * @param type the type of this new name relationship
418 * @param ruleConsidered the string which specifies the rule on which this name relationship is based
419 * @param citation the reference in which this relation was described
420 * @param microCitation the reference detail for this relation (e.g. page)
421 * @see #getRelationsFromThisName()
422 * @see #getNameRelations()
423 * @see #addRelationshipToName(TaxonNameBase, NameRelationshipType, String)
424 * @see #addNameRelationship(NameRelationship)
426 public void addRelationshipFromName(TaxonNameBase fromName
, NameRelationshipType type
, String ruleConsidered
){
427 fromName
.addRelationshipToName(this, type
, null, null, ruleConsidered
);
428 // NameRelationship rel = new NameRelationship(this, fromName, type, ruleConsidered);
431 * Creates a new {@link NameRelationship#NameRelationship(TaxonNameBase, TaxonNameBase, NameRelationshipType, String) name relationship} from another taxon name to <i>this</i> taxon name
432 * and adds it both to the set of {@link #getRelationsToThisName() relations to <i>this</i> taxon name} and
433 * to the set of {@link #getRelationsFromThisName() relations from the other taxon name}.
435 * @param fromName the taxon name of the source for this new name relationship
436 * @param type the type of this new name relationship
437 * @param ruleConsidered the string which specifies the rule on which this name relationship is based
438 * @param citation the reference in which this relation was described
439 * @param microCitation the reference detail for this relation (e.g. page)
440 * @see #getRelationsFromThisName()
441 * @see #getNameRelations()
442 * @see #addRelationshipToName(TaxonNameBase, NameRelationshipType, String)
443 * @see #addNameRelationship(NameRelationship)
445 public void addRelationshipFromName(TaxonNameBase fromName
, NameRelationshipType type
, Reference citation
, String microCitation
, String ruleConsidered
){
446 fromName
.addRelationshipToName(this, type
, citation
, microCitation
, ruleConsidered
);
450 * Adds an existing {@link NameRelationship name relationship} either to the set of
451 * {@link #getRelationsToThisName() relations to <i>this</i> taxon name} or to the set of
452 * {@link #getRelationsFromThisName() relations from <i>this</i> taxon name}. If neither the
453 * source nor the target of the name relationship match with <i>this</i> taxon name
454 * no addition will be carried out.
456 * @param rel the name relationship to be added to one of <i>this</i> taxon name's name relationships sets
457 * @see #getNameRelations()
458 * @see #addRelationshipToName(TaxonNameBase, NameRelationshipType, String)
459 * @see #addRelationshipFromName(TaxonNameBase, NameRelationshipType, String)
461 protected void addNameRelationship(NameRelationship rel
) {
462 if (rel
!=null && rel
.getToName().equals(this)){
463 this.relationsToThisName
.add(rel
);
464 }else if(rel
!=null && rel
.getFromName().equals(this)){
465 this.relationsFromThisName
.add(rel
);
467 throw new RuntimeException("NameRelationship is either null or the relationship does not reference this name");
471 * Removes one {@link NameRelationship name relationship} from one of both sets of
472 * {@link #getNameRelations() name relationships} in which <i>this</i> taxon name is involved.
473 * The name relationship will also be removed from one of both sets belonging
474 * to the second taxon name involved. Furthermore the fromName and toName
475 * attributes of the name relationship object will be nullified.
477 * @param nameRelation the name relationship which should be deleted from one of both sets
478 * @see #getNameRelations()
480 public void removeNameRelationship(NameRelationship nameRelation
) {
482 TaxonNameBase fromName
= nameRelation
.getFromName();
483 TaxonNameBase toName
= nameRelation
.getToName();
485 if (nameRelation
!= null) {
486 nameRelation
.setToName(null);
487 nameRelation
.setFromName(null);
490 if (fromName
!= null) {
491 fromName
.removeNameRelationship(nameRelation
);
494 if (toName
!= null) {
495 toName
.removeNameRelationship(nameRelation
);
498 this.relationsToThisName
.remove(nameRelation
);
499 this.relationsFromThisName
.remove(nameRelation
);
502 public void removeRelationToTaxonName(TaxonNameBase toTaxonName
) {
503 Set
<NameRelationship
> nameRelationships
= new HashSet
<NameRelationship
>();
504 // nameRelationships.addAll(this.getNameRelations());
505 nameRelationships
.addAll(this.getRelationsFromThisName());
506 nameRelationships
.addAll(this.getRelationsToThisName());
507 for(NameRelationship nameRelationship
: nameRelationships
) {
508 // remove name relationship from this side
509 if (nameRelationship
.getFromName().equals(this) && nameRelationship
.getToName().equals(toTaxonName
)) {
510 this.removeNameRelationship(nameRelationship
);
517 * Does exactly the same as the addNameRelationship method provided that
518 * the given relationship is a name relationship.
520 * @param relation the relationship to be added to one of <i>this</i> taxon name's name relationships sets
521 * @see #addNameRelationship(NameRelationship)
522 * @see #getNameRelations()
523 * @see NameRelationship
524 * @see eu.etaxonomy.cdm.model.common.RelationshipBase
526 public void addRelationship(RelationshipBase relation
) {
527 if (relation
instanceof NameRelationship
){
528 addNameRelationship((NameRelationship
)relation
);
529 NameRelationshipType type
= (NameRelationshipType
)relation
.getType();
530 if (type
!= null && ( type
.isBasionymRelation() || type
.isReplacedSynonymRelation() ) ){
531 TaxonNameBase fromName
= ((NameRelationship
)relation
).getFromName();
532 TaxonNameBase toName
= ((NameRelationship
)relation
).getToName();
533 fromName
.mergeHomotypicGroups(toName
);
536 logger
.warn("Relationship not of type NameRelationship!");
537 throw new IllegalArgumentException("Relationship not of type NameRelationship");
543 * Returns the set of all {@link NameRelationship name relationships}
544 * in which <i>this</i> taxon name is involved as a source.
546 * @see #getNameRelations()
547 * @see #getRelationsToThisName()
548 * @see #addRelationshipFromName(TaxonNameBase, NameRelationshipType, String)
550 public Set
<NameRelationship
> getRelationsFromThisName() {
551 if(relationsFromThisName
== null) {
552 this.relationsFromThisName
= new HashSet
<NameRelationship
>();
554 return relationsFromThisName
;
558 * Returns the set of all {@link NameRelationship name relationships}
559 * in which <i>this</i> taxon name is involved as a target.
561 * @see #getNameRelations()
562 * @see #getRelationsFromThisName()
563 * @see #addRelationshipToName(TaxonNameBase, NameRelationshipType, String)
565 public Set
<NameRelationship
> getRelationsToThisName() {
566 if(relationsToThisName
== null) {
567 this.relationsToThisName
= new HashSet
<NameRelationship
>();
569 return relationsToThisName
;
573 * Returns the set of {@link NomenclaturalStatus nomenclatural status} assigned
574 * to <i>this</i> taxon name according to its corresponding nomenclature code.
575 * This includes the {@link NomenclaturalStatusType type} of the nomenclatural status
576 * and the nomenclatural code rule considered.
578 * @see NomenclaturalStatus
579 * @see NomenclaturalStatusType
581 public Set
<NomenclaturalStatus
> getStatus() {
583 this.status
= new HashSet
<NomenclaturalStatus
>();
589 * Adds a new {@link NomenclaturalStatus nomenclatural status}
590 * to <i>this</i> taxon name's set of nomenclatural status.
592 * @param nomStatus the nomenclatural status to be added
595 public void addStatus(NomenclaturalStatus nomStatus
) {
596 this.status
.add(nomStatus
);
600 * Removes one element from the set of nomenclatural status of <i>this</i> taxon name.
601 * Type and ruleConsidered attributes of the nomenclatural status object
604 * @param nomStatus the nomenclatural status of <i>this</i> taxon name which should be deleted
607 public void removeStatus(NomenclaturalStatus nomStatus
) {
608 //TODO to be implemented?
609 logger
.warn("not yet fully implemented?");
610 this.status
.remove(nomStatus
);
615 * Indicates whether <i>this</i> taxon name is a {@link NameRelationshipType#BASIONYM() basionym}
616 * or a {@link NameRelationshipType#REPLACED_SYNONYM() replaced synonym}
617 * of any other taxon name. Returns "true", if a basionym or a replaced
618 * synonym {@link NameRelationship relationship} from <i>this</i> taxon name to another taxon name exists,
619 * false otherwise (also in case <i>this</i> taxon name is the only one in the
620 * homotypical group).
623 public boolean isOriginalCombination(){
624 Set
<NameRelationship
> relationsFromThisName
= this.getRelationsFromThisName();
625 for (NameRelationship relation
: relationsFromThisName
) {
626 if (relation
.getType().isBasionymRelation() ||
627 relation
.getType().isReplacedSynonymRelation()) {
635 * Returns the taxon name which is the {@link NameRelationshipType#BASIONYM() basionym} of <i>this</i> taxon name.
636 * The basionym of a taxon name is its epithet-bringing synonym.
637 * For instance <i>Pinus abies</i> L. was published by Linnaeus and the botanist
638 * Karsten transferred later <i>this</i> taxon to the genus Picea. Therefore,
639 * <i>Pinus abies</i> L. is the basionym of the new combination <i>Picea abies</i> (L.) H. Karst.
641 * If more than one basionym exists one is choosen at radom.
643 * If no basionym exists null is returned.
646 public TaxonNameBase
getBasionym(){
647 Set
<TaxonNameBase
> basionyms
= getBasionyms();
648 if (basionyms
.size() == 0){
651 return basionyms
.iterator().next();
656 * Returns the set of taxon names which are the {@link NameRelationshipType#BASIONYM() basionyms} of <i>this</i> taxon name.
657 * The basionym of a taxon name is its epithet-bringing synonym.
658 * For instance <i>Pinus abies</i> L. was published by Linnaeus and the botanist
659 * Karsten transferred later <i>this</i> taxon to the genus Picea. Therefore,
660 * <i>Pinus abies</i> L. is the basionym of the new combination <i>Picea abies</i> (L.) H. Karst.
663 public Set
<TaxonNameBase
> getBasionyms(){
664 Set
<TaxonNameBase
> result
= new HashSet
<TaxonNameBase
>();
665 Set
<NameRelationship
> rels
= this.getRelationsToThisName();
666 for (NameRelationship rel
: rels
){
667 if (rel
.getType().isBasionymRelation()){
668 TaxonNameBase basionym
= rel
.getFromName();
669 result
.add(basionym
);
676 * Assigns a taxon name as {@link NameRelationshipType#BASIONYM() basionym} of <i>this</i> taxon name.
677 * The basionym {@link NameRelationship relationship} will be added to <i>this</i> taxon name
678 * and to the basionym. The basionym cannot have itself a basionym.
679 * The {@link HomotypicalGroup homotypical groups} of <i>this</i> taxon name and of the basionym
680 * will be {@link HomotypicalGroup#merge(HomotypicalGroup) merged}.
682 * @param basionym the taxon name to be set as the basionym of <i>this</i> taxon name
683 * @see #getBasionym()
684 * @see #addBasionym(TaxonNameBase, String)
686 public void addBasionym(T basionym
){
687 addBasionym(basionym
, null, null, null);
690 * Assigns a taxon name as {@link NameRelationshipType#BASIONYM() basionym} of <i>this</i> taxon name
691 * and keeps the nomenclatural rule considered for it. The basionym
692 * {@link NameRelationship relationship} will be added to <i>this</i> taxon name and to the basionym.
693 * The basionym cannot have itself a basionym.
694 * The {@link HomotypicalGroup homotypical groups} of <i>this</i> taxon name and of the basionym
695 * will be {@link HomotypicalGroup#merge(HomotypicalGroup) merged}.
697 * @param basionym the taxon name to be set as the basionym of <i>this</i> taxon name
698 * @param ruleConsidered the string identifying the nomenclatural rule
700 * @see #getBasionym()
701 * @see #addBasionym(TaxonNameBase)
703 public NameRelationship
addBasionym(T basionym
, Reference citation
, String microcitation
, String ruleConsidered
){
704 if (basionym
!= null){
705 return basionym
.addRelationshipToName(this, NameRelationshipType
.BASIONYM(), citation
, microcitation
, ruleConsidered
);
712 * Assigns a taxon name as {@link NameRelationshipType#REPLACED_SYNONYM() replaced synonym} of <i>this</i> taxon name
713 * and keeps the nomenclatural rule considered for it. The replaced synonym
714 * {@link NameRelationship relationship} will be added to <i>this</i> taxon name and to the replaced synonym.
715 * The {@link HomotypicalGroup homotypical groups} of <i>this</i> taxon name and of the replaced synonym
716 * will be {@link HomotypicalGroup#merge(HomotypicalGroup) merged}.
718 * @param basionym the taxon name to be set as the basionym of <i>this</i> taxon name
719 * @param ruleConsidered the string identifying the nomenclatural rule
720 * @see #getBasionym()
721 * @see #addBasionym(TaxonNameBase)
723 //TODO: Check if true: The replaced synonym cannot have itself a replaced synonym (?).
724 public void addReplacedSynonym(T replacedSynonym
, Reference citation
, String microcitation
, String ruleConsidered
){
725 if (replacedSynonym
!= null){
726 replacedSynonym
.addRelationshipToName(this, NameRelationshipType
.REPLACED_SYNONYM(), citation
, microcitation
, ruleConsidered
);
731 * Removes the {@link NameRelationshipType#BASIONYM() basionym} {@link NameRelationship relationship} from the set of
732 * {@link #getRelationsToThisName() name relationships to} <i>this</i> taxon name. The same relationhip will be
733 * removed from the set of {@link #getRelationsFromThisName() name relationships from} the taxon name
734 * previously used as basionym.
736 * @see #getBasionym()
737 * @see #addBasionym(TaxonNameBase)
739 public void removeBasionyms(){
740 Set
<NameRelationship
> removeRelations
= new HashSet
<NameRelationship
>();
741 for (NameRelationship nameRelation
: this.getRelationsToThisName()){
742 if (nameRelation
.getType().isBasionymRelation()){
743 removeRelations
.add(nameRelation
);
746 // Removing relations from a set through which we are iterating causes a
747 // ConcurrentModificationException. Therefore, we delete the targeted
748 // relations in a second step.
749 for (NameRelationship relation
: removeRelations
){
750 this.removeNameRelationship(relation
);
755 * Returns the taxonomic {@link Rank rank} of <i>this</i> taxon name.
759 public Rank
getRank(){
766 public void setRank(Rank rank
){
771 * Returns the {@link eu.etaxonomy.cdm.model.reference.INomenclaturalReference nomenclatural reference} of <i>this</i> taxon name.
772 * The nomenclatural reference is here meant to be the one publication
773 * <i>this</i> taxon name was originally published in while fulfilling the formal
774 * requirements as specified by the corresponding {@link NomenclaturalCode nomenclatural code}.
776 * @see eu.etaxonomy.cdm.model.reference.INomenclaturalReference
777 * @see eu.etaxonomy.cdm.model.reference.Reference
779 public INomenclaturalReference
getNomenclaturalReference(){
780 return this.nomenclaturalReference
;
783 * Assigns a {@link eu.etaxonomy.cdm.model.reference.INomenclaturalReference nomenclatural reference} to <i>this</i> taxon name.
784 * The corresponding {@link eu.etaxonomy.cdm.model.reference.Reference.isNomenclaturallyRelevant nomenclaturally relevant flag} will be set to true
785 * as it is obviously used for nomenclatural purposes.
787 * @throws IllegalArgumentException if parameter <code>nomenclaturalReference</code> is not assignable from {@link INomenclaturalReference}
788 * @see #getNomenclaturalReference()
790 public void setNomenclaturalReference(INomenclaturalReference nomenclaturalReference
){
791 if(nomenclaturalReference
!= null){
792 if(!INomenclaturalReference
.class.isAssignableFrom(nomenclaturalReference
.getClass())){
793 throw new IllegalArgumentException("Parameter nomenclaturalReference is not assignable from INomenclaturalReference");
795 this.nomenclaturalReference
= (Reference
)nomenclaturalReference
;
797 this.nomenclaturalReference
= null;
802 * Returns the appended phrase string assigned to <i>this</i> taxon name.
803 * The appended phrase is a non-atomised addition to a name. It is
804 * not ruled by a nomenclatural code.
806 public String
getAppendedPhrase(){
807 return this.appendedPhrase
;
811 * @see #getAppendedPhrase()
813 public void setAppendedPhrase(String appendedPhrase
){
814 this.appendedPhrase
= appendedPhrase
;
818 * Returns the details string of the {@link #getNomenclaturalReference() nomenclatural reference} assigned
819 * to <i>this</i> taxon name. The details describe the exact localisation within
820 * the publication used as nomenclature reference. These are mostly
821 * (implicitly) pages but can also be figures or tables or any other
822 * element of a publication. A nomenclatural micro reference (details)
823 * requires the existence of a nomenclatural reference.
825 //Details of the nomenclatural reference (protologue).
826 public String
getNomenclaturalMicroReference(){
827 return this.nomenclaturalMicroReference
;
830 * @see #getNomenclaturalMicroReference()
832 public void setNomenclaturalMicroReference(String nomenclaturalMicroReference
){
833 this.nomenclaturalMicroReference
= nomenclaturalMicroReference
;
837 * @see eu.etaxonomy.cdm.model.common.IParsable#getHasProblem()
839 public int getParsingProblem(){
840 return this.parsingProblem
;
844 * @see eu.etaxonomy.cdm.model.common.IParsable#setHasProblem(int)
846 public void setParsingProblem(int parsingProblem
){
847 this.parsingProblem
= parsingProblem
;
851 * @see eu.etaxonomy.cdm.model.common.IParsable#addProblem(eu.etaxonomy.cdm.strategy.parser.NameParserWarning)
853 public void addParsingProblem(ParserProblem problem
){
854 parsingProblem
= ParserProblem
.addProblem(parsingProblem
, problem
);
858 * @see eu.etaxonomy.cdm.model.common.IParsable#removeParsingProblem(eu.etaxonomy.cdm.strategy.parser.ParserProblem)
860 public void removeParsingProblem(ParserProblem problem
) {
861 parsingProblem
= ParserProblem
.removeProblem(parsingProblem
, problem
);
867 public void addParsingProblems(int problems
){
868 parsingProblem
= ParserProblem
.addProblems(parsingProblem
, problems
);
872 * @see eu.etaxonomy.cdm.model.common.IParsable#hasProblem()
874 public boolean hasProblem(){
875 return parsingProblem
!= 0;
881 * @see eu.etaxonomy.cdm.model.common.IParsable#hasProblem(eu.etaxonomy.cdm.strategy.parser.ParserProblem)
883 public boolean hasProblem(ParserProblem problem
) {
884 return getParsingProblems().contains(problem
);
889 * @see eu.etaxonomy.cdm.model.common.IParsable#problemStarts()
891 public int getProblemStarts(){
892 return this.problemStarts
;
896 * @see eu.etaxonomy.cdm.model.common.IParsable#setProblemStarts(int)
898 public void setProblemStarts(int start
) {
899 this.problemStarts
= start
;
903 * @see eu.etaxonomy.cdm.model.common.IParsable#problemEnds()
905 public int getProblemEnds(){
906 return this.problemEnds
;
910 * @see eu.etaxonomy.cdm.model.common.IParsable#setProblemEnds(int)
912 public void setProblemEnds(int end
) {
913 this.problemEnds
= end
;
916 //*********************** TYPE DESIGNATION *********************************************//
919 * Returns the set of {@link TypeDesignationBase type designations} assigned
920 * to <i>this</i> taxon name.
921 * @see NameTypeDesignation
922 * @see SpecimenTypeDesignation
924 public Set
<TypeDesignationBase
<?
>> getTypeDesignations() {
925 if(typeDesignations
== null) {
926 this.typeDesignations
= new HashSet
<TypeDesignationBase
<?
>>();
928 return typeDesignations
;
932 * Removes one element from the set of {@link TypeDesignationBase type designations} assigned to
933 * <i>this</i> taxon name. The type designation itself will be nullified.
935 * @param typeDesignation the type designation which should be deleted
937 public void removeTypeDesignation(TypeDesignationBase typeDesignation
) {
938 logger
.warn("not yet fully implemented: nullify the specimen type designation itself?");
939 this.typeDesignations
.remove(typeDesignation
);
943 * Returns the set of {@link SpecimenTypeDesignation specimen type designations} assigned
944 * to <i>this</i> taxon name. The {@link Rank rank} of <i>this</i> taxon name is generally
945 * "species" or below. The specimen type designations include all the
946 * specimens on which the typification of this name is based (which are
947 * exclusively used to typify taxon names belonging to the same
948 * {@link HomotypicalGroup homotypical group} to which <i>this</i> taxon name
949 * belongs) and eventually the status of these designations.
951 * @see SpecimenTypeDesignation
952 * @see NameTypeDesignation
953 * @see HomotypicalGroup
956 public Set
<SpecimenTypeDesignation
> getSpecimenTypeDesignationsOfHomotypicalGroup() {
957 return this.getHomotypicalGroup().getSpecimenTypeDesignations();
960 //*********************** NAME TYPE DESIGNATION *********************************************//
963 * Returns the set of {@link NameTypeDesignation name type designations} assigned
964 * to <i>this</i> taxon name the rank of which must be above "species".
965 * The name type designations include all the taxon names used to typify
966 * <i>this</i> taxon name and eventually the rejected or conserved status
967 * of these designations.
969 * @see NameTypeDesignation
970 * @see SpecimenTypeDesignation
973 public Set
<NameTypeDesignation
> getNameTypeDesignations() {
974 Set
<NameTypeDesignation
> result
= new HashSet
<NameTypeDesignation
>();
975 for (TypeDesignationBase typeDesignation
: this.typeDesignations
){
976 if (typeDesignation
instanceof NameTypeDesignation
){
977 result
.add((NameTypeDesignation
)typeDesignation
);
984 * Creates and adds a new {@link NameTypeDesignation name type designation}
985 * to <i>this</i> taxon name's set of type designations.
987 * @param typeSpecies the taxon name to be used as type of <i>this</i> taxon name
988 * @param citation the reference for this new designation
989 * @param citationMicroReference the string with the details (generally pages) within the reference
990 * @param originalNameString the taxon name string used in the reference to assert this designation
991 * @param isRejectedType the boolean status for a rejected name type designation
992 * @param isConservedType the boolean status for a conserved name type designation
993 * @param isLectoType the boolean status for a lectotype name type designation
994 * @param isNotDesignated the boolean status for a name type designation without name type
995 * @param addToAllHomotypicNames the boolean indicating whether the name type designation should be
996 * added to all taxon names of the homotypical group this taxon name belongs to
998 * @see #getNameTypeDesignations()
999 * @see NameTypeDesignation
1000 * @see TypeDesignationBase#isNotDesignated()
1002 public NameTypeDesignation
addNameTypeDesignation(TaxonNameBase typeSpecies
,
1004 String citationMicroReference
,
1005 String originalNameString
,
1006 NameTypeDesignationStatus status
,
1007 boolean isRejectedType
,
1008 boolean isConservedType
,
1009 /*boolean isLectoType, */
1010 boolean isNotDesignated
,
1011 boolean addToAllHomotypicNames
) {
1012 NameTypeDesignation nameTypeDesignation
= new NameTypeDesignation(typeSpecies
, citation
, citationMicroReference
, originalNameString
, status
, isRejectedType
, isConservedType
, isNotDesignated
);
1013 //nameTypeDesignation.setLectoType(isLectoType);
1014 addTypeDesignation(nameTypeDesignation
, addToAllHomotypicNames
);
1015 return nameTypeDesignation
;
1019 * Creates and adds a new {@link NameTypeDesignation name type designation}
1020 * to <i>this</i> taxon name's set of type designations.
1022 * @param typeSpecies the taxon name to be used as type of <i>this</i> taxon name
1023 * @param citation the reference for this new designation
1024 * @param citationMicroReference the string with the details (generally pages) within the reference
1025 * @param originalNameString the taxon name string used in the reference to assert this designation
1026 * @param status the name type designation status
1027 * @param addToAllHomotypicNames the boolean indicating whether the name type designation should be
1028 * added to all taxon names of the homotypical group this taxon name belongs to
1030 * @see #getNameTypeDesignations()
1031 * @see NameTypeDesignation
1032 * @see TypeDesignationBase#isNotDesignated()
1034 public NameTypeDesignation
addNameTypeDesignation(TaxonNameBase typeSpecies
,
1036 String citationMicroReference
,
1037 String originalNameString
,
1038 NameTypeDesignationStatus status
,
1039 boolean addToAllHomotypicNames
) {
1040 NameTypeDesignation nameTypeDesignation
= new NameTypeDesignation(typeSpecies
, status
, citation
, citationMicroReference
, originalNameString
);
1041 addTypeDesignation(nameTypeDesignation
, addToAllHomotypicNames
);
1042 return nameTypeDesignation
;
1045 //*********************** SPECIMEN TYPE DESIGNATION *********************************************//
1048 * Returns the set of {@link SpecimenTypeDesignation specimen type designations}
1049 * that typify <i>this</i> taxon name.
1052 public Set
<SpecimenTypeDesignation
> getSpecimenTypeDesignations() {
1053 Set
<SpecimenTypeDesignation
> result
= new HashSet
<SpecimenTypeDesignation
>();
1054 for (TypeDesignationBase typeDesignation
: this.typeDesignations
){
1055 if (typeDesignation
instanceof SpecimenTypeDesignation
){
1056 result
.add((SpecimenTypeDesignation
)typeDesignation
);
1064 * Creates and adds a new {@link SpecimenTypeDesignation specimen type designation}
1065 * to <i>this</i> taxon name's set of type designations.
1067 * @param typeSpecimen the specimen to be used as a type for <i>this</i> taxon name
1068 * @param status the specimen type designation status
1069 * @param citation the reference for this new specimen type designation
1070 * @param citationMicroReference the string with the details (generally pages) within the reference
1071 * @param originalNameString the taxon name used in the reference to assert this designation
1072 * @param isNotDesignated the boolean status for a specimen type designation without specimen type
1073 * @param addToAllHomotypicNames the boolean indicating whether the specimen type designation should be
1074 * added to all taxon names of the homotypical group the typified
1075 * taxon name belongs to
1077 * @see #getSpecimenTypeDesignations()
1078 * @see SpecimenTypeDesignationStatus
1079 * @see SpecimenTypeDesignation
1080 * @see TypeDesignationBase#isNotDesignated()
1082 public SpecimenTypeDesignation
addSpecimenTypeDesignation(Specimen typeSpecimen
,
1083 SpecimenTypeDesignationStatus status
,
1085 String citationMicroReference
,
1086 String originalNameString
,
1087 boolean isNotDesignated
,
1088 boolean addToAllHomotypicNames
) {
1089 SpecimenTypeDesignation specimenTypeDesignation
= new SpecimenTypeDesignation(typeSpecimen
, status
, citation
, citationMicroReference
, originalNameString
, isNotDesignated
);
1090 addTypeDesignation(specimenTypeDesignation
, addToAllHomotypicNames
);
1091 return specimenTypeDesignation
;
1094 //used by merge strategy
1095 private boolean addTypeDesignation(TypeDesignationBase typeDesignation
){
1096 return addTypeDesignation(typeDesignation
, true);
1100 * Adds a {@link TypeDesignationBase type designation} to <code>this</code> taxon name's set of type designations
1102 * @param typeDesignation the typeDesignation to be added to <code>this</code> taxon name
1103 * @param addToAllNames the boolean indicating whether the type designation should be
1104 * added to all taxon names of the homotypical group the typified
1105 * taxon name belongs to
1106 * @return true if the operation was succesful
1108 * @throws IllegalArgumentException if the type designation already has typified names, an {@link IllegalArgumentException exception}
1109 * is thrown. We do this to prevent a type designation to be used for multiple taxon names.
1112 public boolean addTypeDesignation(TypeDesignationBase typeDesignation
, boolean addToAllNames
){
1113 //at them moment typeDesignations are not persisted with the homotypical group
1114 //so explicit adding to the homotypical group is not necessary.
1115 if (typeDesignation
!= null){
1116 checkHomotypicalGroup(typeDesignation
);
1117 this.typeDesignations
.add(typeDesignation
);
1118 typeDesignation
.addTypifiedName(this);
1121 for (TaxonNameBase taxonName
: this.getHomotypicalGroup().getTypifiedNames()){
1122 if (taxonName
!= this){
1123 taxonName
.addTypeDesignation(typeDesignation
, false);
1132 * Throws an Exception this type designation already has typified names from another homotypical group.
1133 * @param typeDesignation
1135 private void checkHomotypicalGroup(TypeDesignationBase typeDesignation
) {
1136 if(typeDesignation
.getTypifiedNames().size() > 0){
1137 Set
<HomotypicalGroup
> groups
= new HashSet
<HomotypicalGroup
>();
1138 Set
<TaxonNameBase
> names
= typeDesignation
.getTypifiedNames();
1139 for (TaxonNameBase taxonName
: names
){
1140 groups
.add(taxonName
.getHomotypicalGroup());
1142 if (groups
.size() > 1){
1143 throw new IllegalArgumentException("TypeDesignation already has typified names from another homotypical group.");
1150 //*********************** HOMOTYPICAL GROUP *********************************************//
1154 * Returns the {@link HomotypicalGroup homotypical group} to which
1155 * <i>this</i> taxon name belongs. A homotypical group represents all taxon names
1156 * that share the same types.
1158 * @see HomotypicalGroup
1161 public HomotypicalGroup
getHomotypicalGroup() {
1162 return homotypicalGroup
;
1166 * @see #getHomotypicalGroup()
1168 public void setHomotypicalGroup(HomotypicalGroup homotypicalGroup
) {
1169 if (homotypicalGroup
== null){
1170 throw new IllegalArgumentException("HomotypicalGroup of name should never be null but was set to 'null'");
1172 this.homotypicalGroup
= homotypicalGroup
;
1173 if (! homotypicalGroup
.typifiedNames
.contains(this)){
1174 homotypicalGroup
.addTypifiedName(this);
1180 // *************************************************************************//
1183 * @see #getNomenclaturalReference()
1186 public Reference
getCitation(){
1187 //TODO What is the purpose of this method differing from the getNomenclaturalReference method?
1188 logger
.warn("getCitation not yet implemented");
1193 * Returns the complete string containing the
1194 * {@link eu.etaxonomy.cdm.model.reference.INomenclaturalReference#getNomenclaturalCitation() nomenclatural reference citation}
1195 * and the {@link #getNomenclaturalMicroReference() details} assigned to <i>this</i> taxon name.
1197 * @return the string containing the nomenclatural reference of <i>this</i> taxon name
1198 * @see eu.etaxonomy.cdm.model.reference.INomenclaturalReference#getNomenclaturalCitation()
1199 * @see #getNomenclaturalReference()
1200 * @see #getNomenclaturalMicroReference()
1203 public String
getCitationString(){
1204 return getNomenclaturalReference().getNomenclaturalCitation(getNomenclaturalMicroReference());
1208 * Returns the parsing problems
1211 public List
<ParserProblem
> getParsingProblems(){
1212 return ParserProblem
.warningList(this.parsingProblem
);
1216 * Returns the string containing the publication date (generally only year)
1217 * of the {@link #getNomenclaturalReference() nomenclatural reference} for <i>this</i> taxon name, null if there is
1218 * no nomenclatural reference.
1220 * @return the string containing the publication date of <i>this</i> taxon name
1221 * @see eu.etaxonomy.cdm.model.reference.INomenclaturalReference#getYear()
1224 public String
getReferenceYear(){
1225 if (this.getNomenclaturalReference() != null ){
1226 return this.getNomenclaturalReference().getYear();
1233 * Returns the set of {@link eu.etaxonomy.cdm.model.taxon.TaxonBase taxon bases} that refer to <i>this</i> taxon name.
1234 * In this context a taxon base means the use of a taxon name by a reference
1235 * either as a {@link eu.etaxonomy.cdm.model.taxon.Taxon taxon} ("accepted/correct" name) or
1236 * as a (junior) {@link eu.etaxonomy.cdm.model.taxon.Synonym synonym}.
1237 * A taxon name can be used by several distinct {@link eu.etaxonomy.cdm.model.reference.Reference references} but only once
1238 * within a taxonomic treatment (identified by one reference).
1241 * @see #getSynonyms()
1243 public Set
<TaxonBase
> getTaxonBases() {
1244 if(taxonBases
== null) {
1245 this.taxonBases
= new HashSet
<TaxonBase
>();
1247 return this.taxonBases
;
1251 * Adds a new {@link eu.etaxonomy.cdm.model.taxon.TaxonBase taxon base}
1252 * to the set of taxon bases using <i>this</i> taxon name.
1254 * @param taxonBase the taxon base to be added
1255 * @see #getTaxonBases()
1256 * @see #removeTaxonBase(TaxonBase)
1259 public void addTaxonBase(TaxonBase taxonBase
){
1260 Method method
= ReflectionUtils
.findMethod(TaxonBase
.class, "setName", new Class
[] {TaxonNameBase
.class});
1261 ReflectionUtils
.makeAccessible(method
);
1262 ReflectionUtils
.invokeMethod(method
, taxonBase
, new Object
[] {this});
1263 taxonBases
.add(taxonBase
);
1266 * Removes one element from the set of {@link eu.etaxonomy.cdm.model.taxon.TaxonBase taxon bases} that refer to <i>this</i> taxon name.
1268 * @param taxonBase the taxon base which should be removed from the corresponding set
1269 * @see #getTaxonBases()
1270 * @see #addTaxonBase(TaxonBase)
1272 public void removeTaxonBase(TaxonBase taxonBase
){
1273 Method method
= ReflectionUtils
.findMethod(TaxonBase
.class, "setName", new Class
[] {TaxonNameBase
.class});
1274 ReflectionUtils
.makeAccessible(method
);
1275 ReflectionUtils
.invokeMethod(method
, taxonBase
, new Object
[] {null});
1276 taxonBases
.remove(taxonBase
);
1280 * Returns the set of {@link eu.etaxonomy.cdm.model.taxon.Taxon taxa} ("accepted/correct" names according to any
1281 * reference) that are based on <i>this</i> taxon name. This set is a subset of
1282 * the set returned by getTaxonBases().
1284 * @see eu.etaxonomy.cdm.model.taxon.Taxon
1285 * @see #getTaxonBases()
1286 * @see #getSynonyms()
1289 public Set
<Taxon
> getTaxa(){
1290 Set
<Taxon
> result
= new HashSet
<Taxon
>();
1291 for (TaxonBase taxonBase
: this.taxonBases
){
1292 if (taxonBase
instanceof Taxon
){
1293 result
.add((Taxon
)taxonBase
);
1300 * Returns the set of {@link eu.etaxonomy.cdm.model.taxon.Synonym (junior) synonyms} (according to any
1301 * reference) that are based on <i>this</i> taxon name. This set is a subset of
1302 * the set returned by getTaxonBases().
1304 * @see eu.etaxonomy.cdm.model.taxon.Synonym
1305 * @see #getTaxonBases()
1309 public Set
<Synonym
> getSynonyms() {
1310 Set
<Synonym
> result
= new HashSet
<Synonym
>();
1311 for (TaxonBase taxonBase
: this.taxonBases
){
1312 if (taxonBase
instanceof Synonym
){
1313 result
.add((Synonym
)taxonBase
);
1320 // *********** DESCRIPTIONS *************************************
1323 * Returns the set of {@link eu.etaxonomy.cdm.model.description.TaxonNameDescription taxon name descriptions} assigned
1324 * to <i>this</i> taxon name. A taxon name description is a piece of information
1325 * concerning the taxon name like for instance the content of its first
1326 * publication (protolog) or a picture of this publication.
1328 * @see #addDescription(TaxonNameDescription)
1329 * @see #removeDescription(TaxonNameDescription)
1330 * @see eu.etaxonomy.cdm.model.description.TaxonNameDescription
1332 public Set
<TaxonNameDescription
> getDescriptions() {
1333 return descriptions
;
1337 * Adds a new {@link eu.etaxonomy.cdm.model.description.TaxonNameDescription taxon name description}
1338 * to the set of taxon name descriptions assigned to <i>this</i> taxon name. The
1339 * content of the {@link eu.etaxonomy.cdm.model.description.TaxonNameDescription#getTaxonName() taxonName attribute} of the
1340 * taxon name description itself will be replaced with <i>this</i> taxon name.
1342 * @param description the taxon name description to be added
1343 * @see #getDescriptions()
1344 * @see #removeDescription(TaxonNameDescription)
1346 public void addDescription(TaxonNameDescription description
) {
1347 java
.lang
.reflect
.Field field
= ReflectionUtils
.findField(TaxonNameDescription
.class, "taxonName", TaxonNameBase
.class);
1348 ReflectionUtils
.makeAccessible(field
);
1349 ReflectionUtils
.setField(field
, description
, this);
1350 descriptions
.add(description
);
1353 * Removes one element from the set of {@link eu.etaxonomy.cdm.model.description.TaxonNameDescription taxon name descriptions} assigned
1354 * to <i>this</i> taxon name. The content of the {@link eu.etaxonomy.cdm.model.description.TaxonNameDescription#getTaxonName() taxonName attribute}
1355 * of the description itself will be set to "null".
1357 * @param description the taxon name description which should be removed
1358 * @see #getDescriptions()
1359 * @see #addDescription(TaxonNameDescription)
1360 * @see eu.etaxonomy.cdm.model.description.TaxonNameDescription#getTaxonName()
1362 public void removeDescription(TaxonNameDescription description
) {
1363 java
.lang
.reflect
.Field field
= ReflectionUtils
.findField(TaxonNameDescription
.class, "taxonName", TaxonNameBase
.class);
1364 ReflectionUtils
.makeAccessible(field
);
1365 ReflectionUtils
.setField(field
, description
, null);
1366 descriptions
.remove(description
);
1369 // *********** HOMOTYPIC GROUP METHODS **************************************************
1372 public void mergeHomotypicGroups(TaxonNameBase name
){
1373 this.getHomotypicalGroup().merge(name
.getHomotypicalGroup());
1374 //HomotypicalGroup thatGroup = name.homotypicalGroup;
1375 name
.setHomotypicalGroup(this.homotypicalGroup
);
1379 * Returns the boolean value indicating whether a given taxon name belongs
1380 * to the same {@link HomotypicalGroup homotypical group} as <i>this</i> taxon name (true)
1381 * or not (false). Returns "true" only if the homotypical groups of both
1382 * taxon names exist and if they are identical.
1384 * @param homoTypicName the taxon name the homotypical group of which is to be checked
1385 * @return the boolean value of the check
1386 * @see HomotypicalGroup
1389 public boolean isHomotypic(TaxonNameBase homoTypicName
) {
1390 if (homoTypicName
== null) {
1393 HomotypicalGroup homotypicGroup
= homoTypicName
.getHomotypicalGroup();
1394 if (homotypicGroup
== null || this.getHomotypicalGroup() == null) {
1397 if (homotypicGroup
.equals(this.getHomotypicalGroup())) {
1405 * Checks whether name is a basionym for ALL names
1406 * in its homotypical group.
1407 * Returns <code>false</code> if there are no other names in the group
1412 public boolean isGroupsBasionym() {
1413 Set
<TaxonNameBase
> typifiedNames
= homotypicalGroup
.getTypifiedNames();
1415 // Check whether there are any other names in the group
1416 if (typifiedNames
.size() == 1) {
1420 boolean isBasionymToAll
= true;
1422 for (TaxonNameBase taxonName
: typifiedNames
) {
1423 if (!taxonName
.equals(this)) {
1424 if (! isBasionymFor(taxonName
)) {
1433 * Checks whether a basionym relationship exists between fromName and toName.
1440 public boolean isBasionymFor(TaxonNameBase newCombinationName
) {
1441 Set
<NameRelationship
> relations
= newCombinationName
.getRelationsToThisName();
1442 for (NameRelationship relation
: relations
) {
1443 if (relation
.getType().equals(NameRelationshipType
.BASIONYM()) &&
1444 relation
.getFromName().equals(this)) {
1452 * Creates a basionym relationship to all other names in this names homotypical
1455 * @see HomotypicalGroup.setGroupBasionym(TaxonNameBase basionymName)
1459 * @see eu.etaxonomy.cdm.model.name.HomotypicalGroup#setGroupBasionym(TaxonNameBase)
1462 public void makeGroupsBasionym() {
1463 this.homotypicalGroup
.setGroupBasionym(this);
1467 //********* Rank comparison shortcuts ********************//
1469 * Returns the boolean value indicating whether the taxonomic {@link Rank rank} of <i>this</i>
1470 * taxon name is higher than the genus rank (true) or not (false).
1471 * Suprageneric non viral names are monomials.
1472 * Returns false if rank is null.
1475 * @see #isInfraGeneric()
1477 * @see #isInfraSpecific()
1480 public boolean isSupraGeneric() {
1484 return getRank().isSupraGeneric();
1487 * Returns the boolean value indicating whether the taxonomic {@link Rank rank} of <i>this</i>
1488 * taxon name is the genus rank (true) or not (false). Non viral names with
1489 * genus rank are monomials. Returns false if rank is null.
1491 * @see #isSupraGeneric()
1492 * @see #isInfraGeneric()
1494 * @see #isInfraSpecific()
1497 public boolean isGenus() {
1501 return getRank().isGenus();
1504 * Returns the boolean value indicating whether the taxonomic {@link Rank rank} of <i>this</i>
1505 * taxon name is higher than the species rank and lower than the
1506 * genus rank (true) or not (false). Infrageneric non viral names are
1507 * binomials. Returns false if rank is null.
1509 * @see #isSupraGeneric()
1512 * @see #isInfraSpecific()
1515 public boolean isInfraGeneric() {
1519 return getRank().isInfraGeneric();
1523 * Returns the boolean value indicating whether the taxonomic {@link Rank rank} of <i>this</i>
1524 * taxon name is higher than the species rank (true) or not (false).
1525 * Returns false if rank is null.
1528 * @see #isInfraGeneric()
1530 * @see #isInfraSpecific()
1533 public boolean isSupraSpecific(){
1537 return getRank().isHigher(Rank
.SPECIES());
1541 * Returns the boolean value indicating whether the taxonomic {@link Rank rank} of <i>this</i>
1542 * taxon name is the species rank (true) or not (false). Non viral names
1543 * with species rank are binomials.
1544 * Returns false if rank is null.
1546 * @see #isSupraGeneric()
1548 * @see #isInfraGeneric()
1549 * @see #isInfraSpecific()
1552 public boolean isSpecies() {
1556 return getRank().isSpecies();
1559 * Returns the boolean value indicating whether the taxonomic {@link Rank rank} of <i>this</i>
1560 * taxon name is lower than the species rank (true) or not (false).
1561 * Infraspecific non viral names are trinomials.
1562 * Returns false if rank is null.
1564 * @see #isSupraGeneric()
1566 * @see #isInfraGeneric()
1570 public boolean isInfraSpecific() {
1574 return getRank().isInfraSpecific();
1579 * Returns null as the {@link NomenclaturalCode nomenclatural code} that governs
1580 * the construction of <i>this</i> taxon name since there is no specific
1581 * nomenclatural code defined. The real implementention takes place in the
1582 * subclasses {@link ViralName ViralName}, {@link BacterialName BacterialName},
1583 * {@link BotanicalName BotanicalName}, {@link CultivarPlantName CultivarPlantName} and
1584 * {@link ZoologicalName ZoologicalName}. Each taxon name is governed by one
1585 * and only one nomenclatural code.
1588 * @see #isCodeCompliant()
1589 * @see #getHasProblem()
1591 abstract public NomenclaturalCode
getNomenclaturalCode();
1594 * @see eu.etaxonomy.cdm.model.common.IdentifiableEntity#generateTitle()
1597 * Generates and returns the string with the scientific name of <i>this</i>
1598 * taxon name (only non viral taxon names can be generated from their
1599 * components). This string may be stored in the inherited
1600 * {@link eu.etaxonomy.cdm.model.common.IdentifiableEntity#getTitleCache() titleCache} attribute.
1601 * This method overrides the generic and inherited
1602 * {@link eu.etaxonomy.cdm.model.common.IdentifiableEntity#generateTitle() method} from
1603 * {@link eu.etaxonomy.cdm.model.common.IdentifiableEntity IdentifiableEntity}.
1605 * @return the string with the composed name of this non viral taxon name with authorship (and maybe year)
1606 * @see eu.etaxonomy.cdm.model.common.IdentifiableEntity#generateTitle()
1607 * @see eu.etaxonomy.cdm.model.common.IdentifiableEntity#getTitleCache()
1610 // public abstract String generateTitle();
1613 * Creates a basionym relationship between this name and
1614 * each name in its homotypic group.
1616 * @param basionymName
1619 public void setAsGroupsBasionym() {
1622 HomotypicalGroup homotypicalGroup
= this.getHomotypicalGroup();
1624 if (homotypicalGroup
== null) {
1628 Set
<NameRelationship
> relations
= new HashSet
<NameRelationship
>();
1629 Set
<NameRelationship
> removeRelations
= new HashSet
<NameRelationship
>();
1631 for(TaxonNameBase
<?
, ?
> typifiedName
: homotypicalGroup
.getTypifiedNames()){
1633 Set
<NameRelationship
> nameRelations
= typifiedName
.getRelationsFromThisName();
1635 for(NameRelationship nameRelation
: nameRelations
){
1636 relations
.add(nameRelation
);
1640 for (NameRelationship relation
: relations
) {
1642 // If this is a basionym relation, and toName is in the homotypical group,
1643 // remove the relationship.
1644 if (relation
.getType().equals(NameRelationshipType
.BASIONYM()) &&
1645 relation
.getToName().getHomotypicalGroup().equals(homotypicalGroup
)) {
1646 removeRelations
.add(relation
);
1650 // Removing relations from a set through which we are iterating causes a
1651 // ConcurrentModificationException. Therefore, we delete the targeted
1652 // relations in a second step.
1653 for (NameRelationship relation
: removeRelations
) {
1654 this.removeNameRelationship(relation
);
1658 for (TaxonNameBase
<?
, ?
> name
: homotypicalGroup
.getTypifiedNames()) {
1659 if (!name
.equals(this)) {
1661 // First check whether the relationship already exists
1662 if (!this.isBasionymFor(name
)) {
1665 name
.addRelationshipFromName(this,
1666 NameRelationshipType
.BASIONYM(), null);
1673 * Removes basionym relationship between this name and
1674 * each name in its homotypic group.
1676 * @param basionymName
1679 public void removeAsGroupsBasionym() {
1681 HomotypicalGroup homotypicalGroup
= this.getHomotypicalGroup();
1683 if (homotypicalGroup
== null) {
1687 Set
<NameRelationship
> relations
= new HashSet
<NameRelationship
>();
1688 Set
<NameRelationship
> removeRelations
= new HashSet
<NameRelationship
>();
1690 for(TaxonNameBase
<?
, ?
> typifiedName
: homotypicalGroup
.getTypifiedNames()){
1692 Set
<NameRelationship
> nameRelations
= typifiedName
.getRelationsFromThisName();
1694 for(NameRelationship nameRelation
: nameRelations
){
1695 relations
.add(nameRelation
);
1699 for (NameRelationship relation
: relations
) {
1701 // If this is a basionym relation, and toName is in the homotypical group,
1702 // and fromName is basionymName, remove the relationship.
1703 if (relation
.getType().equals(NameRelationshipType
.BASIONYM()) &&
1704 relation
.getFromName().equals(this) &&
1705 relation
.getToName().getHomotypicalGroup().equals(homotypicalGroup
)) {
1706 removeRelations
.add(relation
);
1710 // Removing relations from a set through which we are iterating causes a
1711 // ConcurrentModificationException. Therefore, we delete the targeted
1712 // relations in a second step.
1713 for (NameRelationship relation
: removeRelations
) {
1714 this.removeNameRelationship(relation
);
1718 //*********************** CLONE ********************************************************/
1721 * Clones <i>this</i> taxon name. This is a shortcut that enables to create
1722 * a new instance that differs only slightly from <i>this</i> taxon name by
1723 * modifying only some of the attributes.<BR><BR>
1724 * Usages of this name in a taxon concept are <b>not</b> cloned.<BR>
1725 * <b>The name gets a newly created homotypical group</b><BR>
1726 * (CAUTION: this behaviour needs to be discussed and may change in future).<BR><BR>
1727 * {@link TaxonNameDescription Name descriptions} are cloned and not reused.<BR>
1728 * {@link TypeDesignationBase Type designations} are cloned and not reused.<BR>
1730 * @see eu.etaxonomy.cdm.model.media.IdentifiableEntity#clone()
1731 * @see java.lang.Object#clone()
1734 public Object
clone() {
1735 TaxonNameBase result
;
1737 result
= (TaxonNameBase
)super.clone();
1739 //taxonBases -> empty
1740 result
.taxonBases
= new HashSet
<TaxonBase
>();
1743 if (! protectedFullTitleCache
){
1744 result
.fullTitleCache
= null;
1748 result
.descriptions
= new HashSet
<TaxonNameDescription
>();
1749 for (TaxonNameDescription taxonNameDescription
: getDescriptions()){
1750 TaxonNameDescription newDescription
= (TaxonNameDescription
)taxonNameDescription
.clone();
1751 result
.descriptions
.add(newDescription
);
1755 result
.status
= new HashSet
<NomenclaturalStatus
>();
1756 for (NomenclaturalStatus nomenclaturalStatus
: getStatus()){
1757 NomenclaturalStatus newStatus
= (NomenclaturalStatus
)nomenclaturalStatus
.clone();
1758 result
.status
.add(newStatus
);
1763 result
.relationsToThisName
= new HashSet
<NameRelationship
>();
1764 for (NameRelationship toRelationship
: getRelationsToThisName()){
1765 NameRelationship newRelationship
= (NameRelationship
)toRelationship
.clone();
1766 newRelationship
.setRelatedTo(result
);
1767 result
.relationsToThisName
.add(newRelationship
);
1771 result
.relationsFromThisName
= new HashSet
<NameRelationship
>();
1772 for (NameRelationship fromRelationship
: getRelationsFromThisName()){
1773 NameRelationship newRelationship
= (NameRelationship
)fromRelationship
.clone();
1774 newRelationship
.setRelatedFrom(result
);
1775 result
.relationsFromThisName
.add(newRelationship
);
1779 result
.typeDesignations
= new HashSet
<TypeDesignationBase
>();
1780 for (TypeDesignationBase typeDesignation
: getTypeDesignations()){
1781 TypeDesignationBase newDesignation
= (TypeDesignationBase
)typeDesignation
.clone();
1782 result
.typeDesignations
.add(newDesignation
);
1783 newDesignation
.addTypifiedName(result
);
1787 //TODO still needs to be discussed
1788 homotypicalGroup
= HomotypicalGroup
.NewInstance();
1789 homotypicalGroup
.addTypifiedName(this);
1791 //no changes to: appendedPharse, nomenclaturalReference,
1792 //nomenclaturalMicroReference, parsingProblem, problemEnds, problemStarts
1793 //protectedFullTitleCache, rank
1795 } catch (CloneNotSupportedException e
) {
1796 logger
.warn("Object does not implement cloneable");
1797 e
.printStackTrace();