(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.agent.Institution;
20 import eu.etaxonomy.cdm.model.agent.InstitutionalMembership;
21 import eu.etaxonomy.cdm.model.agent.Person;
22 import eu.etaxonomy.cdm.model.agent.TeamOrPersonBase;
23 import eu.etaxonomy.cdm.model.common.IParsable;
24 import eu.etaxonomy.cdm.model.common.IdentifiableEntity;
25 import eu.etaxonomy.cdm.model.common.IReferencedEntity;
26 import eu.etaxonomy.cdm.model.common.TimePeriod;
27
28 import org.apache.log4j.Logger;
29 import org.hibernate.annotations.Cascade;
30 import org.hibernate.annotations.CascadeType;
31 import org.hibernate.collection.PersistentSet;
32
33 import eu.etaxonomy.cdm.strategy.cache.INameCacheStrategy;
34
35
36 import java.util.*;
37
38 import javax.persistence.*;
39
40 /**
41 * The upmost (abstract) class for scientific taxon names regardless of any
42 * particular nomenclatural code. The scientific name including author strings and
43 * maybe year can be stored as a string in the inherited {@link common.IdentifiableEntity#getTitleCache() titleCache} attribute.
44 * The scientific name string without author strings and year can be stored in the {@link #getNameCache() nameCache} attribute.
45 * The scientific taxon name does not depend on the use made of it
46 * in a publication or a treatment ({@link taxon.TaxonBase taxon concept respectively potential taxon})
47 * as an "accepted" respectively "correct" name ({@link taxon.Taxon taxon})
48 * or as a {@link taxon.Synonym synonym}.
49 *
50 * @author m.doering
51 * @version 1.0
52 * @created 08-Nov-2007 13:06:57
53 */
54 @Entity
55 @Inheritance(strategy=InheritanceType.SINGLE_TABLE)
56 public abstract class TaxonNameBase<T extends TaxonNameBase> extends IdentifiableEntity<TaxonNameBase> implements IReferencedEntity, IParsable {
57 static Logger logger = Logger.getLogger(TaxonNameBase.class);
58 //The scientific name without author strings and year
59 private String nameCache;
60 //Non-atomised addition to a name not ruled by a nomenclatural code
61 private String appendedPhrase;
62 //Details of the nomenclatural reference (protologue). These are mostly (implicitly) pages but can also be figures or
63 //tables or any other element of a publication. {only if a nomenclatural reference exists}
64 private String nomenclaturalMicroReference;
65 //this flag will be set to true if the parseName method was unable to successfully parse the name
66 private boolean hasProblem = false;
67 protected Set<NameTypeDesignation> nameTypeDesignations = new HashSet<NameTypeDesignation>();
68 private HomotypicalGroup homotypicalGroup = new HomotypicalGroup();
69 private Set<NameRelationship> relationsFromThisName = new HashSet<NameRelationship>();
70 private Set<NameRelationship> relationsToThisName = new HashSet<NameRelationship>();
71 private Set<NomenclaturalStatus> status = new HashSet<NomenclaturalStatus>();
72 private Set<TaxonBase> taxonBases = new HashSet<TaxonBase>();
73
74 private Rank rank;
75 //if set, the Reference.isNomenclaturallyRelevant flag should be set to true!
76 private INomenclaturalReference nomenclaturalReference;
77
78 //this flag shows if the getNameCache should return generated value(false) or the given String(true)
79 protected boolean protectedNameCache;
80
81 protected INameCacheStrategy<T> cacheStrategy;
82
83 // /**
84 // * Returns a TaxonNameBase instance
85 // * @param fullName
86 // */
87 // abstract public static TaxonNameBase PARSED_NAME(String fullName);
88
89 // ************* CONSTRUCTORS *************/
90 /**
91 * Class constructor: creates a new empty taxon name instance.
92 *
93 * @see #TaxonNameBase(Rank)
94 * @see #TaxonNameBase(HomotypicalGroup)
95 * @see #TaxonNameBase(Rank, HomotypicalGroup)
96 */
97 public TaxonNameBase() {
98 this(null, null);
99 }
100 /**
101 * Class constructor: creates a new taxon name instance
102 * only containing its {@link common.Rank rank}.
103 *
104 * @param rank the rank to be assigned to this taxon name
105 * @see #TaxonNameBase()
106 * @see #TaxonNameBase(HomotypicalGroup)
107 * @see #TaxonNameBase(Rank, HomotypicalGroup)
108 */
109 public TaxonNameBase(Rank rank) {
110 this(rank, null);
111 }
112 /**
113 * Class constructor: creates a new taxon name instance
114 * only containing its {@link common.HomotypicalGroup homotypical group}.
115 * The new taxon name instance will be also added to the set of taxon names
116 * belonging to this homotypical group. If the homotypical group
117 * does not exist a new instance will be created for it.
118 *
119 * @param homotypicalGroup the homotypical group to which this taxon name belongs
120 * @see #TaxonNameBase()
121 * @see #TaxonNameBase(Rank)
122 * @see #TaxonNameBase(Rank, HomotypicalGroup)
123 */
124 public TaxonNameBase(HomotypicalGroup homotypicalGroup) {
125 this(null, homotypicalGroup);
126 }
127 /**
128 * Class constructor: creates a new instance of a taxon name
129 * only containing its {@link common.Rank rank} and
130 * its {@link common.HomotypicalGroup homotypical group}.
131 *
132 * @param rank the rank to be assigned to this taxon name
133 * @param homotypicalGroup the homotypical group to which this taxon name belongs
134 * @see #TaxonNameBase()
135 * @see #TaxonNameBase(Rank)
136 * @see #TaxonNameBase(HomotypicalGroup)
137 */
138 public TaxonNameBase(Rank rank, HomotypicalGroup homotypicalGroup) {
139 super();
140 this.setRank(rank);
141 if (homotypicalGroup == null){
142 homotypicalGroup = new HomotypicalGroup();
143 }
144 homotypicalGroup.addTypifiedName(this);
145 }
146
147 //********* METHODS **************************************/
148
149
150
151 /**
152 * Generates the composed name string of this taxon name without authors
153 * or year according to the strategy defined in
154 * {@link eu.etaxonomy.cdm.strategy.cache.INameCacheStrategy INameCacheStrategy}.
155 * The result might be stored in {@link #getNameCache() nameCache} if the
156 * flag {@link #isProtectedNameCache() protectedNameCache} is not set.
157 *
158 * @return the string with the composed name of this taxon name without authors or year
159 */
160 protected String generateNameCache(){
161 if (cacheStrategy == null){
162 logger.warn("No CacheStrategy defined for taxonName: " + this.toString());
163 return null;
164 }else{
165 return cacheStrategy.getNameCache((T)this);
166 }
167 }
168
169 /**
170 * Returns or generates the nameCache (scientific name
171 * without author strings and year) string for this taxon name. If the
172 * {@link #isProtectedNameCache() protectedNameCache} flag is not set (False)
173 * the string will be generated according to a defined strategy,
174 * otherwise the value of the actual nameCache string will be returned.
175 *
176 * @return the string which identifies this taxon name (without authors or year)
177 * @see #generateNameCache()
178 */
179 public String getNameCache() {
180 if (protectedNameCache){
181 return this.nameCache;
182 }
183 // is title dirty, i.e. equal NULL?
184 if (nameCache == null){
185 this.nameCache = generateNameCache();
186 }
187 return nameCache;
188 }
189
190 /**
191 * Assigns a nameCache string to this taxon name and protects it from being overwritten.
192 *
193 * @param nameCache the string which identifies this taxon name (without authors or year)
194 * @see #getNameCache()
195 */
196 public void setNameCache(String nameCache){
197 this.nameCache = nameCache;
198 this.setProtectedTitleCache(false);
199 this.setProtectedNameCache(true);
200 }
201
202 /**
203 * Returns the boolean value of the flag intended to protect (true)
204 * or not (false) the {@link #getNameCache() nameCache} (scientific name without author strings and year)
205 * string of this taxon name.
206 *
207 * @return the boolean value of the protectedNameCache flag
208 * @see #getNameCache()
209 */
210 public boolean isProtectedNameCache() {
211 return protectedNameCache;
212 }
213
214 /**
215 * @see #isProtectedNameCache()
216 */
217 public void setProtectedNameCache(boolean protectedNameCache) {
218 this.protectedNameCache = protectedNameCache;
219 }
220
221 /**
222 * Returns the boolean value "true" if the components of this taxon name
223 * follow the rules of the corresponding {@link NomenclaturalCode nomenclatural code},
224 * "false" otherwise. The nomenclatural code depends on
225 * the concrete name subclass ({@link BacterialName BacterialName},
226 * {@link BotanicalName BotanicalName}, {@link CultivarPlantName CultivarPlantName},
227 * {@link ZoologicalName ZoologicalName} or {@link ViralName ViralName})
228 * to which this taxon name belongs.
229 *
230 * @return the boolean value expressing the compliance of this taxon name to the nomenclatural code
231 */
232 @Transient
233 public abstract boolean isCodeCompliant();
234
235
236 /**
237 * Returns the set of all {@link NameRelationship name relationships}
238 * in which this taxon name is involved. A taxon name can be both source
239 * in some name relationships or target in some others.
240 *
241 * @see #getRelationsToThisName()
242 * @see #getRelationsFromThisName()
243 * @see #addNameRelationship(NameRelationship)
244 * @see #addRelationshipToName(TaxonNameBase, NameRelationshipType, String)
245 * @see #addRelationshipFromName(TaxonNameBase, NameRelationshipType, String)
246 */
247 @Transient
248 public Set<NameRelationship> getNameRelations() {
249 Set<NameRelationship> rels = new HashSet<NameRelationship>();
250 rels.addAll(getRelationsFromThisName());
251 rels.addAll(getRelationsToThisName());
252 return rels;
253 }
254 /**
255 * Creates a new {@link NameRelationship#NameRelationship(TaxonNameBase, TaxonNameBase, NameRelationshipType, String) name relationship} from this taxon name to another taxon name
256 * and adds it both to the set of {@link #getRelationsFromThisName() relations from this taxon name} and
257 * to the set of {@link #getRelationsToThisName() relations to the other taxon name}.
258 *
259 * @param toName the taxon name of the target for this new name relationship
260 * @param type the type of this new name relationship
261 * @param ruleConsidered the string which specifies the rule on which this name relationship is based
262 * @see #getRelationsToThisName()
263 * @see #getNameRelations()
264 * @see #addRelationshipFromName(TaxonNameBase, NameRelationshipType, String)
265 * @see #addNameRelationship(NameRelationship)
266 */
267 public void addRelationshipToName(TaxonNameBase toName, NameRelationshipType type, String ruleConsidered){
268 NameRelationship rel = new NameRelationship(toName, this, type, ruleConsidered);
269 }
270 /**
271 * Creates a new {@link NameRelationship#NameRelationship(TaxonNameBase, TaxonNameBase, NameRelationshipType, String) name relationship} from another taxon name to this taxon name
272 * and adds it both to the set of {@link #getRelationsToThisName() relations to this taxon name} and
273 * to the set of {@link #getRelationsFromThisName() relations from the other taxon name}.
274 *
275 * @param fromName the taxon name of the source for this new name relationship
276 * @param type the type of this new name relationship
277 * @param ruleConsidered the string which specifies the rule on which this name relationship is based
278 * @see #getRelationsFromThisName()
279 * @see #getNameRelations()
280 * @see #addRelationshipToName(TaxonNameBase, NameRelationshipType, String)
281 * @see #addNameRelationship(NameRelationship)
282 */
283 public void addRelationshipFromName(TaxonNameBase fromName, NameRelationshipType type, String ruleConsidered){
284 NameRelationship rel = new NameRelationship(this, fromName, type, ruleConsidered);
285 }
286 /**
287 * Adds an existing {@link NameRelationship name relationship} either to the set of
288 * {@link #getRelationsToThisName() relations to this taxon name} or to the set of
289 * {@link #getRelationsFromThisName() relations from this taxon name}. If neither the
290 * source nor the target of the name relationship match with this taxon
291 * no addition will be carried out.
292 *
293 * @param rel the name relationship to be added to one of this taxon name's name relationships sets
294 * @see #getNameRelations()
295 * @see #addRelationshipToName(TaxonNameBase, NameRelationshipType, String)
296 * @see #addRelationshipFromName(TaxonNameBase, NameRelationshipType, String)
297 */
298 protected void addNameRelationship(NameRelationship rel) {
299 if (rel!=null && rel.getToName().equals(this)){
300 this.relationsToThisName.add(rel);
301 }else if(rel!=null && rel.getFromName().equals(this)){
302 this.relationsFromThisName.add(rel);
303 }else{
304 //TODO: raise error???
305 }
306 }
307 /**
308 * Removes one {@link NameRelationship name relationship} from one of both sets of
309 * {@link #getNameRelations() name relationships} in which this taxon name is involved.
310 * The name relationship will also be removed from one of both sets belonging
311 * to the second taxon name involved. Furthermore the fromName and toName
312 * attributes of the name relationship object will be nullified.
313 *
314 * @param nameRelation the name relationship which should be deleted from one of both sets
315 * @see #getNameRelations()
316 */
317 public void removeNameRelationship(NameRelationship nameRelation) {
318 //TODO to be implemented?
319 logger.warn("not yet fully implemented?");
320 this.relationsToThisName.remove(nameRelation);
321 this.relationsFromThisName.remove(nameRelation);
322 }
323
324
325 /**
326 * Returns the set of all {@link NameRelationship name relationships}
327 * in which this taxon name is involved as a source.
328 *
329 * @see #getNameRelations()
330 * @see #getRelationsToThisName()
331 * @see #addRelationshipFromName(TaxonNameBase, NameRelationshipType, String)
332 */
333 @OneToMany(mappedBy="fromName", fetch= FetchType.EAGER)
334 @Cascade({CascadeType.SAVE_UPDATE})
335 public Set<NameRelationship> getRelationsFromThisName() {
336 return relationsFromThisName;
337 }
338 private void setRelationsFromThisName(Set<NameRelationship> relationsFromThisName) {
339 this.relationsFromThisName = relationsFromThisName;
340 }
341
342 /**
343 * Returns the set of all {@link NameRelationship name relationships}
344 * in which this taxon name is involved as a target.
345 *
346 * @see #getNameRelations()
347 * @see #getRelationsFromThisName()
348 * @see #addRelationshipToName(TaxonNameBase, NameRelationshipType, String)
349 */
350 @OneToMany(mappedBy="toName", fetch= FetchType.EAGER)
351 @Cascade({CascadeType.SAVE_UPDATE})
352 public Set<NameRelationship> getRelationsToThisName() {
353 return relationsToThisName;
354 }
355 private void setRelationsToThisName(Set<NameRelationship> relationsToThisName) {
356 this.relationsToThisName = relationsToThisName;
357 }
358
359
360 /**
361 * Returns the set of {@link NomenclaturalStatus nomenclatural status} assigned
362 * to this taxon name according to its corresponding nomenclature code.
363 * This includes the {@link NomenclaturalStatusType type} of the nomenclatural status
364 * and the nomenclatural code rule considered.
365 *
366 * @see NomenclaturalStatus
367 * @see NomenclaturalStatusType
368 */
369 @OneToMany(fetch= FetchType.EAGER)
370 @Cascade({CascadeType.SAVE_UPDATE})
371 public Set<NomenclaturalStatus> getStatus() {
372 return status;
373 }
374 /**
375 * @see #getStatus()
376 */
377 protected void setStatus(Set<NomenclaturalStatus> nomStatus) {
378 this.status = nomStatus;
379 }
380 /**
381 * Adds a new {@link NomenclaturalStatus nomenclatural status}
382 * to this taxon name's set of nomenclatural status.
383 *
384 * @param nomStatus the nomenclatural status to be added
385 * @see #getStatus()
386 */
387 public void addStatus(NomenclaturalStatus nomStatus) {
388 this.status.add(nomStatus);
389 }
390 /**
391 * Removes one element from the set of nomenclatural status of this taxon name.
392 * Type and ruleConsidered attributes of the nomenclatural status object
393 * will be nullified.
394 *
395 * @param nomStatus the nomenclatural status of this taxon name which should be deleted
396 * @see #getStatus()
397 */
398 public void removeStatus(NomenclaturalStatus nomStatus) {
399 //TODO to be implemented?
400 logger.warn("not yet fully implemented?");
401 this.status.remove(nomStatus);
402 }
403
404
405 /**
406 * Indicates if this taxon name is a {@link NameRelationshipType.BASIONYM() basionym}
407 * or a {@link NameRelationshipType.REPLACED_SYNONYM() replaced synonym}
408 * of any other taxon name. Returns true, if a basionym or a replaced synonym
409 * relationship from this taxon name to another taxon name exists,
410 * false otherwise (also in case this taxon name is the only one in the
411 * homotypical group).
412 */
413 @Transient
414 public boolean isOriginalCombination(){
415 Set<NameRelationship> relationsFromThisName = this.getRelationsFromThisName();
416 for (NameRelationship relation : relationsFromThisName) {
417 if (relation.getType().equals(NameRelationshipType.BASIONYM()) ||
418 relation.getType().equals(NameRelationshipType.REPLACED_SYNONYM())) {
419 return true;
420 }
421 }
422 return false;
423 }
424
425 /**
426 * Returns the taxon name which is the {@link NameRelationshipType.BASIONYM() basionym} of this taxon name.
427 * The basionym of a taxon name is its epithet-bringing synonym.
428 * For instance Pinus abies L. was published by Linnaeus and the botanist
429 * Karsten transferred later this taxon to the genus Picea. Therefore,
430 * Pinus abies L. is the basionym of the new combination Picea abies (L.) H. Karst.
431 */
432 @Transient
433 public T getBasionym(){
434 //TODO: pick the right name relationships...
435 return null;
436 }
437 /**
438 * Assigns another taxon name as {@link NameRelationshipType.BASIONYM() basionym} of this taxon name.
439 * The basionym relationship will be added to this taxon name
440 * and to the basionym. The basionym cannot have itself a basionym.
441 *
442 * @see #getBasionym()
443 * @see #setBasionym(TaxonNameBase, String)
444 */
445 public void setBasionym(T basionym){
446 setBasionym(basionym, null);
447 }
448 /**
449 * Assigns another taxon name as {@link NameRelationshipType.BASIONYM() basionym} of this taxon name
450 * and keeps the nomenclatural rule considered for it. The basionym
451 * relationship will be added to this taxon name and to the basionym.
452 * The basionym cannot have itself a basionym.
453 *
454 * @see #getBasionym()
455 * @see #setBasionym(TaxonNameBase)
456 */
457 public void setBasionym(T basionym, String ruleConsidered){
458 basionym.addRelationshipToName(this, NameRelationshipType.BASIONYM(), ruleConsidered);
459 }
460
461
462
463 //TODO for PROTOTYPE
464 @Transient
465 public INameCacheStrategy<T> getCacheStrategy() {
466 return cacheStrategy;
467 }
468 public void setCacheStrategy(INameCacheStrategy cacheStrategy) {
469 this.cacheStrategy = cacheStrategy;
470 }
471
472 @ManyToOne
473 //@Cascade({CascadeType.SAVE_UPDATE})
474 public Rank getRank(){
475 return this.rank;
476 }
477 public void setRank(Rank rank){
478 this.rank = rank;
479 }
480
481 @ManyToOne
482 @Cascade({CascadeType.SAVE_UPDATE})
483 public ReferenceBase getNomenclaturalReference(){
484 return (ReferenceBase) this.nomenclaturalReference;
485 }
486 public void setNomenclaturalReference(INomenclaturalReference nomenclaturalReference){
487 this.nomenclaturalReference = nomenclaturalReference;
488 }
489
490
491 public String getAppendedPhrase(){
492 return this.appendedPhrase;
493 }
494 public void setAppendedPhrase(String appendedPhrase){
495 this.appendedPhrase = appendedPhrase;
496 }
497
498 public String getNomenclaturalMicroReference(){
499 return this.nomenclaturalMicroReference;
500 }
501 public void setNomenclaturalMicroReference(String nomenclaturalMicroReference){
502 this.nomenclaturalMicroReference = nomenclaturalMicroReference;
503 }
504
505 public boolean getHasProblem(){
506 return this.hasProblem;
507 }
508 public void setHasProblem(boolean hasProblem){
509 this.hasProblem = hasProblem;
510 }
511 /**
512 * Same as getHasProblem()
513 * @return
514 */
515 public boolean hasProblem(){
516 return getHasProblem();
517 }
518
519
520 @OneToMany
521 //TODO @Cascade({CascadeType.SAVE_UPDATE, CascadeType.DELETE_ORPHAN})
522 @Cascade(CascadeType.SAVE_UPDATE)
523 public Set<NameTypeDesignation> getNameTypeDesignations() {
524 return nameTypeDesignations;
525 }
526 protected void setNameTypeDesignations(Set<NameTypeDesignation> nameTypeDesignations) {
527 this.nameTypeDesignations = nameTypeDesignations;
528 }
529
530 public void addTypeDesignation(TaxonNameBase typeSpecies, ReferenceBase citation, String citationMicroReference, String originalNameString, boolean isRejectedType, boolean isConservedType) {
531 NameTypeDesignation td = new NameTypeDesignation(this, typeSpecies, citation, citationMicroReference, originalNameString, isRejectedType, isConservedType);
532 }
533 public void addTypeDesignation(Specimen typeSpecimen, TypeDesignationStatus status, ReferenceBase citation, String citationMicroReference, String originalNameString) {
534 this.homotypicalGroup.addTypeDesignation(typeSpecimen, status, citation, citationMicroReference, originalNameString);
535 }
536 public void removeTypeDesignation(NameTypeDesignation typeDesignation) {
537 this.nameTypeDesignations.remove(typeDesignation);
538 }
539 public void removeTypeDesignation(SpecimenTypeDesignation typeDesignation) {
540 this.homotypicalGroup.removeTypeDesignation(typeDesignation);
541 }
542
543
544 @ManyToOne
545 @Cascade({CascadeType.SAVE_UPDATE})
546 public HomotypicalGroup getHomotypicalGroup() {
547 return homotypicalGroup;
548 }
549 public void setHomotypicalGroup(HomotypicalGroup newHomotypicalGroup) {
550 if(this.homotypicalGroup == newHomotypicalGroup) return;
551 if (homotypicalGroup != null) {
552 homotypicalGroup.typifiedNames.remove(this);
553 }
554 if (newHomotypicalGroup!= null) {
555 //hack for avoiding org.hibernate.LazyInitializationException: illegal access to loading collection
556 if (newHomotypicalGroup.typifiedNames instanceof PersistentSet){
557 //
558 }else{
559 newHomotypicalGroup.typifiedNames.add(this);
560 }
561 }
562 this.homotypicalGroup = newHomotypicalGroup;
563 }
564
565 @Transient
566 public StrictReferenceBase getCitation(){
567 logger.warn("getCitation not yet implemented");
568 return null;
569 }
570
571 @Transient
572 public String getCitationString(){
573 logger.warn("getCitationString not yet implemented");
574 return null;
575 }
576
577 @Transient
578 public String[] getProblems(){
579 logger.warn("getProblems not yet implemented");
580 return null;
581 }
582
583 /**
584 * returns year of according nomenclatural reference, null if nomenclatural
585 * reference does not exist
586 */
587 @Transient
588 public String getReferenceYear(){
589 if (this.getNomenclaturalReference() != null ){
590 return this.getNomenclaturalReference().getYear();
591 }else{
592 return null;
593 }
594 }
595
596 @OneToMany(mappedBy="name", fetch= FetchType.EAGER)
597 public Set<TaxonBase> getTaxonBases() {
598 return this.taxonBases;
599 }
600 protected void setTaxonBases(Set<TaxonBase> taxonBases) {
601 if (taxonBases == null){
602 taxonBases = new HashSet<TaxonBase>();
603 }else{
604 this.taxonBases = taxonBases;
605 }
606 }
607 // public void addSynonym(Synonym synonym) {
608 // synonym.setName(this);
609 // }
610 // public void removeSynonym(Synonym synonym) {
611 // synonym.setName(null);
612 // }
613
614 /**
615 * Return a set of taxa that use this name
616 * @return
617 */
618 @Transient
619 public Set<Taxon> getTaxa(){
620 Set<Taxon> result = new HashSet<Taxon>();
621 for (TaxonBase taxonBase : this.taxonBases){
622 if (taxonBase instanceof Taxon){
623 result.add((Taxon)taxonBase);
624 }
625 }
626 return result;
627 }
628
629 /**
630 * Return a set of synonyms that use this name
631 * @return
632 */
633 // TODO: implement this method via bidirectional TaxonBase-NameBase relation or use a DAO instead
634 //@OneToMany
635
636 @Transient
637 public Set<Synonym> getSynonyms() {
638 Set<Synonym> result = new HashSet<Synonym>();
639 for (TaxonBase taxonBase : this.taxonBases){
640 if (taxonBase instanceof Synonym){
641 result.add((Synonym)taxonBase);
642 }
643 }
644 return result;
645 }
646
647 @Transient
648 public Set<SpecimenTypeDesignation> getSpecimenTypeDesignations() {
649 return this.getHomotypicalGroup().getTypeDesignations();
650 }
651
652 // Rank comparison shortcuts
653 @Transient
654 public boolean isSupraGeneric() {
655 return getRank().isSupraGeneric();
656 }
657 @Transient
658 public boolean isGenus() {
659 return getRank().isGenus();
660 }
661 @Transient
662 public boolean isInfraGeneric() {
663 return getRank().isInfraGeneric();
664 }
665 @Transient
666 public boolean isSpecies() {
667 return getRank().isSpecies();
668 }
669 @Transient
670 public boolean isInfraSpecific() {
671 return getRank().isInfraSpecific();
672 }
673
674 @Transient
675 abstract public NomenclaturalCode getNomeclaturalCode();
676
677
678 }