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

Revision 12931, 12.8 kB (checked in by a.mueller, 9 months ago)

minor

  • 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
12import org.apache.log4j.Logger;
13import org.hibernate.annotations.Cascade;
14import org.hibernate.annotations.CascadeType;
15import org.hibernate.envers.Audited;
16import org.hibernate.search.annotations.Indexed;
17import org.hibernate.validator.constraints.NotEmpty;
18import org.springframework.beans.factory.annotation.Configurable;
19
20import eu.etaxonomy.cdm.model.common.IRelated;
21import eu.etaxonomy.cdm.model.name.TaxonNameBase;
22import eu.etaxonomy.cdm.model.reference.Reference;
23import eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy;
24import eu.etaxonomy.cdm.strategy.cache.taxon.TaxonBaseDefaultCacheStrategy;
25import eu.etaxonomy.cdm.validation.Level2;
26
27import java.util.*;
28
29import javax.persistence.*;
30import javax.validation.Valid;
31import javax.validation.constraints.NotNull;
32import javax.xml.bind.annotation.XmlAccessType;
33import javax.xml.bind.annotation.XmlAccessorType;
34import javax.xml.bind.annotation.XmlElement;
35import javax.xml.bind.annotation.XmlElementWrapper;
36import javax.xml.bind.annotation.XmlIDREF;
37import javax.xml.bind.annotation.XmlRootElement;
38import javax.xml.bind.annotation.XmlSchemaType;
39import javax.xml.bind.annotation.XmlType;
40
41/**
42 * The class for synonyms: these are {@link TaxonBase taxa} the {@link name.TaxonNameBase taxon names}
43 * of which are not used by the {@link TaxonBase#getSec() reference} to designate a real
44 * taxon but are mentioned as taxon names that were oder are used by some other
45 * unspecified references to designate (at least to some extent) the same
46 * particular real taxon. Synonyms that are involved in no
47 * {@link SynonymRelationship synonym relationship} are actually meaningless.<BR>
48 * Splitting taxa in "accepted/correct" and "synonyms"
49 * makes it easier to handle particular relationships between
50 * ("accepted/correct") {@link Taxon taxa} on the one hand and between ("synonym") taxa
51 * and ("accepted/correct") taxa on the other.
52 *
53 * @author m.doering
54 * @version 1.0
55 * @created 08-Nov-2007 13:06:55
56 */
57@XmlAccessorType(XmlAccessType.FIELD)
58@XmlType(name = "Synonym", propOrder = {
59    "synonymRelations"
60})
61@XmlRootElement(name = "Synonym")
62@Entity
63@Indexed(index = "eu.etaxonomy.cdm.model.taxon.TaxonBase")
64@Audited
65@Configurable
66public class Synonym extends TaxonBase<IIdentifiableEntityCacheStrategy<Synonym>> implements IRelated<SynonymRelationship>{
67       
68        static Logger logger = Logger.getLogger(Synonym.class);
69
70        // Don't need the synonym relations here since they are stored at taxon side?
71        @XmlElementWrapper(name = "SynonymRelations")
72        @XmlElement(name = "SynonymRelationship")
73    @XmlIDREF
74    @XmlSchemaType(name = "IDREF")
75    @OneToMany(mappedBy="relatedFrom", fetch=FetchType.LAZY)
76        @Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE, CascadeType.DELETE, CascadeType.DELETE_ORPHAN})
77        @NotNull
78        @NotEmpty(groups = Level2.class,message="{eu.etaxonomy.cdm.model.taxon.Synonym.noOrphanedSynonyms.message}")
79        @Valid
80        private Set<SynonymRelationship> synonymRelations = new HashSet<SynonymRelationship>();
81
82        // ************* CONSTRUCTORS *************/   
83        /**
84         * Class constructor: creates a new empty synonym instance.
85         *
86         * @see         #Synonym(TaxonNameBase, Reference)
87         */
88        //TODO should be private, but still produces Spring init errors
89        public Synonym(){
90                this.cacheStrategy = new TaxonBaseDefaultCacheStrategy<Synonym>();
91        }
92       
93        /**
94         * Class constructor: creates a new synonym instance with
95         * the {@link eu.etaxonomy.cdm.model.name.TaxonNameBase taxon name} used and the {@link eu.etaxonomy.cdm.model.reference.Reference reference}
96         * using it as a synonym and not as an ("accepted/correct") {@link Taxon taxon}.
97         *
98         * @param  taxonNameBase        the taxon name used
99         * @param  sec                          the reference using the taxon name
100         * @see                                         Synonym#Synonym(TaxonNameBase, Reference)
101         */
102        public Synonym(TaxonNameBase taxonNameBase, Reference sec){
103                super(taxonNameBase, sec);
104                this.cacheStrategy = new TaxonBaseDefaultCacheStrategy<Synonym>();
105        }
106         
107        //********* METHODS **************************************/
108
109        /**
110         * Creates a new synonym instance with
111         * the {@link eu.etaxonomy.cdm.model.name.TaxonNameBase taxon name} used and the {@link eu.etaxonomy.cdm.model.reference.Reference reference}
112         * using it as a synonym and not as an ("accepted/correct") {@link Taxon taxon}.
113         *
114         * @param  taxonNameBase        the taxon name used
115         * @param  sec                          the reference using the taxon name
116         * @see                                         #Synonym(TaxonNameBase, Reference)
117         */
118        public static Synonym NewInstance(TaxonNameBase taxonName, Reference sec){
119                Synonym result = new Synonym(taxonName, sec);
120                return result;
121        }
122       
123        /**
124         * Returns the set of all {@link SynonymRelationship synonym relationships}
125         * in which <i>this</i> synonym is involved. <i>This</i> synonym can only
126         * be the source within these synonym relationships.
127         * 
128         * @see    #addSynonymRelation(SynonymRelationship)
129         * @see    #addRelationship(SynonymRelationship)
130         * @see    #removeSynonymRelation(SynonymRelationship)
131         */
132        public Set<SynonymRelationship> getSynonymRelations() {
133                if(synonymRelations == null) {
134                        this.synonymRelations = new HashSet<SynonymRelationship>();
135                }
136                return synonymRelations;
137        }
138       
139        /**
140         * @see    #getSynonymRelations()
141         */
142        protected void setSynonymRelations(Set<SynonymRelationship> synonymRelations) {
143                this.synonymRelations = synonymRelations;
144        }
145
146        /**
147         * Adds an existing {@link SynonymRelationship synonym relationship} to the set of
148         * {@link #getSynonymRelations() synonym relationships} assigned to <i>this</i> synonym. If
149         * the source of the synonym relationship does not match with <i>this</i>
150         * synonym no addition will be carried out.<BR>
151         * This methods does the same as the {@link #addRelationship() addRelationship} method.
152         *
153         * @param synonymRelation       the synonym relationship to be added to <i>this</i> synonym's
154         *                                                      synonym relationships set
155         * @see                                         #addRelationship(SynonymRelationship)
156         * @see                                         #getSynonymRelations()
157         * @see                                         #removeSynonymRelation(SynonymRelationship)
158         */
159        protected void addSynonymRelation(SynonymRelationship synonymRelation) {
160                this.synonymRelations.add(synonymRelation);
161        }
162        /**
163         * Removes one element from the set of {@link SynonymRelationship synonym relationships} assigned
164         * to <i>this</i> synonym. Due to bidirectionality the given
165         * synonym relationship will also be removed from the set of synonym
166         * relationships assigned to the {@link Taxon#getSynonymRelations() taxon} involved in the
167         * relationship. Furthermore the content of
168         * the {@link SynonymRelationship#getAcceptedTaxon() accepted taxon} attribute and of the
169         * {@link SynonymRelationship#getSynonym() synonym} attribute within the synonym relationship
170         * itself will be set to "null".
171         *
172         * @param  synonymRelation  the synonym relationship which should be deleted
173         * @see                                 #getSynonymRelations()
174         * @see                                 #addRelationship(SynonymRelationship)
175         */
176        public void removeSynonymRelation(SynonymRelationship synonymRelation) {
177                synonymRelation.setSynonym(null);
178                Taxon taxon = synonymRelation.getAcceptedTaxon();
179                if (taxon != null){
180                        synonymRelation.setAcceptedTaxon(null);
181                        taxon.removeSynonymRelation(synonymRelation);
182                }
183                this.synonymRelations.remove(synonymRelation);
184        }
185       
186       
187        /**
188         * Adds an existing {@link SynonymRelationship synonym relationship} to the set of
189         * {@link #getSynonymRelations() synonym relationships} assigned to <i>this</i> synonym. If
190         * the source of the synonym relationship does not match with <i>this</i>
191         * synonym no addition will be carried out.<BR>
192         * This methods does the same as the {@link #addSynonymRelation(SynonymRelationship) addSynonymRelation} method.
193         *
194         * @param synonymRelation       the synonym relationship to be added to <i>this</i> synonym's
195         *                                                      synonym relationships set
196         * @see                                         #addSynonymRelation(SynonymRelationship)
197         * @see                                         #getSynonymRelations()
198         * @see                                         #removeSynonymRelation(SynonymRelationship)
199         */
200        /* (non-Javadoc)
201         * @see eu.etaxonomy.cdm.model.common.IRelated#addRelationship(eu.etaxonomy.cdm.model.common.RelationshipBase)
202         */
203        public void addRelationship(SynonymRelationship rel){
204                addSynonymRelation(rel);
205        }
206
207
208        /**
209         * Returns the set of all ("accepted/correct") {@link Taxon taxa} involved in the same
210         * {@link SynonymRelationship synonym relationships} as <i>this</i> synonym.
211         * Each taxon is the target and <i>this</i> synonym is the source of a {@link SynonymRelationship synonym relationship}
212         * belonging to the {@link #getSynonymRelations() set of synonym relationships} assigned to
213         * <i>this</i> synonym. For a particular synonym there are more than one
214         * ("accepted/correct") taxon only if the {@link SynonymRelationship#isProParte() "is pro parte" flag}
215         * of the corresponding {@link SynonymRelationship synonym relationships} is set.
216         * 
217         * @see    #getSynonymRelations()
218         * @see    #getRelationType(Taxon)
219         * @see    SynonymRelationship#isProParte()
220         */
221        @Transient
222        public Set<Taxon> getAcceptedTaxa() {
223                Set<Taxon>taxa=new HashSet<Taxon>();
224                for (SynonymRelationship rel:getSynonymRelations()){
225                        taxa.add(rel.getAcceptedTaxon());
226                }
227                return taxa;
228        }
229       
230        /**
231         * Returns true if <i>this</i> is a synonym of the given taxon.
232         *
233         * @param taxon the taxon to check synonym for
234         * @return      true if <i>this</i> is a ynonms of the given taxon
235         *
236         * @see #getAcceptedTaxa()
237         */
238        @Transient
239        public boolean isSynonymOf(Taxon taxon){
240                return getAcceptedTaxa().contains(taxon);
241        }
242
243        /**
244         * Returns the set of {@link SynonymRelationshipType synonym relationship types} of the
245         * {@link SynonymRelationship synonym relationships} where the {@link SynonymRelationship#getSynonym() synonym}
246         * is <i>this</i> synonym and the {@link SynonymRelationship#getAcceptedTaxon() taxon}
247         * is the given one. "Null" is returned if the given taxon is "null" or if
248         * no synonym relationship exists from <i>this</i> synonym to the
249         * given taxon.
250         * 
251         * @param taxon the ("accepted/correct") taxon which a synonym relationship
252         *                              from <i>this</i> synonym should point to
253         * @see                 #getSynonymRelations()
254         * @see                 #getAcceptedTaxa()
255         */
256        public Set<SynonymRelationshipType> getRelationType(Taxon taxon){
257                Set<SynonymRelationshipType> result = new HashSet<SynonymRelationshipType>();
258                if (taxon == null ){
259                        return result;
260                }
261                for (SynonymRelationship rel : getSynonymRelations()){
262                        Taxon acceptedTaxon = rel.getAcceptedTaxon();
263                        if (taxon.equals(acceptedTaxon)){
264                                result.add(rel.getType());
265                        }
266                }
267                return result;
268        }
269
270        /**
271         * Replaces ALL accepted taxa of this synonym by the new accepted taxon.
272         * The citation information (citation /microcitation) of the synonym relationship
273         * is kept.
274         * @param newAcceptedTaxon
275         *                      the new accepted taxon
276         * @param relType
277         *                      if not <code>null</code> the relationship type is changed to relType
278         * @param copyCitationInfo
279         *                      if true the citation and the microcitation of relationship
280         *                      is not changed.
281         * @param citation
282         *                      if copyCitationInfo is <code>false</code> this citation is set
283         *                      to the synonym relationship.
284         * @param microCitation
285         *                      if copyCitationInfo is <code>false</code> this micro citation is set
286         *                      to the synonym relationship.
287         
288         * @param acceptedTaxon
289         */
290        public void replaceAcceptedTaxon(Taxon newAcceptedTaxon, SynonymRelationshipType relType, boolean copyCitationInfo, Reference citation, String microCitation) {
291                Set<SynonymRelationship> rels = new HashSet<SynonymRelationship>();
292                rels.addAll(this.getSynonymRelations());  //avoid concurrent modification exception
293               
294                for (SynonymRelationship rel : rels){
295                        Taxon oldAcceptedTaxon = rel.getAcceptedTaxon();
296                        //remove old
297                        oldAcceptedTaxon.getSynonymRelations().remove(rel);
298                        Synonym syn = rel.getSynonym();  //syn should be this
299                        syn.getSynonymRelations().remove(rel);
300                        //create new
301                        SynonymRelationship newRel = (SynonymRelationship)rel.clone();
302                        newRel.setAcceptedTaxon(newAcceptedTaxon);
303                        newAcceptedTaxon.getSynonymRelations().add(newRel);
304                        newRel.setSynonym(syn);
305                        syn.getSynonymRelations().add(newRel);
306                       
307                        newRel.setType(relType);
308                }
309        }
310//*********************** CLONE ********************************************************/
311       
312        @Override
313        public Object clone() {
314                Synonym result;
315                result = (Synonym)super.clone();
316               
317                result.setSynonymRelations(new HashSet<SynonymRelationship>());
318               
319                        for (SynonymRelationship synRelationship : this.getSynonymRelations()){
320                                SynonymRelationship newRelationship = (SynonymRelationship)synRelationship.clone();
321                                newRelationship.setRelatedFrom(result);
322                                result.synonymRelations.add(newRelationship);
323                        }
324                        return result;
325               
326        }
327}
Note: See TracBrowser for help on using the browser.