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.HashMap;
13
import java.util.HashSet;
14
import java.util.Map;
15
import java.util.Set;
16

    
17
import javax.persistence.Entity;
18
import javax.persistence.FetchType;
19
import javax.persistence.Inheritance;
20
import javax.persistence.InheritanceType;
21
import javax.persistence.ManyToMany;
22
import javax.persistence.ManyToOne;
23
import javax.persistence.OneToMany;
24
import javax.persistence.Transient;
25
import javax.validation.constraints.Min;
26
import javax.validation.constraints.NotNull;
27
import javax.xml.bind.annotation.XmlAccessType;
28
import javax.xml.bind.annotation.XmlAccessorType;
29
import javax.xml.bind.annotation.XmlElement;
30
import javax.xml.bind.annotation.XmlElementWrapper;
31
import javax.xml.bind.annotation.XmlIDREF;
32
import javax.xml.bind.annotation.XmlRootElement;
33
import javax.xml.bind.annotation.XmlSchemaType;
34
import javax.xml.bind.annotation.XmlType;
35
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
36

    
37
import org.apache.log4j.Logger;
38
import org.hibernate.annotations.Cascade;
39
import org.hibernate.annotations.CascadeType;
40
import org.hibernate.annotations.Index;
41
import org.hibernate.annotations.Table;
42
import org.hibernate.envers.Audited;
43
import org.hibernate.search.annotations.Field;
44
import org.hibernate.search.annotations.IndexedEmbedded;
45

    
46
import eu.etaxonomy.cdm.jaxb.MultilanguageTextAdapter;
47
import eu.etaxonomy.cdm.model.common.IMultiLanguageTextHolder;
48
import eu.etaxonomy.cdm.model.common.Language;
49
import eu.etaxonomy.cdm.model.common.LanguageString;
50
import eu.etaxonomy.cdm.model.description.DescriptionBase;
51
import eu.etaxonomy.cdm.model.description.Sex;
52
import eu.etaxonomy.cdm.model.description.SpecimenDescription;
53
import eu.etaxonomy.cdm.model.description.Stage;
54
import eu.etaxonomy.cdm.model.description.TaxonDescription;
55
import eu.etaxonomy.cdm.model.description.TaxonNameDescription;
56
import eu.etaxonomy.cdm.model.media.IdentifiableMediaEntity;
57
import eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy;
58

    
59
/**
60
 * type figures are observations with at least a figure object in media
61
 * @author m.doering
62
 * @version 1.0
63
 * @created 08-Nov-2007 13:06:41
64
 */
65
@XmlAccessorType(XmlAccessType.FIELD)
66
@XmlType(name = "SpecimenOrObservationBase", propOrder = {
67
	"sex",
68
    "individualCount",
69
    "lifeStage",
70
    "definition",
71
    "descriptions",
72
    "determinations",
73
    "derivationEvents"
74
})
75
@XmlRootElement(name = "SpecimenOrObservationBase")
76
@Entity
77
@Audited
78
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
79
@Table(appliesTo="SpecimenOrObservationBase", indexes = { @Index(name = "specimenOrObservationBaseTitleCacheIndex", columnNames = { "titleCache" }) })
80
public abstract class SpecimenOrObservationBase<S extends IIdentifiableEntityCacheStrategy> extends IdentifiableMediaEntity<S> implements IMultiLanguageTextHolder{
81
	
82
	private static final Logger logger = Logger.getLogger(SpecimenOrObservationBase.class);
83
	
84
	@XmlElementWrapper(name = "Descriptions")
85
	@XmlElement(name = "Description")
86
	@ManyToMany(fetch = FetchType.LAZY,mappedBy="describedSpecimenOrObservations",targetEntity=DescriptionBase.class)
87
	@Cascade(CascadeType.SAVE_UPDATE)
88
	@NotNull
89
	private Set<DescriptionBase> descriptions = new HashSet<DescriptionBase>();
90
	
91
	@XmlElementWrapper(name = "Determinations")
92
	@XmlElement(name = "Determination")
93
	@OneToMany(mappedBy="identifiedUnit")
94
	@Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE, CascadeType.DELETE, CascadeType.DELETE_ORPHAN})
95
	@IndexedEmbedded(depth = 2)
96
	@NotNull
97
	private Set<DeterminationEvent> determinations = new HashSet<DeterminationEvent>();
98
	
99
	@XmlElement(name = "Sex")
100
	@XmlIDREF
101
	@XmlSchemaType(name = "IDREF")
102
	@ManyToOne(fetch = FetchType.LAZY)
103
	private Sex sex;
104
	
105
	@XmlElement(name = "LifeStage")
106
	@XmlIDREF
107
	@XmlSchemaType(name = "IDREF")
108
	@ManyToOne(fetch = FetchType.LAZY)
109
	private Stage lifeStage;
110
	
111
	@XmlElement(name = "IndividualCount")
112
	@Field(index=org.hibernate.search.annotations.Index.UN_TOKENIZED)
113
	@Min(0)
114
	private Integer individualCount;
115
	
116
	// the verbatim description of this occurrence. Free text usable when no atomised data is available.
117
	// in conjunction with titleCache which serves as the "citation" string for this object
118
	@XmlElement(name = "Description")
119
	@XmlJavaTypeAdapter(MultilanguageTextAdapter.class)
120
	@OneToMany(fetch = FetchType.LAZY)
121
	@Cascade({CascadeType.SAVE_UPDATE, CascadeType.DELETE, CascadeType.DELETE_ORPHAN})
122
	@IndexedEmbedded
123
	@NotNull
124
	protected Map<Language,LanguageString> definition = new HashMap<Language,LanguageString>();
125
	
126
	// events that created derivedUnits from this unit
127
	@XmlElementWrapper(name = "DerivationEvents")
128
	@XmlElement(name = "DerivationEvent")
129
    @XmlIDREF
130
    @XmlSchemaType(name = "IDREF")
131
    @ManyToMany(fetch=FetchType.LAZY)
132
    @Cascade({CascadeType.SAVE_UPDATE, CascadeType.DELETE, CascadeType.DELETE_ORPHAN})
133
    @NotNull
134
	protected Set<DerivationEvent> derivationEvents = new HashSet<DerivationEvent>();
135

    
136
	/**
137
	 * Constructor
138
	 */
139
	protected SpecimenOrObservationBase(){
140
		super();
141
	}
142
	
143
	/**
144
	 * The descriptions this specimen or observation is part of.<BR>
145
	 * A specimen can not only have it's own {@link SpecimenDescription specimen description }
146
	 * but can also be part of a {@link TaxonDescription taxon description} or a 
147
	 * {@link TaxonNameDescription taxon name description}.<BR>
148
	 * @see #getSpecimenDescriptions()
149
	 * @return
150
	 */
151
	public Set<DescriptionBase> getDescriptions() {
152
		if(descriptions == null) {
153
			this.descriptions = new HashSet<DescriptionBase>();
154
		}
155
		return this.descriptions;
156
	}
157
	
158
	/**
159
	 * Returns the {@link SpecimenDescription specimen descriptions} this specimen is part of.
160
	 * @see #getDescriptions()
161
	 * @return
162
	 */
163
	@Transient
164
	public Set<SpecimenDescription> getSpecimenDescriptions() {
165
		return getSpecimenDescriptions(true);
166
	}
167
	
168
	/**
169
	 * Returns the {@link SpecimenDescription specimen descriptions} this specimen is part of.
170
	 * @see #getDescriptions()
171
	 * @return
172
	 */
173
	@Transient
174
	public Set<SpecimenDescription> getSpecimenDescriptions(boolean includeImageGallery) {
175
		Set<SpecimenDescription> specimenDescriptions = new HashSet<SpecimenDescription>();
176
		for (DescriptionBase descriptionBase : getDescriptions()){
177
			if (descriptionBase.isInstanceOf(SpecimenDescription.class)){
178
				if (includeImageGallery || descriptionBase.isImageGallery() == false){
179
					specimenDescriptions.add(descriptionBase.deproxy(descriptionBase, SpecimenDescription.class));
180
				}
181
				
182
			}
183
		}
184
		return specimenDescriptions;
185
	}
186
	/**
187
	 * Returns the {@link SpecimenDescription specimen descriptions} this specimen is part of.
188
	 * @see #getDescriptions()
189
	 * @return
190
	 */
191
	@Transient
192
	public Set<SpecimenDescription> getSpecimenDescriptionImageGallery() {
193
		Set<SpecimenDescription> specimenDescriptions = new HashSet<SpecimenDescription>();
194
		for (DescriptionBase descriptionBase : getDescriptions()){
195
			if (descriptionBase.isInstanceOf(SpecimenDescription.class)){
196
				if (descriptionBase.isImageGallery() == true){
197
					specimenDescriptions.add(descriptionBase.deproxy(descriptionBase, SpecimenDescription.class));
198
				}
199
			}
200
		}
201
		return specimenDescriptions;
202
	}
203

    
204
	/**
205
	 * Adds a new description to this specimen or observation
206
	 * @param description
207
	 */
208
	public void addDescription(DescriptionBase description) {
209
		this.descriptions.add(description);
210
		if (! description.getDescribedSpecimenOrObservations().contains(this)){
211
			description.addDescribedSpecimenOrObservation(this);
212
		}
213
//		Method method = ReflectionUtils.findMethod(SpecimenDescription.class, "addDescribedSpecimenOrObservation", new Class[] {SpecimenOrObservationBase.class});
214
//		ReflectionUtils.makeAccessible(method);
215
//		ReflectionUtils.invokeMethod(method, description, new Object[] {this});
216
	}
217
	
218
	/**
219
	 * Removes a specimen from a description (removes a description from this specimen)
220
	 * @param description
221
	 */
222
	public void removeDescription(DescriptionBase description) {
223
		this.descriptions.remove(description);
224
		if (description.getDescribedSpecimenOrObservations().contains(this)){
225
			description.removeDescribedSpecimenOrObservation(this);
226
		}
227
//		Method method = ReflectionUtils.findMethod(SpecimenDescription.class, "removeDescribedSpecimenOrObservations", new Class[] {SpecimenOrObservationBase.class});
228
//		ReflectionUtils.makeAccessible(method);
229
//		ReflectionUtils.invokeMethod(method, description, new Object[] {this});
230
	}
231
	
232
	public Set<DerivationEvent> getDerivationEvents() {
233
		if(derivationEvents == null) {
234
			this.derivationEvents = new HashSet<DerivationEvent>();
235
		}
236
		return this.derivationEvents;
237
	}
238
	
239
	public void addDerivationEvent(DerivationEvent derivationEvent) {
240
		if (! this.derivationEvents.contains(derivationEvent)){
241
			this.derivationEvents.add(derivationEvent);
242
			derivationEvent.addOriginal(this);
243
		}
244
	}
245
	
246
	public void removeDerivationEvent(DerivationEvent derivationEvent) {
247
		this.derivationEvents.remove(derivationEvent);
248
	}
249
	
250
	public Set<DeterminationEvent> getDeterminations() {
251
		if(determinations == null) {
252
			this.determinations = new HashSet<DeterminationEvent>();
253
		}
254
		return this.determinations;
255
	}
256

    
257
	public void addDetermination(DeterminationEvent determination) {
258
		// FIXME bidirectional integrity. Use protected Determination setter
259
		this.determinations.add(determination);
260
	}
261
	
262
	public void removeDetermination(DeterminationEvent determination) {
263
		// FIXME bidirectional integrity. Use protected Determination setter
264
		this.determinations.remove(determination);
265
	}
266
	
267
	public Sex getSex() {
268
		return sex;
269
	}
270

    
271
	public void setSex(Sex sex) {
272
		this.sex = sex;
273
	}
274

    
275
	public Stage getLifeStage() {
276
		return lifeStage;
277
	}
278

    
279
	public void setLifeStage(Stage lifeStage) {
280
		this.lifeStage = lifeStage;
281
	}
282
	
283
	@Override
284
	public String generateTitle(){
285
		return getCacheStrategy().getTitleCache(this);
286
	}
287
	
288
	public Integer getIndividualCount() {
289
		return individualCount;
290
	}
291

    
292
	public void setIndividualCount(Integer individualCount) {
293
		this.individualCount = individualCount;
294
	}
295

    
296
	public Map<Language,LanguageString> getDefinition(){
297
		return this.definition;
298
	}
299
	
300
	public void addDefinition(LanguageString description){
301
		this.definition.put(description.getLanguage(),description);
302
	}
303
	
304
	public void addDefinition(String text, Language language){
305
		this.definition.put(language, LanguageString.NewInstance(text, language));
306
	}
307
	public void removeDefinition(Language lang){
308
		this.definition.remove(lang);
309
	}
310
	
311
	/**
312
	 * for derived units get the single next higher parental/original unit.
313
	 * If multiple original units exist throw error
314
	 * @return
315
	 */
316
	@Transient
317
	public SpecimenOrObservationBase getOriginalUnit(){
318
		logger.warn("GetOriginalUnit not yet implemented");
319
		return null;
320
	}
321

    
322
	
323
//******************** CLONE **********************************************/
324
	
325
	/* (non-Javadoc)
326
	 * @see eu.etaxonomy.cdm.model.media.IdentifiableMediaEntity#clone()
327
	 * @see eu.etaxonomy.cdm.model.common.IdentifiableEntity#clone()
328
	 * @see java.lang.Object#clone()
329
	 */
330
	@Override
331
	public Object clone() throws CloneNotSupportedException {
332
		SpecimenOrObservationBase result = null;
333
		result = (SpecimenOrObservationBase)super.clone();
334
		
335
		//defininion (description, languageString)
336
		result.definition = new HashMap<Language,LanguageString>();
337
		for(LanguageString languageString : this.definition.values()) {
338
			LanguageString newLanguageString = (LanguageString)languageString.clone();
339
			result.addDefinition(newLanguageString);
340
		} 
341

    
342
		//sex
343
		result.setSex(this.sex);
344
		//life stage
345
		result.setLifeStage(this.lifeStage);
346
		
347
		//Descriptions
348
		for(DescriptionBase description : this.descriptions) {
349
			result.addDescription((SpecimenDescription)description);
350
		}
351
		
352
		//DeterminationEvent FIXME should clone() the determination
353
		// as the relationship is OneToMany
354
		for(DeterminationEvent determination : this.determinations) {
355
			result.addDetermination(determination);
356
		}
357
		
358
		//DerivationEvent
359
		for(DerivationEvent derivationEvent : this.derivationEvents) {
360
			result.addDerivationEvent(derivationEvent);
361
		}
362
		
363
		//no changes to: individualCount
364
		return result;
365
	}
366
}
(15-15/17)