Project

General

Profile

Download (18.6 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.persistence.Transient;
29
import javax.xml.bind.annotation.XmlAccessType;
30
import javax.xml.bind.annotation.XmlAccessorType;
31
import javax.xml.bind.annotation.XmlElement;
32
import javax.xml.bind.annotation.XmlElementWrapper;
33
import javax.xml.bind.annotation.XmlIDREF;
34
import javax.xml.bind.annotation.XmlSchemaType;
35
import javax.xml.bind.annotation.XmlType;
36
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
37

    
38
import org.apache.log4j.Logger;
39
import org.hibernate.annotations.Cascade;
40
import org.hibernate.annotations.CascadeType;
41
import org.hibernate.annotations.IndexColumn;
42
import org.hibernate.envers.Audited;
43
import org.hibernate.search.annotations.IndexedEmbedded;
44

    
45
import eu.etaxonomy.cdm.jaxb.MultilanguageTextAdapter;
46
import eu.etaxonomy.cdm.model.common.AnnotatableEntity;
47
import eu.etaxonomy.cdm.model.common.Annotation;
48
import eu.etaxonomy.cdm.model.common.DescriptionElementSource;
49
import eu.etaxonomy.cdm.model.common.ISourceable;
50
import eu.etaxonomy.cdm.model.common.IdentifiableSource;
51
import eu.etaxonomy.cdm.model.common.Language;
52
import eu.etaxonomy.cdm.model.common.LanguageString;
53
import eu.etaxonomy.cdm.model.common.MultilanguageText;
54
import eu.etaxonomy.cdm.model.common.TermVocabulary;
55
import eu.etaxonomy.cdm.model.media.Media;
56
import eu.etaxonomy.cdm.model.name.TaxonNameBase;
57
import eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationBase;
58
import eu.etaxonomy.cdm.model.reference.ReferenceBase;
59
import eu.etaxonomy.cdm.model.taxon.Taxon;
60
import eu.etaxonomy.cdm.strategy.merge.Merge;
61
import eu.etaxonomy.cdm.strategy.merge.MergeMode;
62

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

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

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

    
180
	/**
181
	 * Adds a {@link Media media} to the list of {@link #getMedia() media}
182
	 * <i>this</i> description element is based on.
183
	 * 
184
	 * @param media	the media to be added to <i>this</i> description element
185
	 * @see    	   	#getMedia()
186
	 */
187
	public void addMedia(Media media){
188
		this.media.add(media);
189
	}
190
	/** 
191
	 * Removes one element from the list of {@link #getMedia() media}
192
	 * <i>this</i> description element is based on.
193
	 *
194
	 * @param  media	the media which should be removed
195
	 * @see     		#getMedia()
196
	 * @see     		#addMedia(Media)
197
	 */
198
	public void removeMedia(Media media){
199
		this.media.remove(media);
200
	}
201
	
202
	/**
203
	 * Returns the {@link DescriptionBase description} that <i>this</i> DescriptionElement is
204
	 * part of. 
205
	 * @return
206
	 */
207
	public DescriptionBase getInDescription() {
208
		return this.inDescription;
209
	}
210
	
211
	/**
212
	 * @see	#setInDescription() 
213
	 */
214
	protected void setInDescription(DescriptionBase inDescription) {
215
		this.inDescription = inDescription;
216
	}
217

    
218
	/**
219
	 * Does exactly the same as getFeature().
220
	 * @author ben.clark
221
	 * FIXME Is there a need to have two methods with different names which do the same thing?
222
	 * 
223
	 * @see #getFeature() 
224
	 */
225
	@Transient
226
	@Deprecated //will be removed in version 3. 
227
	public Feature getType(){
228
		return this.getFeature();
229
	}
230
	/**
231
	 * Does exactly the same as setFeature(Feature).
232
	 * 
233
	 * @param type	the feature to be described or measured
234
	 * @see 		#setFeature(Feature) 
235
	 * @see 		#getFeature() 
236
	 */
237
	@Deprecated  //will be removed in version 3
238
	public void setType(Feature type){
239
		this.setFeature(type);
240
	}
241
	
242
	/** 
243
	 * Returns the {@link Feature feature} <i>this</i> description element is for.
244
	 * A feature is a property that can be described or measured but not the
245
	 * description or the measurement itself.
246
	 */
247
	public Feature getFeature(){
248
		return this.feature;
249
	}
250
	
251
	/**
252
	 * @see	#getFeature() 
253
	 */
254
	public void setFeature(Feature feature){
255
		this.feature = feature;
256
	}
257

    
258
	/** 
259
	 * Returns the set of {@link Modifier modifiers} used to qualify the validity of
260
	 * <i>this</i> description element. This is only metainformation.
261
	 */
262
	public Set<Modifier> getModifiers(){
263
		return this.modifiers;
264
	}
265

    
266
	/**
267
	 * Adds a {@link Modifier modifier} to the set of {@link #getModifiers() modifiers}
268
	 * used to qualify the validity of <i>this</i> description element.
269
	 * 
270
	 * @param modifier	the modifier to be added to <i>this</i> description element
271
	 * @see    	   		#getModifiers()
272
	 */
273
	public void addModifier(Modifier modifier){
274
		this.modifiers.add(modifier);
275
	}
276
	/** 
277
	 * Removes one element from the set of {@link #getModifiers() modifiers}
278
	 * used to qualify the validity of <i>this</i> description element.
279
	 *
280
	 * @param  modifier	the modifier which should be removed
281
	 * @see     		#getModifiers()
282
	 * @see     		#addModifier(Modifier)
283
	 */
284
	public void removeModifier(Modifier modifier){
285
		this.modifiers.remove(modifier);
286
	}
287

    
288
	
289
	/** 
290
	 * Returns the {@link MultilanguageText multilanguage text} used to qualify the validity
291
	 * of <i>this</i> description element.  The different {@link LanguageString language strings}
292
	 * contained in the multilanguage text should all have the same meaning.<BR>
293
	 * A multilanguage text does not belong to a controlled {@link TermVocabulary term vocabulary}
294
	 * as a {@link Modifier modifier} does.
295
	 * <P>
296
	 * NOTE: the actual content of <i>this</i> description element is NOT
297
	 * stored in the modifying text. This is only metainformation
298
	 * (like "Some experts express doubt about this assertion").
299
	 */
300
	public Map<Language,LanguageString> getModifyingText(){
301
		return this.modifyingText;
302
	}
303

    
304
	/**
305
	 * Adds a translated {@link LanguageString text in a particular language}
306
	 * to the {@link MultilanguageText multilanguage text} used to qualify the validity
307
	 * of <i>this</i> description element.
308
	 * 
309
	 * @param description	the language string describing the validity
310
	 * 						in a particular language
311
	 * @see    	   			#getModifyingText()
312
	 * @see    	   			#addModifyingText(String, Language)
313
	 */
314
	public LanguageString addModifyingText(LanguageString description){
315
		return this.modifyingText.put(description.getLanguage(),description);
316
	}
317
	/**
318
	 * Creates a {@link LanguageString language string} based on the given text string
319
	 * and the given {@link Language language} and adds it to the {@link MultilanguageText multilanguage text} 
320
	 * used to qualify the validity of <i>this</i> description element.
321
	 * 
322
	 * @param text		the string describing the validity
323
	 * 					in a particular language
324
	 * @param language	the language in which the text string is formulated
325
	 * @see    	   		#getModifyingText()
326
	 * @see    	   		#addModifyingText(LanguageString)
327
	 */
328
	public LanguageString addModifyingText(String text, Language language){
329
		return this.modifyingText.put(language, LanguageString.NewInstance(text, language));
330
	}
331
	/** 
332
	 * Removes from the {@link MultilanguageText multilanguage text} used to qualify the validity
333
	 * of <i>this</i> description element the one {@link LanguageString language string}
334
	 * with the given {@link Language language}.
335
	 *
336
	 * @param  language	the language in which the language string to be removed
337
	 * 					has been formulated
338
	 * @see     		#getModifyingText()
339
	 */
340
	public LanguageString removeModifyingText(Language language){
341
		return this.modifyingText.remove(language);
342
	}
343

    
344
	/* (non-Javadoc)
345
	 * @see eu.etaxonomy.cdm.model.common.ISourceable#getSources()
346
	 */
347
	public Set<DescriptionElementSource> getSources() {
348
		return this.sources;		
349
	}
350
	
351
	/* (non-Javadoc)
352
	 * @see eu.etaxonomy.cdm.model.common.ISourceable#addSource(eu.etaxonomy.cdm.model.common.IOriginalSource)
353
	 */
354
	public void addSource(DescriptionElementSource source) {
355
		if (source != null){
356
			DescriptionElementBase oldSourcedObj = source.getSourcedObj();
357
			if (oldSourcedObj != null && oldSourcedObj != this){
358
				oldSourcedObj.getSources().remove(source);
359
			}
360
			this.sources.add(source);
361
			source.setSourcedObj(this);
362
		}
363
	}
364
	
365
	/* (non-Javadoc)
366
	 * @see eu.etaxonomy.cdm.model.common.ISourceable#addSource(java.lang.String, java.lang.String, eu.etaxonomy.cdm.model.reference.ReferenceBase, java.lang.String)
367
	 */
368
	public DescriptionElementSource addSource(String id, String idNamespace, ReferenceBase citation, String microCitation) {
369
		if (id == null && idNamespace == null && citation == null && microCitation == null){
370
			return null;
371
		}
372
		DescriptionElementSource source = DescriptionElementSource.NewInstance(id, idNamespace, citation, microCitation);
373
		addSource(source);
374
		return source;
375
	}
376
	
377
	public void addSource(String id, String idNamespace, ReferenceBase citation, String microReference, TaxonNameBase nameUsedInSource, String originalNameString){
378
		DescriptionElementSource newSource = DescriptionElementSource.NewInstance(id, idNamespace, citation, microReference, nameUsedInSource, originalNameString);
379
		addSource(newSource);
380
	}
381
	 
382
	/* (non-Javadoc)
383
	 * @see eu.etaxonomy.cdm.model.common.ISourceable#removeSource(eu.etaxonomy.cdm.model.common.IOriginalSource)
384
	 */
385
	public void removeSource(DescriptionElementSource source) {
386
		this.sources.remove(source);
387
	}
388

    
389
	
390
	/**
391
	 * Gets the citation micro reference of the first source. This method is deprecated and exists only to be compliant with version 2.0.
392
	 * It will be removed in v2.3
393
	 * @return
394
	 */
395
	@Transient
396
	@Deprecated
397
	public String getCitationMicroReference(){
398
		if (this.sources.size() < 1){
399
			return null;
400
		}else{
401
			return this.sources.iterator().next().getCitationMicroReference();
402
		}
403
	}
404
	
405
	/**
406
	 * Sets the citation micro reference of the first source. This method is deprecated and exists only to be compliant with version 2.0.
407
	 * It will be removed in v2.3
408
	 * If more than one source exists an IllegalStateException is thrown
409
	 **/
410
	@Transient
411
	@Deprecated
412
	public void setCitationMicroReference(String citationMicroReference){
413
		if (this.sources.size() < 1){
414
			ReferenceBase citation = null;
415
			this.addSource(DescriptionElementSource.NewInstance(null, null, citation, citationMicroReference));
416
		}else if (this.sources.size() > 1){
417
			throw new IllegalStateException("When adding a microcitation via the setCitationMicroReference method there must be only one source available");
418
		}else{
419
			this.sources.iterator().next().setCitationMicroReference(citationMicroReference);
420
		}
421
	}
422

    
423
	/**
424
	 * Gets the citation of the first source. This method is deprecated and exists only to be compliant with version 2.0.
425
	 * It will be removed in v2.3
426
	 */ 
427
	@Transient
428
	@Deprecated
429
	public ReferenceBase getCitation(){
430
		if (this.sources.size() < 1){
431
			return null;
432
		}else{
433
			return this.sources.iterator().next().getCitation();
434
		}
435
	}
436
	
437
	/**
438
	 * Sets the citation of the first source. This method is deprecated and exists only to be compliant with version 2.0.
439
	 * It will be removed in v2.3
440
	 * If more than one source exists an IllegalStateException is thrown
441
	 **/
442
	@Deprecated
443
	public void setCitation(ReferenceBase citation) {
444
		if (this.sources.size() < 1){
445
			this.addSource(DescriptionElementSource.NewInstance(null, null, citation, null));
446
		}else if (this.sources.size() > 1){
447
			throw new IllegalStateException("When adding a citation via the setCitation method there must be only one source available");
448
		}else{
449
			this.sources.iterator().next().setCitation(citation);
450
		}
451
	}
452
	
453
	
454
	/**
455
	 * Gets the original name string of the first source. This method is deprecated and exists only to be compliant with version 2.0.
456
	 * It will be removed in v2.3
457
	 * @return
458
	 */
459
	@Transient
460
	@Deprecated
461
	public String getOriginalNameString(){
462
		if (this.sources.size() < 1){
463
			return null;
464
		}else{
465
			return this.sources.iterator().next().getOriginalNameString();
466
		}
467
	}
468
	
469
	/**
470
	 * Sets the original name string of the first source. This method is deprecated and exists only to be compliant with version 2.0.
471
	 * It will be removed in v2.3
472
	 * If more than one source exists an IllegalStateException is thrown
473
	 **/
474
	@Transient
475
	@Deprecated
476
	public void setOriginalNameString(String originalNameString){
477
		if (this.sources.size() < 1){
478
			this.addSource(DescriptionElementSource.NewInstance(null, null, null, null, null, originalNameString));
479
		}else if (this.sources.size() > 1){
480
			throw new IllegalStateException("When adding a microcitation via the setCitationMicroReference method there must be only one source available");
481
		}else{
482
			this.sources.iterator().next().setOriginalNameString(originalNameString);
483
		}
484
	}
485
	
486

    
487
	/**
488
	 * Gets the name used in source of the first source. This method is deprecated and exists only to be compliant with version 2.0.
489
	 * It will be removed in v2.3
490
	 */ 
491
	@Transient
492
	@Deprecated
493
	public TaxonNameBase getNameUsedInReference(){
494
		if (this.sources.size() < 1){
495
			return null;
496
		}else{
497
			return this.sources.iterator().next().getNameUsedInSource();
498
		}
499
	}
500
	
501
	/**
502
	 * Sets the name used in reference of the first source. This method is deprecated and exists only to be compliant with version 2.0.
503
	 * It will be removed in v2.3
504
	 * If more than one source exists an IllegalStateException is thrown
505
	 **/
506
	@Deprecated
507
	public void setNameUsedInReference(TaxonNameBase nameUsedInSource) {
508
		if (this.sources.size() < 1){
509
			this.addSource(DescriptionElementSource.NewInstance(null, null, null, null, nameUsedInSource, null));
510
		}else if (this.sources.size() > 1){
511
			throw new IllegalStateException("When adding a citation via the setCitation method there must be only one source available");
512
		}else{
513
			this.sources.iterator().next().setNameUsedInSource(nameUsedInSource);
514
		}
515
	}
516

    
517
//************************** CLONE **********************************************************/	
518
	
519
	/** 
520
	 * Clones the description element. The element is <b>not</b> added to the same 
521
	 * description as the orginal element (inDescription is set to <code>null</null>.
522
	 * @see eu.etaxonomy.cdm.model.common.AnnotatableEntity#clone()
523
	 */
524
	@Override
525
	public Object clone() throws CloneNotSupportedException{
526
		DescriptionElementBase result = (DescriptionElementBase)super.clone();
527
		
528
		//Sources
529
		result.sources = new HashSet<DescriptionElementSource>();
530
		for (DescriptionElementSource source : getSources()){
531
			DescriptionElementSource newSource = (DescriptionElementSource)source.clone();
532
			result.addSource(newSource);
533
		}
534
		
535
		//inDescription
536
		result.inDescription = null;
537

    
538
		return result;
539
	}
540

    
541
	/** 
542
	 * Clones the description element.<BR> 
543
	 * The new element is added to the <code>description</code>.<BR>
544
	 * @see eu.etaxonomy.cdm.model.common.AnnotatableEntity#clone()
545
	 */
546
	public DescriptionElementBase clone(DescriptionBase description) throws CloneNotSupportedException{
547
		DescriptionElementBase result = (DescriptionElementBase)clone();
548
		description.addElement(result);
549
		return result;
550
	}
551

    
552
	
553
}
(5-5/36)