Project

General

Profile

Download (13.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.occurrence;
11

    
12
import java.util.HashSet;
13
import java.util.Set;
14

    
15
import javax.persistence.Column;
16
import javax.persistence.Entity;
17
import javax.persistence.FetchType;
18
import javax.persistence.Lob;
19
import javax.persistence.ManyToOne;
20
import javax.persistence.OneToMany;
21
import javax.persistence.Transient;
22
import javax.xml.bind.annotation.XmlAccessType;
23
import javax.xml.bind.annotation.XmlAccessorType;
24
import javax.xml.bind.annotation.XmlElement;
25
import javax.xml.bind.annotation.XmlElementWrapper;
26
import javax.xml.bind.annotation.XmlIDREF;
27
import javax.xml.bind.annotation.XmlRootElement;
28
import javax.xml.bind.annotation.XmlSchemaType;
29
import javax.xml.bind.annotation.XmlType;
30

    
31
import org.apache.commons.lang.StringUtils;
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.Analyze;
37
import org.hibernate.search.annotations.Field;
38
import org.hibernate.search.annotations.Indexed;
39
import org.hibernate.search.annotations.IndexedEmbedded;
40

    
41
import eu.etaxonomy.cdm.model.molecular.DnaSample;
42
import eu.etaxonomy.cdm.model.name.SpecimenTypeDesignation;
43
import eu.etaxonomy.cdm.model.name.TaxonNameBase;
44
import eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy;
45
import eu.etaxonomy.cdm.strategy.cache.common.IdentifiableEntityDefaultCacheStrategy;
46

    
47
/**
48
 * A derived unit is regarded as derived from a field unit,
49
 * so locality and gathering related information is captured as a separate FieldUnit object
50
 * related to a specimen via a derivation event
51
 *
52
 * http://www.bgbm.org/biodivinf/docs/CollectionModel/ReprintTNR.pdf
53
 * http://www.bgbm.org/biodivinf/docs/CollectionModel/
54
 * <BR>
55
 * Type figures are derived units with at least a figure object in media
56
 *
57
 * @author m.doering
58
 * @created 08-Nov-2007 13:06:52
59
 *
60
 */
61
@XmlAccessorType(XmlAccessType.FIELD)
62
@XmlType(name = "DerivedUnit", propOrder = {
63
    "collection",
64
    "catalogNumber",
65
    "storedUnder",
66
    "derivedFrom",
67
    "accessionNumber",
68
    "collectorsNumber",
69
    "barcode",
70
	"preservation",
71
	"exsiccatum",
72
	"originalLabelInfo",
73
    "specimenTypeDesignations"
74
})
75
@XmlRootElement(name = "DerivedUnit")
76
@Entity
77
@Audited
78
// even if hibernate complains "Abstract classes can never insert index documents. Remove @Indexed."
79
// this is needed, otherwise the fields of the also abstract super class are missed during indexing
80
@Indexed(index = "eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationBase")
81
public class DerivedUnit extends SpecimenOrObservationBase<IIdentifiableEntityCacheStrategy> implements Cloneable{
82
	private static final long serialVersionUID = -3525746216270843517L;
83

    
84
	private static final Logger logger = Logger.getLogger(DnaSample.class);
85

    
86
	@XmlElement(name = "Collection")
87
	@XmlIDREF
88
	@XmlSchemaType(name = "IDREF")
89
	@ManyToOne(fetch = FetchType.LAZY)
90
	@Cascade({CascadeType.SAVE_UPDATE,CascadeType.MERGE})
91
	@IndexedEmbedded
92
	private Collection collection;
93

    
94
	@XmlElement(name = "CatalogNumber")
95
	@Field(analyze = Analyze.NO)
96
    //TODO Val #3379
97
//	@NullOrNotEmpty
98
	@Column(length=255)
99
	private String catalogNumber;
100

    
101
	@XmlElement(name = "AccessionNumber")
102
	@Field(analyze = Analyze.NO)
103
    //TODO Val #3379
104
//	@NullOrNotEmpty
105
	@Column(length=255)
106
	private String accessionNumber;
107

    
108
	@XmlElement(name = "CollectorsNumber")
109
	@Field(analyze = Analyze.NO)
110
    //TODO Val #3379
111
//	@NullOrNotEmpty
112
	@Column(length=255)
113
	private String collectorsNumber;
114

    
115
	@XmlElement(name = "Barcode")
116
	@Field(analyze = Analyze.NO)
117
    //TODO Val #3379
118
//	@NullOrNotEmpty
119
	@Column(length=255)
120
	private String barcode;
121

    
122
	@XmlElement(name = "StoredUnder")
123
	@XmlIDREF
124
	@XmlSchemaType(name = "IDREF")
125
	@ManyToOne(fetch = FetchType.LAZY)
126
	@Cascade({CascadeType.SAVE_UPDATE,CascadeType.MERGE})
127
	@IndexedEmbedded(includeEmbeddedObjectId=true)
128
	private TaxonNameBase storedUnder;
129

    
130
	@XmlElement(name = "DerivedFrom")
131
	@XmlIDREF
132
	@XmlSchemaType(name = "IDREF")
133
	@ManyToOne(fetch = FetchType.LAZY)
134
	@Cascade({CascadeType.SAVE_UPDATE,CascadeType.MERGE})
135
	@IndexedEmbedded(depth = 4)
136
	private DerivationEvent derivedFrom;
137

    
138
	@XmlElement(name = "OriginalLabelInfo")
139
	@Lob
140
    private String originalLabelInfo;
141

    
142
	@XmlElementWrapper(name = "SpecimenTypeDesignations")
143
	@XmlElement(name = "SpecimenTypeDesignation")
144
	@OneToMany(fetch = FetchType.LAZY, mappedBy = "typeSpecimen")
145
	@Cascade({ CascadeType.SAVE_UPDATE, CascadeType.MERGE, CascadeType.DELETE })
146
	private final Set<SpecimenTypeDesignation> specimenTypeDesignations = new HashSet<SpecimenTypeDesignation>();
147

    
148

    
149
//*** attributes valid only for preserved specimen (PreservedSpecimen, Fossil, DnaSample)
150

    
151
	@XmlElement(name = "Preservation")
152
	@XmlIDREF
153
	@XmlSchemaType(name = "IDREF")
154
	@ManyToOne(fetch = FetchType.LAZY)
155
    @Cascade({CascadeType.SAVE_UPDATE,CascadeType.MERGE})
156
	private PreservationMethod preservation;
157

    
158

    
159
	@XmlElement(name = "Exsiccatum")
160
    //TODO Val #3379
161
//	@NullOrNotEmpty
162
	@Field
163
    @Column(length=255)
164
    private String exsiccatum;
165

    
166
// ******************** FACTORY METHOD **********************************/
167

    
168

    
169
	public static DerivedUnit NewInstance(SpecimenOrObservationType type) {
170
		if (type.isMedia()){
171
			return MediaSpecimen.NewInstance(type);
172
		}else if (type.equals(SpecimenOrObservationType.DnaSample) || type.isKindOf(SpecimenOrObservationType.DnaSample)){
173
			return DnaSample.NewInstance();
174
		}else{
175
			return new DerivedUnit(type);
176
		}
177
	}
178

    
179
	/**
180
	 * Factory method
181
	 * @return
182
	 */
183
	public static DerivedUnit NewPreservedSpecimenInstance(){
184
		DerivedUnit result = new DerivedUnit(SpecimenOrObservationType.PreservedSpecimen);
185
		return result;
186
	}
187

    
188
//************************** CONSTRUCTOR *********************************/
189

    
190
	//Constructor: For hibernate use only
191
	protected DerivedUnit() {
192
	    super();
193
        initDefaultCacheStrategy();
194
	}
195

    
196

    
197
    /**
198
	 * Constructor
199
	 * @param recordBasis
200
	 */
201
	protected DerivedUnit(SpecimenOrObservationType recordBasis) {
202
		super(recordBasis);
203
        initDefaultCacheStrategy();
204
	}
205

    
206

    
207
	/**
208
	 * Create new unit derived from an existing field unit
209
	 * @param fieldUnit existing field unit from where this unit is derived
210
	 */
211
	protected DerivedUnit(SpecimenOrObservationType recordBasis, FieldUnit fieldUnit) {
212
		this(recordBasis);
213
		DerivationEvent derivedFrom = new DerivationEvent();
214
		// TODO: should be done in a more controlled way. Probably by making derivation event implement a general relationship interface (for bidirectional add/remove etc)
215
		fieldUnit.addDerivationEvent(derivedFrom);
216
		derivedFrom.getOriginals().add(fieldUnit);
217
		derivedFrom.getDerivatives().add(this);
218
		this.setDerivedFrom(derivedFrom);
219
	}
220

    
221
	/**
222
	 * create new unit derived from an existing gathering event,
223
	 * thereby creating a new empty field unit
224
	 * @param gatheringEvent the gathering event this unit was collected at
225
	 */
226
	protected DerivedUnit(SpecimenOrObservationType recordBasis, GatheringEvent gatheringEvent) {
227
		this(recordBasis, new FieldUnit());
228
		FieldUnit field = (FieldUnit)this.getOriginalUnit();
229
		field.setGatheringEvent(gatheringEvent);
230
	}
231

    
232
    private static final String facadeStrategyClassName = "eu.etaxonomy.cdm.api.facade.DerivedUnitFacadeCacheStrategy";
233
    /**
234
     * Sets the default cache strategy
235
     */
236
	@Override
237
    protected void initDefaultCacheStrategy() {
238
        try {
239
            String facadeClassName = facadeStrategyClassName;
240
            Class<?> facadeClass = Class.forName(facadeClassName);
241
            try {
242
                this.cacheStrategy = (IIdentifiableEntityCacheStrategy)facadeClass.newInstance();
243
            } catch (InstantiationException e) {
244
                e.printStackTrace();
245
            } catch (IllegalAccessException e) {
246
                e.printStackTrace();
247
            }
248
        } catch (ClassNotFoundException e) {
249
            this.cacheStrategy = new IdentifiableEntityDefaultCacheStrategy<SpecimenOrObservationBase>();
250
        }
251
    }
252
//
253
//    private static Class<?> facadeCacheStrategyClass;
254
//
255
//
256
//    @Override
257
//    protected void setFacadeCacheStrategyClass(Class<?> facadeCacheStrategyClass){
258
//        this.facadeCacheStrategyClass = facadeCacheStrategyClass;
259
//    }
260
//
261
//
262
//    @Override
263
//    protected Class<?> getFacadeCacheStrategyClass(){
264
//	    return facadeCacheStrategyClass;
265
//	}
266

    
267

    
268

    
269
// ******************** GETTER / SETTER *************************************/
270

    
271

    
272
	public DerivationEvent getDerivedFrom() {
273
		return derivedFrom;
274
	}
275

    
276
	public void setDerivedFrom(DerivationEvent derivedFrom){
277
		if (getDerivedFrom() != null){
278
			getDerivedFrom().getDerivatives().remove(derivedFrom);
279
		}
280
		this.derivedFrom = derivedFrom;
281
		if (derivedFrom != null){
282
			derivedFrom.addDerivative(this);
283
		}
284
	}
285

    
286
	@Transient
287
	public Set<SpecimenOrObservationBase> getOriginals(){
288
		if(getDerivedFrom() != null){
289
			return getDerivedFrom().getOriginals();
290
		}
291
		return null;
292
	}
293

    
294
	public Collection getCollection(){
295
		return this.collection;
296
	}
297

    
298
	public void setCollection(Collection collection){
299
		this.collection = collection;
300
	}
301

    
302
	public String getCatalogNumber() {
303
		return catalogNumber;
304
	}
305

    
306
	public void setCatalogNumber(String catalogNumber) {
307
		this.catalogNumber = StringUtils.isBlank(catalogNumber)?null:catalogNumber;
308
	}
309

    
310
	public void setBarcode(String barcode) {
311
		this.barcode = StringUtils.isBlank(barcode)? null : barcode;
312
	}
313
	public String getBarcode() {
314
		return barcode;
315
	}
316

    
317
	public void setStoredUnder(TaxonNameBase storedUnder) {
318
		this.storedUnder = storedUnder;
319
	}
320

    
321
	public String getAccessionNumber() {
322
		return accessionNumber;
323
	}
324

    
325

    
326
	public void setAccessionNumber(String accessionNumber) {
327
		this.accessionNumber = StringUtils.isBlank(accessionNumber)? null : accessionNumber;
328
	}
329

    
330

    
331
	/**
332
	 * Original label information may present the exact original text
333
	 * or any other text which fully or partly represents the text available
334
	 * on the specimens label. This information may differ from the information
335
	 * available in the derived unit itself.
336
	 * @return the original label information
337
	 */
338
	//#4218
339
	public String getOriginalLabelInfo() {
340
		return originalLabelInfo;
341
	}
342

    
343
	public void setOriginalLabelInfo(String originalLabelInfo) {
344
		this.originalLabelInfo = originalLabelInfo;
345
	}
346

    
347
	/**
348
	 * Will be removed in future versions as semantics is not clear.
349
	 * For accessing the collecting number use
350
	 * {@link FieldUnit#getFieldNumber()} instead.
351
	 * @return
352
	 */
353
	@Deprecated
354
	public String getCollectorsNumber() {
355
		return collectorsNumber;
356
	}
357

    
358
	/**
359
	 * Will be removed in future versions as semantics is not clear.
360
	 * For editing the collecting number use
361
	 * {@link FieldUnit#getFieldNumber()} instead.
362
	 * @return
363
	 */
364
	@Deprecated
365
	public void setCollectorsNumber(String collectorsNumber) {
366
		this.collectorsNumber = StringUtils.isBlank(collectorsNumber)? null : collectorsNumber;
367
	}
368

    
369
	public TaxonNameBase getStoredUnder() {
370
		return storedUnder;
371
	}
372

    
373
	public void addSpecimenTypeDesignation(SpecimenTypeDesignation specimenTypeDesignation){
374
		if (specimenTypeDesignation.getTypeSpecimen() == this){
375
			return ;
376
		}else if (specimenTypeDesignation.getTypeSpecimen() != null){
377
			specimenTypeDesignation.getTypeSpecimen().removeSpecimenTypeDesignation(specimenTypeDesignation);
378

    
379
		}
380
		specimenTypeDesignations.add(specimenTypeDesignation);
381
		specimenTypeDesignation.setTypeSpecimen(this);
382
	}
383

    
384
	public void removeSpecimenTypeDesignation(SpecimenTypeDesignation specimenTypeDesignation){
385
		if (specimenTypeDesignation == null){
386
			return;
387
		}
388
		if (specimenTypeDesignations.contains(specimenTypeDesignation)){
389
			specimenTypeDesignations.remove(specimenTypeDesignation);
390
			specimenTypeDesignation.setTypeSpecimen(null);
391
		}
392
	}
393

    
394
    public String getMostSignificantIdentifier() {
395
        if (StringUtils.isNotBlank(getAccessionNumber())) {
396
            return getAccessionNumber();
397
        }
398
        else if(StringUtils.isNotBlank(getBarcode())){
399
            return getBarcode();
400
        }
401
        else if(StringUtils.isNotBlank(getCatalogNumber())){
402
            return getCatalogNumber();
403
        }
404
        return null;
405
    }
406

    
407
// ******* GETTER / SETTER for preserved specimen only ******************/
408

    
409
	public Set<SpecimenTypeDesignation> getSpecimenTypeDesignations(){
410
		return specimenTypeDesignations;
411
	}
412

    
413
	public PreservationMethod getPreservation(){
414
		return this.preservation;
415
	}
416

    
417
	public void setPreservation(PreservationMethod preservation){
418
		this.preservation = preservation;
419
	}
420

    
421

    
422
	public void setExsiccatum(String exsiccatum) {
423
		this.exsiccatum = StringUtils.isBlank(exsiccatum)? null : exsiccatum;
424
	}
425

    
426
	public String getExsiccatum() {
427
		return exsiccatum;
428
	}
429

    
430
//*********** CLONE **********************************/
431

    
432
	/**
433
	 * Clones <i>this</i> derivedUnit. This is a shortcut that enables to
434
	 * create a new instance that differs only slightly from <i>this</i> specimen
435
	 * by modifying only some of the attributes.<BR>
436
	 * This method overrides the clone method from {@link SpecimenOrObservationBase SpecimenOrObservationBase}.
437
	 *
438
	 * @see SpecimenOrObservationBase#clone()
439
	 * @see eu.etaxonomy.cdm.model.media.IdentifiableMediaEntity#clone()
440
	 * @see java.lang.Object#clone()
441
	 */
442
	@Override
443
	public Object clone() {
444
		try{
445
			DerivedUnit result = (DerivedUnit)super.clone();
446
			//collection
447
			result.setCollection(this.collection);
448
			//derivedFrom
449
			result.setDerivedFrom(this.derivedFrom);
450
			//storedUnder
451
			result.setStoredUnder(this.storedUnder);
452
			//preservation
453
			result.setPreservation(this.preservation);
454
			//no changes to: accessionNumber, catalogNumber, collectorsNumber
455
			return result;
456
		} catch (CloneNotSupportedException e) {
457
			logger.warn("Object does not implement cloneable");
458
			e.printStackTrace();
459
			return null;
460
		}
461
	}
462

    
463

    
464

    
465
}
(4-4/14)