Project

General

Profile

Download (12.5 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
	
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 = this.getSynonymRelations();
292
		for (SynonymRelationship rel : rels){
293
			Taxon oldAcceptedTaxon = rel.getAcceptedTaxon();
294
			oldAcceptedTaxon.getSynonymRelations().remove(rel);
295
			rel.getSynonym().getSynonymRelations().remove(rel);
296
			SynonymRelationship newRel = (SynonymRelationship)rel.clone();
297
			newRel.setAcceptedTaxon(newAcceptedTaxon);
298
			newAcceptedTaxon.getSynonymRelations().add(newRel);
299
			newRel.setType(relType);
300
		}
301
	}
302
//*********************** CLONE ********************************************************/
303
	
304
	@Override
305
	public Object clone() {
306
		Synonym result;
307
		result = (Synonym)super.clone();
308
		
309
		result.setSynonymRelations(new HashSet<SynonymRelationship>());
310
		
311
			for (SynonymRelationship synRelationship : this.getSynonymRelations()){
312
				SynonymRelationship newRelationship = (SynonymRelationship)synRelationship.clone();
313
				newRelationship.setRelatedFrom(result);
314
				result.synonymRelations.add(newRelationship);
315
			}
316
			return result;
317
		
318
	}
319
}
(6-6/18)