minor
[cdmlib.git] / cdmlib-model / src / main / java / eu / etaxonomy / cdm / model / description / QuantitativeData.java
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.ArrayList;
13 import java.util.HashSet;
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.XmlType;
29
30 import org.apache.log4j.Logger;
31 import org.hibernate.annotations.Cascade;
32 import org.hibernate.annotations.CascadeType;
33 import org.hibernate.envers.Audited;
34 import org.hibernate.search.annotations.Indexed;
35 import org.hibernate.validator.constraints.NotEmpty;
36
37 import eu.etaxonomy.cdm.validation.Level2;
38
39 /**
40 * This class represents information pieces expressed in numerical data
41 * (in opposition to {@link CategoricalData categorical data} on one side and to literal data on
42 * the other side). Only {@link TaxonDescription taxon descriptions} and
43 * {@link SpecimenDescription specimen descriptions} may contain quantitative data.<BR>
44 * The "length of leaves" {@link Feature feature} for instance can be measured in inches.
45 * If the length of leaves of a particular tree is described as
46 * "typically between 3 and 5 inches" and "at the utmost 8 inches" then three
47 * {@link StatisticalMeasurementValue statistical measurement value} instances
48 * must be assigned to an instance of the present class
49 * (with the {@link MeasurementUnit measurement unit} set to "inch"):<ul>
50 * <li> the first one with the value "3" and the {@link StatisticalMeasure statistical measure}
51 * "typical lower boundary",
52 * <li> the second one with the value "5" and the statistical measure
53 * "typical upper boundary"
54 * <li> the third one with the value "8" and the statistical measure "maximum"
55 * </ul>
56 * <P>
57 * This class corresponds partially to CodedDescriptionType according to
58 * the SDD schema.
59 *
60 * @author m.doering
61 * @version 1.0
62 * @created 08-Nov-2007 13:06:46
63 */
64 @XmlAccessorType(XmlAccessType.FIELD)
65 @XmlType(name = "QuantitativeData", propOrder = {
66 "unit",
67 "statisticalValues"
68 })
69 @XmlRootElement(name = "QuantitativeData")
70 @Entity
71 @Indexed(index = "eu.etaxonomy.cdm.model.description.DescriptionElementBase")
72 @Audited
73 public class QuantitativeData extends DescriptionElementBase implements Cloneable {
74 private static final long serialVersionUID = -2755806455420051488L;
75 @SuppressWarnings("unused")
76 private static final Logger logger = Logger.getLogger(QuantitativeData.class);
77
78 @XmlElement(name = "MeasurementUnit")
79 @XmlIDREF
80 @XmlSchemaType(name = "IDREF")
81 @ManyToOne(fetch = FetchType.LAZY)
82 private MeasurementUnit unit;
83
84 @XmlElementWrapper(name = "StatisticalValues")
85 @XmlElement(name = "StatisticalValue")
86 @OneToMany(fetch = FetchType.LAZY)
87 @Cascade({ CascadeType.SAVE_UPDATE, CascadeType.MERGE, CascadeType.DELETE,CascadeType.DELETE_ORPHAN })
88 @NotEmpty(groups = Level2.class)
89 private Set<StatisticalMeasurementValue> statisticalValues = new HashSet<StatisticalMeasurementValue>();
90
91 // ******************************** FACTORY METHOD *******************************/
92
93 /**
94 * Creates a new empty quantitative data instance.
95 */
96 public static QuantitativeData NewInstance(){
97 return new QuantitativeData();
98 }
99
100 // ******************************** FACTORY METHOD *******************************/
101
102 /**
103 * Creates a new empty quantitative data instance.
104 */
105 public static QuantitativeData NewInstance(Feature feature){
106 return new QuantitativeData(feature);
107 }
108
109
110 // ******************************** CONSTRUCTOR *******************************/
111
112 /**
113 * Class constructor: creates a new empty quantitative data instance.
114 */
115 protected QuantitativeData(){
116 super(null);
117 }
118
119 /**
120 * Class constructor: creates a new empty quantitative data instance.
121 */
122 protected QuantitativeData(Feature feature){
123 super(feature);
124 }
125
126
127 // ******************************** GETTER /SETTER *******************************/
128
129
130 /**
131 * Returns the set of {@link StatisticalMeasurementValue statistical measurement values} describing
132 * the {@link Feature feature} corresponding to <i>this</i> quantitative data.
133 */
134 public Set<StatisticalMeasurementValue> getStatisticalValues() {
135 return statisticalValues;
136 }
137
138 protected void setStatisticalValues(Set<StatisticalMeasurementValue> statisticalValues) {
139 this.statisticalValues = statisticalValues;
140 }
141 /**
142 * Adds a {@link StatisticalMeasurementValue statistical measurement value} to the set of
143 * {@link #getStatisticalValues() statistical measurement values} describing
144 * the {@link Feature feature} corresponding to <i>this</i> quantitative data.
145 *
146 * @param statisticalValue the statistical measurement value to be added to
147 * <i>this</i> quantitative data
148 * @see #getStatisticalValues()
149 */
150 public void addStatisticalValue(StatisticalMeasurementValue statisticalValue) {
151 this.statisticalValues.add(statisticalValue);
152 }
153 /**
154 * Removes one element from the set of {@link #getStatisticalValues() statistical measurement values}
155 * describing the {@link Feature feature} corresponding to <i>this</i> quantitative data.
156 *
157 * @param statisticalValue the statistical measurement value which should be removed
158 * @see #getStatisticalValues()
159 * @see #addStatisticalValue(StatisticalMeasurementValue)
160 */
161 public void removeStatisticalValue(StatisticalMeasurementValue statisticalValue) {
162 this.statisticalValues.remove(statisticalValue);
163 }
164
165
166 /**
167 * Returns the {@link MeasurementUnit measurement unit} used in <i>this</i>
168 * quantitative data.
169 */
170 public MeasurementUnit getUnit(){
171 return this.unit;
172 }
173 /**
174 * @see #getUnit()
175 */
176 public void setUnit(MeasurementUnit unit){
177 this.unit = unit;
178 }
179
180 // ******************************** TRANSIENT METHODS *******************************/
181
182
183 /**
184 * Returns the numerical value of the one {@link StatisticalMeasurementValue statistical measurement value}
185 * with the corresponding {@link StatisticalMeasure statistical measure} "minimum" and
186 * belonging to <i>this</i> quantitative data. Returns <code>null</code> if no such
187 * statistical measurement value instance exists.
188 */
189 @Transient
190 public Float getMin(){
191 return getSpecificStatisticalValue(StatisticalMeasure.MIN());
192 }
193
194 /**
195 * Returns the numerical value of the one {@link StatisticalMeasurementValue statistical measurement value}
196 * with the corresponding {@link StatisticalMeasure statistical measure} "maximum" and
197 * belonging to <i>this</i> quantitative data. Returns <code>null</code> if no such
198 * statistical measurement value instance exists.
199 */
200 @Transient
201 public Float getMax(){
202 return getSpecificStatisticalValue(StatisticalMeasure.MAX());
203 }
204
205 /**
206 * Returns the numerical value of the one {@link StatisticalMeasurementValue statistical measurement value}
207 * with the corresponding {@link StatisticalMeasure statistical measure}
208 * "typical lower boundary" and belonging to <i>this</i> quantitative data.
209 * Returns <code>null</code> if no such statistical measurement value instance exists.
210 */
211 @Transient
212 public Float getTypicalLowerBoundary(){
213 return getSpecificStatisticalValue(StatisticalMeasure.TYPICAL_LOWER_BOUNDARY());
214 }
215
216 /**
217 * Returns the numerical value of the one {@link StatisticalMeasurementValue statistical measurement value}
218 * with the corresponding {@link StatisticalMeasure statistical measure}
219 * "typical upper boundary" and belonging to <i>this</i> quantitative data.
220 * Returns <code>null</code> if no such statistical measurement value instance exists.
221 */
222 @Transient
223 public Float getTypicalUpperBoundary(){
224 return getSpecificStatisticalValue(StatisticalMeasure.TYPICAL_UPPER_BOUNDARY());
225 }
226
227 /**
228 * Returns the statistical value of type <code>type</code>.
229 * If no such value exists <code>null</code> is returned. If multiple such
230 * values exist an arbitrary one is returned.
231 * @param type
232 * @return the value
233 */
234 public Float getSpecificStatisticalValue(StatisticalMeasure type){
235 Float result = null;
236 for (StatisticalMeasurementValue value : statisticalValues){
237 if (type.equals(value.getType())){
238 result = value.getValue();
239 break;
240 }
241 }
242 return result;
243 }
244
245
246 //*********************************** CLONE *****************************************/
247
248 /**
249 * Clones <i>this</i> quantitative data. This is a shortcut that enables to create
250 * a new instance that differs only slightly from <i>this</i> quantitative data by
251 * modifying only some of the attributes.
252 *
253 * @see eu.etaxonomy.cdm.model.description.DescriptionElementBase#clone()
254 * @see java.lang.Object#clone()
255 */
256 @Override
257 public Object clone() {
258
259 try {
260 QuantitativeData result = (QuantitativeData)super.clone();
261
262 //states
263 result.statisticalValues = new HashSet<StatisticalMeasurementValue>();
264 for (StatisticalMeasurementValue data : getStatisticalValues()){
265 //TODO do we need to clone here?
266 StatisticalMeasurementValue newData = (StatisticalMeasurementValue)data.clone();
267 result.statisticalValues.add(newData);
268 }
269
270 return result;
271 //no changes to: unit
272 } catch (CloneNotSupportedException e) {
273 logger.warn("Object does not implement cloneable");
274 e.printStackTrace();
275 return null;
276 }
277 }
278
279 }