2 * Copyright (C) 2007 EDIT
3 * European Distributed Institute of Taxonomy
4 * http://www.e-taxonomy.eu
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.
10 package eu
.etaxonomy
.cdm
.model
.description
;
12 import java
.math
.BigDecimal
;
13 import java
.util
.HashSet
;
14 import java
.util
.Iterator
;
17 import javax
.persistence
.Column
;
18 import javax
.persistence
.Entity
;
19 import javax
.persistence
.FetchType
;
20 import javax
.persistence
.ManyToOne
;
21 import javax
.persistence
.OneToMany
;
22 import javax
.persistence
.Transient
;
23 import javax
.validation
.constraints
.NotEmpty
;
24 import javax
.xml
.bind
.annotation
.XmlAccessType
;
25 import javax
.xml
.bind
.annotation
.XmlAccessorType
;
26 import javax
.xml
.bind
.annotation
.XmlAttribute
;
27 import javax
.xml
.bind
.annotation
.XmlElement
;
28 import javax
.xml
.bind
.annotation
.XmlElementWrapper
;
29 import javax
.xml
.bind
.annotation
.XmlIDREF
;
30 import javax
.xml
.bind
.annotation
.XmlRootElement
;
31 import javax
.xml
.bind
.annotation
.XmlSchemaType
;
32 import javax
.xml
.bind
.annotation
.XmlTransient
;
33 import javax
.xml
.bind
.annotation
.XmlType
;
35 import org
.apache
.logging
.log4j
.LogManager
;
36 import org
.apache
.logging
.log4j
.Logger
;
37 import org
.hibernate
.annotations
.Cascade
;
38 import org
.hibernate
.annotations
.CascadeType
;
39 import org
.hibernate
.annotations
.Type
;
40 import org
.hibernate
.envers
.Audited
;
41 import org
.hibernate
.search
.annotations
.Indexed
;
43 import eu
.etaxonomy
.cdm
.common
.BigDecimalUtil
;
44 import eu
.etaxonomy
.cdm
.model
.term
.DefinedTerm
;
45 import eu
.etaxonomy
.cdm
.validation
.Level2
;
48 * This class represents information pieces expressed in numerical data
49 * (in opposition to {@link CategoricalData categorical data} on one side and to literal data on
50 * the other side). Only {@link TaxonDescription taxon descriptions} and
51 * {@link SpecimenDescription specimen descriptions} may contain quantitative data.<BR>
52 * The "length of leaves" {@link Feature feature} for instance can be measured in inches.
53 * If the length of leaves of a particular tree is described as
54 * "typically between 3 and 5 inches" and "at the utmost 8 inches" then three
55 * {@link StatisticalMeasurementValue statistical measurement value} instances
56 * must be assigned to an instance of the present class
57 * (with the {@link MeasurementUnit measurement unit} set to "inch"):<ul>
58 * <li> the first one with the value "3" and the {@link StatisticalMeasure statistical measure}
59 * "typical lower boundary",
60 * <li> the second one with the value "5" and the statistical measure
61 * "typical upper boundary"
62 * <li> the third one with the value "8" and the statistical measure "maximum"
65 * This class corresponds partially to CodedDescriptionType according to
69 * @since 08-Nov-2007 13:06:46
71 @XmlAccessorType(XmlAccessType
.FIELD
)
72 @XmlType(name
= "QuantitativeData", propOrder
= {
77 @XmlRootElement(name
= "QuantitativeData")
79 @Indexed(index
= "eu.etaxonomy.cdm.model.description.DescriptionElementBase")
81 public class QuantitativeData
82 extends DescriptionElementBase
{
84 private static final long serialVersionUID
= -2755806455420051488L;
85 @SuppressWarnings("unused")
86 private static final Logger logger
= LogManager
.getLogger();
88 @XmlElement(name
= "MeasurementUnit")
90 @XmlSchemaType(name
= "IDREF")
91 @ManyToOne(fetch
= FetchType
.LAZY
)
92 private MeasurementUnit unit
;
94 @XmlElementWrapper(name
= "StatisticalValues")
95 @XmlElement(name
= "StatisticalValue")
96 @OneToMany(fetch
= FetchType
.LAZY
, mappedBy
="quantitativeData", orphanRemoval
=true)
97 @Cascade({ CascadeType
.SAVE_UPDATE
, CascadeType
.MERGE
, CascadeType
.DELETE
})
98 @NotEmpty(groups
= Level2
.class)
99 private Set
<StatisticalMeasurementValue
> statisticalValues
= new HashSet
<>();
102 // @Column(precision = 20, scale = 10)
103 // private BigDecimal minimum;
105 // @Column(precision = 20, scale = 10)
106 // private BigDecimal maximum;
108 // @Column(precision = 20, scale = 10)
109 // private BigDecimal average;
111 // @Column(precision = 16, scale = 8)
112 // private BigDecimal variance;
114 // @Column(precision = 16, scale = 8)
115 // private BigDecimal standardDeviation;
117 // @Column(precision = 20, scale = 10)
118 // private BigDecimal singleValue;
120 // private Integer sampleSize;
122 @XmlElement(name
= "UnknownData")
123 @Deprecated //will be replaced by #noDataStatus
124 private Boolean unknownData
= false;
126 @XmlAttribute(name
="NoDataStatus")
127 @Column(name
="noDataStatus", length
=10)
128 @Type(type
= "eu.etaxonomy.cdm.hibernate.EnumUserType",
129 parameters
= {@org.hibernate
.annotations
.Parameter(name
= "enumClass", value
= "eu.etaxonomy.cdm.model.description.NoDescriptiveDataStatus")}
131 //see also CategoricalData.noDataStatus
132 private NoDescriptiveDataStatus noDataStatus
;
134 // ******************************** FACTORY METHODS *******************************/
137 * Creates a new empty quantitative data instance.
139 public static QuantitativeData
NewInstance(){
140 return new QuantitativeData();
144 * Creates a new quantitative data instance of type feature.
146 public static QuantitativeData
NewInstance(Feature feature
){
147 return new QuantitativeData(feature
);
151 * Creates a new quantitative data instance of type feature with defined min and may value.
153 public static QuantitativeData
NewMinMaxInstance(Feature feature
, BigDecimal min
, BigDecimal max
){
154 QuantitativeData result
= new QuantitativeData(feature
);
156 StatisticalMeasurementValue minValue
= StatisticalMeasurementValue
.NewInstance(StatisticalMeasure
.MIN(),min
);
157 result
.addStatisticalValue(minValue
);
160 StatisticalMeasurementValue maxValue
= StatisticalMeasurementValue
.NewInstance(StatisticalMeasure
.MAX(), max
);
161 result
.addStatisticalValue(maxValue
);
167 * Creates a new quantitative data instance of type feature with defined exact value.
169 public static QuantitativeData
NewExactValueInstance(Feature feature
, BigDecimal
... exactValues
){
170 QuantitativeData result
= new QuantitativeData(feature
);
171 for (BigDecimal exactVal
: exactValues
){
172 StatisticalMeasurementValue exactValue
= StatisticalMeasurementValue
.NewInstance(StatisticalMeasure
.EXACT_VALUE(), exactVal
);
173 result
.addStatisticalValue(exactValue
);
178 public static QuantitativeData
NewMinMaxInstance(Feature feature
, MeasurementUnit unit
, BigDecimal min
, BigDecimal max
){
179 QuantitativeData result
= NewMinMaxInstance(feature
, min
, max
);
180 result
.setUnit(unit
);
184 public static QuantitativeData
NewExactValueInstance(Feature feature
, MeasurementUnit unit
, BigDecimal
... exactValues
){
185 QuantitativeData result
= NewExactValueInstance(feature
, exactValues
);
186 result
.setUnit(unit
);
190 // ******************************** CONSTRUCTOR *******************************/
193 * Class constructor: creates a new empty quantitative data instance.
195 protected QuantitativeData(){
200 * Class constructor: creates a new empty quantitative data instance.
202 protected QuantitativeData(Feature feature
){
206 // ******************************** GETTER /SETTER *******************************/
209 * Returns the set of {@link StatisticalMeasurementValue statistical measurement values} describing
210 * the {@link Feature feature} corresponding to <i>this</i> quantitative data.
212 public Set
<StatisticalMeasurementValue
> getStatisticalValues() {
213 return statisticalValues
;
216 @Deprecated //for internal use only
217 protected void setStatisticalValues(Set
<StatisticalMeasurementValue
> statisticalValues
) {
218 this.statisticalValues
= statisticalValues
;
221 * Adds a {@link StatisticalMeasurementValue statistical measurement value} to the set of
222 * {@link #getStatisticalValues() statistical measurement values} describing
223 * the {@link Feature feature} corresponding to <i>this</i> quantitative data.
225 * @param statisticalValue the statistical measurement value to be added to
226 * <i>this</i> quantitative data
227 * @see #getStatisticalValues()
229 @SuppressWarnings("deprecation")
230 public void addStatisticalValue(StatisticalMeasurementValue statisticalValue
) {
231 this.statisticalValues
.add(statisticalValue
);
232 statisticalValue
.setQuantitativeData(this);
235 * Removes one element from the set of {@link #getStatisticalValues() statistical measurement values}
236 * describing the {@link Feature feature} corresponding to <i>this</i> quantitative data.
238 * @param statisticalValue the statistical measurement value which should be removed
239 * @see #getStatisticalValues()
240 * @see #addStatisticalValue(StatisticalMeasurementValue)
242 @SuppressWarnings("deprecation")
243 public void removeStatisticalValue(StatisticalMeasurementValue statisticalValue
) {
244 this.statisticalValues
.remove(statisticalValue
);
245 statisticalValue
.setQuantitativeData(null);
250 * Returns the {@link MeasurementUnit measurement unit} used in <i>this</i>
253 public MeasurementUnit
getUnit(){
259 public void setUnit(MeasurementUnit unit
){
263 // ******************************** TRANSIENT METHODS *******************************/
266 public BigDecimal
getOverallMin(){
267 BigDecimal result
= BigDecimalUtil
.MAX_BIGDECIMAL
;
268 for (StatisticalMeasurementValue value
: statisticalValues
){
269 if (withRangeValue(value
)){
270 result
= result
.min(value
.getValue());
273 return (result
== BigDecimalUtil
.MAX_BIGDECIMAL
)?
null: result
;
277 public BigDecimal
getOverallMax(){
278 BigDecimal result
= BigDecimalUtil
.MIN_BIGDECIMAL
;
279 for (StatisticalMeasurementValue value
: statisticalValues
){
280 if (withRangeValue(value
)){
281 result
= result
.max(value
.getValue());
284 return (result
== BigDecimalUtil
.MIN_BIGDECIMAL
)?
null: result
;
287 private boolean withRangeValue(StatisticalMeasurementValue value
) {
288 StatisticalMeasure type
= value
.getType();
290 if (type
.isAverage()|| type
.isMin() || type
.isTypicalLowerBoundary()||type
.isMax()||type
.isTypicalUpperBoundary()||type
.isExactValue()){
298 * Returns the numerical value of the one {@link StatisticalMeasurementValue statistical measurement value}
299 * with the corresponding {@link StatisticalMeasure statistical measure} "minimum" and
300 * belonging to <i>this</i> quantitative data. Returns <code>null</code> if no such
301 * statistical measurement value instance exists.
304 public BigDecimal
getMin(){
305 return getSpecificStatisticalValue(StatisticalMeasure
.MIN());
309 * Returns the numerical value of the one {@link StatisticalMeasurementValue statistical measurement value}
310 * with the corresponding {@link StatisticalMeasure statistical measure} "maximum" and
311 * belonging to <i>this</i> quantitative data. Returns <code>null</code> if no such
312 * statistical measurement value instance exists.
315 public BigDecimal
getMax(){
316 return getSpecificStatisticalValue(StatisticalMeasure
.MAX());
320 * Returns the numerical value of the one {@link StatisticalMeasurementValue statistical measurement value}
321 * with the corresponding {@link StatisticalMeasure statistical measure}
322 * "typical lower boundary" and belonging to <i>this</i> quantitative data.
323 * Returns <code>null</code> if no such statistical measurement value instance exists.
326 public BigDecimal
getTypicalLowerBoundary(){
327 return getSpecificStatisticalValue(StatisticalMeasure
.TYPICAL_LOWER_BOUNDARY());
331 public Set
<BigDecimal
> getExactValues(){
332 return getSpecificStatisticalValues(StatisticalMeasure
.EXACT_VALUE());
336 * Returns the numerical value of the one {@link StatisticalMeasurementValue statistical measurement value}
337 * with the corresponding {@link StatisticalMeasure statistical measure}
338 * "average" and belonging to <i>this</i> quantitative data.
339 * Returns <code>null</code> if no such statistical measurement value instance exists.
342 public BigDecimal
getAverage(){
343 return getSpecificStatisticalValue(StatisticalMeasure
.AVERAGE());
347 * Returns the numerical value of the one {@link StatisticalMeasurementValue statistical measurement value}
348 * with the corresponding {@link StatisticalMeasure statistical measure}
349 * "standard deviation" and belonging to <i>this</i> quantitative data.
350 * Returns <code>null</code> if no such statistical measurement value instance exists.
353 public BigDecimal
getStandardDeviation(){
354 return getSpecificStatisticalValue(StatisticalMeasure
.STANDARD_DEVIATION());
358 * Returns the numerical value of the one {@link StatisticalMeasurementValue statistical measurement value}
359 * with the corresponding {@link StatisticalMeasure statistical measure}
360 * "sample size" and belonging to <i>this</i> quantitative data.
361 * Returns <code>null</code> if no such statistical measurement value instance exists.
364 public BigDecimal
getSampleSize(){
365 return getSpecificStatisticalValue(StatisticalMeasure
.SAMPLE_SIZE());
369 * Returns the numerical value of the one {@link StatisticalMeasurementValue statistical measurement value}
370 * with the corresponding {@link StatisticalMeasure statistical measure}
371 * "typical upper boundary" and belonging to <i>this</i> quantitative data.
372 * Returns <code>null</code> if no such statistical measurement value instance exists.
375 public BigDecimal
getTypicalUpperBoundary(){
376 return getSpecificStatisticalValue(StatisticalMeasure
.TYPICAL_UPPER_BOUNDARY());
380 * Returns the statistical value of type <code>type</code>.
381 * If no such value exists <code>null</code> is returned. If multiple such
382 * values exist an arbitrary one is returned.
386 public BigDecimal
getSpecificStatisticalValue(StatisticalMeasure type
){
387 BigDecimal result
= null;
388 for (StatisticalMeasurementValue value
: statisticalValues
){
389 if (type
.equals(value
.getType())){
390 result
= value
.getValue();
397 public StatisticalMeasurementValue
getSpecificStatisticalValueAsSMV(StatisticalMeasure type
){
398 StatisticalMeasurementValue result
= null;
399 for (StatisticalMeasurementValue value
: statisticalValues
){
400 if (type
.equals(value
.getType())){
408 public Set
<BigDecimal
> getSpecificStatisticalValues(StatisticalMeasure type
){
409 Set
<BigDecimal
> result
= new HashSet
<>();
410 for (StatisticalMeasurementValue value
: statisticalValues
){
411 if (type
.equals(value
.getType())){
412 result
.add(value
.getValue());
420 * Sets the statistical value for the minimum.
421 * If such value exists the old value is replaced by the new value.
422 * The new value is returned.
425 * @return the newValue
428 public StatisticalMeasurementValue
setMinimum(BigDecimal value
, Set
<DefinedTerm
> modifiers
){
429 return setSpecificStatisticalValue(value
, modifiers
, StatisticalMeasure
.MIN());
434 * Sets the statistical value for the maximum.
435 * If such value exists the old value is replaced by the new value.
436 * The new value is returned.
439 * @return the newValue
442 public StatisticalMeasurementValue
setMaximum(BigDecimal value
, Set
<DefinedTerm
> modifiers
){
443 return setSpecificStatisticalValue(value
, modifiers
, StatisticalMeasure
.MAX());
448 * Sets the statistical value for the average.
449 * If such value exists the old value is replaced by the new value.
450 * The new value is returned.
453 * @return the newValue
456 public StatisticalMeasurementValue
setAverage(BigDecimal value
, Set
<DefinedTerm
> modifiers
){
457 return setSpecificStatisticalValue(value
, modifiers
, StatisticalMeasure
.AVERAGE());
461 * Sets the statistical value for the standard deviation.
462 * If such value exists the old value is replaced by the new value.
463 * The new value is returned.
466 * @return the newValue
469 public StatisticalMeasurementValue
setStandardDeviation(BigDecimal value
, Set
<DefinedTerm
> modifiers
){
470 return setSpecificStatisticalValue(value
, modifiers
, StatisticalMeasure
.STANDARD_DEVIATION());
474 * Sets the statistical value for the sample size.
475 * If such value exists the old value is replaced by the new value.
476 * The new value is returned.
479 * @return the newValue
482 public StatisticalMeasurementValue
setSampleSize(BigDecimal value
, Set
<DefinedTerm
> modifiers
){
483 return setSpecificStatisticalValue(value
, modifiers
, StatisticalMeasure
.SAMPLE_SIZE());
488 * Sets the statistical value for the typical lower boundary.
489 * If such value exists the old value is replaced by the new value.
490 * The new value is returned.
493 * @return the newValue
496 public StatisticalMeasurementValue
setTypicalLowerBoundary(BigDecimal value
, Set
<DefinedTerm
> modifiers
){
497 return setSpecificStatisticalValue(value
, modifiers
, StatisticalMeasure
.TYPICAL_LOWER_BOUNDARY());
502 * Sets the statistical value for the typical upper boundary.
503 * If such value exists the old value is replaced by the new value.
504 * The new value is returned.
507 * @return the newValue
510 public StatisticalMeasurementValue
setTypicalUpperBoundary(BigDecimal value
, Set
<DefinedTerm
> modifiers
){
511 return setSpecificStatisticalValue(value
, modifiers
, StatisticalMeasure
.TYPICAL_UPPER_BOUNDARY());
515 * Sets the statistical value of type <code>type</code>.
516 * If such value exists the old value is replaced by the new value.
517 * The new value is returned.
520 * @return the newValue
522 public StatisticalMeasurementValue
setSpecificStatisticalValue(BigDecimal value
,
523 Set
<DefinedTerm
> modifiers
, StatisticalMeasure type
){
525 StatisticalMeasurementValue result
= null;
526 StatisticalMeasurementValue existingSmValue
= null;
528 for (StatisticalMeasurementValue existingValue
: statisticalValues
){
529 if (type
.equals(existingValue
.getType())){
530 existingSmValue
= existingValue
;
534 if (value
== null && existingSmValue
== null){
536 }else if (value
== null && existingSmValue
!= null){
537 this.removeStatisticalValue(existingSmValue
);
539 }else if (value
!= null && existingSmValue
== null){
540 result
= StatisticalMeasurementValue
.NewInstance(type
, value
);
541 if (modifiers
!= null){
542 for (DefinedTerm modifier
: modifiers
){
543 result
.addModifier(modifier
);
546 this.addStatisticalValue(result
);
547 } else if (value
!= null && existingSmValue
!= null){
548 result
= existingSmValue
;
549 result
.setValue(value
);
550 //remove existing modifiers
551 Iterator
<DefinedTerm
> it
= result
.getModifiers().iterator();
552 while (it
.hasNext()){
556 if (modifiers
!= null){
557 for (DefinedTerm modifier
: modifiers
){
558 result
.addModifier(modifier
);
565 // public StatisticalMeasurementValue setSpecificStatisticalValue_old(Float value, Set<DefinedTerm> modifiers, StatisticalMeasure type){
566 // StatisticalMeasurementValue result = null;
567 // if (value != null){
568 // StatisticalMeasurementValue newValue = StatisticalMeasurementValue.NewInstance();
569 // newValue.setValue(value);
570 // if (modifiers != null){
571 // newValue.getModifiers().addAll(modifiers);
573 // newValue.setType(type);
574 // result = newValue;
576 // for (StatisticalMeasurementValue existingValue : statisticalValues){
577 // if (type.equals(existingValue.getType())){
578 // result = existingValue;
579 // statisticalValues.remove(existingValue);
583 // if (result != null){
584 // statisticalValues.add(result);
589 @Deprecated //will be replaced by #noDataStatus
590 public Boolean
getUnknownData() {
593 @Deprecated //will be replaced by #noDataStatus
594 public void setUnknownData(Boolean unknownData
) {
595 this.unknownData
= unknownData
;
598 //no data status, #2975
599 public NoDescriptiveDataStatus
getNoDataStatus() {
602 public void setNoDataStatus(NoDescriptiveDataStatus noDataStatus
) {
603 this.noDataStatus
= noDataStatus
;
607 // public BigDecimal getMinimum() {
611 // public void setMinimum(BigDecimal minimum) {
612 // this.minimum = minimum;
615 // public BigDecimal getMaximum() {
619 // public void setMaximum(BigDecimal maximum) {
620 // this.maximum = maximum;
623 // public BigDecimal getVariance() {
627 // public void setVariance(BigDecimal variance) {
628 // this.variance = variance;
631 // public BigDecimal getSingleValue() {
632 // return singleValue;
635 // public void setSingleValue(BigDecimal singleValue) {
636 // this.singleValue = singleValue;
640 // public void setAverage(BigDecimal average) {
641 // this.average = average;
644 // public void setStandardDeviation(BigDecimal standardDeviation) {
645 // this.standardDeviation = standardDeviation;
648 // public void setSampleSize(Integer sampleSize) {
649 // this.sampleSize = sampleSize;
656 public boolean isCharacterData() {
661 //*********************************** CLONE *****************************************/
664 * Clones <i>this</i> quantitative data. This is a shortcut that enables to create
665 * a new instance that differs only slightly from <i>this</i> quantitative data by
666 * modifying only some of the attributes.
668 * @see eu.etaxonomy.cdm.model.description.DescriptionElementBase#clone()
669 * @see java.lang.Object#clone()
672 public QuantitativeData
clone() {
674 QuantitativeData result
= (QuantitativeData
)super.clone();
677 result
.statisticalValues
= new HashSet
<>();
678 for (StatisticalMeasurementValue data
: getStatisticalValues()){
679 StatisticalMeasurementValue newData
= data
.clone();
680 result
.addStatisticalValue(newData
);
683 //no changes to: unit
688 //********************** TO STRING **************************************/
691 public String
toString() {
692 return (getFeature()!=null ?
getFeature().getLabel(): "") +
693 "[" + statisticalValues
+
694 (unit
!=null ?
", unit=" + unit
: "") +
695 (noDataStatus
!= null ?
", noDataStatus=" + noDataStatus
.getLabel() :"")