Project

General

Profile

Download (12 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.occurrence;
11

    
12
import java.util.Calendar;
13
import java.util.HashSet;
14
import java.util.Set;
15

    
16
import javax.persistence.Column;
17
import javax.persistence.Entity;
18
import javax.persistence.FetchType;
19
import javax.persistence.ManyToMany;
20
import javax.persistence.ManyToOne;
21
import javax.persistence.OneToOne;
22
import javax.persistence.Transient;
23
import javax.validation.Valid;
24
import javax.validation.constraints.NotNull;
25
import javax.xml.bind.annotation.XmlAccessType;
26
import javax.xml.bind.annotation.XmlAccessorType;
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.XmlType;
33

    
34
import org.apache.log4j.Logger;
35
import org.hibernate.annotations.Cascade;
36
import org.hibernate.annotations.CascadeType;
37
import org.hibernate.envers.Audited;
38
import org.hibernate.search.annotations.Analyze;
39
import org.hibernate.search.annotations.Field;
40
import org.hibernate.search.annotations.IndexedEmbedded;
41
import org.hibernate.search.annotations.NumericField;
42
import org.joda.time.Partial;
43

    
44
import eu.etaxonomy.cdm.model.agent.AgentBase;
45
import eu.etaxonomy.cdm.model.common.EventBase;
46
import eu.etaxonomy.cdm.model.common.Language;
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 unit only
54
 *
55
 * @author m.doering
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
    "distanceToGroundText",
70
    "distanceToWaterSurface",
71
    "distanceToWaterSurfaceMax",
72
    "distanceToWaterSurfaceText"
73
})
74
@XmlRootElement(name = "GatheringEvent")
75
@Entity
76
@Audited
77
//@Indexed disabled to reduce clutter in indexes, since this type is not used by any search
78
//@Indexed
79
public class GatheringEvent extends EventBase implements Cloneable{
80
	private static final long serialVersionUID = 7980806082366532180L;
81
	private static final Logger logger = Logger.getLogger(GatheringEvent.class);
82

    
83
	@XmlElement(name = "Locality")
84
	@OneToOne(fetch = FetchType.LAZY, orphanRemoval=true)
85
	@Cascade({CascadeType.ALL})
86
	@IndexedEmbedded
87
	private LanguageString locality;
88

    
89
	@XmlElement(name = "ExactLocation")
90
	@IndexedEmbedded
91
	@Valid
92
	private Point exactLocation;
93

    
94

    
95
	@XmlElement(name = "Country")
96
	@XmlIDREF
97
	@XmlSchemaType(name = "IDREF")
98
	@ManyToOne(fetch = FetchType.LAZY)
99
	@IndexedEmbedded
100
	private NamedArea country;
101

    
102
    @XmlElementWrapper(name = "CollectingAreas")
103
	@XmlElement(name = "CollectingArea")
104
	@XmlIDREF
105
	@XmlSchemaType(name = "IDREF")
106
	@ManyToMany(fetch = FetchType.LAZY)
107
	@NotNull
108
	// further collecting areas. Should not include country
109
	private Set<NamedArea> collectingAreas = new HashSet<>();
110

    
111
	@XmlElement(name = "CollectingMethod")
112
	@Field
113
    //TODO Val #3379
114
//	@NullOrNotEmpty
115
	@Column(length=255)
116
	private String collectingMethod;
117

    
118
	/**
119
	 * meter above/below sea level of the surface
120
	* if absoluteElevationMax is defined this is the minimum value
121
	* of the range
122
	 */
123
	@XmlElement(name = "AbsoluteElevation")
124
	@Field
125
	@NumericField
126
	private Integer absoluteElevation;
127

    
128
	// meter above/below sea level of the surface, maximum value
129
	@XmlElement(name = "AbsoluteElevationMax")
130
	@Field
131
	@NumericField
132
	private Integer absoluteElevationMax;
133

    
134

    
135
	/**
136
	 * Maximum value of meter above/below sea level of the surface as text.
137
	 * If min/max value exists together with absoluteElevationText
138
	 * the later will be preferred for formatting where as the former
139
	 * will be used for computations. If the absoluteElevation
140
	 * does not require any additional information such as
141
	 * "ca." it is suggested to use min/max value instead.
142
	 */
143
	@XmlElement(name = "AbsoluteElevationText")
144
	@Field
145
    @Column(length=30)
146
	private String absoluteElevationText;
147

    
148
	// 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
149
	@XmlElement(name = "DistanceToGround")
150
	@Field(analyze = Analyze.NO)
151
	@NumericField
152
	private Double distanceToGround;
153

    
154
	// 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
155
	@XmlElement(name = "distanceToGroundMax")
156
	@Field(analyze = Analyze.NO)
157
	@NumericField
158
	private Double distanceToGroundMax;
159

    
160

    
161
	/**
162
	 * Distance to ground (e.g. when sample is taken from a tree) as text.
163
	 * If min/max value exists together with distanceToGroundText
164
	 * the later will be preferred for formatting whereas the former
165
	 * will be used for computations. If the distanceToGround
166
	 * does not require any additional information such as
167
	 * "ca." it is suggested to use min/max value instead.
168
	 */
169
	@XmlElement(name = "distanceToGroundText")
170
	@Field
171
    @Column(length=30)
172
	private String distanceToGroundText;
173

    
174
	// distance in meters to lake or sea surface. Similar to distanceToGround use negative integers for distance *below* the surface, ie under water
175
	@XmlElement(name = "DistanceToWaterSurface")
176
	@Field(analyze = Analyze.NO)
177
	@NumericField
178
	private Double distanceToWaterSurface;
179

    
180
	// distance in meters to lake or sea surface. Similar to distanceToGround use negative integers for distance *below* the surface, ie under water
181
	@XmlElement(name = "DistanceToWaterSurface")
182
	@Field(analyze = Analyze.NO)
183
	@NumericField
184
	private Double distanceToWaterSurfaceMax;
185

    
186
	/**
187
	 * Distance to water surface (e.g. when sample is taken within water) as text.
188
	 * If min/max value exists together with distanceToWaterSurfaceText
189
	 * the later will be preferred for formatting whereas the former
190
	 * will be used for computations. If the distanceToWaterSurface
191
	 * does not require any additional information such as
192
	 * "ca." it is suggested to use min/max value instead.
193
	 */
194
	@XmlElement(name = "distanceToGroundText")
195
	@Field
196
    @Column(length=30)
197
	private String distanceToWaterSurfaceText;
198

    
199

    
200
	/**
201
	 * Factory method
202
	 * @return
203
	 */
204
	public static GatheringEvent NewInstance(){
205
		return new GatheringEvent();
206
	}
207

    
208
	/**
209
	 * Constructor
210
	 */
211
	protected GatheringEvent() {
212
		super();
213
	}
214

    
215
	public Point getExactLocation(){
216
		return this.exactLocation;
217
	}
218
	public void setExactLocation(Point exactLocation){
219
		this.exactLocation = exactLocation;
220
	}
221

    
222

    
223

    
224
	public NamedArea getCountry() {
225
		return country;
226
	}
227

    
228
	public void setCountry(NamedArea country) {
229
		this.country = country;
230
	}
231

    
232
	/**
233
	 * Further collecting areas. Should not include #getCountry()
234
	 * @return
235
	 */
236
	public Set<NamedArea> getCollectingAreas(){
237
		if(collectingAreas == null) {
238
			this.collectingAreas = new HashSet<NamedArea>();
239
		}
240
		return this.collectingAreas;
241
	}
242

    
243

    
244
	 /**
245
	  * Further collecting areas. Should not include #getCountry()
246
	  * @param area
247
	 */
248
	public void addCollectingArea(NamedArea area){
249
		if (this.collectingAreas == null) {
250
            this.collectingAreas = getNewNamedAreaSet();
251
        }
252
		this.collectingAreas.add(area);
253
	}
254

    
255
	public void removeCollectingArea(NamedArea area){
256
		//TODO to be implemented?
257
		logger.warn("not yet fully implemented?");
258
		this.collectingAreas.remove(area);
259
	}
260

    
261
	public LanguageString getLocality(){
262
		return this.locality;
263
	}
264

    
265
	public void setLocality(LanguageString locality){
266
		this.locality = locality;
267
	}
268
	public void putLocality(Language language, String locality){
269
		this.setLocality(LanguageString.NewInstance(locality, language));
270
	}
271

    
272
/* ***** EventBase managed attributes  */
273

    
274
	@Transient
275
	public Partial getGatheringDate(){
276
	    if(this.getTimeperiod()!=null){
277
	        return this.getTimeperiod().getStart();
278
	    }
279
	    return null;
280
	}
281

    
282
	public void setGatheringDate(Partial gatheringDate){
283
		this.setTimeperiod(TimePeriod.NewInstance(gatheringDate));
284
	}
285
	public void setGatheringDate(Calendar gatheringDate){
286
		this.setTimeperiod(TimePeriod.NewInstance(gatheringDate));
287
	}
288

    
289
	@Transient
290
	public AgentBase getCollector(){
291
		return this.getActor();
292
	}
293
	public void setCollector(AgentBase collector){
294
		this.setActor(collector);
295
	}
296

    
297
// ****************** GETTER / SETTER ************************/
298

    
299
	public String getCollectingMethod() {
300
		return collectingMethod;
301
	}
302
	public void setCollectingMethod(String collectingMethod) {
303
		this.collectingMethod = isBlank(collectingMethod)? null : collectingMethod;
304
	}
305

    
306
	public Integer getAbsoluteElevation() {
307
		return absoluteElevation;
308
	}
309
	public void setAbsoluteElevation(Integer absoluteElevation) {
310
		this.absoluteElevation = absoluteElevation;
311
	}
312

    
313
	public Integer getAbsoluteElevationMax() {
314
		return absoluteElevationMax;
315
	}
316
	public void setAbsoluteElevationMax(Integer absoluteElevationMax) {
317
		this.absoluteElevationMax = absoluteElevationMax;
318
	}
319

    
320
	public String getAbsoluteElevationText() {
321
		return absoluteElevationText;
322
	}
323
	public void setAbsoluteElevationText(String absoluteElevationText) {
324
		this.absoluteElevationText = absoluteElevationText;
325
	}
326

    
327
	public Double getDistanceToGround() {
328
		return distanceToGround;
329
	}
330
	public void setDistanceToGround(Double distanceToGround) {
331
		this.distanceToGround = distanceToGround;
332
	}
333

    
334
	public Double getDistanceToWaterSurface() {
335
		return distanceToWaterSurface;
336
	}
337
	public void setDistanceToWaterSurface(Double distanceToWaterSurface) {
338
		this.distanceToWaterSurface = distanceToWaterSurface;
339
	}
340

    
341
	public Double getDistanceToGroundMax() {
342
		return distanceToGroundMax;
343
	}
344
	public void setDistanceToGroundMax(Double distanceToGroundMax) {
345
		this.distanceToGroundMax = distanceToGroundMax;
346
	}
347

    
348
	public Double getDistanceToWaterSurfaceMax() {
349
		return distanceToWaterSurfaceMax;
350
	}
351
	public void setDistanceToWaterSurfaceMax(Double distanceToWaterSurfaceMax) {
352
		this.distanceToWaterSurfaceMax = distanceToWaterSurfaceMax;
353
	}
354

    
355
	public String getDistanceToGroundText() {
356
		return distanceToGroundText;
357
	}
358
	public void setDistanceToGroundText(String distanceToGroundText) {
359
		this.distanceToGroundText = distanceToGroundText;
360
	}
361

    
362
	public String getDistanceToWaterSurfaceText() {
363
		return distanceToWaterSurfaceText;
364
	}
365
	public void setDistanceToWaterSurfaceText(String distanceToWaterSurfaceText) {
366
		this.distanceToWaterSurfaceText = distanceToWaterSurfaceText;
367
	}
368

    
369
//*********** CLONE **********************************/
370

    
371
	/**
372
	 * Clones <i>this</i> gathering event. This is a shortcut that enables to
373
	 * create a new instance that differs only slightly from <i>this</i> gathering event
374
	 * by modifying only some of the attributes.<BR>
375
	 * This method overrides the clone method from {@link DerivedUnit DerivedUnit}.
376
	 *
377
	 * @see DerivedUnit#clone()
378
	 * @see eu.etaxonomy.cdm.model.media.IdentifiableMediaEntity#clone()
379
	 * @see java.lang.Object#clone()
380
	 */
381
	@Override
382
	public GatheringEvent clone(){
383
		try{
384
			GatheringEvent result = (GatheringEvent)super.clone();
385
			//locality
386
			LanguageString langString = LanguageString.NewInstance(this.locality.getText(), this.locality.getLanguage());
387
			result.setLocality(langString);
388
			//exact location
389
			result.setExactLocation(this.exactLocation==null?null:this.exactLocation.clone());
390
			//namedAreas
391
			result.collectingAreas = new HashSet<>();
392
			for(NamedArea collectingArea : this.collectingAreas) {
393
				result.addCollectingArea(collectingArea);
394
			}
395

    
396
			//no changes to: distanceToWaterSurface, distanceToGround, collectingMethod, absoluteElevationError, absoluteElevation
397
			return result;
398
		} catch (CloneNotSupportedException e) {
399
			logger.warn("Object does not implement cloneable");
400
			e.printStackTrace();
401
			return null;
402
		}
403
	}
404

    
405
	private static Set<NamedArea> getNewNamedAreaSet(){
406
		return new HashSet<NamedArea>();
407
	}
408

    
409

    
410

    
411
}
(7-7/14)