root/trunk/cdmlib/cdmlib-model/src/main/java/eu/etaxonomy/cdm/model/occurrence/SpecimenOrObservationBase.java

Revision 11262, 14.3 kB (checked in by a.mueller, 16 months ago)

some final changes for #2176 (putXXX)

  • Property svn:keywords set to Id
Line 
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
10package eu.etaxonomy.cdm.model.occurrence;
11
12import java.util.HashMap;
13import java.util.HashSet;
14import java.util.Map;
15import java.util.Set;
16
17import javax.persistence.Entity;
18import javax.persistence.FetchType;
19import javax.persistence.Inheritance;
20import javax.persistence.InheritanceType;
21import javax.persistence.ManyToMany;
22import javax.persistence.ManyToOne;
23import javax.persistence.OneToMany;
24import javax.persistence.Transient;
25import javax.validation.constraints.Min;
26import javax.validation.constraints.NotNull;
27import javax.xml.bind.annotation.XmlAccessType;
28import javax.xml.bind.annotation.XmlAccessorType;
29import javax.xml.bind.annotation.XmlElement;
30import javax.xml.bind.annotation.XmlElementWrapper;
31import javax.xml.bind.annotation.XmlIDREF;
32import javax.xml.bind.annotation.XmlRootElement;
33import javax.xml.bind.annotation.XmlSchemaType;
34import javax.xml.bind.annotation.XmlType;
35import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
36
37import org.apache.log4j.Logger;
38import org.hibernate.annotations.Cascade;
39import org.hibernate.annotations.CascadeType;
40import org.hibernate.annotations.Index;
41import org.hibernate.annotations.Table;
42import org.hibernate.envers.Audited;
43import org.hibernate.search.annotations.Field;
44import org.hibernate.search.annotations.IndexedEmbedded;
45
46import eu.etaxonomy.cdm.jaxb.MultilanguageTextAdapter;
47import eu.etaxonomy.cdm.model.common.IMultiLanguageTextHolder;
48import eu.etaxonomy.cdm.model.common.Language;
49import eu.etaxonomy.cdm.model.common.LanguageString;
50import eu.etaxonomy.cdm.model.common.MultilanguageText;
51import eu.etaxonomy.cdm.model.description.DescriptionBase;
52import eu.etaxonomy.cdm.model.description.Sex;
53import eu.etaxonomy.cdm.model.description.SpecimenDescription;
54import eu.etaxonomy.cdm.model.description.Stage;
55import eu.etaxonomy.cdm.model.description.TaxonDescription;
56import eu.etaxonomy.cdm.model.description.TaxonNameDescription;
57import eu.etaxonomy.cdm.model.media.IdentifiableMediaEntity;
58import eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy;
59
60/**
61 * type figures are observations with at least a figure object in media
62 * @author m.doering
63 * @version 1.0
64 * @created 08-Nov-2007 13:06:41
65 */
66@XmlAccessorType(XmlAccessType.FIELD)
67@XmlType(name = "SpecimenOrObservationBase", propOrder = {
68        "sex",
69    "individualCount",
70    "lifeStage",
71    "definition",
72    "descriptions",
73    "determinations",
74    "derivationEvents"
75})
76@XmlRootElement(name = "SpecimenOrObservationBase")
77@Entity
78@Audited
79@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
80@Table(appliesTo="SpecimenOrObservationBase", indexes = { @Index(name = "specimenOrObservationBaseTitleCacheIndex", columnNames = { "titleCache" }) })
81public abstract class SpecimenOrObservationBase<S extends IIdentifiableEntityCacheStrategy> extends IdentifiableMediaEntity<S> implements IMultiLanguageTextHolder{
82       
83        private static final Logger logger = Logger.getLogger(SpecimenOrObservationBase.class);
84       
85        @XmlElementWrapper(name = "Descriptions")
86        @XmlElement(name = "Description")
87        @ManyToMany(fetch = FetchType.LAZY,mappedBy="describedSpecimenOrObservations",targetEntity=DescriptionBase.class)
88        @Cascade(CascadeType.SAVE_UPDATE)
89        @NotNull
90        private Set<DescriptionBase> descriptions = new HashSet<DescriptionBase>();
91       
92        @XmlElementWrapper(name = "Determinations")
93        @XmlElement(name = "Determination")
94        @OneToMany(mappedBy="identifiedUnit")
95        @Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE, CascadeType.DELETE, CascadeType.DELETE_ORPHAN})
96        @IndexedEmbedded(depth = 2)
97        @NotNull
98        private Set<DeterminationEvent> determinations = new HashSet<DeterminationEvent>();
99       
100        @XmlElement(name = "Sex")
101        @XmlIDREF
102        @XmlSchemaType(name = "IDREF")
103        @ManyToOne(fetch = FetchType.LAZY)
104        private Sex sex;
105       
106        @XmlElement(name = "LifeStage")
107        @XmlIDREF
108        @XmlSchemaType(name = "IDREF")
109        @ManyToOne(fetch = FetchType.LAZY)
110        private Stage lifeStage;
111       
112        @XmlElement(name = "IndividualCount")
113        @Field(index=org.hibernate.search.annotations.Index.UN_TOKENIZED)
114        @Min(0)
115        private Integer individualCount;
116       
117        // the verbatim description of this occurrence. Free text usable when no atomised data is available.
118        // in conjunction with titleCache which serves as the "citation" string for this object
119        @XmlElement(name = "Description")
120        @XmlJavaTypeAdapter(MultilanguageTextAdapter.class)
121        @OneToMany(fetch = FetchType.LAZY)
122        @Cascade({CascadeType.SAVE_UPDATE, CascadeType.DELETE, CascadeType.DELETE_ORPHAN})
123        @IndexedEmbedded
124        @NotNull
125        protected Map<Language,LanguageString> definition = new HashMap<Language,LanguageString>();
126       
127        // events that created derivedUnits from this unit
128        @XmlElementWrapper(name = "DerivationEvents")
129        @XmlElement(name = "DerivationEvent")
130    @XmlIDREF
131    @XmlSchemaType(name = "IDREF")
132    @ManyToMany(fetch=FetchType.LAZY)
133    @Cascade({CascadeType.SAVE_UPDATE, CascadeType.DELETE, CascadeType.DELETE_ORPHAN})
134    @NotNull
135        protected Set<DerivationEvent> derivationEvents = new HashSet<DerivationEvent>();
136
137        /**
138         * Constructor
139         */
140        protected SpecimenOrObservationBase(){
141                super();
142        }
143       
144        /**
145         * The descriptions this specimen or observation is part of.<BR>
146         * A specimen can not only have it's own {@link SpecimenDescription specimen description }
147         * but can also be part of a {@link TaxonDescription taxon description} or a
148         * {@link TaxonNameDescription taxon name description}.<BR>
149         * @see #getSpecimenDescriptions()
150         * @return
151         */
152        public Set<DescriptionBase> getDescriptions() {
153                if(descriptions == null) {
154                        this.descriptions = new HashSet<DescriptionBase>();
155                }
156                return this.descriptions;
157        }
158       
159        /**
160         * Returns the {@link SpecimenDescription specimen descriptions} this specimen is part of.
161         * @see #getDescriptions()
162         * @return
163         */
164        @Transient
165        public Set<SpecimenDescription> getSpecimenDescriptions() {
166                return getSpecimenDescriptions(true);
167        }
168       
169        /**
170         * Returns the {@link SpecimenDescription specimen descriptions} this specimen is part of.
171         * @see #getDescriptions()
172         * @return
173         */
174        @Transient
175        public Set<SpecimenDescription> getSpecimenDescriptions(boolean includeImageGallery) {
176                Set<SpecimenDescription> specimenDescriptions = new HashSet<SpecimenDescription>();
177                for (DescriptionBase descriptionBase : getDescriptions()){
178                        if (descriptionBase.isInstanceOf(SpecimenDescription.class)){
179                                if (includeImageGallery || descriptionBase.isImageGallery() == false){
180                                        specimenDescriptions.add(descriptionBase.deproxy(descriptionBase, SpecimenDescription.class));
181                                }
182                               
183                        }
184                }
185                return specimenDescriptions;
186        }
187        /**
188         * Returns the {@link SpecimenDescription specimen descriptions} this specimen is part of.
189         * @see #getDescriptions()
190         * @return
191         */
192        @Transient
193        public Set<SpecimenDescription> getSpecimenDescriptionImageGallery() {
194                Set<SpecimenDescription> specimenDescriptions = new HashSet<SpecimenDescription>();
195                for (DescriptionBase descriptionBase : getDescriptions()){
196                        if (descriptionBase.isInstanceOf(SpecimenDescription.class)){
197                                if (descriptionBase.isImageGallery() == true){
198                                        specimenDescriptions.add(descriptionBase.deproxy(descriptionBase, SpecimenDescription.class));
199                                }
200                        }
201                }
202                return specimenDescriptions;
203        }
204
205        /**
206         * Adds a new description to this specimen or observation
207         * @param description
208         */
209        public void addDescription(DescriptionBase description) {
210                this.descriptions.add(description);
211                if (! description.getDescribedSpecimenOrObservations().contains(this)){
212                        description.addDescribedSpecimenOrObservation(this);
213                }
214//              Method method = ReflectionUtils.findMethod(SpecimenDescription.class, "addDescribedSpecimenOrObservation", new Class[] {SpecimenOrObservationBase.class});
215//              ReflectionUtils.makeAccessible(method);
216//              ReflectionUtils.invokeMethod(method, description, new Object[] {this});
217        }
218       
219        /**
220         * Removes a specimen from a description (removes a description from this specimen)
221         * @param description
222         */
223        public void removeDescription(DescriptionBase description) {
224                this.descriptions.remove(description);
225                if (description.getDescribedSpecimenOrObservations().contains(this)){
226                        description.removeDescribedSpecimenOrObservation(this);
227                }
228//              Method method = ReflectionUtils.findMethod(SpecimenDescription.class, "removeDescribedSpecimenOrObservations", new Class[] {SpecimenOrObservationBase.class});
229//              ReflectionUtils.makeAccessible(method);
230//              ReflectionUtils.invokeMethod(method, description, new Object[] {this});
231        }
232       
233        public Set<DerivationEvent> getDerivationEvents() {
234                if(derivationEvents == null) {
235                        this.derivationEvents = new HashSet<DerivationEvent>();
236                }
237                return this.derivationEvents;
238        }
239       
240        public void addDerivationEvent(DerivationEvent derivationEvent) {
241                if (! this.derivationEvents.contains(derivationEvent)){
242                        this.derivationEvents.add(derivationEvent);
243                        derivationEvent.addOriginal(this);
244                }
245        }
246       
247        public void removeDerivationEvent(DerivationEvent derivationEvent) {
248                this.derivationEvents.remove(derivationEvent);
249        }
250       
251        public Set<DeterminationEvent> getDeterminations() {
252                if(determinations == null) {
253                        this.determinations = new HashSet<DeterminationEvent>();
254                }
255                return this.determinations;
256        }
257
258        public void addDetermination(DeterminationEvent determination) {
259                // FIXME bidirectional integrity. Use protected Determination setter
260                this.determinations.add(determination);
261        }
262       
263        public void removeDetermination(DeterminationEvent determination) {
264                // FIXME bidirectional integrity. Use protected Determination setter
265                this.determinations.remove(determination);
266        }
267       
268        public Sex getSex() {
269                return sex;
270        }
271
272        public void setSex(Sex sex) {
273                this.sex = sex;
274        }
275
276        public Stage getLifeStage() {
277                return lifeStage;
278        }
279
280        public void setLifeStage(Stage lifeStage) {
281                this.lifeStage = lifeStage;
282        }
283       
284        @Override
285        public String generateTitle(){
286                return getCacheStrategy().getTitleCache(this);
287        }
288       
289        public Integer getIndividualCount() {
290                return individualCount;
291        }
292
293        public void setIndividualCount(Integer individualCount) {
294                this.individualCount = individualCount;
295        }
296
297        public Map<Language,LanguageString> getDefinition(){
298                return this.definition;
299        }
300       
301        /**
302         * adds the {@link LanguageString description} to the {@link MultilanguageText multilanguage text}
303         * used to define <i>this</i> specimen or observation.
304         *
305         * @param description   the languageString in with the title string and the given language
306         * 
307         * @see                         #getDefinition()
308         * @see                         #putDefinition(Language, String)
309         * @deprecated          should follow the put semantic of maps, this method will be removed in v4.0
310         *                                      Use the {@link #putDefinition(LanguageString) putDefinition} method instead
311         */
312        @Deprecated
313        public void addDefinition(LanguageString description){
314                this.putDefinition(description);
315        }
316        /**
317         * adds the {@link LanguageString description} to the {@link MultilanguageText multilanguage text}
318         * used to define <i>this</i> specimen or observation.
319         *
320         * @param description   the languageString in with the title string and the given language
321         * 
322         * @see                         #getDefinition()
323         * @see                         #putDefinition(Language, String)
324         */
325        public void putDefinition(LanguageString description){
326                this.definition.put(description.getLanguage(),description);
327        }
328        /**
329         * Creates a {@link LanguageString language string} based on the given text string
330         * and the given {@link Language language} and adds it to the {@link MultilanguageText multilanguage text}
331         * used to define <i>this</i> specimen or observation.
332         *
333         * @param language      the language in which the title string is formulated
334         * @param text          the definition in a particular language
335         *
336         * @see                         #getDefinition()
337         * @see                         #putDefinition(LanguageString)
338         * @deprecated          should follow the put semantic of maps, this method will be removed in v4.0
339         *                                      Use the {@link #putDefinition(Language String) putDefinition} method instead
340         */
341        @Deprecated
342        public void addDefinition( String text, Language language){
343                this.putDefinition(language, text);
344        }
345        /**
346         * Creates a {@link LanguageString language string} based on the given text string
347         * and the given {@link Language language} and adds it to the {@link MultilanguageText multilanguage text}
348         * used to define <i>this</i> specimen or observation.
349         *
350         * @param language      the language in which the title string is formulated
351         * @param text          the definition in a particular language
352         *
353         * @see                         #getDefinition()
354         * @see                         #putDefinition(LanguageString)
355         */
356        public void putDefinition(Language language, String text){
357                this.definition.put(language, LanguageString.NewInstance(text, language));
358        }
359       
360       
361        public void removeDefinition(Language lang){
362                this.definition.remove(lang);
363        }
364       
365        /**
366         * for derived units get the single next higher parental/original unit.
367         * If multiple original units exist throw error
368         * @return
369         */
370        @Transient
371        public SpecimenOrObservationBase getOriginalUnit(){
372                logger.warn("GetOriginalUnit not yet implemented");
373                return null;
374        }
375
376       
377//******************** CLONE **********************************************/
378       
379        /* (non-Javadoc)
380         * @see eu.etaxonomy.cdm.model.media.IdentifiableMediaEntity#clone()
381         * @see eu.etaxonomy.cdm.model.common.IdentifiableEntity#clone()
382         * @see java.lang.Object#clone()
383         */
384        @Override
385        public Object clone() throws CloneNotSupportedException {
386                SpecimenOrObservationBase result = null;
387                result = (SpecimenOrObservationBase)super.clone();
388               
389                //defininion (description, languageString)
390                result.definition = new HashMap<Language,LanguageString>();
391                for(LanguageString languageString : this.definition.values()) {
392                        LanguageString newLanguageString = (LanguageString)languageString.clone();
393                        result.putDefinition(newLanguageString);
394                } 
395
396                //sex
397                result.setSex(this.sex);
398                //life stage
399                result.setLifeStage(this.lifeStage);
400               
401                //Descriptions
402                for(DescriptionBase description : this.descriptions) {
403                        result.addDescription((SpecimenDescription)description);
404                }
405               
406                //DeterminationEvent FIXME should clone() the determination
407                // as the relationship is OneToMany
408                for(DeterminationEvent determination : this.determinations) {
409                        result.addDetermination(determination);
410                }
411               
412                //DerivationEvent
413                for(DerivationEvent derivationEvent : this.derivationEvents) {
414                        result.addDerivationEvent(derivationEvent);
415                }
416               
417                //no changes to: individualCount
418                return result;
419        }
420}
Note: See TracBrowser for help on using the browser.