Project

General

Profile

Download (12.9 KB) Statistics
| Branch: | Tag: | Revision:
1
/**
2
* Copyright (C) 2007 EDIT
3
* European Distributed Institute of Taxonomy
4
* http://www.e-taxonomy.eu
5
*
6
* The contents of this file are subject to the Mozilla Public License Version 1.1
7
* See LICENSE.TXT at the top of this package for the full license terms.
8
*/
9

    
10
package eu.etaxonomy.cdm.model.taxon;
11

    
12
import java.util.HashSet;
13
import java.util.Set;
14

    
15
import javax.persistence.Entity;
16
import javax.persistence.FetchType;
17
import javax.persistence.OneToMany;
18
import javax.persistence.Transient;
19
import javax.validation.Valid;
20
import javax.validation.constraints.NotNull;
21
import javax.xml.bind.annotation.XmlAccessType;
22
import javax.xml.bind.annotation.XmlAccessorType;
23
import javax.xml.bind.annotation.XmlElement;
24
import javax.xml.bind.annotation.XmlElementWrapper;
25
import javax.xml.bind.annotation.XmlIDREF;
26
import javax.xml.bind.annotation.XmlRootElement;
27
import javax.xml.bind.annotation.XmlSchemaType;
28
import javax.xml.bind.annotation.XmlType;
29

    
30
import org.apache.log4j.Logger;
31
import org.hibernate.annotations.Cascade;
32
import org.hibernate.annotations.CascadeType;
33
import org.hibernate.envers.Audited;
34
import org.hibernate.search.annotations.Indexed;
35
import org.hibernate.validator.constraints.NotEmpty;
36
import org.springframework.beans.factory.annotation.Configurable;
37

    
38
import eu.etaxonomy.cdm.model.common.IRelated;
39
import eu.etaxonomy.cdm.model.name.TaxonNameBase;
40
import eu.etaxonomy.cdm.model.reference.Reference;
41
import eu.etaxonomy.cdm.strategy.cache.taxon.ITaxonCacheStrategy;
42
import eu.etaxonomy.cdm.strategy.cache.taxon.TaxonBaseDefaultCacheStrategy;
43
import eu.etaxonomy.cdm.validation.Level2;
44

    
45
/**
46
 * The class for synonyms: these are {@link TaxonBase taxa} the {@link name.TaxonNameBase taxon names}
47
 * of which are not used by the {@link TaxonBase#getSec() reference} to designate a real
48
 * taxon but are mentioned as taxon names that were oder are used by some other
49
 * unspecified references to designate (at least to some extent) the same
50
 * particular real taxon. Synonyms that are involved in no
51
 * {@link SynonymRelationship synonym relationship} are actually meaningless.<BR>
52
 * Splitting taxa in "accepted/correct" and "synonyms"
53
 * makes it easier to handle particular relationships between
54
 * ("accepted/correct") {@link Taxon taxa} on the one hand and between ("synonym") taxa
55
 * and ("accepted/correct") taxa on the other.
56
 *
57
 * @author m.doering
58
 * @version 1.0
59
 * @created 08-Nov-2007 13:06:55
60
 */
61
@XmlAccessorType(XmlAccessType.FIELD)
62
@XmlType(name = "Synonym", propOrder = {
63
    "synonymRelations"
64
})
65
@XmlRootElement(name = "Synonym")
66
@Entity
67
@Indexed(index = "eu.etaxonomy.cdm.model.taxon.TaxonBase")
68
@Audited
69
@Configurable
70
public class Synonym extends TaxonBase<ITaxonCacheStrategy<Synonym>> implements IRelated<SynonymRelationship>{
71
	private static final long serialVersionUID = -454067515022159757L;
72

    
73
	@SuppressWarnings("unused")
74
	private static final Logger logger = Logger.getLogger(Synonym.class);
75

    
76
	// Don't need the synonym relations here since they are stored at taxon side?
77
	@XmlElementWrapper(name = "SynonymRelations")
78
	@XmlElement(name = "SynonymRelationship")
79
    @XmlIDREF
80
    @XmlSchemaType(name = "IDREF")
81
    @OneToMany(mappedBy="relatedFrom", fetch=FetchType.LAZY, orphanRemoval=true)
82
	@Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE})
83
	@NotNull
84
	@NotEmpty(groups = Level2.class,message="{eu.etaxonomy.cdm.model.taxon.Synonym.noOrphanedSynonyms.message}")
85
	@Valid
86
	private Set<SynonymRelationship> synonymRelations = new HashSet<SynonymRelationship>();
87

    
88
	// ************* CONSTRUCTORS *************/
89
	/**
90
	 * Class constructor: creates a new empty synonym instance.
91
	 *
92
	 * @see 	#Synonym(TaxonNameBase, Reference)
93
	 */
94
	//TODO should be private, but still produces Spring init errors
95
	public Synonym(){
96
		this.cacheStrategy = new TaxonBaseDefaultCacheStrategy<Synonym>();
97
	}
98

    
99
	/**
100
	 * Class constructor: creates a new synonym instance with
101
	 * the {@link eu.etaxonomy.cdm.model.name.TaxonNameBase taxon name} used and the {@link eu.etaxonomy.cdm.model.reference.Reference reference}
102
	 * using it as a synonym and not as an ("accepted/correct") {@link Taxon taxon}.
103
	 *
104
	 * @param  taxonNameBase	the taxon name used
105
	 * @param  sec				the reference using the taxon name
106
	 * @see    					Synonym#Synonym(TaxonNameBase, Reference)
107
	 */
108
	public Synonym(TaxonNameBase taxonNameBase, Reference sec){
109
		super(taxonNameBase, sec);
110
		this.cacheStrategy = new TaxonBaseDefaultCacheStrategy<Synonym>();
111
	}
112

    
113
	//********* METHODS **************************************/
114

    
115
	/**
116
	 * Creates a new synonym instance with
117
	 * the {@link eu.etaxonomy.cdm.model.name.TaxonNameBase taxon name} used and the {@link eu.etaxonomy.cdm.model.reference.Reference reference}
118
	 * using it as a synonym and not as an ("accepted/correct") {@link Taxon taxon}.
119
	 *
120
	 * @param  taxonNameBase	the taxon name used
121
	 * @param  sec				the reference using the taxon name
122
	 * @see    					#Synonym(TaxonNameBase, Reference)
123
	 */
124
	public static Synonym NewInstance(TaxonNameBase taxonName, Reference sec){
125
		Synonym result = new Synonym(taxonName, sec);
126
		return result;
127
	}
128

    
129
	/**
130
	 * Returns the set of all {@link SynonymRelationship synonym relationships}
131
	 * in which <i>this</i> synonym is involved. <i>This</i> synonym can only
132
	 * be the source within these synonym relationships.
133
	 *
134
	 * @see    #addSynonymRelation(SynonymRelationship)
135
	 * @see    #addRelationship(SynonymRelationship)
136
	 * @see    #removeSynonymRelation(SynonymRelationship)
137
	 */
138
	public Set<SynonymRelationship> getSynonymRelations() {
139
		if(synonymRelations == null) {
140
			this.synonymRelations = new HashSet<SynonymRelationship>();
141
		}
142
		return synonymRelations;
143
	}
144

    
145
	/**
146
	 * @see    #getSynonymRelations()
147
	 */
148
	protected void setSynonymRelations(Set<SynonymRelationship> synonymRelations) {
149
		this.synonymRelations = synonymRelations;
150
	}
151

    
152
	/**
153
	 * Adds an existing {@link SynonymRelationship synonym relationship} to the set of
154
	 * {@link #getSynonymRelations() synonym relationships} assigned to <i>this</i> synonym. If
155
	 * the source of the synonym relationship does not match with <i>this</i>
156
	 * synonym no addition will be carried out.<BR>
157
	 * This methods does the same as the {@link #addRelationship() addRelationship} method.
158
	 *
159
	 * @param synonymRelation	the synonym relationship to be added to <i>this</i> synonym's
160
	 * 							synonym relationships set
161
	 * @see    	   				#addRelationship(SynonymRelationship)
162
	 * @see    	   				#getSynonymRelations()
163
	 * @see    	   				#removeSynonymRelation(SynonymRelationship)
164
	 */
165
	protected void addSynonymRelation(SynonymRelationship synonymRelation) {
166
		this.synonymRelations.add(synonymRelation);
167
	}
168
	/**
169
	 * Removes one element from the set of {@link SynonymRelationship synonym relationships} assigned
170
	 * to <i>this</i> synonym. Due to bidirectionality the given
171
	 * synonym relationship will also be removed from the set of synonym
172
	 * relationships assigned to the {@link Taxon#getSynonymRelations() taxon} involved in the
173
	 * relationship. Furthermore the content of
174
	 * the {@link SynonymRelationship#getAcceptedTaxon() accepted taxon} attribute and of the
175
	 * {@link SynonymRelationship#getSynonym() synonym} attribute within the synonym relationship
176
	 * itself will be set to "null".
177
	 *
178
	 * @param  synonymRelation  the synonym relationship which should be deleted
179
	 * @see     		  		#getSynonymRelations()
180
	 * @see     		  		#addRelationship(SynonymRelationship)
181
	 */
182
	public void removeSynonymRelation(SynonymRelationship synonymRelation) {
183
		synonymRelation.setSynonym(null);
184
		Taxon taxon = synonymRelation.getAcceptedTaxon();
185
		if (taxon != null){
186
			synonymRelation.setAcceptedTaxon(null);
187
			taxon.removeSynonymRelation(synonymRelation);
188
		}
189
		this.synonymRelations.remove(synonymRelation);
190
	}
191

    
192

    
193
	/**
194
	 * Adds an existing {@link SynonymRelationship synonym relationship} to the set of
195
	 * {@link #getSynonymRelations() synonym relationships} assigned to <i>this</i> synonym. If
196
	 * the source of the synonym relationship does not match with <i>this</i>
197
	 * synonym no addition will be carried out.<BR>
198
	 * This methods does the same as the {@link #addSynonymRelation(SynonymRelationship) addSynonymRelation} method.
199
	 *
200
	 * @param synonymRelation	the synonym relationship to be added to <i>this</i> synonym's
201
	 * 							synonym relationships set
202
	 * @see    	   				#addSynonymRelation(SynonymRelationship)
203
	 * @see    	   				#getSynonymRelations()
204
	 * @see    	   				#removeSynonymRelation(SynonymRelationship)
205
	 */
206
	/* (non-Javadoc)
207
	 * @see eu.etaxonomy.cdm.model.common.IRelated#addRelationship(eu.etaxonomy.cdm.model.common.RelationshipBase)
208
	 */
209
	@Override
210
    public void addRelationship(SynonymRelationship rel){
211
		addSynonymRelation(rel);
212
	}
213

    
214

    
215
	/**
216
	 * Returns the set of all ("accepted/correct") {@link Taxon taxa} involved in the same
217
	 * {@link SynonymRelationship synonym relationships} as <i>this</i> synonym.
218
	 * Each taxon is the target and <i>this</i> synonym is the source of a {@link SynonymRelationship synonym relationship}
219
	 * belonging to the {@link #getSynonymRelations() set of synonym relationships} assigned to
220
	 * <i>this</i> synonym. For a particular synonym there are more than one
221
	 * ("accepted/correct") taxa only if the {@link SynonymRelationship#isProParte() "is pro parte" flag}
222
	 * of the corresponding {@link SynonymRelationship synonym relationships} is set.
223
	 *
224
	 * @see    #getSynonymRelations()
225
	 * @see    #getRelationType(Taxon)
226
	 * @see    SynonymRelationship#isProParte()
227
	 */
228
	@Transient
229
	public Set<Taxon> getAcceptedTaxa() {
230
		Set<Taxon>taxa=new HashSet<Taxon>();
231
		for (SynonymRelationship rel:getSynonymRelations()){
232
			taxa.add(rel.getAcceptedTaxon());
233
		}
234
		return taxa;
235
	}
236

    
237
	/**
238
	 * Returns true if <i>this</i> is a synonym of the given taxon.
239
	 *
240
	 * @param taxon	the taxon to check synonym for
241
	 * @return	true if <i>this</i> is a ynonms of the given taxon
242
	 *
243
	 * @see #getAcceptedTaxa()
244
	 */
245
	@Transient
246
	public boolean isSynonymOf(Taxon taxon){
247
		return getAcceptedTaxa().contains(taxon);
248
	}
249

    
250
	@Override
251
    @Transient
252
	public boolean isOrphaned() {
253
		return false;
254
	}
255
	/**
256
	 * Returns the set of {@link SynonymRelationshipType synonym relationship types} of the
257
	 * {@link SynonymRelationship synonym relationships} where the {@link SynonymRelationship#getSynonym() synonym}
258
	 * is <i>this</i> synonym and the {@link SynonymRelationship#getAcceptedTaxon() taxon}
259
	 * is the given one. "Null" is returned if the given taxon is "null" or if
260
	 * no synonym relationship exists from <i>this</i> synonym to the
261
	 * given taxon.
262
	 *
263
	 * @param taxon	the ("accepted/correct") taxon which a synonym relationship
264
	 * 				from <i>this</i> synonym should point to
265
	 * @see    		#getSynonymRelations()
266
	 * @see    		#getAcceptedTaxa()
267
	 */
268
	public Set<SynonymRelationshipType> getRelationType(Taxon taxon){
269
		Set<SynonymRelationshipType> result = new HashSet<SynonymRelationshipType>();
270
		if (taxon == null ){
271
			return result;
272
		}
273
		for (SynonymRelationship rel : getSynonymRelations()){
274
			Taxon acceptedTaxon = rel.getAcceptedTaxon();
275
			if (taxon.equals(acceptedTaxon)){
276
				result.add(rel.getType());
277
			}
278
		}
279
		return result;
280
	}
281

    
282
	/**
283
	 * Replaces ALL accepted taxa of this synonym by the new accepted taxon.
284
	 * The citation information (citation /microcitation) of the synonym relationship
285
	 * is kept.
286
	 * @param newAcceptedTaxon
287
	 * 			the new accepted taxon
288
	 * @param relType
289
	 * 			if not <code>null</code> the relationship type is changed to relType
290
	 * @param copyCitationInfo
291
	 * 			if true the citation and the microcitation of relationship
292
	 * 			is not changed.
293
	 * @param citation
294
	 * 			if copyCitationInfo is <code>false</code> this citation is set
295
	 * 			to the synonym relationship.
296
	 * @param microCitation
297
	 * 			if copyCitationInfo is <code>false</code> this micro citation is set
298
	 * 			to the synonym relationship.
299

    
300
	 * @param acceptedTaxon
301
	 */
302
	public void replaceAcceptedTaxon(Taxon newAcceptedTaxon, SynonymRelationshipType relType, boolean copyCitationInfo, Reference citation, String microCitation) {
303
		Set<SynonymRelationship> rels = new HashSet<SynonymRelationship>();
304
		rels.addAll(this.getSynonymRelations());  //avoid concurrent modification exception
305

    
306
		for (SynonymRelationship rel : rels){
307
			Taxon oldAcceptedTaxon = rel.getAcceptedTaxon();
308
			Synonym syn = rel.getSynonym();
309

    
310
			oldAcceptedTaxon.removeSynonym(rel.getSynonym(), false);
311

    
312
			SynonymRelationship newRel = (SynonymRelationship)rel.clone();
313
			newRel.setAcceptedTaxon(newAcceptedTaxon);
314
			newAcceptedTaxon.getSynonymRelations().add(newRel);
315
			newRel.setSynonym(syn);
316
			syn.addSynonymRelation(newRel);
317

    
318
			newRel.setType(relType);
319
		}
320
	}
321
//*********************** CLONE ********************************************************/
322

    
323
	@Override
324
	public Object clone() {
325
		Synonym result;
326
		result = (Synonym)super.clone();
327

    
328
		result.setSynonymRelations(new HashSet<SynonymRelationship>());
329

    
330
			for (SynonymRelationship synRelationship : this.getSynonymRelations()){
331
				SynonymRelationship newRelationship = (SynonymRelationship)synRelationship.clone();
332
				newRelationship.setRelatedFrom(result);
333
				result.synonymRelations.add(newRelationship);
334
			}
335
			return result;
336

    
337
	}
338

    
339

    
340
}
(7-7/21)