Project

General

Profile

Download (15.8 KB) Statistics
| Branch: | Tag: | Revision:
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
import java.util.HashMap;
13
import java.util.List;
14
import java.util.Map;
15

    
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;
32

    
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;
41

    
42
import eu.etaxonomy.cdm.common.CdmUtils;
43
import eu.etaxonomy.cdm.hibernate.search.MultilanguageTextFieldBridge;
44
import eu.etaxonomy.cdm.jaxb.MultilanguageTextAdapter;
45
import eu.etaxonomy.cdm.model.common.IMultiLanguageTextHolder;
46
import eu.etaxonomy.cdm.model.common.Language;
47
import eu.etaxonomy.cdm.model.common.LanguageString;
48
import eu.etaxonomy.cdm.model.common.MultilanguageTextHelper;
49
import eu.etaxonomy.cdm.model.term.TermBase;
50

    
51

    
52
/**
53
 * This class represents information pieces expressed in one or several natural
54
 * languages (for the {@link Feature feature} "medical use" for instance).
55
 * A {@link TextFormat format} used for structuring the text may also be stated.
56
 * <P>
57
 * This class corresponds partially to NaturalLanguageDescriptionType according
58
 * to the SDD schema.
59
 *
60
 * @author m.doering
61
 * @version 1.0
62
 * @since 08-Nov-2007 13:06:59
63
 */
64
@SuppressWarnings("unused")
65
@XmlAccessorType(XmlAccessType.FIELD)
66
@XmlType(name = "TextData", propOrder = {
67
    "multilanguageText",
68
    "format"
69
})
70
@XmlRootElement(name = "TextData")
71
@Entity
72
@Audited
73
@Indexed(index = "eu.etaxonomy.cdm.model.description.DescriptionElementBase")
74
public class TextData extends DescriptionElementBase implements IMultiLanguageTextHolder, Cloneable{
75
    private static final long serialVersionUID = -2165015581278282615L;
76
    private static final Logger logger = Logger.getLogger(TextData.class);
77

    
78
    //@XmlElement(name = "MultiLanguageText", type = MultilanguageText.class)
79
    @XmlElement(name = "MultiLanguageText")
80
    @XmlJavaTypeAdapter(MultilanguageTextAdapter.class)
81
    @OneToMany (fetch= FetchType.LAZY, orphanRemoval=true)
82
    @MapKeyJoinColumn(name="multilanguagetext_mapkey_id")
83
    @Cascade({CascadeType.SAVE_UPDATE,CascadeType.MERGE, CascadeType.DELETE})
84
    @Field(name="text", store=Store.YES)
85
    @FieldBridge(impl=MultilanguageTextFieldBridge.class)
86
    @NotNull
87
    private Map<Language, LanguageString> multilanguageText = new HashMap<>();
88

    
89
    @XmlElement(name = "Format")
90
    @XmlIDREF
91
    @XmlSchemaType(name = "IDREF")
92
    @ManyToOne(fetch = FetchType.LAZY)
93
    private TextFormat format;
94

    
95
    @XmlTransient
96
    @Transient
97
    private boolean isHashMapHibernateBugFixed = false;
98

    
99
    // ************* CONSTRUCTORS *************/
100
    /**
101
     * Class constructor: creates a new empty text data instance.
102
     *
103
     * @see #TextData(Feature)
104
     */
105
    public TextData(){
106
        this(null);
107
    }
108

    
109
    /**
110
     * Class constructor: creates a new text data instance with the {@link Feature feature}
111
     * to be described.
112
     *
113
     * @param	feature	the feature the text data refer to
114
     * @see 			#TextData()
115
     */
116
    public TextData(Feature feature){
117
        super(feature);
118
    }
119

    
120
    //********* METHODS **************************************/
121
    /**
122
     * Creates a new empty text data instance.
123
     *
124
     * @see #NewInstance(Feature)
125
     * @see #NewInstance(String, Language, TextFormat)
126
     * @see	#NewInstance(Feature, String, Language, TextFormat)
127
     */
128
    public static TextData NewInstance(){
129
        return new TextData();
130
    }
131

    
132
    /**
133
     * Creates a new text data instance with the {@link Feature feature}
134
     * to be described.
135
     *
136
     * @param	feature	the feature the text data refer to
137
     * @see 			#NewInstance()
138
     * @see 			#NewInstance(String, Language, TextFormat)
139
     * @see					#NewInstance(Feature, String, Language, TextFormat)
140
     */
141
    public static TextData NewInstance(Feature feature){
142
        return new TextData(feature);
143
    }
144

    
145
    /**
146
     * Creates a new text data instance with a given text in a given particular
147
     * {@link Language language} and with the given text format for structuring it.
148
     *
149
     * @param	text		the text string with the content of the description
150
     * @param	language	the language in which the text string is formulated
151
     * @param	format		the text format used to structure the text string
152
     * @see 				#NewInstance()
153
     * @see 				#NewInstance(Feature)
154
     * @see					#NewInstance(Feature, String, Language, TextFormat)
155
     */
156
    public static TextData NewInstance(String text, Language language, TextFormat format){
157
        TextData result =  new TextData();
158
        result.putText(language, text);
159
        result.setFormat(format);
160
        return result;
161
    }
162

    
163

    
164
    /**
165
     * Creates a new text data instance with a given text in a given particular
166
     * {@link Language language} and with the given text format for structuring it.
167
     *
168
     * @param   feature	    the feature the text data refer to
169
     * @param	text		the text string with the content of the description
170
     * @param	language	the language in which the text string is formulated
171
     * @param	format		the text format used to structure the text string
172
     * @see 				#NewInstance()
173
     * @see 				#NewInstance(Feature)
174
     * @see					#NewInstance(String, Language, TextFormat)
175
     */
176
    public static TextData NewInstance(Feature feature, String text, Language language, TextFormat format){
177
        TextData result =  new TextData(feature);
178
        result.putText(language, text);
179
        result.setFormat(format);
180
        return result;
181
    }
182

    
183
    /**
184
     * Returns a copy of the multilanguage text with the content of <i>this</i> text data.
185
     * The different {@link LanguageString language strings} (texts) contained in the
186
     * multilanguage text should all have the same meaning.
187
     *
188
     * @see	#getText(Language)
189
     */
190
    public Map<Language, LanguageString> getMultilanguageText() {
191
        fixHashMapHibernateBug();
192

    
193
//    	HashMap<Language, LanguageString> result = new HashMap<>();
194
//		result.putAll(multilanguageText);
195
//		return result;
196
        return multilanguageText;
197
    }
198

    
199
//    /**
200
//     * Sets the multilanguage text.
201
//	 * The different {@link LanguageString language strings} (texts) contained in the
202
//	 * multilanguage text should all have the same meaning.
203
//     *
204
//     * @param multilanguageText
205
//     */
206
//    private void setMultilanguageText(Map<Language,LanguageString> multilanguageText) {
207
//    	this.multilanguageText = multilanguageText;
208
//    }
209

    
210
    /**
211
     * Returns the multilanguage text with the content of <i>this</i> text data for
212
     * a specific language.
213
     *
214
     * @param language the language in which the text string looked for is formulated
215
     * @return
216
     */
217
    public LanguageString getLanguageText(Language language){
218
        //work around for the problem that contains does not work correctly in persisted maps.
219
        //This is because the persisted uuid is not present when loading the map key and
220
        //therefore the hash code for language is not computed correctly
221
        //see DescriptionElementDaoHibernateTest and #2114
222
//    	for (Map.Entry<Language, LanguageString> entry : multilanguageText.entrySet()){
223
//    		if (entry.getKey() != null){
224
//        		if (entry.getKey().equals(language)){
225
//        			return entry.getValue();
226
//        		}
227
//    		}else{
228
//    			if (language == null){
229
//    				return entry.getValue();
230
//    			}
231
//    		}
232
//    	}
233
//    	return null;
234
        //old
235
        return getMultilanguageText().get(language);
236
    }
237

    
238
    /**
239
     * Returns the text string in the given {@link Language language} with the content
240
     * of <i>this</i> text data.
241
     *
242
     * @param language	the language in which the text string looked for is formulated
243
     * @see				#getMultilanguageText(Language)
244
     */
245
    public String getText(Language language) {
246
        LanguageString languageString = getLanguageText(language);
247
        if (languageString == null){
248
            return null;
249
        }else{
250
            return languageString.getText();
251
        }
252
    }
253

    
254
    /**
255
     * Returns the LanguageString in the preferred language. Preferred languages
256
     * are specified by the parameter languages, which receives a list of
257
     * Language instances in the order of preference. If no representation in
258
     * any preferred languages is found the method falls back to return the
259
     * Representation in Language.DEFAULT() and if neccesary further falls back
260
     * to return the first element found if any.
261
     *
262
     * TODO think about this fall-back strategy &
263
     * see also {@link TermBase#getPreferredRepresentation(List)}
264
     *
265
     * @param languages
266
     * @return
267
     */
268
    public LanguageString getPreferredLanguageString(List<Language> languages) {
269
        return MultilanguageTextHelper.getPreferredLanguageString(getMultilanguageText(), languages);
270
    }
271

    
272
    private void fixHashMapHibernateBug() {
273
        //workaround for key problem
274
        if(! isHashMapHibernateBugFixed){
275
            HashMap<Language, LanguageString> tmp = new HashMap<>();
276
            tmp.putAll(multilanguageText);
277
            multilanguageText.clear();
278
            multilanguageText.putAll(tmp);
279

    
280
            isHashMapHibernateBugFixed = true;
281
        }
282
    }
283

    
284

    
285
    /**
286
     * Creates a {@link LanguageString language string} based on the given text string
287
     * and the given {@link Language language}, returns it and adds it to the multilanguage
288
     * text representing the content of <i>this</i> text data.
289
     *
290
     * @param language	the language in which the text string is formulated
291
     * @param text		the string representing the content of the text data
292
     * 					in a particular language
293
     *
294
     * @see    	   		#getMultilanguageText()
295
     * @see    	   		#putText(LanguageString)
296
     * @return			the previous language string associated with the given Language, or null if there was no mapping for the given Language
297
     */
298
    public LanguageString putText(Language language, String text) {
299
        fixHashMapHibernateBug();
300
        //** end workaround
301
        LanguageString languageString = multilanguageText.get(language);
302
        if (languageString != null){
303
            languageString.setText(text);
304
        }else{
305
            languageString = LanguageString.NewInstance(text, language);
306
        }
307
        this.multilanguageText.put(language , languageString);
308
        return languageString;
309
    }
310

    
311

    
312
    /**
313
     * Adds a translated {@link LanguageString text in a particular language}
314
     * to the multi-language text representing the content of <i>this</i> text data.
315
     * The given language string will be returned.
316
     *
317
     * @param languageString	the language string representing the content of
318
     * 							the text data in a particular language
319
     * @see    	   				#getMultilanguageText()
320
     * @see    	   				#putText(String, Language)
321
     * @see						HashMap#put(Object, Object)
322
     * @return					the previous language string associated with key, or null if there was no mapping for key
323
     */
324
    public LanguageString putText(LanguageString languageString) {
325

    
326
        if (languageString == null){
327
            return null;
328
        }else{
329
            Language language = languageString.getLanguage();
330
            return this.multilanguageText.put(language, languageString);
331
        }
332
    }
333
    /**
334
     * Removes from the multilanguage representing the content of
335
     * <i>this</i> text data the one {@link LanguageString language string}
336
     * with the given {@link Language language}. Returns the removed
337
     * language string.
338
     *
339
     * @param  language	the language in which the language string to be removed
340
     * 					has been formulated
341
     * @return			the language string associated with the given language or null if there was no mapping for the given Language
342
     * @see     		#getMultilanguageText()
343
     */
344
    public LanguageString removeText(Language language) {
345
        fixHashMapHibernateBug();
346
        return this.multilanguageText.remove(language);
347
    }
348

    
349
    /**
350
     * Returns the number of {@link Language languages} in which the content
351
     * of <i>this</i> text data has been formulated.
352
     *
353
     * @see	#getMultilanguageText()
354
     */
355
    public int countLanguages(){
356
        return multilanguageText.size();
357
    }
358

    
359

    
360
    /**
361
     * Returns the {@link TextFormat format} used for structuring the text representing
362
     * the content of <i>this</i> text data.
363
     *
364
     * @see	#getMultilanguageText()
365
     */
366
    public TextFormat getFormat() {
367
        return format;
368
    }
369
    /**
370
     * @see	#getFormat()
371
     */
372
    public void setFormat(TextFormat format) {
373
        this.format = format;
374
    }
375

    
376
    /**
377
     * @see {@link java.util.Map#containsKey(Object)}
378
     * @param language
379
     * @return
380
     */
381
    public boolean containsKey(Language language){
382
        return getMultilanguageText().containsKey(language);
383
    }
384

    
385
    /**
386
     * @see {@link java.util.Map#containsValue(Object)}
387
     * @param languageString
388
     * @return
389
     */
390
    public boolean containsValue(LanguageString languageString){
391
        return getMultilanguageText().containsValue(languageString);
392
    }
393

    
394

    
395
    /**
396
     * Returns the number of languages available for this text data.
397
     * @see {@link java.util.Map#size()}
398
     * @return
399
     */
400
    public int size(){
401
        return this.multilanguageText.size();
402
    }
403

    
404

    
405

    
406

    
407
//*********************************** CLONE *****************************************/
408

    
409
    /**
410
     * {@inheritDoc}
411
     */
412
    @Override
413
    public String toString() {
414
        Map<Language, LanguageString> multiLangText = getMultilanguageText();
415
        if (multiLangText.isEmpty()){
416
            return super.toString();
417
        }else{
418
            String result = null;
419
            for(LanguageString ls : multiLangText.values()){
420
                result = CdmUtils.concat(";", result, ls.toString());
421
            }
422
            return "[" + result + "]";
423
        }
424
    }
425

    
426
    /**
427
     * Clones <i>this</i> text data. This is a shortcut that enables to create
428
     * a new instance that differs only slightly from <i>this</i> text data by
429
     * modifying only some of the attributes.
430
     *
431
     * @see eu.etaxonomy.cdm.model.description.DescriptionElementBase#clone()
432
     * @see java.lang.Object#clone()
433
     */
434
    @Override
435
    public Object clone() {
436

    
437
        try {
438
            TextData result = (TextData)super.clone();
439

    
440
            //description
441
            result.multilanguageText = new HashMap<Language, LanguageString>();
442
            for (Language language : getMultilanguageText().keySet()){
443
                //TODO clone needed? See also IndividualsAssociation
444
                LanguageString newLanguageString = (LanguageString)getMultilanguageText().get(language).clone();
445
                result.multilanguageText.put(language, newLanguageString);
446
            }
447

    
448
            return result;
449
            //no changes to: format
450
        } catch (CloneNotSupportedException e) {
451
            logger.warn("Object does not implement cloneable");
452
            e.printStackTrace();
453
            return null;
454
        }
455
    }
456

    
457
}
(34-34/37)