Project

General

Profile

Download (47.8 KB) Statistics
| Branch: | Tag: | Revision:
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 java.lang.reflect.Method;
13
import java.util.HashSet;
14
import java.util.Set;
15

    
16
import javax.persistence.Column;
17
import javax.persistence.Entity;
18
import javax.persistence.FetchType;
19
import javax.persistence.Inheritance;
20
import javax.persistence.InheritanceType;
21
import javax.persistence.ManyToMany;
22
import javax.persistence.ManyToOne;
23
import javax.persistence.OneToMany;
24
import javax.persistence.Transient;
25
import javax.xml.bind.annotation.XmlAccessType;
26
import javax.xml.bind.annotation.XmlAccessorType;
27
import javax.xml.bind.annotation.XmlAttribute;
28
import javax.xml.bind.annotation.XmlElement;
29
import javax.xml.bind.annotation.XmlElementWrapper;
30
import javax.xml.bind.annotation.XmlIDREF;
31
import javax.xml.bind.annotation.XmlRootElement;
32
import javax.xml.bind.annotation.XmlSchemaType;
33
import javax.xml.bind.annotation.XmlType;
34

    
35
import org.apache.log4j.Logger;
36
import org.hibernate.annotations.Cascade;
37
import org.hibernate.annotations.CascadeType;
38
import org.hibernate.annotations.Index;
39
import org.hibernate.annotations.Table;
40
import org.hibernate.envers.Audited;
41
import org.hibernate.search.annotations.Field;
42
import org.springframework.util.ReflectionUtils;
43

    
44
import eu.etaxonomy.cdm.model.common.IParsable;
45
import eu.etaxonomy.cdm.model.common.IReferencedEntity;
46
import eu.etaxonomy.cdm.model.common.IRelated;
47
import eu.etaxonomy.cdm.model.common.IdentifiableEntity;
48
import eu.etaxonomy.cdm.model.common.RelationshipBase;
49
import eu.etaxonomy.cdm.model.description.TaxonNameDescription;
50
import eu.etaxonomy.cdm.model.occurrence.Specimen;
51
import eu.etaxonomy.cdm.model.reference.INomenclaturalReference;
52
import eu.etaxonomy.cdm.model.reference.ReferenceBase;
53
import eu.etaxonomy.cdm.model.reference.StrictReferenceBase;
54
import eu.etaxonomy.cdm.model.taxon.Synonym;
55
import eu.etaxonomy.cdm.model.taxon.Taxon;
56
import eu.etaxonomy.cdm.model.taxon.TaxonBase;
57
import eu.etaxonomy.cdm.strategy.cache.name.INameCacheStrategy;
58

    
59
/**
60
 * The upmost (abstract) class for scientific taxon names regardless of any
61
 * particular {@link NomenclaturalCode nomenclature code}. The scientific taxon name does not depend
62
 * on the use made of it in a publication or a treatment
63
 * ({@link eu.etaxonomy.cdm.model.taxon.TaxonBase taxon concept respectively potential taxon})
64
 * as an {@link eu.etaxonomy.cdm.model.taxon.Taxon "accepted" respectively "correct" (taxon) name}
65
 * or as a {@link eu.etaxonomy.cdm.model.taxon.Synonym synonym}.
66
 * <P>
67
 * This class corresponds partially to: <ul>
68
 * <li> TaxonName according to the TDWG ontology
69
 * <li> ScientificName and CanonicalName according to the TCS
70
 * <li> ScientificName according to the ABCD schema
71
 * </ul>
72
 * 
73
 * @author m.doering
74
 * @version 1.0
75
 * @created 08-Nov-2007 13:06:57
76
 */
77
@XmlAccessorType(XmlAccessType.FIELD)
78
@XmlType(name = "TaxonNameBase", propOrder = {
79
    "appendedPhrase",
80
    "nomenclaturalMicroReference",
81
    "nomenclaturalReference",
82
    "rank",
83
    "fullTitleCache",
84
    "protectedFullTitleCache",
85
    "homotypicalGroup",
86
    "typeDesignations",
87
    "relationsFromThisName",
88
    "relationsToThisName",
89
    "status",
90
    "descriptions",
91
    "taxonBases"
92
})
93
@XmlRootElement(name = "TaxonNameBase")
94
@Entity
95
@Audited
96
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
97
@Table(appliesTo="TaxonNameBase", indexes = { @Index(name = "taxonNameBaseTitleCacheIndex", columnNames = { "titleCache" }) })
98
public abstract class TaxonNameBase<T extends TaxonNameBase<?,?>, S extends INameCacheStrategy> extends IdentifiableEntity implements IReferencedEntity, IParsable, IRelated {
99

    
100
	private static final long serialVersionUID = -4530368639601532116L;
101
	private static final Logger logger = Logger.getLogger(TaxonNameBase.class);
102

    
103
	@XmlElement(name = "FullTitleCache")
104
	@Column(length=330, name="fullTitleCache")
105
	private String fullTitleCache;
106
	
107
	//if true titleCache will not be automatically generated/updated
108
	@XmlElement(name = "ProtectedFullTitleCache")
109
	private boolean protectedFullTitleCache;
110
	
111
    @XmlElementWrapper(name = "Descriptions")
112
    @XmlElement(name = "Description")
113
    @OneToMany(mappedBy="taxonName", fetch= FetchType.LAZY) 
114
	@Cascade({CascadeType.SAVE_UPDATE})
115
	private Set<TaxonNameDescription> descriptions = new HashSet<TaxonNameDescription>();
116
	
117
    @XmlElement(name = "AppendedPhrase")
118
    @Field(index= org.hibernate.search.annotations.Index.TOKENIZED)
119
	private String appendedPhrase;
120
	
121
    @XmlElement(name = "NomenclaturalMicroReference")
122
    @Field(index= org.hibernate.search.annotations.Index.TOKENIZED)
123
	private String nomenclaturalMicroReference;
124
	
125
    @XmlAttribute
126
	private boolean hasProblem = false;
127
	
128
    @XmlAttribute
129
    private int problemStarts = -1;
130
    
131
    @XmlAttribute
132
    private int problemEnds = -1;
133
    
134
    @XmlElementWrapper(name = "TypeDesignations")
135
    @XmlElement(name = "TypeDesignation")
136
    @XmlIDREF
137
    @XmlSchemaType(name = "IDREF")
138
    @ManyToMany(fetch = FetchType.LAZY)
139
	//TODO @Cascade({CascadeType.SAVE_UPDATE, CascadeType.DELETE_ORPHAN})
140
	@Cascade(CascadeType.SAVE_UPDATE)
141
	private Set<TypeDesignationBase> typeDesignations = new HashSet<TypeDesignationBase>();
142

    
143
    @XmlElement(name = "HomotypicalGroup")
144
    @XmlIDREF
145
    @XmlSchemaType(name = "IDREF")
146
    @ManyToOne(fetch = FetchType.LAZY)
147
	@Cascade({CascadeType.SAVE_UPDATE})
148
	private HomotypicalGroup homotypicalGroup;
149

    
150
    @XmlElementWrapper(name = "RelationsFromThisName")
151
    @XmlElement(name = "RelationFromThisName")
152
    @OneToMany(mappedBy="relatedFrom", fetch= FetchType.LAZY)
153
	//TODO @Cascade({CascadeType.SAVE_UPDATE, CascadeType.DELETE_ORPHAN}) => DELETE_ORPHAN does not work ( org.hibernate.HibernateException: Don't change the reference to a collection with cascade="all-delete-orphan": eu.etaxonomy.cdm.model.name.TaxonNameBase.relationsFromThisName)
154
	@Cascade(CascadeType.SAVE_UPDATE)
155
	private Set<NameRelationship> relationsFromThisName = new HashSet<NameRelationship>();
156

    
157
    @XmlElementWrapper(name = "RelationsToThisName")
158
    @XmlElement(name = "RelationToThisName")
159
    @XmlIDREF
160
    @XmlSchemaType(name = "IDREF")
161
    @OneToMany(mappedBy="relatedTo", fetch= FetchType.LAZY)
162
	//@Cascade({CascadeType.SAVE_UPDATE, CascadeType.DELETE_ORPHAN})
163
	@Cascade(CascadeType.SAVE_UPDATE)
164
	private Set<NameRelationship> relationsToThisName = new HashSet<NameRelationship>();
165

    
166
    @XmlElementWrapper(name = "NomenclaturalStatuses")
167
    @XmlElement(name = "NomenclaturalStatus")
168
    @OneToMany(fetch= FetchType.LAZY)
169
	@Cascade({CascadeType.SAVE_UPDATE})
170
	private Set<NomenclaturalStatus> status = new HashSet<NomenclaturalStatus>();
171

    
172
    @XmlElementWrapper(name = "TaxonBases")
173
    @XmlElement(name = "TaxonBase")
174
    @XmlIDREF
175
    @XmlSchemaType(name = "IDREF")
176
    @OneToMany(mappedBy="name", fetch= FetchType.LAZY)
177
	private Set<TaxonBase> taxonBases = new HashSet<TaxonBase>();
178
    
179
    @XmlElement(name = "Rank")
180
	@XmlIDREF
181
	@XmlSchemaType(name = "IDREF")
182
	@ManyToOne(fetch = FetchType.LAZY)
183
	private Rank rank;
184

    
185

    
186
	@XmlElement(name = "NomenclaturalReference")
187
    @XmlIDREF
188
    @XmlSchemaType(name = "IDREF")
189
    @ManyToOne(fetch = FetchType.LAZY)
190
	@Cascade({CascadeType.SAVE_UPDATE})
191
	private ReferenceBase nomenclaturalReference;
192
	
193
// ************* CONSTRUCTORS *************/	
194
	/** 
195
	 * Class constructor: creates a new empty taxon name.
196
	 * 
197
	 * @see #TaxonNameBase(Rank)
198
	 * @see #TaxonNameBase(HomotypicalGroup)
199
	 * @see #TaxonNameBase(Rank, HomotypicalGroup)
200
	 */
201
	public TaxonNameBase() {
202
		super();
203
	}
204
	/** 
205
	 * Class constructor: creates a new taxon name
206
	 * only containing its {@link Rank rank}.
207
	 * 
208
	 * @param  rank  the rank to be assigned to <i>this</i> taxon name
209
	 * @see    		 #TaxonNameBase()
210
	 * @see    		 #TaxonNameBase(HomotypicalGroup)
211
	 * @see    		 #TaxonNameBase(Rank, HomotypicalGroup)
212
	 */
213
	public TaxonNameBase(Rank rank) {
214
		this(rank, null);
215
	}
216
	/** 
217
	 * Class constructor: creates a new taxon name
218
	 * only containing its {@link HomotypicalGroup homotypical group}.
219
	 * The new taxon name will be also added to the set of taxon names
220
	 * belonging to this homotypical group.
221
	 * 
222
	 * @param  homotypicalGroup  the homotypical group to which <i>this</i> taxon name belongs
223
	 * @see    					 #TaxonNameBase()
224
	 * @see    					 #TaxonNameBase(Rank)
225
	 * @see    					 #TaxonNameBase(Rank, HomotypicalGroup)
226
	 */
227
	public TaxonNameBase(HomotypicalGroup homotypicalGroup) {
228
		this(null, homotypicalGroup);
229
	}
230
	/** 
231
	 * Class constructor: creates a new taxon name
232
	 * only containing its {@link Rank rank} and
233
	 * its {@link HomotypicalGroup homotypical group}.
234
	 * The new taxon name will be also added to the set of taxon names
235
	 * belonging to this homotypical group.
236
	 * 
237
	 * @param  rank  			 the rank to be assigned to <i>this</i> taxon name
238
	 * @param  homotypicalGroup  the homotypical group to which <i>this</i> taxon name belongs
239
	 * @see    					 #TaxonNameBase()
240
	 * @see    					 #TaxonNameBase(Rank)
241
	 * @see    					 #TaxonNameBase(HomotypicalGroup)
242
	 */
243
	public TaxonNameBase(Rank rank, HomotypicalGroup homotypicalGroup) {
244
		super();
245
		this.setRank(rank);
246
		if (homotypicalGroup == null){
247
			homotypicalGroup = new HomotypicalGroup();
248
		}
249
		homotypicalGroup.addTypifiedName(this);
250
	}
251
	
252
//********* METHODS **************************************/
253
	
254
	/**
255
	 * Returns the boolean value "false" since the components of <i>this</i> taxon name
256
	 * cannot follow the rules of a corresponding {@link NomenclaturalCode nomenclatural code}
257
	 * which is not defined for this class. The nomenclature code depends on
258
	 * the concrete name subclass ({@link BacterialName BacterialName},
259
	 * {@link BotanicalName BotanicalName}, {@link CultivarPlantName CultivarPlantName},
260
	 * {@link ZoologicalName ZoologicalName} or {@link ViralName ViralName}) 
261
	 * to which a taxon name belongs.
262
	 *  
263
	 * @return  false
264
	 */
265
	@Transient
266
	public abstract boolean isCodeCompliant();
267
	
268
	public abstract String generateFullTitle();
269

    
270
	@Transient
271
	public String getFullTitleCache(){
272
		if (protectedFullTitleCache){
273
			return this.fullTitleCache;			
274
		}
275
		if (fullTitleCache == null){
276
			this.setFullTitleCache(generateFullTitle(), protectedFullTitleCache);
277
		}
278
		return fullTitleCache;
279
	}
280

    
281
    public void setFullTitleCache(String fullTitleCache){
282
		setFullTitleCache(fullTitleCache, PROTECTED);
283
	}
284
	
285
	public void setFullTitleCache(String fullTitleCache, boolean protectCache){
286
		//TODO truncation of full title cache
287
		if (fullTitleCache != null && fullTitleCache.length() > 329){
288
			logger.warn("Truncation of full title cache: " + this.toString() + "/" + fullTitleCache);
289
			fullTitleCache = fullTitleCache.substring(0, 329) + "...";
290
		}
291
		this.fullTitleCache = fullTitleCache;
292
		this.setProtectedFullTitleCache(protectCache);
293
	}
294
	
295
	public boolean isProtectedFullTitleCache() {
296
		return protectedFullTitleCache;
297
	}
298

    
299
	public void setProtectedFullTitleCache(boolean protectedFullTitleCache) {
300
		this.protectedFullTitleCache = protectedFullTitleCache;
301
	}
302
	
303
	/** 
304
	 * Returns the set of all {@link NameRelationship name relationships}
305
	 * in which <i>this</i> taxon name is involved. A taxon name can be both source
306
	 * in some name relationships or target in some others.
307
	 *  
308
	 * @see    #getRelationsToThisName()
309
	 * @see    #getRelationsFromThisName()
310
	 * @see    #addNameRelationship(NameRelationship)
311
	 * @see    #addRelationshipToName(TaxonNameBase, NameRelationshipType, String)
312
	 * @see    #addRelationshipFromName(TaxonNameBase, NameRelationshipType, String)
313
	 */
314
	@Transient
315
	public Set<NameRelationship> getNameRelations() {
316
		Set<NameRelationship> rels = new HashSet<NameRelationship>();
317
		rels.addAll(getRelationsFromThisName());
318
		rels.addAll(getRelationsToThisName());
319
		return rels;
320
	}
321
	
322
	/**
323
	 * Creates a new {@link NameRelationship#NameRelationship(TaxonNameBase, TaxonNameBase, NameRelationshipType, String) name relationship} from <i>this</i> taxon name to another taxon name
324
	 * and adds it both to the set of {@link #getRelationsFromThisName() relations from <i>this</i> taxon name} and
325
	 * to the set of {@link #getRelationsToThisName() relations to the other taxon name}.
326
	 * 
327
	 * @param toName		  the taxon name of the target for this new name relationship
328
	 * @param type			  the type of this new name relationship
329
	 * @param ruleConsidered  the string which specifies the rule on which this name relationship is based
330
	 * @see    				  #getRelationsToThisName()
331
	 * @see    				  #getNameRelations()
332
	 * @see    				  #addRelationshipFromName(TaxonNameBase, NameRelationshipType, String)
333
	 * @see    				  #addNameRelationship(NameRelationship)
334
	 */
335
	public void addRelationshipToName(TaxonNameBase toName, NameRelationshipType type, String ruleConsidered){
336
		NameRelationship rel = new NameRelationship(toName, this, type, ruleConsidered);
337
	}
338
	/**
339
	 * Creates a new {@link NameRelationship#NameRelationship(TaxonNameBase, TaxonNameBase, NameRelationshipType, String) name relationship} from another taxon name to <i>this</i> taxon name
340
	 * and adds it both to the set of {@link #getRelationsToThisName() relations to <i>this</i> taxon name} and
341
	 * to the set of {@link #getRelationsFromThisName() relations from the other taxon name}.
342
	 * 
343
	 * @param fromName		  the taxon name of the source for this new name relationship
344
	 * @param type			  the type of this new name relationship
345
	 * @param ruleConsidered  the string which specifies the rule on which this name relationship is based
346
	 * @see    				  #getRelationsFromThisName()
347
	 * @see    				  #getNameRelations()
348
	 * @see    				  #addRelationshipToName(TaxonNameBase, NameRelationshipType, String)
349
	 * @see    				  #addNameRelationship(NameRelationship)
350
	 */
351
	public void addRelationshipFromName(TaxonNameBase fromName, NameRelationshipType type, String ruleConsidered){
352
		NameRelationship rel = new NameRelationship(this, fromName, type, ruleConsidered);
353
	}
354
	/**
355
	 * Adds an existing {@link NameRelationship name relationship} either to the set of
356
	 * {@link #getRelationsToThisName() relations to <i>this</i> taxon name} or to the set of
357
	 * {@link #getRelationsFromThisName() relations from <i>this</i> taxon name}. If neither the
358
	 * source nor the target of the name relationship match with <i>this</i> taxon name
359
	 * no addition will be carried out.
360
	 * 
361
	 * @param rel  the name relationship to be added to one of <i>this</i> taxon name's name relationships sets
362
	 * @see    	   #getNameRelations()
363
	 * @see    	   #addRelationshipToName(TaxonNameBase, NameRelationshipType, String)
364
	 * @see    	   #addRelationshipFromName(TaxonNameBase, NameRelationshipType, String)
365
	 */
366
	protected void addNameRelationship(NameRelationship rel) {
367
		if (rel!=null && rel.getToName().equals(this)){
368
			this.relationsToThisName.add(rel);
369
		}else if(rel!=null && rel.getFromName().equals(this)){
370
			this.relationsFromThisName.add(rel);			
371
		}else{
372
			//TODO: raise error???
373
		}
374
	}
375
	/** 
376
	 * Removes one {@link NameRelationship name relationship} from one of both sets of
377
	 * {@link #getNameRelations() name relationships} in which <i>this</i> taxon name is involved.
378
	 * The name relationship will also be removed from one of both sets belonging
379
	 * to the second taxon name involved. Furthermore the fromName and toName
380
	 * attributes of the name relationship object will be nullified. 
381
	 *
382
	 * @param  nameRelation  the name relationship which should be deleted from one of both sets
383
	 * @see    				 #getNameRelations()
384
	 */
385
	public void removeNameRelationship(NameRelationship nameRelation) {
386
		
387
		TaxonNameBase fromName = nameRelation.getFromName();
388
		TaxonNameBase toName = nameRelation.getToName();
389

    
390
		if (nameRelation != null) {
391
			nameRelation.setToName(null);
392
			nameRelation.setFromName(null);
393
		}
394
		
395
		if (fromName != null) {
396
			fromName.removeNameRelationship(nameRelation);
397
		}
398
		
399
		if (toName != null) {
400
			toName.removeNameRelationship(nameRelation);
401
		}
402
		
403
		this.relationsToThisName.remove(nameRelation);
404
		this.relationsFromThisName.remove(nameRelation);
405
	}
406
		
407
	public void removeTaxonName(TaxonNameBase taxonName) {
408
		Set<NameRelationship> nameRelationships = new HashSet<NameRelationship>();
409
//		nameRelationships.addAll(this.getNameRelations());
410
		nameRelationships.addAll(this.getRelationsFromThisName());
411
		nameRelationships.addAll(this.getRelationsToThisName());
412
		for(NameRelationship nameRelationship : nameRelationships) {
413
			// remove name relationship from this side 
414
			if (nameRelationship.getFromName().equals(this) && nameRelationship.getToName().equals(taxonName)) {
415
				this.removeNameRelation(nameRelationship);
416
			}
417
		}
418
	}
419
	
420
	public void removeNameRelation(NameRelationship nameRelation) {
421
		nameRelation.setToName(null);
422
	
423
		TaxonNameBase name = nameRelation.getFromName();
424
		if (name != null){
425
			nameRelation.setFromName(null);
426
			name.removeNameRelation(nameRelation);
427
		}
428
		this.relationsToThisName.remove(nameRelation);
429
		this.relationsFromThisName.remove(nameRelation);
430
	}
431
	
432
	
433
	/**
434
	 * Does exactly the same as the addNameRelationship method provided that
435
	 * the given relationship is a name relationship.
436
	 * 
437
	 * @param relation  the relationship to be added to one of <i>this</i> taxon name's name relationships sets
438
	 * @see    	   		#addNameRelationship(NameRelationship)
439
	 * @see    	   		#getNameRelations()
440
	 * @see    	   		NameRelationship
441
	 * @see    	   		eu.etaxonomy.cdm.model.common.RelationshipBase
442
	 */
443
	public void addRelationship(RelationshipBase relation) {
444
		if (relation instanceof NameRelationship){
445
			addNameRelationship((NameRelationship)relation);
446
			if (relation.getType() != null && 
447
						( relation.getType().equals(NameRelationshipType.BASIONYM()) ||
448
						  relation.getType().equals(NameRelationshipType.REPLACED_SYNONYM()) 
449
						 )){
450
				TaxonNameBase fromName = ((NameRelationship)relation).getFromName();
451
				TaxonNameBase toName = ((NameRelationship)relation).getToName();
452
				fromName.getHomotypicalGroup().merge(toName.getHomotypicalGroup());
453
			}		
454
		}else{
455
			logger.warn("Relationship not of type NameRelationship!");
456
			//TODO exception handling
457
		}
458
	}
459

    
460
	
461
	/** 
462
	 * Returns the set of all {@link NameRelationship name relationships}
463
	 * in which <i>this</i> taxon name is involved as a source.
464
	 *  
465
	 * @see    #getNameRelations()
466
	 * @see    #getRelationsToThisName()
467
	 * @see    #addRelationshipFromName(TaxonNameBase, NameRelationshipType, String)
468
	 */
469
	public Set<NameRelationship> getRelationsFromThisName() {
470
		return relationsFromThisName;
471
	}
472

    
473
	/** 
474
	 * Returns the set of all {@link NameRelationship name relationships}
475
	 * in which <i>this</i> taxon name is involved as a target.
476
	 *  
477
	 * @see    #getNameRelations()
478
	 * @see    #getRelationsFromThisName()
479
	 * @see    #addRelationshipToName(TaxonNameBase, NameRelationshipType, String)
480
	 */
481
	public Set<NameRelationship> getRelationsToThisName() {
482
		return relationsToThisName;
483
	}
484
	
485
	/** 
486
	 * Returns the set of {@link NomenclaturalStatus nomenclatural status} assigned
487
	 * to <i>this</i> taxon name according to its corresponding nomenclature code.
488
	 * This includes the {@link NomenclaturalStatusType type} of the nomenclatural status
489
	 * and the nomenclatural code rule considered.
490
	 *
491
	 * @see     NomenclaturalStatus
492
	 * @see     NomenclaturalStatusType
493
	 */
494
	public Set<NomenclaturalStatus> getStatus() {
495
		return status;
496
	}
497

    
498
	/** 
499
	 * Adds a new {@link NomenclaturalStatus nomenclatural status}
500
	 * to <i>this</i> taxon name's set of nomenclatural status.
501
	 *
502
	 * @param  nomStatus  the nomenclatural status to be added
503
	 * @see 			  #getStatus()
504
	 */
505
	public void addStatus(NomenclaturalStatus nomStatus) {
506
		this.status.add(nomStatus);
507
	}
508
	
509
	/** 
510
	 * Removes one element from the set of nomenclatural status of <i>this</i> taxon name.
511
	 * Type and ruleConsidered attributes of the nomenclatural status object
512
	 * will be nullified.
513
	 *
514
	 * @param  nomStatus  the nomenclatural status of <i>this</i> taxon name which should be deleted
515
	 * @see     		  #getStatus()
516
	 */
517
	public void removeStatus(NomenclaturalStatus nomStatus) {
518
		//TODO to be implemented?
519
		logger.warn("not yet fully implemented?");
520
		this.status.remove(nomStatus);
521
	}
522

    
523
	
524
	/**
525
	 * Indicates whether <i>this</i> taxon name is a {@link NameRelationshipType#BASIONYM() basionym}
526
	 * or a {@link NameRelationshipType#REPLACED_SYNONYM() replaced synonym}
527
	 * of any other taxon name. Returns "true", if a basionym or a replaced 
528
	 * synonym {@link NameRelationship relationship} from <i>this</i> taxon name to another taxon name exists,
529
	 * false otherwise (also in case <i>this</i> taxon name is the only one in the
530
	 * homotypical group).
531
	 */
532
	@Transient
533
	public boolean isOriginalCombination(){
534
		Set<NameRelationship> relationsFromThisName = this.getRelationsFromThisName();
535
		for (NameRelationship relation : relationsFromThisName) {
536
			if (relation.getType().equals(NameRelationshipType.BASIONYM()) ||
537
					relation.getType().equals(NameRelationshipType.REPLACED_SYNONYM())) {
538
				return true;
539
			}
540
		}
541
		return false;
542
	}
543
	
544
	/**
545
	 * Returns the taxon name which is the {@link NameRelationshipType#BASIONYM() basionym} of <i>this</i> taxon name.
546
	 * The basionym of a taxon name is its epithet-bringing synonym.
547
	 * For instance <i>Pinus abies</i> L. was published by Linnaeus and the botanist
548
	 * Karsten transferred later <i>this</i> taxon to the genus Picea. Therefore,
549
	 * <i>Pinus abies</i> L. is the basionym of the new combination <i>Picea abies</i> (L.) H. Karst.
550
	 */
551
	@Transient
552
	public T getBasionym(){
553
		//TODO: pick the right name relationships...
554
		logger.warn("get Basionym not yet implemented");
555
		return null;
556
	}
557
	/**
558
	 * Assigns a taxon name as {@link NameRelationshipType#BASIONYM() basionym} of <i>this</i> taxon name.
559
	 * The basionym {@link NameRelationship relationship} will be added to <i>this</i> taxon name
560
	 * and to the basionym. The basionym cannot have itself a basionym.
561
	 * The {@link HomotypicalGroup homotypical groups} of <i>this</i> taxon name and of the basionym
562
	 * will be {@link HomotypicalGroup#merge(HomotypicalGroup) merged}.
563
	 * 
564
	 * @param  basionym		the taxon name to be set as the basionym of <i>this</i> taxon name
565
	 * @see  				#getBasionym()
566
	 * @see  				#addBasionym(TaxonNameBase, String)
567
	 */
568
	public void addBasionym(T basionym){
569
		addBasionym(basionym, null);
570
	}
571
	/**
572
	 * Assigns a taxon name as {@link NameRelationshipType#BASIONYM() basionym} of <i>this</i> taxon name
573
	 * and keeps the nomenclatural rule considered for it. The basionym
574
	 * {@link NameRelationship relationship} will be added to <i>this</i> taxon name and to the basionym.
575
	 * The basionym cannot have itself a basionym.
576
	 * The {@link HomotypicalGroup homotypical groups} of <i>this</i> taxon name and of the basionym
577
	 * will be {@link HomotypicalGroup#merge(HomotypicalGroup) merged}.
578
	 * 
579
	 * @param  basionym			the taxon name to be set as the basionym of <i>this</i> taxon name
580
	 * @param  ruleConsidered	the string identifying the nomenclatural rule
581
	 * @see  					#getBasionym()
582
	 * @see  					#addBasionym(TaxonNameBase)
583
	 */
584
	public void addBasionym(T basionym, String ruleConsidered){
585
		if (basionym != null){
586
			basionym.addRelationshipToName(this, NameRelationshipType.BASIONYM(), ruleConsidered);
587
		}
588
	}
589
	
590
	/** 
591
	 * Removes the {@link NameRelationshipType#BASIONYM() basionym} {@link NameRelationship relationship} from the set of
592
	 * {@link #getRelationsToThisName() name relationships to} <i>this</i> taxon name. The same relationhip will be
593
	 * removed from the set of {@link #getRelationsFromThisName() name relationships from} the taxon name
594
	 * previously used as basionym.
595
	 *
596
	 * @see   #getBasionym()
597
	 * @see   #addBasionym(TaxonNameBase)
598
	 */
599
	public void removeBasionym(){
600
		//TODO implement
601
		logger.warn("not yet implemented");
602
	}
603

    
604
	/**
605
	 * Returns the {@link eu.etaxonomy.cdm.strategy.cache.name.INameCacheStrategy cache strategy} used to generate
606
	 * several strings corresponding to <i>this</i> taxon name
607
	 * (in particular taxon name caches and author strings).
608
	 * 
609
	 * @return  the cache strategy used for <i>this</i> taxon name
610
	 * @see 	eu.etaxonomy.cdm.strategy.cache.name.INameCacheStrategy
611
	 * @see     eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy
612
	 */
613
	@Transient
614
	public abstract S getCacheStrategy();
615
	/** 
616
	 * @see 	#getCacheStrategy()
617
	 */
618
	
619
	public abstract void setCacheStrategy(S cacheStrategy);
620
	
621
	/** 
622
	 * Returns the taxonomic {@link Rank rank} of <i>this</i> taxon name.
623
	 *
624
	 * @see 	Rank
625
	 */
626
	public Rank getRank(){
627
		return this.rank;
628
	}
629
	
630
	/**
631
	 * @see  #getRank()
632
	 */
633
	public void setRank(Rank rank){
634
		this.rank = rank;
635
	}
636

    
637
	/** 
638
	 * Returns the {@link eu.etaxonomy.cdm.model.reference.INomenclaturalReference nomenclatural reference} of <i>this</i> taxon name.
639
	 * The nomenclatural reference is here meant to be the one publication
640
	 * <i>this</i> taxon name was originally published in while fulfilling the formal
641
	 * requirements as specified by the corresponding {@link NomenclaturalCode nomenclatural code}.
642
	 *
643
	 * @see 	eu.etaxonomy.cdm.model.reference.INomenclaturalReference
644
	 * @see 	eu.etaxonomy.cdm.model.reference.ReferenceBase
645
	 */
646
	public ReferenceBase getNomenclaturalReference(){
647
		return this.nomenclaturalReference;
648
	}
649
	/**
650
	 * Assigns a {@link eu.etaxonomy.cdm.model.reference.INomenclaturalReference nomenclatural reference} to <i>this</i> taxon name.
651
	 * The corresponding {@link eu.etaxonomy.cdm.model.reference.ReferenceBase.isNomenclaturallyRelevant nomenclaturally relevant flag} will be set to true
652
	 * as it is obviously used for nomenclatural purposes.
653
	 *
654
	 * @throws IllegalArgumentException if parameter <code>nomenclaturalReference</code> is not assignable from {@link INomenclaturalReference}
655
	 * @see  #getNomenclaturalReference()
656
	 */
657
	public void setNomenclaturalReference(ReferenceBase nomenclaturalReference){
658
		if(nomenclaturalReference != null){
659
			if(!INomenclaturalReference.class.isAssignableFrom(nomenclaturalReference.getClass())){
660
				throw new IllegalArgumentException("Parameter nomenclaturalReference is not assignable from INomenclaturalReference");
661
			}
662
			this.nomenclaturalReference = (ReferenceBase)nomenclaturalReference;
663
		} else {
664
			this.nomenclaturalReference = null;
665
		}
666
	}
667

    
668
	/** 
669
	 * Returns the appended phrase string assigned to <i>this</i> taxon name.
670
	 * The appended phrase is a non-atomised addition to a name. It is
671
	 * not ruled by a nomenclatural code.
672
	 */
673
	public String getAppendedPhrase(){
674
		return this.appendedPhrase;
675
	}
676
	
677
	/**
678
	 * @see  #getAppendedPhrase()
679
	 */
680
	public void setAppendedPhrase(String appendedPhrase){
681
		this.appendedPhrase = appendedPhrase;
682
	}
683

    
684
	/** 
685
	 * Returns the details string of the {@link #getNomenclaturalReference() nomenclatural reference} assigned
686
	 * to <i>this</i> taxon name. The details describe the exact localisation within
687
	 * the publication used as nomenclature reference. These are mostly
688
	 * (implicitly) pages but can also be figures or tables or any other
689
	 * element of a publication. A nomenclatural micro reference (details)
690
	 * requires the existence of a nomenclatural reference.
691
	 */
692
	//Details of the nomenclatural reference (protologue). 
693
	public String getNomenclaturalMicroReference(){
694
		return this.nomenclaturalMicroReference;
695
	}
696
	/**
697
	 * @see  #getNomenclaturalMicroReference()
698
	 */
699
	public void setNomenclaturalMicroReference(String nomenclaturalMicroReference){
700
		this.nomenclaturalMicroReference = nomenclaturalMicroReference;
701
	}
702

    
703
	/* (non-Javadoc)
704
	 * @see eu.etaxonomy.cdm.model.common.IParsable#getHasProblem()
705
	 */
706
	public boolean getHasProblem(){
707
		return this.hasProblem;
708
	}
709
	
710
	/* (non-Javadoc)
711
	 * @see eu.etaxonomy.cdm.model.common.IParsable#setHasProblem(boolean)
712
	 */
713
	public void setHasProblem(boolean hasProblem){
714
		this.hasProblem = hasProblem;
715
	}
716
	
717
	/* (non-Javadoc)
718
	 * @see eu.etaxonomy.cdm.model.common.IParsable#hasProblem()
719
	 */
720
	public boolean hasProblem(){
721
		return getHasProblem();
722
	}
723
	
724
	/* (non-Javadoc)
725
	 * @see eu.etaxonomy.cdm.model.common.IParsable#problemStarts()
726
	 */
727
	public int getProblemStarts(){
728
		return this.problemStarts;
729
	}
730
	
731
	/* (non-Javadoc)
732
	 * @see eu.etaxonomy.cdm.model.common.IParsable#setProblemStarts(int)
733
	 */
734
	public void setProblemStarts(int start) {
735
		this.problemStarts = start;
736
	}
737
	
738
	/* (non-Javadoc)
739
	 * @see eu.etaxonomy.cdm.model.common.IParsable#problemEnds()
740
	 */
741
	public int getProblemEnds(){
742
		return this.problemEnds;
743
	}
744

    
745
	/* (non-Javadoc)
746
	 * @see eu.etaxonomy.cdm.model.common.IParsable#setProblemEnds(int)
747
	 */
748
	public void setProblemEnds(int end) {
749
		this.problemEnds = end;
750
	}
751

    
752
//*********************** TYPE DESIGNATION *********************************************//	
753
	
754
	/** 
755
	 * Returns the set of {@link TypeDesignationBase type designations} assigned
756
	 * to <i>this</i> taxon name.
757
	 * @see     NameTypeDesignation
758
	 * @see     SpecimenTypeDesignation
759
	 */
760
	public Set<TypeDesignationBase> getTypeDesignations() {
761
		return typeDesignations;
762
	}
763
	
764
	/** 
765
	 * Removes one element from the set of {@link TypeDesignationBase type designations} assigned to
766
	 * <i>this</i> taxon name. The type designation itself will be nullified.
767
	 *
768
	 * @param  typeDesignation  the type designation which should be deleted
769
	 */
770
	public void removeTypeDesignation(TypeDesignationBase typeDesignation) {
771
		logger.warn("not yet fully implemented: nullify the specimen type designation itself?");
772
		this.typeDesignations.remove(typeDesignation);
773
	}
774
	
775
	/** 
776
	 * Returns the set of {@link SpecimenTypeDesignation specimen type designations} assigned
777
	 * to <i>this</i> taxon name. The {@link Rank rank} of <i>this</i> taxon name is generally
778
	 * "species" or below. The specimen type designations include all the
779
	 * specimens on which the typification of this name is based (which are
780
	 * exclusively used to typify taxon names belonging to the same
781
	 * {@link HomotypicalGroup homotypical group} to which <i>this</i> taxon name
782
	 * belongs) and eventually the status of these designations.
783
	 *
784
	 * @see     SpecimenTypeDesignation
785
	 * @see     NameTypeDesignation
786
	 * @see     HomotypicalGroup
787
	 */
788
	@Transient
789
	public Set<SpecimenTypeDesignation> getSpecimenTypeDesignationsOfHomotypicalGroup() {
790
		return this.getHomotypicalGroup().getSpecimenTypeDesignations();
791
	}
792
	
793
//*********************** NAME TYPE DESIGNATION *********************************************//	
794
	
795
	/** 
796
	 * Returns the set of {@link NameTypeDesignation name type designations} assigned
797
	 * to <i>this</i> taxon name the rank of which must be above "species".
798
	 * The name type designations include all the taxon names used to typify
799
	 * <i>this</i> taxon name and eventually the rejected or conserved status
800
	 * of these designations.
801
	 *
802
	 * @see     NameTypeDesignation
803
	 * @see     SpecimenTypeDesignation
804
	 */
805
	@Transient
806
	public Set<NameTypeDesignation> getNameTypeDesignations() {
807
		Set<NameTypeDesignation> result = new HashSet<NameTypeDesignation>();
808
		for (TypeDesignationBase typeDesignation : this.typeDesignations){
809
			if (typeDesignation instanceof NameTypeDesignation){
810
				result.add((NameTypeDesignation)typeDesignation);
811
			}
812
		}
813
		return result;
814
	}
815
	
816
	/** 
817
	 * Creates and adds a new {@link NameTypeDesignation name type designation}
818
	 * to <i>this</i> taxon name's set of type designations.
819
	 *
820
	 * @param  typeSpecies				the taxon name to be used as type of <i>this</i> taxon name
821
	 * @param  citation					the reference for this new designation
822
	 * @param  citationMicroReference	the string with the details (generally pages) within the reference
823
	 * @param  originalNameString		the taxon name string used in the reference to assert this designation
824
	 * @param  isRejectedType			the boolean status for a rejected name type designation
825
	 * @param  isConservedType			the boolean status for a conserved name type designation
826
	 * @param  isLectoType				the boolean status for a lectotype name type designation
827
	 * @param  isNotDesignated			the boolean status for a name type designation without name type
828
	 * @param  addToAllHomotypicNames	the boolean indicating whether the name type designation should be
829
	 * 									added to all taxon names of the homotypical group this taxon name belongs to
830
	 * @see 			  				#getNameTypeDesignations()
831
	 * @see 			  				NameTypeDesignation
832
	 * @see 			  				TypeDesignationBase#isNotDesignated()
833
	 */
834
	public void addNameTypeDesignation(TaxonNameBase typeSpecies, 
835
				ReferenceBase citation, 
836
				String citationMicroReference, 
837
				String originalNameString, 
838
				boolean isRejectedType, 
839
				boolean isConservedType, 
840
				boolean isLectoType, 
841
				boolean isNotDesignated, 
842
				boolean addToAllHomotypicNames) {
843
		NameTypeDesignation nameTypeDesignation = new NameTypeDesignation(typeSpecies, citation, citationMicroReference, originalNameString, isRejectedType, isConservedType, isLectoType, isNotDesignated);
844
		nameTypeDesignation.setLectoType(isLectoType);
845
		addTypeDesignation(nameTypeDesignation, addToAllHomotypicNames);
846
	}
847
	
848
//*********************** SPECIMEN TYPE DESIGNATION *********************************************//	
849
	
850
	/** 
851
	 * Returns the set of {@link SpecimenTypeDesignation specimen type designations}
852
	 * that typify <i>this</i> taxon name.
853
	 */
854
	@Transient
855
	public Set<SpecimenTypeDesignation> getSpecimenTypeDesignations() {
856
		Set<SpecimenTypeDesignation> result = new HashSet<SpecimenTypeDesignation>();
857
		for (TypeDesignationBase typeDesignation : this.typeDesignations){
858
			if (typeDesignation instanceof SpecimenTypeDesignation){
859
				result.add((SpecimenTypeDesignation)typeDesignation);
860
			}
861
		}
862
		return result;
863
	}
864

    
865
	
866
	/** 
867
	 * Creates and adds a new {@link SpecimenTypeDesignation specimen type designation}
868
	 * to <i>this</i> taxon name's set of type designations.
869
	 *
870
	 * @param  typeSpecimen				the specimen to be used as a type for <i>this</i> taxon name
871
	 * @param  status					the specimen type designation status
872
	 * @param  citation					the reference for this new specimen type designation
873
	 * @param  citationMicroReference	the string with the details (generally pages) within the reference
874
	 * @param  originalNameString		the taxon name used in the reference to assert this designation
875
	 * @param  isNotDesignated			the boolean status for a specimen type designation without specimen type
876
	 * @param  addToAllHomotypicNames	the boolean indicating whether the specimen type designation should be
877
	 * 									added to all taxon names of the homotypical group the typified
878
	 * 									taxon name belongs to
879
	 * @see 			  				#getSpecimenTypeDesignations()
880
	 * @see 			  				SpecimenTypeDesignationStatus
881
	 * @see 			  				SpecimenTypeDesignation
882
	 * @see 			  				TypeDesignationBase#isNotDesignated()
883
	 */
884
	public void addSpecimenTypeDesignation(Specimen typeSpecimen, 
885
				SpecimenTypeDesignationStatus status, 
886
				ReferenceBase citation, 
887
				String citationMicroReference, 
888
				String originalNameString, 
889
				boolean isNotDesignated, 
890
				boolean addToAllHomotypicNames) {
891
		SpecimenTypeDesignation specimenTypeDesignation = new SpecimenTypeDesignation(typeSpecimen, status, citation, citationMicroReference, originalNameString, isNotDesignated);
892
		addTypeDesignation(specimenTypeDesignation, addToAllHomotypicNames);
893
	}
894
	
895
	private boolean addTypeDesignation(TypeDesignationBase typeDesignation, boolean addToAllNames){
896
		//at them moment typeDesignations are not persisted with the homotypical group
897
		//so explicit adding to the homotypical group is not necessary.
898
		if (typeDesignation != null){
899
			this.typeDesignations.add(typeDesignation);
900
			typeDesignation.addTypifiedName(this);
901
			
902
			if (addToAllNames){
903
				for (TaxonNameBase taxonName : this.getHomotypicalGroup().getTypifiedNames()){
904
					if (taxonName != this){
905
						taxonName.addTypeDesignation(typeDesignation, false);
906
					}
907
				}
908
			}
909
		}
910
		return true;
911
	}
912
	
913

    
914
	
915
//*********************** HOMOTYPICAL GROUP *********************************************//	
916

    
917
	
918
	/** 
919
	 * Returns the {@link HomotypicalGroup homotypical group} to which
920
	 * <i>this</i> taxon name belongs. A homotypical group represents all taxon names
921
	 * that share the same types.
922
	 *
923
	 * @see 	HomotypicalGroup
924
	 */
925
	
926
	public HomotypicalGroup getHomotypicalGroup() {
927
		return homotypicalGroup;
928
	}
929
	
930
	/* 
931
	 * @see #getHomotypicalGroup()
932
	 */
933
	protected void setHomotypicalGroup(HomotypicalGroup homotypicalGroup) {
934
		this.homotypicalGroup = homotypicalGroup;
935
	}
936

    
937
// *************************************************************************//
938
	
939
	/** 
940
	 * @see #getNomenclaturalReference()
941
	 */
942
	@Transient
943
	public StrictReferenceBase getCitation(){
944
		//TODO What is the purpose of this method differing from the getNomenclaturalReference method? 
945
		logger.warn("getCitation not yet implemented");
946
		return null;
947
	}
948

    
949
	/** 
950
	 * Returns the complete string containing the
951
	 * {@link eu.etaxonomy.cdm.model.reference.INomenclaturalReference#getNomenclaturalCitation() nomenclatural reference citation}
952
	 * and the {@link #getNomenclaturalMicroReference() details} assigned to <i>this</i> taxon name.
953
	 * 
954
	 * @return  the string containing the nomenclatural reference of <i>this</i> taxon name
955
	 * @see		eu.etaxonomy.cdm.model.reference.INomenclaturalReference#getNomenclaturalCitation()
956
	 * @see		#getNomenclaturalReference()
957
	 * @see		#getNomenclaturalMicroReference()
958
	 */
959
	@Transient
960
	@Deprecated
961
	public String getCitationString(){
962
		logger.warn("getCitationString not yet implemented");
963
		return null;
964
	}
965

    
966
	/** 
967
	 * Not yet implemented
968
	 */
969
	@Deprecated
970
	public String[] getProblems(){
971
		logger.warn("getProblems not yet implemented");
972
		return null;
973
	}
974

    
975
	/**
976
	 * Returns the string containing the publication date (generally only year)
977
	 * of the {@link #getNomenclaturalReference() nomenclatural reference} for <i>this</i> taxon name, null if there is
978
	 * no nomenclatural reference.
979
	 * 
980
	 * @return  the string containing the publication date of <i>this</i> taxon name
981
	 * @see		eu.etaxonomy.cdm.model.reference.INomenclaturalReference#getYear()
982
	 */
983
	@Transient
984
	public String getReferenceYear(){
985
		if (this.getNomenclaturalReference() != null ){
986
			return this.getNomenclaturalReference().getYear();
987
		}else{
988
			return null;
989
		}
990
	}
991

    
992
	/** 
993
	 * Returns the set of {@link eu.etaxonomy.cdm.model.taxon.TaxonBase taxon bases} that refer to <i>this</i> taxon name.
994
	 * In this context a taxon base means the use of a taxon name by a reference
995
	 * either as a {@link eu.etaxonomy.cdm.model.taxon.Taxon taxon} ("accepted/correct" name) or
996
	 * as a (junior) {@link eu.etaxonomy.cdm.model.taxon.Synonym synonym}.
997
	 * A taxon name can be used by several distinct {@link eu.etaxonomy.cdm.model.reference.ReferenceBase references} but only once
998
	 * within a taxonomic treatment (identified by one reference).
999
	 *
1000
	 * @see	#getTaxa()
1001
	 * @see	#getSynonyms()
1002
	 */
1003
	public Set<TaxonBase> getTaxonBases() {
1004
		return this.taxonBases;
1005
	}
1006
	
1007
	/** 
1008
	 * Adds a new {@link eu.etaxonomy.cdm.model.taxon.TaxonBase taxon base}
1009
	 * to the set of taxon bases using <i>this</i> taxon name.
1010
	 *
1011
	 * @param  taxonBase  the taxon base to be added
1012
	 * @see 			  #getTaxonBases()
1013
	 * @see 			  #removeTaxonBase(TaxonBase)
1014
	 */
1015
	//TODO protected
1016
	public void addTaxonBase(TaxonBase taxonBase){
1017
		Method method = ReflectionUtils.findMethod(TaxonBase.class, "setName", new Class[] {TaxonNameBase.class});
1018
		ReflectionUtils.makeAccessible(method);
1019
		ReflectionUtils.invokeMethod(method, taxonBase, new Object[] {this});
1020
		taxonBases.add(taxonBase);
1021
	}
1022
	/** 
1023
	 * Removes one element from the set of {@link eu.etaxonomy.cdm.model.taxon.TaxonBase taxon bases} that refer to <i>this</i> taxon name.
1024
	 *
1025
	 * @param  taxonBase	the taxon base which should be removed from the corresponding set
1026
	 * @see    				#getTaxonBases()
1027
	 * @see    				#addTaxonBase(TaxonBase)
1028
	 */
1029
	public void removeTaxonBase(TaxonBase taxonBase){
1030
		Method method = ReflectionUtils.findMethod(TaxonBase.class, "setName", new Class[] {TaxonNameBase.class});
1031
		ReflectionUtils.makeAccessible(method);
1032
		ReflectionUtils.invokeMethod(method, taxonBase, new Object[] {null});
1033
		taxonBases.remove(taxonBase);
1034
	}
1035
	
1036
	/**
1037
	 * Returns the set of {@link eu.etaxonomy.cdm.model.taxon.Taxon taxa} ("accepted/correct" names according to any
1038
	 * reference) that are based on <i>this</i> taxon name. This set is a subset of
1039
	 * the set returned by getTaxonBases(). 
1040
	 * 
1041
	 * @see	eu.etaxonomy.cdm.model.taxon.Taxon
1042
	 * @see	#getTaxonBases()
1043
	 * @see	#getSynonyms()
1044
	 */
1045
	@Transient
1046
	public Set<Taxon> getTaxa(){
1047
		Set<Taxon> result = new HashSet<Taxon>();
1048
		for (TaxonBase taxonBase : this.taxonBases){
1049
			if (taxonBase instanceof Taxon){
1050
				result.add((Taxon)taxonBase);
1051
			}
1052
		}
1053
		return result;
1054
	}
1055
	
1056
	/**
1057
	 * Returns the set of {@link eu.etaxonomy.cdm.model.taxon.Synonym (junior) synonyms} (according to any
1058
	 * reference) that are based on <i>this</i> taxon name. This set is a subset of
1059
	 * the set returned by getTaxonBases(). 
1060
	 * 
1061
	 * @see	eu.etaxonomy.cdm.model.taxon.Synonym
1062
	 * @see	#getTaxonBases()
1063
	 * @see	#getTaxa()
1064
	 */
1065
	@Transient
1066
	public Set<Synonym> getSynonyms() {
1067
		Set<Synonym> result = new HashSet<Synonym>();
1068
		for (TaxonBase taxonBase : this.taxonBases){
1069
			if (taxonBase instanceof Synonym){
1070
				result.add((Synonym)taxonBase);
1071
			}
1072
		}
1073
		return result;
1074
	}
1075
	
1076
	
1077
// *********** DESCRIPTIONS *************************************	
1078

    
1079
	/**
1080
	 * Returns the set of {@link eu.etaxonomy.cdm.model.description.TaxonNameDescription taxon name descriptions} assigned
1081
	 * to <i>this</i> taxon name. A taxon name description is a piece of information
1082
	 * concerning the taxon name like for instance the content of its first
1083
	 * publication (protolog) or a picture of this publication.
1084
	 * 
1085
	 * @see	#addDescription(TaxonNameDescription)
1086
	 * @see	#removeDescription(TaxonNameDescription)
1087
	 * @see	eu.etaxonomy.cdm.model.description.TaxonNameDescription
1088
	 */
1089
	public Set<TaxonNameDescription> getDescriptions() {
1090
		return descriptions;
1091
	}
1092

    
1093
	/** 
1094
	 * Adds a new {@link eu.etaxonomy.cdm.model.description.TaxonNameDescription taxon name description}
1095
	 * to the set of taxon name descriptions assigned to <i>this</i> taxon name. The
1096
	 * content of the {@link eu.etaxonomy.cdm.model.description.TaxonNameDescription#getTaxonName() taxonName attribute} of the
1097
	 * taxon name description itself will be replaced with <i>this</i> taxon name.
1098
	 *
1099
	 * @param  description  the taxon name description to be added
1100
	 * @see					#getDescriptions()
1101
	 * @see 			  	#removeDescription(TaxonNameDescription)
1102
	 */
1103
	public void addDescription(TaxonNameDescription description) {
1104
		java.lang.reflect.Field field = ReflectionUtils.findField(TaxonNameDescription.class, "taxonName", TaxonNameBase.class);
1105
		ReflectionUtils.makeAccessible(field);
1106
		ReflectionUtils.setField(field, description, this);
1107
		descriptions.add(description);
1108
	}
1109
	/** 
1110
	 * Removes one element from the set of {@link eu.etaxonomy.cdm.model.description.TaxonNameDescription taxon name descriptions} assigned
1111
	 * to <i>this</i> taxon name. The content of the {@link eu.etaxonomy.cdm.model.description.TaxonNameDescription#getTaxonName() taxonName attribute}
1112
	 * of the description itself will be set to "null".
1113
	 *
1114
	 * @param  description  the taxon name description which should be removed
1115
	 * @see     		  	#getDescriptions()
1116
	 * @see     		  	#addDescription(TaxonNameDescription)
1117
	 * @see 			  	eu.etaxonomy.cdm.model.description.TaxonNameDescription#getTaxonName()
1118
	 */
1119
	public void removeDescription(TaxonNameDescription description) {
1120
		java.lang.reflect.Field field = ReflectionUtils.findField(TaxonNameDescription.class, "taxonName", TaxonNameBase.class);
1121
		ReflectionUtils.makeAccessible(field);
1122
		ReflectionUtils.setField(field, description, null);
1123
		descriptions.remove(description);
1124
	}
1125
	
1126
// ***********
1127
	/**
1128
	 * Returns the boolean value indicating whether a given taxon name belongs
1129
	 * to the same {@link HomotypicalGroup homotypical group} as <i>this</i> taxon name (true)
1130
	 * or not (false). Returns "true" only if the homotypical groups of both
1131
	 * taxon names exist and if they are identical. 
1132
	 *
1133
	 * @param	homoTypicName  the taxon name the homotypical group of which is to be checked
1134
	 * @return  			   the boolean value of the check
1135
	 * @see     			   HomotypicalGroup
1136
	 */
1137
	@Transient
1138
	public boolean isHomotypic(TaxonNameBase homoTypicName) {
1139
		if (homoTypicName == null) {
1140
			return false;
1141
		}
1142
		HomotypicalGroup homotypicGroup = homoTypicName.getHomotypicalGroup();
1143
		if (homotypicGroup == null || this.getHomotypicalGroup() == null) {
1144
			return false;
1145
		}
1146
		if (homotypicGroup.equals(this.getHomotypicalGroup())) {
1147
			return true;
1148
		}
1149
		return false;
1150
	}
1151
	
1152
//*********  Rank comparison shortcuts   ********************//
1153
	/**
1154
	 * Returns the boolean value indicating whether the taxonomic {@link Rank rank} of <i>this</i>
1155
	 * taxon name is higher than the genus rank (true) or not (false).
1156
	 * Suprageneric non viral names are monomials.
1157
	 * Returns false if rank is null.
1158
	 * 
1159
	 * @see  #isGenus()
1160
	 * @see  #isInfraGeneric()
1161
	 * @see  #isSpecies()
1162
	 * @see  #isInfraSpecific()
1163
	 */
1164
	@Transient
1165
	public boolean isSupraGeneric() {
1166
		if (rank == null){
1167
			return false;
1168
		}
1169
		return getRank().isSupraGeneric();
1170
	}
1171
	/**
1172
	 * Returns the boolean value indicating whether the taxonomic {@link Rank rank} of <i>this</i>
1173
	 * taxon name is the genus rank (true) or not (false). Non viral names with
1174
	 * genus rank are monomials. Returns false if rank is null.
1175
	 *
1176
	 * @see  #isSupraGeneric()
1177
	 * @see  #isInfraGeneric()
1178
	 * @see  #isSpecies()
1179
	 * @see  #isInfraSpecific()
1180
	 */
1181
	@Transient
1182
	public boolean isGenus() {
1183
		if (rank == null){
1184
			return false;
1185
		}
1186
		return getRank().isGenus();
1187
	}
1188
	/**
1189
	 * Returns the boolean value indicating whether the taxonomic {@link Rank rank} of <i>this</i>
1190
	 * taxon name is higher than the species rank and lower than the
1191
	 * genus rank (true) or not (false). Infrageneric non viral names are
1192
	 * binomials. Returns false if rank is null.
1193
	 *
1194
	 * @see  #isSupraGeneric()
1195
	 * @see  #isGenus()
1196
	 * @see  #isSpecies()
1197
	 * @see  #isInfraSpecific()
1198
	 */
1199
	@Transient
1200
	public boolean isInfraGeneric() {
1201
		if (rank == null){
1202
			return false;
1203
		}
1204
		return getRank().isInfraGeneric();
1205
	}
1206
	/**
1207
	 * Returns the boolean value indicating whether the taxonomic {@link Rank rank} of <i>this</i>
1208
	 * taxon name is the species rank (true) or not (false). Non viral names
1209
	 * with species rank are binomials.
1210
	 * Returns false if rank is null.
1211
	 *
1212
	 * @see  #isSupraGeneric()
1213
	 * @see  #isGenus()
1214
	 * @see  #isInfraGeneric()
1215
	 * @see  #isInfraSpecific()
1216
	 */
1217
	@Transient
1218
	public boolean isSpecies() {
1219
		if (rank == null){
1220
			return false;
1221
		}
1222
		return getRank().isSpecies();
1223
	}
1224
	/**
1225
	 * Returns the boolean value indicating whether the taxonomic {@link Rank rank} of <i>this</i>
1226
	 * taxon name is lower than the species rank (true) or not (false).
1227
	 * Infraspecific non viral names are trinomials.
1228
	 * Returns false if rank is null.
1229
	 *
1230
	 * @see  #isSupraGeneric()
1231
	 * @see  #isGenus()
1232
	 * @see  #isInfraGeneric()
1233
	 * @see  #isSpecies()
1234
	 */
1235
	@Transient
1236
	public boolean isInfraSpecific() {
1237
		if (rank == null){
1238
			return false;
1239
		}
1240
		return getRank().isInfraSpecific();
1241
	}
1242
	
1243
	
1244
	/**
1245
	 * Returns null as the {@link NomenclaturalCode nomenclatural code} that governs
1246
	 * the construction of <i>this</i> taxon name since there is no specific
1247
	 * nomenclatural code defined. The real implementention takes place in the
1248
	 * subclasses {@link ViralName ViralName}, {@link BacterialName BacterialName},
1249
	 * {@link BotanicalName BotanicalName}, {@link CultivarPlantName CultivarPlantName} and
1250
	 * {@link ZoologicalName ZoologicalName}. Each taxon name is governed by one
1251
	 * and only one nomenclatural code. 
1252
	 *
1253
	 * @return  null
1254
	 * @see  	#isCodeCompliant()
1255
	 * @see  	#getHasProblem()
1256
	 */
1257
	abstract public NomenclaturalCode getNomenclaturalCode();
1258
	/* (non-Javadoc)
1259
	 * @see eu.etaxonomy.cdm.model.common.IdentifiableEntity#generateTitle()
1260
	 */
1261
	/**
1262
	 * Generates and returns the string with the scientific name of <i>this</i>
1263
	 * taxon name (only non viral taxon names can be generated from their
1264
	 * components). This string may be stored in the inherited
1265
	 * {@link eu.etaxonomy.cdm.model.common.IdentifiableEntity#getTitleCache() titleCache} attribute.
1266
	 * This method overrides the generic and inherited
1267
	 * {@link eu.etaxonomy.cdm.model.common.IdentifiableEntity#generateTitle() method} from
1268
	 * {@link eu.etaxonomy.cdm.model.common.IdentifiableEntity IdentifiableEntity}.
1269
	 *
1270
	 * @return  the string with the composed name of this non viral taxon name with authorship (and maybe year)
1271
	 * @see  	eu.etaxonomy.cdm.model.common.IdentifiableEntity#generateTitle()
1272
	 * @see  	eu.etaxonomy.cdm.model.common.IdentifiableEntity#getTitleCache()
1273
	 */
1274
	@Override
1275
	public String generateTitle() {
1276
		// TODO Auto-generated method stub
1277
		logger.warn("not yet implemented");
1278
		return null;
1279
	}	
1280
}
(19-19/25)