Project

General

Profile

Download (38.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.HashMap;
14
import java.util.HashSet;
15
import java.util.List;
16
import java.util.Map;
17
import java.util.Set;
18
import java.util.UUID;
19

    
20
import javax.persistence.Entity;
21
import javax.persistence.FetchType;
22
import javax.persistence.JoinColumn;
23
import javax.persistence.JoinTable;
24
import javax.persistence.ManyToMany;
25
import javax.persistence.OneToMany;
26
import javax.persistence.Transient;
27
import javax.xml.bind.annotation.XmlAccessType;
28
import javax.xml.bind.annotation.XmlAccessorType;
29
import javax.xml.bind.annotation.XmlElement;
30
import javax.xml.bind.annotation.XmlElementWrapper;
31
import javax.xml.bind.annotation.XmlIDREF;
32
import javax.xml.bind.annotation.XmlRootElement;
33
import javax.xml.bind.annotation.XmlSchemaType;
34
import javax.xml.bind.annotation.XmlType;
35

    
36
import org.apache.log4j.Logger;
37
import org.hibernate.annotations.Cascade;
38
import org.hibernate.annotations.CascadeType;
39
import org.hibernate.envers.Audited;
40

    
41
import eu.etaxonomy.cdm.model.common.DefinedTerm;
42
import eu.etaxonomy.cdm.model.common.DefinedTermBase;
43
import eu.etaxonomy.cdm.model.common.Language;
44
import eu.etaxonomy.cdm.model.common.Representation;
45
import eu.etaxonomy.cdm.model.common.TermType;
46
import eu.etaxonomy.cdm.model.common.TermVocabulary;
47
import eu.etaxonomy.cdm.model.name.BotanicalName;
48
import eu.etaxonomy.cdm.model.name.HybridRelationshipType;
49
import eu.etaxonomy.cdm.model.name.NomenclaturalCode;
50
import eu.etaxonomy.cdm.model.name.TaxonNameBase;
51
import eu.etaxonomy.cdm.model.taxon.Taxon;
52

    
53

    
54
/**
55
 * The class for individual properties (also designed as character, type or
56
 * category) of observed phenomena able to be described or measured. It also
57
 * covers categories of informations on {@link TaxonNameBase taxon names} not
58
 * taken in account in {@link NomenclaturalCode nomenclature}.<BR>
59
 * Descriptions require features in order to be structured and disaggregated
60
 * in {@link DescriptionElementBase description elements}.<BR>
61
 * Experts do not use the word feature for the actual description
62
 * but only for the property itself. Therefore naming this class FeatureType
63
 * would have leaded to confusion.
64
 * <P>
65
 * Since features are {@link DefinedTermBase defined terms} they have a hierarchical
66
 * structure that allows to specify ("kind of") or generalize
67
 * ("generalization of") features. "Kind of" / "generalization of" relations
68
 * are bidirectional (a feature F1 is a "Kind of" a feature F2 if and only
69
 * if the feature F2 is a "generalization of" the feature F1. This hierarchical
70
 * structure has nothing in common with {@link FeatureTree feature trees} used for determination.
71
 * <P>
72
 * A standard set of feature instances will be automatically
73
 * created as the project starts. But this class allows to extend this standard
74
 * set by creating new instances of additional features if needed.<BR>
75
 * <P>
76
 * This class corresponds to DescriptionsSectionType according to the SDD
77
 * schema.
78
 *
79
 * @author m.doering
80
 * @created 08-Nov-2007 13:06:24
81
 */
82
@XmlAccessorType(XmlAccessType.PROPERTY)
83
@XmlType(name="Feature", factoryMethod="NewInstance", propOrder = {
84
		"kindOf",
85
		"generalizationOf",
86
		"partOf",
87
		"includes",
88
	    "supportsTextData",
89
	    "supportsQuantitativeData",
90
	    "supportsDistribution",
91
	    "supportsIndividualAssociation",
92
	    "supportsTaxonInteraction",
93
	    "supportsCommonTaxonName",
94
	    "supportsCategoricalData",
95
	    "recommendedModifierEnumeration",
96
	    "recommendedStatisticalMeasures",
97
	    "supportedCategoricalEnumerations",
98
	    "recommendedMeasurementUnits",
99
	    "inverseRepresentations"
100
})
101
@XmlRootElement(name = "Feature")
102
@Entity
103
//@Indexed disabled to reduce clutter in indexes, since this type is not used by any search
104
//@Indexed(index = "eu.etaxonomy.cdm.model.common.DefinedTermBase")
105
@Audited
106
public class Feature extends DefinedTermBase<Feature> {
107
	private static final long serialVersionUID = 6754598791831848704L;
108
	private static final Logger logger = Logger.getLogger(Feature.class);
109

    
110
	protected static Map<UUID, Feature> termMap = null;
111

    
112
	private boolean supportsTextData = true;   //by default text data should be always supported
113

    
114
	private boolean supportsQuantitativeData;
115

    
116
	private boolean supportsDistribution;
117

    
118
	private boolean supportsIndividualAssociation;
119

    
120
	private boolean supportsTaxonInteraction;
121

    
122
	private boolean supportsCategoricalData;
123

    
124
	private boolean supportsCommonTaxonName;
125

    
126
    /* for M:M see #4843 */
127
	@ManyToMany(fetch = FetchType.LAZY)
128
    @JoinTable(name="DefinedTermBase_RecommendedModifierEnumeration")
129
	private final Set<TermVocabulary<DefinedTerm>> recommendedModifierEnumeration = new HashSet<TermVocabulary<DefinedTerm>>();
130

    
131
	@ManyToMany(fetch = FetchType.LAZY)
132
    @JoinTable(name="DefinedTermBase_StatisticalMeasure")
133
	private final Set<StatisticalMeasure> recommendedStatisticalMeasures = new HashSet<StatisticalMeasure>();
134

    
135
	/* for M:M see #4843 */
136
	@ManyToMany(fetch = FetchType.LAZY)
137
	@JoinTable(name="DefinedTermBase_SupportedCategoricalEnumeration")
138
	private final Set<TermVocabulary<State>> supportedCategoricalEnumerations = new HashSet<TermVocabulary<State>>();
139

    
140

    
141
	@ManyToMany(fetch = FetchType.LAZY)
142
    @JoinTable(name="DefinedTermBase_MeasurementUnit")
143
	private final Set<MeasurementUnit> recommendedMeasurementUnits = new HashSet<MeasurementUnit>();
144

    
145

    
146
    //copy from RelationshipTermBase
147
	@XmlElementWrapper(name = "InverseRepresentations")
148
    @XmlElement(name = "Representation")
149
    @OneToMany(fetch = FetchType.LAZY, orphanRemoval=true)
150
    @JoinTable(name="RelationshipTermBase_inverseRepresentation",
151
            joinColumns=@JoinColumn(name="relationshiptermbase_id")
152
    )
153
    @Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE, CascadeType.DELETE})
154
//    @IndexedEmbedded(depth = 2)
155
    private Set<Representation> inverseRepresentations = new HashSet<Representation>();
156

    
157
    private static final UUID uuidUnknown = UUID.fromString("910307f1-dc3c-452c-a6dd-af5ac7cd365c");
158
    public static final UUID uuidDescription = UUID.fromString("9087cdcd-8b08-4082-a1de-34c9ba9fb493");
159
    private static final UUID uuidDistribution = UUID.fromString("9fc9d10c-ba50-49ee-b174-ce83fc3f80c6");
160
    private static final UUID uuidEcology = UUID.fromString("aa923827-d333-4cf5-9a5f-438ae0a4746b");
161
    private static final UUID uuidHabitat = UUID.fromString("fb16929f-bc9c-456f-9d40-dec987b36438");
162
    private static final UUID uuidHabitatAndEcology = UUID.fromString("9fdc4663-4d56-47d0-90b5-c0bf251bafbb");
163
    private static final UUID uuidChromosomeNumber = UUID.fromString("6f677e98-d8d5-4bc5-80bf-affdb7e3945a");
164

    
165
    private static final UUID uuidBiologyEcology = UUID.fromString("9832e24f-b670-43b4-ac7c-20a7261a1d8c");
166
    private static final UUID uuidKey = UUID.fromString("a677f827-22b9-4205-bb37-11cb48dd9106");
167
    private static final UUID uuidMaterialsExamined = UUID.fromString("7c0c7571-a864-47c1-891d-01f59000dae1");
168
    private static final UUID uuidMaterialsMethods = UUID.fromString("1e87d9c3-0844-4a03-9686-773e2ccb3ab6");
169
    private static final UUID uuidEtymology = UUID.fromString("dd653d48-355c-4aec-a4e7-724f6eb29f8d");
170
    private static final UUID uuidDiagnosis = UUID.fromString("d43d8501-ceab-4caa-9e51-e87138528fac");
171
    private static final UUID uuidProtologue = UUID.fromString("71b356c5-1e3f-4f5d-9b0f-c2cf8ae7779f");
172
    public static final UUID uuidCommonName = UUID.fromString("fc810911-51f0-4a46-ab97-6562fe263ae5");
173
    private static final UUID uuidPhenology = UUID.fromString("a7786d3e-7c58-4141-8416-346d4c80c4a2");
174
    private static final UUID uuidOccurrence = UUID.fromString("5deff505-1a32-4817-9a74-50e6936fd630");
175
    private static final UUID uuidCitation = UUID.fromString("99b2842f-9aa7-42fa-bd5f-7285311e0101");
176
    private static final UUID uuidAdditionalPublication = UUID.fromString("2c355c16-cb04-4858-92bf-8da8d56dea95");
177
    public static final UUID uuidUses = UUID.fromString("e5374d39-b210-47c7-bec1-bee05b5f1cb6");
178
    private static final UUID uuidConservation = UUID.fromString("4518fc20-2492-47de-b345-777d2b83c9cf");
179
    private static final UUID uuidCultivation = UUID.fromString("e28965b2-a367-48c5-b954-8afc8ac2c69b");
180
    private static final UUID uuidIntroduction = UUID.fromString("e75255ca-8ff4-4905-baad-f842927fe1d3");
181
    private static final UUID uuidDiscussion = UUID.fromString("d3c4cbb6-0025-4322-886b-cd0156753a25");
182
    public static final UUID uuidImage = UUID.fromString("84193b2c-327f-4cce-90ef-c8da18fd5bb5");
183
    private static final UUID uuidAnatomy = UUID.fromString("94213b2c-e67a-4d37-25ef-e8d316edfba1");
184
    private static final UUID uuidHostPlant = UUID.fromString("6e9de1d5-05f0-40d5-8786-2fe30d0d894d");
185
    private static final UUID uuidPathogenAgent = UUID.fromString("002d05f2-fd72-49f1-ba4d-196cf09240b5");
186
    private static final UUID uuidIndividualsAssociation = UUID.fromString("e2308f37-ddc5-447d-b483-5e2171dd85fd");
187
    public static final UUID uuidSpecimen = UUID.fromString("8200e050-d5fd-4cac-8a76-4b47afb13809");
188
    private static final UUID uuidObservation = UUID.fromString("f59e747d-0b4f-4bf7-b69a-cbd50bc78595");
189
    private static final UUID uuidStatus = UUID.fromString("86d40635-2a63-4ad6-be75-9faa4a6a57fb");
190
    private static final UUID uuidSystematics = UUID.fromString("bd9aca17-cd0e-4418-a3a1-1a4b80dbc162");
191
    private static final UUID uuidUseRecord = UUID.fromString("8125a59d-b4d5-4485-89ea-67306297b599");
192
    private static final UUID uuidNotes = UUID.fromString("b5780b45-6439-4f3c-9818-d89d26d36eb2");
193

    
194

    
195
/* ***************** CONSTRUCTOR AND FACTORY METHODS **********************************/
196

    
197
	/**
198
	 * Class constructor: creates a new feature instance with a description (in the {@link Language#DEFAULT() default language}),
199
	 * a label and a label abbreviation.
200
	 *
201
	 * @param	term  		 the string (in the default language) describing the
202
	 * 						 new feature to be created
203
	 * @param	label  		 the string identifying the new feature to be created
204
	 * @param	labelAbbrev  the string identifying (in abbreviated form) the
205
	 * 						 new feature to be created
206
	 * @see 				 #Feature()
207
	 */
208
	protected Feature(String term, String label, String labelAbbrev) {
209
		super(TermType.Feature, term, label, labelAbbrev);
210
	}
211

    
212
	/**
213
	 * Creates a new empty feature instance.
214
	 *
215
	 * @see #NewInstance(String, String, String)
216
	 */
217
	public static Feature NewInstance() {
218
		return new Feature();
219
	}
220

    
221
	/**
222
	 * Creates a new feature instance with a description (in the {@link Language#DEFAULT() default language}),
223
	 * a label and a label abbreviation.
224
	 *
225
	 * @param	term  		 the string (in the default language) describing the
226
	 * 						 new feature to be created
227
	 * @param	label  		 the string identifying the new feature to be created
228
	 * @param	labelAbbrev  the string identifying (in abbreviated form) the
229
	 * 						 new feature to be created
230
	 * @see 				 #readCsvLine(List, Language)
231
	 * @see 				 #NewInstance()
232
	 */
233
	public static Feature NewInstance(String term, String label, String labelAbbrev){
234
		return new Feature(term, label, labelAbbrev);
235
	}
236

    
237

    
238
    //for hibernate use only
239
    @Deprecated
240
    protected Feature() {
241
        super(TermType.Feature);
242
    }
243

    
244
/* *************************************************************************************/
245

    
246
	@Override
247
	public void resetTerms(){
248
		termMap = null;
249
	}
250

    
251

    
252
	/**
253
	 * Returns the boolean value of the flag indicating whether <i>this</i>
254
	 * feature can be described with {@link QuantitativeData quantitative data} (true)
255
	 * or not (false). If this flag is set <i>this</i> feature can only apply to
256
	 * {@link TaxonDescription taxon descriptions} or {@link SpecimenDescription specimen descriptions}.
257
	 *
258
	 * @return  the boolean value of the supportsQuantitativeData flag
259
	 */
260
	@XmlElement(name = "SupportsQuantitativeData")
261
	public boolean isSupportsQuantitativeData() {
262
		return supportsQuantitativeData;
263
	}
264

    
265
	/**
266
	 * @see	#isSupportsQuantitativeData()
267
	 */
268
	public void setSupportsQuantitativeData(boolean supportsQuantitativeData) {
269
		this.supportsQuantitativeData = supportsQuantitativeData;
270
	}
271

    
272
	/**
273
	 * Returns the boolean value of the flag indicating whether <i>this</i>
274
	 * feature can be described with {@link TextData text data} (true)
275
	 * or not (false).
276
	 *
277
	 * @return  the boolean value of the supportsTextData flag
278
	 */
279
	@XmlElement(name = "SupportsTextData")
280
	public boolean isSupportsTextData() {
281
		return supportsTextData;
282
	}
283

    
284
	/**
285
	 * @see	#isSupportsTextData()
286
	 */
287
	public void setSupportsTextData(boolean supportsTextData) {
288
		this.supportsTextData = supportsTextData;
289
	}
290

    
291
	/**
292
	 * Returns the boolean value of the flag indicating whether <i>this</i>
293
	 * feature can be described with {@link Distribution distribution} objects
294
	 * (true) or not (false). This flag is set if and only if <i>this</i> feature
295
	 * is the {@link #DISTRIBUTION() distribution feature}.
296
	 *
297
	 * @return  the boolean value of the supportsDistribution flag
298
	 */
299
	@XmlElement(name = "SupportsDistribution")
300
	public boolean isSupportsDistribution() {
301
		return supportsDistribution;
302
	}
303

    
304
	/**
305
	 * @see	#isSupportsDistribution()
306
	 */
307
	public void setSupportsDistribution(boolean supportsDistribution) {
308
		this.supportsDistribution = supportsDistribution;
309
	}
310

    
311
	/**
312
	 * Returns the boolean value of the flag indicating whether <i>this</i>
313
	 * feature can be described with {@link IndividualsAssociation individuals associations}
314
	 * (true) or not (false).
315
	 *
316
	 * @return  the boolean value of the supportsIndividualAssociation flag
317
	 */
318
	@XmlElement(name = "SupportsIndividualAssociation")
319
	public boolean isSupportsIndividualAssociation() {
320
		return supportsIndividualAssociation;
321
	}
322

    
323
	/**
324
	 * @see	#isSupportsIndividualAssociation()
325
	 */
326
	public void setSupportsIndividualAssociation(
327
			boolean supportsIndividualAssociation) {
328
		this.supportsIndividualAssociation = supportsIndividualAssociation;
329
	}
330

    
331
	/**
332
	 * Returns the boolean value of the flag indicating whether <i>this</i>
333
	 * feature can be described with {@link TaxonInteraction taxon interactions}
334
	 * (true) or not (false).
335
	 *
336
	 * @return  the boolean value of the supportsTaxonInteraction flag
337
	 */
338
	@XmlElement(name = "SupportsTaxonInteraction")
339
	public boolean isSupportsTaxonInteraction() {
340
		return supportsTaxonInteraction;
341
	}
342

    
343
	/**
344
	 * @see	#isSupportsTaxonInteraction()
345
	 */
346
	public void setSupportsTaxonInteraction(boolean supportsTaxonInteraction) {
347
		this.supportsTaxonInteraction = supportsTaxonInteraction;
348
	}
349

    
350
	/**
351
	 * Returns the boolean value of the flag indicating whether <i>this</i>
352
	 * feature can be described with {@link CommonTaxonName common names}
353
	 * (true) or not (false). This flag is set if and only if <i>this</i> feature
354
	 * is the {@link #COMMON_NAME() common name feature}.
355
	 *
356
	 * @return  the boolean value of the supportsCommonTaxonName flag
357
	 */
358
	@XmlElement(name = "SupportsCommonTaxonName")
359
	public boolean isSupportsCommonTaxonName() {
360
		return supportsCommonTaxonName;
361
	}
362

    
363
	/**
364
	 * @see	#isSupportsTaxonInteraction()
365
	 */
366
	public void setSupportsCommonTaxonName(boolean supportsCommonTaxonName) {
367
		this.supportsCommonTaxonName = supportsCommonTaxonName;
368
	}
369

    
370
	/**
371
	 * Returns the boolean value of the flag indicating whether <i>this</i>
372
	 * feature can be described with {@link CategoricalData categorical data}
373
	 * (true) or not (false).
374
	 *
375
	 * @return  the boolean value of the supportsCategoricalData flag
376
	 */
377
	@XmlElement(name = "SupportsCategoricalData")
378
	public boolean isSupportsCategoricalData() {
379
		return supportsCategoricalData;
380
	}
381

    
382
	/**
383
	 * @see	#supportsCategoricalData()
384
	 */
385
	public void setSupportsCategoricalData(boolean supportsCategoricalData) {
386
		this.supportsCategoricalData = supportsCategoricalData;
387
	}
388

    
389

    
390
	/**
391
	 * Returns the set of {@link TermVocabulary term vocabularies} containing the
392
	 * {@link Modifier modifiers} recommended to be used for {@link DescriptionElementBase description elements}
393
	 * with <i>this</i> feature.
394
	 *
395
	 */
396
	@XmlElementWrapper(name = "RecommendedModifierEnumerations")
397
	@XmlElement(name = "RecommendedModifierEnumeration")
398
	@XmlIDREF
399
	@XmlSchemaType(name = "IDREF")
400
	public Set<TermVocabulary<DefinedTerm>> getRecommendedModifierEnumeration() {
401
		return recommendedModifierEnumeration;
402
	}
403

    
404
	/**
405
	 * Adds a {@link TermVocabulary term vocabulary} (with {@link Modifier modifiers}) to the set of
406
	 * {@link #getRecommendedModifierEnumeration() recommended modifier vocabularies} assigned
407
	 * to <i>this</i> feature.
408
	 *
409
	 * @param recommendedModifierEnumeration	the term vocabulary to be added
410
	 * @see    	   								#getRecommendedModifierEnumeration()
411
	 */
412
	public void addRecommendedModifierEnumeration(
413
			TermVocabulary<DefinedTerm> recommendedModifierEnumeration) {
414
		this.recommendedModifierEnumeration.add(recommendedModifierEnumeration);
415
	}
416
	/**
417
	 * Removes one element from the set of {@link #getRecommendedModifierEnumeration() recommended modifier vocabularies}
418
	 * assigned to <i>this</i> feature.
419
	 *
420
	 * @param  recommendedModifierEnumeration	the term vocabulary which should be removed
421
	 * @see     								#getRecommendedModifierEnumeration()
422
	 * @see     								#addRecommendedModifierEnumeration(TermVocabulary)
423
	 */
424
	public void removeRecommendedModifierEnumeration(
425
			TermVocabulary<DefinedTerm> recommendedModifierEnumeration) {
426
		this.recommendedModifierEnumeration.remove(recommendedModifierEnumeration);
427
	}
428

    
429
	/**
430
	 * Returns the set of {@link StatisticalMeasure statistical measures} recommended to be used
431
	 * in case of {@link QuantitativeData quantitative data} with <i>this</i> feature.
432
	 */
433
	@XmlElementWrapper(name = "RecommendedStatisticalMeasures")
434
	@XmlElement(name = "RecommendedStatisticalMeasure")
435
	@XmlIDREF
436
	@XmlSchemaType(name = "IDREF")
437
	public Set<StatisticalMeasure> getRecommendedStatisticalMeasures() {
438
		return recommendedStatisticalMeasures;
439
	}
440

    
441
	/**
442
	 * Adds a {@link StatisticalMeasure statistical measure} to the set of
443
	 * {@link #getRecommendedStatisticalMeasures() recommended statistical measures} assigned
444
	 * to <i>this</i> feature.
445
	 *
446
	 * @param recommendedStatisticalMeasure	the statistical measure to be added
447
	 * @see    	   							#getRecommendedStatisticalMeasures()
448
	 */
449
	public void addRecommendedStatisticalMeasure(
450
			StatisticalMeasure recommendedStatisticalMeasure) {
451
		this.recommendedStatisticalMeasures.add(recommendedStatisticalMeasure);
452
	}
453
	/**
454
	 * Removes one element from the set of {@link #getRecommendedStatisticalMeasures() recommended statistical measures}
455
	 * assigned to <i>this</i> feature.
456
	 *
457
	 * @param  recommendedStatisticalMeasure	the statistical measure which should be removed
458
	 * @see     								#getRecommendedStatisticalMeasures()
459
	 * @see     								#addRecommendedStatisticalMeasure(StatisticalMeasure)
460
	 */
461
	public void removeRecommendedStatisticalMeasure(
462
			StatisticalMeasure recommendedStatisticalMeasure) {
463
		this.recommendedStatisticalMeasures.remove(recommendedStatisticalMeasure);
464
	}
465

    
466
	/**
467
	 * Returns the set of {@link StatisticalMeasure statistical measures} recommended to be used
468
	 * in case of {@link QuantitativeData quantitative data} with <i>this</i> feature.
469
	 */
470
	@XmlElementWrapper(name = "RecommendedMeasurementUnits")
471
	@XmlElement(name = "RecommendedMeasurementUnit")
472
	@XmlIDREF
473
	@XmlSchemaType(name = "IDREF")
474
	public Set<MeasurementUnit> getRecommendedMeasurementUnits() {
475
		return recommendedMeasurementUnits;
476
	}
477

    
478
	/**
479
	 * Adds a {@link StatisticalMeasure statistical measure} to the set of
480
	 * {@link #getRecommendedStatisticalMeasures() recommended statistical measures} assigned
481
	 * to <i>this</i> feature.
482
	 *
483
	 * @param recommendedStatisticalMeasure	the statistical measure to be added
484
	 * @see    	   							#getRecommendedStatisticalMeasures()
485
	 */
486
	public void addRecommendedMeasurementUnit(
487
			MeasurementUnit recommendedMeasurementUnit) {
488
		this.recommendedMeasurementUnits.add(recommendedMeasurementUnit);
489
	}
490
	/**
491
	 * Removes one element from the set of {@link #getRecommendedStatisticalMeasures() recommended statistical measures}
492
	 * assigned to <i>this</i> feature.
493
	 *
494
	 * @param  recommendedStatisticalMeasure	the statistical measure which should be removed
495
	 * @see     								#getRecommendedStatisticalMeasures()
496
	 * @see     								#addRecommendedStatisticalMeasure(StatisticalMeasure)
497
	 */
498
	public void removeRecommendedMeasurementUnit(
499
			MeasurementUnit recommendedMeasurementUnit) {
500
		this.recommendedMeasurementUnits.remove(recommendedMeasurementUnit);
501
	}
502

    
503
	/**
504
	 * Returns the set of {@link TermVocabulary term vocabularies} containing the list of
505
	 * possible {@link State states} to be used in {@link CategoricalData categorical data}
506
	 * with <i>this</i> feature.
507
	 *
508
	 */
509
	@XmlElementWrapper(name = "SupportedCategoricalEnumerations")
510
	@XmlElement(name = "SupportedCategoricalEnumeration")
511
	@XmlIDREF
512
	@XmlSchemaType(name = "IDREF")
513
	public Set<TermVocabulary<State>> getSupportedCategoricalEnumerations() {
514
		return supportedCategoricalEnumerations;
515
	}
516

    
517
	/**
518
	 * Adds a {@link TermVocabulary term vocabulary} to the set of
519
	 * {@link #getSupportedCategoricalEnumerations() supported state vocabularies} assigned
520
	 * to <i>this</i> feature.
521
	 *
522
	 * @param supportedCategoricalEnumeration	the term vocabulary which should be removed
523
	 * @see    	   								#getSupportedCategoricalEnumerations()
524
	 */
525
	public void addSupportedCategoricalEnumeration(
526
			TermVocabulary<State> supportedCategoricalEnumeration) {
527
		this.supportedCategoricalEnumerations.add(supportedCategoricalEnumeration);
528
	}
529
	/**
530
	 * Removes one element from the set of {@link #getSupportedCategoricalEnumerations() supported state vocabularies}
531
	 * assigned to <i>this</i> feature.
532
	 *
533
	 * @param  supportedCategoricalEnumeration	the term vocabulary which should be removed
534
	 * @see     								#getSupportedCategoricalEnumerations()
535
	 * @see     								#addSupportedCategoricalEnumeration(TermVocabulary)
536
	 */
537
	public void removeSupportedCategoricalEnumeration(
538
			TermVocabulary<State> supportedCategoricalEnumeration) {
539
		this.supportedCategoricalEnumerations.remove(supportedCategoricalEnumeration);
540
	}
541

    
542
	@XmlElement(name = "KindOf", namespace = "http://etaxonomy.eu/cdm/model/common/1.0")
543
    @XmlIDREF
544
    @XmlSchemaType(name = "IDREF")
545
    @Override
546
	public Feature getKindOf(){
547
		return super.getKindOf();
548
	}
549

    
550
	@Override
551
    public void setKindOf(Feature kindOf){
552
		super.setKindOf(kindOf);
553
	}
554

    
555
	@Override
556
    @XmlElement(name = "PartOf", namespace = "http://etaxonomy.eu/cdm/model/common/1.0")
557
	@XmlIDREF
558
    @XmlSchemaType(name = "IDREF")
559
	public Feature getPartOf(){
560
		return super.getPartOf();
561
	}
562

    
563
	@Override
564
    public void setPartOf(Feature partOf){
565
		super.setPartOf(partOf);
566
	}
567

    
568
	@Override
569
    @XmlElementWrapper(name = "Generalizations", namespace = "http://etaxonomy.eu/cdm/model/common/1.0")
570
	@XmlElement(name = "GeneralizationOf", namespace = "http://etaxonomy.eu/cdm/model/common/1.0")
571
    @XmlIDREF
572
    @XmlSchemaType(name = "IDREF")
573
	public Set<Feature> getGeneralizationOf(){
574
		return super.getGeneralizationOf();
575
	}
576

    
577
	@Override
578
    protected void setGeneralizationOf(Set<Feature> value){
579
		super.setGeneralizationOf(value);
580
	}
581

    
582
	@Override
583
    @XmlElementWrapper(name = "Includes", namespace = "http://etaxonomy.eu/cdm/model/common/1.0")
584
	@XmlElement(name = "Include", namespace = "http://etaxonomy.eu/cdm/model/common/1.0")
585
	@XmlIDREF
586
    @XmlSchemaType(name = "IDREF")
587
	public Set<Feature> getIncludes(){
588
		return super.getIncludes();
589
	}
590

    
591
	@Override
592
    protected void setIncludes(Set<Feature> includes) {
593
		super.setIncludes(includes);
594
	}
595

    
596
// ***************** Invers Label *****************************************/
597

    
598
	public Set<Representation> getInverseRepresentations() {
599
        return inverseRepresentations;
600
    }
601
    public void addInverseRepresentation(Representation inverseRepresentation) {
602
        this.inverseRepresentations.add(inverseRepresentation);
603
    }
604
    public void removeInverseRepresentation(Representation inverseRepresentation) {
605
        this.inverseRepresentations.remove(inverseRepresentation);
606
    }
607
    /*
608
     * Inverse representation convenience methods similar to TermBase.xxx
609
     * @see eu.etaxonomy.cdm.model.common.TermBase#getLabel()
610
     */
611
    @Transient
612
    public String getInverseLabel() {
613
        if(getInverseLabel(Language.DEFAULT()) != null){
614
            return this.getInverseRepresentation(Language.DEFAULT()).getLabel();
615
        }else{
616
            for (Representation r : inverseRepresentations){
617
                return r.getLabel();
618
            }
619
        }
620
        return super.getUuid().toString();
621
    }
622
    public String getInverseLabel(Language lang) {
623
        Representation r = this.getInverseRepresentation(lang);
624
        if(r==null){
625
            return null;
626
        }else{
627
            return r.getLabel();
628
        }
629
    }
630
    public Representation getInverseRepresentation(Language lang) {
631
        Representation result = null;
632
        for (Representation repr : this.getInverseRepresentations()){
633
            if (lang.equals(repr.getLanguage())){
634
                result = repr;
635
            }
636
        }
637
        return result;
638
    }
639
// ****************** END INVERS REPRESENTATION **************************/
640

    
641
	/**
642
	 * Creates and returns a new feature instance on the basis of a given string
643
	 * list (containing an UUID, an URI, a label and a description) and a given
644
	 * {@link Language language} to be associated with the description. Furthermore
645
	 * the flags concerning the supported subclasses of {@link DescriptionElementBase description elements}
646
	 * are set according to a particular string belonging to the given
647
	 * string list.<BR>
648
	 * This method overrides the readCsvLine method from {@link DefinedTermBase#readCsvLine(List, Language) DefinedTermBase}.
649
	 *
650
	 * @param  csvLine	the string list with elementary information for attributes
651
	 * @param  lang		the language in which the description has been formulated
652
	 * @see     		#NewInstance(String, String, String)
653
	 */
654
	@Override
655
	public Feature readCsvLine(Class<Feature> termClass, List<String> csvLine, Map<UUID,DefinedTermBase> terms, boolean abbrevAsId) {
656
		Feature newInstance = super.readCsvLine(termClass, csvLine, terms, abbrevAsId);
657
		String text = csvLine.get(4);
658
		if (text != null && text.length() >= 6){
659
			if ("1".equals(text.substring(0, 1))){newInstance.setSupportsTextData(true);};
660
			if ("1".equals(text.substring(1, 2))){newInstance.setSupportsQuantitativeData(true);};
661
			if ("1".equals(text.substring(2, 3))){newInstance.setSupportsDistribution(true);};
662
			if ("1".equals(text.substring(3, 4))){newInstance.setSupportsIndividualAssociation(true);};
663
			if ("1".equals(text.substring(4, 5))){newInstance.setSupportsTaxonInteraction(true);};
664
			if ("1".equals(text.substring(5, 6))){newInstance.setSupportsCommonTaxonName(true);};
665
			// if ("1".equals(text.substring(6, 7))){newInstance.setSupportsCategoricalData(true);};
666
			//there is no abbreviated label for features yet, if there is one in future we need to increment the index for supportXXX form 4 to 5
667
			newInstance.getRepresentation(Language.DEFAULT()).setAbbreviatedLabel(null);
668
		}
669
		return newInstance;
670
	}
671

    
672
//******************************* STATIC METHODS *****************************************
673

    
674
	protected static Feature getTermByUuid(UUID uuid){
675
	    if (termMap == null || termMap.isEmpty()){
676
            return getTermByClassAndUUID(Feature.class, uuid);
677
        } else {
678
			return termMap.get(uuid);
679
        }
680
	}
681

    
682
	/**
683
	 * Returns the "unknown" feature. This feature allows to store values of
684
	 * {@link DescriptionElementBase description elements} even if it is momentarily
685
	 * not known what they mean.
686
	 */
687
	public static final Feature UNKNOWN(){
688
		return getTermByUuid(uuidUnknown);
689
	}
690

    
691
	/**
692
	 * Returns the "description" feature. This feature allows to handle global
693
	 * {@link DescriptionElementBase description elements} for a global {@link DescriptionBase description}.<BR>
694
	 * The "description" feature is the highest level feature.
695
	 */
696
	public static final Feature DESCRIPTION(){
697
		return getTermByUuid(uuidDescription);
698
	}
699

    
700
	/**
701
	 * Returns the "distribution" feature. This feature allows to handle only
702
	 * {@link Distribution distributions}.
703
	 *
704
	 * @see	#isSupportsDistribution()
705
	 */
706
	public static final Feature DISTRIBUTION(){
707
		return getTermByUuid(uuidDistribution);
708
	}
709

    
710
	/**
711
	 * Returns the "discussion" feature. This feature can only be described
712
	 * with {@link TextData text data}.
713
	 *
714
	 * @see	#isSupportsTextData()
715
	 */
716
	public static final Feature DISCUSSION(){
717
		return getTermByUuid(uuidDiscussion);
718
	}
719

    
720
	/**
721
	 * Returns the "ecology" feature. This feature only applies
722
	 * to {@link SpecimenDescription specimen descriptions} or to {@link TaxonDescription taxon descriptions}.<BR>
723
	 * The "ecology" feature generalizes all other possible features concerning
724
	 * ecological matters.
725
	 */
726
	public static final Feature ECOLOGY(){
727
		return getTermByUuid(uuidEcology);
728
	}
729

    
730
	/**
731
	 * Returns the "habitat" feature. This feature only applies
732
	 * to {@link SpecimenDescription specimen descriptions} or to {@link TaxonDescription taxon descriptions}.<BR>
733
	 * The "habitat" feature generalizes all other possible features concerning
734
	 * habitat matters.
735
	 */
736
	public static final Feature HABITAT(){
737
		return getTermByUuid(uuidHabitat);
738
	}
739

    
740

    
741
	/**
742
	 * Returns the "habitat & ecology" feature. This feature only applies
743
	 * to {@link SpecimenDescription specimen descriptions} or to {@link TaxonDescription taxon descriptions}.<BR>
744
	 * The "habitat & ecology" feature generalizes all other possible features concerning
745
	 * habitat and ecology matters.
746
	 */
747
	public static final Feature HABITAT_ECOLOGY(){
748
		return getTermByUuid(uuidHabitatAndEcology);
749
	}
750

    
751
	/**
752
	 * Returns the "biology_ecology" feature. This feature only applies
753
	 * to {@link SpecimenDescription specimen descriptions} or to {@link TaxonDescription taxon descriptions}.<BR>
754
	 * The "biology_ecology" feature generalizes all possible features concerning
755
	 * biological aspects of ecological matters.
756
	 *
757
	 * @see #ECOLOGY()
758
	 */
759
	public static final Feature BIOLOGY_ECOLOGY(){
760
		return getTermByUuid(uuidBiologyEcology);
761
	}
762

    
763
	/**
764
	 * Returns the "chromosome number" feature. This feature only applies
765
	 * to {@link SpecimenDescription specimen descriptions} or to {@link TaxonDescription taxon descriptions}.<BR>
766
	 */
767
	public static final Feature CHROMOSOME_NUMBER(){
768
		return getTermByUuid(uuidChromosomeNumber);
769
	}
770

    
771

    
772
	/**
773
	 * Returns the "key" feature. This feature is the "upper" feature generalizing
774
	 * all features being used within an identification key.
775
	 */
776
	public static final Feature KEY(){
777
		return getTermByUuid(uuidKey);
778
	}
779

    
780

    
781
	/**
782
	 * Returns the "materials_examined" feature. This feature can only be described
783
	 * with {@link TextData text data} or eventually with {@link CategoricalData categorical data}
784
	 * mentioning which material has been examined in order to accomplish
785
	 * the description. This feature applies only to
786
	 * {@link SpecimenDescription specimen descriptions} or to {@link TaxonDescription taxon descriptions}.
787
	 */
788
	public static final Feature MATERIALS_EXAMINED(){
789
		return getTermByUuid(uuidMaterialsExamined);
790
	}
791

    
792
	/**
793
	 * Returns the "materials_methods" feature. This feature can only be described
794
	 * with {@link TextData text data} or eventually with {@link CategoricalData categorical data}
795
	 * mentioning which methods have been adopted to analyze the material in
796
	 * order to accomplish the description. This feature applies only to
797
	 * {@link SpecimenDescription specimen descriptions} or to {@link TaxonDescription taxon descriptions}.
798
	 */
799
	public static final Feature MATERIALS_METHODS(){
800
		return getTermByUuid(uuidMaterialsMethods);
801
	}
802

    
803
	/**
804
	 * Returns the "etymology" feature. This feature can only be described
805
	 * with {@link TextData text data} or eventually with {@link CategoricalData categorical data}
806
	 * giving some information about the history of the taxon name. This feature applies only to
807
	 * {@link TaxonNameDescription taxon name descriptions}.
808
	 */
809
	public static final Feature ETYMOLOGY(){
810
		return getTermByUuid(uuidEtymology);
811
	}
812

    
813
	/**
814
	 * Returns the "diagnosis" feature. This feature can only be described
815
	 * with {@link TextData text data} or eventually with {@link CategoricalData categorical data}.
816
	 * This feature applies only to {@link SpecimenDescription specimen descriptions} or to
817
	 * {@link TaxonDescription taxon descriptions}.
818
	 */
819
	public static final Feature DIAGNOSIS(){
820
		return getTermByUuid(uuidDiagnosis);
821
	}
822

    
823

    
824
	/**
825
	 * Returns the "introduction" feature. This feature can only be described
826
	 * with {@link TextData text data}.
827
	 *
828
	 * @see	#isSupportsTextData()
829
	 */
830
	public static final Feature INTRODUCTION(){
831
		return getTermByUuid(uuidIntroduction);
832
	}
833

    
834
	/**
835
	 * Returns the "protologue" feature. This feature can only be described
836
	 * with {@link TextData text data} reproducing the content of the protologue
837
	 * (or some information about it) of the taxon name. This feature applies only to
838
	 * {@link TaxonNameDescription taxon name descriptions}.
839
	 *
840
	 * @see	#isSupportsTextData()
841
	 */
842
	public static final Feature PROTOLOGUE(){
843
		return getTermByUuid(uuidProtologue);
844
	}
845

    
846
	/**
847
	 * Returns the "common_name" feature. This feature allows to handle only
848
	 * {@link CommonTaxonName common names}.
849
	 *
850
	 * @see	#isSupportsCommonTaxonName()
851
	 */
852
	public static final Feature COMMON_NAME(){
853
		return getTermByUuid(uuidCommonName);
854
	}
855

    
856
	/**
857
	 * Returns the "phenology" feature. This feature can only be described
858
	 * with {@link CategoricalData categorical data} or eventually with {@link TextData text data}
859
	 * containing information time about recurring natural phenomena.
860
	 * This feature only applies to {@link TaxonDescription taxon descriptions}.<BR>
861
	 * The "phenology" feature generalizes all other possible features
862
	 * concerning time information about particular natural phenomena
863
	 * (such as "first flight of butterflies").
864
	 */
865
	public static final Feature PHENOLOGY(){
866
		return getTermByUuid(uuidPhenology);
867
	}
868

    
869
	/**
870
	 * Returns the "occurrence" feature.
871
	 */
872
	public static final Feature OCCURRENCE(){
873
		return getTermByUuid(uuidOccurrence);
874
	}
875

    
876
	/**
877
	 * Returns the "anatomy" feature.
878
	 */
879
	public static final Feature ANATOMY(){
880
		return getTermByUuid(uuidAnatomy);
881
	}
882
	/**
883
	 * Returns the "hostplant" feature.
884
	 */
885
	public static final Feature HOSTPLANT(){
886
		return getTermByUuid(uuidHostPlant);
887
	}
888
	/**
889
	 * Returns the "pathogen agent" feature.
890
	 */
891
	public static final Feature PATHOGEN_AGENT(){
892
		return getTermByUuid(uuidPathogenAgent);
893
	}
894

    
895
	/**
896
	 * Returns the "citation" feature. This feature can only be described
897
	 * with {@link TextData text data}.
898
	 *
899
	 * @see	#isSupportsTextData()
900
	 */
901
	public static final Feature CITATION(){
902
		return getTermByUuid(uuidCitation);
903
	}
904

    
905
	/**
906
	 * Returns the "additional_publication" feature. This feature can only be
907
	 * described with {@link TextData text data} with information about a
908
	 * publication where a {@link TaxonNameBase taxon name} has also been published
909
	 * but which is not the {@link TaxonNameBase#getNomenclaturalReference() nomenclatural reference}.
910
	 * This feature applies only to {@link TaxonNameDescription taxon name descriptions}.
911
	 *
912
	 * @see	#isSupportsTextData()
913
	 */
914
	public static final Feature ADDITIONAL_PUBLICATION(){
915
		return getTermByUuid(uuidAdditionalPublication);
916
	}
917

    
918

    
919
	/**
920
	 * Returns the "uses" feature. This feature only applies
921
	 * to {@link TaxonDescription taxon descriptions}.<BR>
922
	 * The "uses" feature generalizes all other possible features concerning
923
	 * particular uses (for instance "industrial use of seeds").
924
	 */
925
	public static final Feature USES(){
926
		return getTermByUuid(uuidUses);
927
	}
928

    
929
	public static final Feature USERECORD(){
930
		return getTermByUuid(uuidUseRecord);
931
	}
932

    
933
    /**
934
     * Returns the "notes" feature. Used for
935
     * taxonomic notes.
936
     */
937
    public static final Feature NOTES(){
938
        return getTermByUuid(uuidNotes);
939
    }
940

    
941
	/**
942
	 * Returns the "conservation" feature. This feature only applies
943
	 * to {@link SpecimenDescription specimen descriptions} and generalizes
944
	 * methods and conditions for the conservation of {@link Specimen specimens}.<BR>
945
	 */
946
	public static final Feature CONSERVATION(){
947
		return getTermByUuid(uuidConservation);
948
	}
949

    
950

    
951
	/**
952
	 * Returns the "cultivation" feature.
953
	 */
954
	public static final Feature CULTIVATION(){
955
		return getTermByUuid(uuidCultivation);
956
	}
957

    
958

    
959
	/**
960
	 * Returns the "image" feature.
961
	 */
962
	public static final Feature IMAGE(){
963
		return getTermByUuid(uuidImage);
964
	}
965

    
966
	/**
967
	 * Returns the "individuals association" feature.
968
	 */
969
	public static final Feature INDIVIDUALS_ASSOCIATION(){
970
		Feature individuals_association =  getTermByUuid(uuidIndividualsAssociation);
971
		Set<Feature> generalizationOf = new HashSet<Feature>();
972
		generalizationOf.add(SPECIMEN());
973
		generalizationOf.add(OBSERVATION());
974
		individuals_association.setGeneralizationOf(generalizationOf);
975
		return individuals_association;
976

    
977
	}
978

    
979
	public static final Feature SPECIMEN(){
980
		return getTermByUuid(uuidSpecimen);
981
	}
982

    
983
	public static final Feature OBSERVATION(){
984
		return getTermByUuid(uuidObservation);
985
	}
986

    
987
	/**
988
	 * The status of a taxon. Usually the status should be determined within a {@link Distribution distribution}.
989
	 * If this is not possible for some reason (e.g. the area is not well defined) the status feature
990
	 * may be used.
991
	 * @return
992
	 */
993
	public static final Feature STATUS(){
994
		return getTermByUuid(uuidStatus);
995
	}
996

    
997
	public static final Feature SYSTEMATICS(){
998
		return getTermByUuid(uuidSystematics);
999
	}
1000

    
1001
	/**
1002
	 * Returns the "hybrid_parent" feature. This feature can only be used
1003
	 * by {@link TaxonInteraction taxon interactions}.<BR>
1004
	 * <P>
1005
	 * Note: It must be distinguished between hybrid relationships as
1006
	 * relevant nomenclatural relationships between {@link BotanicalName plant names}
1007
	 * on the one side and the biological relation between two {@link Taxon taxa}
1008
	 * as it is here the case on the other one.
1009
	 *
1010
	 * @see	#isSupportsTaxonInteraction()
1011
	 * @see	HybridRelationshipType
1012
	 */
1013
	public static final Feature HYBRID_PARENT(){
1014
		//TODO
1015
		logger.warn("HYBRID_PARENT not yet implemented");
1016
		return null;
1017
	}
1018

    
1019
	@Override
1020
	protected void setDefaultTerms(TermVocabulary<Feature> termVocabulary) {
1021
		if (termMap == null){  //needed because there are multiple feature vocabularies
1022
			termMap = new HashMap<UUID, Feature>();
1023
		}
1024
		for (Feature term : termVocabulary.getTerms()){
1025
			termMap.put(term.getUuid(), term);
1026
		}
1027
	}
1028

    
1029
//*********************************** CLONE *********************************************************/
1030

    
1031
    @Override
1032
    public Object clone() {
1033
        Feature result = (Feature)super.clone();
1034

    
1035
        result.inverseRepresentations = new HashSet<Representation>();
1036
        for (Representation rep: this.inverseRepresentations){
1037
            result.addInverseRepresentation((Representation)rep.clone());
1038
        }
1039

    
1040
        //no changes to: symmetric, transitiv
1041
        return result;
1042
    }
1043

    
1044
}
(8-8/36)