2 * Copyright (C) 2007 EDIT
3 * European Distributed Institute of Taxonomy
4 * http://www.e-taxonomy.eu
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.
10 package eu
.etaxonomy
.cdm
.model
.name
;
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
.IdentifiableEntity
;
20 import eu
.etaxonomy
.cdm
.model
.common
.IReferencedEntity
;
21 import org
.apache
.log4j
.Logger
;
22 import org
.hibernate
.annotations
.Cascade
;
23 import org
.hibernate
.annotations
.CascadeType
;
24 import org
.hibernate
.collection
.PersistentSet
;
26 import eu
.etaxonomy
.cdm
.strategy
.cache
.INameCacheStrategy
;
31 import javax
.persistence
.*;
34 * The upmost (abstract) class for scientific taxon names regardless of any
35 * particular nomenclatural code. The scientific name including author strings and
36 * maybe year is stored in IdentifiableEntity.titleCache
40 * @created 08-Nov-2007 13:06:57
43 @Inheritance(strategy
=InheritanceType
.SINGLE_TABLE
)
44 public abstract class TaxonNameBase
<T
extends TaxonNameBase
> extends IdentifiableEntity
<TaxonNameBase
> implements IReferencedEntity
{
45 static Logger logger
= Logger
.getLogger(TaxonNameBase
.class);
46 //The scientific name without author strings and year
47 private String nameCache
;
48 //Non-atomised addition to a name not ruled by a nomenclatural code
49 private String appendedPhrase
;
50 //Details of the nomenclatural reference (protologue). These are mostly (implicitly) pages but can also be figures or
51 //tables or any other element of a publication. {only if a nomenclatural reference exists}
52 private String nomenclaturalMicroReference
;
53 //this flag will be set to true if the parseName method was unable to successfully parse the name
54 private boolean hasProblem
= false;
55 protected Set
<NameTypeDesignation
> nameTypeDesignations
= new HashSet
<NameTypeDesignation
>();
56 private HomotypicalGroup homotypicalGroup
= new HomotypicalGroup();
57 private Set
<NameRelationship
> relationsFromThisName
= new HashSet
<NameRelationship
>();
58 private Set
<NameRelationship
> relationsToThisName
= new HashSet
<NameRelationship
>();
59 private Set
<NomenclaturalStatus
> status
= new HashSet
<NomenclaturalStatus
>();
60 private Set
<TaxonBase
> taxonBases
= new HashSet
<TaxonBase
>();
63 //if set, the Reference.isNomenclaturallyRelevant flag should be set to true!
64 private INomenclaturalReference nomenclaturalReference
;
66 //this flag shows if the getNameCache should return generated value(false) or the given String(true)
67 protected boolean protectedNameCache
;
69 protected INameCacheStrategy
<T
> cacheStrategy
;
72 // * Returns a TaxonNameBase instance
75 // abstract public static TaxonNameBase PARSED_NAME(String fullName);
77 // ************* CONSTRUCTORS *************/
78 public TaxonNameBase() {
81 public TaxonNameBase(Rank rank
) {
84 public TaxonNameBase(HomotypicalGroup homotypicalGroup
) {
85 this(null, homotypicalGroup
);
87 public TaxonNameBase(Rank rank
, HomotypicalGroup homotypicalGroup
) {
90 if (homotypicalGroup
== null){
91 homotypicalGroup
= new HomotypicalGroup();
93 homotypicalGroup
.addTypifiedName(this);
96 //********* METHODS **************************************/
100 protected String
generateNameCache(){
101 if (cacheStrategy
== null){
102 logger
.warn("No CacheStrategy defined for taxonName: " + this.toString());
105 return cacheStrategy
.getNameCache((T
)this);
109 public String
getNameCache() {
110 if (protectedNameCache
){
111 return this.nameCache
;
113 // is title dirty, i.e. equal NULL?
114 if (nameCache
== null){
115 this.nameCache
= generateNameCache();
120 public void setNameCache(String nameCache
){
121 this.nameCache
= nameCache
;
122 this.setProtectedTitleCache(false);
123 this.setProtectedNameCache(true);
126 public boolean isProtectedNameCache() {
127 return protectedNameCache
;
130 public void setProtectedNameCache(boolean protectedNameCache
) {
131 this.protectedNameCache
= protectedNameCache
;
137 public abstract boolean isCodeCompliant();
141 public Set
<NameRelationship
> getNameRelations() {
142 Set
<NameRelationship
> rels
= new HashSet
<NameRelationship
>();
143 rels
.addAll(getRelationsFromThisName());
144 rels
.addAll(getRelationsToThisName());
148 * Add a name relationship to both names involved
151 public void addRelationshipToName(TaxonNameBase toName
, NameRelationshipType type
, String ruleConsidered
){
152 NameRelationship rel
= new NameRelationship(toName
, this, type
, ruleConsidered
);
154 public void addRelationshipFromName(TaxonNameBase fromName
, NameRelationshipType type
, String ruleConsidered
){
155 NameRelationship rel
= new NameRelationship(this, fromName
, type
, ruleConsidered
);
157 protected void addNameRelationship(NameRelationship rel
) {
158 if (rel
!=null && rel
.getToName().equals(this)){
159 this.relationsToThisName
.add(rel
);
160 }else if(rel
!=null && rel
.getFromName().equals(this)){
161 this.relationsFromThisName
.add(rel
);
163 //TODO: raise error???
166 public void removeNameRelationship(NameRelationship nameRelation
) {
167 this.relationsToThisName
.remove(nameRelation
);
168 this.relationsFromThisName
.remove(nameRelation
);
172 @OneToMany(mappedBy
="fromName", fetch
= FetchType
.EAGER
)
173 @Cascade({CascadeType
.SAVE_UPDATE
})
174 public Set
<NameRelationship
> getRelationsFromThisName() {
175 return relationsFromThisName
;
177 private void setRelationsFromThisName(Set
<NameRelationship
> relationsFromThisName
) {
178 this.relationsFromThisName
= relationsFromThisName
;
181 @OneToMany(mappedBy
="toName", fetch
= FetchType
.EAGER
)
182 @Cascade({CascadeType
.SAVE_UPDATE
})
183 public Set
<NameRelationship
> getRelationsToThisName() {
184 return relationsToThisName
;
186 private void setRelationsToThisName(Set
<NameRelationship
> relationsToThisName
) {
187 this.relationsToThisName
= relationsToThisName
;
192 @OneToMany(fetch
= FetchType
.EAGER
)
193 @Cascade({CascadeType
.SAVE_UPDATE
})
194 public Set
<NomenclaturalStatus
> getStatus() {
197 protected void setStatus(Set
<NomenclaturalStatus
> nomStatus
) {
198 this.status
= nomStatus
;
200 public void addStatus(NomenclaturalStatus nomStatus
) {
201 this.status
.add(nomStatus
);
203 public void removeStatus(NomenclaturalStatus nomStatus
) {
204 this.status
.remove(nomStatus
);
209 * Indicates if this taxon name has a basionym or replaced synonym relationship to any other name.
210 * @return true, if a {@link NameRelationshipType.BASIONYM()} or a {@link NameRelationshipType.REPLACED_SYNONYM()}
211 * relationship from this name to another name exists.
214 public boolean isOriginalCombination(){
215 Set
<NameRelationship
> relationsFromThisName
= this.getRelationsFromThisName();
216 for (NameRelationship relation
: relationsFromThisName
) {
217 if (relation
.getType().equals(NameRelationshipType
.BASIONYM()) ||
218 relation
.getType().equals(NameRelationshipType
.REPLACED_SYNONYM())) {
227 public T
getBasionym(){
228 //TODO: pick the right name relationships...
231 public void setBasionym(T basionym
){
232 setBasionym(basionym
, null);
234 public void setBasionym(T basionym
, String ruleConsidered
){
235 basionym
.addRelationshipToName(this, NameRelationshipType
.BASIONYM(), null);
242 public INameCacheStrategy
<T
> getCacheStrategy() {
243 return cacheStrategy
;
245 public void setCacheStrategy(INameCacheStrategy cacheStrategy
) {
246 this.cacheStrategy
= cacheStrategy
;
250 //@Cascade({CascadeType.SAVE_UPDATE})
251 public Rank
getRank(){
254 public void setRank(Rank rank
){
259 @Cascade({CascadeType
.SAVE_UPDATE
})
260 public ReferenceBase
getNomenclaturalReference(){
261 return (ReferenceBase
) this.nomenclaturalReference
;
263 public void setNomenclaturalReference(INomenclaturalReference nomenclaturalReference
){
264 this.nomenclaturalReference
= nomenclaturalReference
;
268 public String
getAppendedPhrase(){
269 return this.appendedPhrase
;
271 public void setAppendedPhrase(String appendedPhrase
){
272 this.appendedPhrase
= appendedPhrase
;
275 public String
getNomenclaturalMicroReference(){
276 return this.nomenclaturalMicroReference
;
278 public void setNomenclaturalMicroReference(String nomenclaturalMicroReference
){
279 this.nomenclaturalMicroReference
= nomenclaturalMicroReference
;
282 public boolean getHasProblem(){
283 return this.hasProblem
;
285 public void setHasProblem(boolean hasProblem
){
286 this.hasProblem
= hasProblem
;
291 //TODO @Cascade({CascadeType.SAVE_UPDATE, CascadeType.DELETE_ORPHAN})
292 @Cascade(CascadeType
.SAVE_UPDATE
)
293 public Set
<NameTypeDesignation
> getNameTypeDesignations() {
294 return nameTypeDesignations
;
296 protected void setNameTypeDesignations(Set
<NameTypeDesignation
> nameTypeDesignations
) {
297 this.nameTypeDesignations
= nameTypeDesignations
;
300 public void addTypeDesignation(TaxonNameBase typeSpecies
, ReferenceBase citation
, String citationMicroReference
, String originalNameString
, boolean isRejectedType
, boolean isConservedType
) {
301 NameTypeDesignation td
= new NameTypeDesignation(this, typeSpecies
, citation
, citationMicroReference
, originalNameString
, isRejectedType
, isConservedType
);
303 public void addTypeDesignation(Specimen typeSpecimen
, TypeDesignationStatus status
, ReferenceBase citation
, String citationMicroReference
, String originalNameString
) {
304 this.homotypicalGroup
.addTypeDesignation(typeSpecimen
, status
, citation
, citationMicroReference
, originalNameString
);
306 public void removeTypeDesignation(NameTypeDesignation typeDesignation
) {
307 this.nameTypeDesignations
.remove(typeDesignation
);
309 public void removeTypeDesignation(SpecimenTypeDesignation typeDesignation
) {
310 this.homotypicalGroup
.removeTypeDesignation(typeDesignation
);
315 @Cascade({CascadeType
.SAVE_UPDATE
})
316 public HomotypicalGroup
getHomotypicalGroup() {
317 return homotypicalGroup
;
319 public void setHomotypicalGroup(HomotypicalGroup newHomotypicalGroup
) {
320 if(this.homotypicalGroup
== newHomotypicalGroup
) return;
321 if (homotypicalGroup
!= null) {
322 homotypicalGroup
.typifiedNames
.remove(this);
324 if (newHomotypicalGroup
!= null) {
325 //hack for avoiding org.hibernate.LazyInitializationException: illegal access to loading collection
326 if (newHomotypicalGroup
.typifiedNames
instanceof PersistentSet
){
329 newHomotypicalGroup
.typifiedNames
.add(this);
332 this.homotypicalGroup
= newHomotypicalGroup
;
336 public StrictReferenceBase
getCitation(){
337 logger
.warn("getCitation not yet implemented");
342 public String
getCitationString(){
343 logger
.warn("getCitationString not yet implemented");
348 public String
[] getProblems(){
349 logger
.warn("getProblems not yet implemented");
354 * returns year of according nomenclatural reference, null if nomenclatural
355 * reference does not exist
358 public String
getReferenceYear(){
359 if (this.getNomenclaturalReference() != null ){
360 return this.getNomenclaturalReference().getYear();
366 @OneToMany(mappedBy
="name", fetch
= FetchType
.EAGER
)
367 public Set
<TaxonBase
> getTaxonBases() {
368 return this.taxonBases
;
370 protected void setTaxonBases(Set
<TaxonBase
> taxonBases
) {
371 if (taxonBases
== null){
372 taxonBases
= new HashSet
<TaxonBase
>();
374 this.taxonBases
= taxonBases
;
377 // public void addSynonym(Synonym synonym) {
378 // synonym.setName(this);
380 // public void removeSynonym(Synonym synonym) {
381 // synonym.setName(null);
385 * Return a set of taxa that use this name
389 public Set
<Taxon
> getTaxa(){
390 Set
<Taxon
> result
= new HashSet
<Taxon
>();
391 for (TaxonBase taxonBase
: this.taxonBases
){
392 if (taxonBase
instanceof Taxon
){
393 result
.add((Taxon
)taxonBase
);
400 * Return a set of synonyms that use this name
403 // TODO: implement this method via bidirectional TaxonBase-NameBase relation or use a DAO instead
407 public Set
<Synonym
> getSynonyms() {
408 Set
<Synonym
> result
= new HashSet
<Synonym
>();
409 for (TaxonBase taxonBase
: this.taxonBases
){
410 if (taxonBase
instanceof Synonym
){
411 result
.add((Synonym
)taxonBase
);
418 public Set
<SpecimenTypeDesignation
> getSpecimenTypeDesignations() {
419 return this.getHomotypicalGroup().getTypeDesignations();
422 // Rank comparison shortcuts
424 public boolean isSupraGeneric() {
425 return getRank().isSupraGeneric();
428 public boolean isGenus() {
429 return getRank().isGenus();
432 public boolean isInfraGeneric() {
433 return getRank().isInfraGeneric();
436 public boolean isSpecies() {
437 return getRank().isSpecies();
440 public boolean isInfraSpecific() {
441 return getRank().isInfraSpecific();
445 public String
getNomeclaturalCodeAbbrev(){