Project

General

Profile

Download (14.1 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.IndexedEmbedded;
41

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

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

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

    
88
    @XmlElement( name = "DescribedSpecimenOrObservation")
89
    @ManyToOne(fetch = FetchType.LAZY)
90
    @XmlIDREF
91
    @XmlSchemaType(name="IDREF")
92
    @Cascade({CascadeType.SAVE_UPDATE,CascadeType.MERGE})
93
    @JoinColumn(name="specimen_id")
94
    @IndexedEmbedded
95
    //TODO maybe move down to specific classes SpecimenDescription (with Cascade.Delete) and TaxonDescription (without Cascade)
96
    private SpecimenOrObservationBase<?> describedSpecimenOrObservation;
97
    
98
    
99
    @XmlElementWrapper(name = "DescriptionSources")
100
    @XmlElement(name = "DescriptionSource")
101
    @XmlIDREF
102
    @XmlSchemaType(name="IDREF")
103
    @ManyToMany(fetch = FetchType.LAZY)  //FIXME what is the difference between this and IdentifiableEntity.sources
104
    private Set<Reference> descriptionSources = new HashSet<Reference>();
105

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

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

    
129
    @XmlElement(name = "ImageGallery")
130
    private boolean imageGallery;
131

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

    
146

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

    
161

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

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

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

    
201
    /**
202
     * Returns the set of {@link DescriptionElementBase elementary description data} which constitute
203
     * <i>this</i> description as a whole.
204
     *
205
     * @see    #addElement(DescriptionElementBase)
206
     * @see    #removeElement(DescriptionElementBase)
207
     */
208
    public Set<DescriptionElementBase> getElements() {
209
        return this.descriptionElements;
210
    }
211
    
212
    /**
213
     * Adds an existing {@link DescriptionElementBase elementary description} to the set of
214
     * {@link #getElements() elementary description data} which constitute <i>this</i>
215
     * description as a whole.
216
     * If the elementary descriptions already belongs to a description it is first removed from
217
     * the old description.
218
     *
219
     * @param element	the elementary description to be added to <i>this</i> description
220
     * @see    	   		#getDescriptionSources()
221
     */
222
    public void addElement(DescriptionElementBase element) {
223
        if (element.getInDescription() != null){
224
            element.getInDescription().removeElement(element);
225
        }
226
        element.setInDescription(this);
227
        this.descriptionElements.add(element);
228
    }
229
    
230
    /**
231
     * Convenience method to add multiple elements.
232
     * @param elements
233
     */
234
    public void addElements(DescriptionElementBase ... elements) {
235
    	for (DescriptionElementBase element : elements){
236
    		addElement(element);
237
    	}
238
    }
239

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

    
253
    /**
254
     * Returns the number of {@link DescriptionElementBase elementary description data} which constitute
255
     * <i>this</i> description as a whole. This is the cardinality of the set of
256
     * elementary description data.
257
     *
258
     * @see		#getElements()
259
     * @return	the number of elements of the elementary description data set
260
     */
261
    public int size(){
262
        return this.descriptionElements.size();
263
    }
264

    
265
    /**
266
     * @return the imageGallery
267
     */
268
    public boolean isImageGallery() {
269
        return imageGallery;
270
    }
271

    
272
    /**
273
     * @param imageGallery the imageGallery to set
274
     */
275
    public void setImageGallery(boolean imageGallery) {
276
        this.imageGallery = imageGallery;
277
    }
278

    
279

    
280
    public Set<WorkingSet> getWorkingSets() {
281
        return workingSets;
282
    }
283

    
284
    public boolean addWorkingSet(WorkingSet workingSet){
285
        boolean result = this.workingSets.add(workingSet);
286
        if (! workingSet.getDescriptions().contains(this)){
287
            workingSet.addDescription(this);
288
        }
289
        return result;
290
    }
291

    
292
    public boolean removeWorkingSet(WorkingSet workingSet){
293
        boolean result = this.workingSets.remove(workingSet);
294
        if (workingSet.getDescriptions().contains(this)){
295
            workingSet.addDescription(this);
296
        }
297
        return result;
298
    }
299

    
300
    protected void setWorkingSets(Set<WorkingSet> workingSets) {
301
        this.workingSets = workingSets;
302
    }
303

    
304

    
305

    
306
    @Transient
307
    public boolean hasStructuredData(){
308
        for (DescriptionElementBase element : this.getElements()){
309
            if (element.isInstanceOf(QuantitativeData.class) ||
310
                    element.isInstanceOf(CategoricalData.class)){
311
                return true;
312
            }
313
        }
314
        return false;
315
    }
316

    
317

    
318
//*********************** CLONE ********************************************************/
319

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

    
341
            //working set
342
            result.workingSets = new HashSet<WorkingSet>();
343
            for (WorkingSet workingSet : getWorkingSets()){
344
                workingSet.addDescription(result);
345
            }
346

    
347
            //descriptions
348
            result.descriptionSources = new HashSet<Reference>();
349
            for (Reference reference : getDescriptionSources()){
350
                result.descriptionSources.add(reference);
351
            }
352

    
353
            //elements
354
            result.descriptionElements = new HashSet<DescriptionElementBase>();
355
            for (DescriptionElementBase element : getElements()){
356
                DescriptionElementBase newElement = (DescriptionElementBase)element.clone();
357
                result.addElement(newElement);
358
            }
359

    
360
            //no changes to: imageGallery
361
            return result;
362
        } catch (CloneNotSupportedException e) {
363
            logger.warn("Object does not implement cloneable");
364
            e.printStackTrace();
365
            return null;
366
        }
367

    
368
    }
369
}
(3-3/36)