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