2 * Copyright (C) 2007 EDIT
3 * European Distributed Institute of Taxonomy
4 * http://www.e-taxonomy.eu
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.
10 package eu
.etaxonomy
.cdm
.model
.taxon
;
12 import java
.util
.HashSet
;
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
;
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
;
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
;
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.
59 * @created 08-Nov-2007 13:06:55
61 @XmlAccessorType(XmlAccessType
.FIELD
)
62 @XmlType(name
= "Synonym", propOrder
= {
65 @XmlRootElement(name
= "Synonym")
67 @Indexed(index
= "eu.etaxonomy.cdm.model.taxon.TaxonBase")
70 public class Synonym
extends TaxonBase
<ITaxonCacheStrategy
<Synonym
>> implements IRelated
<SynonymRelationship
>{
71 private static final long serialVersionUID
= -454067515022159757L;
73 @SuppressWarnings("unused")
74 private static final Logger logger
= Logger
.getLogger(Synonym
.class);
76 // Don't need the synonym relations here since they are stored at taxon side?
77 @XmlElementWrapper(name
= "SynonymRelations")
78 @XmlElement(name
= "SynonymRelationship")
80 @XmlSchemaType(name
= "IDREF")
81 @OneToMany(mappedBy
="relatedFrom", fetch
=FetchType
.LAZY
, orphanRemoval
=true)
82 @Cascade({CascadeType
.SAVE_UPDATE
, CascadeType
.MERGE
, CascadeType
.DELETE
})
84 @NotEmpty(groups
= Level2
.class,message
="{eu.etaxonomy.cdm.model.taxon.Synonym.noOrphanedSynonyms.message}")
86 private Set
<SynonymRelationship
> synonymRelations
= new HashSet
<SynonymRelationship
>();
88 // ************* CONSTRUCTORS *************/
90 * Class constructor: creates a new empty synonym instance.
92 * @see #Synonym(TaxonNameBase, Reference)
94 //TODO should be private, but still produces Spring init errors
96 this.cacheStrategy
= new TaxonBaseDefaultCacheStrategy
<Synonym
>();
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}.
104 * @param taxonNameBase the taxon name used
105 * @param sec the reference using the taxon name
106 * @see Synonym#Synonym(TaxonNameBase, Reference)
108 public Synonym(TaxonNameBase taxonNameBase
, Reference sec
){
109 super(taxonNameBase
, sec
);
110 this.cacheStrategy
= new TaxonBaseDefaultCacheStrategy
<Synonym
>();
113 //********* METHODS **************************************/
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}.
120 * @param taxonNameBase the taxon name used
121 * @param sec the reference using the taxon name
122 * @see #Synonym(TaxonNameBase, Reference)
124 public static Synonym
NewInstance(TaxonNameBase taxonName
, Reference sec
){
125 Synonym result
= new Synonym(taxonName
, sec
);
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.
134 * @see #addSynonymRelation(SynonymRelationship)
135 * @see #addRelationship(SynonymRelationship)
136 * @see #removeSynonymRelation(SynonymRelationship)
138 public Set
<SynonymRelationship
> getSynonymRelations() {
139 if(synonymRelations
== null) {
140 this.synonymRelations
= new HashSet
<SynonymRelationship
>();
142 return synonymRelations
;
146 * @see #getSynonymRelations()
148 protected void setSynonymRelations(Set
<SynonymRelationship
> synonymRelations
) {
149 this.synonymRelations
= synonymRelations
;
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.
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)
165 protected void addSynonymRelation(SynonymRelationship synonymRelation
) {
166 this.synonymRelations
.add(synonymRelation
);
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".
178 * @param synonymRelation the synonym relationship which should be deleted
179 * @see #getSynonymRelations()
180 * @see #addRelationship(SynonymRelationship)
182 public void removeSynonymRelation(SynonymRelationship synonymRelation
) {
183 synonymRelation
.setSynonym(null);
184 Taxon taxon
= synonymRelation
.getAcceptedTaxon();
186 synonymRelation
.setAcceptedTaxon(null);
187 taxon
.removeSynonymRelation(synonymRelation
);
189 this.synonymRelations
.remove(synonymRelation
);
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.
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)
207 * @see eu.etaxonomy.cdm.model.common.IRelated#addRelationship(eu.etaxonomy.cdm.model.common.RelationshipBase)
210 public void addRelationship(SynonymRelationship rel
){
211 addSynonymRelation(rel
);
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.
224 * @see #getSynonymRelations()
225 * @see #getRelationType(Taxon)
226 * @see SynonymRelationship#isProParte()
229 public Set
<Taxon
> getAcceptedTaxa() {
230 Set
<Taxon
>taxa
=new HashSet
<Taxon
>();
231 for (SynonymRelationship rel
:getSynonymRelations()){
232 taxa
.add(rel
.getAcceptedTaxon());
238 * Returns true if <i>this</i> is a synonym of the given taxon.
240 * @param taxon the taxon to check synonym for
241 * @return true if <i>this</i> is a ynonms of the given taxon
243 * @see #getAcceptedTaxa()
246 public boolean isSynonymOf(Taxon taxon
){
247 return getAcceptedTaxa().contains(taxon
);
252 public boolean isOrphaned() {
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
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()
268 public Set
<SynonymRelationshipType
> getRelationType(Taxon taxon
){
269 Set
<SynonymRelationshipType
> result
= new HashSet
<SynonymRelationshipType
>();
273 for (SynonymRelationship rel
: getSynonymRelations()){
274 Taxon acceptedTaxon
= rel
.getAcceptedTaxon();
275 if (taxon
.equals(acceptedTaxon
)){
276 result
.add(rel
.getType());
283 * Replaces ALL accepted taxa of this synonym by the new accepted taxon.
284 * The citation information (citation /microcitation) of the synonym relationship
286 * @param newAcceptedTaxon
287 * the new accepted taxon
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
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.
300 * @param acceptedTaxon
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
306 for (SynonymRelationship rel
: rels
){
307 Taxon oldAcceptedTaxon
= rel
.getAcceptedTaxon();
308 Synonym syn
= rel
.getSynonym();
310 oldAcceptedTaxon
.removeSynonym(rel
.getSynonym(), false);
312 SynonymRelationship newRel
= (SynonymRelationship
)rel
.clone();
313 newRel
.setAcceptedTaxon(newAcceptedTaxon
);
314 newAcceptedTaxon
.getSynonymRelations().add(newRel
);
315 newRel
.setSynonym(syn
);
316 syn
.addSynonymRelation(newRel
);
318 newRel
.setType(relType
);
321 //*********************** CLONE ********************************************************/
324 public Object
clone() {
326 result
= (Synonym
)super.clone();
328 result
.setSynonymRelations(new HashSet
<SynonymRelationship
>());
330 for (SynonymRelationship synRelationship
: this.getSynonymRelations()){
331 SynonymRelationship newRelationship
= (SynonymRelationship
)synRelationship
.clone();
332 newRelationship
.setRelatedFrom(result
);
333 result
.synonymRelations
.add(newRelationship
);