Project

General

Profile

Download (18.6 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.Iterator;
14
import java.util.Set;
15

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

    
31
import org.apache.log4j.Logger;
32
import org.hibernate.annotations.Cascade;
33
import org.hibernate.annotations.CascadeType;
34
import org.hibernate.envers.Audited;
35
import org.hibernate.search.annotations.Indexed;
36
import org.hibernate.validator.constraints.NotEmpty;
37

    
38
import eu.etaxonomy.cdm.model.common.DefinedTerm;
39
import eu.etaxonomy.cdm.validation.Level2;
40

    
41
/**
42
 * This class represents information pieces expressed in numerical data
43
 * (in opposition to {@link CategoricalData categorical data} on one side and to literal data on
44
 * the other side). Only {@link TaxonDescription taxon descriptions} and
45
 * {@link SpecimenDescription specimen descriptions} may contain quantitative data.<BR>
46
 * The "length of leaves" {@link Feature feature} for instance can be measured in inches.
47
 * If the length of leaves of a particular tree is described as
48
 * "typically between 3 and 5 inches" and "at the utmost 8 inches" then three
49
 * {@link StatisticalMeasurementValue statistical measurement value} instances
50
 * must be assigned to an instance of the present class
51
 * (with the {@link MeasurementUnit measurement unit} set to "inch"):<ul>
52
 * <li> the first one with the value "3" and the {@link StatisticalMeasure statistical measure}
53
 * "typical lower boundary",
54
 * <li> the second one with the value "5" and the statistical measure
55
 * "typical upper boundary"
56
 * <li> the third one with the value "8" and the statistical measure "maximum"
57
 * </ul>
58
 * <P>
59
 * This class corresponds partially to CodedDescriptionType according to
60
 * the SDD schema.
61
 *
62
 * @author m.doering
63
 * @version 1.0
64
 * @created 08-Nov-2007 13:06:46
65
 */
66
@XmlAccessorType(XmlAccessType.FIELD)
67
@XmlType(name = "QuantitativeData", propOrder = {
68
    "unit",
69
    "statisticalValues",
70
    "unknownData"
71
})
72
@XmlRootElement(name = "QuantitativeData")
73
@Entity
74
@Indexed(index = "eu.etaxonomy.cdm.model.description.DescriptionElementBase")
75
@Audited
76
public class QuantitativeData extends DescriptionElementBase implements Cloneable {
77
	private static final long serialVersionUID = -2755806455420051488L;
78

    
79
	private static final Logger logger = Logger.getLogger(QuantitativeData.class);
80

    
81
	@XmlElement(name = "MeasurementUnit")
82
	@XmlIDREF
83
	@XmlSchemaType(name = "IDREF")
84
	@ManyToOne(fetch = FetchType.LAZY)
85
	private MeasurementUnit unit;
86

    
87
	@XmlElementWrapper(name = "StatisticalValues")
88
	@XmlElement(name = "StatisticalValue")
89
	@OneToMany(fetch = FetchType.LAZY, mappedBy="quantitativeData", orphanRemoval=true)
90
	@Cascade({ CascadeType.SAVE_UPDATE, CascadeType.MERGE, CascadeType.DELETE})
91
	@NotEmpty(groups = Level2.class)
92
	private Set<StatisticalMeasurementValue> statisticalValues = new HashSet<StatisticalMeasurementValue>();
93

    
94
//see #4471
95
//	@Column(precision = 20, scale = 10)
96
//	private BigDecimal minimum;
97
//
98
//	@Column(precision = 20, scale = 10)
99
//	private BigDecimal maximum;
100
//
101
//	@Column(precision = 20, scale = 10)
102
//	private BigDecimal average;
103
//
104
//	@Column(precision = 16, scale = 8)
105
//	private BigDecimal variance;
106
//
107
//	@Column(precision = 16, scale = 8)
108
//	private BigDecimal standardDeviation;
109
//
110
//	@Column(precision = 20, scale = 10)
111
//	private BigDecimal singleValue;
112
//
113
//	private Integer sampleSize;
114

    
115
	@XmlElement(name = "UnknownData")
116
	private Boolean unknownData = false;
117

    
118

    
119
// ******************************** FACTORY METHOD *******************************/
120

    
121
	/**
122
	 * Creates a new empty quantitative data instance.
123
	 */
124
	public static QuantitativeData NewInstance(){
125
		return new QuantitativeData();
126
	}
127

    
128
// ******************************** FACTORY METHOD *******************************/
129

    
130
	/**
131
	 * Creates a new empty quantitative data instance.
132
	 */
133
	public static QuantitativeData NewInstance(Feature feature){
134
		return new QuantitativeData(feature);
135
	}
136

    
137

    
138
// ******************************** CONSTRUCTOR *******************************/
139

    
140
	/**
141
	 * Class constructor: creates a new empty quantitative data instance.
142
	 */
143
	protected QuantitativeData(){
144
		super(null);
145
	}
146

    
147
	/**
148
	 * Class constructor: creates a new empty quantitative data instance.
149
	 */
150
	protected QuantitativeData(Feature feature){
151
		super(feature);
152
	}
153

    
154

    
155
// ******************************** GETTER /SETTER *******************************/
156

    
157

    
158
	/**
159
	 * Returns the set of {@link StatisticalMeasurementValue statistical measurement values} describing
160
	 * the {@link Feature feature} corresponding to <i>this</i> quantitative data.
161
	 */
162
	public Set<StatisticalMeasurementValue> getStatisticalValues() {
163
		return statisticalValues;
164
	}
165

    
166
	@Deprecated  //for internal use only
167
	protected void setStatisticalValues(Set<StatisticalMeasurementValue> statisticalValues) {
168
		this.statisticalValues = statisticalValues;
169
	}
170
	/**
171
	 * Adds a {@link StatisticalMeasurementValue statistical measurement value} to the set of
172
	 * {@link #getStatisticalValues() statistical measurement values} describing
173
	 * the {@link Feature feature} corresponding to <i>this</i> quantitative data.
174
	 *
175
	 * @param statisticalValue	the statistical measurement value to be added to
176
	 * 							<i>this</i> quantitative data
177
	 * @see    	   				#getStatisticalValues()
178
	 */
179
	@SuppressWarnings("deprecation")
180
    public void addStatisticalValue(StatisticalMeasurementValue statisticalValue) {
181
		this.statisticalValues.add(statisticalValue);
182
		statisticalValue.setQuantitativeData(this);
183
	}
184
	/**
185
	 * Removes one element from the set of {@link #getStatisticalValues() statistical measurement values}
186
	 * describing the {@link Feature feature} corresponding to <i>this</i> quantitative data.
187
	 *
188
	 * @param  statisticalValue	the statistical measurement value which should be removed
189
	 * @see     				#getStatisticalValues()
190
	 * @see     				#addStatisticalValue(StatisticalMeasurementValue)
191
	 */
192
	@SuppressWarnings("deprecation")
193
    public void removeStatisticalValue(StatisticalMeasurementValue statisticalValue) {
194
		this.statisticalValues.remove(statisticalValue);
195
		statisticalValue.setQuantitativeData(null);
196
	}
197

    
198

    
199
	/**
200
	 * Returns the {@link MeasurementUnit measurement unit} used in <i>this</i>
201
	 * quantitative data.
202
	 */
203
	public MeasurementUnit getUnit(){
204
		return this.unit;
205
	}
206
	/**
207
	 * @see	#getUnit()
208
	 */
209
	public void setUnit(MeasurementUnit unit){
210
		this.unit = unit;
211
	}
212

    
213
// ******************************** TRANSIENT METHODS *******************************/
214

    
215

    
216
	/**
217
	 * Returns the numerical value of the one {@link StatisticalMeasurementValue statistical measurement value}
218
	 * with the corresponding {@link StatisticalMeasure statistical measure} "minimum" and
219
	 * belonging to <i>this</i> quantitative data. Returns <code>null</code> if no such
220
	 * statistical measurement value instance exists.
221
	 */
222
	@Transient
223
	public Float getMin(){
224
		return getSpecificStatisticalValue(StatisticalMeasure.MIN());
225
	}
226

    
227
	/**
228
	 * Returns the numerical value of the one {@link StatisticalMeasurementValue statistical measurement value}
229
	 * with the corresponding {@link StatisticalMeasure statistical measure} "maximum" and
230
	 * belonging to <i>this</i> quantitative data. Returns <code>null</code> if no such
231
	 * statistical measurement value instance exists.
232
	 */
233
	@Transient
234
	public Float getMax(){
235
		return getSpecificStatisticalValue(StatisticalMeasure.MAX());
236
	}
237

    
238
	/**
239
	 * Returns the numerical value of the one {@link StatisticalMeasurementValue statistical measurement value}
240
	 * with the corresponding {@link StatisticalMeasure statistical measure}
241
	 * "typical lower boundary" and belonging to <i>this</i> quantitative data.
242
	 * Returns <code>null</code> if no such statistical measurement value instance exists.
243
	 */
244
	@Transient
245
	public Float getTypicalLowerBoundary(){
246
		return getSpecificStatisticalValue(StatisticalMeasure.TYPICAL_LOWER_BOUNDARY());
247
	}
248

    
249
	/**
250
	 * Returns the numerical value of the one {@link StatisticalMeasurementValue statistical measurement value}
251
	 * with the corresponding {@link StatisticalMeasure statistical measure}
252
	 * "average" and belonging to <i>this</i> quantitative data.
253
	 * Returns <code>null</code> if no such statistical measurement value instance exists.
254
	 */
255
	@Transient
256
	public Float getAverage(){
257
		return getSpecificStatisticalValue(StatisticalMeasure.AVERAGE());
258
	}
259

    
260
	/**
261
	 * Returns the numerical value of the one {@link StatisticalMeasurementValue statistical measurement value}
262
	 * with the corresponding {@link StatisticalMeasure statistical measure}
263
	 * "standard deviation" and belonging to <i>this</i> quantitative data.
264
	 * Returns <code>null</code> if no such statistical measurement value instance exists.
265
	 */
266
	@Transient
267
	public Float getStandardDeviation(){
268
		return getSpecificStatisticalValue(StatisticalMeasure.STANDARD_DEVIATION());
269
	}
270

    
271
	/**
272
	 * Returns the numerical value of the one {@link StatisticalMeasurementValue statistical measurement value}
273
	 * with the corresponding {@link StatisticalMeasure statistical measure}
274
	 * "sample size" and belonging to <i>this</i> quantitative data.
275
	 * Returns <code>null</code> if no such statistical measurement value instance exists.
276
	 */
277
	@Transient
278
	public Float getSampleSize(){
279
		return getSpecificStatisticalValue(StatisticalMeasure.SAMPLE_SIZE());
280
	}
281

    
282
	/**
283
	 * Returns the numerical value of the one {@link StatisticalMeasurementValue statistical measurement value}
284
	 * with the corresponding {@link StatisticalMeasure statistical measure}
285
	 * "typical upper boundary" and belonging to <i>this</i> quantitative data.
286
	 * Returns <code>null</code> if no such statistical measurement value instance exists.
287
	 */
288
	@Transient
289
	public Float getTypicalUpperBoundary(){
290
		return getSpecificStatisticalValue(StatisticalMeasure.TYPICAL_UPPER_BOUNDARY());
291
	}
292

    
293
	/**
294
	 * Returns the statistical value of type <code>type</code>.
295
	 * If no such value exists <code>null</code> is returned. If multiple such
296
	 * values exist an arbitrary one is returned.
297
	 * @param type
298
	 * @return the value
299
	 */
300
	public Float getSpecificStatisticalValue(StatisticalMeasure type){
301
		Float result = null;
302
		for (StatisticalMeasurementValue value : statisticalValues){
303
			if (type.equals(value.getType())){
304
				result = value.getValue();
305
				break;
306
			}
307
		}
308
		return result;
309
	}
310

    
311

    
312
	/**
313
	 * Sets the statistical value for the minimum.
314
	 * If such value exists the old value is replaced by the new value.
315
	 * The new value is returned.
316
	 * @param type
317
	 * @param value
318
	 * @return the newValue
319
	 */
320
	@Transient
321
	public StatisticalMeasurementValue setMinimum(Float value, Set<DefinedTerm> modifiers){
322
		return setSpecificStatisticalValue(value, modifiers, StatisticalMeasure.MIN());
323
	}
324

    
325

    
326
	/**
327
	 * Sets the statistical value for the maximum.
328
	 * If such value exists the old value is replaced by the new value.
329
	 * The new value is returned.
330
	 * @param type
331
	 * @param value
332
	 * @return the newValue
333
	 */
334
	@Transient
335
	public StatisticalMeasurementValue setMaximum(Float value, Set<DefinedTerm> modifiers){
336
		return setSpecificStatisticalValue(value, modifiers, StatisticalMeasure.MAX());
337
	}
338

    
339

    
340
	/**
341
	 * Sets the statistical value for the average.
342
	 * If such value exists the old value is replaced by the new value.
343
	 * The new value is returned.
344
	 * @param type
345
	 * @param value
346
	 * @return the newValue
347
	 */
348
	@Transient
349
	public StatisticalMeasurementValue setAverage(Float value, Set<DefinedTerm> modifiers){
350
		return setSpecificStatisticalValue(value, modifiers, StatisticalMeasure.AVERAGE());
351
	}
352

    
353

    
354
	/**
355
	 * Sets the statistical value for the standard deviation.
356
	 * If such value exists the old value is replaced by the new value.
357
	 * The new value is returned.
358
	 * @param type
359
	 * @param value
360
	 * @return the newValue
361
	 */
362
	@Transient
363
	public StatisticalMeasurementValue setStandardDeviation(Float value, Set<DefinedTerm> modifiers){
364
		return setSpecificStatisticalValue(value, modifiers, StatisticalMeasure.STANDARD_DEVIATION());
365
	}
366

    
367
	/**
368
	 * Sets the statistical value for the sample size.
369
	 * If such value exists the old value is replaced by the new value.
370
	 * The new value is returned.
371
	 * @param type
372
	 * @param value
373
	 * @return the newValue
374
	 */
375
	@Transient
376
	public StatisticalMeasurementValue setSampleSize(Float value, Set<DefinedTerm> modifiers){
377
		return setSpecificStatisticalValue(value, modifiers, StatisticalMeasure.SAMPLE_SIZE());
378
	}
379

    
380

    
381
	/**
382
	 * Sets the statistical value for the typical lower boundary.
383
	 * If such value exists the old value is replaced by the new value.
384
	 * The new value is returned.
385
	 * @param type
386
	 * @param value
387
	 * @return the newValue
388
	 */
389
	@Transient
390
	public StatisticalMeasurementValue setTypicalLowerBoundary(Float value, Set<DefinedTerm> modifiers){
391
		return setSpecificStatisticalValue(value, modifiers, StatisticalMeasure.TYPICAL_LOWER_BOUNDARY());
392
	}
393

    
394

    
395
	/**
396
	 * Sets the statistical value for the typical upper boundary.
397
	 * If such value exists the old value is replaced by the new value.
398
	 * The new value is returned.
399
	 * @param type
400
	 * @param value
401
	 * @return the newValue
402
	 */
403
	@Transient
404
	public StatisticalMeasurementValue setTypicalUpperBoundary(Float value, Set<DefinedTerm> modifiers){
405
		return setSpecificStatisticalValue(value, modifiers, StatisticalMeasure.TYPICAL_UPPER_BOUNDARY());
406
	}
407

    
408
	/**
409
	 * Sets the statistical value of type <code>type</code>.
410
	 * If such value exists the old value is replaced by the new value.
411
	 * The new value is returned.
412
	 * @param type
413
	 * @param value
414
	 * @return the newValue
415
	 */
416
	public StatisticalMeasurementValue setSpecificStatisticalValue(Float value, Set<DefinedTerm> modifiers, StatisticalMeasure type){
417

    
418
	    StatisticalMeasurementValue result = null;
419
		StatisticalMeasurementValue existingSmValue = null;
420

    
421
        for (StatisticalMeasurementValue existingValue : statisticalValues){
422
            if (type.equals(existingValue.getType())){
423
                existingSmValue = existingValue;
424
                break;
425
            }
426
        }
427
        if (value == null && existingSmValue == null){
428
            return null;
429
        }else if (value == null && existingSmValue != null){
430
            this.removeStatisticalValue(existingSmValue);
431
            return null;
432
        }else if (value != null && existingSmValue == null){
433
            result = StatisticalMeasurementValue.NewInstance(type, value);
434
            if (modifiers != null){
435
                for (DefinedTerm modifier : modifiers){
436
                    result.addModifier(modifier);
437
                }
438
            }
439
            this.addStatisticalValue(result);
440
        } else if (value != null && existingSmValue != null){
441
            result = existingSmValue;
442
            result.setValue(value);
443
            //remove existing modifiers
444
            Iterator<DefinedTerm> it = result.getModifiers().iterator();
445
            while (it.hasNext()){
446
                it.remove();
447
            }
448
            //add new modifiers
449
            if (modifiers != null){
450
                for (DefinedTerm modifier : modifiers){
451
                    result.addModifier(modifier);
452
                }
453
            }
454
        }
455
		return result;
456
	}
457

    
458
//   public StatisticalMeasurementValue setSpecificStatisticalValue_old(Float value, Set<DefinedTerm> modifiers, StatisticalMeasure type){
459
//        StatisticalMeasurementValue result = null;
460
//        if (value != null){
461
//            StatisticalMeasurementValue newValue = StatisticalMeasurementValue.NewInstance();
462
//            newValue.setValue(value);
463
//            if (modifiers != null){
464
//                newValue.getModifiers().addAll(modifiers);
465
//            }
466
//            newValue.setType(type);
467
//            result = newValue;
468
//        }
469
//        for (StatisticalMeasurementValue existingValue : statisticalValues){
470
//            if (type.equals(existingValue.getType())){
471
//                result = existingValue;
472
//                statisticalValues.remove(existingValue);
473
//                break;
474
//            }
475
//        }
476
//        if (result != null){
477
//            statisticalValues.add(result);
478
//        }
479
//        return result;
480
//    }
481

    
482
	public Boolean getUnknownData() {
483
		return unknownData;
484
	}
485

    
486
	public void setUnknownData(Boolean unknownData) {
487
		this.unknownData = unknownData;
488
	}
489

    
490
//
491
//	public BigDecimal getMinimum() {
492
//		return minimum;
493
//	}
494
//
495
//	public void setMinimum(BigDecimal minimum) {
496
//		this.minimum = minimum;
497
//	}
498
//
499
//	public BigDecimal getMaximum() {
500
//		return maximum;
501
//	}
502
//
503
//	public void setMaximum(BigDecimal maximum) {
504
//		this.maximum = maximum;
505
//	}
506
//
507
//	public BigDecimal getVariance() {
508
//		return variance;
509
//	}
510
//
511
//	public void setVariance(BigDecimal variance) {
512
//		this.variance = variance;
513
//	}
514
//
515
//	public BigDecimal getSingleValue() {
516
//		return singleValue;
517
//	}
518
//
519
//	public void setSingleValue(BigDecimal singleValue) {
520
//		this.singleValue = singleValue;
521
//	}
522

    
523
//
524
//	public void setAverage(BigDecimal average) {
525
//		this.average = average;
526
//	}
527
//
528
//	public void setStandardDeviation(BigDecimal standardDeviation) {
529
//		this.standardDeviation = standardDeviation;
530
//	}
531
//
532
//	public void setSampleSize(Integer sampleSize) {
533
//		this.sampleSize = sampleSize;
534
//	}
535

    
536

    
537
    @Transient
538
    @XmlTransient
539
    @Override
540
    public boolean isCharacterData() {
541
        return true;
542
    }
543

    
544

    
545
//*********************************** CLONE *****************************************/
546

    
547
	/**
548
	 * Clones <i>this</i> quantitative data. This is a shortcut that enables to create
549
	 * a new instance that differs only slightly from <i>this</i> quantitative data by
550
	 * modifying only some of the attributes.
551
	 *
552
	 * @see eu.etaxonomy.cdm.model.description.DescriptionElementBase#clone()
553
	 * @see java.lang.Object#clone()
554
	 */
555
	@Override
556
	public Object clone() {
557

    
558
		try {
559
			QuantitativeData result = (QuantitativeData)super.clone();
560

    
561
			//states
562
			result.statisticalValues = new HashSet<StatisticalMeasurementValue>();
563
			for (StatisticalMeasurementValue data : getStatisticalValues()){
564
				//TODO do we need to clone here?
565
				StatisticalMeasurementValue newData = (StatisticalMeasurementValue)data.clone();
566
				result.statisticalValues.add(newData);
567
			}
568

    
569
			return result;
570
			//no changes to: unit
571
		} catch (CloneNotSupportedException e) {
572
			logger.warn("Object does not implement cloneable");
573
			e.printStackTrace();
574
			return null;
575
		}
576
	}
577

    
578
}
(23-23/36)