(no commit message)
[cdmlib.git] / cdmlib-model / src / main / java / eu / etaxonomy / cdm / model / name / TaxonNameBase.java
1 /**
2 * Copyright (C) 2007 EDIT
3 * European Distributed Institute of Taxonomy
4 * http://www.e-taxonomy.eu
5 *
6 * The contents of this file are subject to the Mozilla Public License Version 1.1
7 * See LICENSE.TXT at the top of this package for the full license terms.
8 */
9
10 package eu.etaxonomy.cdm.model.name;
11
12 import eu.etaxonomy.cdm.model.occurrence.Specimen;
13 import eu.etaxonomy.cdm.model.reference.INomenclaturalReference;
14 import eu.etaxonomy.cdm.model.reference.ReferenceBase;
15 import eu.etaxonomy.cdm.model.reference.StrictReferenceBase;
16 import eu.etaxonomy.cdm.model.taxon.Synonym;
17 import eu.etaxonomy.cdm.model.taxon.Taxon;
18 import eu.etaxonomy.cdm.model.taxon.TaxonBase;
19 import eu.etaxonomy.cdm.model.common.IParsable;
20 import eu.etaxonomy.cdm.model.common.IRelated;
21 import eu.etaxonomy.cdm.model.common.IdentifiableEntity;
22 import eu.etaxonomy.cdm.model.common.IReferencedEntity;
23 import eu.etaxonomy.cdm.model.common.RelationshipBase;
24 import eu.etaxonomy.cdm.model.description.TaxonDescription;
25 import eu.etaxonomy.cdm.model.description.TaxonNameDescription;
26
27
28 import org.apache.log4j.Logger;
29 import org.hibernate.annotations.Cascade;
30 import org.hibernate.annotations.CascadeType;
31 import org.hibernate.annotations.Index;
32 import org.hibernate.annotations.Table;
33 import org.hibernate.annotations.Target;
34
35 import eu.etaxonomy.cdm.strategy.cache.name.INameCacheStrategy;
36
37
38
39 import java.lang.reflect.Method;
40 import java.util.*;
41
42 import javax.persistence.*;
43 import javax.xml.bind.annotation.XmlAccessType;
44 import javax.xml.bind.annotation.XmlAccessorType;
45 import javax.xml.bind.annotation.XmlAnyElement;
46 import javax.xml.bind.annotation.XmlAttribute;
47 import javax.xml.bind.annotation.XmlElement;
48 import javax.xml.bind.annotation.XmlElementWrapper;
49 import javax.xml.bind.annotation.XmlIDREF;
50 import javax.xml.bind.annotation.XmlRootElement;
51 import javax.xml.bind.annotation.XmlSchemaType;
52 import javax.xml.bind.annotation.XmlTransient;
53 import javax.xml.bind.annotation.XmlType;
54
55 /**
56 * The upmost (abstract) class for scientific taxon names regardless of any
57 * particular nomenclature code. The scientific taxon name does not depend
58 * on the use made of it in a publication or a treatment
59 * ({@link taxon.TaxonBase taxon concept respectively potential taxon})
60 * as an {@link taxon.Taxon "accepted" respectively "correct" (taxon) name}
61 * or as a {@link taxon.Synonym synonym}.
62 *
63 * @author m.doering
64 * @version 1.0
65 * @created 08-Nov-2007 13:06:57
66 */
67 @XmlAccessorType(XmlAccessType.FIELD)
68 @XmlType(name = "TaxonNameBase", propOrder = {
69 "appendedPhrase",
70 "nomenclaturalMicroReference",
71 "nomenclaturalReference",
72 "rank",
73 "homotypicalGroup",
74 "nameTypeDesignations",
75 "specimenTypeDesignations",
76 "relationsFromThisName",
77 "relationsToThisName",
78 "status",
79 "descriptions"
80 // "taxonBases"
81 })
82 @Entity
83 @Inheritance(strategy=InheritanceType.SINGLE_TABLE)
84 @Table(appliesTo="TaxonNameBase", indexes = { @Index(name = "taxonNameBaseTitleCacheIndex", columnNames = { "persistentTitleCache" }) })
85 public abstract class TaxonNameBase<T extends TaxonNameBase, S extends INameCacheStrategy> extends IdentifiableEntity<TaxonNameBase> implements IReferencedEntity, IParsable, IRelated {
86
87 static Logger logger = Logger.getLogger(TaxonNameBase.class);
88
89 private static Method methodDescriptionSetTaxonName;
90
91 @XmlElementWrapper(name = "Descriptions")
92 @XmlElement(name = "Description")
93 private Set<TaxonNameDescription> descriptions = new HashSet<TaxonNameDescription>();
94
95 @XmlElement(name = "AppendedPhrase")
96 private String appendedPhrase;
97
98 @XmlElement(name = "NomenclaturalMicroReference")
99 private String nomenclaturalMicroReference;
100
101 @XmlAttribute
102 private boolean hasProblem = false;
103
104 @XmlElementWrapper(name = "NameTypeDesignations")
105 @XmlElement(name = "NameTypeDesignation")
106 protected Set<NameTypeDesignation> nameTypeDesignations = new HashSet<NameTypeDesignation>();
107
108 @XmlElementWrapper(name = "SpecimenTypeDesignations")
109 @XmlElement(name = "SpecimenTypeDesignation")
110 private Set<SpecimenTypeDesignation> specimenTypeDesignations = new HashSet<SpecimenTypeDesignation>();
111
112 // List homotypical groups here in TaxonomicNames or separately?
113 // FIXME: Stack overflow if listed here.
114 @XmlElement(name = "HomotypicalGroup")
115 @XmlIDREF
116 @XmlSchemaType(name = "IDREF")
117 private HomotypicalGroup homotypicalGroup = new HomotypicalGroup();
118
119 @XmlElementWrapper(name = "RelationsFromThisName")
120 @XmlElement(name = "RelationFromThisName")
121 @XmlIDREF
122 private Set<NameRelationship> relationsFromThisName = new HashSet<NameRelationship>();
123
124 @XmlElementWrapper(name = "RelationsToThisName")
125 @XmlElement(name = "RelationToThisName")
126 @XmlIDREF
127 private Set<NameRelationship> relationsToThisName = new HashSet<NameRelationship>();
128
129 @XmlElementWrapper(name = "Statuses")
130 @XmlElement(name = "Status")
131 @XmlIDREF
132 private Set<NomenclaturalStatus> status = new HashSet<NomenclaturalStatus>();
133
134 @XmlTransient
135 //@XmlElementWrapper(name = "TaxonBases")
136 //@XmlElement(name = "TaxonBase")
137 private Set<TaxonBase> taxonBases = new HashSet<TaxonBase>();
138
139 @XmlElement(name = "Rank")
140 @XmlIDREF
141 @XmlSchemaType(name = "IDREF")
142 private Rank rank;
143
144 // FIXME: This must be an IDREF to the corresponding nomenclatural reference.
145 @XmlAnyElement
146 private INomenclaturalReference nomenclaturalReference;
147
148 static Method methodTaxonBaseSetName;
149
150 // ************* CONSTRUCTORS *************/
151 /**
152 * Class constructor: creates a new empty taxon name.
153 *
154 * @see #TaxonNameBase(Rank)
155 * @see #TaxonNameBase(HomotypicalGroup)
156 * @see #TaxonNameBase(Rank, HomotypicalGroup)
157 */
158 public TaxonNameBase() {
159 this(null, null);
160 }
161 /**
162 * Class constructor: creates a new taxon name
163 * only containing its {@link common.Rank rank}.
164 *
165 * @param rank the rank to be assigned to this taxon name
166 * @see #TaxonNameBase()
167 * @see #TaxonNameBase(HomotypicalGroup)
168 * @see #TaxonNameBase(Rank, HomotypicalGroup)
169 */
170 public TaxonNameBase(Rank rank) {
171 this(rank, null);
172 }
173 /**
174 * Class constructor: creates a new taxon name
175 * only containing its {@link HomotypicalGroup homotypical group}.
176 * The new taxon name will be also added to the set of taxon names
177 * belonging to this homotypical group.
178 *
179 * @param homotypicalGroup the homotypical group to which this taxon name belongs
180 * @see #TaxonNameBase()
181 * @see #TaxonNameBase(Rank)
182 * @see #TaxonNameBase(Rank, HomotypicalGroup)
183 */
184 public TaxonNameBase(HomotypicalGroup homotypicalGroup) {
185 this(null, homotypicalGroup);
186 }
187 /**
188 * Class constructor: creates a new taxon name
189 * only containing its {@link common.Rank rank} and
190 * its {@link HomotypicalGroup homotypical group}.
191 * The new taxon name will be also added to the set of taxon names
192 * belonging to this homotypical group.
193 *
194 * @param rank the rank to be assigned to this taxon name
195 * @param homotypicalGroup the homotypical group to which this taxon name belongs
196 * @see #TaxonNameBase()
197 * @see #TaxonNameBase(Rank)
198 * @see #TaxonNameBase(HomotypicalGroup)
199 */
200 public TaxonNameBase(Rank rank, HomotypicalGroup homotypicalGroup) {
201 super();
202 this.setRank(rank);
203 if (homotypicalGroup == null){
204 homotypicalGroup = new HomotypicalGroup();
205 }
206 homotypicalGroup.addTypifiedName(this);
207 }
208
209 //********* METHODS **************************************/
210
211 //@Index(name="TaxonNameBaseTitleCacheIndex")
212 // public String getTitleCache(){
213 // return super.getTitleCache();
214 // }
215
216 /**
217 * Returns the boolean value "false" since the components of this taxon name
218 * cannot follow the rules of a corresponding {@link NomenclaturalCode nomenclatural code}
219 * which is not defined for this class. The nomenclature code depends on
220 * the concrete name subclass ({@link BacterialName BacterialName},
221 * {@link BotanicalName BotanicalName}, {@link CultivarPlantName CultivarPlantName},
222 * {@link ZoologicalName ZoologicalName} or {@link ViralName ViralName})
223 * to which a taxon name belongs.
224 *
225 * @return false
226 */
227 @Transient
228 public abstract boolean isCodeCompliant();
229
230
231 /**
232 * Returns the set of all {@link NameRelationship name relationships}
233 * in which this taxon name is involved. A taxon name can be both source
234 * in some name relationships or target in some others.
235 *
236 * @see #getRelationsToThisName()
237 * @see #getRelationsFromThisName()
238 * @see #addNameRelationship(NameRelationship)
239 * @see #addRelationshipToName(TaxonNameBase, NameRelationshipType, String)
240 * @see #addRelationshipFromName(TaxonNameBase, NameRelationshipType, String)
241 */
242 @Transient
243 public Set<NameRelationship> getNameRelations() {
244 Set<NameRelationship> rels = new HashSet<NameRelationship>();
245 rels.addAll(getRelationsFromThisName());
246 rels.addAll(getRelationsToThisName());
247 return rels;
248 }
249 /**
250 * Creates a new {@link NameRelationship#NameRelationship(TaxonNameBase, TaxonNameBase, NameRelationshipType, String) name relationship} from this taxon name to another taxon name
251 * and adds it both to the set of {@link #getRelationsFromThisName() relations from this taxon name} and
252 * to the set of {@link #getRelationsToThisName() relations to the other taxon name}.
253 *
254 * @param toName the taxon name of the target for this new name relationship
255 * @param type the type of this new name relationship
256 * @param ruleConsidered the string which specifies the rule on which this name relationship is based
257 * @see #getRelationsToThisName()
258 * @see #getNameRelations()
259 * @see #addRelationshipFromName(TaxonNameBase, NameRelationshipType, String)
260 * @see #addNameRelationship(NameRelationship)
261 */
262 public void addRelationshipToName(TaxonNameBase toName, NameRelationshipType type, String ruleConsidered){
263 NameRelationship rel = new NameRelationship(toName, this, type, ruleConsidered);
264 }
265 /**
266 * Creates a new {@link NameRelationship#NameRelationship(TaxonNameBase, TaxonNameBase, NameRelationshipType, String) name relationship} from another taxon name to this taxon name
267 * and adds it both to the set of {@link #getRelationsToThisName() relations to this taxon name} and
268 * to the set of {@link #getRelationsFromThisName() relations from the other taxon name}.
269 *
270 * @param fromName the taxon name of the source for this new name relationship
271 * @param type the type of this new name relationship
272 * @param ruleConsidered the string which specifies the rule on which this name relationship is based
273 * @see #getRelationsFromThisName()
274 * @see #getNameRelations()
275 * @see #addRelationshipToName(TaxonNameBase, NameRelationshipType, String)
276 * @see #addNameRelationship(NameRelationship)
277 */
278 public void addRelationshipFromName(TaxonNameBase fromName, NameRelationshipType type, String ruleConsidered){
279 NameRelationship rel = new NameRelationship(this, fromName, type, ruleConsidered);
280 }
281 /**
282 * Adds an existing {@link NameRelationship name relationship} either to the set of
283 * {@link #getRelationsToThisName() relations to this taxon name} or to the set of
284 * {@link #getRelationsFromThisName() relations from this taxon name}. If neither the
285 * source nor the target of the name relationship match with this taxon
286 * no addition will be carried out.
287 *
288 * @param rel the name relationship to be added to one of this taxon name's name relationships sets
289 * @see #getNameRelations()
290 * @see #addRelationshipToName(TaxonNameBase, NameRelationshipType, String)
291 * @see #addRelationshipFromName(TaxonNameBase, NameRelationshipType, String)
292 */
293 protected void addNameRelationship(NameRelationship rel) {
294 if (rel!=null && rel.getToName().equals(this)){
295 this.relationsToThisName.add(rel);
296 }else if(rel!=null && rel.getFromName().equals(this)){
297 this.relationsFromThisName.add(rel);
298 }else{
299 //TODO: raise error???
300 }
301 }
302 /**
303 * Removes one {@link NameRelationship name relationship} from one of both sets of
304 * {@link #getNameRelations() name relationships} in which this taxon name is involved.
305 * The name relationship will also be removed from one of both sets belonging
306 * to the second taxon name involved. Furthermore the fromName and toName
307 * attributes of the name relationship object will be nullified.
308 *
309 * @param nameRelation the name relationship which should be deleted from one of both sets
310 * @see #getNameRelations()
311 */
312 public void removeNameRelationship(NameRelationship nameRelation) {
313 //TODO to be implemented?
314 logger.warn("not yet fully implemented?");
315 this.relationsToThisName.remove(nameRelation);
316 this.relationsFromThisName.remove(nameRelation);
317 }
318
319
320 /**
321 * Does exactly the same as the addNameRelationship method provided that
322 * the given relationship is a name relationship.
323 *
324 * @param relation the relationship to be added to one of this taxon name's name relationships sets
325 * @see #addNameRelationship(NameRelationship)
326 * @see #getNameRelations()
327 * @see NameRelationship
328 * @see common.RelationshipBase
329 */
330 public void addRelationship(RelationshipBase relation) {
331 if (relation instanceof NameRelationship){
332 addNameRelationship((NameRelationship)relation);
333 if (relation.getType() != null &&
334 ( relation.getType().equals(NameRelationshipType.BASIONYM()) ||
335 relation.getType().equals(NameRelationshipType.REPLACED_SYNONYM())
336 )){
337 TaxonNameBase fromName = ((NameRelationship)relation).getFromName();
338 TaxonNameBase toName = ((NameRelationship)relation).getToName();
339 fromName.getHomotypicalGroup().merge(toName.getHomotypicalGroup());
340 }
341 }else{
342 logger.warn("Relationship not of type NameRelationship!");
343 //TODO exception handling
344 }
345 }
346
347
348 /**
349 * Returns the set of all {@link NameRelationship name relationships}
350 * in which this taxon name is involved as a source.
351 *
352 * @see #getNameRelations()
353 * @see #getRelationsToThisName()
354 * @see #addRelationshipFromName(TaxonNameBase, NameRelationshipType, String)
355 */
356 @OneToMany(mappedBy="relatedFrom", fetch= FetchType.LAZY)
357 @Cascade({CascadeType.SAVE_UPDATE})
358 public Set<NameRelationship> getRelationsFromThisName() {
359 return relationsFromThisName;
360 }
361 private void setRelationsFromThisName(Set<NameRelationship> relationsFromThisName) {
362 this.relationsFromThisName = relationsFromThisName;
363 }
364
365 /**
366 * Returns the set of all {@link NameRelationship name relationships}
367 * in which this taxon name is involved as a target.
368 *
369 * @see #getNameRelations()
370 * @see #getRelationsFromThisName()
371 * @see #addRelationshipToName(TaxonNameBase, NameRelationshipType, String)
372 */
373 @OneToMany(mappedBy="relatedTo", fetch= FetchType.LAZY)
374 @Cascade({CascadeType.SAVE_UPDATE})
375 public Set<NameRelationship> getRelationsToThisName() {
376 return relationsToThisName;
377 }
378 private void setRelationsToThisName(Set<NameRelationship> relationsToThisName) {
379 this.relationsToThisName = relationsToThisName;
380 }
381
382
383 /**
384 * Returns the set of {@link NomenclaturalStatus nomenclatural status} assigned
385 * to this taxon name according to its corresponding nomenclature code.
386 * This includes the {@link NomenclaturalStatusType type} of the nomenclatural status
387 * and the nomenclatural code rule considered.
388 *
389 * @see NomenclaturalStatus
390 * @see NomenclaturalStatusType
391 */
392 @OneToMany(fetch= FetchType.LAZY)
393 @Cascade({CascadeType.SAVE_UPDATE})
394 public Set<NomenclaturalStatus> getStatus() {
395 return status;
396 }
397 /**
398 * @see #getStatus()
399 */
400 protected void setStatus(Set<NomenclaturalStatus> nomStatus) {
401 this.status = nomStatus;
402 }
403 /**
404 * Adds a new {@link NomenclaturalStatus nomenclatural status}
405 * to this taxon name's set of nomenclatural status.
406 *
407 * @param nomStatus the nomenclatural status to be added
408 * @see #getStatus()
409 */
410 public void addStatus(NomenclaturalStatus nomStatus) {
411 this.status.add(nomStatus);
412 }
413 /**
414 * Removes one element from the set of nomenclatural status of this taxon name.
415 * Type and ruleConsidered attributes of the nomenclatural status object
416 * will be nullified.
417 *
418 * @param nomStatus the nomenclatural status of this taxon name which should be deleted
419 * @see #getStatus()
420 */
421 public void removeStatus(NomenclaturalStatus nomStatus) {
422 //TODO to be implemented?
423 logger.warn("not yet fully implemented?");
424 this.status.remove(nomStatus);
425 }
426
427
428 /**
429 * Indicates whether this taxon name is a {@link NameRelationshipType.BASIONYM() basionym}
430 * or a {@link NameRelationshipType.REPLACED_SYNONYM() replaced synonym}
431 * of any other taxon name. Returns "true", if a basionym or a replaced
432 * synonym relationship from this taxon name to another taxon name exists,
433 * false otherwise (also in case this taxon name is the only one in the
434 * homotypical group).
435 */
436 @Transient
437 public boolean isOriginalCombination(){
438 Set<NameRelationship> relationsFromThisName = this.getRelationsFromThisName();
439 for (NameRelationship relation : relationsFromThisName) {
440 if (relation.getType().equals(NameRelationshipType.BASIONYM()) ||
441 relation.getType().equals(NameRelationshipType.REPLACED_SYNONYM())) {
442 return true;
443 }
444 }
445 return false;
446 }
447
448 /**
449 * Returns the taxon name which is the {@link NameRelationshipType.BASIONYM() basionym} of this taxon name.
450 * The basionym of a taxon name is its epithet-bringing synonym.
451 * For instance Pinus abies L. was published by Linnaeus and the botanist
452 * Karsten transferred later this taxon to the genus Picea. Therefore,
453 * Pinus abies L. is the basionym of the new combination Picea abies (L.) H. Karst.
454 */
455 @Transient
456 public T getBasionym(){
457 //TODO: pick the right name relationships...
458 logger.warn("get Basionym not yet implemented");
459 return null;
460 }
461 /**
462 * Assigns another taxon name as {@link NameRelationshipType.BASIONYM() basionym} of this taxon name.
463 * The basionym relationship will be added to this taxon name
464 * and to the basionym. The basionym cannot have itself a basionym.
465 * The homotypical group of this taxon name will be changed the basionyms homotypical group.
466 * @see #getBasionym()
467 * @see #addBasionym(TaxonNameBase, String)
468 */
469 public void addBasionym(T basionym){
470 addBasionym(basionym, null);
471 }
472 /**
473 * Assigns another taxon name as {@link NameRelationshipType.BASIONYM() basionym} of this taxon name
474 * and keeps the nomenclatural rule considered for it. The basionym
475 * relationship will be added to this taxon name and to the basionym.
476 * The basionym cannot have itself as a basionym.
477 * The homotypical group of this taxon name will be changed the basionyms homotypical group.
478 * @see #getBasionym()
479 * @see #setBasionym(TaxonNameBase)
480 */
481 public void addBasionym(T basionym, String ruleConsidered){
482 if (basionym != null){
483 basionym.addRelationshipToName(this, NameRelationshipType.BASIONYM(), ruleConsidered);
484 }
485 }
486
487 public void removeBasionym(){
488 //TODO implement
489 logger.warn("not yet implemented");
490 }
491
492
493
494 @Transient
495 public abstract S getCacheStrategy();
496 public abstract void setCacheStrategy(S cacheStrategy);
497
498 /**
499 * Returns the taxonomic {@link Rank rank} of this taxon name.
500 *
501 * @see Rank
502 */
503 @ManyToOne
504 //@Cascade({CascadeType.SAVE_UPDATE})
505 public Rank getRank(){
506 return this.rank;
507 }
508 /**
509 * @see #getRank()
510 */
511 public void setRank(Rank rank){
512 this.rank = rank;
513 }
514
515 /**
516 * Returns the {@link reference.INomenclaturalReference nomenclatural reference} of this taxon name.
517 * The nomenclatural reference is here meant to be the one publication
518 * this taxon name was originally published in while fulfilling the formal
519 * requirements as specified by the corresponding nomenclatural code.
520 *
521 * @see reference.INomenclaturalReference
522 * @see reference.ReferenceBase
523 */
524 @ManyToOne
525 @Cascade({CascadeType.SAVE_UPDATE})
526 @Target(ReferenceBase.class)
527 public INomenclaturalReference getNomenclaturalReference(){
528 return (INomenclaturalReference) this.nomenclaturalReference;
529 }
530 /**
531 * Assigns a nomenclatural {@link reference.INomenclaturalReference nomenclatural reference} to this taxon name.
532 * The corresponding {@link reference.ReferenceBase.isNomenclaturallyRelevant nomenclaturally relevant flag} will be set to true
533 * as it is obviously used for nomenclatural purposes.
534 *
535 * @see #getNomenclaturalReference()
536 */
537 public void setNomenclaturalReference(INomenclaturalReference nomenclaturalReference){
538 this.nomenclaturalReference = nomenclaturalReference;
539 }
540
541 /**
542 * Returns the appended phrase string assigned to this taxon name.
543 * The appended phrase is a non-atomised addition to a name. It is
544 * not ruled by a nomenclatural code.
545 */
546 public String getAppendedPhrase(){
547 return this.appendedPhrase;
548 }
549 /**
550 * @see #getAppendedPhrase()
551 */
552 public void setAppendedPhrase(String appendedPhrase){
553 this.appendedPhrase = appendedPhrase;
554 }
555
556 /**
557 * Returns the details string of the nomenclatural reference assigned
558 * to this taxon name. The details describe the exact localisation within
559 * the publication used as nomenclature reference. These are mostly
560 * (implicitly) pages but can also be figures or tables or any other
561 * element of a publication. A nomenclatural micro reference (details)
562 * requires the existence of a nomenclatural reference.
563 */
564 //Details of the nomenclatural reference (protologue).
565 public String getNomenclaturalMicroReference(){
566 return this.nomenclaturalMicroReference;
567 }
568 /**
569 * @see #getNomenclaturalMicroReference()
570 */
571 public void setNomenclaturalMicroReference(String nomenclaturalMicroReference){
572 this.nomenclaturalMicroReference = nomenclaturalMicroReference;
573 }
574
575 /**
576 * Returns the boolean value of the flag indicating whether the used {@link eu.etaxonomy.cdm.strategy.parser.INonViralNameParser parser}
577 * method was able to parse the taxon name string successfully (false)
578 * or not (true). The parser itself may also depend on the {@link NomenclaturalCode nomenclatural code}
579 * governing the construction of this taxon name.
580 *
581 * @return the boolean value of the hasProblem flag
582 * @see #getNameCache()
583 */
584 public boolean getHasProblem(){
585 return this.hasProblem;
586 }
587 /**
588 * @see #getHasProblem()
589 */
590 public void setHasProblem(boolean hasProblem){
591 this.hasProblem = hasProblem;
592 }
593 /**
594 * Returns exactly the same boolean value as the {@link #getHasProblem() getHasProblem} method.
595 *
596 * @see #getHasProblem()
597 */
598 public boolean hasProblem(){
599 return getHasProblem();
600 }
601
602
603 /**
604 * Returns the set of {@link NameTypeDesignation name type designations} assigned
605 * to this taxon name the rank of which must be above "species".
606 * The name type designations include all the taxon names used to typify
607 * this name and eventually the rejected or conserved status
608 * of these designations.
609 *
610 * @see NameTypeDesignation
611 * @see SpecimenTypeDesignation
612 */
613 @OneToMany
614 //TODO @Cascade({CascadeType.SAVE_UPDATE, CascadeType.DELETE_ORPHAN})
615 @Cascade(CascadeType.SAVE_UPDATE)
616 public Set<NameTypeDesignation> getNameTypeDesignations() {
617 return nameTypeDesignations;
618 }
619 /**
620 * @see #getNameTypeDesignations()
621 */
622 protected void setNameTypeDesignations(Set<NameTypeDesignation> nameTypeDesignations) {
623 this.nameTypeDesignations = nameTypeDesignations;
624 }
625
626
627 /**
628 * Creates and adds a new {@link NameTypeDesignation name type designation}
629 * to this taxon name's set of name type designations.
630 *
631 * @param typeSpecies the taxon name to be used as type of this taxon name
632 * @param citation the reference for this new designation
633 * @param citationMicroReference the string with the details (generally pages) within the reference
634 * @param originalNameString the taxon name string used in the reference to assert this designation
635 * @param isRejectedType the boolean status for rejected
636 * @param isConservedType the boolean status for conserved
637 * @see #getNameTypeDesignations()
638 * @see #addTypeDesignation(Specimen, TypeDesignationStatus, ReferenceBase, String, String)
639 */
640 public void addNameTypeDesignation(TaxonNameBase typeSpecies, ReferenceBase citation, String citationMicroReference, String originalNameString, boolean isRejectedType, boolean isConservedType) {
641 NameTypeDesignation td = new NameTypeDesignation(this, typeSpecies, citation, citationMicroReference, originalNameString, isRejectedType, isConservedType);
642 }
643
644 /**
645 * Removes one element from the set of {@link NameTypeDesignation name type designations} of this taxon name.
646 * The name type designation itself will be nullified.
647 *
648 * @param typeDesignation the name type designation of this taxon name which should be deleted
649 * @see #getNameTypeDesignations()
650 * @see #removeTypeDesignation(SpecimenTypeDesignation)
651 */
652 public void removeNameTypeDesignation(NameTypeDesignation typeDesignation) {
653 //TODO
654 logger.warn("not yet fully implemented: nullify the name type designation itself?");
655 this.nameTypeDesignations.remove(typeDesignation);
656 }
657
658 /**
659 * Returns the set of {@link SpecimenTypeDesignation specimen type designations}
660 * that typify this taxon name.
661 */
662 @ManyToMany
663 @Cascade(CascadeType.SAVE_UPDATE)
664 public Set<SpecimenTypeDesignation> getSpecimenTypeDesignations() {
665 return specimenTypeDesignations;
666 }
667 /**
668 * @see #getSpecimenTypeDesignations()
669 */
670 protected void setSpecimenTypeDesignations(Set<SpecimenTypeDesignation> specimenTypeDesignations) {
671 this.specimenTypeDesignations = specimenTypeDesignations;
672 }
673
674 /**
675 * Returns the set of {@link SpecimenTypeDesignation specimen type designations} assigned
676 * indirectly to this taxon name through its {@link HomotypicalGroup homotypical group}.
677 * The rank of this taxon name is generally "species" or below.
678 * The specimen type designations include all the specimens on which
679 * the typification of this name is based (and which are common to all
680 * taxon names belonging to the homotypical group) and eventually
681 * the status of these designations.
682 *
683 * @see SpecimenTypeDesignation
684 * @see NameTypeDesignation
685 */
686 @Transient
687 public Set<SpecimenTypeDesignation> getSpecimenTypeDesignationsOfHomotypicalGroup() {
688 return this.getHomotypicalGroup().getTypeDesignations();
689 }
690
691 /**
692 * Adds a new {@link SpecimenTypeDesignation specimen type designation}
693 * (using its attributes as parameters) to the set of specimen type designations assigned to the
694 * {@link HomotypicalGroup homotypical group} to which this taxon name belongs.
695 *
696 * @param typeSpecimen the specimen to be used as a type for this taxon name's homotypical group
697 * @param status the specimen type designation status
698 * @param citation the reference for this new specimen type designation
699 * @param citationMicroReference the string with the details (generally pages) within the reference
700 * @param originalNameString the taxon name used in the reference to assert this designation
701 * @see HomotypicalGroup#getTypeDesignations()
702 * @see #addTypeDesignation(TaxonNameBase, ReferenceBase, String, String, boolean, boolean)
703 * @see TypeDesignationStatus
704 */
705 public void addSpecimenTypeDesignation(Specimen typeSpecimen, TypeDesignationStatus status, ReferenceBase citation, String citationMicroReference, String originalNameString, boolean addToAllNames) {
706 SpecimenTypeDesignation specimenTypeDesignation =
707 SpecimenTypeDesignation.NewInstance(typeSpecimen, status, citation, citationMicroReference, originalNameString);
708 this.getHomotypicalGroup().addTypeDesignation(specimenTypeDesignation, addToAllNames);
709 }
710
711 //only to be used for xxx
712 /**
713 * Adds a new {@link SpecimenTypeDesignation specimen type designation}
714 * to the set of specimen type designations assigned to the
715 * {@link HomotypicalGroup homotypical group} to which this taxon name belongs.
716 *
717 * @param specimenTypeDesignation the specimen type designation to be added for this taxon name's homotypical group
718 * @see #addSpecimenTypeDesignation(Specimen, TypeDesignationStatus, ReferenceBase, String, String, boolean)
719 * @see HomotypicalGroup#getTypeDesignations()
720 * @see #addTypeDesignation(TaxonNameBase, ReferenceBase, String, String, boolean, boolean)
721 */
722 protected void addSpecimenTypeDesignation(SpecimenTypeDesignation specimenTypeDesignation) {
723 this.specimenTypeDesignations.add(specimenTypeDesignation);
724 }
725
726 //only to be used for xxx
727 /**
728 * Removes one element from the set of {@link SpecimenTypeDesignation specimen type designations} assigned to the
729 * {@link HomotypicalGroup homotypical group} to which this taxon name belongs.
730 *
731 * @param SpecimenTypeDesignation the specimen type designation which should be deleted
732 * @see HomotypicalGroup#getTypeDesignations()
733 * @see #removeTypeDesignation(SpecimenTypeDesignation)
734 * @see #removeNameTypeDesignation(NameTypeDesignation)
735 */
736 protected void removeSpecimenTypeDesignation(SpecimenTypeDesignation specimenTypeDesignation) {
737 this.specimenTypeDesignations.remove(specimenTypeDesignation);
738 }
739
740 /**
741 * Removes one element from the set of {@link SpecimenTypeDesignation specimen type designations} assigned to the
742 * {@link HomotypicalGroup homotypical group} to which this taxon name belongs.
743 * The specimen type designation itself will be nullified.
744 *
745 * @param typeDesignation the specimen type designation which should be deleted
746 * @see HomotypicalGroup#getTypeDesignations()
747 * @see #removeSpecimenTypeDesignation(SpecimenTypeDesignation)
748 * @see #removeNameTypeDesignation(NameTypeDesignation)
749 */
750 public void removeTypeDesignation(SpecimenTypeDesignation typeDesignation) {
751 logger.warn("not yet fully implemented: nullify the specimen type designation itself?");
752 this.homotypicalGroup.removeTypeDesignation(typeDesignation);
753 }
754
755 /**
756 * Returns the {@link HomotypicalGroup homotypical group} to which
757 * this taxon name belongs. A homotypical group represents all taxon names
758 * that share the same type specimens.
759 *
760 * @see HomotypicalGroup
761 */
762 @ManyToOne
763 @Cascade({CascadeType.SAVE_UPDATE})
764 public HomotypicalGroup getHomotypicalGroup() {
765 return homotypicalGroup;
766 }
767 @Deprecated //only for bidirectional and persistence use
768 protected void setHomotypicalGroup(HomotypicalGroup newHomotypicalGroup) {
769 this.homotypicalGroup = newHomotypicalGroup;
770 }
771
772 /**
773 * @see #getNomenclaturalReference()
774 */
775 @Transient
776 public StrictReferenceBase getCitation(){
777 //TODO What is the purpose of this method differing from the getNomenclaturalReference method?
778 logger.warn("getCitation not yet implemented");
779 return null;
780 }
781
782 /**
783 * Returns the complete string containing the
784 * {@link reference.INomenclaturalReference#getNomenclaturalCitation() nomenclatural reference citation}
785 * (including {@link #getNomenclaturalMicroReference() details}) assigned to this taxon name.
786 *
787 * @return the string containing the nomenclatural reference of this taxon name
788 * @see reference.INomenclaturalReference#getNomenclaturalCitation()
789 * @see #getNomenclaturalReference()
790 * @see #getNomenclaturalMicroReference()
791 */
792 @Transient
793 public String getCitationString(){
794 logger.warn("getCitationString not yet implemented");
795 return null;
796 }
797
798 @Transient
799 public String[] getProblems(){
800 logger.warn("getProblems not yet implemented");
801 return null;
802 }
803
804 /**
805 * Returns the string containing the publication date (generally only year)
806 * of the nomenclatural reference for this taxon name, null if there is
807 * no nomenclatural reference.
808 *
809 * @return the string containing the publication date of this taxon name
810 * @see reference.INomenclaturalReference#getYear()
811 */
812 @Transient
813 public String getReferenceYear(){
814 if (this.getNomenclaturalReference() != null ){
815 return this.getNomenclaturalReference().getYear();
816 }else{
817 return null;
818 }
819 }
820
821 /**
822 * Returns the set of {@link taxon.TaxonBase taxon bases} that refer to this taxon name.
823 * In this context a taxon base means the use of a taxon name by a reference
824 * either as a taxon ("accepted/correct" name) or as a (junior) synonym.
825 * A taxon name can be used by several distinct references but only once
826 * within a taxonomic treatment (identified by one reference).
827 *
828 * @see taxon.TaxonBase
829 * @see #getTaxa()
830 * @see #getSynonyms()
831 */
832 @OneToMany(mappedBy="name", fetch= FetchType.LAZY)
833 public Set<TaxonBase> getTaxonBases() {
834 return this.taxonBases;
835 }
836 /**
837 * @see #getTaxonBases()
838 */
839 protected void setTaxonBases(Set<TaxonBase> taxonBases) {
840 if (taxonBases == null){
841 taxonBases = new HashSet<TaxonBase>();
842 }else{
843 this.taxonBases = taxonBases;
844 }
845 }
846 /**
847 * Adds a new {@link taxon.TaxonBase taxon base}
848 * to the set of taxon bases using this taxon name.
849 *
850 * @param taxonBase the taxon base to be added
851 * @see #getTaxonBases()
852 * @see #removeTaxonBase(TaxonBase)
853 */
854 //TODO protected
855 public void addTaxonBase(TaxonBase taxonBase){
856 taxonBases.add(taxonBase);
857 initMethods();
858 invokeSetMethod(methodTaxonBaseSetName, taxonBase);
859 }
860 /**
861 * Removes one element from the set of {@link taxon.TaxonBase taxon bases} that refer to this taxon name.
862 *
863 * @param taxonBase the taxon base which should be removed from the corresponding set
864 * @see #addTaxonBase(TaxonBase)
865 */
866 public void removeTaxonBase(TaxonBase taxonBase){
867 taxonBases.remove(taxonBase);
868 initMethods();
869 invokeSetMethodWithNull(methodTaxonBaseSetName, taxonBase);
870 }
871
872 private void initMethods(){
873 if (methodTaxonBaseSetName == null){
874 try {
875 methodTaxonBaseSetName = TaxonBase.class.getDeclaredMethod("setName", TaxonNameBase.class);
876 methodTaxonBaseSetName.setAccessible(true);
877 } catch (Exception e) {
878 e.printStackTrace();
879 //TODO handle exception
880 }
881 }
882 if (methodDescriptionSetTaxonName == null){
883 try {
884 methodDescriptionSetTaxonName = TaxonNameDescription.class.getDeclaredMethod("setTaxonName", TaxonNameBase.class);
885 methodDescriptionSetTaxonName.setAccessible(true);
886 } catch (Exception e) {
887 e.printStackTrace();
888 //TODO handle exception
889 }
890 }
891 }
892
893
894
895 /**
896 * Returns the set of {@link taxon.Taxon taxa} ("accepted/correct" names according to any
897 * reference) that are based on this taxon name. This set is a subset of
898 * the set returned by getTaxonBases().
899 *
900 * @see taxon.Taxon
901 * @see #getTaxonBases()
902 * @see #getSynonyms()
903 */
904 @Transient
905 public Set<Taxon> getTaxa(){
906 Set<Taxon> result = new HashSet<Taxon>();
907 for (TaxonBase taxonBase : this.taxonBases){
908 if (taxonBase instanceof Taxon){
909 result.add((Taxon)taxonBase);
910 }
911 }
912 return result;
913 }
914
915 /**
916 * Returns the set of {@link taxon.Synonym (junior) synonyms} (according to any
917 * reference) that are based on this taxon name. This set is a subset of
918 * the set returned by getTaxonBases().
919 *
920 * @see taxon.Synonym
921 * @see #getTaxonBases()
922 * @see #getTaxa()
923 */
924 @Transient
925 public Set<Synonym> getSynonyms() {
926 Set<Synonym> result = new HashSet<Synonym>();
927 for (TaxonBase taxonBase : this.taxonBases){
928 if (taxonBase instanceof Synonym){
929 result.add((Synonym)taxonBase);
930 }
931 }
932 return result;
933 }
934
935
936 // *********** DESCRIPTIONS *************************************
937
938 @OneToMany(mappedBy="taxonName", fetch= FetchType.LAZY)
939 @Cascade({CascadeType.SAVE_UPDATE})
940 public Set<TaxonNameDescription> getDescriptions() {
941 return descriptions;
942 }
943 protected void setDescriptions(Set<TaxonNameDescription> descriptions) {
944 this.descriptions = descriptions;
945 }
946 /**
947 * Adds a description to this taxon. Set the taxon property of description to this taxon.
948 * @param description
949 */
950 public void addDescription(TaxonNameDescription description) {
951 initMethods();
952 this.invokeSetMethod(methodDescriptionSetTaxonName, description);
953 descriptions.add(description);
954 }
955 public void removeDescription(TaxonNameDescription description) {
956 initMethods();
957 this.invokeSetMethod(methodDescriptionSetTaxonName, null);
958 descriptions.remove(description);
959 }
960
961
962
963
964
965
966 // ***********
967 /**
968 * Returns the boolean value indicating whether a given taxon name belongs
969 * to the same {@link HomotypicalGroup homotypical group} as this taxon name (true)
970 * or not (false). Returns "true" only if the homotypical groups of both
971 * taxon names exist and if they are identical.
972 *
973 * @param homoTypicName the taxon name the homotypical group of which is to be checked
974 * @return the boolean value of the check
975 * @see HomotypicalGroup
976 */
977 public boolean isHomotypic(TaxonNameBase homoTypicName) {
978 if (homoTypicName == null) {
979 return false;
980 }
981 HomotypicalGroup homotypicGroup = homoTypicName.getHomotypicalGroup();
982 if (homotypicGroup == null || this.getHomotypicalGroup() == null) {
983 return false;
984 }
985 if (homotypicGroup.equals(this.getHomotypicalGroup())) {
986 return true;
987 }
988 return false;
989 }
990
991
992
993 //********* Rank comparison shortcuts ********************//
994 /**
995 * Returns the boolean value indicating whether the taxonomic {@link Rank rank} of this
996 * taxon name is higher than the genus rank (true) or not (false).
997 * Suprageneric non viral names are monomials.
998 * Returns false if rank is null.
999 *
1000 * @see #isGenus()
1001 * @see #isInfraGeneric()
1002 * @see #isSpecies()
1003 * @see #isInfraSpecific()
1004 */
1005 @Transient
1006 public boolean isSupraGeneric() {
1007 if (rank == null){
1008 return false;
1009 }
1010 return getRank().isSupraGeneric();
1011 }
1012 /**
1013 * Returns the boolean value indicating whether the taxonomic {@link Rank rank} of this
1014 * taxon name is the genus rank (true) or not (false). Non viral names with
1015 * genus rank are monomials.
1016 * Returns false if rank is null.
1017 *
1018 * @see #isSupraGeneric()
1019 * @see #isInfraGeneric()
1020 * @see #isSpecies()
1021 * @see #isInfraSpecific()
1022 */
1023 @Transient
1024 public boolean isGenus() {
1025 if (rank == null){
1026 return false;
1027 }
1028 return getRank().isGenus();
1029 }
1030 /**
1031 * Returns the boolean value indicating whether the taxonomic {@link Rank rank} of this
1032 * taxon name is higher than the species aggregate rank and lower than
1033 * the genus rank (true) or not (false). Infrageneric non viral names
1034 * are binomials.
1035 * Returns false if rank is null.
1036 *
1037 * @see #isSupraGeneric()
1038 * @see #isGenus()
1039 * @see #isSpecies()
1040 * @see #isInfraSpecific()
1041 */
1042 @Transient
1043 public boolean isInfraGeneric() {
1044 if (rank == null){
1045 return false;
1046 }
1047 return getRank().isInfraGeneric();
1048 }
1049 /**
1050 * Returns the boolean value indicating whether the taxonomic {@link Rank rank} of this
1051 * taxon name is the species or species aggregate rank (true) or not (false). Non viral names
1052 * with species rank are binomials.
1053 * Returns false if rank is null.
1054 *
1055 * @see #isSupraGeneric()
1056 * @see #isGenus()
1057 * @see #isInfraGeneric()
1058 * @see #isInfraSpecific()
1059 */
1060 @Transient
1061 public boolean isSpecies() {
1062 if (rank == null){
1063 return false;
1064 }
1065 return getRank().isSpecies();
1066 }
1067 /**
1068 * Returns the boolean value indicating whether the taxonomic {@link Rank rank} of this
1069 * taxon name is lower than the species rank (true) or not (false).
1070 * Infraspecific non viral names are trinomials.
1071 * Returns false if rank is null.
1072 *
1073 * @see #isSupraGeneric()
1074 * @see #isGenus()
1075 * @see #isInfraGeneric()
1076 * @see #isSpecies()
1077 */
1078 @Transient
1079 public boolean isInfraSpecific() {
1080 if (rank == null){
1081 return false;
1082 }
1083 return getRank().isInfraSpecific();
1084 }
1085
1086
1087 /**
1088 * Returns null as the {@link NomenclaturalCode nomenclatural code} that governs
1089 * the construction of this taxon name since there is no specific
1090 * nomenclatural code defined. The real implementention takes place in the
1091 * subclasses {@link ViralName ViralName}, {@link BacterialName BacterialName},
1092 * {@link BotanicalName BotanicalName}, {@link CultivarPlantName CultivarPlantName} and
1093 * {@link ZoologicalName ZoologicalName}. Each taxon name is governed by one
1094 * and only one nomenclatural code.
1095 *
1096 * @return null
1097 * @see #isCodeCompliant()
1098 * @see #getHasProblem()
1099 */
1100 @Transient
1101 abstract public NomenclaturalCode getNomenclaturalCode();
1102 /* (non-Javadoc)
1103 * @see eu.etaxonomy.cdm.model.common.IdentifiableEntity#generateTitle()
1104 */
1105 /**
1106 * Generates and returns the string with the scientific name of this
1107 * taxon name.
1108 * This string may be stored in the inherited
1109 * {@link common.IdentifiableEntity#getTitleCache() titleCache} attribute.
1110 * This method overrides the generic and inherited
1111 * IdentifiableEntity#generateTitle() method.
1112 *
1113 * @return the string with the composed name of this non viral taxon name with authorship (and maybe year)
1114 * @see common.IdentifiableEntity#generateTitle()
1115 * @see common.IdentifiableEntity#getTitleCache()
1116 */
1117 @Override
1118 public String generateTitle() {
1119 // TODO Auto-generated method stub
1120 logger.warn("not yet implemented");
1121 return null;
1122 }
1123
1124 }