Project

General

Profile

Download (17.7 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
import org.hibernate.search.annotations.ClassBridge;
37
import org.hibernate.search.annotations.ClassBridges;
38
import org.hibernate.search.annotations.ContainedIn;
39
import org.hibernate.search.annotations.Field;
40

    
41
import eu.etaxonomy.cdm.hibernate.search.DescriptionBaseClassBridge;
42
import eu.etaxonomy.cdm.hibernate.search.GroupByTaxonClassBridge;
43
import eu.etaxonomy.cdm.model.common.IdentifiableEntity;
44
import eu.etaxonomy.cdm.model.name.NameRelationship;
45
import eu.etaxonomy.cdm.model.name.TypeDesignationBase;
46
import eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationBase;
47
import eu.etaxonomy.cdm.model.reference.Reference;
48
import eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy;
49

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

    
66
@XmlAccessorType(XmlAccessType.FIELD)
67
@XmlType(name = "DescriptionBase", propOrder = {
68
    "describedSpecimenOrObservations",
69
    "descriptionSources",
70
    "descriptiveSystem",
71
    "workingSets",
72
    "descriptionElements",
73
    "imageGallery"
74
})
75
@Entity
76
@Audited
77
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
78
@ClassBridges({
79
    @ClassBridge(impl=DescriptionBaseClassBridge.class),
80
    @ClassBridge(impl=GroupByTaxonClassBridge.class)
81
})
82
public abstract class DescriptionBase<S extends IIdentifiableEntityCacheStrategy> extends IdentifiableEntity<S> {
83
    private static final long serialVersionUID = 5504218413819040193L;
84
    private static final Logger logger = Logger.getLogger(DescriptionBase.class);
85

    
86
    @XmlElementWrapper(name = "DescribedSpecimenOrObservations")
87
    @XmlElement(name = "DescribedSpecimenOrObservation")
88
    @XmlIDREF
89
    @XmlSchemaType(name="IDREF")
90
    @ManyToMany(fetch = FetchType.LAZY)
91
    @Cascade(CascadeType.SAVE_UPDATE)
92
    private Set<SpecimenOrObservationBase> describedSpecimenOrObservations = new HashSet<SpecimenOrObservationBase>();
93

    
94
    @XmlElementWrapper(name = "DescriptionSources")
95
    @XmlElement(name = "DescriptionSource")
96
    @XmlIDREF
97
    @XmlSchemaType(name="IDREF")
98
    @ManyToMany(fetch = FetchType.LAZY)  //FIXME what is the difference between this and IdentifiableEntity.sources
99
    private Set<Reference> descriptionSources = new HashSet<Reference>();
100

    
101
    @XmlElementWrapper(name = "DescriptiveSystem")
102
    @XmlElement(name = "Feature")
103
    @XmlIDREF
104
    @XmlSchemaType(name="IDREF")
105
    @ManyToMany(fetch = FetchType.LAZY)  //FIXME
106
    //@Cascade( { CascadeType.SAVE_UPDATE, CascadeType.MERGE })
107
    @JoinTable(name = "DescriptionBase_Feature")
108
    @Deprecated //will probably be removed in future versions due to #2240
109
    //fortunately never worked well due to missing cascade #1846
110
    private Set<Feature> descriptiveSystem = new HashSet<Feature>();
111

    
112
    @XmlElementWrapper(name = "WorkingSets")
113
    @XmlElement(name = "WorkingSet")
114
    @XmlIDREF
115
    @XmlSchemaType(name = "IDREF")
116
    @ManyToMany(fetch = FetchType.LAZY, mappedBy = "descriptions")
117
    @Cascade(CascadeType.SAVE_UPDATE)
118
    private Set<WorkingSet> workingSets = new HashSet<WorkingSet>();
119

    
120
    @XmlElementWrapper(name = "DescriptionElements")
121
    @XmlElements({
122
        @XmlElement(name = "CategorialData", namespace = "http://etaxonomy.eu/cdm/model/description/1.0", type = CategoricalData.class),
123
        @XmlElement(name = "CommonTaxonName", namespace = "http://etaxonomy.eu/cdm/model/description/1.0", type = CommonTaxonName.class),
124
        @XmlElement(name = "Distribution", namespace = "http://etaxonomy.eu/cdm/model/description/1.0", type = Distribution.class),
125
        @XmlElement(name = "IndividualsAssociation", namespace = "http://etaxonomy.eu/cdm/model/description/1.0", type = IndividualsAssociation.class),
126
        @XmlElement(name = "QuantitativeData", namespace = "http://etaxonomy.eu/cdm/model/description/1.0", type = QuantitativeData.class),
127
        @XmlElement(name = "TaxonInteraction", namespace = "http://etaxonomy.eu/cdm/model/description/1.0", type = TaxonInteraction.class),
128
        @XmlElement(name = "TextData", namespace = "http://etaxonomy.eu/cdm/model/description/1.0", type = TextData.class)
129
    })
130
    @OneToMany(fetch=FetchType.LAZY, mappedBy = "inDescription")
131
    @Cascade( { CascadeType.SAVE_UPDATE, CascadeType.MERGE, CascadeType.DELETE, CascadeType.DELETE_ORPHAN })
132
    @ContainedIn
133
    private Set<DescriptionElementBase> descriptionElements = new HashSet<DescriptionElementBase>();
134

    
135
    @XmlElement(name = "ImageGallery")
136
    private boolean imageGallery;
137

    
138

    
139
    /**
140
     * Returns the set of {@link SpecimenOrObservationBase specimens or observations} involved in
141
     * <i>this</i> description as a whole. {@link TaxonDescription Taxon descriptions} are also often based
142
     * on concrete specimens or observations. For {@link TaxonNameDescription taxon name descriptions}
143
     * this set should be empty.
144
     *
145
     * @see    #addDescribedSpecimenOrObservations(SpecimenOrObservationBase)
146
     * @see    #removeDescribedSpecimenOrObservations(SpecimenOrObservationBase)
147
     */
148
    public Set<SpecimenOrObservationBase> getDescribedSpecimenOrObservations() {
149
        return describedSpecimenOrObservations;
150
    }
151

    
152
    /**
153
     * Adds an existing {@link SpecimenOrObservationBase specimen or observation} to the set of
154
     * {@link #getDescribedSpecimenOrObservations() specimens or observations} described in <i>this</i>
155
     * description or which <i>this</i> description is based on.<BR>
156
     * Due to bidirectionality if <i>this</i> description is a {@link SpecimenDescription specimen description},
157
     * <i>this</i> description will also be added to the set of specimen
158
     * descriptions corresponding to the given additional specimen or observation.
159
     *
160
     * @param describedSpecimenOrObservation	the specimen or observation to be added to <i>this</i> description
161
     * @see    	   								#getDescribedSpecimenOrObservations()
162
     * @see    	   								SpecimenOrObservationBase#addDescription(DescriptionBase)
163
     */
164
    public void addDescribedSpecimenOrObservation(SpecimenOrObservationBase describedSpecimenOrObservation) {
165
        logger.debug("addDescribedSpecimenOrObservations");
166
        this.describedSpecimenOrObservations.add(describedSpecimenOrObservation);
167
        if (! describedSpecimenOrObservation.getDescriptions().contains(this)){
168
            describedSpecimenOrObservation.addDescription(this);
169
        }
170
    }
171

    
172
    /**
173
     * Removes one element from the set of {@link #getDescribedSpecimenOrObservations() specimens or observations} involved
174
     * in <i>this</i> description.<BR>
175
     * Due to bidirectionality if <i>this</i> description is a {@link SpecimenDescription specimen description},
176
     * <i>this</i> description will also be removed from the set of specimen
177
     * descriptions corresponding to the given specimen or observation.
178
     *
179
     * @param  describedSpecimenOrObservation   the specimen or observation which should be removed
180
     * @see     		  						#getDescribedSpecimenOrObservations()
181
     * @see     		  						#addDescribedSpecimenOrObservations(SpecimenOrObservationBase)
182
     * @see     		  						SpecimenOrObservationBase#removeDescription(DescriptionBase)
183
     */
184
    public void removeDescribedSpecimenOrObservation(SpecimenOrObservationBase describedSpecimenOrObservation) {
185
        this.describedSpecimenOrObservations.remove(describedSpecimenOrObservation);
186
        if (describedSpecimenOrObservation.getDescriptions().contains(this)){
187
            describedSpecimenOrObservation.removeDescription(this);
188
        }
189
    }
190

    
191
    /**
192
     * Returns the set of {@link Reference references} used as sources for <i>this</i> description as a
193
     * whole. More than one source can be used for a general description without
194
     * assigning for each data element of the description one of those sources.
195
     *
196
     * @see    #addDescriptionSource(Reference)
197
     * @see    #removeDescriptionSource(Reference)
198
     */
199
    @Deprecated //will probably be removed in future versions due to #2240
200
    public Set<Reference> getDescriptionSources() {
201
        return this.descriptionSources;
202
    }
203

    
204
    /**
205
     * Adds an existing {@link Reference reference} to the set of
206
     * {@link #getDescriptionSources() references} used as sources for <i>this</i>
207
     * description.
208
     *
209
     * @param descriptionSource	the reference source to be added to <i>this</i> description
210
     * @see    	   				#getDescriptionSources()
211
     */
212
    @Deprecated //will probably be removed in future versions due to #2240
213
    public void addDescriptionSource(Reference descriptionSource) {
214
        this.descriptionSources.add(descriptionSource);
215
    }
216

    
217
    /**
218
     * Removes one element from the set of {@link #getDescriptionSources() references} used as
219
     * sources for <i>this</i> description.
220
     *
221
     * @param  descriptionSource	the reference source which should be deleted
222
     * @see     		  			#getDescriptionSources()
223
     * @see     		  			#addDescriptionSource(Reference)
224
     */
225
    @Deprecated //will probably be removed in future versions due to #2240
226
    public void removeDescriptionSource(Reference descriptionSource) {
227
        this.descriptionSources.remove(descriptionSource);
228
    }
229

    
230
    /**
231
     * Returns the set of {@link Feature feature} used as
232
     * features/characters/descriptors for <i>this</i> description.
233
     *
234
     * @see    #addFeature(Feature)
235
     * @see    #removeFeature(Feature)
236
     */
237
    public Set<Feature> getDescriptiveSystem() {
238
        return this.descriptiveSystem;
239
    }
240

    
241
    /**
242
     * @see    #getDescriptiveSystem()
243
     * @see    #addDescriptiveSystem(Feature)
244
     */
245
    public void setDescriptiveSystem(Set<Feature> descriptiveSystem) {
246
        this.descriptiveSystem = descriptiveSystem;
247
    }
248

    
249
    /**
250
     * Adds an existing {@link Feature feature} to the set of
251
     * {@link #getDescriptiveSystem() descriptiveSystem} used as features for
252
     * <i>this</i> description.
253
     *
254
     * @param feature	the feature to be added to the descriptive system
255
     * @see     #getDescriptiveSystem()
256
     */
257
    public void addFeature(Feature feature) {
258
        this.descriptiveSystem.add(feature);
259
    }
260

    
261
    /**
262
     * Removes one element from the set of {@link #getDescriptiveSystem() features} used as
263
     * features for <i>this</i> description.
264
     *
265
     * @param  feature	the feature which should be deleted
266
     * @see     #getDescriptiveSystem()
267
     * @see     addFeature(Feature)
268
     */
269
    public void removeFeature(Feature feature) {
270
        this.descriptiveSystem.remove(feature);
271
    }
272

    
273
    /**
274
     * Returns the set of {@link DescriptionElementBase elementary description data} which constitute
275
     * <i>this</i> description as a whole.
276
     *
277
     * @see    #addElement(DescriptionElementBase)
278
     * @see    #removeElement(DescriptionElementBase)
279
     */
280
    public Set<DescriptionElementBase> getElements() {
281
        return this.descriptionElements;
282
    }
283

    
284
    /**
285
     * Adds an existing {@link DescriptionElementBase elementary description} to the set of
286
     * {@link #getElements() elementary description data} which constitute <i>this</i>
287
     * description as a whole.
288
     * If the elementary descriptions already belongs to a description it is first removed from
289
     * the old description.
290
     *
291
     * @param element	the elementary description to be added to <i>this</i> description
292
     * @see    	   		#getDescriptionSources()
293
     */
294
    public void addElement(DescriptionElementBase element) {
295
        if (element.getInDescription() != null){
296
            element.getInDescription().removeElement(element);
297
        }
298
        element.setInDescription(this);
299
        this.descriptionElements.add(element);
300
    }
301

    
302
    /**
303
     * Removes one element from the set of {@link #getElements() elementary description data} which
304
     * constitute <i>this</i> description as a whole.
305
     *
306
     * @param  element	the reference source which should be deleted
307
     * @see     		#getElements()
308
     * @see     		#addElement(DescriptionElementBase)
309
     */
310
    public void removeElement(DescriptionElementBase element) {
311
        this.descriptionElements.remove(element);
312
        element.setInDescription(null);
313
    }
314

    
315
    /**
316
     * Returns the number of {@link DescriptionElementBase elementary description data} which constitute
317
     * <i>this</i> description as a whole. This is the cardinality of the set of
318
     * elementary description data.
319
     *
320
     * @see		#getElements()
321
     * @return	the number of elements of the elementary description data set
322
     */
323
    public int size(){
324
        return this.descriptionElements.size();
325
    }
326

    
327
    /**
328
     * @return the imageGallery
329
     */
330
    public boolean isImageGallery() {
331
        return imageGallery;
332
    }
333

    
334
    /**
335
     * @param imageGallery the imageGallery to set
336
     */
337
    public void setImageGallery(boolean imageGallery) {
338
        this.imageGallery = imageGallery;
339
    }
340

    
341

    
342
    public Set<WorkingSet> getWorkingSets() {
343
        return workingSets;
344
    }
345

    
346
    public boolean addWorkingSet(WorkingSet workingSet){
347
        boolean result = this.workingSets.add(workingSet);
348
        if (! workingSet.getDescriptions().contains(this)){
349
            workingSet.addDescription(this);
350
        }
351
        return result;
352
    }
353

    
354
    public boolean removeWorkingSet(WorkingSet workingSet){
355
        boolean result = this.workingSets.remove(workingSet);
356
        if (workingSet.getDescriptions().contains(this)){
357
            workingSet.addDescription(this);
358
        }
359
        return result;
360
    }
361

    
362
    protected void setWorkingSets(Set<WorkingSet> workingSets) {
363
        this.workingSets = workingSets;
364
    }
365

    
366

    
367

    
368
    @Transient
369
    public boolean hasStructuredData(){
370
        for (DescriptionElementBase element : this.getElements()){
371
            if (element.isInstanceOf(QuantitativeData.class) ||
372
                    element.isInstanceOf(CategoricalData.class)){
373
                return true;
374
            }
375
        }
376
        return false;
377
    }
378

    
379

    
380
//*********************** CLONE ********************************************************/
381

    
382
    /**
383
     * Clones <i>this</i> descriptioin. This is a shortcut that enables to create
384
     * a new instance that differs only slightly from <i>this</i> description by
385
     * modifying only some of the attributes.<BR>
386
     *
387
     * Usages of this name in a taxon concept are NOT cloned.<BR>
388
     * The name is added to the same homotypical group as the original name
389
     * (CAUTION: this behaviour needs to be discussed and may change in future).<BR>
390
     * {@link TaxonNameDescription Name descriptions} are cloned as XXX.<BR>
391
     * {@link TypeDesignationBase Type designations} are cloned as XXX.<BR>
392
     * {@link NameRelationship Name relation} are cloned as XXX.<BR>
393
     *
394
     * @see eu.etaxonomy.cdm.model.media.IdentifiableEntity#clone()
395
     * @see java.lang.Object#clone()
396
     */
397
    @Override
398
    public Object clone()  {
399
        DescriptionBase result;
400
        try{
401
            result = (DescriptionBase)super.clone();
402

    
403
            //descriptive system
404
            result.descriptiveSystem = new HashSet<Feature>();
405
            for (Feature feature : getDescriptiveSystem()){
406
                result.descriptiveSystem.add(feature);
407
            }
408

    
409
            //working set
410
            result.workingSets = new HashSet<WorkingSet>();
411
            for (WorkingSet workingSet : getWorkingSets()){
412
                workingSet.addDescription(result);
413
            }
414

    
415
            //descriptions
416
            result.descriptionSources = new HashSet<Reference>();
417
            for (Reference reference : getDescriptionSources()){
418
                result.descriptionSources.add(reference);
419
            }
420

    
421
            //elements
422
            result.descriptionElements = new HashSet<DescriptionElementBase>();
423
            for (DescriptionElementBase element : getElements()){
424
                DescriptionElementBase newElement = (DescriptionElementBase)element.clone();
425
                result.addElement(newElement);
426
            }
427

    
428
            //specimen or observations
429
            result.describedSpecimenOrObservations = new HashSet<SpecimenOrObservationBase>();
430
            for (SpecimenOrObservationBase specimenOrObservation : getDescribedSpecimenOrObservations()){
431
                specimenOrObservation.addDescription(result);
432
            }
433

    
434
            //no changes to: imageGallery
435
            return result;
436
        } catch (CloneNotSupportedException e) {
437
            logger.warn("Object does not implement cloneable");
438
            e.printStackTrace();
439
            return null;
440
        }
441

    
442
    }
443
}
(4-4/40)