free text search: better querying for 'isNotNull' and code harmonization
[cdmlib.git] / cdmlib-model / src / main / java / eu / etaxonomy / cdm / model / description / QuantitativeData.java
index 2799e2db67db1666156207910e8f0b1485b49303..208ac3c5fbf52a9fa5228c8d423a9ad4b001ffd7 100644 (file)
@@ -13,6 +13,7 @@ import java.util.HashSet;
 import java.util.Set;
 
 import javax.persistence.Entity;
+import javax.persistence.FetchType;
 import javax.persistence.ManyToOne;
 import javax.persistence.OneToMany;
 import javax.persistence.Transient;
@@ -28,6 +29,11 @@ import javax.xml.bind.annotation.XmlType;
 import org.apache.log4j.Logger;
 import org.hibernate.annotations.Cascade;
 import org.hibernate.annotations.CascadeType;
+import org.hibernate.envers.Audited;
+import org.hibernate.search.annotations.Indexed;
+import org.hibernate.validator.constraints.NotEmpty;
+
+import eu.etaxonomy.cdm.validation.Level2;
 
 /**
  * This class represents information pieces expressed in numerical data
@@ -61,7 +67,9 @@ import org.hibernate.annotations.CascadeType;
 })
 @XmlRootElement(name = "QuantitativeData")
 @Entity
-public class QuantitativeData extends DescriptionElementBase {
+@Indexed(index = "eu.etaxonomy.cdm.model.description.DescriptionElementBase")
+@Audited
+public class QuantitativeData extends DescriptionElementBase implements Cloneable {
        private static final long serialVersionUID = -2755806455420051488L;
        @SuppressWarnings("unused")
        private static final Logger logger = Logger.getLogger(QuantitativeData.class);
@@ -69,42 +77,64 @@ public class QuantitativeData extends DescriptionElementBase {
        @XmlElement(name = "MeasurementUnit")
        @XmlIDREF
        @XmlSchemaType(name = "IDREF")
+       @ManyToOne(fetch = FetchType.LAZY)
        private MeasurementUnit unit;
        
        @XmlElementWrapper(name = "StatisticalValues")
        @XmlElement(name = "StatisticalValue")
-       @XmlIDREF
-       @XmlSchemaType(name = "IDREF")
+       @OneToMany(fetch = FetchType.LAZY)
+       @Cascade({ CascadeType.SAVE_UPDATE, CascadeType.MERGE, CascadeType.DELETE,CascadeType.DELETE_ORPHAN })
+       @NotEmpty(groups = Level2.class)
        private Set<StatisticalMeasurementValue> statisticalValues = new HashSet<StatisticalMeasurementValue>();
+
+// ******************************** FACTORY METHOD *******************************/
+       
+       /** 
+        * Creates a new empty quantitative data instance.
+        */
+       public static QuantitativeData NewInstance(){
+               return new QuantitativeData();
+       }
+
+// ******************************** FACTORY METHOD *******************************/
+       
+       /** 
+        * Creates a new empty quantitative data instance.
+        */
+       public static QuantitativeData NewInstance(Feature feature){
+               return new QuantitativeData(feature);
+       }
+
        
+// ******************************** CONSTRUCTOR *******************************/
+
        /** 
         * Class constructor: creates a new empty quantitative data instance.
         */
        protected QuantitativeData(){
                super(null);
        }
-       
+
        /** 
-        * Creates a new empty quantitative data instance.
+        * Class constructor: creates a new empty quantitative data instance.
         */
-       public static QuantitativeData NewInstance(){
-               return new QuantitativeData();
+       protected QuantitativeData(Feature feature){
+               super(feature);
        }
+
+       
+// ******************************** GETTER /SETTER *******************************/
+       
        
        /** 
         * Returns the set of {@link StatisticalMeasurementValue statistical measurement values} describing
         * the {@link Feature feature} corresponding to <i>this</i> quantitative data.
         */
-       @OneToMany
-       @Cascade({CascadeType.SAVE_UPDATE})
        public Set<StatisticalMeasurementValue> getStatisticalValues() {
                return statisticalValues;
        }
-       /**
-        * @see #getStatisticalValues() 
-        */
-       protected void setStatisticalValues(
-                       Set<StatisticalMeasurementValue> statisticalValues) {
+
+       protected void setStatisticalValues(Set<StatisticalMeasurementValue> statisticalValues) {
                this.statisticalValues = statisticalValues;
        }
        /**
@@ -116,8 +146,7 @@ public class QuantitativeData extends DescriptionElementBase {
         *                                                      <i>this</i> quantitative data
         * @see                                         #getStatisticalValues()
         */
-       public void addStatisticalValue(
-                       StatisticalMeasurementValue statisticalValue) {
+       public void addStatisticalValue(StatisticalMeasurementValue statisticalValue) {
                this.statisticalValues.add(statisticalValue);
        }
        /** 
@@ -128,8 +157,7 @@ public class QuantitativeData extends DescriptionElementBase {
         * @see                                 #getStatisticalValues()
         * @see                                 #addStatisticalValue(StatisticalMeasurementValue)
         */
-       public void removeStatisticalValue(
-                       StatisticalMeasurementValue statisticalValue) {
+       public void removeStatisticalValue(StatisticalMeasurementValue statisticalValue) {
                this.statisticalValues.remove(statisticalValue);
        }
 
@@ -138,7 +166,6 @@ public class QuantitativeData extends DescriptionElementBase {
         * Returns the {@link MeasurementUnit measurement unit} used in <i>this</i>
         * quantitative data.
         */
-       @ManyToOne
        public MeasurementUnit getUnit(){
                return this.unit;
        }
@@ -149,48 +176,265 @@ public class QuantitativeData extends DescriptionElementBase {
                this.unit = unit;
        }
 
+// ******************************** TRANSIENT METHODS *******************************/
+       
+       
        /** 
         * Returns the numerical value of the one {@link StatisticalMeasurementValue statistical measurement value}
         * with the corresponding {@link StatisticalMeasure statistical measure} "minimum" and
-        * belonging to <i>this</i> quantitative data. Returns "0" if no such
+        * belonging to <i>this</i> quantitative data. Returns <code>null</code> if no such
         * statistical measurement value instance exists. 
         */
        @Transient
-       public float getMin(){
-               return 0;
+       public Float getMin(){
+               return getSpecificStatisticalValue(StatisticalMeasure.MIN());
        }
 
        /** 
         * Returns the numerical value of the one {@link StatisticalMeasurementValue statistical measurement value}
         * with the corresponding {@link StatisticalMeasure statistical measure} "maximum" and
-        * belonging to <i>this</i> quantitative data. Returns "0" if no such
+        * belonging to <i>this</i> quantitative data. Returns <code>null</code> if no such
         * statistical measurement value instance exists. 
         */
        @Transient
-       public float getMax(){
-               return 0;
+       public Float getMax(){
+               return getSpecificStatisticalValue(StatisticalMeasure.MAX());
        }
 
        /** 
         * Returns the numerical value of the one {@link StatisticalMeasurementValue statistical measurement value}
         * with the corresponding {@link StatisticalMeasure statistical measure}
         * "typical lower boundary" and belonging to <i>this</i> quantitative data.
-        * Returns "0" if no such statistical measurement value instance exists. 
+        * Returns <code>null</code> if no such statistical measurement value instance exists. 
+        */
+       @Transient
+       public Float getTypicalLowerBoundary(){
+               return getSpecificStatisticalValue(StatisticalMeasure.TYPICAL_LOWER_BOUNDARY());
+       }
+       
+       /** 
+        * Returns the numerical value of the one {@link StatisticalMeasurementValue statistical measurement value}
+        * with the corresponding {@link StatisticalMeasure statistical measure}
+        * "average" and belonging to <i>this</i> quantitative data.
+        * Returns <code>null</code> if no such statistical measurement value instance exists. 
         */
        @Transient
-       public float getTypicalLowerBoundary(){
-               return 0;
+       public Float getAverage(){
+               return getSpecificStatisticalValue(StatisticalMeasure.AVERAGE());
        }
 
+       /** 
+        * Returns the numerical value of the one {@link StatisticalMeasurementValue statistical measurement value}
+        * with the corresponding {@link StatisticalMeasure statistical measure}
+        * "standard deviation" and belonging to <i>this</i> quantitative data.
+        * Returns <code>null</code> if no such statistical measurement value instance exists. 
+        */
+       @Transient
+       public Float getStandardDeviation(){
+               return getSpecificStatisticalValue(StatisticalMeasure.STANDARD_DEVIATION());
+       }
+
+       /** 
+        * Returns the numerical value of the one {@link StatisticalMeasurementValue statistical measurement value}
+        * with the corresponding {@link StatisticalMeasure statistical measure}
+        * "sample size" and belonging to <i>this</i> quantitative data.
+        * Returns <code>null</code> if no such statistical measurement value instance exists. 
+        */
+       @Transient
+       public Float getSampleSize(){
+               return getSpecificStatisticalValue(StatisticalMeasure.SAMPLE_SIZE());
+       }
+       
        /** 
         * Returns the numerical value of the one {@link StatisticalMeasurementValue statistical measurement value}
         * with the corresponding {@link StatisticalMeasure statistical measure}
         * "typical upper boundary" and belonging to <i>this</i> quantitative data.
-        * Returns "0" if no such statistical measurement value instance exists. 
+        * Returns <code>null</code> if no such statistical measurement value instance exists. 
+        */
+       @Transient
+       public Float getTypicalUpperBoundary(){
+               return getSpecificStatisticalValue(StatisticalMeasure.TYPICAL_UPPER_BOUNDARY());
+       }
+
+       /**
+        * Returns the statistical value of type <code>type</code>.
+        * If no such value exists <code>null</code> is returned. If multiple such
+        * values exist an arbitrary one is returned.
+        * @param type
+        * @return the value
+        */
+       public Float getSpecificStatisticalValue(StatisticalMeasure type){
+               Float result = null;
+               for (StatisticalMeasurementValue value : statisticalValues){
+                       if (type.equals(value.getType())){
+                               result = value.getValue();
+                               break;
+                       }
+               }
+               return result;
+       }
+
+       
+       /**
+        * Sets the statistical value for the minimum.
+        * If such value exists the old value is replaced by the new value. 
+        * The new value is returned.
+        * @param type
+        * @param value
+        * @return the newValue
+        */
+       @Transient
+       public StatisticalMeasurementValue setMinimum(Float value, Set<Modifier> modifiers){
+               return setSpecificStatisticalValue(value, modifiers, StatisticalMeasure.MIN());
+       }
+
+       
+       /**
+        * Sets the statistical value for the maximum.
+        * If such value exists the old value is replaced by the new value. 
+        * The new value is returned.
+        * @param type
+        * @param value
+        * @return the newValue
+        */
+       @Transient
+       public StatisticalMeasurementValue setMaximum(Float value, Set<Modifier> modifiers){
+               return setSpecificStatisticalValue(value, modifiers, StatisticalMeasure.MAX());
+       }
+       
+       
+       /**
+        * Sets the statistical value for the average.
+        * If such value exists the old value is replaced by the new value. 
+        * The new value is returned.
+        * @param type
+        * @param value
+        * @return the newValue
         */
        @Transient
-       public float getTypicalUpperBoundary(){
-               return 0;
+       public StatisticalMeasurementValue setAverage(Float value, Set<Modifier> modifiers){
+               return setSpecificStatisticalValue(value, modifiers, StatisticalMeasure.AVERAGE());
        }
 
+       
+       /**
+        * Sets the statistical value for the standard deviation.
+        * If such value exists the old value is replaced by the new value. 
+        * The new value is returned.
+        * @param type
+        * @param value
+        * @return the newValue
+        */
+       @Transient
+       public StatisticalMeasurementValue setStandardDeviation(Float value, Set<Modifier> modifiers){
+               return setSpecificStatisticalValue(value, modifiers, StatisticalMeasure.STANDARD_DEVIATION());
+       }
+
+       /**
+        * Sets the statistical value for the sample size.
+        * If such value exists the old value is replaced by the new value. 
+        * The new value is returned.
+        * @param type
+        * @param value
+        * @return the newValue
+        */
+       @Transient
+       public StatisticalMeasurementValue setSampleSize(Float value, Set<Modifier> modifiers){
+               return setSpecificStatisticalValue(value, modifiers, StatisticalMeasure.SAMPLE_SIZE());
+       }
+
+       
+       /**
+        * Sets the statistical value for the typical lower boundary.
+        * If such value exists the old value is replaced by the new value. 
+        * The new value is returned.
+        * @param type
+        * @param value
+        * @return the newValue
+        */
+       @Transient
+       public StatisticalMeasurementValue setTypicalLowerBoundary(Float value, Set<Modifier> modifiers){
+               return setSpecificStatisticalValue(value, modifiers, StatisticalMeasure.TYPICAL_LOWER_BOUNDARY());
+       }
+
+       
+       /**
+        * Sets the statistical value for the typical upper boundary.
+        * If such value exists the old value is replaced by the new value. 
+        * The new value is returned.
+        * @param type
+        * @param value
+        * @return the newValue
+        */
+       @Transient
+       public StatisticalMeasurementValue setTypicalUpperBoundary(Float value, Set<Modifier> modifiers){
+               return setSpecificStatisticalValue(value, modifiers, StatisticalMeasure.TYPICAL_UPPER_BOUNDARY());
+       }
+       
+       /**
+        * Sets the statistical value of type <code>type</code>.
+        * If such value exists the old value is replaced by the new value. 
+        * The new value is returned.
+        * @param type
+        * @param value
+        * @return the newValue
+        */
+       public StatisticalMeasurementValue setSpecificStatisticalValue(Float value, Set<Modifier> modifiers, StatisticalMeasure type){
+               StatisticalMeasurementValue result = null;
+               if (value != null){
+                       StatisticalMeasurementValue newValue = StatisticalMeasurementValue.NewInstance();
+                       newValue.setValue(value);
+                       if (modifiers != null){
+                               newValue.getModifiers().addAll(modifiers);
+                       }
+                       newValue.setType(type);
+                       result = newValue;
+               }
+               for (StatisticalMeasurementValue existingValue : statisticalValues){
+                       if (type.equals(existingValue.getType())){
+                               result = existingValue;
+                               statisticalValues.remove(existingValue);
+                               break;
+                       }
+               }
+               if (result != null){
+                       statisticalValues.add(result);
+               }
+               return result;
+       }
+       
+
+//*********************************** CLONE *****************************************/
+
+       /** 
+        * Clones <i>this</i> quantitative data. This is a shortcut that enables to create
+        * a new instance that differs only slightly from <i>this</i> quantitative data by
+        * modifying only some of the attributes.
+        * 
+        * @see eu.etaxonomy.cdm.model.description.DescriptionElementBase#clone()
+        * @see java.lang.Object#clone()
+        */
+       @Override
+       public Object clone() {
+
+               try {
+                       QuantitativeData result = (QuantitativeData)super.clone();
+                       
+                       //states
+                       result.statisticalValues = new HashSet<StatisticalMeasurementValue>();
+                       for (StatisticalMeasurementValue data : getStatisticalValues()){
+                               //TODO do we need to clone here?
+                               StatisticalMeasurementValue newData = (StatisticalMeasurementValue)data.clone();
+                               result.statisticalValues.add(newData);
+                       }
+                       
+                       return result;
+                       //no changes to: unit
+               } catch (CloneNotSupportedException e) {
+                       logger.warn("Object does not implement cloneable");
+                       e.printStackTrace();
+                       return null;
+               }
+       }       
+
 }
\ No newline at end of file