root/trunk/cdmlib/cdmlib-model/src/main/java/eu/etaxonomy/cdm/model/taxon/Taxon.java

Revision 13569, 81.5 kB (checked in by a.kohlbecker, 5 months ago)

lucene search: multi instance configuration fixed, native lucene search, ....

  • Property svn:keywords set to Id
Line 
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
10package eu.etaxonomy.cdm.model.taxon;
11
12
13import java.lang.reflect.Field;
14import java.util.ArrayList;
15import java.util.Collections;
16import java.util.HashMap;
17import java.util.HashSet;
18import java.util.List;
19import java.util.Map;
20import java.util.Set;
21
22import javax.persistence.Entity;
23import javax.persistence.FetchType;
24import javax.persistence.ManyToOne;
25import javax.persistence.OneToMany;
26import javax.persistence.Transient;
27import javax.validation.Valid;
28import javax.validation.constraints.NotNull;
29import javax.xml.bind.annotation.XmlAccessType;
30import javax.xml.bind.annotation.XmlAccessorType;
31import javax.xml.bind.annotation.XmlAttribute;
32import javax.xml.bind.annotation.XmlElement;
33import javax.xml.bind.annotation.XmlElementWrapper;
34import javax.xml.bind.annotation.XmlIDREF;
35import javax.xml.bind.annotation.XmlRootElement;
36import javax.xml.bind.annotation.XmlSchemaType;
37import javax.xml.bind.annotation.XmlType;
38
39import org.apache.log4j.Logger;
40import org.hibernate.annotations.Cascade;
41import org.hibernate.annotations.CascadeType;
42import org.hibernate.envers.Audited;
43import org.hibernate.search.annotations.ContainedIn;
44import org.hibernate.search.annotations.Indexed;
45import org.springframework.beans.factory.annotation.Configurable;
46import org.springframework.util.ReflectionUtils;
47
48import eu.etaxonomy.cdm.model.common.IRelated;
49import eu.etaxonomy.cdm.model.common.RelationshipBase;
50import eu.etaxonomy.cdm.model.description.TaxonDescription;
51import eu.etaxonomy.cdm.model.name.HomotypicalGroup;
52import eu.etaxonomy.cdm.model.name.TaxonNameBase;
53import eu.etaxonomy.cdm.model.reference.Reference;
54import eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy;
55import eu.etaxonomy.cdm.strategy.cache.taxon.TaxonBaseDefaultCacheStrategy;
56
57/**
58 * The class for "accepted/correct" {@link TaxonBase taxa} (only these taxa according to
59 * the opinion of the {@link eu.etaxonomy.cdm.model.reference.Reference reference} can build a classification).
60 * An {@link java.lang.Iterable interface} is supported to iterate through taxonomic children.<BR>
61 * Splitting taxa in "accepted/correct" and {@link Synonym "synonyms"} makes it easier to handle
62 * particular relationships between ("accepted/correct") taxa on the one hand
63 * and between ("synonym") taxa and ("accepted/correct") taxa on the other.
64 *
65 * @author m.doering
66 * @version 1.0
67 * @created 08-Nov-2007 13:06:56
68 */
69@XmlAccessorType(XmlAccessType.FIELD)
70@XmlType(name = "Taxon", propOrder = {
71    "taxonomicParentCache",
72    "taxonNodes",
73    "taxonomicChildrenCount",
74    "synonymRelations",
75    "relationsFromThisTaxon",
76    "relationsToThisTaxon",
77    "descriptions"
78})
79@XmlRootElement(name = "Taxon")
80@Entity
81@Indexed(index = "eu.etaxonomy.cdm.model.taxon.TaxonBase")
82@Audited
83@Configurable
84public class Taxon extends TaxonBase<IIdentifiableEntityCacheStrategy<Taxon>> implements IRelated<RelationshipBase>, Cloneable{
85    private static final long serialVersionUID = -584946869762749006L;
86    private static final Logger logger = Logger.getLogger(Taxon.class);
87
88    @XmlElementWrapper(name = "Descriptions")
89    @XmlElement(name = "Description")
90    @OneToMany(mappedBy="taxon", fetch= FetchType.LAZY)
91    @Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE})
92    @NotNull
93    @ContainedIn
94    private Set<TaxonDescription> descriptions = new HashSet<TaxonDescription>();
95
96    // all related synonyms
97    @XmlElementWrapper(name = "SynonymRelations")
98    @XmlElement(name = "SynonymRelationship")
99    @OneToMany(mappedBy="relatedTo", fetch=FetchType.LAZY)
100    @Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE, CascadeType.DELETE, CascadeType.DELETE_ORPHAN})
101    @NotNull
102    @Valid
103    private Set<SynonymRelationship> synonymRelations = new HashSet<SynonymRelationship>();
104
105    // all taxa relations with rel.fromTaxon==this
106    @XmlElementWrapper(name = "RelationsFromThisTaxon")
107    @XmlElement(name = "FromThisTaxonRelationship")
108    @OneToMany(mappedBy="relatedFrom", fetch=FetchType.LAZY)
109    @Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE, CascadeType.DELETE, CascadeType.DELETE_ORPHAN})
110    @NotNull
111    @Valid
112    private Set<TaxonRelationship> relationsFromThisTaxon = new HashSet<TaxonRelationship>();
113
114    // all taxa relations with rel.toTaxon==this
115    @XmlElementWrapper(name = "RelationsToThisTaxon")
116    @XmlElement(name = "ToThisTaxonRelationship")
117    @XmlIDREF
118    @XmlSchemaType(name = "IDREF")
119    @OneToMany(mappedBy="relatedTo", fetch=FetchType.LAZY)
120    @Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE, CascadeType.DELETE, CascadeType.DELETE_ORPHAN})
121    @NotNull
122    @Valid
123    private Set<TaxonRelationship> relationsToThisTaxon = new HashSet<TaxonRelationship>();
124
125    @XmlAttribute(name= "taxonStatusUnknown")
126    private boolean taxonStatusUnknown = false;
127
128    @XmlAttribute(name= "unplaced")
129    private boolean unplaced = false;
130
131    @XmlAttribute(name= "excluded")
132    private boolean excluded = false;
133
134    // shortcut to the taxonomicIncluded (parent) taxon. Managed by the taxonRelations setter
135    @XmlElement(name = "TaxonomicParentCache")
136    @XmlIDREF
137    @XmlSchemaType(name = "IDREF")
138    @ManyToOne(fetch = FetchType.LAZY)
139    @Deprecated //will be removed in future versions. Use Classification/TaxonNode instead
140    private Taxon taxonomicParentCache;
141
142
143
144    @XmlElementWrapper(name = "taxonNodes")
145    @XmlElement(name = "taxonNode")
146    @XmlIDREF
147    @XmlSchemaType(name = "IDREF")
148    @OneToMany(mappedBy="taxon", fetch=FetchType.LAZY)
149    @Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE})
150    private Set<TaxonNode> taxonNodes = new HashSet<TaxonNode>();
151
152    //cached number of taxonomic children
153    @XmlElement(name = "TaxonomicChildrenCount")
154    @Deprecated //will be removed in future versions. Use Classification/TaxonNode instead
155    private int taxonomicChildrenCount;
156
157// ************* CONSTRUCTORS *************/
158
159    //TODO should be private, but still produces Spring init errors
160    @Deprecated
161    public Taxon(){
162        this.cacheStrategy = new TaxonBaseDefaultCacheStrategy<Taxon>();
163    }
164
165    /**
166     * Class constructor: creates a new (accepted/correct) taxon instance with
167     * the {@link eu.etaxonomy.cdm.model.name.TaxonNameBase taxon name} used and the {@link eu.etaxonomy.cdm.model.reference.Reference reference}
168     * using it.
169     *
170     * @param  taxonNameBase    the taxon name used
171     * @param  sec                              the reference using the taxon name
172     * @see                                     TaxonBase#TaxonBase(TaxonNameBase, Reference)
173     */
174    public Taxon(TaxonNameBase taxonNameBase, Reference sec){
175        super(taxonNameBase, sec);
176        this.cacheStrategy = new TaxonBaseDefaultCacheStrategy<Taxon>();
177    }
178
179//********* METHODS **************************************/
180
181    /**
182     * Creates a new (accepted/correct) taxon instance with
183     * the {@link eu.etaxonomy.cdm.model.name.TaxonNameBase taxon name} used and the {@link eu.etaxonomy.cdm.model.reference.Reference reference}
184     * using it.
185     *
186     * @param  taxonNameBase    the taxon name used
187     * @param  sec                              the reference using the taxon name
188     * @see                                     #Taxon(TaxonNameBase, Reference)
189     */
190    public static Taxon NewInstance(TaxonNameBase taxonNameBase, Reference sec){
191        Taxon result = new Taxon(taxonNameBase, sec);
192        return result;
193    }
194
195    /**
196     * Creates a new taxon instance with an unknown status (accepted/synonym) and with
197     * the {@link eu.etaxonomy.cdm.model.name.TaxonNameBase taxon name} used and the {@link eu.etaxonomy.cdm.model.reference.Reference reference}
198     * using it.
199     *
200     * @param  taxonNameBase    the taxon name used
201     * @param  sec                              the reference using the taxon name
202     * @see                                     #Taxon(TaxonNameBase, Reference)
203     */
204    public static Taxon NewUnknownStatusInstance(TaxonNameBase taxonNameBase, Reference sec){
205        Taxon result = new Taxon(taxonNameBase, sec);
206        result.setTaxonStatusUnknown(true);
207        return result;
208    }
209
210    /**
211     * Returns the set of {@link eu.etaxonomy.cdm.model.description.TaxonDescription taxon descriptions}
212     * concerning <i>this</i> taxon.
213     *
214     * @see #removeDescription(TaxonDescription)
215     * @see #addDescription(TaxonDescription)
216     * @see eu.etaxonomy.cdm.model.description.TaxonDescription#getTaxon()
217     */
218    public Set<TaxonDescription> getDescriptions() {
219        if(descriptions == null) {
220            descriptions = new HashSet<TaxonDescription>();
221        }
222        return descriptions;
223    }
224
225    /**
226     * Adds a new {@link eu.etaxonomy.cdm.model.description.TaxonDescription taxon description} to the set
227     * of taxon descriptions assigned to <i>this</i> (accepted/correct) taxon.
228     * Due to bidirectionality the content of the {@link eu.etaxonomy.cdm.model.description.TaxonDescription#getTaxon() taxon attribute} of the
229     * taxon description itself will be replaced with <i>this</i> taxon. The taxon
230     * description will also be removed from the set of taxon descriptions
231     * assigned to its previous taxon.
232     *
233     * @param  description      the taxon description to be added for <i>this</i> taxon
234     * @see                             #getDescriptions()
235     * @see                             #removeDescription(TaxonDescription)
236     * @see                             eu.etaxonomy.cdm.model.description.TaxonDescription#getTaxon()
237     */
238    public void addDescription(TaxonDescription description) {
239        if (description.getTaxon() != null){
240            description.getTaxon().removeDescription(description);
241        }
242        Field field = ReflectionUtils.findField(TaxonDescription.class, "taxon", Taxon.class);
243        ReflectionUtils.makeAccessible(field);
244        ReflectionUtils.setField(field, description, this);
245        descriptions.add(description);
246
247    }
248    /**
249     * Removes one element from the set of {@link eu.etaxonomy.cdm.model.description.TaxonDescription taxon descriptions} assigned
250     * to <i>this</i> (accepted/correct) taxon. Due to bidirectionality the content of
251     * the {@link eu.etaxonomy.cdm.model.description.TaxonDescription#getTaxon() taxon attribute} of the taxon description
252     * itself will be set to "null".
253     *
254     * @param  description  the taxon description which should be removed
255     * @see                             #getDescriptions()
256     * @see                             #addDescription(TaxonDescription)
257     * @see                             eu.etaxonomy.cdm.model.description.TaxonDescription#getTaxon()
258     */
259    public void removeDescription(TaxonDescription description) {
260        //description.setTaxon(null) for not visible method
261        Field field = ReflectionUtils.findField(TaxonDescription.class, "taxon", Taxon.class);
262        ReflectionUtils.makeAccessible(field);
263        ReflectionUtils.setField(field, description, null);
264        descriptions.remove(description);
265    }
266
267    /**
268     * Returns the image gallery for a taxon. If there are multiple taxon descriptions
269     * marked as image galleries an arbitrary one is chosen.
270     * If no image gallery exists, a new one is created if <code>createNewIfNotExists</code>
271     * is <code>true</code>.
272     * @param createNewIfNotExists
273     * @return
274     */
275    public TaxonDescription getImageGallery(boolean createNewIfNotExists) {
276        TaxonDescription result = null;
277        Set<TaxonDescription> descriptions= getDescriptions();
278        for (TaxonDescription description : descriptions){
279            if (description.isImageGallery()){
280                result = description;
281                break;
282            }
283        }
284        if (result == null && createNewIfNotExists){
285            result = TaxonDescription.NewInstance(this);
286            result.setImageGallery(true);
287        }
288        return result;
289    }
290
291
292
293    public Set<TaxonNode> getTaxonNodes() {
294        return taxonNodes;
295    }
296    //  protected void setTaxonNodes(Set<TaxonNode> taxonNodes) {
297//              this.taxonNodes = taxonNodes;
298//      }
299    protected void addTaxonNode(TaxonNode taxonNode){
300        taxonNodes.add(taxonNode);
301    }
302    protected void removeTaxonNode(TaxonNode taxonNode){
303        taxonNodes.remove(taxonNode);
304    }
305
306
307
308
309    /**
310     * Returns the set of all {@link SynonymRelationship synonym relationships}
311     * in which <i>this</i> ("accepted/correct") taxon is involved. <i>This</i> taxon can only
312     * be the target of these synonym relationships.
313     *
314     * @see    #addSynonymRelation(SynonymRelationship)
315     * @see    #removeSynonymRelation(SynonymRelationship)
316     * @see    #getSynonyms()
317     */
318    public Set<SynonymRelationship> getSynonymRelations() {
319        if(synonymRelations == null) {
320            this.synonymRelations = new HashSet<SynonymRelationship>();
321        }
322        return synonymRelations;
323    }
324
325    /**
326     * Adds an existing {@link SynonymRelationship synonym relationship} to the set of
327     * {@link #getSynonymRelations() synonym relationships} assigned to <i>this</i> taxon. If
328     * the target of the synonym relationship does not match with <i>this</i> taxon
329     * no addition will be carried out.
330     *
331     * @param synonymRelation   the synonym relationship to be added to <i>this</i> taxon's
332     *                                                  synonym relationships set
333     * @see                                     #getSynonymRelations()
334     * @see                                     #addSynonym(Synonym, SynonymRelationshipType)
335     * @see                                     #addSynonym(Synonym, SynonymRelationshipType, Reference, String)
336     * @see                                     #addSynonymName(TaxonNameBase, SynonymRelationshipType)
337     * @see                                     #addSynonymName(TaxonNameBase, SynonymRelationshipType, Reference, String)
338     */
339    protected void addSynonymRelation(SynonymRelationship synonymRelation) {
340        this.synonymRelations.add(synonymRelation);
341    }
342    /**
343     * Removes one element from the set of {@link SynonymRelationship synonym relationships} assigned
344     * to <i>this</i> (accepted/correct) taxon. Due to bidirectionality the given
345     * synonym relationship will also be removed from the set of synonym
346     * relationships assigned to the {@link Synonym#getSynonymRelations() synonym} involved in the
347     * relationship. Furthermore the content of
348     * the {@link SynonymRelationship#getAcceptedTaxon() accepted taxon} attribute and of the
349     * {@link SynonymRelationship#getSynonym() synonym} attribute within the synonym relationship
350     * itself will be set to "null".
351     *
352     * @param synonymRelation   the synonym relationship which should be deleted
353     * @param removeSynonymNameFromHomotypicalGroup
354     *                          if <code>true</code> the synonym name will also be deleted from its homotypical group if the
355     *                          group contains other names
356     * @see     #getSynonymRelations()
357     * @see     #addSynonymRelation(SynonymRelationship)
358     * @see     #removeSynonym(Synonym)
359     */
360    public void removeSynonymRelation(SynonymRelationship synonymRelation, boolean removeSynonymNameFromHomotypicalGroup) {
361        synonymRelation.setAcceptedTaxon(null);
362        Synonym synonym = synonymRelation.getSynonym();
363        if (synonym != null){
364            synonymRelation.setSynonym(null);
365            synonym.removeSynonymRelation(synonymRelation);
366            if(removeSynonymNameFromHomotypicalGroup){
367                HomotypicalGroup synHG = synonym.getName().getHomotypicalGroup();
368                if (synHG.getTypifiedNames().size() > 1){
369                    synHG.removeTypifiedName(synonym.getName());
370                }
371            }
372        }
373        this.synonymRelations.remove(synonymRelation);
374    }
375
376    /**
377     * Like {@link Taxon#removeSynonymRelation(SynonymRelationship, boolean)} but synonym name
378     * will be deleted from homotypical group by default
379     *
380     * @param synonymRelation   the synonym relationship which should be deleted
381     *
382     * @see                                     #removeSynonymRelation(SynonymRelationship, boolean)
383     */
384    public void removeSynonymRelation(SynonymRelationship synonymRelation){
385        removeSynonymRelation(synonymRelation, true);
386    }
387
388
389    /**
390     * Returns the set of all {@link TaxonRelationship taxon relationships}
391     * between two taxa in which <i>this</i> taxon is involved as a source.
392     *
393     * @see    #getRelationsToThisTaxon()
394     * @see    #getTaxonRelations()
395     */
396    public Set<TaxonRelationship> getRelationsFromThisTaxon() {
397        if(relationsFromThisTaxon == null) {
398            this.relationsFromThisTaxon = new HashSet<TaxonRelationship>();
399        }
400        return relationsFromThisTaxon;
401    }
402
403
404    /**
405     * Returns the set of all {@link TaxonRelationship taxon relationships}
406     * between two taxa in which <i>this</i> taxon is involved as a target.
407     *
408     * @see    #getRelationsFromThisTaxon()
409     * @see    #getTaxonRelations()
410     */
411    public Set<TaxonRelationship> getRelationsToThisTaxon() {
412        if(relationsToThisTaxon == null) {
413            this.relationsToThisTaxon = new HashSet<TaxonRelationship>();
414        }
415        return relationsToThisTaxon;
416    }
417    /**
418     * @see    #getRelationsToThisTaxon()
419     */
420    protected void setRelationsToThisTaxon(Set<TaxonRelationship> relationsToThisTaxon) {
421        this.relationsToThisTaxon = relationsToThisTaxon;
422    }
423
424    /**
425     * @see    #getRelationsFromThisTaxon()
426     */
427    protected void setRelationsFromThisTaxon(Set<TaxonRelationship> relationsFromThisTaxon) {
428        this.relationsFromThisTaxon = relationsFromThisTaxon;
429    }
430
431    /**
432     * Returns the set of all {@link TaxonRelationship taxon relationships}
433     * between two taxa in which <i>this</i> taxon is involved either as a source or
434     * as a target.
435     *
436     * @see    #getRelationsFromThisTaxon()
437     * @see    #getRelationsToThisTaxon()
438     */
439    @Transient
440    public Set<TaxonRelationship> getTaxonRelations() {
441        Set<TaxonRelationship> rels = new HashSet<TaxonRelationship>();
442        rels.addAll(getRelationsToThisTaxon());
443        rels.addAll(getRelationsFromThisTaxon());
444        return rels;
445    }
446
447    /**
448     * If a relationships between <i>this</i> and the given taxon exists they will be returned.
449     * <i>This</i> taxon is involved either as a source or as a target in the relationships.
450     * The method will return <code>null</code> if no relations exist between the two taxa.
451     *
452     * @param possiblyRelatedTaxon
453     *                  a taxon to check for a relationship
454     * @return
455     *                  a set of <code>TaxonRelationship</code>s or <code>null</null> if none exists.
456     */
457    public Set<TaxonRelationship> getTaxonRelations(Taxon possiblyRelatedTaxon){
458        Set<TaxonRelationship> relations = new HashSet<TaxonRelationship>();
459
460        for(TaxonRelationship relationship : getTaxonRelations()){
461            if(relationship.getFromTaxon().equals(possiblyRelatedTaxon))
462                relations.add(relationship);
463            if(relationship.getToTaxon().equals(possiblyRelatedTaxon))
464                relations.add(relationship);
465        }
466
467        return relations.size() > 0 ? relations : null;
468    }
469
470    /**
471     * Removes one {@link TaxonRelationship taxon relationship} from one of both sets of
472     * {@link #getTaxonRelations() taxon relationships} in which <i>this</i> taxon is involved
473     * either as a {@link #getRelationsFromThisTaxon() source} or as a {@link #getRelationsToThisTaxon() target}.
474     * The taxon relationship will also be removed from one of both sets
475     * belonging to the second taxon involved. Furthermore the inherited RelatedFrom and
476     * RelatedTo attributes of the given taxon relationship will be nullified.<P>
477     * If the taxon relationship concerns the classification possible
478     * modifications of the {@link #getTaxonomicParent() parent taxon} or of the number of
479     * {@link #getTaxonomicChildrenCount() childrens} will be stored.
480     *
481     * @param  rel  the taxon relationship which should be removed from one
482     *                          of both sets
483     * @see             #getTaxonRelations()
484     * @see         #getTaxonomicParent()
485     * @see         #getTaxonomicChildrenCount()
486     * @see             eu.etaxonomy.cdm.model.common.RelationshipBase#getRelatedFrom()
487     * @see             eu.etaxonomy.cdm.model.common.RelationshipBase#getRelatedTo()
488     *
489     */
490    public void removeTaxonRelation(TaxonRelationship rel) {
491        this.relationsToThisTaxon.remove(rel);
492        this.relationsFromThisTaxon.remove(rel);
493        Taxon fromTaxon = rel.getFromTaxon();
494        Taxon toTaxon = rel.getToTaxon();
495        // check if this removes the taxonomical parent. If so, also remove shortcut to the higher taxon
496        if (rel.getType().equals(TaxonRelationshipType.TAXONOMICALLY_INCLUDED_IN()) ){
497            if (fromTaxon != null && fromTaxon.equals(this)){
498                this.taxonomicParentCache = null;
499            }else if (toTaxon != null && toTaxon.equals(this)){
500                this.setTaxonomicChildrenCount(computeTaxonomicChildrenCount());
501            }
502        }
503        //delete Relationship from other related Taxon
504        if (fromTaxon != null && fromTaxon != this){
505            rel.setToTaxon(null);  //remove this Taxon from relationship
506            fromTaxon.removeTaxonRelation(rel);
507        }
508        if (toTaxon != null && toTaxon != this){
509            rel.setFromTaxon(null); //remove this Taxon from relationship
510            toTaxon.removeTaxonRelation(rel);
511        }
512    }
513
514    /**
515     * Adds an existing {@link TaxonRelationship taxon relationship} either to the set of
516     * {@link #getRelationsToThisTaxon() taxon relationships to <i>this</i> taxon} or to the set of
517     * {@link #getRelationsFromThisTaxon() taxon relationships from <i>this</i> taxon}. If neither the
518     * source nor the target of the taxon relationship match with <i>this</i> taxon
519     * no addition will be carried out. The taxon relationship will also be
520     * added to the second taxon involved in the given relationship.<P>
521     * If the taxon relationship concerns the classification possible
522     * modifications of the {@link #getTaxonomicParent() parent taxon} or of the number of
523     * {@link #getTaxonomicChildrenCount() childrens} will be stored.
524     *
525     * @param rel  the taxon relationship to be added to one of <i>this</i> taxon's taxon relationships sets
526     * @see        #addTaxonRelation(Taxon, TaxonRelationshipType, Reference, String)
527     * @see        #getTaxonRelations()
528     * @see        #getRelationsFromThisTaxon()
529     * @see        #getRelationsToThisTaxon()
530     * @see        #getTaxonomicParent()
531     * @see        #getTaxonomicChildrenCount()
532     */
533    public void addTaxonRelation(TaxonRelationship rel) {
534        if (rel!=null && rel.getType()!=null && !getTaxonRelations().contains(rel) ){
535            Taxon toTaxon=rel.getToTaxon();
536            Taxon fromTaxon=rel.getFromTaxon();
537            if ( this.equals(toTaxon) || this.equals(fromTaxon) ){
538                if (this.equals(fromTaxon)){
539                    relationsFromThisTaxon.add(rel);
540                    // also add relation to other taxon object
541                    if (toTaxon!=null){
542                        toTaxon.addTaxonRelation(rel);
543                    }
544                    // check if this sets the taxonomical parent. If so, remember a shortcut to this taxon
545                    if (rel.getType().equals(TaxonRelationshipType.TAXONOMICALLY_INCLUDED_IN()) && toTaxon!=null ){
546                        this.taxonomicParentCache = toTaxon;
547                    }
548                }else if (this.equals(toTaxon)){
549                    relationsToThisTaxon.add(rel);
550                    // also add relation to other taxon object
551                    if (fromTaxon!=null){
552                        fromTaxon.addTaxonRelation(rel);
553                    }
554                    if (rel.getType().equals(TaxonRelationshipType.TAXONOMICALLY_INCLUDED_IN()) && fromTaxon!=null ){
555                        this.taxonomicChildrenCount++;
556                    }
557
558                }
559            }else if (toTaxon == null || fromTaxon == null){
560                if (toTaxon == null){
561                    toTaxon = this;
562                    relationsToThisTaxon.add(rel);
563                    if (fromTaxon!= null){
564                        fromTaxon.addTaxonRelation(rel);
565                    }
566                    if (rel.getType().equals(TaxonRelationshipType.TAXONOMICALLY_INCLUDED_IN()) && fromTaxon!=null ){
567                        this.taxonomicChildrenCount++;
568                    }
569                }else if (fromTaxon == null && toTaxon != null){
570                    fromTaxon = this;
571                    relationsFromThisTaxon.add(rel);
572                    if (toTaxon!=null){
573                        toTaxon.addTaxonRelation(rel);
574                    }
575                    if (rel.getType().equals(TaxonRelationshipType.TAXONOMICALLY_INCLUDED_IN()) && toTaxon!=null ){
576                        this.taxonomicParentCache = toTaxon;
577                    }
578                }
579            }
580        }
581    }
582
583    /* (non-Javadoc)
584     * @see eu.etaxonomy.cdm.model.common.IRelated#addRelationship(eu.etaxonomy.cdm.model.common.RelationshipBase)
585     */
586    @Deprecated //for inner use by RelationshipBase only
587    public void addRelationship(RelationshipBase rel){
588        if (rel instanceof TaxonRelationship){
589            addTaxonRelation((TaxonRelationship)rel);
590        }else if (rel instanceof SynonymRelationship){
591            addSynonymRelation((SynonymRelationship)rel);
592        }else{
593            throw new ClassCastException("Wrong Relationsship type for Taxon.addRelationship");
594        }
595    }
596
597    /**
598     * Creates a new {@link TaxonRelationship taxon relationship} instance where <i>this</i> taxon
599     * plays the source role and adds it to the set of
600     * {@link #getRelationsFromThisTaxon() "taxon relationships from"} belonging to <i>this</i> taxon.
601     * The taxon relationship will also be added to the set of taxon
602     * relationships to the second taxon involved in the created relationship.<P>
603     * If the taxon relationship concerns the classification possible
604     * modifications of the {@link #getTaxonomicParent() parent taxon} or of the number of
605     * {@link #getTaxonomicChildrenCount() childrens} will be stored.
606     *
607     * @param toTaxon           the taxon which plays the target role in the new taxon relationship
608     * @param type                      the taxon relationship type for the new taxon relationship
609     * @param citation          the reference source for the new taxon relationship
610     * @param microcitation     the string with the details describing the exact localisation within the reference
611     * @return
612     * @see                             #addTaxonRelation(TaxonRelationship)
613     * @see                             #getTaxonRelations()
614     * @see                             #getRelationsFromThisTaxon()
615     * @see                             #getRelationsToThisTaxon()
616     * @see                             #getTaxonomicParent()
617     * @see                             #getTaxonomicChildrenCount()
618     */
619    public TaxonRelationship addTaxonRelation(Taxon toTaxon, TaxonRelationshipType type, Reference citation, String microcitation) {
620        return new TaxonRelationship(this, toTaxon, type, citation, microcitation);
621    }
622    /**
623     * Creates a new {@link TaxonRelationship taxon relationship} (with {@link TaxonRelationshipType taxon relationship type}
624     * "misapplied name for") instance where <i>this</i> taxon plays the target role
625     * and adds it to the set of {@link #getRelationsToThisTaxon() taxon relationships to <i>this</i> taxon}.
626     * The taxon relationship will also be added to the set of taxon
627     * relationships to the other (misapplied name) taxon involved in the created relationship.
628     *
629     * @param misappliedNameTaxon       the taxon which plays the target role in the new taxon relationship
630     * @param citation                          the reference source for the new taxon relationship
631     * @param microcitation                     the string with the details describing the exact localisation within the reference
632     * @return
633     * @see                                             #getMisappliedNames()
634     * @see                                             #addTaxonRelation(Taxon, TaxonRelationshipType, Reference, String)
635     * @see                                             #addTaxonRelation(TaxonRelationship)
636     * @see                                             #getTaxonRelations()
637     * @see                                             #getRelationsFromThisTaxon()
638     * @see                                             #getRelationsToThisTaxon()
639     */
640    public TaxonRelationship addMisappliedName(Taxon misappliedNameTaxon, Reference citation, String microcitation) {
641        return misappliedNameTaxon.addTaxonRelation(this, TaxonRelationshipType.MISAPPLIED_NAME_FOR(), citation, microcitation);
642    }
643
644//      public void removeMisappliedName(Taxon misappliedNameTaxon){
645//              Set<TaxonRelationship> taxRels = this.getTaxonRelations();
646//              for (TaxonRelationship taxRel : taxRels ){
647//                      if (taxRel.getType().equals(TaxonRelationshipType.MISAPPLIED_NAME_FOR())
648//                              && taxRel.getFromTaxon().equals(misappliedNameTaxon)){
649//                              this.removeTaxonRelation(taxRel);
650//                      }
651//              }
652//      }
653
654    /**
655     * TODO update documentation
656     * Removes one {@link TaxonRelationship taxon relationship} with {@link TaxonRelationshipType taxon relationship type}
657     * taxonRelType and with the given child taxon playing the
658     * source role from the set of {@link #getRelationsToThisTaxon() "taxon relationships to"} belonging
659     * to <i>this</i> taxon. The taxon relationship will also be removed from the set
660     * of {@link #getRelationsFromThisTaxon() "taxon relationships from"} belonging to the other side taxon.
661     * Furthermore, the inherited RelatedFrom and RelatedTo attributes of the
662     * taxon relationship will be nullified.<P>
663     *
664     * @param taxon                     the taxon which plays the source role in the taxon relationship
665     * @param taxonRelType      the taxon relationship type
666     */
667    public void removeTaxon(Taxon taxon, TaxonRelationshipType taxonRelType){
668        Set<TaxonRelationship> taxRels = this.getTaxonRelations();
669        for (TaxonRelationship taxRel : taxRels ){
670            if (taxRel.getType().equals(taxonRelType)
671                && taxRel.getFromTaxon().equals(taxon)){
672                this.removeTaxonRelation(taxRel);
673            }
674        }
675    }
676
677    /**
678     * Creates a new {@link TaxonRelationship taxon relationship} (with {@link TaxonRelationshipType taxon relationship type}
679     * "taxonomically included in") instance where <i>this</i> taxon plays the target
680     * role (parent) and adds it to the set of
681     * {@link #getRelationsToThisTaxon() "taxon relationships to"} belonging to <i>this</i> taxon.
682     * The taxon relationship will also be added to the set of
683     * {@link #getRelationsFromThisTaxon() "taxon relationships from"} belonging to the second taxon
684     * (child) involved in the created relationship.<P>
685     * Since the taxon relationship concerns the modifications
686     * of the number of {@link #getTaxonomicChildrenCount() childrens} for <i>this</i> taxon and
687     * of the {@link #getTaxonomicParent() parent taxon} for the child taxon will be stored.
688     * The {@link name.Rank rank} of the taxon name used as a parent taxon must be higher
689     * than the rank of the taxon name used as a child taxon.
690     *
691     * @param child                     the taxon which plays the source role (child) in the new taxon relationship
692     * @param citation          the reference source for the new taxon relationship
693     * @param microcitation     the string with the details describing the exact localisation within the reference
694     * @see                             #setTaxonomicParent(Taxon, Reference, String)
695     * @see                             #addTaxonRelation(Taxon, TaxonRelationshipType, Reference, String)
696     * @see                             #addTaxonRelation(TaxonRelationship)
697     * @see                             #getTaxonRelations()
698     * @see                             #getRelationsFromThisTaxon()
699     * @see                             #getRelationsToThisTaxon()
700     * @see                             #getTaxonomicParent()
701     * @see                             #getTaxonomicChildrenCount()
702     */
703    @Deprecated //will be removed in future versions. Use Classification/TaxonNode instead
704    public void addTaxonomicChild(Taxon child, Reference citation, String microcitation){
705        if (child == null){
706            throw new NullPointerException("Child Taxon is 'null'");
707        }else{
708            child.setTaxonomicParent(this, citation, microcitation);
709        }
710    }
711
712    /**
713     * Removes one {@link TaxonRelationship taxon relationship} with {@link TaxonRelationshipType taxon relationship type}
714     * "taxonomically included in" and with the given child taxon playing the
715     * source role from the set of {@link #getRelationsToThisTaxon() "taxon relationships to"} belonging
716     * to <i>this</i> taxon. The taxon relationship will also be removed from the set
717     * of {@link #getRelationsFromThisTaxon() "taxon relationships from"} belonging to the child taxon.
718     * Furthermore the inherited RelatedFrom and RelatedTo attributes of the
719     * taxon relationship will be nullified.<P>
720     * Since the taxon relationship concerns the classification modifications
721     * of the number of {@link #getTaxonomicChildrenCount() childrens} for <i>this</i> taxon and
722     * of the {@link #getTaxonomicParent() parent taxon} for the child taxon will be stored.
723     *
724     * @param  child    the taxon playing the source role in the relationship to be removed
725     * @see             #removeTaxonRelation(TaxonRelationship)
726     * @see                     #getRelationsToThisTaxon()
727     * @see                     #getRelationsFromThisTaxon()
728     * @see             #getTaxonomicParent()
729     * @see             #getTaxonomicChildrenCount()
730     * @see                     eu.etaxonomy.cdm.model.common.RelationshipBase#getRelatedFrom()
731     * @see                     eu.etaxonomy.cdm.model.common.RelationshipBase#getRelatedTo()
732     *
733     */
734    @Deprecated //will be removed in future versions. Use classification/TaxonNode instead
735    public void removeTaxonomicChild(Taxon child){
736        Set<TaxonRelationship> taxRels = this.getTaxonRelations();
737        for (TaxonRelationship taxRel : taxRels ){
738            if (taxRel.getType().equals(TaxonRelationshipType.TAXONOMICALLY_INCLUDED_IN())
739                && taxRel.getFromTaxon().equals(child)){
740                this.removeTaxonRelation(taxRel);
741            }
742        }
743    }
744
745    /**
746     * Returns the taxon which is the next higher taxon (parent) of <i>this</i> taxon
747     * within the classification and which is stored in the
748     * TaxonomicParentCache attribute. Each taxon can have only one parent taxon.
749     * The child taxon and the parent taxon play the source respectively the
750     * target role in one {@link TaxonRelationship taxon relationship} with
751     * {@link TaxonRelationshipType taxon relationship type} "taxonomically included in".
752     * The {@link name.Rank rank} of the taxon name used as a parent taxon must be higher
753     * than the rank of the taxon name used as a child taxon.
754     *
755     * @see  #setTaxonomicParent(Taxon, Reference, String)
756     * @see  #getTaxonomicChildren()
757     * @see  #getTaxonomicChildrenCount()
758     * @see  #getRelationsFromThisTaxon()
759     */
760    @Deprecated //will be removed in future versions. Use Classification/TaxonNode instead
761    public Taxon getTaxonomicParent() {
762        return this.taxonomicParentCache;
763    }
764
765    /**
766     * Sets the taxononomic parent of <i>this</i> taxon to null.
767     * Note that this method does not handle taxonomic relationships.
768     */
769    @Deprecated //will be removed in future versions. Use Classification/TaxonNode instead
770    public void nullifyTaxonomicParent() {
771        this.taxonomicParentCache = null;
772    }
773
774    /**
775     * Replaces both the taxonomic parent cache with the given new parent taxon
776     * and the corresponding taxon relationship with a new {@link TaxonRelationship taxon relationship}
777     * (with {@link TaxonRelationshipType taxon relationship type} "taxonomically included in") instance.
778     * In the new taxon relationship <i>this</i> taxon plays the source role (child).
779     * This method creates and adds the new taxon relationship to the set of
780     * {@link #getRelationsFromThisTaxon() "taxon relationships from"} belonging to <i>this</i> taxon.
781     * The taxon relationship will also be added to the set of
782     * {@link #getRelationsToThisTaxon() "taxon relationships to"} belonging to the second taxon
783     * (parent) involved in the new relationship.<P>
784     * Since the taxon relationship concerns the classification modifications
785     * of the {@link #getTaxonomicParent() parent taxon} for <i>this</i> taxon and of the number of
786     * {@link #getTaxonomicChildrenCount() childrens} for the child taxon will be stored.
787     *
788     * @param newParent         the taxon which plays the target role (parent) in the new taxon relationship
789     * @param citation          the reference source for the new taxon relationship
790     * @param microcitation     the string with the details describing the exact localisation within the reference
791     * @see                             #removeTaxonRelation(TaxonRelationship)
792     * @see                             #getTaxonomicParent()
793     * @see                             #addTaxonRelation(Taxon, TaxonRelationshipType, Reference, String)
794     * @see                             #addTaxonRelation(TaxonRelationship)
795     * @see                             #getTaxonRelations()
796     * @see                             #getRelationsFromThisTaxon()
797     * @see                             #getRelationsToThisTaxon()
798     * @see                             #getTaxonomicChildrenCount()
799     */
800    @Deprecated //will be removed in future versions. Use Classification/TaxonNode instead
801    public void setTaxonomicParent(Taxon newParent, Reference citation, String microcitation){
802        //remove previously existing parent relationship!!!
803        Taxon oldParent = this.getTaxonomicParent();
804        Set<TaxonRelationship> taxRels = this.getTaxonRelations();
805        for (TaxonRelationship taxRel : taxRels ){
806            if (taxRel.getType().equals(TaxonRelationshipType.TAXONOMICALLY_INCLUDED_IN()) && taxRel.getToTaxon().equals(oldParent)){
807                this.removeTaxonRelation(taxRel);
808            }
809        }
810        //add new parent
811        if (newParent != null){
812            addTaxonRelation(newParent, TaxonRelationshipType.TAXONOMICALLY_INCLUDED_IN(),citation,microcitation);
813        }
814    }
815
816    /**
817     * Returns the set of taxa which have <i>this</i> taxon as next higher taxon
818     * (parent) within the classification. Each taxon can have several child
819     * taxa. The child taxon and the parent taxon play the source respectively
820     * the target role in one {@link TaxonRelationship taxon relationship} with
821     * {@link TaxonRelationshipType taxon relationship type} "taxonomically included in".
822     * The {@link name.Rank rank} of the taxon name used as a parent taxon must be higher
823     * than the rank of the taxon name used as a child taxon.
824     *
825     * @see  #getTaxonomicParent()
826     * @see  #addTaxonomicChild(Taxon, Reference, String)
827     * @see  #getTaxonomicChildrenCount()
828     * @see  #getRelationsToThisTaxon()
829     */
830    @Transient
831    @Deprecated //will be removed in future versions. Use Classification/TaxonNode instead
832    public Set<Taxon> getTaxonomicChildren() {
833        Set<Taxon> taxa = new HashSet<Taxon>();
834        Set<TaxonRelationship> rels = this.getRelationsToThisTaxon();
835        for (TaxonRelationship rel: rels){
836            TaxonRelationshipType tt = rel.getType();
837            TaxonRelationshipType incl = TaxonRelationshipType.TAXONOMICALLY_INCLUDED_IN();
838            if (tt.equals(incl)){
839                taxa.add(rel.getFromTaxon());
840            }
841        }
842        return taxa;
843    }
844
845    /**
846     * Returns the number of taxa which have <i>this</i> taxon as next higher taxon
847     * (parent) within the classification and the number of which is stored in
848     * the TaxonomicChildrenCount attribute. Each taxon can have several child
849     * taxa. The child taxon and the parent taxon play the source respectively
850     * the target role in one {@link TaxonRelationship taxon relationship} with
851     * {@link TaxonRelationshipType taxon relationship type} "taxonomically included in".
852     * The {@link name.Rank rank} of the taxon name used as a parent taxon must be higher
853     * than the rank of the taxon name used as a child taxon.
854     *
855     * @see  #getTaxonomicChildren()
856     * @see  #getRelationsToThisTaxon()
857     */
858    @Deprecated //will be removed in future versions. Use Classification/TaxonNode instead
859    public int getTaxonomicChildrenCount(){
860        return taxonomicChildrenCount;
861    }
862
863    /**
864     * @see  #getTaxonomicChildrenCount()
865     */
866    @Deprecated //will be removed in future versions. Use Classification/TaxonNode instead
867    public void setTaxonomicChildrenCount(int taxonomicChildrenCount) {
868        this.taxonomicChildrenCount = taxonomicChildrenCount;
869    }
870
871    /**
872     * Returns the boolean value indicating whether <i>this</i> taxon has at least one
873     * taxonomic child taxon within the classification (true) or not (false).
874     *
875     * @see  #getTaxonomicChildrenCount()
876     * @see  #getTaxonomicChildren()
877     */
878    @Deprecated //will be removed in future versions. Use Classification/TaxonNode instead
879    public boolean hasTaxonomicChildren(){
880        return this.taxonomicChildrenCount > 0;
881    }
882
883    @Deprecated //will be removed in future versions. Use Classification/TaxonNode instead
884    private int computeTaxonomicChildrenCount(){
885        int count = 0;
886        for (TaxonRelationship rel: this.getRelationsToThisTaxon()){
887            if (rel.getType().equals(TaxonRelationshipType.TAXONOMICALLY_INCLUDED_IN())){
888                count++;
889            }
890        }
891        return count;
892    }
893
894
895    /**
896     * Returns the boolean value indicating whether <i>this</i> taxon is a misaplication
897     * (misapplied name) for at least one other taxon.
898     */
899    // TODO cache as for #hasTaxonomicChildren
900    @Transient
901    public boolean isMisapplication(){
902        return computeMisapliedNameRelations() > 0;
903    }
904
905    /**
906     * Counts the number of misaplied names relationships where this taxon represents the
907     * misaplied name for another taxon.
908     * @return
909     */
910    private int computeMisapliedNameRelations(){
911        int count = 0;
912        for (TaxonRelationship rel: this.getRelationsFromThisTaxon()){
913            if (rel.getType().equals(TaxonRelationshipType.MISAPPLIED_NAME_FOR())){
914                count++;
915            }
916        }
917        return count;
918    }
919
920    /**
921     * Returns the boolean value indicating whether <i>this</i> taxon is a related
922     * concept for at least one other taxon.
923     */
924    @Transient
925    public boolean isRelatedConcept(){
926        return computeConceptRelations() > 0;
927    }
928
929    /**
930     * Counts the number of concept relationships where this taxon represents the
931     * related concept for another taxon.
932     * @return
933     */
934    private int computeConceptRelations(){
935        int count = 0;
936        for (TaxonRelationship rel: this.getRelationsFromThisTaxon()){
937            TaxonRelationshipType type = rel.getType();
938            if (type.isConceptRelationship()){
939                count++;
940            }
941        }
942        return count;
943    }
944
945    /**
946     * Returns the boolean value indicating whether <i>this</i> taxon has at least one
947     * {@link Synonym synonym} (true) or not (false). If true the {@link #getSynonymRelations() set of synonym relationships}
948     * belonging to <i>this</i> ("accepted/correct") taxon is not empty .
949     *
950     * @see  #getSynonymRelations()
951     * @see  #getSynonyms()
952     * @see  #getSynonymNames()
953     * @see  #removeSynonym(Synonym)
954     * @see  SynonymRelationship
955     */
956    public boolean hasSynonyms(){
957        return this.getSynonymRelations().size() > 0;
958    }
959
960
961    /**
962     * Returns the boolean value indicating whether <i>this</i> taxon is at least
963     * involved in one {@link #getTaxonRelations() taxon relationship} between
964     * two taxa (true), either as a source or as a target, or not (false).
965     *
966     * @see  #getTaxonRelations()
967     * @see  #getRelationsToThisTaxon()
968     * @see  #getRelationsFromThisTaxon()
969     * @see  #removeTaxonRelation(TaxonRelationship)
970     * @see  TaxonRelationship
971     */
972    public boolean hasTaxonRelationships(){
973        return this.getTaxonRelations().size() > 0;
974    }
975
976    /*
977     * MISAPPLIED NAMES
978     */
979    /**
980     * Returns the set of taxa playing the source role in {@link TaxonRelationship taxon relationships}
981     * (with {@link TaxonRelationshipType taxon relationship type} "misapplied name for") where
982     * <i>this</i> taxon plays the target role. A misapplied name is a taxon the
983     * {@link eu.etaxonomy.cdm.model.name.TaxonNameBase taxon name} of which has been erroneously used
984     * by its {@link TaxonBase#getSec() taxon reference} to denominate the same real taxon
985     * as the one meant by <i>this</i> ("accepted/correct") taxon.
986     *
987     * @see  #getTaxonRelations()
988     * @see  #getRelationsToThisTaxon()
989     * @see  #addMisappliedName(Taxon, Reference, String)
990     */
991    @Transient
992    public Set<Taxon> getMisappliedNames(){
993        Set<Taxon> taxa = new HashSet<Taxon>();
994        Set<TaxonRelationship> rels = this.getRelationsToThisTaxon();
995        for (TaxonRelationship rel: rels){
996            TaxonRelationshipType tt = rel.getType();
997            TaxonRelationshipType incl = TaxonRelationshipType.MISAPPLIED_NAME_FOR();
998            if (tt.equals(incl)){
999                taxa.add(rel.getFromTaxon());
1000            }
1001        }
1002        return taxa;
1003    }
1004    /**
1005     * Returns the set of taxa playing the target role in {@link TaxonRelationship taxon relationships}
1006     * (with {@link TaxonRelationshipType taxon relationship type} "misapplied name for") where
1007     * <i>this</i> taxon plays the source role. A misapplied name is a taxon the
1008     * {@link eu.etaxonomy.cdm.model.name.TaxonNameBase taxon name} of which has been erroneously used
1009     * by its {@link TaxonBase#getSec() taxon reference} to denominate the same real taxon
1010     * as the one meant by <i>this</i> ("accepted/correct") taxon.
1011     *
1012     * @see  #getTaxonRelations()
1013     * @see  #getRelationsToThisTaxon()
1014     * @see  #addMisappliedName(Taxon, Reference, String)
1015     */
1016    @Transient
1017    public Set<Taxon> getTaxonForMisappliedName(){
1018        Set<Taxon> taxa = new HashSet<Taxon>();
1019        Set<TaxonRelationship> rels = this.getRelationsFromThisTaxon();
1020        for (TaxonRelationship rel: rels){
1021            TaxonRelationshipType tt = rel.getType();
1022            TaxonRelationshipType incl = TaxonRelationshipType.MISAPPLIED_NAME_FOR();
1023            if (tt.equals(incl)){
1024                taxa.add(rel.getToTaxon());
1025            }
1026        }
1027        return taxa;
1028    }
1029
1030
1031    /*
1032     * DEALING WITH SYNONYMS
1033     */
1034    /**
1035     * Returns the set of all {@link Synonym synonyms} of <i>this</i> ("accepted/correct") taxon.
1036     * Each synonym is the source and <i>this</i> taxon is the target of a {@link SynonymRelationship synonym relationship}
1037     * belonging to the {@link #getSynonymRelations() set of synonym relationships} assigned to <i>this</i> taxon.
1038     * For a particular synonym and for a particular ("accepted/correct") taxon
1039     * there can be several synonym relationships (if two or more
1040     * {@link SynonymRelationshipType synonym relationship types} - for instance
1041     * "pro parte synonym of" and "is homotypic synonym of" - must be combined).
1042     *
1043     * @see    #getSynonymsSortedByType()
1044     * @see    #getSynonymNames()
1045     * @see    #getSynonymRelations()
1046     * @see    #addSynonym(Synonym, SynonymRelationshipType)
1047     * @see    #addSynonym(Synonym, SynonymRelationshipType, Reference, String)
1048     * @see    #removeSynonymRelation(SynonymRelationship)
1049     * @see    #removeSynonym(Synonym)
1050     */
1051    @Transient
1052    public Set<Synonym> getSynonyms(){
1053        Set<Synonym> syns = new HashSet<Synonym>();
1054        for (SynonymRelationship rel: this.getSynonymRelations()){
1055            syns.add(rel.getSynonym());
1056        }
1057        return syns;
1058    }
1059    /**
1060     * Returns the set of all {@link Synonym synonyms} of <i>this</i> ("accepted/correct") taxon
1061     * sorted by the different {@link SynonymRelationshipType categories of synonym relationships}.
1062     * Each synonym is the source and <i>this</i> taxon is the target of a {@link SynonymRelationship synonym relationship}
1063     * belonging to the {@link #getSynonymRelations() set of synonym relationships} assigned to <i>this</i> taxon.
1064     *
1065     * @see    #getSynonyms()
1066     * @see    #getSynonymNames()
1067     * @see    #getSynonymRelations()
1068     * @see    #addSynonym(Synonym, SynonymRelationshipType)
1069     * @see    #addSynonym(Synonym, SynonymRelationshipType, Reference, String)
1070     * @see    #removeSynonymRelation(SynonymRelationship)
1071     * @see    #removeSynonym(Synonym)
1072     */
1073    @Transient
1074    public Set<Synonym> getSynonymsSortedByType(){
1075        // FIXME: need to sort synonyms according to type!!!
1076        logger.warn("getSynonymsSortedByType() not yet implemented");
1077        return getSynonyms();
1078    }
1079    /**
1080     * Returns the set of all {@link name.TaxonNameBase taxon names} used as {@link Synonym synonyms}
1081     * of <i>this</i> ("accepted/correct") taxon. Each synonym is the source and
1082     * <i>this</i> taxon is the target of a {@link SynonymRelationship synonym relationship} belonging
1083     * to the {@link #getSynonymRelations() set of synonym relationships} assigned to <i>this</i> taxon.
1084     *
1085     * @see    #getSynonyms()
1086     * @see    #getSynonymsSortedByType()
1087     * @see    #getSynonymRelations()
1088     * @see    #addSynonymName(TaxonNameBase, SynonymRelationshipType)
1089     * @see    #addSynonym(Synonym, SynonymRelationshipType, Reference, String)
1090     * @see    #removeSynonymRelation(SynonymRelationship)
1091     * @see    #removeSynonym(Synonym)
1092     */
1093    @Transient
1094    public Set<TaxonNameBase> getSynonymNames(){
1095        Set<TaxonNameBase> names = new HashSet<TaxonNameBase>();
1096        for (SynonymRelationship rel: this.getSynonymRelations()){
1097            names.add(rel.getSynonym().getName());
1098        }
1099        return names;
1100    }
1101    /**
1102     * Creates a new {@link SynonymRelationship synonym relationship} (with the given {@link Synonym synonym}
1103     * and with the given {@link SynonymRelationshipType synonym relationship type}), returns it and adds it
1104     * to the set of {@link #getSynonymRelations() synonym relationships} assigned to <i>this</i> taxon.
1105     * The new synonym relationship will also be added to the set of
1106     * {@link Synonym#getSynonymRelations() synonym relationships} belonging to the synonym
1107     * involved in this synonym relationship.<BR>
1108     * The returned synonym relationship allows to add further information to it.
1109     *
1110     * @param synonym           the synonym involved in the relationship to be created
1111     *                                          and added to <i>this</i> taxon's synonym relationships set
1112     * @param synonymType       the synonym relationship category of the synonym
1113     *                                          relationship to be added
1114     * @return                          the created synonym relationship
1115     * @see                             #addSynonymRelation(SynonymRelationship)
1116     * @see                             #addSynonym(Synonym, SynonymRelationshipType, Reference, String)
1117     * @see                             #addSynonymName(TaxonNameBase, SynonymRelationshipType)
1118     * @see                             #addSynonymName(TaxonNameBase, SynonymRelationshipType, Reference, String)
1119     * @see                             #addHomotypicSynonym(Synonym, Reference, String)
1120     * @see                             #addHomotypicSynonymName(TaxonNameBase, Reference, String)
1121     * @see                             #addHeterotypicSynonymName(TaxonNameBase)
1122     * @see                             #addHeterotypicSynonymName(TaxonNameBase, HomotypicalGroup, Reference, String)
1123     * @see                             #getSynonymRelations()
1124     * @see                             #removeSynonym(Synonym)
1125     * @see                             Synonym#getSynonymRelations()
1126     */
1127    public SynonymRelationship addSynonym(Synonym synonym, SynonymRelationshipType synonymType){
1128        return addSynonym(synonym, synonymType, null, null);
1129    }
1130    /**
1131     * Creates a new {@link SynonymRelationship synonym relationship} (with the given {@link Synonym synonym},
1132     * with the given {@link SynonymRelationshipType synonym relationship type} and with the
1133     * {@link eu.etaxonomy.cdm.model.reference.Reference reference source} on which the relationship assertion is based),
1134     * returns it and adds it to the set of {@link #getSynonymRelations() synonym relationships}
1135     * assigned to <i>this</i> taxon. The new synonym relationship will also be
1136     * added to the set of {@link Synonym#getSynonymRelations() synonym relationships} belonging to the synonym
1137     * involved in this synonym relationship.<BR>
1138     * The returned synonym relationship allows to add further information to it.
1139     *
1140     * @param synonym           the synonym involved in the relationship to be created
1141     *                                          and added to <i>this</i> taxon's synonym relationships set
1142     * @param synonymType       the synonym relationship category of the synonym
1143     *                                          relationship to be added
1144     * @param citation          the reference source for the new synonym relationship
1145     * @param microcitation     the string with the details describing the exact localisation within the reference
1146     * @return                          the created synonym relationship
1147     * @see                             #addSynonymRelation(SynonymRelationship)
1148     * @see                             #addSynonym(Synonym, SynonymRelationshipType, Reference, String)
1149     * @see                             #addSynonymName(TaxonNameBase, SynonymRelationshipType)
1150     * @see                             #addSynonymName(TaxonNameBase, SynonymRelationshipType, Reference, String)
1151     * @see                             #addHomotypicSynonym(Synonym, Reference, String)
1152     * @see                             #addHomotypicSynonymName(TaxonNameBase, Reference, String)
1153     * @see                             #addHeterotypicSynonymName(TaxonNameBase)
1154     * @see                             #addHeterotypicSynonymName(TaxonNameBase, HomotypicalGroup, Reference, String)
1155     * @see                             #getSynonymRelations()
1156     * @see                             #removeSynonym(Synonym)
1157     * @see                             Synonym#getSynonymRelations()
1158     */
1159    public SynonymRelationship addSynonym(Synonym synonym, SynonymRelationshipType synonymType, Reference citation, String citationMicroReference){
1160        SynonymRelationship synonymRelationship = new SynonymRelationship(synonym, this, synonymType, citation, citationMicroReference);
1161        return synonymRelationship;
1162    }
1163
1164    /**
1165     * Creates a new {@link Synonym synonym} (with the given {@link eu.etaxonomy.cdm.model.name.TaxonNameBase taxon name}),
1166     * a new {@link SynonymRelationship synonym relationship} (with the new synonym and with the given
1167     * {@link SynonymRelationshipType synonym relationship type}), returns the relationship and adds it
1168     * to the set of {@link #getSynonymRelations() synonym relationships} assigned to <i>this</i> taxon.
1169     * The new synonym will have the same {@link TaxonBase#getSec() concept reference}
1170     * as <i>this</i> taxon. The new synonym relationship will also be added to
1171     * the set of {@link Synonym#getSynonymRelations() synonym relationships} belonging
1172     * to the created synonym.<BR>
1173     * The returned synonym relationship allows to add further information to it.
1174     *
1175     * @param synonymName       the taxon name to be used as a synonym to be added
1176     *                                          to <i>this</i> taxon's set of synonyms
1177     * @param synonymType       the synonym relationship category of the synonym
1178     *                                          relationship to be added
1179     * @return                          the created synonym relationship
1180     * @see                             #addSynonymName(TaxonNameBase, SynonymRelationshipType, Reference, String)
1181     * @see                             #addSynonym(Synonym, SynonymRelationshipType)
1182     * @see                             #addSynonym(Synonym, SynonymRelationshipType, Reference, String)
1183     * @see                             #addSynonymRelation(SynonymRelationship)
1184     * @see                             #addHomotypicSynonym(Synonym, Reference, String)
1185     * @see                             #addHomotypicSynonymName(TaxonNameBase, Reference, String)
1186     * @see                             #addHeterotypicSynonymName(TaxonNameBase)
1187     * @see                             #addHeterotypicSynonymName(TaxonNameBase, HomotypicalGroup, Reference, String)
1188     * @see                             #getSynonymRelations()
1189     * @see                             #removeSynonym(Synonym)
1190     * @see                             Synonym#getSynonymRelations()
1191     */
1192    public SynonymRelationship addSynonymName(TaxonNameBase synonymName, SynonymRelationshipType synonymType){
1193        return addSynonymName(synonymName, synonymType, null, null);
1194    }
1195    /**
1196     * Creates a new {@link Synonym synonym} (with the given {@link eu.etaxonomy.cdm.model.name.TaxonNameBase taxon name}),
1197     * a new {@link SynonymRelationship synonym relationship} (with the new synonym, with the given
1198     * {@link SynonymRelationshipType synonym relationship type} and with the {@link eu.etaxonomy.cdm.model.reference.Reference reference source}
1199     * on which the relationship assertion is based), returns the relationship
1200     * and adds it to the set of {@link #getSynonymRelations() synonym relationships} assigned
1201     * to <i>this</i> taxon. The new synonym will have the same {@link TaxonBase#getSec() concept reference}
1202     * as <i>this</i> taxon. The new synonym relationship will also be added to
1203     * the set of {@link Synonym#getSynonymRelations() synonym relationships} belonging
1204     * to the created synonym.<BR>
1205     * The returned synonym relationship allows to add further information to it.
1206     *
1207     * @param synonymName       the taxon name to be used as a synonym to be added
1208     *                                          to <i>this</i> taxon's set of synonyms
1209     * @param synonymType       the synonym relationship category of the synonym
1210     *                                          relationship to be added
1211     * @param citation          the reference source for the new synonym relationship
1212     * @param microcitation     the string with the details describing the exact localisation within the reference
1213     * @return                          the created synonym relationship
1214     * @see                             #addSynonymName(TaxonNameBase, SynonymRelationshipType, Reference, String)
1215     * @see                             #addSynonym(Synonym, SynonymRelationshipType)
1216     * @see                             #addSynonym(Synonym, SynonymRelationshipType, Reference, String)
1217     * @see                             #addSynonymRelation(SynonymRelationship)
1218     * @see                             #addHomotypicSynonym(Synonym, Reference, String)
1219     * @see                             #addHomotypicSynonymName(TaxonNameBase, Reference, String)
1220     * @see                             #addHeterotypicSynonymName(TaxonNameBase)
1221     * @see                             #addHeterotypicSynonymName(TaxonNameBase, HomotypicalGroup, Reference, String)
1222     * @see                             #getSynonymRelations()
1223     * @see                             #removeSynonym(Synonym)
1224     * @see                             Synonym#getSynonymRelations()
1225     */
1226    public SynonymRelationship addSynonymName(TaxonNameBase synonymName, SynonymRelationshipType synonymType, Reference citation, String citationMicroReference){
1227        Synonym synonym = Synonym.NewInstance(synonymName, this.getSec());
1228        return addSynonym(synonym, synonymType, citation, citationMicroReference);
1229    }
1230
1231    /**
1232     * Creates a new {@link Synonym synonym} (with the given {@link eu.etaxonomy.cdm.model.name.TaxonNameBase taxon name}),
1233     * a new {@link SynonymRelationship synonym relationship} (with the new synonym and with the
1234     * {@link SynonymRelationshipType#HETEROTYPIC_SYNONYM_OF() "is heterotypic synonym of" relationship type}),
1235     * returns the relationship and adds it to the set of
1236     * {@link #getSynonymRelations() synonym relationships} assigned to <i>this</i> taxon.
1237     * The new synonym will have the same {@link TaxonBase#getSec() concept reference}
1238     * as <i>this</i> taxon. The new synonym relationship will also be added to
1239     * the set of {@link Synonym#getSynonymRelations() synonym relationships} belonging
1240     * to the created synonym.<BR>
1241     * The returned synonym relationship allows to add further information to it.
1242     *
1243     * @param synonymName       the taxon name to be used as an heterotypic synonym
1244     *                                          to be added to <i>this</i> taxon's set of synonyms
1245     * @return                          the created synonym relationship
1246     * @see                             #addHeterotypicSynonymName(TaxonNameBase, HomotypicalGroup, Reference, String)
1247     * @see                             #addSynonymName(TaxonNameBase, SynonymRelationshipType)
1248     * @see                             #addSynonymName(TaxonNameBase, SynonymRelationshipType, Reference, String)
1249     * @see                             #addSynonym(Synonym, SynonymRelationshipType)
1250     * @see                             #addSynonym(Synonym, SynonymRelationshipType, Reference, String)
1251     * @see                             #addSynonymRelation(SynonymRelationship)
1252     * @see                             #addHomotypicSynonym(Synonym, Reference, String)
1253     * @see                             #addHomotypicSynonymName(TaxonNameBase, Reference, String)
1254     * @see                             #getSynonymRelations()
1255     * @see                             #removeSynonym(Synonym)
1256     * @see                             Synonym#getSynonymRelations()
1257     */
1258    public SynonymRelationship addHeterotypicSynonymName(TaxonNameBase synonymName){
1259        return addHeterotypicSynonymName(synonymName, null, null, null);
1260    }
1261
1262    /**
1263     * Creates a new {@link Synonym synonym} (with the given {@link eu.etaxonomy.cdm.model.name.TaxonNameBase taxon name}),
1264     * a new {@link SynonymRelationship synonym relationship} (with the new synonym, with the
1265     * {@link SynonymRelationshipType#HETEROTYPIC_SYNONYM_OF() "is heterotypic synonym of" relationship type}
1266     * and with the {@link eu.etaxonomy.cdm.model.reference.Reference reference source}
1267     * on which the relationship assertion is based), returns the relationship
1268     * and adds it to the set of {@link #getSynonymRelations() synonym relationships} assigned
1269     * to <i>this</i> taxon. The new synonym will have the same {@link TaxonBase#getSec() concept reference}
1270     * as <i>this</i> taxon. Furthermore the new synonym relationship will be
1271     * added to the set of {@link Synonym#getSynonymRelations() synonym relationships} belonging
1272     * to the created synonym and the taxon name used as synonym will be added
1273     * to the given {@link name.HomotypicalGroup homotypical group}.<BR>
1274     * The returned synonym relationship allows to add further information to it.
1275     *
1276     * @param synonymName               the taxon name to be used as an heterotypic synonym
1277     *                                                  to be added to <i>this</i> taxon's set of synonyms
1278     * @param homotypicalGroup  the homotypical group to which the taxon name
1279     *                                                  of the synonym will be added
1280     * @param citation                  the reference source for the new synonym relationship
1281     * @param microcitation             the string with the details describing the exact localisation
1282     *                                                  within the reference
1283     * @return                                  the created synonym relationship
1284     * @see                                     #addHeterotypicSynonymName(TaxonNameBase)
1285     * @see                                     #addSynonymName(TaxonNameBase, SynonymRelationshipType, Reference, String)
1286     * @see                                     #addSynonymName(TaxonNameBase, SynonymRelationshipType)
1287     * @see                                     #addSynonym(Synonym, SynonymRelationshipType)
1288     * @see                                     #addSynonym(Synonym, SynonymRelationshipType, Reference, String)
1289     * @see                                     #addSynonymRelation(SynonymRelationship)
1290     * @see                                     #addHomotypicSynonym(Synonym, Reference, String)
1291     * @see                                     #addHomotypicSynonymName(TaxonNameBase, Reference, String)
1292     * @see                                     #getSynonymRelations()
1293     * @see                                     #removeSynonym(Synonym)
1294     * @see                                     Synonym#getSynonymRelations()
1295     */
1296    public SynonymRelationship addHeterotypicSynonymName(TaxonNameBase synonymName, HomotypicalGroup homotypicalGroup, Reference citation, String microCitation){
1297        Synonym synonym = Synonym.NewInstance(synonymName, this.getSec());
1298        if (homotypicalGroup != null){
1299            homotypicalGroup.addTypifiedName(synonymName);
1300        }
1301        return addSynonym(synonym, SynonymRelationshipType.HETEROTYPIC_SYNONYM_OF(), citation, microCitation);
1302    }
1303
1304    /**
1305     * Creates a new {@link Synonym synonym} (with the given {@link eu.etaxonomy.cdm.model.name.TaxonNameBase taxon name}),
1306     * a new {@link SynonymRelationship synonym relationship} (with the new synonym, with the
1307     * {@link SynonymRelationshipType#HOMOTYPIC_SYNONYM_OF() "is homotypic synonym of" relationship type})
1308     * and with the {@link eu.etaxonomy.cdm.model.reference.Reference reference source}
1309     * on which the relationship assertion is based), returns the relationship
1310     * and adds it to the set of {@link #getSynonymRelations() synonym relationships} assigned
1311     * to <i>this</i> taxon. The new synonym will have the same {@link TaxonBase#getSec() concept reference}
1312     * as <i>this</i> taxon. Furthermore the new synonym relationship will be
1313     * added to the set of {@link Synonym#getSynonymRelations() synonym relationships} belonging
1314     * to the created synonym and the taxon name used as synonym will be added
1315     * to the same {@link eu.etaxonomy.cdm.model.name.HomotypicalGroup homotypical group} to which the taxon name
1316     * of <i>this</i> taxon belongs.<BR>
1317     * The returned synonym relationship allows to add further information to it.
1318     *
1319     * @param synonymName       the taxon name to be used as an homotypic synonym
1320     *                                          to be added to <i>this</i> taxon's set of synonyms
1321     * @param citation          the reference source for the new synonym relationship
1322     * @param microcitation     the string with the details describing the exact localisation
1323     *                                          within the reference
1324     * @return                          the created synonym relationship
1325     * @see                             #addHomotypicSynonym(Synonym, Reference, String)
1326     * @see                             #addSynonymName(TaxonNameBase, SynonymRelationshipType, Reference, String)
1327     * @see                             #addSynonymName(TaxonNameBase, SynonymRelationshipType)
1328     * @see                             #addSynonym(Synonym, SynonymRelationshipType)
1329     * @see                             #addSynonym(Synonym, SynonymRelationshipType, Reference, String)
1330     * @see                             #addSynonymRelation(SynonymRelationship)
1331     * @see                             #addHeterotypicSynonymName(TaxonNameBase)
1332     * @see                             #addHeterotypicSynonymName(TaxonNameBase, HomotypicalGroup, Reference, String)
1333     * @see                             #getSynonymRelations()
1334     * @see                             #removeSynonym(Synonym)
1335     * @see                             Synonym#getSynonymRelations()
1336     */
1337    public SynonymRelationship addHomotypicSynonymName(TaxonNameBase synonymName, Reference citation, String microCitation){
1338        Synonym synonym = Synonym.NewInstance(synonymName, this.getSec());
1339        return addHomotypicSynonym(synonym, citation, microCitation);
1340    }
1341
1342    /**
1343     * Creates a new {@link SynonymRelationship synonym relationship} (with the given {@link Synonym synonym},
1344     * with the {@link SynonymRelationshipType#HOMOTYPIC_SYNONYM_OF() "is homotypic synonym of" relationship type}
1345     * and with the {@link eu.etaxonomy.cdm.model.reference.Reference reference source} on which the relationship
1346     * assertion is based), returns it and adds it to the set of
1347     * {@link #getSynonymRelations() synonym relationships} assigned to <i>this</i> taxon.
1348     * Furthermore the new synonym relationship will be added to the set of
1349     * {@link Synonym#getSynonymRelations() synonym relationships} belonging to the synonym
1350     * involved in this synonym relationship and the {@link eu.etaxonomy.cdm.model.name.TaxonNameBase taxon name}
1351     * used as synonym will be added to the same {@link eu.etaxonomy.cdm.model.name.HomotypicalGroup homotypical group}
1352     * to which the taxon name of <i>this</i> taxon belongs.<BR>
1353     * The returned synonym relationship allows to add further information to it.
1354     *
1355     * @param synonym           the synonym involved in the "is homotypic synonym of" relationship to be created
1356     *                                          and added to <i>this</i> taxon's synonym relationships set
1357     * @param citation          the reference source for the new synonym relationship
1358     * @param microcitation     the string with the details describing the exact localisation within the reference
1359     * @return                          the created synonym relationship
1360     * @see                             #addHomotypicSynonymName(TaxonNameBase, Reference, String)
1361     * @see                             #addSynonym(Synonym, SynonymRelationshipType)
1362     * @see                             #addSynonym(Synonym, SynonymRelationshipType, Reference, String)
1363     * @see                             #addSynonymName(TaxonNameBase, SynonymRelationshipType, Reference, String)
1364     * @see                             #addSynonymName(TaxonNameBase, SynonymRelationshipType)
1365     * @see                             #addSynonymRelation(SynonymRelationship)
1366     * @see                             #addHeterotypicSynonymName(TaxonNameBase)
1367     * @see                             #addHeterotypicSynonymName(TaxonNameBase, HomotypicalGroup, Reference, String)
1368     * @see                             #getSynonymRelations()
1369     * @see                             #removeSynonym(Synonym)
1370     * @see                             Synonym#getSynonymRelations()
1371     */
1372    public SynonymRelationship addHomotypicSynonym(Synonym synonym, Reference citation, String microCitation){
1373    if (this.getName() != null){
1374            if (this.getName().getHomotypicalGroup().getTypifiedNames().isEmpty()){
1375                this.getName().getHomotypicalGroup().getTypifiedNames().add(this.getName());
1376
1377            }
1378            this.getName().getHomotypicalGroup().addTypifiedName(synonym.getName());
1379
1380        }
1381        SynonymRelationship synRel = addSynonym(synonym, SynonymRelationshipType.HOMOTYPIC_SYNONYM_OF(), citation, microCitation);
1382        return synRel;
1383    }
1384
1385    /**
1386     * Like {@link #removeSynonym(Synonym, boolean)} with <code>removeSynonymNameFromHomotypicalGroup</code> set to true.
1387     * @see #removeSynonym(Synonym, boolean)
1388     */
1389    public void removeSynonym(Synonym synonym){
1390        removeSynonym(synonym, true);
1391    }
1392
1393    /**
1394     * Removes the element(s) from the set of {@link SynonymRelationship synonym relationships}
1395     * assigned to <i>this</i> ("accepted/valid") taxon in which the given synonym is involved.
1396     * Due to bidirectionality the same synonym relationships will also be
1397     * removed from the set of synonym relationships assigned to the
1398     * {@link Synonym#getSynonymRelations() synonym} involved in the relationship. Furthermore the content of
1399     * the {@link SynonymRelationship#getAcceptedTaxon() accepted taxon} attribute and of the
1400     * {@link SynonymRelationship#getSynonym() synonym} attribute within the synonym relationships
1401     * themselves will be set to "null".
1402     *
1403     * @param  synonym  the synonym involved in the synonym relationship which should be deleted
1404     * @param removeSynonymNameFromHomotypicalGroup if <code>true</code> the removed synonyms
1405     *          name will get a new homotypic group in case it is together with other names in a group.
1406     * @see                     #getSynonymRelations()
1407     * @see                     #addSynonym(Synonym, SynonymRelationshipType)
1408     * @see                     #addSynonym(Synonym, SynonymRelationshipType, Reference, String)
1409     * @see                     #removeSynonymRelation(SynonymRelationship)
1410     * @see                             #removeSynonymRelation(SynonymRelationship, boolean)
1411     */
1412    public void removeSynonym(Synonym synonym, boolean removeSynonymNameFromHomotypicalGroup){
1413        Set<SynonymRelationship> synonymRelationships = new HashSet<SynonymRelationship>();
1414        synonymRelationships.addAll(this.getSynonymRelations());
1415        for(SynonymRelationship synonymRelationship : synonymRelationships){
1416            if (synonymRelationship.getAcceptedTaxon().equals(this) && synonymRelationship.getSynonym().equals(synonym)){
1417                this.removeSynonymRelation(synonymRelationship, removeSynonymNameFromHomotypicalGroup);
1418            }
1419        }
1420    }
1421
1422
1423    /**
1424     * Retrieves the ordered list (depending on the date of publication) of
1425     * homotypic {@link Synonym synonyms} (according to the same {@link eu.etaxonomy.cdm.model.reference.Reference reference}
1426     * as for <i>this</i> taxon) under the condition that the {@link eu.etaxonomy.cdm.model.name.TaxonNameBase taxon names}
1427     * of these synonyms and the taxon name of <i>this</i> taxon belong to the
1428     * same {@link eu.etaxonomy.cdm.model.name.HomotypicalGroup homotypical group}.
1429     *
1430     * @return          the ordered list of homotypic synonyms
1431     * @see                     #getHomotypicSynonymsByHomotypicRelationship()
1432     * @see                     #getSynonyms()
1433     * @see                     #getHomotypicSynonymyGroups()
1434     * @see                     eu.etaxonomy.cdm.model.name.HomotypicalGroup
1435     * @see                     eu.etaxonomy.cdm.model.name.HomotypicalGroup#getSynonymsInGroup(Reference)
1436     */
1437    @Transient
1438    public List<Synonym> getHomotypicSynonymsByHomotypicGroup(){
1439        if (this.getHomotypicGroup() == null){
1440            return null;
1441        }else{
1442            return this.getSynonymsInGroup(this.getHomotypicGroup());
1443        }
1444    }
1445
1446    /**
1447     * Retrieves the ordered list (depending on the date of publication) of
1448     * homotypic {@link Synonym synonyms} (according to the same {@link eu.etaxonomy.cdm.model.reference.Reference reference}
1449     * as for <i>this</i> taxon) under the condition that these synonyms and
1450     * <i>this</i> taxon are involved in {@link SynonymRelationship synonym relationships} with an
1451     * "is homotypic synonym of" {@link SynonymRelationshipType#HOMOTYPIC_SYNONYM_OF() synonym relationship type}.
1452     *
1453     * @return          the ordered list of homotypic synonyms
1454     * @see                     #getHomotypicSynonymsByHomotypicGroup()
1455     * @see                     #getSynonyms()
1456     * @see                     #getHomotypicSynonymyGroups()
1457     * @see                     SynonymRelationshipType
1458     */
1459    @Transient
1460    public List<Synonym> getHomotypicSynonymsByHomotypicRelationship(){
1461        Set<SynonymRelationship> synonymRelations = this.getSynonymRelations();
1462        List<Synonym> result = new ArrayList<Synonym>();
1463        for(SynonymRelationship synonymRelation : synonymRelations) {
1464            if(synonymRelation.getType().equals(SynonymRelationshipType.HOMOTYPIC_SYNONYM_OF())){
1465                result.add(synonymRelation.getSynonym());
1466            }
1467        }
1468        return result;
1469    }
1470
1471    /**
1472     * Returns the ordered list of all {@link eu.etaxonomy.cdm.model.name.HomotypicalGroup homotypical groups} {@link Synonym synonyms} of
1473     * <i>this</i> taxon belong to. {@link eu.etaxonomy.cdm.model.name.TaxonNameBase Taxon names} of homotypic synonyms
1474     * belong to the same homotypical group as the taxon name of <i>this</i>
1475     * taxon. Taxon names of heterotypic synonyms belong to at least one other
1476     * homotypical group. <BR>
1477     * The list returned is ordered according to the date of publication of the
1478     * first published name within each homotypical group.
1479     *
1480     * @see                     #getHeterotypicSynonymyGroups()
1481     * @see                     #getSynonyms()
1482     * @see                     eu.etaxonomy.cdm.model.name.HomotypicalGroup
1483     */
1484    @Transient
1485    public List<HomotypicalGroup> getHomotypicSynonymyGroups(){
1486        List<HomotypicalGroup> result = new ArrayList<HomotypicalGroup>();
1487        result.add(this.getHomotypicGroup());
1488        for (TaxonNameBase taxonNameBase :this.getSynonymNames()){
1489            if (taxonNameBase != null) {
1490                if (!result.contains(taxonNameBase.getHomotypicalGroup())){
1491                    result.add(taxonNameBase.getHomotypicalGroup());
1492                }
1493            } // TODO: give error message to user
1494        }
1495        // TODO: sort list according to date of first published name within each group
1496        return result;
1497    }
1498
1499
1500
1501    /**
1502     * The status of this taxon is unknown it could also be some kind of synonym.
1503     * @return the taxonStatusUnknown
1504     */
1505    public boolean isTaxonStatusUnknown() {
1506        return taxonStatusUnknown;
1507    }
1508
1509    /**
1510     * @param taxonStatusUnknown the taxonStatusUnknown to set
1511     */
1512    public void setTaxonStatusUnknown(boolean taxonStatusUnknown) {
1513        this.taxonStatusUnknown = taxonStatusUnknown;
1514    }
1515
1516
1517
1518
1519    public boolean isUnplaced() {
1520        return unplaced;
1521    }
1522
1523    public void setUnplaced(boolean unplaced) {
1524        this.unplaced = unplaced;
1525    }
1526
1527    public boolean isExcluded() {
1528        return excluded;
1529    }
1530
1531    public void setExcluded(boolean excluded) {
1532        this.excluded = excluded;
1533    }
1534
1535    /**
1536     * Returns the ordered list of all {@link eu.etaxonomy.cdm.model.name.HomotypicalGroup homotypical groups}
1537     * that contain {@link Synonym synonyms} that are heterotypic to <i>this</i> taxon.
1538     * {@link eu.etaxonomy.cdm.model.name.TaxonNameBase Taxon names} of heterotypic synonyms
1539     * belong to a homotypical group which cannot be the homotypical group to which the
1540     * taxon name of <i>this</i> taxon belongs. This method returns the same
1541     * list as the {@link #getHomotypicSynonymyGroups() getHomotypicSynonymyGroups} method
1542     * but without the homotypical group to which the taxon name of <i>this</i> taxon
1543     * belongs.<BR>
1544     * The list returned is ordered according to the date of publication of the
1545     * first published name within each homotypical group.
1546     *
1547     * @see                     #getHeterotypicSynonymyGroups()
1548     * @see                     #getSynonyms()
1549     * @see                     SynonymRelationshipType#HETEROTYPIC_SYNONYM_OF()
1550     * @see                     eu.etaxonomy.cdm.model.name.HomotypicalGroup
1551     */
1552    @Transient
1553    public List<HomotypicalGroup> getHeterotypicSynonymyGroups(){
1554        List<HomotypicalGroup> list = getHomotypicSynonymyGroups();
1555        list.remove(this.getHomotypicGroup());
1556        //sort
1557        Map<Synonym, HomotypicalGroup> map = new HashMap<Synonym, HomotypicalGroup>();
1558        for (HomotypicalGroup homotypicalGroup: list){
1559            List<Synonym> synonymList = getSynonymsInGroup(homotypicalGroup);
1560            if (synonymList.size() > 0){
1561                map.put(synonymList.get(0), homotypicalGroup);
1562            }
1563        }
1564        List<Synonym> keyList = new ArrayList<Synonym>();
1565        keyList.addAll(map.keySet());
1566        Collections.sort(keyList, new TaxonComparator());
1567
1568        List<HomotypicalGroup> result = new ArrayList<HomotypicalGroup>();
1569        for(Synonym synonym: keyList){
1570            result.add(map.get(synonym));
1571        }
1572        //sort end
1573        return result;
1574    }
1575
1576    /**
1577     * Retrieves the ordered list (depending on the date of publication) of
1578     * {@link taxon.Synonym synonyms} (according to a given reference)
1579     * the {@link TaxonNameBase taxon names} of which belong to the homotypical group.
1580     * If other names are part of the group that are not considered synonyms of
1581     * <i>this</i> taxon, then they will not be included in
1582     * the result set.
1583     *
1584     * @param homoGroup
1585     * @see                     TaxonNameBase#getSynonyms()
1586     * @see                     TaxonNameBase#getTaxa()
1587     * @see                     taxon.Synonym
1588     */
1589    @Transient
1590    public List<Synonym> getSynonymsInGroup(HomotypicalGroup homotypicGroup){
1591        List<Synonym> result = new ArrayList<Synonym>();
1592
1593        for (TaxonNameBase<?, ?>name : homotypicGroup.getTypifiedNames()){
1594            for (Synonym synonym : name.getSynonyms()){
1595                for(SynonymRelationship synRel : synonym.getSynonymRelations()){
1596                    if (synRel.getAcceptedTaxon().equals(this)){
1597                        result.add(synRel.getSynonym());
1598                    }
1599                }
1600            }
1601        }
1602        Collections.sort(result, new TaxonComparator());
1603        return result;
1604    }
1605
1606
1607    /**
1608     * Returns the image gallery description. If no image gallery exists, a new one is created using the
1609     * defined title and adds the string "-Image Gallery" to the title.</BR>
1610     * If multiple image galleries exist an arbitrary one is choosen.
1611     * @param title
1612     * @return
1613     */
1614    @Transient
1615    public TaxonDescription getOrCreateImageGallery(String title){
1616        return getOrCreateImageGallery(title, true, false);
1617    }
1618
1619    /**
1620     * Returns the image gallery description. If no image gallery exists, a new one is created using the
1621     * defined title.</BR>
1622     * If onlyTitle == true we look only for an image gallery with this title, create a new one otherwise.
1623     * If multiple image galleries exist that match the conditions an arbitrary one is choosen.
1624     * @param title
1625     * @param onlyTitle
1626     * @param if true, the String "Image Gallery
1627     * @return
1628     */
1629    @Transient
1630    public TaxonDescription getOrCreateImageGallery(String title, boolean addImageGalleryToTitle, boolean onlyTitle){
1631        TaxonDescription result = null;
1632        String titleCache = (title == null) ? "Image Gallery" : title;
1633        if (title != null && addImageGalleryToTitle){
1634            titleCache = titleCache+ "-Image Gallery";
1635        }
1636        Set<TaxonDescription> descriptionSet = this.getDescriptions();
1637        for (TaxonDescription desc: descriptionSet){
1638            if (desc.isImageGallery()){
1639                if (onlyTitle && ! titleCache.equals(desc.getTitleCache())){
1640                    continue;
1641                }
1642                result = desc;
1643                if (onlyTitle && titleCache.equals(desc.getTitleCache())){
1644                    break;
1645                }
1646            }
1647        }
1648        if (result == null){
1649            result = TaxonDescription.NewInstance();
1650            result.setTitleCache(titleCache, true);
1651            this.addDescription(result);
1652            result.setImageGallery(true);
1653        }
1654        return result;
1655    }
1656    //*********************** CLONE ********************************************************/
1657
1658
1659    /**
1660     * Clones <i>this</i> taxon. This is a shortcut that enables to create
1661     * a new instance that differs only slightly from <i>this</i> taxon by
1662     * modifying only some of the attributes.<BR><BR>
1663     * The TaxonNodes are not cloned, the list is empty.<BR>
1664     * (CAUTION: this behaviour needs to be discussed and may change in future).<BR><BR>
1665     * The taxon relationships and synonym relationships are cloned <BR>
1666     *
1667     * @see eu.etaxonomy.cdm.model.taxon.TaxonBase#clone()
1668     * @see eu.etaxonomy.cdm.model.media.IdentifiableEntity#clone()
1669     * @see java.lang.Object#clone()
1670     */
1671    @Override
1672    public Object clone() {
1673        Taxon result;
1674        result = (Taxon)super.clone();
1675
1676        result.setRelationsFromThisTaxon(new HashSet<TaxonRelationship>());
1677
1678        for (TaxonRelationship fromRelationship : this.getRelationsFromThisTaxon()){
1679            TaxonRelationship newRelationship = (TaxonRelationship)fromRelationship.clone();
1680            newRelationship.setRelatedFrom(result);
1681            result.relationsFromThisTaxon.add(newRelationship);
1682        }
1683
1684        result.setRelationsToThisTaxon(new HashSet<TaxonRelationship>());
1685        for (TaxonRelationship toRelationship : this.getRelationsToThisTaxon()){
1686            TaxonRelationship newRelationship = (TaxonRelationship)toRelationship.clone();
1687            newRelationship.setRelatedTo(result);
1688            result.relationsToThisTaxon.add(newRelationship);
1689        }
1690
1691
1692        result.synonymRelations = new HashSet<SynonymRelationship>();
1693        for (SynonymRelationship synRelationship : this.getSynonymRelations()){
1694            SynonymRelationship newRelationship = (SynonymRelationship)synRelationship.clone();
1695            newRelationship.setRelatedTo(result);
1696            result.synonymRelations.add(newRelationship);
1697        }
1698
1699
1700        result.taxonNodes = new HashSet<TaxonNode>();
1701
1702        /*for (TaxonNode taxonNode : this.getTaxonNodes()){
1703            TaxonNode newTaxonNode = (TaxonNode)taxonNode.clone();
1704            newTaxonNode.setTaxon(result);
1705            result.addTaxonNode(newTaxonNode);
1706        }*/
1707
1708        return result;
1709
1710    }
1711}
Note: See TracBrowser for help on using the browser.