Project

General

Profile

Download (9.69 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 javax.persistence.Entity;
13
import javax.persistence.FetchType;
14
import javax.persistence.ManyToOne;
15
import javax.persistence.Transient;
16
import javax.xml.bind.annotation.XmlAccessType;
17
import javax.xml.bind.annotation.XmlAccessorType;
18
import javax.xml.bind.annotation.XmlElement;
19
import javax.xml.bind.annotation.XmlIDREF;
20
import javax.xml.bind.annotation.XmlRootElement;
21
import javax.xml.bind.annotation.XmlSchemaType;
22
import javax.xml.bind.annotation.XmlType;
23

    
24
import org.apache.log4j.Logger;
25
import org.hibernate.annotations.Cascade;
26
import org.hibernate.annotations.CascadeType;
27
import org.hibernate.envers.Audited;
28
import org.hibernate.search.annotations.ContainedIn;
29
import org.hibernate.search.annotations.Indexed;
30
import org.springframework.beans.factory.annotation.Configurable;
31

    
32
import eu.etaxonomy.cdm.model.name.HomotypicalGroup;
33
import eu.etaxonomy.cdm.model.name.TaxonNameBase;
34
import eu.etaxonomy.cdm.model.reference.Reference;
35
import eu.etaxonomy.cdm.strategy.cache.taxon.ITaxonCacheStrategy;
36
import eu.etaxonomy.cdm.strategy.cache.taxon.TaxonBaseDefaultCacheStrategy;
37
import eu.etaxonomy.cdm.validation.Level3;
38
import eu.etaxonomy.cdm.validation.annotation.HomotypicSynonymsShouldBelongToGroup;
39

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

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

    
75

    
76
    @XmlElement(name = "acceptedTaxon")
77
    @XmlIDREF
78
    @XmlSchemaType(name = "IDREF")
79
    @ManyToOne(fetch = FetchType.LAZY)
80
    @Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE})
81
    @ContainedIn
82
//  @NotEmpty(groups = Level2.class,message="{eu.etaxonomy.cdm.model.taxon.Synonym.noOrphanedSynonyms.message}")
83
//    @NotNull(groups = Level2.class)
84
    private Taxon acceptedTaxon;
85

    
86

    
87
    @XmlElement(name = "IsProParte")
88
    private boolean proParte = false;
89

    
90
    @XmlElement(name = "IsPartial")
91
    private boolean partial = false;
92

    
93

    
94
    @XmlElement(name = "Type")
95
    @XmlIDREF
96
    @XmlSchemaType(name = "IDREF")
97
    @ManyToOne(fetch=FetchType.EAGER)
98
    private SynonymRelationshipType type;
99

    
100
//************************************* FACTORY ****************************/
101

    
102
    /**
103
     * Creates a new synonym instance with
104
     * the {@link eu.etaxonomy.cdm.model.name.TaxonNameBase taxon name} used and the {@link eu.etaxonomy.cdm.model.reference.Reference reference}
105
     * using it as a synonym and not as an ("accepted/correct") {@link Taxon taxon}.
106
     *
107
     * @param  taxonNameBase    the taxon name used
108
     * @param  sec              the reference using the taxon name
109
     * @see                     #Synonym(TaxonNameBase, Reference)
110
     */
111
    public static Synonym NewInstance(TaxonNameBase taxonName, Reference sec){
112
        Synonym result = new Synonym(taxonName, sec, null);
113
        return result;
114
    }
115

    
116
    public static Synonym NewInstance(TaxonNameBase taxonName, Reference sec, String secDetail){
117
        Synonym result = new Synonym(taxonName, sec, secDetail);
118
        return result;
119
    }
120

    
121
// ************* CONSTRUCTORS *************/
122
	/**
123
	 * Class constructor: creates a new empty synonym instance.
124
	 *
125
	 * @see 	#Synonym(TaxonNameBase, Reference)
126
	 */
127
	//TODO should be private, but still produces Spring init errors
128
	public Synonym(){
129
		this.cacheStrategy = new TaxonBaseDefaultCacheStrategy<Synonym>();
130
	}
131

    
132
	private Synonym(TaxonNameBase taxonNameBase, Reference sec, String secDetail){
133
		super(taxonNameBase, sec, secDetail);
134
		this.cacheStrategy = new TaxonBaseDefaultCacheStrategy<Synonym>();
135
	}
136

    
137
//********************** GETTER/SETTER ******************************/
138

    
139
	/**
140
	 * Returns the "accepted/valid" {@link Taxon taxon}
141
	 *
142
	 */
143
	public Taxon getAcceptedTaxon() {
144
		return this.acceptedTaxon;
145
	}
146

    
147

    
148
    /**
149
     * @param acceptedTaxon the acceptedTaxon to set
150
     */
151
    protected void setAcceptedTaxon(Taxon acceptedTaxon) {
152
        if (acceptedTaxon == null){
153
            Taxon oldTaxon = this.acceptedTaxon;
154
            this.acceptedTaxon = null;
155
            oldTaxon.removeSynonym(this);
156
        }else{
157
            if (this.acceptedTaxon != null){
158
                this.acceptedTaxon.removeSynonym(this, false);
159
            }
160
            this.acceptedTaxon = acceptedTaxon;
161
            this.acceptedTaxon.addSynonym(this);
162
            checkHomotypic();
163
        }
164
    }
165

    
166
    /**
167
     * Returns "true" if the proParte flag is set.
168
     * This indicates that the {@link name.TaxonNameBase taxon name} used as a
169
     * {@link Synonym synonym} designated originally a real taxon which later has
170
     * been split. In this case the synonym is therefore the synonym of at least
171
     * two different ("accepted/valid") {@link Taxon taxa}.
172
     */
173
    public boolean isProParte() {
174
        return proParte;
175
    }
176

    
177
    /**
178
     * @see #isProParte()
179
     */
180
    public void setProParte(boolean proParte) {
181
        this.proParte = proParte;
182
    }
183

    
184
    /**
185
     * Returns "true" if the ProParte flag is set.
186
     * This indicates that the {@link name.TaxonNameBase taxon name} used as <code>this</code>
187
     * {@link Synonym synonym} designated originally a real taxon which later has
188
     * been lumped together with another one. In this case the
189
     * ("accepted/valid") {@link Taxon taxon} has therefore at least
190
     * two different synonyms (for the two lumped real taxa).
191
     */
192
    public boolean isPartial() {
193
        return partial;
194
    }
195

    
196
    /**
197
     * @see #isPartial()
198
     */
199
    public void setPartial(boolean partial) {
200
        this.partial = partial;
201
    }
202

    
203

    
204
    public SynonymRelationshipType getType() {
205
        return type;
206
    }
207

    
208
    public void setType(SynonymRelationshipType type) {
209
        this.type = type;
210
        checkHomotypic();
211
    }
212

    
213

    
214
//***************** METHODS **************************/
215
	/**
216
	 * Returns true if <i>this</i> is a synonym of the given taxon.
217
	 *
218
	 * @param taxon	the taxon to check synonym for
219
	 * @return	true if <i>this</i> is a synonm of the given taxon
220
	 *
221
	 * @see #getAcceptedTaxon()
222
	 */
223
	@Transient
224
	public boolean isSynonymOf(Taxon taxon){
225
		return taxon != null && taxon.equals(this.acceptedTaxon);
226
	}
227

    
228
	@Override
229
    @Transient
230
	public boolean isOrphaned() {
231
	    return this.acceptedTaxon == null || this.acceptedTaxon.isOrphaned();
232
	}
233

    
234

    
235
	/**
236
	 * Replaces ALL accepted taxa of this synonym by the new accepted taxon.
237
	 * The citation information (citation /microcitation) of the synonym relationship
238
	 * is kept.
239
	 * @param newAcceptedTaxon
240
	 * 			the new accepted taxon
241
	 * @param relType
242
	 * 			if not <code>null</code> the relationship type is changed to relType
243
	 * @param copyCitationInfo
244
	 * 			if true the citation and the microcitation of relationship
245
	 * 			is not changed.
246
	 * @param citation
247
	 * 			if copyCitationInfo is <code>false</code> this citation is set
248
	 * 			to the synonym relationship.
249
	 * @param microCitation
250
	 * 			if copyCitationInfo is <code>false</code> this micro citation is set
251
	 * 			to the synonym relationship.
252

    
253
	 * @param acceptedTaxon
254
	 */
255
	public void replaceAcceptedTaxon(Taxon newAcceptedTaxon, SynonymRelationshipType relType) {
256

    
257
//		Taxon oldAcceptedTaxon = this.getAcceptedTaxon();
258
//
259
//		oldAcceptedTaxon.removeSynonym(this, false);
260

    
261
		this.setAcceptedTaxon(newAcceptedTaxon);
262
//		newAcceptedTaxon.getSynonyms().add(this);x;
263

    
264
		if (relType != null){
265
		    this.setType(relType);
266
		}
267
	}
268

    
269
	public void replaceAcceptedTaxonAndSecundum(Taxon newAcceptedTaxon, SynonymRelationshipType relType, Reference sec, String microSec) {
270
	    replaceAcceptedTaxon(newAcceptedTaxon, relType);
271
	    this.setSec(sec);
272
        this.setSecMicroReference(microSec);
273
	}
274

    
275
    /**
276
     * Checks if the synonym relationship type is homotypic. If it is
277
     * the name of <code>this</code> synonym is added to the {@link HomotypicalGroup
278
     * homotypic group} of the {@link Taxon accepted taxon}.
279
     */
280
    private void checkHomotypic() {
281
        if (type != null && type.equals(SynonymRelationshipType.HOMOTYPIC_SYNONYM_OF())
282
                && acceptedTaxon != null && acceptedTaxon.getName() != null){
283
                acceptedTaxon.getName().getHomotypicalGroup().addTypifiedName(this.getName());
284
        }
285
    }
286

    
287
//*********************** CLONE ********************************************************/
288

    
289
	@Override
290
	public Object clone() {
291
		Synonym result;
292
		result = (Synonym)super.clone();
293

    
294
		//no changes to accepted taxon, type, partial, proParte
295

    
296
		return result;
297

    
298
	}
299

    
300

    
301
}
(7-7/20)