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
.HashSet
;
14 import java
.util
.List
;
17 import javax
.persistence
.Entity
;
18 import javax
.persistence
.FetchType
;
19 import javax
.persistence
.ManyToOne
;
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
.Indexed
;
38 import org
.hibernate
.search
.annotations
.IndexedEmbedded
;
40 import eu
.etaxonomy
.cdm
.jaxb
.MultilanguageTextAdapter
;
41 import eu
.etaxonomy
.cdm
.model
.common
.IMultiLanguageTextHolder
;
42 import eu
.etaxonomy
.cdm
.model
.common
.Language
;
43 import eu
.etaxonomy
.cdm
.model
.common
.LanguageString
;
44 import eu
.etaxonomy
.cdm
.model
.common
.MultilanguageTextHelper
;
45 import eu
.etaxonomy
.cdm
.model
.common
.TermBase
;
49 * This class represents information pieces expressed in one or several natural
50 * languages (for the {@link Feature feature} "medical use" for instance).
51 * A {@link TextFormat format} used for structuring the text may also be stated.
53 * This class corresponds partially to NaturalLanguageDescriptionType according
58 * @created 08-Nov-2007 13:06:59
60 @XmlAccessorType(XmlAccessType
.FIELD
)
61 @XmlType(name
= "TextData", propOrder
= {
65 @XmlRootElement(name
= "TextData")
68 @Indexed(index
= "eu.etaxonomy.cdm.model.description.DescriptionElementBase")
69 public class TextData
extends DescriptionElementBase
implements IMultiLanguageTextHolder
, Cloneable
{
70 private static final long serialVersionUID
= -2165015581278282615L;
71 private static final Logger logger
= Logger
.getLogger(TextData
.class);
73 //@XmlElement(name = "MultiLanguageText", type = MultilanguageText.class)
74 @XmlElement(name
= "MultiLanguageText")
75 @XmlJavaTypeAdapter(MultilanguageTextAdapter
.class)
76 @OneToMany (fetch
= FetchType
.LAZY
)
77 @Cascade({CascadeType
.SAVE_UPDATE
,CascadeType
.MERGE
, CascadeType
.DELETE
, CascadeType
.DELETE_ORPHAN
})
80 private Map
<Language
, LanguageString
> multilanguageText
= new HashMap
<Language
,LanguageString
>();
82 @XmlElement(name
= "Format")
84 @XmlSchemaType(name
= "IDREF")
85 @ManyToOne(fetch
= FetchType
.LAZY
)
86 private TextFormat format
;
90 private boolean isHashMapHibernateBugFixed
= false;
92 // ************* CONSTRUCTORS *************/
94 * Class constructor: creates a new empty text data instance.
96 * @see #TextData(Feature)
103 * Class constructor: creates a new text data instance with the {@link Feature feature}
106 * @param feature the feature the text data refer to
109 public TextData(Feature feature
){
113 //********* METHODS **************************************/
115 * Creates a new empty text data instance.
117 * @see #NewInstance(Feature)
118 * @see #NewInstance(String, Language, TextFormat)
120 public static TextData
NewInstance(){
121 return new TextData();
125 * Creates a new text data instance with the {@link Feature feature}
128 * @param feature the feature the text data refer to
129 * @see #NewInstance()
130 * @see #NewInstance(String, Language, TextFormat)
132 public static TextData
NewInstance(Feature feature
){
133 return new TextData(feature
);
137 * Creates a new text data instance with a given text in a given particular
138 * {@link Language language} and with the given text format for structuring it.
140 * @param text the text string with the content of the description
141 * @param language the language in which the text string is formulated
142 * @param format the text format used to structure the text string
143 * @see #NewInstance()
144 * @see #NewInstance(Feature)
146 public static TextData
NewInstance(String text
, Language language
, TextFormat format
){
147 TextData result
= new TextData();
148 result
.putText(text
, language
);
149 result
.setFormat(format
);
154 * Returns a copy of the multilanguage text with the content of <i>this</i> text data.
155 * The different {@link LanguageString language strings} (texts) contained in the
156 * multilanguage text should all have the same meaning.
158 * @see #getText(Language)
160 public Map
<Language
, LanguageString
> getMultilanguageText() {
161 fixHashMapHibernateBug();
163 // HashMap<Language, LanguageString> result = new HashMap<Language, LanguageString>();
164 // result.putAll(multilanguageText);
166 return multilanguageText
;
170 // * Sets the multilanguage text.
171 // * The different {@link LanguageString language strings} (texts) contained in the
172 // * multilanguage text should all have the same meaning.
174 // * @param multilanguageText
176 // private void setMultilanguageText(Map<Language,LanguageString> multilanguageText) {
177 // this.multilanguageText = multilanguageText;
181 * Returns the multilanguage text with the content of <i>this</i> text data for
182 * a specific language.
184 * @param language the language in which the text string looked for is formulated
187 public LanguageString
getLanguageText(Language language
){
188 //work around for the problem that contains does not work correctly in persisted maps.
189 //This is because the persisted uuid is not present when loading the map key and
190 //therefore the hash code for language is not computed correctly
191 //see DescriptionElementDaoHibernateTest and #2114
192 // for (Map.Entry<Language, LanguageString> entry : multilanguageText.entrySet()){
193 // if (entry.getKey() != null){
194 // if (entry.getKey().equals(language)){
195 // return entry.getValue();
198 // if (language == null){
199 // return entry.getValue();
205 return getMultilanguageText().get(language
);
209 * Returns the text string in the given {@link Language language} with the content
210 * of <i>this</i> text data.
212 * @param language the language in which the text string looked for is formulated
213 * @see #getMultilanguageText(Language)
215 public String
getText(Language language
) {
216 LanguageString languageString
= getLanguageText(language
);
217 if (languageString
== null){
220 return languageString
.getText();
225 * Returns the LanguageString in the preferred language. Preferred languages
226 * are specified by the parameter languages, which receives a list of
227 * Language instances in the order of preference. If no representation in
228 * any preferred languages is found the method falls back to return the
229 * Representation in Language.DEFAULT() and if neccesary further falls back
230 * to return the first element found if any.
232 * TODO think about this fall-back strategy &
233 * see also {@link TermBase#getPreferredRepresentation(List)}
238 public LanguageString
getPreferredLanguageString(List
<Language
> languages
) {
239 return MultilanguageTextHelper
.getPreferredLanguageString(getMultilanguageText(), languages
);
242 private void fixHashMapHibernateBug() {
243 //workaround for key problem
244 if(! isHashMapHibernateBugFixed
){
245 HashMap
<Language
, LanguageString
> tmp
= new HashMap
<Language
, LanguageString
>();
246 tmp
.putAll(multilanguageText
);
247 multilanguageText
.clear();
248 multilanguageText
.putAll(tmp
);
250 isHashMapHibernateBugFixed
= true;
255 * Creates a {@link LanguageString language string} based on the given text string
256 * and the given {@link Language language}, returns it and adds it to the multilanguage
257 * text representing the content of <i>this</i> text data.
259 * @param text the string representing the content of the text data
260 * in a particular language
261 * @param language the language in which the text string is formulated
262 * @see #getMultilanguageText()
263 * @see #putText(LanguageString)
264 * @return the previous language string associated with the given Language, or null if there was no mapping for the given Language
265 * @deprecated should follow the put semantic of maps, this method will be removed in v4.0
266 * Use the {@link #putText(Language, String) putText} method instead
269 public LanguageString
putText(String text
, Language language
) {
270 return this.putText(language
, text
);
274 * Creates a {@link LanguageString language string} based on the given text string
275 * and the given {@link Language language}, returns it and adds it to the multilanguage
276 * text representing the content of <i>this</i> text data.
278 * @param language the language in which the text string is formulated
279 * @param text the string representing the content of the text data
280 * in a particular language
282 * @see #getMultilanguageText()
283 * @see #putText(LanguageString)
284 * @return the previous language string associated with the given Language, or null if there was no mapping for the given Language
286 public LanguageString
putText(Language language
, String text
) {
287 fixHashMapHibernateBug();
289 LanguageString languageString
= multilanguageText
.get(language
);
290 if (languageString
!= null){
291 languageString
.setText(text
);
293 languageString
= LanguageString
.NewInstance(text
, language
);
295 LanguageString result
= this.multilanguageText
.put(language
, languageString
);
296 return (result
== null ?
null : result
);
301 * Adds a translated {@link LanguageString text in a particular language}
302 * to the multi-language text representing the content of <i>this</i> text data.
303 * The given language string will be returned.
305 * @param languageString the language string representing the content of
306 * the text data in a particular language
307 * @see #getMultilanguageText()
308 * @see #putText(String, Language)
309 * @see HashMap#put(Object, Object)
310 * @return the previous language string associated with key, or null if there was no mapping for key
312 public LanguageString
putText(LanguageString languageString
) {
314 if (languageString
== null){
317 Language language
= languageString
.getLanguage();
318 return this.multilanguageText
.put(language
, languageString
);
322 * Removes from the multilanguage representing the content of
323 * <i>this</i> text data the one {@link LanguageString language string}
324 * with the given {@link Language language}. Returns the removed
327 * @param language the language in which the language string to be removed
328 * has been formulated
329 * @return the language string associated with the given language or null if there was no mapping for the given Language
330 * @see #getMultilanguageText()
332 public LanguageString
removeText(Language language
) {
333 fixHashMapHibernateBug();
334 return this.multilanguageText
.remove(language
);
338 * Returns the number of {@link Language languages} in which the content
339 * of <i>this</i> text data has been formulated.
341 * @see #getMultilanguageText()
343 public int countLanguages(){
344 return multilanguageText
.size();
349 * Returns the {@link TextFormat format} used for structuring the text representing
350 * the content of <i>this</i> text data.
352 * @see #getMultilanguageText()
354 public TextFormat
getFormat() {
360 public void setFormat(TextFormat format
) {
361 this.format
= format
;
365 * @see {@link java.util.Map#containsKey(Object)}
369 public boolean containsKey(Language language
){
370 return getMultilanguageText().containsKey(language
);
374 * @see {@link java.util.Map#containsValue(Object)}
375 * @param languageString
378 public boolean containsValue(LanguageString languageString
){
379 return getMultilanguageText().containsValue(languageString
);
384 * Returns the number of languages available for this text data.
385 * @see {@link java.util.Map#size()}
389 return this.multilanguageText
.size();
393 //*********************************** CLONE *****************************************/
396 * Clones <i>this</i> text data. This is a shortcut that enables to create
397 * a new instance that differs only slightly from <i>this</i> text data by
398 * modifying only some of the attributes.
400 * @see eu.etaxonomy.cdm.model.description.DescriptionElementBase#clone()
401 * @see java.lang.Object#clone()
404 public Object
clone() {
407 TextData result
= (TextData
)super.clone();
410 result
.multilanguageText
= new HashMap
<Language
, LanguageString
>();
411 for (Language language
: getMultilanguageText().keySet()){
412 //TODO clone needed? See also IndividualsAssociation
413 LanguageString newLanguageString
= (LanguageString
)getMultilanguageText().get(language
).clone();
414 result
.multilanguageText
.put(language
, newLanguageString
);
418 //no changes to: format
419 } catch (CloneNotSupportedException e
) {
420 logger
.warn("Object does not implement cloneable");