Project

General

Profile

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

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

    
12
import org.apache.log4j.Logger;
13
import org.hibernate.annotations.Cascade;
14
import org.hibernate.annotations.CascadeType;
15
import org.hibernate.envers.Audited;
16
import org.hibernate.search.annotations.Indexed;
17
import org.hibernate.validator.constraints.NotEmpty;
18
import org.springframework.beans.factory.annotation.Configurable;
19

    
20
import eu.etaxonomy.cdm.model.common.IRelated;
21
import eu.etaxonomy.cdm.model.name.TaxonNameBase;
22
import eu.etaxonomy.cdm.model.reference.Reference;
23
import eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy;
24
import eu.etaxonomy.cdm.strategy.cache.taxon.TaxonBaseDefaultCacheStrategy;
25
import eu.etaxonomy.cdm.validation.Level2;
26

    
27
import java.util.*;
28

    
29
import javax.persistence.*;
30
import javax.validation.Valid;
31
import javax.validation.constraints.NotNull;
32
import javax.xml.bind.annotation.XmlAccessType;
33
import javax.xml.bind.annotation.XmlAccessorType;
34
import javax.xml.bind.annotation.XmlElement;
35
import javax.xml.bind.annotation.XmlElementWrapper;
36
import javax.xml.bind.annotation.XmlIDREF;
37
import javax.xml.bind.annotation.XmlRootElement;
38
import javax.xml.bind.annotation.XmlSchemaType;
39
import 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
66
public class Synonym extends TaxonBase<IIdentifiableEntityCacheStrategy<Synonym>> implements IRelated<SynonymRelationship>{
67
	private static final long serialVersionUID = -454067515022159757L;
68

    
69
	@SuppressWarnings("unused")
70
	private static final Logger logger = Logger.getLogger(Synonym.class);
71

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

    
84
	// ************* CONSTRUCTORS *************/	
85
	/** 
86
	 * Class constructor: creates a new empty synonym instance.
87
	 * 
88
	 * @see 	#Synonym(TaxonNameBase, Reference)
89
	 */
90
	//TODO should be private, but still produces Spring init errors
91
	public Synonym(){
92
		this.cacheStrategy = new TaxonBaseDefaultCacheStrategy<Synonym>();
93
	}
94
	
95
	/** 
96
	 * Class constructor: creates a new synonym instance with
97
	 * the {@link eu.etaxonomy.cdm.model.name.TaxonNameBase taxon name} used and the {@link eu.etaxonomy.cdm.model.reference.Reference reference}
98
	 * using it as a synonym and not as an ("accepted/correct") {@link Taxon taxon}.
99
	 * 
100
	 * @param  taxonNameBase	the taxon name used
101
	 * @param  sec				the reference using the taxon name
102
	 * @see    					Synonym#Synonym(TaxonNameBase, Reference)
103
	 */
104
	public Synonym(TaxonNameBase taxonNameBase, Reference sec){
105
		super(taxonNameBase, sec);
106
		this.cacheStrategy = new TaxonBaseDefaultCacheStrategy<Synonym>();
107
	}
108
	 
109
	//********* METHODS **************************************/
110

    
111
	/** 
112
	 * Creates a new synonym instance with
113
	 * the {@link eu.etaxonomy.cdm.model.name.TaxonNameBase taxon name} used and the {@link eu.etaxonomy.cdm.model.reference.Reference reference}
114
	 * using it as a synonym and not as an ("accepted/correct") {@link Taxon taxon}.
115
	 * 
116
	 * @param  taxonNameBase	the taxon name used
117
	 * @param  sec				the reference using the taxon name
118
	 * @see    					#Synonym(TaxonNameBase, Reference)
119
	 */
120
	public static Synonym NewInstance(TaxonNameBase taxonName, Reference sec){
121
		Synonym result = new Synonym(taxonName, sec);
122
		return result;
123
	}
124
	
125
	/** 
126
	 * Returns the set of all {@link SynonymRelationship synonym relationships}
127
	 * in which <i>this</i> synonym is involved. <i>This</i> synonym can only
128
	 * be the source within these synonym relationships. 
129
	 *  
130
	 * @see    #addSynonymRelation(SynonymRelationship)
131
	 * @see    #addRelationship(SynonymRelationship)
132
	 * @see    #removeSynonymRelation(SynonymRelationship)
133
	 */
134
	public Set<SynonymRelationship> getSynonymRelations() {
135
		if(synonymRelations == null) {
136
			this.synonymRelations = new HashSet<SynonymRelationship>();
137
		}
138
		return synonymRelations;
139
	}
140
	
141
	/** 
142
	 * @see    #getSynonymRelations()
143
	 */
144
	protected void setSynonymRelations(Set<SynonymRelationship> synonymRelations) {
145
		this.synonymRelations = synonymRelations;
146
	}
147

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

    
209

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

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

    
276
	/**
277
	 * Replaces ALL accepted taxa of this synonym by the new accepted taxon.
278
	 * The citation information (citation /microcitation) of the synonym relationship
279
	 * is kept.
280
	 * @param newAcceptedTaxon
281
	 * 			the new accepted taxon
282
	 * @param relType
283
	 * 			if not <code>null</code> the relationship type is changed to relType
284
	 * @param copyCitationInfo
285
	 * 			if true the citation and the microcitation of relationship
286
	 * 			is not changed.
287
	 * @param citation
288
	 * 			if copyCitationInfo is <code>false</code> this citation is set
289
	 * 			to the synonym relationship. 
290
	 * @param microCitation
291
	 * 			if copyCitationInfo is <code>false</code> this micro citation is set
292
	 * 			to the synonym relationship. 
293
	 
294
	 * @param acceptedTaxon
295
	 */
296
	public void replaceAcceptedTaxon(Taxon newAcceptedTaxon, SynonymRelationshipType relType, boolean copyCitationInfo, Reference citation, String microCitation) {
297
		Set<SynonymRelationship> rels = new HashSet<SynonymRelationship>();
298
		rels.addAll(this.getSynonymRelations());  //avoid concurrent modification exception
299
		
300
		for (SynonymRelationship rel : rels){
301
			Taxon oldAcceptedTaxon = rel.getAcceptedTaxon();
302
			Synonym syn = rel.getSynonym();
303
			
304
			oldAcceptedTaxon.removeSynonym(rel.getSynonym(), false);
305
						
306
			SynonymRelationship newRel = (SynonymRelationship)rel.clone();
307
			newRel.setAcceptedTaxon(newAcceptedTaxon);
308
			newAcceptedTaxon.getSynonymRelations().add(newRel);
309
			newRel.setSynonym(syn);
310
			syn.addSynonymRelation(newRel);
311
			
312
			newRel.setType(relType);
313
		}
314
	}
315
//*********************** CLONE ********************************************************/
316
	
317
	@Override
318
	public Object clone() {
319
		Synonym result;
320
		result = (Synonym)super.clone();
321
		
322
		result.setSynonymRelations(new HashSet<SynonymRelationship>());
323
		
324
			for (SynonymRelationship synRelationship : this.getSynonymRelations()){
325
				SynonymRelationship newRelationship = (SynonymRelationship)synRelationship.clone();
326
				newRelationship.setRelatedFrom(result);
327
				result.synonymRelations.add(newRelationship);
328
			}
329
			return result;
330
		
331
	}
332

    
333
	
334
}
(6-6/18)