minor
[cdmlib.git] / cdmlib-model / src / main / java / eu / etaxonomy / cdm / model / description / DescriptionElementBase.java
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.description;
11
12
13 import java.util.ArrayList;
14 import java.util.HashMap;
15 import java.util.HashSet;
16 import java.util.List;
17 import java.util.Map;
18 import java.util.Set;
19
20 import javax.persistence.Entity;
21 import javax.persistence.FetchType;
22 import javax.persistence.Inheritance;
23 import javax.persistence.InheritanceType;
24 import javax.persistence.JoinTable;
25 import javax.persistence.ManyToMany;
26 import javax.persistence.ManyToOne;
27 import javax.persistence.OneToMany;
28 import javax.persistence.Transient;
29 import javax.xml.bind.annotation.XmlAccessType;
30 import javax.xml.bind.annotation.XmlAccessorType;
31 import javax.xml.bind.annotation.XmlElement;
32 import javax.xml.bind.annotation.XmlElementWrapper;
33 import javax.xml.bind.annotation.XmlIDREF;
34 import javax.xml.bind.annotation.XmlSchemaType;
35 import javax.xml.bind.annotation.XmlType;
36 import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
37
38 import org.apache.log4j.Logger;
39 import org.hibernate.annotations.Cascade;
40 import org.hibernate.annotations.CascadeType;
41 import org.hibernate.annotations.IndexColumn;
42 import org.hibernate.envers.Audited;
43 import org.hibernate.search.annotations.Indexed;
44 import org.hibernate.search.annotations.IndexedEmbedded;
45
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.common.MultilanguageText;
50 import eu.etaxonomy.cdm.model.common.ReferencedEntityBase;
51 import eu.etaxonomy.cdm.model.common.TermVocabulary;
52 import eu.etaxonomy.cdm.model.media.IMediaEntity;
53 import eu.etaxonomy.cdm.model.media.Media;
54 import eu.etaxonomy.cdm.model.name.TaxonNameBase;
55 import eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationBase;
56 import eu.etaxonomy.cdm.model.taxon.Taxon;
57
58 /**
59 * The upmost (abstract) class for a piece of information) about
60 * a {@link SpecimenOrObservationBase specimen}, a {@link Taxon taxon} or even a {@link TaxonNameBase taxon name}.
61 * A concrete description element assigns descriptive data to one {@link Feature feature}.<BR>
62 * Experts use the word feature for the property itself but not for the actual
63 * description element. Therefore naming this class FeatureBase would have
64 * leaded to confusion.
65 * <P>
66 * This class corresponds to: <ul>
67 * <li> DescriptionsBaseType according to the the SDD schema
68 * <li> InfoItem according to the TDWG ontology
69 * <li> MeasurementOrFactAtomised according to the ABCD schema
70 * </ul>
71 *
72 * @author m.doering
73 * @version 1.0
74 * @created 08-Nov-2007 13:06:24
75 */
76 @XmlAccessorType(XmlAccessType.FIELD)
77 @XmlType(name = "DescriptionElementBase", propOrder = {
78 "feature",
79 "modifiers",
80 "modifyingText",
81 "media",
82 "inDescription",
83 "nameUsedInReference"
84 })
85 @Entity
86 @Audited
87 @Inheritance(strategy=InheritanceType.SINGLE_TABLE)
88 public abstract class DescriptionElementBase extends ReferencedEntityBase {
89 private static final long serialVersionUID = 5000910777835755905L;
90 @SuppressWarnings("unused")
91 private static final Logger logger = Logger.getLogger(DescriptionElementBase.class);
92
93 //type, category of information. In structured descriptions characters
94 @XmlElement(name = "Feature")
95 @XmlIDREF
96 @XmlSchemaType(name = "IDREF")
97 @ManyToOne(fetch = FetchType.LAZY)
98 @IndexedEmbedded
99 private Feature feature;
100
101 @XmlElementWrapper(name = "Modifiers")
102 @XmlElement(name = "Modifier")
103 @XmlIDREF
104 @XmlSchemaType(name = "IDREF")
105 @ManyToMany(fetch = FetchType.LAZY)
106 @JoinTable(name="DescriptionElementBase_Modifier")
107 private Set<Modifier> modifiers = new HashSet<Modifier>();
108
109 @XmlElement(name = "ModifyingText")
110 @XmlJavaTypeAdapter(MultilanguageTextAdapter.class)
111 @OneToMany(fetch = FetchType.LAZY)
112 @JoinTable(name = "DescriptionElementBase_ModifyingText")
113 private Map<Language,LanguageString> modifyingText = new HashMap<Language,LanguageString>();
114
115 @XmlElementWrapper(name = "Media")
116 @XmlElement(name = "Medium")
117 @XmlIDREF
118 @XmlSchemaType(name = "IDREF")
119 @ManyToMany(fetch = FetchType.LAZY)
120 @IndexColumn(name="sortIndex", base = 0)
121 @Cascade({CascadeType.SAVE_UPDATE})
122 private List<Media> media = new ArrayList<Media>();
123
124 @XmlElement(name = "InDescription")
125 @XmlIDREF
126 @XmlSchemaType(name = "IDREF")
127 @ManyToOne(fetch = FetchType.LAZY)
128 @Cascade(CascadeType.SAVE_UPDATE)
129 @IndexedEmbedded
130 private DescriptionBase inDescription;
131
132 //TODO can this be handled together with ReferencedEntityBase.originalNameString??
133 @XmlElement(name = "nameUsedInReference")
134 @XmlIDREF
135 @XmlSchemaType(name = "IDREF")
136 @ManyToOne(fetch = FetchType.LAZY)
137 @Cascade({CascadeType.SAVE_UPDATE})
138 private TaxonNameBase nameUsedInReference;
139
140
141 // ************* CONSTRUCTORS *************/
142 /**
143 * Class constructor: creates a new empty description element instance.
144 *
145 * @see #DescriptionElementBase(Feature)
146 */
147 protected DescriptionElementBase(){
148 }
149
150 /**
151 * Class constructor: creates a new description element instance with the
152 * given {@link Feature feature} that is described or measured.
153 *
154 * @param feature the feature described or measured
155 * @see #DescriptionElementBase()
156 */
157 protected DescriptionElementBase(Feature feature){
158 if (feature == null){
159 feature = Feature.UNKNOWN();
160 }
161 this.feature = feature;
162 }
163
164 /**
165 * Returns the set of {@link Media media} (that is pictures, movies,
166 * recorded sounds ...) <i>this</i> description element is based on.
167 */
168 public List<Media> getMedia(){
169 return this.media;
170 }
171
172 /**
173 * Adds a {@link Media media} to the set of {@link #getMedia() media}
174 * <i>this</i> description element is based on.
175 *
176 * @param media the media to be added to <i>this</i> description element
177 * @see #getMedia()
178 */
179 public void addMedia(Media media){
180 this.media.add(media);
181 }
182 /**
183 * Removes one element from the set of {@link #getMedia() media}
184 * <i>this</i> description element is based on.
185 *
186 * @param media the media which should be removed
187 * @see #getMedia()
188 * @see #addMedia(Media)
189 */
190 public void removeMedia(Media media){
191 this.media.remove(media);
192 }
193
194 /**
195 * Returns the {@link DescriptionBase description} that <i>this</i> DescriptionElement is
196 * part of.
197 * @return
198 */
199 public DescriptionBase getInDescription() {
200 return this.inDescription;
201 }
202
203 /**
204 * @see #setInDescription()
205 */
206 protected void setInDescription(DescriptionBase inDescription) {
207 this.inDescription = inDescription;
208 }
209
210 /**
211 * Does exactly the same as getFeature().
212 * @author ben.clark
213 * FIXME Is there a need to have two methods with different names which do the same thing?
214 *
215 * @see #getFeature()
216 */
217 @Transient
218 public Feature getType(){
219 return this.getFeature();
220 }
221 /**
222 * Does exactly the same as setFeature(Feature).
223 *
224 * @param type the feature to be described or measured
225 * @see #setFeature(Feature)
226 * @see #getFeature()
227 */
228 public void setType(Feature type){
229 this.setFeature(type);
230 }
231
232 /**
233 * Returns the {@link Feature feature} <i>this</i> description element is for.
234 * A feature is a property that can be described or measured but not the
235 * description or the measurement itself.
236 */
237 public Feature getFeature(){
238 return this.feature;
239 }
240
241 /**
242 * @see #getFeature()
243 */
244 public void setFeature(Feature feature){
245 this.feature = feature;
246 }
247
248 /**
249 * Returns the set of {@link Modifier modifiers} used to qualify the validity of
250 * <i>this</i> description element. This is only metainformation.
251 */
252 public Set<Modifier> getModifiers(){
253 return this.modifiers;
254 }
255
256 /**
257 * Adds a {@link Modifier modifier} to the set of {@link #getModifiers() modifiers}
258 * used to qualify the validity of <i>this</i> description element.
259 *
260 * @param modifier the modifier to be added to <i>this</i> description element
261 * @see #getModifiers()
262 */
263 public void addModifier(Modifier modifier){
264 this.modifiers.add(modifier);
265 }
266 /**
267 * Removes one element from the set of {@link #getModifiers() modifiers}
268 * used to qualify the validity of <i>this</i> description element.
269 *
270 * @param modifier the modifier which should be removed
271 * @see #getModifiers()
272 * @see #addModifier(Modifier)
273 */
274 public void removeModifier(Modifier modifier){
275 this.modifiers.remove(modifier);
276 }
277
278
279 /**
280 * Returns the {@link MultilanguageText multilanguage text} used to qualify the validity
281 * of <i>this</i> description element. The different {@link LanguageString language strings}
282 * contained in the multilanguage text should all have the same meaning.<BR>
283 * A multilanguage text does not belong to a controlled {@link TermVocabulary term vocabulary}
284 * as a {@link Modifier modifier} does.
285 * <P>
286 * NOTE: the actual content of <i>this</i> description element is NOT
287 * stored in the modifying text. This is only metainformation
288 * (like "Some experts express doubt about this assertion").
289 */
290 public Map<Language,LanguageString> getModifyingText(){
291 return this.modifyingText;
292 }
293
294 /**
295 * Adds a translated {@link LanguageString text in a particular language}
296 * to the {@link MultilanguageText multilanguage text} used to qualify the validity
297 * of <i>this</i> description element.
298 *
299 * @param description the language string describing the validity
300 * in a particular language
301 * @see #getModifyingText()
302 * @see #addModifyingText(String, Language)
303 */
304 public LanguageString addModifyingText(LanguageString description){
305 return this.modifyingText.put(description.getLanguage(),description);
306 }
307 /**
308 * Creates a {@link LanguageString language string} based on the given text string
309 * and the given {@link Language language} and adds it to the {@link MultilanguageText multilanguage text}
310 * used to qualify the validity of <i>this</i> description element.
311 *
312 * @param text the string describing the validity
313 * in a particular language
314 * @param language the language in which the text string is formulated
315 * @see #getModifyingText()
316 * @see #addModifyingText(LanguageString)
317 */
318 public LanguageString addModifyingText(String text, Language language){
319 return this.modifyingText.put(language, LanguageString.NewInstance(text, language));
320 }
321 /**
322 * Removes from the {@link MultilanguageText multilanguage text} used to qualify the validity
323 * of <i>this</i> description element the one {@link LanguageString language string}
324 * with the given {@link Language language}.
325 *
326 * @param language the language in which the language string to be removed
327 * has been formulated
328 * @see #getModifyingText()
329 */
330 public LanguageString removeModifyingText(Language language){
331 return this.modifyingText.remove(language);
332 }
333
334 /**
335 * @return the nameUsedInReference
336 */
337 public TaxonNameBase getNameUsedInReference() {
338 return nameUsedInReference;
339 }
340
341 /**
342 * @param nameUsedInReference the nameUsedInReference to set
343 */
344 public void setNameUsedInReference(TaxonNameBase nameUsedInReference) {
345 this.nameUsedInReference = nameUsedInReference;
346 }
347
348
349 }