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