Project

General

Profile

Download (8.53 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.ITaxonNameBase;
34
import eu.etaxonomy.cdm.model.name.TaxonName;
35
import eu.etaxonomy.cdm.model.reference.Reference;
36
import eu.etaxonomy.cdm.strategy.cache.taxon.ITaxonCacheStrategy;
37
import eu.etaxonomy.cdm.strategy.cache.taxon.TaxonBaseDefaultCacheStrategy;
38
import eu.etaxonomy.cdm.validation.Level3;
39
import eu.etaxonomy.cdm.validation.annotation.HomotypicSynonymsShouldBelongToGroup;
40

    
41
/**
42
 * The class for synonyms: these are {@link TaxonBase taxa} the {@link name.TaxonName 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 {@link #getAcceptedTaxon() attached} to an accepted {@link Taxon taxon}
47
 * are actually meaningless.<BR>
48
 * Splitting taxa in "accepted/valid" and "synonyms"
49
 * makes it easier to handle particular relationships between
50
 * ("accepted/valid") {@link Taxon taxa} on the one hand and ("synonym") taxa
51
 *  on the other.
52
 *
53
 * @author m.doering
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 = 6977221584815363620L;
71

    
72

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

    
76

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

    
87

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

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

    
94

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

    
101
//************************************* FACTORY ****************************/
102
    /**
103
     * @see #NewInstance(TaxonName, Reference)
104
     * @param taxonName
105
     * @param sec
106
     * @return
107
     */
108
    public static Synonym NewInstance(ITaxonNameBase taxonName, Reference sec){
109
        return NewInstance(TaxonName.castAndDeproxy(taxonName), sec);
110
    }
111

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

    
126
    public static Synonym NewInstance(TaxonName taxonName, Reference sec, String secDetail){
127
        Synonym result = new Synonym(taxonName, sec, secDetail);
128
        return result;
129
    }
130

    
131
// ************* CONSTRUCTORS *************/
132
	/**
133
	 * Class constructor: creates a new empty synonym instance.
134
	 *
135
	 * @see 	#Synonym(TaxonName, Reference)
136
	 */
137
	//TODO should be private, but still produces Spring init errors
138
	public Synonym(){
139
		this.cacheStrategy = new TaxonBaseDefaultCacheStrategy<Synonym>();
140
	}
141

    
142
	private Synonym(TaxonName taxonName, Reference sec, String secDetail){
143
		super(taxonName, sec, secDetail);
144
		this.cacheStrategy = new TaxonBaseDefaultCacheStrategy<Synonym>();
145
	}
146

    
147
//********************** GETTER/SETTER ******************************/
148

    
149
	/**
150
	 * Returns the "accepted/valid" {@link Taxon taxon}
151
	 *
152
	 */
153
	public Taxon getAcceptedTaxon() {
154
		return this.acceptedTaxon;
155
	}
156

    
157

    
158
    /**
159
     * @param acceptedTaxon the acceptedTaxon to set
160
     */
161
    protected void setAcceptedTaxon(Taxon acceptedTaxon) {
162
        if (acceptedTaxon == null){
163
            Taxon oldTaxon = this.acceptedTaxon;
164
            this.acceptedTaxon = null;
165
            oldTaxon.removeSynonym(this);
166
        }else{
167
            if (this.acceptedTaxon != null){
168
                this.acceptedTaxon.removeSynonym(this, false);
169
            }
170
            this.acceptedTaxon = acceptedTaxon;
171
            this.acceptedTaxon.addSynonym(this);
172
            checkHomotypic();
173
        }
174
    }
175

    
176
    /**
177
     * Returns "true" if the proParte flag is set.
178
     * This indicates that the {@link name.TaxonName taxon name} used as a
179
     * {@link Synonym synonym} designated originally a real taxon which later has
180
     * been split. In this case the synonym is therefore the synonym of at least
181
     * two different ("accepted/valid") {@link Taxon taxa}.
182
     */
183
    public boolean isProParte() {
184
        return proParte;
185
    }
186

    
187
    /**
188
     * @see #isProParte()
189
     */
190
    public void setProParte(boolean proParte) {
191
        this.proParte = proParte;
192
    }
193

    
194
    /**
195
     * Returns "true" if the ProParte flag is set.
196
     * This indicates that the {@link name.TaxonName taxon name} used as <code>this</code>
197
     * {@link Synonym synonym} designated originally a real taxon which later has
198
     * been lumped together with another one. In this case the
199
     * ("accepted/valid") {@link Taxon taxon} has therefore at least
200
     * two different synonyms (for the two lumped real taxa).
201
     */
202
    public boolean isPartial() {
203
        return partial;
204
    }
205

    
206
    /**
207
     * @see #isPartial()
208
     */
209
    public void setPartial(boolean partial) {
210
        this.partial = partial;
211
    }
212

    
213

    
214
    public SynonymType getType() {
215
        return type;
216
    }
217

    
218
    public void setType(SynonymType type) {
219
        this.type = type;
220
        checkHomotypic();
221
    }
222

    
223

    
224
//***************** METHODS **************************/
225
	/**
226
	 * Returns true if <i>this</i> is a synonym of the given taxon.
227
	 *
228
	 * @param taxon	the taxon to check synonym for
229
	 * @return	true if <i>this</i> is a synonm of the given taxon
230
	 *
231
	 * @see #getAcceptedTaxon()
232
	 */
233
	@Transient
234
	public boolean isSynonymOf(Taxon taxon){
235
		return taxon != null && taxon.equals(this.acceptedTaxon);
236
	}
237

    
238
	@Override
239
    @Transient
240
	public boolean isOrphaned() {
241
	    return this.acceptedTaxon == null || this.acceptedTaxon.isOrphaned();
242
	}
243

    
244
    /**
245
     * Checks if the synonym type is homotypic. If it is
246
     * the name of <code>this</code> synonym is added to the {@link HomotypicalGroup
247
     * homotypic group} of the {@link Taxon accepted taxon}.
248
     */
249
    private void checkHomotypic() {
250
        if (type != null && type.equals(SynonymType.HOMOTYPIC_SYNONYM_OF())
251
                && acceptedTaxon != null && acceptedTaxon.getName() != null){
252
                acceptedTaxon.getName().getHomotypicalGroup().addTypifiedName(this.getName());
253
        }
254
    }
255

    
256
//*********************** CLONE ********************************************************/
257

    
258
	@Override
259
	public Object clone() {
260
		Synonym result;
261
		result = (Synonym)super.clone();
262

    
263
		//no changes to accepted taxon, type, partial, proParte
264

    
265
		return result;
266

    
267
	}
268

    
269

    
270
}
(7-7/20)