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
.description
;
13 import java
.util
.ArrayList
;
14 import java
.util
.HashMap
;
15 import java
.util
.HashSet
;
16 import java
.util
.List
;
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
.xml
.bind
.annotation
.XmlAccessType
;
29 import javax
.xml
.bind
.annotation
.XmlAccessorType
;
30 import javax
.xml
.bind
.annotation
.XmlElement
;
31 import javax
.xml
.bind
.annotation
.XmlElementWrapper
;
32 import javax
.xml
.bind
.annotation
.XmlIDREF
;
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
.IndexColumn
;
41 import org
.hibernate
.envers
.Audited
;
42 import org
.hibernate
.search
.annotations
.Field
;
43 import org
.hibernate
.search
.annotations
.FieldBridge
;
44 import org
.hibernate
.search
.annotations
.IndexedEmbedded
;
46 import eu
.etaxonomy
.cdm
.hibernate
.search
.DefinedTermBaseFieldBridge
;
47 import eu
.etaxonomy
.cdm
.hibernate
.search
.MultilanguageTextFieldBridge
;
48 import eu
.etaxonomy
.cdm
.jaxb
.MultilanguageTextAdapter
;
49 import eu
.etaxonomy
.cdm
.model
.common
.AnnotatableEntity
;
50 import eu
.etaxonomy
.cdm
.model
.common
.DescriptionElementSource
;
51 import eu
.etaxonomy
.cdm
.model
.common
.IMultiLanguageTextHolder
;
52 import eu
.etaxonomy
.cdm
.model
.common
.ISourceable
;
53 import eu
.etaxonomy
.cdm
.model
.common
.Language
;
54 import eu
.etaxonomy
.cdm
.model
.common
.LanguageString
;
55 import eu
.etaxonomy
.cdm
.model
.common
.MultilanguageText
;
56 import eu
.etaxonomy
.cdm
.model
.common
.TermVocabulary
;
57 import eu
.etaxonomy
.cdm
.model
.media
.Media
;
58 import eu
.etaxonomy
.cdm
.model
.name
.TaxonNameBase
;
59 import eu
.etaxonomy
.cdm
.model
.occurrence
.SpecimenOrObservationBase
;
60 import eu
.etaxonomy
.cdm
.model
.reference
.Reference
;
61 import eu
.etaxonomy
.cdm
.model
.taxon
.Taxon
;
62 import eu
.etaxonomy
.cdm
.strategy
.merge
.Merge
;
63 import eu
.etaxonomy
.cdm
.strategy
.merge
.MergeMode
;
66 * The upmost (abstract) class for a piece of information) about
67 * a {@link SpecimenOrObservationBase specimen}, a {@link Taxon taxon} or even a {@link TaxonNameBase taxon name}.
68 * A concrete description element assigns descriptive data to one {@link Feature feature}.<BR>
69 * Experts use the word feature for the property itself but not for the actual
70 * description element. Therefore naming this class FeatureBase would have
71 * leaded to confusion.
73 * This class corresponds to: <ul>
74 * <li> DescriptionsBaseType according to the the SDD schema
75 * <li> InfoItem according to the TDWG ontology
76 * <li> MeasurementOrFactAtomised according to the ABCD schema
81 * @created 08-Nov-2007 13:06:24
83 @XmlAccessorType(XmlAccessType
.FIELD
)
84 @XmlType(name
= "DescriptionElementBase", propOrder
= {
94 @Inheritance(strategy
=InheritanceType
.SINGLE_TABLE
)
95 public abstract class DescriptionElementBase
extends AnnotatableEntity
implements ISourceable
<DescriptionElementSource
>, IModifiable
, IMultiLanguageTextHolder
{
96 private static final long serialVersionUID
= 5000910777835755905L;
97 @SuppressWarnings("unused")
98 private static final Logger logger
= Logger
.getLogger(DescriptionElementBase
.class);
100 //type, category of information. In structured descriptions characters
101 @XmlElement(name
= "Feature")
103 @XmlSchemaType(name
= "IDREF")
104 @ManyToOne(fetch
= FetchType
.LAZY
)
105 //@Cascade(CascadeType.SAVE_UPDATE)
106 @Cascade(CascadeType
.MERGE
)
107 @IndexedEmbedded(depth
=3)
108 private Feature feature
;
110 @XmlElementWrapper(name
= "Modifiers")
111 @XmlElement(name
= "Modifier")
113 @XmlSchemaType(name
= "IDREF")
114 @ManyToMany(fetch
= FetchType
.LAZY
)
115 @JoinTable(name
="DescriptionElementBase_Modifier")
116 @IndexedEmbedded(depth
=3)
117 private Set
<Modifier
> modifiers
= new HashSet
<Modifier
>();
119 @XmlElement(name
= "ModifyingText")
120 @XmlJavaTypeAdapter(MultilanguageTextAdapter
.class)
121 @OneToMany(fetch
= FetchType
.LAZY
)
122 @JoinTable(name
= "DescriptionElementBase_ModifyingText")
123 @Cascade({CascadeType
.SAVE_UPDATE
, CascadeType
.MERGE
})
125 @FieldBridge(impl
=MultilanguageTextFieldBridge
.class)
126 private Map
<Language
,LanguageString
> modifyingText
= new HashMap
<Language
,LanguageString
>();
128 @XmlElementWrapper(name
= "Media")
129 @XmlElement(name
= "Medium")
131 @XmlSchemaType(name
= "IDREF")
132 @ManyToMany(fetch
= FetchType
.LAZY
)
133 @IndexColumn(name
="sortIndex", base
= 0)
134 @Cascade({CascadeType
.SAVE_UPDATE
, CascadeType
.MERGE
})
135 private List
<Media
> media
= new ArrayList
<Media
>();
137 @XmlElement(name
= "InDescription")
139 @XmlSchemaType(name
= "IDREF")
140 @ManyToOne(fetch
= FetchType
.LAZY
)
141 @Cascade(CascadeType
.SAVE_UPDATE
)
143 private DescriptionBase inDescription
;
145 @XmlElementWrapper(name
= "Sources")
146 @XmlElement(name
= "DescriptionElementSource")
147 @OneToMany(fetch
= FetchType
.LAZY
)
148 @Cascade({CascadeType
.SAVE_UPDATE
, CascadeType
.MERGE
, CascadeType
.DELETE
, CascadeType
.DELETE_ORPHAN
})
149 @Merge(MergeMode
.ADD_CLONE
)
150 private Set
<DescriptionElementSource
> sources
= new HashSet
<DescriptionElementSource
>();
154 // ************* CONSTRUCTORS *************/
156 * Class constructor: creates a new empty description element instance.
158 * @see #DescriptionElementBase(Feature)
160 protected DescriptionElementBase(){
164 * Class constructor: creates a new description element instance with the
165 * given {@link Feature feature} that is described or measured.
167 * @param feature the feature described or measured
168 * @see #DescriptionElementBase()
170 protected DescriptionElementBase(Feature feature
){
171 if (feature
== null){
172 feature
= Feature
.UNKNOWN();
174 this.feature
= feature
;
178 * Returns the list of {@link Media media} (that is pictures, movies,
179 * recorded sounds ...) <i>this</i> description element is based on.
181 public List
<Media
> getMedia(){
186 * Adds a {@link Media media} to the list of {@link #getMedia() media}
187 * <i>this</i> description element is based on.
189 * @param media the media to be added to <i>this</i> description element
192 public void addMedia(Media media
){
193 this.media
.add(media
);
196 * Removes one element from the list of {@link #getMedia() media}
197 * <i>this</i> description element is based on.
199 * @param media the media which should be removed
201 * @see #addMedia(Media)
203 public void removeMedia(Media media
){
204 this.media
.remove(media
);
208 * Returns the {@link DescriptionBase description} that <i>this</i> DescriptionElement is
212 public DescriptionBase
getInDescription() {
213 return this.inDescription
;
217 * @see #setInDescription()
219 protected void setInDescription(DescriptionBase inDescription
) {
220 this.inDescription
= inDescription
;
224 * Returns the {@link Feature feature} <i>this</i> description element is for.
225 * A feature is a property that can be described or measured but not the
226 * description or the measurement itself.
228 public Feature
getFeature(){
235 public void setFeature(Feature feature
){
236 this.feature
= feature
;
240 * Returns the set of {@link Modifier modifiers} used to qualify the validity of
241 * <i>this</i> description element. This is only metainformation.
243 public Set
<Modifier
> getModifiers(){
244 return this.modifiers
;
248 * Adds a {@link Modifier modifier} to the set of {@link #getModifiers() modifiers}
249 * used to qualify the validity of <i>this</i> description element.
251 * @param modifier the modifier to be added to <i>this</i> description element
252 * @see #getModifiers()
254 public void addModifier(Modifier modifier
){
255 this.modifiers
.add(modifier
);
258 * Removes one element from the set of {@link #getModifiers() modifiers}
259 * used to qualify the validity of <i>this</i> description element.
261 * @param modifier the modifier which should be removed
262 * @see #getModifiers()
263 * @see #addModifier(Modifier)
265 public void removeModifier(Modifier modifier
){
266 this.modifiers
.remove(modifier
);
271 * Returns the {@link MultilanguageText multilanguage text} used to qualify the validity
272 * of <i>this</i> description element. The different {@link LanguageString language strings}
273 * contained in the multilanguage text should all have the same meaning.<BR>
274 * A multilanguage text does not belong to a controlled {@link TermVocabulary term vocabulary}
275 * as a {@link Modifier modifier} does.
277 * NOTE: the actual content of <i>this</i> description element is NOT
278 * stored in the modifying text. This is only metainformation
279 * (like "Some experts express doubt about this assertion").
281 public Map
<Language
,LanguageString
> getModifyingText(){
282 return this.modifyingText
;
286 * Adds a translated {@link LanguageString text in a particular language}
287 * to the {@link MultilanguageText multilanguage text} used to qualify the validity
288 * of <i>this</i> description element.
290 * @param description the language string describing the validity
291 * in a particular language
292 * @see #getModifyingText()
293 * @see #putModifyingText(Language, String)
294 * @deprecated should follow the put semantic of maps, this method will be removed in v4.0
295 * Use the {@link #putModifyingText(LanguageString) putModifyingText} method
297 public LanguageString
addModifyingText(LanguageString description
){
298 return this.putModifyingText(description
);
302 * Adds a translated {@link LanguageString text in a particular language}
303 * to the {@link MultilanguageText multilanguage text} used to qualify the validity
304 * of <i>this</i> description element.
306 * @param description the language string describing the validity
307 * in a particular language
308 * @see #getModifyingText()
309 * @see #putModifyingText(Language, String)
311 public LanguageString
putModifyingText(LanguageString description
){
312 return this.modifyingText
.put(description
.getLanguage(),description
);
315 * Creates a {@link LanguageString language string} based on the given text string
316 * and the given {@link Language language} and adds it to the {@link MultilanguageText multilanguage text}
317 * used to qualify the validity of <i>this</i> description element.
319 * @param text the string describing the validity
320 * in a particular language
321 * @param language the language in which the text string is formulated
322 * @see #getModifyingText()
323 * @see #putModifyingText(LanguageString)
324 * @deprecated should follow the put semantic of maps, this method will be removed in v4.0
325 * Use the {@link #putModifyingText(Language, String) putModifyingText} method
327 public LanguageString
addModifyingText(String text
, Language language
){
328 return this.putModifyingText(language
, text
);
332 * Creates a {@link LanguageString language string} based on the given text string
333 * and the given {@link Language language} and adds it to the {@link MultilanguageText multilanguage text}
334 * used to qualify the validity of <i>this</i> description element.
336 * @param language the language in which the text string is formulated
337 * @param text the string describing the validity
338 * in a particular language
340 * @see #getModifyingText()
341 * @see #putModifyingText(LanguageString)
344 public LanguageString
putModifyingText(Language language
, String text
){
345 return this.modifyingText
.put(language
, LanguageString
.NewInstance(text
, language
));
348 * Removes from the {@link MultilanguageText multilanguage text} used to qualify the validity
349 * of <i>this</i> description element the one {@link LanguageString language string}
350 * with the given {@link Language language}.
352 * @param language the language in which the language string to be removed
353 * has been formulated
354 * @see #getModifyingText()
356 public LanguageString
removeModifyingText(Language language
){
357 return this.modifyingText
.remove(language
);
361 * @see eu.etaxonomy.cdm.model.common.ISourceable#getSources()
363 public Set
<DescriptionElementSource
> getSources() {
368 * @see eu.etaxonomy.cdm.model.common.ISourceable#addSource(eu.etaxonomy.cdm.model.common.IOriginalSource)
370 public void addSource(DescriptionElementSource source
) {
372 DescriptionElementBase oldSourcedObj
= source
.getSourcedObj();
373 if (oldSourcedObj
!= null && oldSourcedObj
!= this){
374 oldSourcedObj
.getSources().remove(source
);
376 this.sources
.add(source
);
377 source
.setSourcedObj(this);
382 * @see eu.etaxonomy.cdm.model.common.ISourceable#addSource(java.lang.String, java.lang.String, eu.etaxonomy.cdm.model.reference.Reference, java.lang.String)
384 public DescriptionElementSource
addSource(String id
, String idNamespace
, Reference citation
, String microCitation
) {
385 if (id
== null && idNamespace
== null && citation
== null && microCitation
== null){
388 DescriptionElementSource source
= DescriptionElementSource
.NewInstance(id
, idNamespace
, citation
, microCitation
);
393 public void addSource(String id
, String idNamespace
, Reference citation
, String microReference
, TaxonNameBase nameUsedInSource
, String originalNameString
){
394 DescriptionElementSource newSource
= DescriptionElementSource
.NewInstance(id
, idNamespace
, citation
, microReference
, nameUsedInSource
, originalNameString
);
395 addSource(newSource
);
399 * @see eu.etaxonomy.cdm.model.common.ISourceable#removeSource(eu.etaxonomy.cdm.model.common.IOriginalSource)
401 public void removeSource(DescriptionElementSource source
) {
402 this.sources
.remove(source
);
405 // ******************* METHODS *************************************************************/
407 protected Map
<TermVocabulary
, List
<Modifier
>> makeModifierMap(){
408 Map
<TermVocabulary
, List
<Modifier
>> result
= new HashMap
<TermVocabulary
, List
<Modifier
>>();
409 for (Modifier modifier
: getModifiers()){
410 TermVocabulary
<Modifier
> voc
= modifier
.getVocabulary();
411 if (result
.get(voc
) == null){
412 result
.put(voc
, new ArrayList
<Modifier
>());
414 result
.get(voc
).add(modifier
);
419 public List
<Modifier
> getModifiers(TermVocabulary voc
){
420 List
<Modifier
> result
= makeModifierMap().get(voc
);
422 result
= new ArrayList
<Modifier
>();
429 //************************** CLONE **********************************************************/
432 * Clones the description element. The element is <b>not</b> added to the same
433 * description as the orginal element (inDescription is set to <code>null</null>).
434 * @see eu.etaxonomy.cdm.model.common.AnnotatableEntity#clone()
437 public Object
clone() throws CloneNotSupportedException
{
438 DescriptionElementBase result
= (DescriptionElementBase
)super.clone();
441 result
.inDescription
= null;
444 result
.sources
= new HashSet
<DescriptionElementSource
>();
445 for (DescriptionElementSource source
: getSources()){
446 DescriptionElementSource newSource
= (DescriptionElementSource
)source
.clone();
447 result
.addSource(newSource
);
451 result
.media
= new ArrayList
<Media
>();
452 for (Media media
: getMedia()){
453 result
.media
.add(media
);
457 result
.modifyingText
= new HashMap
<Language
, LanguageString
>();
458 for (Language language
: getModifyingText().keySet()){
459 //TODO clone needed? See also IndividualsAssociation
460 LanguageString newLanguageString
= (LanguageString
)getModifyingText().get(language
).clone();
461 result
.modifyingText
.put(language
, newLanguageString
);
465 result
.modifiers
= new HashSet
<Modifier
>();
466 for (Modifier modifier
: getModifiers()){
467 result
.modifiers
.add(modifier
);
470 //no changes to: feature
475 * Clones the description element.<BR>
476 * The new element is added to the <code>description</code>.<BR>
477 * @see eu.etaxonomy.cdm.model.common.AnnotatableEntity#clone()
479 public DescriptionElementBase
clone(DescriptionBase description
) throws CloneNotSupportedException
{
480 DescriptionElementBase result
= (DescriptionElementBase
)clone();
481 description
.addElement(result
);