Project

General

Profile

Download (18.5 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
 * @since 08-Nov-2007 13:06:46
64
 */
65
@XmlAccessorType(XmlAccessType.FIELD)
66
@XmlType(name = "QuantitativeData", propOrder = {
67
    "unit",
68
    "statisticalValues",
69
    "unknownData"
70
})
71
@XmlRootElement(name = "QuantitativeData")
72
@Entity
73
@Indexed(index = "eu.etaxonomy.cdm.model.description.DescriptionElementBase")
74
@Audited
75
public class QuantitativeData extends DescriptionElementBase implements Cloneable {
76
	private static final long serialVersionUID = -2755806455420051488L;
77

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

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

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

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

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

    
117

    
118
// ******************************** FACTORY METHOD *******************************/
119

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

    
127
// ******************************** FACTORY METHOD *******************************/
128

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

    
136

    
137
// ******************************** CONSTRUCTOR *******************************/
138

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

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

    
153

    
154
// ******************************** GETTER /SETTER *******************************/
155

    
156

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

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

    
197

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

    
212
// ******************************** TRANSIENT METHODS *******************************/
213

    
214

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

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

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

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

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

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

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

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

    
310

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

    
324

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

    
338

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

    
352

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

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

    
379

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

    
393

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

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

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

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

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

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

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

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

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

    
535

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

    
543

    
544
//*********************************** CLONE *****************************************/
545

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

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

    
560
			//states
561
			result.statisticalValues = new HashSet<>();
562
			for (StatisticalMeasurementValue data : getStatisticalValues()){
563
				StatisticalMeasurementValue newData = (StatisticalMeasurementValue)data.clone();
564
				result.addStatisticalValue(newData);
565
			}
566

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

    
576
}
(24-24/37)