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()
171 public Set
<SpecimenDescription
> getSpecimenDescriptions(boolean includeImageGallery
) {
172 Set
<SpecimenDescription
> specimenDescriptions
= new HashSet
<SpecimenDescription
>();
173 for (DescriptionBase descriptionBase
: getDescriptions()){
174 if (descriptionBase
.isInstanceOf(SpecimenDescription
.class)){
175 if (includeImageGallery
|| descriptionBase
.isImageGallery() == false){
176 specimenDescriptions
.add(descriptionBase
.deproxy(descriptionBase
, SpecimenDescription
.class));
181 return specimenDescriptions
;
185 * Adds a new description to this specimen or observation
188 public void addDescription(DescriptionBase description
) {
189 this.descriptions
.add(description
);
190 if (! description
.getDescribedSpecimenOrObservations().contains(this)){
191 description
.addDescribedSpecimenOrObservation(this);
193 // Method method = ReflectionUtils.findMethod(SpecimenDescription.class, "addDescribedSpecimenOrObservation", new Class[] {SpecimenOrObservationBase.class});
194 // ReflectionUtils.makeAccessible(method);
195 // ReflectionUtils.invokeMethod(method, description, new Object[] {this});
199 * Removes a specimen from a description (removes a description from this specimen)
202 public void removeDescription(DescriptionBase description
) {
203 this.descriptions
.remove(description
);
204 if (description
.getDescribedSpecimenOrObservations().contains(this)){
205 description
.removeDescribedSpecimenOrObservation(this);
207 // Method method = ReflectionUtils.findMethod(SpecimenDescription.class, "removeDescribedSpecimenOrObservations", new Class[] {SpecimenOrObservationBase.class});
208 // ReflectionUtils.makeAccessible(method);
209 // ReflectionUtils.invokeMethod(method, description, new Object[] {this});
212 public Set
<DerivationEvent
> getDerivationEvents() {
213 if(derivationEvents
== null) {
214 this.derivationEvents
= new HashSet
<DerivationEvent
>();
216 return this.derivationEvents
;
219 public void addDerivationEvent(DerivationEvent derivationEvent
) {
220 if (! this.derivationEvents
.contains(derivationEvent
)){
221 this.derivationEvents
.add(derivationEvent
);
222 derivationEvent
.addOriginal(this);
226 public void removeDerivationEvent(DerivationEvent derivationEvent
) {
227 this.derivationEvents
.remove(derivationEvent
);
230 public Set
<DeterminationEvent
> getDeterminations() {
231 if(determinations
== null) {
232 this.determinations
= new HashSet
<DeterminationEvent
>();
234 return this.determinations
;
237 public void addDetermination(DeterminationEvent determination
) {
238 // FIXME bidirectional integrity. Use protected Determination setter
239 this.determinations
.add(determination
);
242 public void removeDetermination(DeterminationEvent determination
) {
243 // FIXME bidirectional integrity. Use protected Determination setter
244 this.determinations
.remove(determination
);
247 public Sex
getSex() {
251 public void setSex(Sex sex
) {
255 public Stage
getLifeStage() {
259 public void setLifeStage(Stage lifeStage
) {
260 this.lifeStage
= lifeStage
;
264 public String
generateTitle(){
265 return getCacheStrategy().getTitleCache(this);
268 public Integer
getIndividualCount() {
269 return individualCount
;
272 public void setIndividualCount(Integer individualCount
) {
273 this.individualCount
= individualCount
;
276 public Map
<Language
,LanguageString
> getDefinition(){
277 return this.description
;
280 public void addDefinition(LanguageString description
){
281 this.description
.put(description
.getLanguage(),description
);
284 public void addDefinition(String text
, Language language
){
285 this.description
.put(language
, LanguageString
.NewInstance(text
, language
));
287 public void removeDefinition(Language lang
){
288 this.description
.remove(lang
);
292 * for derived units get the single next higher parental/original unit.
293 * If multiple original units exist throw error
297 public SpecimenOrObservationBase
getOriginalUnit(){
298 logger
.warn("GetOriginalUnit not yet implemented");
303 public abstract GatheringEvent
getGatheringEvent();
306 //******************** CLONE **********************************************/
309 * @see eu.etaxonomy.cdm.model.media.IdentifiableMediaEntity#clone()
310 * @see eu.etaxonomy.cdm.model.common.IdentifiableEntity#clone()
311 * @see java.lang.Object#clone()
314 public Object
clone() throws CloneNotSupportedException
{
315 SpecimenOrObservationBase result
= null;
316 result
= (SpecimenOrObservationBase
)super.clone();
318 //defininion (description, languageString)
319 result
.description
= new HashMap
<Language
,LanguageString
>();
320 for(LanguageString languageString
: this.description
.values()) {
321 LanguageString newLanguageString
= (LanguageString
)languageString
.clone();
322 result
.addDefinition(newLanguageString
);
326 result
.setSex(this.sex
);
328 result
.setLifeStage(this.lifeStage
);
331 for(DescriptionBase description
: this.descriptions
) {
332 result
.addDescription((SpecimenDescription
)description
);
335 //DeterminationEvent FIXME should clone() the determination
336 // as the relationship is OneToMany
337 for(DeterminationEvent determination
: this.determinations
) {
338 result
.addDetermination(determination
);
342 for(DerivationEvent derivationEvent
: this.derivationEvents
) {
343 result
.addDerivationEvent(derivationEvent
);
346 //no changes to: individualCount