Project

General

Profile

Download (17.3 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

    
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.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;
36

    
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.IndexedEmbedded;
43

    
44
import eu.etaxonomy.cdm.jaxb.MultilanguageTextAdapter;
45
import eu.etaxonomy.cdm.model.common.AnnotatableEntity;
46
import eu.etaxonomy.cdm.model.common.DescriptionElementSource;
47
import eu.etaxonomy.cdm.model.common.IMultiLanguageTextHolder;
48
import eu.etaxonomy.cdm.model.common.ISourceable;
49
import eu.etaxonomy.cdm.model.common.Language;
50
import eu.etaxonomy.cdm.model.common.LanguageString;
51
import eu.etaxonomy.cdm.model.common.MultilanguageText;
52
import eu.etaxonomy.cdm.model.common.TermVocabulary;
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.reference.Reference;
57
import eu.etaxonomy.cdm.strategy.merge.Merge;
58
import eu.etaxonomy.cdm.strategy.merge.MergeMode;
59

    
60
/**
61
 * The upmost (abstract) class for a piece of information) about
62
 * a {@link SpecimenOrObservationBase specimen}, a {@link Taxon taxon} or even a {@link TaxonNameBase taxon name}.
63
 * A concrete description element assigns descriptive data to one {@link Feature feature}.<BR>
64
 * Experts use the word feature for the property itself but not for the actual
65
 * description element. Therefore naming this class FeatureBase would have
66
 * leaded to confusion.  
67
 * <P>
68
 * This class corresponds to: <ul>
69
 * <li> DescriptionsBaseType according to the the SDD schema
70
 * <li> InfoItem according to the TDWG ontology
71
 * <li> MeasurementOrFactAtomised according to the ABCD schema
72
 * </ul>
73
 * 
74
 * @author m.doering
75
 * @version 1.0
76
 * @created 08-Nov-2007 13:06:24
77
 */
78
@XmlAccessorType(XmlAccessType.FIELD)
79
@XmlType(name = "DescriptionElementBase", propOrder = {
80
	    "feature",
81
	    "modifiers",
82
	    "modifyingText",
83
	    "media",
84
	    "inDescription",
85
	    "sources"
86
})
87
@Entity
88
@Audited
89
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
90
public abstract class DescriptionElementBase extends AnnotatableEntity implements ISourceable<DescriptionElementSource>, IModifiable, IMultiLanguageTextHolder{
91
	private static final long serialVersionUID = 5000910777835755905L;
92
	@SuppressWarnings("unused")
93
	private static final Logger logger = Logger.getLogger(DescriptionElementBase.class);
94
	
95
	//type, category of information. In structured descriptions characters
96
	@XmlElement(name = "Feature")
97
    @XmlIDREF
98
    @XmlSchemaType(name = "IDREF")
99
    @ManyToOne(fetch = FetchType.LAZY)
100
    //@Cascade(CascadeType.SAVE_UPDATE)
101
    @Cascade(CascadeType.MERGE)
102
    @IndexedEmbedded
103
	private Feature feature;
104
	
105
	@XmlElementWrapper(name = "Modifiers")
106
	@XmlElement(name = "Modifier")
107
	@XmlIDREF
108
    @XmlSchemaType(name = "IDREF")
109
	@ManyToMany(fetch = FetchType.LAZY)
110
    @JoinTable(name="DescriptionElementBase_Modifier")
111
	private Set<Modifier> modifiers = new HashSet<Modifier>();
112
	
113
	@XmlElement(name = "ModifyingText")
114
    @XmlJavaTypeAdapter(MultilanguageTextAdapter.class)
115
    @OneToMany(fetch = FetchType.LAZY)
116
    @JoinTable(name = "DescriptionElementBase_ModifyingText")
117
    @Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE})
118
	private Map<Language,LanguageString> modifyingText = new HashMap<Language,LanguageString>();
119
	
120
	@XmlElementWrapper(name = "Media")
121
	@XmlElement(name = "Medium")
122
    @XmlIDREF
123
    @XmlSchemaType(name = "IDREF")
124
    @ManyToMany(fetch = FetchType.LAZY)
125
    @IndexColumn(name="sortIndex", base = 0)
126
	@Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE})
127
	private List<Media> media = new ArrayList<Media>();
128
	
129
	@XmlElement(name = "InDescription")
130
	@XmlIDREF
131
    @XmlSchemaType(name = "IDREF")
132
    @ManyToOne(fetch = FetchType.LAZY)
133
    @Cascade(CascadeType.SAVE_UPDATE)
134
	@IndexedEmbedded
135
    private DescriptionBase inDescription;
136
	
137
    @XmlElementWrapper(name = "Sources")
138
    @XmlElement(name = "DescriptionElementSource")
139
    @OneToMany(fetch = FetchType.LAZY)		
140
	@Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE, CascadeType.DELETE, CascadeType.DELETE_ORPHAN})
141
	@Merge(MergeMode.ADD_CLONE)
142
	private Set<DescriptionElementSource> sources = new HashSet<DescriptionElementSource>();
143
    
144
	
145

    
146
	// ************* CONSTRUCTORS *************/	
147
	/** 
148
	 * Class constructor: creates a new empty description element instance.
149
	 * 
150
	 * @see #DescriptionElementBase(Feature)
151
	 */
152
	protected DescriptionElementBase(){
153
	}
154
	
155
	/** 
156
	 * Class constructor: creates a new description element instance with the
157
	 * given {@link Feature feature} that is described or measured.
158
	 * 
159
	 * @param	feature	the feature described or measured
160
	 * @see 			#DescriptionElementBase()
161
	 */
162
	protected DescriptionElementBase(Feature feature){
163
		if (feature == null){
164
			feature = Feature.UNKNOWN();
165
		}
166
		this.feature = feature; 
167
	}
168

    
169
	/** 
170
	 * Returns the list of {@link Media media} (that is pictures, movies,
171
	 * recorded sounds ...) <i>this</i> description element is based on.
172
	 */
173
	public List<Media> getMedia(){
174
		return this.media;
175
	}
176

    
177
	/**
178
	 * Adds a {@link Media media} to the list of {@link #getMedia() media}
179
	 * <i>this</i> description element is based on.
180
	 * 
181
	 * @param media	the media to be added to <i>this</i> description element
182
	 * @see    	   	#getMedia()
183
	 */
184
	public void addMedia(Media media){
185
		this.media.add(media);
186
	}
187
	/** 
188
	 * Removes one element from the list of {@link #getMedia() media}
189
	 * <i>this</i> description element is based on.
190
	 *
191
	 * @param  media	the media which should be removed
192
	 * @see     		#getMedia()
193
	 * @see     		#addMedia(Media)
194
	 */
195
	public void removeMedia(Media media){
196
		this.media.remove(media);
197
	}
198
	
199
	/**
200
	 * Returns the {@link DescriptionBase description} that <i>this</i> DescriptionElement is
201
	 * part of. 
202
	 * @return
203
	 */
204
	public DescriptionBase getInDescription() {
205
		return this.inDescription;
206
	}
207
	
208
	/**
209
	 * @see	#setInDescription() 
210
	 */
211
	protected void setInDescription(DescriptionBase inDescription) {
212
		this.inDescription = inDescription;
213
	}
214
	
215
	/** 
216
	 * Returns the {@link Feature feature} <i>this</i> description element is for.
217
	 * A feature is a property that can be described or measured but not the
218
	 * description or the measurement itself.
219
	 */
220
	public Feature getFeature(){
221
		return this.feature;
222
	}
223
	
224
	/**
225
	 * @see	#getFeature() 
226
	 */
227
	public void setFeature(Feature feature){
228
		this.feature = feature;
229
	}
230

    
231
	/** 
232
	 * Returns the set of {@link Modifier modifiers} used to qualify the validity of
233
	 * <i>this</i> description element. This is only metainformation.
234
	 */
235
	public Set<Modifier> getModifiers(){
236
		return this.modifiers;
237
	}
238

    
239
	/**
240
	 * Adds a {@link Modifier modifier} to the set of {@link #getModifiers() modifiers}
241
	 * used to qualify the validity of <i>this</i> description element.
242
	 * 
243
	 * @param modifier	the modifier to be added to <i>this</i> description element
244
	 * @see    	   		#getModifiers()
245
	 */
246
	public void addModifier(Modifier modifier){
247
		this.modifiers.add(modifier);
248
	}
249
	/** 
250
	 * Removes one element from the set of {@link #getModifiers() modifiers}
251
	 * used to qualify the validity of <i>this</i> description element.
252
	 *
253
	 * @param  modifier	the modifier which should be removed
254
	 * @see     		#getModifiers()
255
	 * @see     		#addModifier(Modifier)
256
	 */
257
	public void removeModifier(Modifier modifier){
258
		this.modifiers.remove(modifier);
259
	}
260

    
261
	
262
	/** 
263
	 * Returns the {@link MultilanguageText multilanguage text} used to qualify the validity
264
	 * of <i>this</i> description element.  The different {@link LanguageString language strings}
265
	 * contained in the multilanguage text should all have the same meaning.<BR>
266
	 * A multilanguage text does not belong to a controlled {@link TermVocabulary term vocabulary}
267
	 * as a {@link Modifier modifier} does.
268
	 * <P>
269
	 * NOTE: the actual content of <i>this</i> description element is NOT
270
	 * stored in the modifying text. This is only metainformation
271
	 * (like "Some experts express doubt about this assertion").
272
	 */
273
	public Map<Language,LanguageString> getModifyingText(){
274
		return this.modifyingText;
275
	}
276

    
277
	/**
278
	 * Adds a translated {@link LanguageString text in a particular language}
279
	 * to the {@link MultilanguageText multilanguage text} used to qualify the validity
280
	 * of <i>this</i> description element.
281
	 * 
282
	 * @param description	the language string describing the validity
283
	 * 						in a particular language
284
	 * @see    	   			#getModifyingText()
285
	 * @see    	   			#putModifyingText(Language, String)
286
	 * @deprecated 			should follow the put semantic of maps, this method will be removed in v4.0
287
	 * 						Use the {@link #putModifyingText(LanguageString) putModifyingText} method 
288
	 */
289
	public LanguageString addModifyingText(LanguageString description){
290
		return this.putModifyingText(description);
291
	}
292
	
293
	/**
294
	 * Adds a translated {@link LanguageString text in a particular language}
295
	 * to the {@link MultilanguageText multilanguage text} used to qualify the validity
296
	 * of <i>this</i> description element.
297
	 * 
298
	 * @param description	the language string describing the validity
299
	 * 						in a particular language
300
	 * @see    	   			#getModifyingText()
301
	 * @see    	   			#putModifyingText(Language, String)
302
	 */
303
	public LanguageString putModifyingText(LanguageString description){
304
		return this.modifyingText.put(description.getLanguage(),description);
305
	}
306
	/**
307
	 * Creates a {@link LanguageString language string} based on the given text string
308
	 * and the given {@link Language language} and adds it to the {@link MultilanguageText multilanguage text} 
309
	 * used to qualify the validity of <i>this</i> description element.
310
	 * 
311
	 * @param text		the string describing the validity
312
	 * 					in a particular language
313
	 * @param language	the language in which the text string is formulated
314
	 * @see    	   		#getModifyingText()
315
	 * @see    	   		#putModifyingText(LanguageString)
316
	 * @deprecated 		should follow the put semantic of maps, this method will be removed in v4.0
317
	 * 					Use the {@link #putModifyingText(Language, String) putModifyingText} method
318
	 */
319
	public LanguageString addModifyingText(String text, Language language){
320
		return this.putModifyingText(language, text);
321
	}
322
	
323
	/**
324
	 * Creates a {@link LanguageString language string} based on the given text string
325
	 * and the given {@link Language language} and adds it to the {@link MultilanguageText multilanguage text} 
326
	 * used to qualify the validity of <i>this</i> description element.
327
	 * 
328
	 * @param language	the language in which the text string is formulated
329
	 * @param text		the string describing the validity
330
	 * 					in a particular language
331
	 * 
332
	 * @see    	   		#getModifyingText()
333
	 * @see    	   		#putModifyingText(LanguageString)
334
	 * 
335
	 */
336
	public LanguageString putModifyingText(Language language, String text){
337
		return this.modifyingText.put(language, LanguageString.NewInstance(text, language));
338
	}
339
	/** 
340
	 * Removes from the {@link MultilanguageText multilanguage text} used to qualify the validity
341
	 * of <i>this</i> description element the one {@link LanguageString language string}
342
	 * with the given {@link Language language}.
343
	 *
344
	 * @param  language	the language in which the language string to be removed
345
	 * 					has been formulated
346
	 * @see     		#getModifyingText()
347
	 */
348
	public LanguageString removeModifyingText(Language language){
349
		return this.modifyingText.remove(language);
350
	}
351

    
352
	/* (non-Javadoc)
353
	 * @see eu.etaxonomy.cdm.model.common.ISourceable#getSources()
354
	 */
355
	public Set<DescriptionElementSource> getSources() {
356
		return this.sources;		
357
	}
358
	
359
	/* (non-Javadoc)
360
	 * @see eu.etaxonomy.cdm.model.common.ISourceable#addSource(eu.etaxonomy.cdm.model.common.IOriginalSource)
361
	 */
362
	public void addSource(DescriptionElementSource source) {
363
		if (source != null){
364
			DescriptionElementBase oldSourcedObj = source.getSourcedObj();
365
			if (oldSourcedObj != null && oldSourcedObj != this){
366
				oldSourcedObj.getSources().remove(source);
367
			}
368
			this.sources.add(source);
369
			source.setSourcedObj(this);
370
		}
371
	}
372
	
373
	/* (non-Javadoc)
374
	 * @see eu.etaxonomy.cdm.model.common.ISourceable#addSource(java.lang.String, java.lang.String, eu.etaxonomy.cdm.model.reference.Reference, java.lang.String)
375
	 */
376
	public DescriptionElementSource addSource(String id, String idNamespace, Reference citation, String microCitation) {
377
		if (id == null && idNamespace == null && citation == null && microCitation == null){
378
			return null;
379
		}
380
		DescriptionElementSource source = DescriptionElementSource.NewInstance(id, idNamespace, citation, microCitation);
381
		addSource(source);
382
		return source;
383
	}
384
	
385
	public void addSource(String id, String idNamespace, Reference citation, String microReference, TaxonNameBase nameUsedInSource, String originalNameString){
386
		DescriptionElementSource newSource = DescriptionElementSource.NewInstance(id, idNamespace, citation, microReference, nameUsedInSource, originalNameString);
387
		addSource(newSource);
388
	}
389
	 
390
	/* (non-Javadoc)
391
	 * @see eu.etaxonomy.cdm.model.common.ISourceable#removeSource(eu.etaxonomy.cdm.model.common.IOriginalSource)
392
	 */
393
	public void removeSource(DescriptionElementSource source) {
394
		this.sources.remove(source);
395
	}
396
	
397
//	
398
//	/**
399
//	 * Sets the citation micro reference of the first source. This method is deprecated and exists only to be compliant with version 2.0.
400
//	 * It will be removed in v2.3
401
//	 * If more than one source exists an IllegalStateException is thrown
402
//	 **/
403
//	@Transient
404
//	@Deprecated
405
//	public void setCitationMicroReference(String citationMicroReference){
406
//		if (this.sources.size() < 1){
407
//			Reference citation = null;
408
//			this.addSource(DescriptionElementSource.NewInstance(null, null, citation, citationMicroReference));
409
//		}else if (this.sources.size() > 1){
410
//			throw new IllegalStateException("When adding a microcitation via the setCitationMicroReference method there must be only one source available");
411
//		}else{
412
//			this.sources.iterator().next().setCitationMicroReference(citationMicroReference);
413
//		}
414
//	}
415
//	
416
//	/**
417
//	 * Sets the citation of the first source. This method is deprecated and exists only to be compliant with version 2.0.
418
//	 * It will be removed in v2.3
419
//	 * If more than one source exists an IllegalStateException is thrown
420
//	 **/
421
//	@Deprecated
422
//	public void setCitation(Reference citation) {
423
//		if (this.sources.size() < 1){
424
//			this.addSource(DescriptionElementSource.NewInstance(null, null, citation, null));
425
//		}else if (this.sources.size() > 1){
426
//			throw new IllegalStateException("When adding a citation via the setCitation method there must be only one source available");
427
//		}else{
428
//			this.sources.iterator().next().setCitation(citation);
429
//		}
430
//	}
431
	
432

    
433
//************************** CLONE **********************************************************/	
434
	
435
	/** 
436
	 * Clones the description element. The element is <b>not</b> added to the same 
437
	 * description as the orginal element (inDescription is set to <code>null</null>).
438
	 * @see eu.etaxonomy.cdm.model.common.AnnotatableEntity#clone()
439
	 */
440
	@Override
441
	public Object clone() throws CloneNotSupportedException{
442
		DescriptionElementBase result = (DescriptionElementBase)super.clone();
443

    
444
		//inDescription
445
		result.inDescription = null;
446
		
447
		//Sources
448
		result.sources = new HashSet<DescriptionElementSource>();
449
		for (DescriptionElementSource source : getSources()){
450
			DescriptionElementSource newSource = (DescriptionElementSource)source.clone();
451
			result.addSource(newSource);
452
		}
453
		
454
		//media
455
		result.media = new ArrayList<Media>();
456
		for (Media media : getMedia()){
457
			result.media.add(media);
458
		}
459
		
460
		//modifying text
461
		result.modifyingText = new HashMap<Language, LanguageString>();
462
		for (Language language : getModifyingText().keySet()){
463
			//TODO clone needed? See also IndividualsAssociation
464
			LanguageString newLanguageString = (LanguageString)getModifyingText().get(language).clone();
465
			result.modifyingText.put(language, newLanguageString);
466
		}
467
		
468
		//modifiers
469
		result.modifiers = new HashSet<Modifier>();
470
		for (Modifier modifier : getModifiers()){
471
			result.modifiers.add(modifier);
472
		}
473

    
474
		//no changes to: feature
475
		return result;
476
	}
477

    
478
	/** 
479
	 * Clones the description element.<BR> 
480
	 * The new element is added to the <code>description</code>.<BR>
481
	 * @see eu.etaxonomy.cdm.model.common.AnnotatableEntity#clone()
482
	 */
483
	public DescriptionElementBase clone(DescriptionBase description) throws CloneNotSupportedException{
484
		DescriptionElementBase result = (DescriptionElementBase)clone();
485
		description.addElement(result);
486
		return result;
487
	}
488

    
489
	
490
}
(5-5/40)