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