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
;
12 import java
.util
.HashMap
;
13 import java
.util
.List
;
16 import javax
.persistence
.Entity
;
17 import javax
.persistence
.FetchType
;
18 import javax
.persistence
.ManyToOne
;
19 import javax
.persistence
.MapKeyJoinColumn
;
20 import javax
.persistence
.OneToMany
;
21 import javax
.persistence
.Transient
;
22 import javax
.validation
.constraints
.NotNull
;
23 import javax
.xml
.bind
.annotation
.XmlAccessType
;
24 import javax
.xml
.bind
.annotation
.XmlAccessorType
;
25 import javax
.xml
.bind
.annotation
.XmlElement
;
26 import javax
.xml
.bind
.annotation
.XmlIDREF
;
27 import javax
.xml
.bind
.annotation
.XmlRootElement
;
28 import javax
.xml
.bind
.annotation
.XmlSchemaType
;
29 import javax
.xml
.bind
.annotation
.XmlTransient
;
30 import javax
.xml
.bind
.annotation
.XmlType
;
31 import javax
.xml
.bind
.annotation
.adapters
.XmlJavaTypeAdapter
;
33 import org
.apache
.log4j
.Logger
;
34 import org
.hibernate
.annotations
.Cascade
;
35 import org
.hibernate
.annotations
.CascadeType
;
36 import org
.hibernate
.envers
.Audited
;
37 import org
.hibernate
.search
.annotations
.Field
;
38 import org
.hibernate
.search
.annotations
.FieldBridge
;
39 import org
.hibernate
.search
.annotations
.Indexed
;
40 import org
.hibernate
.search
.annotations
.Store
;
42 import eu
.etaxonomy
.cdm
.hibernate
.search
.MultilanguageTextFieldBridge
;
43 import eu
.etaxonomy
.cdm
.jaxb
.MultilanguageTextAdapter
;
44 import eu
.etaxonomy
.cdm
.model
.common
.IMultiLanguageTextHolder
;
45 import eu
.etaxonomy
.cdm
.model
.common
.Language
;
46 import eu
.etaxonomy
.cdm
.model
.common
.LanguageString
;
47 import eu
.etaxonomy
.cdm
.model
.common
.MultilanguageTextHelper
;
48 import eu
.etaxonomy
.cdm
.model
.common
.TermBase
;
52 * This class represents information pieces expressed in one or several natural
53 * languages (for the {@link Feature feature} "medical use" for instance).
54 * A {@link TextFormat format} used for structuring the text may also be stated.
56 * This class corresponds partially to NaturalLanguageDescriptionType according
61 * @created 08-Nov-2007 13:06:59
63 @XmlAccessorType(XmlAccessType
.FIELD
)
64 @XmlType(name
= "TextData", propOrder
= {
68 @XmlRootElement(name
= "TextData")
71 @Indexed(index
= "eu.etaxonomy.cdm.model.description.DescriptionElementBase")
72 public class TextData
extends DescriptionElementBase
implements IMultiLanguageTextHolder
, Cloneable
{
73 private static final long serialVersionUID
= -2165015581278282615L;
74 private static final Logger logger
= Logger
.getLogger(TextData
.class);
76 //@XmlElement(name = "MultiLanguageText", type = MultilanguageText.class)
77 @XmlElement(name
= "MultiLanguageText")
78 @XmlJavaTypeAdapter(MultilanguageTextAdapter
.class)
79 @OneToMany (fetch
= FetchType
.LAZY
, orphanRemoval
=true)
80 @MapKeyJoinColumn(name
="multilanguagetext_mapkey_id")
81 @Cascade({CascadeType
.SAVE_UPDATE
,CascadeType
.MERGE
, CascadeType
.DELETE
})
82 @Field(name
="text", store
=Store
.YES
)
83 @FieldBridge(impl
=MultilanguageTextFieldBridge
.class)
85 private Map
<Language
, LanguageString
> multilanguageText
= new HashMap
<Language
,LanguageString
>();
87 @XmlElement(name
= "Format")
89 @XmlSchemaType(name
= "IDREF")
90 @ManyToOne(fetch
= FetchType
.LAZY
)
91 private TextFormat format
;
95 private boolean isHashMapHibernateBugFixed
= false;
97 // ************* CONSTRUCTORS *************/
99 * Class constructor: creates a new empty text data instance.
101 * @see #TextData(Feature)
108 * Class constructor: creates a new text data instance with the {@link Feature feature}
111 * @param feature the feature the text data refer to
114 public TextData(Feature feature
){
118 //********* METHODS **************************************/
120 * Creates a new empty text data instance.
122 * @see #NewInstance(Feature)
123 * @see #NewInstance(String, Language, TextFormat)
125 public static TextData
NewInstance(){
126 return new TextData();
130 * Creates a new text data instance with the {@link Feature feature}
133 * @param feature the feature the text data refer to
134 * @see #NewInstance()
135 * @see #NewInstance(String, Language, TextFormat)
137 public static TextData
NewInstance(Feature feature
){
138 return new TextData(feature
);
142 * Creates a new text data instance with a given text in a given particular
143 * {@link Language language} and with the given text format for structuring it.
145 * @param text the text string with the content of the description
146 * @param language the language in which the text string is formulated
147 * @param format the text format used to structure the text string
148 * @see #NewInstance()
149 * @see #NewInstance(Feature)
151 public static TextData
NewInstance(String text
, Language language
, TextFormat format
){
152 TextData result
= new TextData();
153 result
.putText(language
, text
);
154 result
.setFormat(format
);
159 * Returns a copy of the multilanguage text with the content of <i>this</i> text data.
160 * The different {@link LanguageString language strings} (texts) contained in the
161 * multilanguage text should all have the same meaning.
163 * @see #getText(Language)
165 public Map
<Language
, LanguageString
> getMultilanguageText() {
166 fixHashMapHibernateBug();
168 // HashMap<Language, LanguageString> result = new HashMap<Language, LanguageString>();
169 // result.putAll(multilanguageText);
171 return multilanguageText
;
175 // * Sets the multilanguage text.
176 // * The different {@link LanguageString language strings} (texts) contained in the
177 // * multilanguage text should all have the same meaning.
179 // * @param multilanguageText
181 // private void setMultilanguageText(Map<Language,LanguageString> multilanguageText) {
182 // this.multilanguageText = multilanguageText;
186 * Returns the multilanguage text with the content of <i>this</i> text data for
187 * a specific language.
189 * @param language the language in which the text string looked for is formulated
192 public LanguageString
getLanguageText(Language language
){
193 //work around for the problem that contains does not work correctly in persisted maps.
194 //This is because the persisted uuid is not present when loading the map key and
195 //therefore the hash code for language is not computed correctly
196 //see DescriptionElementDaoHibernateTest and #2114
197 // for (Map.Entry<Language, LanguageString> entry : multilanguageText.entrySet()){
198 // if (entry.getKey() != null){
199 // if (entry.getKey().equals(language)){
200 // return entry.getValue();
203 // if (language == null){
204 // return entry.getValue();
210 return getMultilanguageText().get(language
);
214 * Returns the text string in the given {@link Language language} with the content
215 * of <i>this</i> text data.
217 * @param language the language in which the text string looked for is formulated
218 * @see #getMultilanguageText(Language)
220 public String
getText(Language language
) {
221 LanguageString languageString
= getLanguageText(language
);
222 if (languageString
== null){
225 return languageString
.getText();
230 * Returns the LanguageString in the preferred language. Preferred languages
231 * are specified by the parameter languages, which receives a list of
232 * Language instances in the order of preference. If no representation in
233 * any preferred languages is found the method falls back to return the
234 * Representation in Language.DEFAULT() and if neccesary further falls back
235 * to return the first element found if any.
237 * TODO think about this fall-back strategy &
238 * see also {@link TermBase#getPreferredRepresentation(List)}
243 public LanguageString
getPreferredLanguageString(List
<Language
> languages
) {
244 return MultilanguageTextHelper
.getPreferredLanguageString(getMultilanguageText(), languages
);
247 private void fixHashMapHibernateBug() {
248 //workaround for key problem
249 if(! isHashMapHibernateBugFixed
){
250 HashMap
<Language
, LanguageString
> tmp
= new HashMap
<Language
, LanguageString
>();
251 tmp
.putAll(multilanguageText
);
252 multilanguageText
.clear();
253 multilanguageText
.putAll(tmp
);
255 isHashMapHibernateBugFixed
= true;
260 * Creates a {@link LanguageString language string} based on the given text string
261 * and the given {@link Language language}, returns it and adds it to the multilanguage
262 * text representing the content of <i>this</i> text data.
264 * @param text the string representing the content of the text data
265 * in a particular language
266 * @param language the language in which the text string is formulated
267 * @see #getMultilanguageText()
268 * @see #putText(LanguageString)
269 * @return the previous language string associated with the given Language, or null if there was no mapping for the given Language
270 * @deprecated should follow the put semantic of maps, this method will be removed in v4.0
271 * Use the {@link #putText(Language, String) putText} method instead
274 public LanguageString
putText(String text
, Language language
) {
275 return this.putText(language
, text
);
279 * Creates a {@link LanguageString language string} based on the given text string
280 * and the given {@link Language language}, returns it and adds it to the multilanguage
281 * text representing the content of <i>this</i> text data.
283 * @param language the language in which the text string is formulated
284 * @param text the string representing the content of the text data
285 * in a particular language
287 * @see #getMultilanguageText()
288 * @see #putText(LanguageString)
289 * @return the previous language string associated with the given Language, or null if there was no mapping for the given Language
291 public LanguageString
putText(Language language
, String text
) {
292 fixHashMapHibernateBug();
294 LanguageString languageString
= multilanguageText
.get(language
);
295 if (languageString
!= null){
296 languageString
.setText(text
);
298 languageString
= LanguageString
.NewInstance(text
, language
);
300 LanguageString result
= this.multilanguageText
.put(language
, languageString
);
301 return (result
== null ?
null : result
);
306 * Adds a translated {@link LanguageString text in a particular language}
307 * to the multi-language text representing the content of <i>this</i> text data.
308 * The given language string will be returned.
310 * @param languageString the language string representing the content of
311 * the text data in a particular language
312 * @see #getMultilanguageText()
313 * @see #putText(String, Language)
314 * @see HashMap#put(Object, Object)
315 * @return the previous language string associated with key, or null if there was no mapping for key
317 public LanguageString
putText(LanguageString languageString
) {
319 if (languageString
== null){
322 Language language
= languageString
.getLanguage();
323 return this.multilanguageText
.put(language
, languageString
);
327 * Removes from the multilanguage representing the content of
328 * <i>this</i> text data the one {@link LanguageString language string}
329 * with the given {@link Language language}. Returns the removed
332 * @param language the language in which the language string to be removed
333 * has been formulated
334 * @return the language string associated with the given language or null if there was no mapping for the given Language
335 * @see #getMultilanguageText()
337 public LanguageString
removeText(Language language
) {
338 fixHashMapHibernateBug();
339 return this.multilanguageText
.remove(language
);
343 * Returns the number of {@link Language languages} in which the content
344 * of <i>this</i> text data has been formulated.
346 * @see #getMultilanguageText()
348 public int countLanguages(){
349 return multilanguageText
.size();
354 * Returns the {@link TextFormat format} used for structuring the text representing
355 * the content of <i>this</i> text data.
357 * @see #getMultilanguageText()
359 public TextFormat
getFormat() {
365 public void setFormat(TextFormat format
) {
366 this.format
= format
;
370 * @see {@link java.util.Map#containsKey(Object)}
374 public boolean containsKey(Language language
){
375 return getMultilanguageText().containsKey(language
);
379 * @see {@link java.util.Map#containsValue(Object)}
380 * @param languageString
383 public boolean containsValue(LanguageString languageString
){
384 return getMultilanguageText().containsValue(languageString
);
389 * Returns the number of languages available for this text data.
390 * @see {@link java.util.Map#size()}
394 return this.multilanguageText
.size();
398 //*********************************** CLONE *****************************************/
401 * Clones <i>this</i> text data. This is a shortcut that enables to create
402 * a new instance that differs only slightly from <i>this</i> text data by
403 * modifying only some of the attributes.
405 * @see eu.etaxonomy.cdm.model.description.DescriptionElementBase#clone()
406 * @see java.lang.Object#clone()
409 public Object
clone() {
412 TextData result
= (TextData
)super.clone();
415 result
.multilanguageText
= new HashMap
<Language
, LanguageString
>();
416 for (Language language
: getMultilanguageText().keySet()){
417 //TODO clone needed? See also IndividualsAssociation
418 LanguageString newLanguageString
= (LanguageString
)getMultilanguageText().get(language
).clone();
419 result
.multilanguageText
.put(language
, newLanguageString
);
423 //no changes to: format
424 } catch (CloneNotSupportedException e
) {
425 logger
.warn("Object does not implement cloneable");