(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
13 import eu.etaxonomy.cdm.model.occurrence.Specimen;
14 import eu.etaxonomy.cdm.model.reference.INomenclaturalReference;
15 import eu.etaxonomy.cdm.model.reference.ReferenceBase;
16 import eu.etaxonomy.cdm.model.reference.StrictReferenceBase;
17 import eu.etaxonomy.cdm.model.taxon.Synonym;
18 import eu.etaxonomy.cdm.model.taxon.Taxon;
19 import eu.etaxonomy.cdm.model.taxon.TaxonBase;
20 import eu.etaxonomy.cdm.model.common.IdentifiableEntity;
21 import eu.etaxonomy.cdm.model.common.IReferencedEntity;
22 import org.apache.log4j.Logger;
23 import org.hibernate.annotations.Cascade;
24 import org.hibernate.annotations.CascadeType;
25
26 import eu.etaxonomy.cdm.strategy.cache.INameCacheStrategy;
27 import eu.etaxonomy.cdm.strategy.parser.ITaxonNameParser;
28
29 import java.util.*;
30
31 import javax.persistence.*;
32
33 /**
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
37 *
38 * @author m.doering
39 * @version 1.0
40 * @created 08-Nov-2007 13:06:57
41 */
42 @Entity
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>();
61
62 private Rank rank;
63 //if set, the Reference.isNomenclaturallyRelevant flag should be set to true!
64 private INomenclaturalReference nomenclaturalReference;
65
66 //this flag shows if the getNameCache should return generated value(false) or the given String(true)
67 protected boolean protectedNameCache;
68
69 protected INameCacheStrategy<T> cacheStrategy;
70
71 // /**
72 // * Returns a TaxonNameBase instance
73 // * @param fullName
74 // */
75 // abstract public static TaxonNameBase PARSED_NAME(String fullName);
76
77 // ************* CONSTRUCTORS *************/
78 public TaxonNameBase() {
79 this(null, null);
80 }
81 public TaxonNameBase(Rank rank) {
82 this(rank, null);
83 }
84 public TaxonNameBase(HomotypicalGroup homotypicalGroup) {
85 this(null, homotypicalGroup);
86 }
87 public TaxonNameBase(Rank rank, HomotypicalGroup homotypicalGroup) {
88 super();
89 this.setRank(rank);
90 if (homotypicalGroup == null){
91 homotypicalGroup = new HomotypicalGroup();
92 }
93 homotypicalGroup.addTypifiedName(this);
94 }
95
96 //********* METHODS **************************************/
97
98
99
100 protected String generateNameCache(){
101 if (cacheStrategy == null){
102 logger.warn("No CacheStrategy defined for taxonName: " + this.toString());
103 return null;
104 }else{
105 return cacheStrategy.getNameCache((T)this);
106 }
107 }
108
109 public String getNameCache() {
110 if (protectedNameCache){
111 return this.nameCache;
112 }
113 // is title dirty, i.e. equal NULL?
114 if (nameCache == null){
115 this.nameCache = generateNameCache();
116 }
117 return nameCache;
118 }
119
120 public void setNameCache(String nameCache){
121 this.nameCache = nameCache;
122 // TODO this.setProtectedNameCache(true);
123 }
124
125
126
127 @Transient
128 public abstract boolean isCodeCompliant();
129
130
131 @Transient
132 public Set<NameRelationship> getNameRelations() {
133 Set<NameRelationship> rels = new HashSet<NameRelationship>();
134 rels.addAll(getRelationsFromThisName());
135 rels.addAll(getRelationsToThisName());
136 return rels;
137 }
138 /**
139 * Add a name relationship to both names involved
140 * @param rel
141 */
142 public void addRelationshipToName(TaxonNameBase toName, NameRelationshipType type, String ruleConsidered){
143 NameRelationship rel = new NameRelationship(toName, this, type, ruleConsidered);
144 }
145 public void addRelationshipFromName(TaxonNameBase fromName, NameRelationshipType type, String ruleConsidered){
146 NameRelationship rel = new NameRelationship(this, fromName, type, ruleConsidered);
147 }
148 protected void addNameRelationship(NameRelationship rel) {
149 if (rel!=null && rel.getToName().equals(this)){
150 this.relationsToThisName.add(rel);
151 }else if(rel!=null && rel.getFromName().equals(this)){
152 this.relationsFromThisName.add(rel);
153 }else{
154 //TODO: raise error???
155 }
156 }
157 public void removeNameRelationship(NameRelationship nameRelation) {
158 this.relationsToThisName.remove(nameRelation);
159 this.relationsFromThisName.remove(nameRelation);
160 }
161
162
163 @OneToMany(mappedBy="fromName")
164 @Cascade({CascadeType.SAVE_UPDATE})
165 public Set<NameRelationship> getRelationsFromThisName() {
166 return relationsFromThisName;
167 }
168 private void setRelationsFromThisName(Set<NameRelationship> relationsFromThisName) {
169 this.relationsFromThisName = relationsFromThisName;
170 }
171
172 @OneToMany(mappedBy="toName")
173 @Cascade({CascadeType.SAVE_UPDATE})
174 public Set<NameRelationship> getRelationsToThisName() {
175 return relationsToThisName;
176 }
177 private void setRelationsToThisName(Set<NameRelationship> relationsToThisName) {
178 this.relationsToThisName = relationsToThisName;
179 }
180
181
182
183 @OneToMany
184 @Cascade({CascadeType.SAVE_UPDATE})
185 public Set<NomenclaturalStatus> getStatus() {
186 return status;
187 }
188 protected void setStatus(Set<NomenclaturalStatus> nomStatus) {
189 this.status = nomStatus;
190 }
191 public void addStatus(NomenclaturalStatus nomStatus) {
192 this.status.add(nomStatus);
193 }
194 public void removeStatus(NomenclaturalStatus nomStatus) {
195 this.status.remove(nomStatus);
196 }
197
198
199 @Transient
200 public T getBasionym(){
201 //TODO: pick the right name relationships...
202 return null;
203 }
204 public void setBasionym(T basionym){
205 setBasionym(basionym, null);
206 }
207 public void setBasionym(T basionym, String ruleConsidered){
208 basionym.addRelationshipToName(this, NameRelationshipType.BASIONYM(), null);
209 }
210
211
212
213 //TODO for PROTOTYPE
214 @Transient
215 public INameCacheStrategy<T> getCacheStrategy() {
216 return cacheStrategy;
217 }
218 public void setCacheStrategy(INameCacheStrategy cacheStrategy) {
219 this.cacheStrategy = cacheStrategy;
220 }
221
222 @ManyToOne
223 //@Cascade({CascadeType.SAVE_UPDATE})
224 public Rank getRank(){
225 return this.rank;
226 }
227 public void setRank(Rank rank){
228 this.rank = rank;
229 }
230
231 @ManyToOne
232 @Cascade({CascadeType.SAVE_UPDATE})
233 public ReferenceBase getNomenclaturalReference(){
234 return (ReferenceBase) this.nomenclaturalReference;
235 }
236 public void setNomenclaturalReference(INomenclaturalReference nomenclaturalReference){
237 this.nomenclaturalReference = nomenclaturalReference;
238 }
239
240
241 public String getAppendedPhrase(){
242 return this.appendedPhrase;
243 }
244 public void setAppendedPhrase(String appendedPhrase){
245 this.appendedPhrase = appendedPhrase;
246 }
247
248 public String getNomenclaturalMicroReference(){
249 return this.nomenclaturalMicroReference;
250 }
251 public void setNomenclaturalMicroReference(String nomenclaturalMicroReference){
252 this.nomenclaturalMicroReference = nomenclaturalMicroReference;
253 }
254
255 public boolean getHasProblem(){
256 return this.hasProblem;
257 }
258 public void setHasProblem(boolean hasProblem){
259 this.hasProblem = hasProblem;
260 }
261
262
263 @OneToMany
264 //TODO @Cascade({CascadeType.SAVE_UPDATE, CascadeType.DELETE_ORPHAN})
265 @Cascade(CascadeType.SAVE_UPDATE)
266 public Set<NameTypeDesignation> getNameTypeDesignations() {
267 return nameTypeDesignations;
268 }
269 protected void setNameTypeDesignations(Set<NameTypeDesignation> nameTypeDesignations) {
270 this.nameTypeDesignations = nameTypeDesignations;
271 }
272
273 public void addTypeDesignation(TaxonNameBase typeSpecies, ReferenceBase citation, String citationMicroReference, String originalNameString, boolean isRejectedType, boolean isConservedType) {
274 NameTypeDesignation td = new NameTypeDesignation(this, typeSpecies, citation, citationMicroReference, originalNameString, isRejectedType, isConservedType);
275 }
276 public void addTypeDesignation(Specimen typeSpecimen, TypeDesignationStatus status, ReferenceBase citation, String citationMicroReference, String originalNameString) {
277 this.homotypicalGroup.addTypeDesignation(typeSpecimen, status, citation, citationMicroReference, originalNameString);
278 }
279 public void removeTypeDesignation(NameTypeDesignation typeDesignation) {
280 this.nameTypeDesignations.remove(typeDesignation);
281 }
282 public void removeTypeDesignation(SpecimenTypeDesignation typeDesignation) {
283 this.homotypicalGroup.removeTypeDesignation(typeDesignation);
284 }
285
286
287 @ManyToOne
288 @Cascade({CascadeType.SAVE_UPDATE})
289 public HomotypicalGroup getHomotypicalGroup() {
290 return homotypicalGroup;
291 }
292 public void setHomotypicalGroup(HomotypicalGroup newHomotypicalGroup) {
293 if(this.homotypicalGroup == newHomotypicalGroup) return;
294 if (homotypicalGroup != null) {
295 homotypicalGroup.typifiedNames.remove(this);
296 }
297 if (newHomotypicalGroup!= null) {
298 newHomotypicalGroup.typifiedNames.add(this);
299 }
300 this.homotypicalGroup = newHomotypicalGroup;
301 }
302
303 @Transient
304 public StrictReferenceBase getCitation(){
305 logger.warn("getCitation not yet implemented");
306 return null;
307 }
308
309 @Transient
310 public String getCitationString(){
311 logger.warn("getCitationString not yet implemented");
312 return null;
313 }
314
315 @Transient
316 public String[] getProblems(){
317 logger.warn("getProblems not yet implemented");
318 return null;
319 }
320
321 /**
322 * returns year of according nomenclatural reference, null if nomenclatural
323 * reference does not exist
324 */
325 @Transient
326 public String getReferenceYear(){
327 if (this.getNomenclaturalReference() != null ){
328 return this.getNomenclaturalReference().getYear();
329 }else{
330 return null;
331 }
332 }
333
334 @OneToMany(mappedBy="name", fetch= FetchType.EAGER)
335 public Set<TaxonBase> getTaxonBases() {
336 return this.taxonBases;
337 }
338 protected void setTaxonBases(Set<TaxonBase> taxonBases) {
339 if (taxonBases == null){
340 taxonBases = new HashSet<TaxonBase>();
341 }else{
342 this.taxonBases = taxonBases;
343 }
344 }
345 // public void addSynonym(Synonym synonym) {
346 // synonym.setName(this);
347 // }
348 // public void removeSynonym(Synonym synonym) {
349 // synonym.setName(null);
350 // }
351
352 /**
353 * Return a set of taxa that use this name
354 * @return
355 */
356 @Transient
357 public Set<Taxon> getTaxa(){
358 Set<Taxon> result = new HashSet<Taxon>();
359 for (TaxonBase taxonBase : this.taxonBases){
360 if (taxonBase instanceof Taxon){
361 result.add((Taxon)taxonBase);
362 }
363 }
364 return result;
365 }
366
367 /**
368 * Return a set of synonyms that use this name
369 * @return
370 */
371 // TODO: implement this method via bidirectional TaxonBase-NameBase relation or use a DAO instead
372 //@OneToMany
373
374 @Transient
375 public Set<Synonym> getSynonyms() {
376 Set<Synonym> result = new HashSet<Synonym>();
377 for (TaxonBase taxonBase : this.taxonBases){
378 if (taxonBase instanceof Synonym){
379 result.add((Synonym)taxonBase);
380 }
381 }
382 return result;
383 }
384
385 @Transient
386 public Set<SpecimenTypeDesignation> getSpecimenTypeDesignations() {
387 return this.getHomotypicalGroup().getTypeDesignations();
388 }
389
390 // Rank comparison shortcuts
391 @Transient
392 public boolean isSupraGeneric() {
393 return getRank().isSupraGeneric();
394 }
395 @Transient
396 public boolean isGenus() {
397 return getRank().isGenus();
398 }
399 @Transient
400 public boolean isInfraGeneric() {
401 return getRank().isInfraGeneric();
402 }
403 @Transient
404 public boolean isSpecies() {
405 return getRank().isSpecies();
406 }
407 @Transient
408 public boolean isInfraSpecific() {
409 return getRank().isInfraSpecific();
410 }
411
412 }