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