2 * Copyright (C) 2007 EDIT
3 * European Distributed Institute of Taxonomy
4 * http://www.e-taxonomy.eu
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.
10 package eu
.etaxonomy
.cdm
.model
.occurrence
;
12 import java
.util
.HashMap
;
13 import java
.util
.HashSet
;
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
;
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
;
46 import eu
.etaxonomy
.cdm
.jaxb
.MultilanguageTextAdapter
;
47 import eu
.etaxonomy
.cdm
.model
.common
.Language
;
48 import eu
.etaxonomy
.cdm
.model
.common
.LanguageString
;
49 import eu
.etaxonomy
.cdm
.model
.description
.DescriptionBase
;
50 import eu
.etaxonomy
.cdm
.model
.description
.Sex
;
51 import eu
.etaxonomy
.cdm
.model
.description
.SpecimenDescription
;
52 import eu
.etaxonomy
.cdm
.model
.description
.Stage
;
53 import eu
.etaxonomy
.cdm
.model
.description
.TaxonDescription
;
54 import eu
.etaxonomy
.cdm
.model
.description
.TaxonNameDescription
;
55 import eu
.etaxonomy
.cdm
.model
.media
.IdentifiableMediaEntity
;
56 import eu
.etaxonomy
.cdm
.strategy
.cache
.common
.IIdentifiableEntityCacheStrategy
;
59 * type figures are observations with at least a figure object in media
62 * @created 08-Nov-2007 13:06:41
64 @XmlAccessorType(XmlAccessType
.FIELD
)
65 @XmlType(name
= "SpecimenOrObservationBase", propOrder
= {
74 @XmlRootElement(name
= "SpecimenOrObservationBase")
77 @Inheritance(strategy
=InheritanceType
.SINGLE_TABLE
)
78 @Table(appliesTo
="SpecimenOrObservationBase", indexes
= { @Index(name
= "specimenOrObservationBaseTitleCacheIndex", columnNames
= { "titleCache" }) })
79 public abstract class SpecimenOrObservationBase
<S
extends IIdentifiableEntityCacheStrategy
> extends IdentifiableMediaEntity
<S
> {
81 private static final Logger logger
= Logger
.getLogger(SpecimenOrObservationBase
.class);
83 @XmlElementWrapper(name
= "Descriptions")
84 @XmlElement(name
= "Description")
85 @ManyToMany(fetch
= FetchType
.LAZY
,mappedBy
="describedSpecimenOrObservations",targetEntity
=DescriptionBase
.class)
86 @Cascade(CascadeType
.SAVE_UPDATE
)
88 private Set
<DescriptionBase
> descriptions
= new HashSet
<DescriptionBase
>();
90 @XmlElementWrapper(name
= "Determinations")
91 @XmlElement(name
= "Determination")
92 @OneToMany(mappedBy
="identifiedUnit")
93 @Cascade({CascadeType
.SAVE_UPDATE
, CascadeType
.MERGE
, CascadeType
.DELETE
, CascadeType
.DELETE_ORPHAN
})
94 @IndexedEmbedded(depth
= 2)
96 private Set
<DeterminationEvent
> determinations
= new HashSet
<DeterminationEvent
>();
98 @XmlElement(name
= "Sex")
100 @XmlSchemaType(name
= "IDREF")
101 @ManyToOne(fetch
= FetchType
.LAZY
)
104 @XmlElement(name
= "LifeStage")
106 @XmlSchemaType(name
= "IDREF")
107 @ManyToOne(fetch
= FetchType
.LAZY
)
108 private Stage lifeStage
;
110 @XmlElement(name
= "IndividualCount")
111 @Field(index
=org
.hibernate
.search
.annotations
.Index
.UN_TOKENIZED
)
113 private Integer individualCount
;
115 // the verbatim description of this occurrence. Free text usable when no atomised data is available.
116 // in conjunction with titleCache which serves as the "citation" string for this object
117 @XmlElement(name
= "Description")
118 @XmlJavaTypeAdapter(MultilanguageTextAdapter
.class)
119 @OneToMany(fetch
= FetchType
.LAZY
)
120 @Cascade({CascadeType
.SAVE_UPDATE
, CascadeType
.DELETE
, CascadeType
.DELETE_ORPHAN
})
123 protected Map
<Language
,LanguageString
> description
= new HashMap
<Language
,LanguageString
>();
125 // events that created derivedUnits from this unit
126 @XmlElementWrapper(name
= "DerivationEvents")
127 @XmlElement(name
= "DerivationEvent")
129 @XmlSchemaType(name
= "IDREF")
130 @ManyToMany(fetch
=FetchType
.LAZY
)
131 @Cascade({CascadeType
.SAVE_UPDATE
, CascadeType
.DELETE
, CascadeType
.DELETE_ORPHAN
})
133 protected Set
<DerivationEvent
> derivationEvents
= new HashSet
<DerivationEvent
>();
138 protected SpecimenOrObservationBase(){
143 * The descriptions this specimen or observation is part of.<BR>
144 * A specimen can not only have it's own {@link SpecimenDescription specimen description }
145 * but can also be part of a {@link TaxonDescription taxon description} or a
146 * {@link TaxonNameDescription taxon name description}.<BR>
147 * @see #getSpecimenDescriptions()
150 public Set
<DescriptionBase
> getDescriptions() {
151 if(descriptions
== null) {
152 this.descriptions
= new HashSet
<DescriptionBase
>();
154 return this.descriptions
;
158 * Returns the {@link SpecimenDescription specimen descriptions} this specimen is part of.
159 * @see #getDescriptions()
162 public Set
<SpecimenDescription
> getSpecimenDescriptions() {
163 return getSpecimenDescriptions(true);
167 * Returns the {@link SpecimenDescription specimen descriptions} this specimen is part of.
168 * @see #getDescriptions()
172 public Set
<SpecimenDescription
> getSpecimenDescriptions(boolean includeImageGallery
) {
173 Set
<SpecimenDescription
> specimenDescriptions
= new HashSet
<SpecimenDescription
>();
174 for (DescriptionBase descriptionBase
: getDescriptions()){
175 if (descriptionBase
.isInstanceOf(SpecimenDescription
.class)){
176 if (includeImageGallery
|| descriptionBase
.isImageGallery() == false){
177 specimenDescriptions
.add(descriptionBase
.deproxy(descriptionBase
, SpecimenDescription
.class));
182 return specimenDescriptions
;
185 * Returns the {@link SpecimenDescription specimen descriptions} this specimen is part of.
186 * @see #getDescriptions()
190 public Set
<SpecimenDescription
> getSpecimenDescriptionImageGallery() {
191 Set
<SpecimenDescription
> specimenDescriptions
= new HashSet
<SpecimenDescription
>();
192 for (DescriptionBase descriptionBase
: getDescriptions()){
193 if (descriptionBase
.isInstanceOf(SpecimenDescription
.class)){
194 if (descriptionBase
.isImageGallery() == true){
195 specimenDescriptions
.add(descriptionBase
.deproxy(descriptionBase
, SpecimenDescription
.class));
199 return specimenDescriptions
;
203 * Adds a new description to this specimen or observation
206 public void addDescription(DescriptionBase description
) {
207 this.descriptions
.add(description
);
208 if (! description
.getDescribedSpecimenOrObservations().contains(this)){
209 description
.addDescribedSpecimenOrObservation(this);
211 // Method method = ReflectionUtils.findMethod(SpecimenDescription.class, "addDescribedSpecimenOrObservation", new Class[] {SpecimenOrObservationBase.class});
212 // ReflectionUtils.makeAccessible(method);
213 // ReflectionUtils.invokeMethod(method, description, new Object[] {this});
217 * Removes a specimen from a description (removes a description from this specimen)
220 public void removeDescription(DescriptionBase description
) {
221 this.descriptions
.remove(description
);
222 if (description
.getDescribedSpecimenOrObservations().contains(this)){
223 description
.removeDescribedSpecimenOrObservation(this);
225 // Method method = ReflectionUtils.findMethod(SpecimenDescription.class, "removeDescribedSpecimenOrObservations", new Class[] {SpecimenOrObservationBase.class});
226 // ReflectionUtils.makeAccessible(method);
227 // ReflectionUtils.invokeMethod(method, description, new Object[] {this});
230 public Set
<DerivationEvent
> getDerivationEvents() {
231 if(derivationEvents
== null) {
232 this.derivationEvents
= new HashSet
<DerivationEvent
>();
234 return this.derivationEvents
;
237 public void addDerivationEvent(DerivationEvent derivationEvent
) {
238 if (! this.derivationEvents
.contains(derivationEvent
)){
239 this.derivationEvents
.add(derivationEvent
);
240 derivationEvent
.addOriginal(this);
244 public void removeDerivationEvent(DerivationEvent derivationEvent
) {
245 this.derivationEvents
.remove(derivationEvent
);
248 public Set
<DeterminationEvent
> getDeterminations() {
249 if(determinations
== null) {
250 this.determinations
= new HashSet
<DeterminationEvent
>();
252 return this.determinations
;
255 public void addDetermination(DeterminationEvent determination
) {
256 // FIXME bidirectional integrity. Use protected Determination setter
257 this.determinations
.add(determination
);
260 public void removeDetermination(DeterminationEvent determination
) {
261 // FIXME bidirectional integrity. Use protected Determination setter
262 this.determinations
.remove(determination
);
265 public Sex
getSex() {
269 public void setSex(Sex sex
) {
273 public Stage
getLifeStage() {
277 public void setLifeStage(Stage lifeStage
) {
278 this.lifeStage
= lifeStage
;
282 public String
generateTitle(){
283 return getCacheStrategy().getTitleCache(this);
286 public Integer
getIndividualCount() {
287 return individualCount
;
290 public void setIndividualCount(Integer individualCount
) {
291 this.individualCount
= individualCount
;
294 public Map
<Language
,LanguageString
> getDefinition(){
295 return this.description
;
298 public void addDefinition(LanguageString description
){
299 this.description
.put(description
.getLanguage(),description
);
302 public void addDefinition(String text
, Language language
){
303 this.description
.put(language
, LanguageString
.NewInstance(text
, language
));
305 public void removeDefinition(Language lang
){
306 this.description
.remove(lang
);
310 * for derived units get the single next higher parental/original unit.
311 * If multiple original units exist throw error
315 public SpecimenOrObservationBase
getOriginalUnit(){
316 logger
.warn("GetOriginalUnit not yet implemented");
321 //******************** CLONE **********************************************/
324 * @see eu.etaxonomy.cdm.model.media.IdentifiableMediaEntity#clone()
325 * @see eu.etaxonomy.cdm.model.common.IdentifiableEntity#clone()
326 * @see java.lang.Object#clone()
329 public Object
clone() throws CloneNotSupportedException
{
330 SpecimenOrObservationBase result
= null;
331 result
= (SpecimenOrObservationBase
)super.clone();
333 //defininion (description, languageString)
334 result
.description
= new HashMap
<Language
,LanguageString
>();
335 for(LanguageString languageString
: this.description
.values()) {
336 LanguageString newLanguageString
= (LanguageString
)languageString
.clone();
337 result
.addDefinition(newLanguageString
);
341 result
.setSex(this.sex
);
343 result
.setLifeStage(this.lifeStage
);
346 for(DescriptionBase description
: this.descriptions
) {
347 result
.addDescription((SpecimenDescription
)description
);
350 //DeterminationEvent FIXME should clone() the determination
351 // as the relationship is OneToMany
352 for(DeterminationEvent determination
: this.determinations
) {
353 result
.addDetermination(determination
);
357 for(DerivationEvent derivationEvent
: this.derivationEvents
) {
358 result
.addDerivationEvent(derivationEvent
);
361 //no changes to: individualCount