Project

General

Profile

Download (16 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.description;
11

    
12
import java.util.HashSet;
13
import java.util.Set;
14

    
15
import javax.persistence.Entity;
16
import javax.persistence.FetchType;
17
import javax.persistence.Inheritance;
18
import javax.persistence.InheritanceType;
19
import javax.persistence.JoinTable;
20
import javax.persistence.ManyToMany;
21
import javax.persistence.OneToMany;
22
import javax.persistence.Transient;
23
import javax.xml.bind.annotation.XmlAccessType;
24
import javax.xml.bind.annotation.XmlAccessorType;
25
import javax.xml.bind.annotation.XmlElement;
26
import javax.xml.bind.annotation.XmlElementWrapper;
27
import javax.xml.bind.annotation.XmlElements;
28
import javax.xml.bind.annotation.XmlIDREF;
29
import javax.xml.bind.annotation.XmlSchemaType;
30
import javax.xml.bind.annotation.XmlType;
31

    
32
import org.apache.log4j.Logger;
33
import org.hibernate.annotations.Cascade;
34
import org.hibernate.annotations.CascadeType;
35
import org.hibernate.envers.Audited;
36

    
37
import eu.etaxonomy.cdm.model.common.IdentifiableEntity;
38
import eu.etaxonomy.cdm.model.name.NameRelationship;
39
import eu.etaxonomy.cdm.model.name.TypeDesignationBase;
40
import eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationBase;
41
import eu.etaxonomy.cdm.model.reference.Reference;
42
import eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy;
43

    
44
/**
45
 * The upmost (abstract) class for a description as a whole (with possibly
46
 * several {@link DescriptionElementBase elementary information data})
47
 * for a {@link SpecimenOrObservationBase specimen}, a {@link Taxon taxon}
48
 * or even a {@link TaxonNameBase taxon name}.
49
 * <P>
50
 * This class corresponds to: <ul>
51
 * <li> DescriptionsSectionType according to the the SDD schema
52
 * <li> MeasurementOrFact according to the ABCD schema
53
 * </ul>
54
 * 
55
 * @author m.doering
56
 * @version 1.0
57
 * @created 08-Nov-2007 13:06:24
58
 */
59

    
60
@XmlAccessorType(XmlAccessType.FIELD)
61
@XmlType(name = "DescriptionBase", propOrder = {
62
    "describedSpecimenOrObservations",
63
    "descriptionSources",
64
    "descriptiveSystem",
65
    "workingSets",
66
    "descriptionElements",
67
    "imageGallery"
68
})
69
@Entity
70
@Audited
71
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
72
public abstract class DescriptionBase<S extends IIdentifiableEntityCacheStrategy> extends IdentifiableEntity<S> {
73
	private static final long serialVersionUID = 5504218413819040193L;
74
	private static final Logger logger = Logger.getLogger(DescriptionBase.class);
75
	
76
	@XmlElementWrapper(name = "DescribedSpecimenOrObservations")
77
	@XmlElement(name = "DescribedSpecimenOrObservation")
78
	@XmlIDREF
79
	@XmlSchemaType(name="IDREF")
80
	@ManyToMany(fetch = FetchType.LAZY)
81
	@Cascade(CascadeType.SAVE_UPDATE)
82
	private Set<SpecimenOrObservationBase> describedSpecimenOrObservations = new HashSet<SpecimenOrObservationBase>();
83
	
84
	@XmlElementWrapper(name = "DescriptionSources")
85
	@XmlElement(name = "DescriptionSource")
86
	@XmlIDREF
87
	@XmlSchemaType(name="IDREF")
88
	@ManyToMany(fetch = FetchType.LAZY)  //FIXME what is the difference between this and IdentifiableEntity.sources
89
	private Set<Reference> descriptionSources = new HashSet<Reference>();
90
	
91
	@XmlElementWrapper(name = "DescriptiveSystem")
92
	@XmlElement(name = "Feature")
93
	@XmlIDREF
94
	@XmlSchemaType(name="IDREF")
95
	@ManyToMany(fetch = FetchType.LAZY)  //FIXME
96
    //@Cascade( { CascadeType.SAVE_UPDATE, CascadeType.MERGE })
97
    @JoinTable(name = "DescriptionBase_Feature")
98
	@Deprecated //will probably be removed in future versions due to #2240
99
	//fortunately never worked well due to missing cascade #1846
100
    private Set<Feature> descriptiveSystem = new HashSet<Feature>();
101
	
102
	@XmlElementWrapper(name = "WorkingSets")
103
	@XmlElement(name = "WorkingSet")
104
    @XmlIDREF
105
    @XmlSchemaType(name = "IDREF")
106
    @ManyToMany(fetch = FetchType.LAZY, mappedBy = "descriptions")
107
	@Cascade(CascadeType.SAVE_UPDATE)
108
	private Set<WorkingSet> workingSets = new HashSet<WorkingSet>();
109
	
110
	@XmlElementWrapper(name = "DescriptionElements")
111
    @XmlElements({
112
        @XmlElement(name = "CategorialData", namespace = "http://etaxonomy.eu/cdm/model/description/1.0", type = CategoricalData.class),
113
        @XmlElement(name = "CommonTaxonName", namespace = "http://etaxonomy.eu/cdm/model/description/1.0", type = CommonTaxonName.class),
114
        @XmlElement(name = "Distribution", namespace = "http://etaxonomy.eu/cdm/model/description/1.0", type = Distribution.class),
115
        @XmlElement(name = "IndividualsAssociation", namespace = "http://etaxonomy.eu/cdm/model/description/1.0", type = IndividualsAssociation.class),
116
        @XmlElement(name = "QuantitativeData", namespace = "http://etaxonomy.eu/cdm/model/description/1.0", type = QuantitativeData.class),
117
        @XmlElement(name = "TaxonInteraction", namespace = "http://etaxonomy.eu/cdm/model/description/1.0", type = TaxonInteraction.class),
118
        @XmlElement(name = "TextData", namespace = "http://etaxonomy.eu/cdm/model/description/1.0", type = TextData.class)
119
    })
120
    @OneToMany(fetch=FetchType.LAZY, mappedBy = "inDescription")
121
	@Cascade( { CascadeType.SAVE_UPDATE, CascadeType.MERGE, CascadeType.DELETE, CascadeType.DELETE_ORPHAN })
122
	private Set<DescriptionElementBase> descriptionElements = new HashSet<DescriptionElementBase>();
123

    
124
	@XmlElement(name = "ImageGallery")
125
	private boolean imageGallery;
126
	
127
	
128
	/**
129
	 * Returns the set of {@link SpecimenOrObservationBase specimens or observations} involved in
130
	 * <i>this</i> description as a whole. {@link TaxonDescription Taxon descriptions} are also often based
131
	 * on concrete specimens or observations. For {@link TaxonNameDescription taxon name descriptions}
132
	 * this set should be empty.
133
	 * 
134
	 * @see    #addDescribedSpecimenOrObservations(SpecimenOrObservationBase)
135
	 * @see    #removeDescribedSpecimenOrObservations(SpecimenOrObservationBase)
136
	 */
137
	public Set<SpecimenOrObservationBase> getDescribedSpecimenOrObservations() {
138
		return describedSpecimenOrObservations;
139
	}
140
	
141
	/**
142
	 * Adds an existing {@link SpecimenOrObservationBase specimen or observation} to the set of
143
	 * {@link #getDescribedSpecimenOrObservations() specimens or observations} described in <i>this</i>
144
	 * description or which <i>this</i> description is based on.<BR>
145
	 * Due to bidirectionality if <i>this</i> description is a {@link SpecimenDescription specimen description},
146
	 * <i>this</i> description will also be added to the set of specimen
147
	 * descriptions corresponding to the given additional specimen or observation.
148
	 * 
149
	 * @param describedSpecimenOrObservation	the specimen or observation to be added to <i>this</i> description
150
	 * @see    	   								#getDescribedSpecimenOrObservations()
151
	 * @see    	   								SpecimenOrObservationBase#addDescription(DescriptionBase)
152
	 */
153
	public void addDescribedSpecimenOrObservation(SpecimenOrObservationBase describedSpecimenOrObservation) {
154
		logger.debug("addDescribedSpecimenOrObservations");
155
		this.describedSpecimenOrObservations.add(describedSpecimenOrObservation);
156
		if (! describedSpecimenOrObservation.getDescriptions().contains(this)){
157
			describedSpecimenOrObservation.addDescription(this);
158
		}
159
	}
160
	
161
	/** 
162
	 * Removes one element from the set of {@link #getDescribedSpecimenOrObservations() specimens or observations} involved
163
	 * in <i>this</i> description.<BR>
164
	 * Due to bidirectionality if <i>this</i> description is a {@link SpecimenDescription specimen description},
165
	 * <i>this</i> description will also be removed from the set of specimen
166
	 * descriptions corresponding to the given specimen or observation.
167
	 *
168
	 * @param  describedSpecimenOrObservation   the specimen or observation which should be removed
169
	 * @see     		  						#getDescribedSpecimenOrObservations()
170
	 * @see     		  						#addDescribedSpecimenOrObservations(SpecimenOrObservationBase)
171
	 * @see     		  						SpecimenOrObservationBase#removeDescription(DescriptionBase)
172
	 */
173
	public void removeDescribedSpecimenOrObservation(SpecimenOrObservationBase describedSpecimenOrObservation) {
174
		this.describedSpecimenOrObservations.remove(describedSpecimenOrObservation);
175
		if (describedSpecimenOrObservation.getDescriptions().contains(this)){
176
			describedSpecimenOrObservation.removeDescription(this);
177
		}
178
	}
179

    
180
	/**
181
	 * Returns the set of {@link Reference references} used as sources for <i>this</i> description as a
182
	 * whole. More than one source can be used for a general description without
183
	 * assigning for each data element of the description one of those sources. 
184
	 * 
185
	 * @see    #addDescriptionSource(Reference)
186
	 * @see    #removeDescriptionSource(Reference)
187
	 */
188
	@Deprecated //will probably be removed in future versions due to #2240
189
	public Set<Reference> getDescriptionSources() {
190
		return this.descriptionSources;
191
	}
192
	
193
	/**
194
	 * Adds an existing {@link Reference reference} to the set of
195
	 * {@link #getDescriptionSources() references} used as sources for <i>this</i>
196
	 * description.
197
	 * 
198
	 * @param descriptionSource	the reference source to be added to <i>this</i> description
199
	 * @see    	   				#getDescriptionSources()
200
	 */
201
	@Deprecated //will probably be removed in future versions due to #2240
202
	public void addDescriptionSource(Reference descriptionSource) {
203
		this.descriptionSources.add(descriptionSource);
204
	}
205
	
206
	/** 
207
	 * Removes one element from the set of {@link #getDescriptionSources() references} used as
208
	 * sources for <i>this</i> description.
209
	 *
210
	 * @param  descriptionSource	the reference source which should be deleted
211
	 * @see     		  			#getDescriptionSources()
212
	 * @see     		  			#addDescriptionSource(Reference)
213
	 */
214
	@Deprecated //will probably be removed in future versions due to #2240
215
	public void removeDescriptionSource(Reference descriptionSource) {
216
		this.descriptionSources.remove(descriptionSource);
217
	}
218

    
219
	/**
220
	 * Returns the set of {@link Feature feature} used as 
221
	 * features/characters/descriptors for <i>this</i> description.
222
	 * 
223
	 * @see    #addFeature(Feature)
224
	 * @see    #removeFeature(Feature)
225
	 */
226
	public Set<Feature> getDescriptiveSystem() {
227
		return this.descriptiveSystem;
228
	}
229
	
230
	/** 
231
	 * @see    #getDescriptiveSystem()
232
	 * @see    #addDescriptiveSystem(Feature)
233
	 */
234
	public void setDescriptiveSystem(Set<Feature> descriptiveSystem) {
235
		this.descriptiveSystem = descriptiveSystem;
236
	}
237
	
238
	/**
239
	 * Adds an existing {@link Feature feature} to the set of
240
	 * {@link #getDescriptiveSystem() descriptiveSystem} used as features for
241
	 * <i>this</i> description.
242
	 * 
243
	 * @param feature	the feature to be added to the descriptive system
244
	 * @see     #getDescriptiveSystem()
245
	 */
246
	public void addFeature(Feature feature) {
247
		this.descriptiveSystem.add(feature);
248
	}
249
	
250
	/** 
251
	 * Removes one element from the set of {@link #getDescriptiveSystem() features} used as
252
	 * features for <i>this</i> description.
253
	 *
254
	 * @param  feature	the feature which should be deleted
255
	 * @see     #getDescriptiveSystem()
256
	 * @see     addFeature(Feature)
257
	 */
258
	public void removeFeature(Feature feature) {
259
		this.descriptiveSystem.remove(feature);
260
	}
261
	
262
	/**
263
	 * Returns the set of {@link DescriptionElementBase elementary description data} which constitute
264
	 * <i>this</i> description as a whole. 
265
	 * 
266
	 * @see    #addElement(DescriptionElementBase)
267
	 * @see    #removeElement(DescriptionElementBase)
268
	 */
269
	public Set<DescriptionElementBase> getElements() {
270
		return this.descriptionElements;
271
	}
272

    
273
	/**
274
	 * Adds an existing {@link DescriptionElementBase elementary description} to the set of
275
	 * {@link #getElements() elementary description data} which constitute <i>this</i>
276
	 * description as a whole.
277
	 * If the elementary descriptions already belongs to a description it is first removed from
278
	 * the old description.
279
	 * 
280
	 * @param element	the elementary description to be added to <i>this</i> description
281
	 * @see    	   		#getDescriptionSources()
282
	 */
283
	public void addElement(DescriptionElementBase element) {
284
		if (element.getInDescription() != null){
285
			element.getInDescription().removeElement(element);
286
		}
287
		element.setInDescription(this);
288
		this.descriptionElements.add(element);
289
	}
290

    
291
	/** 
292
	 * Removes one element from the set of {@link #getElements() elementary description data} which
293
	 * constitute <i>this</i> description as a whole.
294
	 *
295
	 * @param  element	the reference source which should be deleted
296
	 * @see     		#getElements()
297
	 * @see     		#addElement(DescriptionElementBase)
298
	 */
299
	public void removeElement(DescriptionElementBase element) {
300
		this.descriptionElements.remove(element);
301
		element.setInDescription(null);
302
	}
303
	
304
	/**
305
	 * Returns the number of {@link DescriptionElementBase elementary description data} which constitute
306
	 * <i>this</i> description as a whole. This is the cardinality of the set of
307
	 * elementary description data.
308
	 * 
309
	 * @see		#getElements()
310
	 * @return	the number of elements of the elementary description data set
311
	 */
312
	public int size(){
313
		return this.descriptionElements.size();
314
	}
315
	
316
    /**
317
	 * @return the imageGallery
318
	 */
319
	public boolean isImageGallery() {
320
		return imageGallery;
321
	}
322

    
323
	/**
324
	 * @param imageGallery the imageGallery to set
325
	 */
326
	public void setImageGallery(boolean imageGallery) {
327
		this.imageGallery = imageGallery;
328
	}
329

    
330

    
331
	public Set<WorkingSet> getWorkingSets() {
332
		return workingSets;
333
	}
334
	
335
	public boolean addWorkingSet(WorkingSet workingSet){
336
		boolean result = this.workingSets.add(workingSet);
337
		if (! workingSet.getDescriptions().contains(this)){
338
			workingSet.addDescription(this);
339
		}
340
		return result;
341
	}
342
	
343
	public boolean removeWorkingSet(WorkingSet workingSet){
344
		boolean result = this.workingSets.remove(workingSet);
345
		if (workingSet.getDescriptions().contains(this)){
346
			workingSet.addDescription(this);
347
		}
348
		return result;
349
	}
350

    
351
	protected void setWorkingSets(Set<WorkingSet> workingSets) {
352
		this.workingSets = workingSets;
353
	}
354

    
355

    
356
	
357
	@Transient
358
	public boolean hasStructuredData(){
359
		for (DescriptionElementBase element : this.getElements()){
360
			if (element.isInstanceOf(QuantitativeData.class) ||
361
					element.isInstanceOf(CategoricalData.class)){
362
				return true;
363
			}
364
		}
365
		return false;
366
	}
367
	
368
	
369
//*********************** CLONE ********************************************************/
370
	
371
	/** 
372
	 * Clones <i>this</i> descriptioin. This is a shortcut that enables to create
373
	 * a new instance that differs only slightly from <i>this</i> description by
374
	 * modifying only some of the attributes.<BR>
375
     *
376
	 * Usages of this name in a taxon concept are NOT cloned.<BR>
377
	 * The name is added to the same homotypical group as the original name 
378
	 * (CAUTION: this behaviour needs to be discussed and may change in future).<BR>
379
	 * {@link TaxonNameDescription Name descriptions} are cloned as XXX.<BR>
380
	 * {@link TypeDesignationBase Type designations} are cloned as XXX.<BR>
381
	 * {@link NameRelationship Name relation} are cloned as XXX.<BR>
382
	 *  
383
	 * @see eu.etaxonomy.cdm.model.media.IdentifiableEntity#clone()
384
	 * @see java.lang.Object#clone()
385
	 */
386
	@Override
387
	public Object clone()  {
388
		DescriptionBase result;
389
		try{
390
			result = (DescriptionBase)super.clone();
391
			
392
			//descriptive system
393
			result.descriptiveSystem = new HashSet<Feature>();
394
			for (Feature feature : getDescriptiveSystem()){
395
				result.descriptiveSystem.add(feature);
396
			}
397
			
398
			//working set
399
			result.workingSets = new HashSet<WorkingSet>();
400
			for (WorkingSet workingSet : getWorkingSets()){
401
				workingSet.addDescription(result);
402
			}
403
			
404
			//descriptions
405
			result.descriptionSources = new HashSet<Reference>();
406
			for (Reference reference : getDescriptionSources()){
407
				result.descriptionSources.add(reference);
408
			}
409

    
410
			//elements
411
			result.descriptionElements = new HashSet<DescriptionElementBase>();
412
			for (DescriptionElementBase element : getElements()){
413
				DescriptionElementBase newElement = (DescriptionElementBase)element.clone();
414
				result.addElement(newElement);
415
			}
416

    
417
			//specimen or observations
418
			result.describedSpecimenOrObservations = new HashSet<SpecimenOrObservationBase>();
419
			for (SpecimenOrObservationBase specimenOrObservation : getDescribedSpecimenOrObservations()){
420
				specimenOrObservation.addDescription(result);
421
			}
422
			
423
			//no changes to: imageGallery 
424
			return result;
425
		} catch (CloneNotSupportedException e) {
426
			logger.warn("Object does not implement cloneable");
427
			e.printStackTrace();
428
			return null;
429
		}
430
		
431
	}
432
}
(4-4/40)