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
 * @since 08-Nov-2007 13:06:24
68
 */
69

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

    
89
    private static final long serialVersionUID = 5504218413819040193L;
90
    private static final Logger logger = Logger.getLogger(DescriptionBase.class);
91

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

    
102

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

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

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

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

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

    
139

    
140
    /**
141
     * Returns a {@link SpecimenOrObservationBase specimen or observation} involved in
142
     * <i>this</i> description as a whole. {@link TaxonDescription Taxon descriptions} are also often based
143
     * on concrete specimens or observations. For {@link TaxonNameDescription taxon name descriptions}
144
     * this attribute should be empty.
145
     * To handle sets of specimen or observations one may first group them by a derivation event of type
146
     * "Grouping" and then use the grouped unit here.
147
     * @return
148
     */
149
    public SpecimenOrObservationBase getDescribedSpecimenOrObservation() {
150
		return describedSpecimenOrObservation;
151
	}
152

    
153

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

    
168

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

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

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

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

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

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

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

    
263

    
264

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

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

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

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

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

    
299

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

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

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

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

    
324

    
325

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

    
337

    
338
//*********************** CLONE ********************************************************/
339

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

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

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

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

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

    
388
    }
389
}
(4-4/35)