Project

General

Profile

Download (14.9 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.JoinColumn;
20
import javax.persistence.ManyToMany;
21
import javax.persistence.ManyToOne;
22
import javax.persistence.OneToMany;
23
import javax.persistence.Transient;
24
import javax.xml.bind.annotation.XmlAccessType;
25
import javax.xml.bind.annotation.XmlAccessorType;
26
import javax.xml.bind.annotation.XmlElement;
27
import javax.xml.bind.annotation.XmlElementWrapper;
28
import javax.xml.bind.annotation.XmlElements;
29
import javax.xml.bind.annotation.XmlIDREF;
30
import javax.xml.bind.annotation.XmlSchemaType;
31
import javax.xml.bind.annotation.XmlType;
32

    
33
import org.apache.log4j.Logger;
34
import org.hibernate.annotations.Cascade;
35
import org.hibernate.annotations.CascadeType;
36
import org.hibernate.envers.Audited;
37
import org.hibernate.search.annotations.ClassBridge;
38
import org.hibernate.search.annotations.ClassBridges;
39
import org.hibernate.search.annotations.ContainedIn;
40
import org.hibernate.search.annotations.FieldBridge;
41

    
42
import eu.etaxonomy.cdm.hibernate.HHH_9751_Util;
43
import eu.etaxonomy.cdm.hibernate.search.DescriptionBaseClassBridge;
44
import eu.etaxonomy.cdm.hibernate.search.GroupByTaxonClassBridge;
45
import eu.etaxonomy.cdm.hibernate.search.NotNullAwareIdBridge;
46
import eu.etaxonomy.cdm.model.common.IdentifiableEntity;
47
import eu.etaxonomy.cdm.model.name.NameRelationship;
48
import eu.etaxonomy.cdm.model.name.TaxonName;
49
import eu.etaxonomy.cdm.model.name.TypeDesignationBase;
50
import eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationBase;
51
import eu.etaxonomy.cdm.model.reference.Reference;
52
import eu.etaxonomy.cdm.model.taxon.Taxon;
53
import eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy;
54

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

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

    
91
    @XmlElement( name = "DescribedSpecimenOrObservation")
92
    @ManyToOne(fetch = FetchType.LAZY)
93
    @XmlIDREF
94
    @XmlSchemaType(name="IDREF")
95
    @Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE})
96
    @JoinColumn(name="specimen_id")
97
    @FieldBridge(impl=NotNullAwareIdBridge.class)
98
    //TODO maybe move down to specific classes SpecimenDescription (with Cascade.Delete) and TaxonDescription (without Cascade)
99
    private SpecimenOrObservationBase<?> describedSpecimenOrObservation;
100

    
101

    
102
    @XmlElementWrapper(name = "DescriptionSources")
103
    @XmlElement(name = "DescriptionSource")
104
    @XmlIDREF
105
    @XmlSchemaType(name="IDREF")
106
    @ManyToMany(fetch = FetchType.LAZY)  //FIXME what is the difference between this and IdentifiableEntity.sources
107
    private Set<Reference> descriptionSources = new HashSet<Reference>();
108

    
109
    @XmlElementWrapper(name = "DescriptiveDataSets")
110
    @XmlElement(name = "DescriptiveDataSet")
111
    @XmlIDREF
112
    @XmlSchemaType(name = "IDREF")
113
    @ManyToMany(fetch = FetchType.LAZY, mappedBy = "descriptions")
114
    @Cascade({CascadeType.SAVE_UPDATE,CascadeType.MERGE})
115
    private Set<DescriptiveDataSet> descriptiveDataSets = new HashSet<>();
116

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

    
132
    @XmlElement(name = "ImageGallery")
133
    private boolean imageGallery;
134

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

    
138

    
139
    /**
140
     * Returns a {@link SpecimenOrObservationBase specimen or observation} 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 attribute should be empty.
144
     * To handle sets of specimen or observations one may first group them by a derivation event of type
145
     * "Grouping" and then use the grouped unit here.
146
     * @return
147
     */
148
    public SpecimenOrObservationBase getDescribedSpecimenOrObservation() {
149
		return describedSpecimenOrObservation;
150
	}
151

    
152

    
153
	/**
154
	 * @see #getDescribedSpecimenOrObservation()
155
	 * @param describedSpecimenOrObservation
156
	 */
157
	//TODO bidirectional method should maybe removed as a description should belong to its specimen or taxon
158
    public void setDescribedSpecimenOrObservation(SpecimenOrObservationBase describedSpecimenOrObservation) {
159
		if (describedSpecimenOrObservation == null ){
160
			this.describedSpecimenOrObservation.removeDescription(this);
161
		}else if (! describedSpecimenOrObservation.getDescriptions().contains(this)){
162
			describedSpecimenOrObservation.addDescription(this);
163
		}
164
		this.describedSpecimenOrObservation = describedSpecimenOrObservation;
165
	}
166

    
167

    
168
	/**
169
     * Returns the set of {@link Reference references} used as sources for <i>this</i> description as a
170
     * whole. More than one source can be used for a general description without
171
     * assigning for each data element of the description one of those sources.
172
     *
173
     * @see    #addDescriptionSource(Reference)
174
     * @see    #removeDescriptionSource(Reference)
175
     */
176
    @Deprecated //will probably be removed in future versions due to #2240
177
    public Set<Reference> getDescriptionSources() {
178
        return this.descriptionSources;
179
    }
180

    
181
    /**
182
     * Adds an existing {@link Reference reference} to the set of
183
     * {@link #getDescriptionSources() references} used as sources for <i>this</i>
184
     * description.
185
     *
186
     * @param descriptionSource	the reference source to be added to <i>this</i> description
187
     * @see    	   				#getDescriptionSources()
188
     */
189
    @Deprecated //will probably be removed in future versions due to #2240
190
    public void addDescriptionSource(Reference descriptionSource) {
191
        this.descriptionSources.add(descriptionSource);
192
    }
193

    
194
    /**
195
     * Removes one element from the set of {@link #getDescriptionSources() references} used as
196
     * sources for <i>this</i> description.
197
     *
198
     * @param  descriptionSource	the reference source which should be deleted
199
     * @see     		  			#getDescriptionSources()
200
     * @see     		  			#addDescriptionSource(Reference)
201
     */
202
    @Deprecated //will probably be removed in future versions due to #2240
203
    public void removeDescriptionSource(Reference descriptionSource) {
204
        this.descriptionSources.remove(descriptionSource);
205
    }
206

    
207
    /**
208
     * Returns the set of {@link DescriptionElementBase elementary description data} which constitute
209
     * <i>this</i> description as a whole.
210
     *
211
     * @see    #addElement(DescriptionElementBase)
212
     * @see    #removeElement(DescriptionElementBase)
213
     */
214
    public Set<DescriptionElementBase> getElements() {
215
        return this.descriptionElements;
216
    }
217

    
218
    /**
219
     * Adds an existing {@link DescriptionElementBase elementary description} to the set of
220
     * {@link #getElements() elementary description data} which constitute <i>this</i>
221
     * description as a whole.
222
     * If the elementary descriptions already belongs to a description it is first removed from
223
     * the old description.
224
     *
225
     * @param element	the elementary description to be added to <i>this</i> description
226
     * @see    	   		#getDescriptionSources()
227
     */
228
    public void addElement(DescriptionElementBase element) {
229
        HHH_9751_Util.removeAllNull(this.descriptionElements);
230
        if (element.getInDescription() != null){
231
            element.getInDescription().removeElement(element);
232
        }
233
        element.setInDescription(this);
234
        this.descriptionElements.add(element);
235
    }
236

    
237
    /**
238
     * Convenience method to add multiple elements.
239
     * @param elements
240
     */
241
    public void addElements(DescriptionElementBase ... elements) {
242
        HHH_9751_Util.removeAllNull(this.descriptionElements);
243
        for (DescriptionElementBase element : elements){
244
    		addElement(element);
245
    	}
246
    }
247

    
248
    /**
249
     * Removes one element from the set of {@link #getElements() elementary description data} which
250
     * constitute <i>this</i> description as a whole.
251
     *
252
     * @param  element	the reference source which should be deleted
253
     * @see     		#getElements()
254
     * @see     		#addElement(DescriptionElementBase)
255
     */
256
    public void removeElement(DescriptionElementBase element) {
257
        HHH_9751_Util.removeAllNull(this.descriptionElements);
258
        this.descriptionElements.remove(element);
259
        element.setInDescription(null);
260
    }
261

    
262

    
263

    
264
    /**
265
     * Returns the number of {@link DescriptionElementBase elementary description data} which constitute
266
     * <i>this</i> description as a whole. This is the cardinality of the set of
267
     * elementary description data.
268
     *
269
     * @see		#getElements()
270
     * @return	the number of elements of the elementary description data set
271
     */
272
    public int size(){
273
        return this.descriptionElements.size();
274
    }
275

    
276
    /**
277
     * @return the imageGallery
278
     */
279
    public boolean isImageGallery() {
280
        return imageGallery;
281
    }
282

    
283
    /**
284
     * @param imageGallery the imageGallery to set
285
     */
286
    public void setImageGallery(boolean imageGallery) {
287
        this.imageGallery = imageGallery;
288
    }
289

    
290
    public boolean isDefault() {
291
        return isDefault;
292
    }
293

    
294
    public void setDefault(boolean isDefault) {
295
        this.isDefault = isDefault;
296
    }
297

    
298

    
299
    public Set<DescriptiveDataSet> getDescriptiveDataSets() {
300
        return descriptiveDataSets;
301
    }
302

    
303
    public boolean addDescriptiveDataSet(DescriptiveDataSet descriptiveDataSet){
304
        boolean result = this.descriptiveDataSets.add(descriptiveDataSet);
305
        if (! descriptiveDataSet.getDescriptions().contains(this)){
306
            descriptiveDataSet.addDescription(this);
307
        }
308
        return result;
309
    }
310

    
311
    public boolean removeDescriptiveDataSet(DescriptiveDataSet descriptiveDataSet){
312
        boolean result = this.descriptiveDataSets.remove(descriptiveDataSet);
313
        if (descriptiveDataSet.getDescriptions().contains(this)){
314
            descriptiveDataSet.addDescription(this);
315
        }
316
        return result;
317
    }
318

    
319
    protected void setDescriptiveDataSet(Set<DescriptiveDataSet> descriptiveDataSets) {
320
        this.descriptiveDataSets = descriptiveDataSets;
321
    }
322

    
323

    
324

    
325
    @Transient
326
    public boolean hasStructuredData(){
327
        for (DescriptionElementBase element : this.getElements()){
328
            if (element.isInstanceOf(QuantitativeData.class) ||
329
                    element.isInstanceOf(CategoricalData.class)){
330
                return true;
331
            }
332
        }
333
        return false;
334
    }
335

    
336

    
337
//*********************** CLONE ********************************************************/
338

    
339
    /**
340
     * Clones <i>this</i> descriptioin. This is a shortcut that enables to create
341
     * a new instance that differs only slightly from <i>this</i> description by
342
     * modifying only some of the attributes.<BR>
343
     *
344
     * Usages of this name in a taxon concept are NOT cloned.<BR>
345
     * The name is added to the same homotypical group as the original name
346
     * (CAUTION: this behaviour needs to be discussed and may change in future).<BR>
347
     * {@link TaxonNameDescription Name descriptions} are cloned as XXX.<BR>
348
     * {@link TypeDesignationBase Type designations} are cloned as XXX.<BR>
349
     * {@link NameRelationship Name relation} are cloned as XXX.<BR>
350
     *
351
     * @see eu.etaxonomy.cdm.model.media.IdentifiableEntity#clone()
352
     * @see java.lang.Object#clone()
353
     */
354
    @Override
355
    public Object clone()  {
356
        DescriptionBase<?> result;
357
        try{
358
            result = (DescriptionBase<?>)super.clone();
359

    
360
            //working set
361
            result.descriptiveDataSets = new HashSet<DescriptiveDataSet>();
362
            for (DescriptiveDataSet descriptiveDataSet : getDescriptiveDataSets()){
363
                descriptiveDataSet.addDescription(result);
364
            }
365

    
366
            //descriptions
367
            result.descriptionSources = new HashSet<Reference>();
368
            for (Reference reference : getDescriptionSources()){
369
                result.descriptionSources.add(reference);
370
            }
371

    
372
            //elements
373
            result.descriptionElements = new HashSet<DescriptionElementBase>();
374
            for (DescriptionElementBase element : getElements()){
375
                DescriptionElementBase newElement = (DescriptionElementBase)element.clone();
376
                result.addElement(newElement);
377
            }
378

    
379
            //no changes to: imageGallery
380
            return result;
381
        } catch (CloneNotSupportedException e) {
382
            logger.warn("Object does not implement cloneable");
383
            e.printStackTrace();
384
            return null;
385
        }
386

    
387
    }
388
}
(4-4/37)