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