implement RankClass, remove iso639_2, add max values to distance attributes, change...
[cdmlib.git] / cdmlib-model / src / main / java / eu / etaxonomy / cdm / model / occurrence / GatheringEvent.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.occurrence;
11
12 import java.util.Calendar;
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.ManyToMany;
19 import javax.persistence.ManyToOne;
20 import javax.persistence.OneToOne;
21 import javax.persistence.Transient;
22 import javax.validation.constraints.NotNull;
23 import javax.validation.constraints.Size;
24 import javax.xml.bind.annotation.XmlAccessType;
25 import javax.xml.bind.annotation.XmlAccessorType;
26 import javax.xml.bind.annotation.XmlElement;
27 import javax.xml.bind.annotation.XmlElementWrapper;
28 import javax.xml.bind.annotation.XmlIDREF;
29 import javax.xml.bind.annotation.XmlRootElement;
30 import javax.xml.bind.annotation.XmlSchemaType;
31 import javax.xml.bind.annotation.XmlType;
32
33 import org.apache.log4j.Logger;
34 import org.hibernate.annotations.Cascade;
35 import org.hibernate.annotations.CascadeType;
36 import org.hibernate.envers.Audited;
37 import org.hibernate.search.annotations.Analyze;
38 import org.hibernate.search.annotations.Field;
39 import org.hibernate.search.annotations.Indexed;
40 import org.hibernate.search.annotations.IndexedEmbedded;
41 import org.hibernate.search.annotations.NumericField;
42 import org.hibernate.validator.constraints.Length;
43 import org.joda.time.Partial;
44
45 import eu.etaxonomy.cdm.model.agent.AgentBase;
46 import eu.etaxonomy.cdm.model.common.EventBase;
47 import eu.etaxonomy.cdm.model.common.LanguageString;
48 import eu.etaxonomy.cdm.model.common.TimePeriod;
49 import eu.etaxonomy.cdm.model.location.NamedArea;
50 import eu.etaxonomy.cdm.model.location.Point;
51
52 /**
53 * The event when gathering a specimen or recording a field observation only
54 * @author m.doering
55 *
56 */
57 @XmlAccessorType(XmlAccessType.FIELD)
58 @XmlType(name = "GatheringEvent", propOrder = {
59 "locality",
60 "exactLocation",
61 "country",
62 "collectingAreas",
63 "collectingMethod",
64 "absoluteElevation",
65 "absoluteElevationMax",
66 "absoluteElevationText",
67 "distanceToGround",
68 "distanceToGroundMax",
69 "distanceToWaterSurface",
70 "distanceToWaterSurfaceMax"
71 })
72 @XmlRootElement(name = "GatheringEvent")
73 @Entity
74 @Audited
75 @Indexed
76 public class GatheringEvent extends EventBase implements Cloneable{
77 private static final long serialVersionUID = 7980806082366532180L;
78 private static final Logger logger = Logger.getLogger(GatheringEvent.class);
79
80 @XmlElement(name = "Locality")
81 @OneToOne(fetch = FetchType.LAZY, orphanRemoval=true)
82 @Cascade({CascadeType.ALL})
83 @IndexedEmbedded
84 private LanguageString locality;
85
86 @XmlElement(name = "ExactLocation")
87 @IndexedEmbedded
88 private Point exactLocation;
89
90
91 @XmlElement(name = "Country")
92 @XmlIDREF
93 @XmlSchemaType(name = "IDREF")
94 @ManyToOne(fetch = FetchType.LAZY)
95 @Cascade({CascadeType.SAVE_UPDATE})
96 @IndexedEmbedded
97 private NamedArea country;
98
99 @XmlElementWrapper(name = "CollectingAreas")
100 @XmlElement(name = "CollectingArea")
101 @XmlIDREF
102 @XmlSchemaType(name = "IDREF")
103 @ManyToMany(fetch = FetchType.LAZY)
104 @NotNull
105 // further collecting areas. Should not include country
106 private Set<NamedArea> collectingAreas = new HashSet<NamedArea>();
107
108 @XmlElement(name = "CollectingMethod")
109 @Field
110 //TODO Val #3379
111 // @NullOrNotEmpty
112 @Length(max = 255)
113 private String collectingMethod;
114
115 /**
116 * meter above/below sea level of the surface
117 * if absoluteElevationMax is defined this is the minimum value
118 * of the range
119 */
120 @XmlElement(name = "AbsoluteElevation")
121 @Field
122 @NumericField
123 private Integer absoluteElevation;
124
125 // meter above/below sea level of the surface, maximum value
126 @XmlElement(name = "AbsoluteElevationMax")
127 @Field
128 @NumericField
129 private Integer absoluteElevationMax;
130
131
132 /**
133 * Maximum value of meter above/below sea level of the surface as text.
134 * If min/max value exists together with absoluteElevationText
135 * the later will be preferred for formatting where as the former
136 * will be used for computations. If the absoluteElevation
137 * does not require any additional information such as
138 * "ca." it is suggested to use min/max value instead.
139 */
140 @XmlElement(name = "AbsoluteElevationText")
141 @Field
142 @Size(max=30)
143 private String absoluteElevationText;
144
145 // @XmlElement(name = "AbsoluteElevationError")
146 // @Field(analyze = Analyze.NO)
147 // @NumericField
148 // private Integer absoluteElevationError;
149
150 // distance in meter from the ground surface when collecting. E.g. 10m below the ground or 10m above the ground/bottom of a lake or 20m up in the canope
151 @XmlElement(name = "DistanceToGround")
152 @Field(analyze = Analyze.NO)
153 @NumericField
154 private Double distanceToGround;
155
156 // distance in meter from the ground surface when collecting. E.g. 10m below the ground or 10m above the ground/bottom of a lake or 20m up in the canope
157 @XmlElement(name = "distanceToGroundMax")
158 @Field(analyze = Analyze.NO)
159 @NumericField
160 private Double distanceToGroundMax;
161
162 // distance in meters to lake or sea surface. Similar to distanceToGround use negative integers for distance *below* the surface, ie under water
163 @XmlElement(name = "DistanceToWaterSurface")
164 @Field(analyze = Analyze.NO)
165 @NumericField
166 private Double distanceToWaterSurface;
167
168 // distance in meters to lake or sea surface. Similar to distanceToGround use negative integers for distance *below* the surface, ie under water
169 @XmlElement(name = "DistanceToWaterSurface")
170 @Field(analyze = Analyze.NO)
171 @NumericField
172 private Double distanceToWaterSurfaceMax;
173
174 /**
175 * Factory method
176 * @return
177 */
178 public static GatheringEvent NewInstance(){
179 return new GatheringEvent();
180 }
181
182 /**
183 * Constructor
184 */
185 protected GatheringEvent() {
186 super();
187 }
188
189 public Point getExactLocation(){
190 return this.exactLocation;
191 }
192 public void setExactLocation(Point exactLocation){
193 this.exactLocation = exactLocation;
194 }
195
196
197
198 public NamedArea getCountry() {
199 return country;
200 }
201
202 public void setCountry(NamedArea country) {
203 this.country = country;
204 }
205
206 /**
207 * Further collecting areas. Should not include #getCountry()
208 * @return
209 */
210 public Set<NamedArea> getCollectingAreas(){
211 if(collectingAreas == null) {
212 this.collectingAreas = new HashSet<NamedArea>();
213 }
214 return this.collectingAreas;
215 }
216
217
218 /**
219 * Further collecting areas. Should not include #getCountry()
220 * @param area
221 */
222 public void addCollectingArea(NamedArea area){
223 if (this.collectingAreas == null) {
224 this.collectingAreas = getNewNamedAreaSet();
225 }
226 this.collectingAreas.add(area);
227 }
228
229 public void removeCollectingArea(NamedArea area){
230 //TODO to be implemented?
231 logger.warn("not yet fully implemented?");
232 this.collectingAreas.remove(area);
233 }
234
235 public LanguageString getLocality(){
236 return this.locality;
237 }
238
239 public void setLocality(LanguageString locality){
240 this.locality = locality;
241 }
242
243 /**
244 * EventBase managed attributes
245 * @return
246 */
247
248 @Transient
249 public Partial getGatheringDate(){
250 return this.getTimeperiod().getStart();
251 }
252
253 public void setGatheringDate(Partial gatheringDate){
254 this.setTimeperiod(TimePeriod.NewInstance(gatheringDate));
255 }
256
257 public void setGatheringDate(Calendar gatheringDate){
258 this.setTimeperiod(TimePeriod.NewInstance(gatheringDate));
259 }
260
261 @Transient
262 public AgentBase getCollector(){
263 return this.getActor();
264 }
265
266 public void setCollector(AgentBase collector){
267 this.setActor(collector);
268 }
269
270 public String getCollectingMethod() {
271 return collectingMethod;
272 }
273
274 public void setCollectingMethod(String collectingMethod) {
275 this.collectingMethod = collectingMethod;
276 }
277
278 public Integer getAbsoluteElevation() {
279 return absoluteElevation;
280 }
281
282 public void setAbsoluteElevation(Integer absoluteElevation) {
283 this.absoluteElevation = absoluteElevation;
284 }
285
286
287 public Integer getAbsoluteElevationMax() {
288 return absoluteElevationMax;
289 }
290
291 public void setAbsoluteElevationMax(Integer absoluteElevationMax) {
292 this.absoluteElevationMax = absoluteElevationMax;
293 }
294
295
296 public String getAbsoluteElevationText() {
297 return absoluteElevationText;
298 }
299
300 public void setAbsoluteElevationText(String absoluteElevationText) {
301 this.absoluteElevationText = absoluteElevationText;
302 }
303
304 // public Integer getAbsoluteElevationError() {
305 // return absoluteElevationError;
306 // }
307 //
308 // public void setAbsoluteElevationError(Integer absoluteElevationError) {
309 // this.absoluteElevationError = absoluteElevationError;
310 // }
311
312 public Double getDistanceToGround() {
313 return distanceToGround;
314 }
315
316 public void setDistanceToGround(Double distanceToGround) {
317 this.distanceToGround = distanceToGround;
318 }
319
320 public Double getDistanceToWaterSurface() {
321 return distanceToWaterSurface;
322 }
323
324 public void setDistanceToWaterSurface(Double distanceToWaterSurface) {
325 this.distanceToWaterSurface = distanceToWaterSurface;
326 }
327
328 //*********** CLONE **********************************/
329
330 /**
331 * Clones <i>this</i> gathering event. This is a shortcut that enables to
332 * create a new instance that differs only slightly from <i>this</i> gathering event
333 * by modifying only some of the attributes.<BR>
334 * This method overrides the clone method from {@link DerivedUnitBase DerivedUnitBase}.
335 *
336 * @see DerivedUnitBase#clone()
337 * @see eu.etaxonomy.cdm.model.media.IdentifiableMediaEntity#clone()
338 * @see java.lang.Object#clone()
339 */
340 @Override
341 public GatheringEvent clone(){
342 try{
343 GatheringEvent result = (GatheringEvent)super.clone();
344 //locality
345 LanguageString langString = LanguageString.NewInstance(this.locality.getText(), this.locality.getLanguage());
346 result.setLocality(langString);
347 //exact location
348 result.setExactLocation(this.exactLocation.clone());
349 //namedAreas
350 result.collectingAreas = new HashSet<NamedArea>();
351 for(NamedArea collectingArea : this.collectingAreas) {
352 result.addCollectingArea(collectingArea);
353 }
354
355 //no changes to: distanceToWaterSurface, distanceToGround, collectingMethod, absoluteElevationError, absoluteElevation
356 return result;
357 } catch (CloneNotSupportedException e) {
358 logger.warn("Object does not implement cloneable");
359 e.printStackTrace();
360 return null;
361 }
362 }
363
364 private static Set<NamedArea> getNewNamedAreaSet(){
365 return new HashSet<NamedArea>();
366 }
367
368
369 }