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.model.taxon.Taxon;
58
import eu.etaxonomy.cdm.strategy.merge.Merge;
59
import eu.etaxonomy.cdm.strategy.merge.MergeMode;
60

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

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

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

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

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

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

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

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

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

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

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

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

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

    
490
	
491
}
(5-5/39)