Project

General

Profile

Download (14.4 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.TaxonNameBase;
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 TaxonNameBase 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
 * @created 08-Nov-2007 13:06:24
69
 */
70

    
71
@XmlAccessorType(XmlAccessType.FIELD)
72
@XmlType(name = "DescriptionBase", propOrder = {
73
    "describedSpecimenOrObservation",
74
    "descriptionSources",
75
    "workingSets",
76
    "descriptionElements",
77
    "imageGallery"
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> extends IdentifiableEntity<S> {
87
    private static final long serialVersionUID = 5504218413819040193L;
88
    private static final Logger logger = Logger.getLogger(DescriptionBase.class);
89

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

    
100

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

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

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

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

    
134

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

    
148

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

    
163

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

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

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

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

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

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

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

    
258

    
259

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

    
272
    /**
273
     * @return the imageGallery
274
     */
275
    public boolean isImageGallery() {
276
        return imageGallery;
277
    }
278

    
279
    /**
280
     * @param imageGallery the imageGallery to set
281
     */
282
    public void setImageGallery(boolean imageGallery) {
283
        this.imageGallery = imageGallery;
284
    }
285

    
286

    
287
    public Set<WorkingSet> getWorkingSets() {
288
        return workingSets;
289
    }
290

    
291
    public boolean addWorkingSet(WorkingSet workingSet){
292
        boolean result = this.workingSets.add(workingSet);
293
        if (! workingSet.getDescriptions().contains(this)){
294
            workingSet.addDescription(this);
295
        }
296
        return result;
297
    }
298

    
299
    public boolean removeWorkingSet(WorkingSet workingSet){
300
        boolean result = this.workingSets.remove(workingSet);
301
        if (workingSet.getDescriptions().contains(this)){
302
            workingSet.addDescription(this);
303
        }
304
        return result;
305
    }
306

    
307
    protected void setWorkingSets(Set<WorkingSet> workingSets) {
308
        this.workingSets = workingSets;
309
    }
310

    
311

    
312

    
313
    @Transient
314
    public boolean hasStructuredData(){
315
        for (DescriptionElementBase element : this.getElements()){
316
            if (element.isInstanceOf(QuantitativeData.class) ||
317
                    element.isInstanceOf(CategoricalData.class)){
318
                return true;
319
            }
320
        }
321
        return false;
322
    }
323

    
324

    
325
//*********************** CLONE ********************************************************/
326

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

    
348
            //working set
349
            result.workingSets = new HashSet<WorkingSet>();
350
            for (WorkingSet workingSet : getWorkingSets()){
351
                workingSet.addDescription(result);
352
            }
353

    
354
            //descriptions
355
            result.descriptionSources = new HashSet<Reference>();
356
            for (Reference reference : getDescriptionSources()){
357
                result.descriptionSources.add(reference);
358
            }
359

    
360
            //elements
361
            result.descriptionElements = new HashSet<DescriptionElementBase>();
362
            for (DescriptionElementBase element : getElements()){
363
                DescriptionElementBase newElement = (DescriptionElementBase)element.clone();
364
                result.addElement(newElement);
365
            }
366

    
367
            //no changes to: imageGallery
368
            return result;
369
        } catch (CloneNotSupportedException e) {
370
            logger.warn("Object does not implement cloneable");
371
            e.printStackTrace();
372
            return null;
373
        }
374

    
375
    }
376
}
(3-3/36)