Project

General

Profile

Download (38.9 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.Language;
42
import eu.etaxonomy.cdm.model.name.HybridRelationshipType;
43
import eu.etaxonomy.cdm.model.name.NomenclaturalCode;
44
import eu.etaxonomy.cdm.model.name.TaxonName;
45
import eu.etaxonomy.cdm.model.taxon.Taxon;
46
import eu.etaxonomy.cdm.model.term.DefinedTerm;
47
import eu.etaxonomy.cdm.model.term.DefinedTermBase;
48
import eu.etaxonomy.cdm.model.term.FeatureTree;
49
import eu.etaxonomy.cdm.model.term.Representation;
50
import eu.etaxonomy.cdm.model.term.TermType;
51
import eu.etaxonomy.cdm.model.term.TermVocabulary;
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 TaxonName 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
 * @since 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.term.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<>();
130

    
131
	@ManyToMany(fetch = FetchType.LAZY)
132
    @JoinTable(name="DefinedTermBase_StatisticalMeasure")
133
	private final Set<StatisticalMeasure> recommendedStatisticalMeasures = new HashSet<>();
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<>();
139

    
140

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

    
145

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

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

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

    
197

    
198
/* ***************** CONSTRUCTOR AND FACTORY METHODS **********************************/
199

    
200

    
201
	/**
202
	 * Creates a new empty feature instance.
203
	 *
204
	 * @see #NewInstance(String, String, String)
205
	 */
206
	public static Feature NewInstance() {
207
		return new Feature();
208
	}
209

    
210
	/**
211
	 * Creates a new feature instance with a description (in the {@link Language#DEFAULT() default language}),
212
	 * a label and a label abbreviation.
213
	 *
214
	 * @param	description      the string (in the default language) describing the
215
	 * 						 new feature to be created
216
	 * @param	label  		 the string identifying the new feature to be created
217
	 * @param	labelAbbrev      the string identifying (in abbreviated form) the
218
	 * 						 new feature to be created
219
	 * @see 				 #readCsvLine(List, Language)
220
	 * @see 				 #NewInstance()
221
	 */
222
	public static Feature NewInstance(String description, String label, String labelAbbrev){
223
		return new Feature(description, label, labelAbbrev);
224
	}
225

    
226

    
227
    //for hibernate use only
228
    @Deprecated
229
    protected Feature() {
230
        super(TermType.Feature);
231
    }
232

    
233
    /**
234
     * Class constructor: creates a new feature instance with a description (in the {@link Language#DEFAULT() default language}),
235
     * a label and a label abbreviation.
236
     *
237
     * @param   term         the string (in the default language) describing the
238
     *                       new feature to be created
239
     * @param   label        the string identifying the new feature to be created
240
     * @param   labelAbbrev  the string identifying (in abbreviated form) the
241
     *                       new feature to be created
242
     * @see                  #Feature()
243
     */
244
    protected Feature(String term, String label, String labelAbbrev) {
245
        super(TermType.Feature, term, label, labelAbbrev);
246
    }
247

    
248
/* *************************************************************************************/
249

    
250
	@Override
251
	public void resetTerms(){
252
		termMap = null;
253
	}
254

    
255

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

    
269
	/**
270
	 * @see	#isSupportsQuantitativeData()
271
	 */
272
	public void setSupportsQuantitativeData(boolean supportsQuantitativeData) {
273
		this.supportsQuantitativeData = supportsQuantitativeData;
274
	}
275

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

    
288
	/**
289
	 * @see	#isSupportsTextData()
290
	 */
291
	public void setSupportsTextData(boolean supportsTextData) {
292
		this.supportsTextData = supportsTextData;
293
	}
294

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

    
308
	/**
309
	 * @see	#isSupportsDistribution()
310
	 */
311
	public void setSupportsDistribution(boolean supportsDistribution) {
312
		this.supportsDistribution = supportsDistribution;
313
	}
314

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

    
327
	/**
328
	 * @see	#isSupportsIndividualAssociation()
329
	 */
330
	public void setSupportsIndividualAssociation(
331
			boolean supportsIndividualAssociation) {
332
		this.supportsIndividualAssociation = supportsIndividualAssociation;
333
	}
334

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

    
347
	/**
348
	 * @see	#isSupportsTaxonInteraction()
349
	 */
350
	public void setSupportsTaxonInteraction(boolean supportsTaxonInteraction) {
351
		this.supportsTaxonInteraction = supportsTaxonInteraction;
352
	}
353

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

    
367
	/**
368
	 * @see	#isSupportsTaxonInteraction()
369
	 */
370
	public void setSupportsCommonTaxonName(boolean supportsCommonTaxonName) {
371
		this.supportsCommonTaxonName = supportsCommonTaxonName;
372
	}
373

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

    
386
	/**
387
	 * @see	#supportsCategoricalData()
388
	 */
389
	public void setSupportsCategoricalData(boolean supportsCategoricalData) {
390
		this.supportsCategoricalData = supportsCategoricalData;
391
	}
392

    
393

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

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

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

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

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

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

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

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

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

    
554
	@Override
555
    public void setKindOf(Feature kindOf){
556
		super.setKindOf(kindOf);
557
	}
558

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

    
567
	@Override
568
    public void setPartOf(Feature partOf){
569
		super.setPartOf(partOf);
570
	}
571

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

    
581
	@Override
582
    protected void setGeneralizationOf(Set<Feature> value){
583
		super.setGeneralizationOf(value);
584
	}
585

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

    
595
	@Override
596
    protected void setIncludes(Set<Feature> includes) {
597
		super.setIncludes(includes);
598
	}
599

    
600
// ***************** Invers Label *****************************************/
601

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

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

    
677
//******************************* STATIC METHODS *****************************************
678

    
679
	protected static Feature getTermByUuid(UUID uuid){
680
	    if (termMap == null || termMap.isEmpty()){
681
            return getTermByClassAndUUID(Feature.class, uuid);
682
        } else {
683
			return termMap.get(uuid);
684
        }
685
	}
686

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

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

    
705
	/**
706
	 * Returns the "distribution" feature. This feature allows to handle only
707
	 * {@link Distribution distributions}.
708
	 *
709
	 * @see	#isSupportsDistribution()
710
	 */
711
	public static final Feature DISTRIBUTION(){
712
		return getTermByUuid(uuidDistribution);
713
	}
714

    
715
    /**
716
     * Returns the feature for general text-based
717
     * distributions
718
     */
719
    public static final Feature DISTRIBUTION_GENERAL(){
720
        return getTermByUuid(uuidDistributionGeneral);
721
    }
722

    
723
	/**
724
	 * Returns the "discussion" feature. This feature can only be described
725
	 * with {@link TextData text data}.
726
	 *
727
	 * @see	#isSupportsTextData()
728
	 */
729
	public static final Feature DISCUSSION(){
730
		return getTermByUuid(uuidDiscussion);
731
	}
732

    
733
	/**
734
	 * Returns the "ecology" feature. This feature only applies
735
	 * to {@link SpecimenDescription specimen descriptions} or to {@link TaxonDescription taxon descriptions}.<BR>
736
	 * The "ecology" feature generalizes all other possible features concerning
737
	 * ecological matters.
738
	 */
739
	public static final Feature ECOLOGY(){
740
		return getTermByUuid(uuidEcology);
741
	}
742

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

    
753

    
754
	/**
755
	 * Returns the "habitat & ecology" feature. This feature only applies
756
	 * to {@link SpecimenDescription specimen descriptions} or to {@link TaxonDescription taxon descriptions}.<BR>
757
	 * The "habitat & ecology" feature generalizes all other possible features concerning
758
	 * habitat and ecology matters.
759
	 */
760
	public static final Feature HABITAT_ECOLOGY(){
761
		return getTermByUuid(uuidHabitatAndEcology);
762
	}
763

    
764
	/**
765
	 * Returns the "biology_ecology" feature. This feature only applies
766
	 * to {@link SpecimenDescription specimen descriptions} or to {@link TaxonDescription taxon descriptions}.<BR>
767
	 * The "biology_ecology" feature generalizes all possible features concerning
768
	 * biological aspects of ecological matters.
769
	 *
770
	 * @see #ECOLOGY()
771
	 */
772
	public static final Feature BIOLOGY_ECOLOGY(){
773
		return getTermByUuid(uuidBiologyEcology);
774
	}
775

    
776
	/**
777
	 * Returns the "chromosome number" feature. This feature only applies
778
	 * to {@link SpecimenDescription specimen descriptions} or to {@link TaxonDescription taxon descriptions}.<BR>
779
	 */
780
	public static final Feature CHROMOSOME_NUMBER(){
781
		return getTermByUuid(uuidChromosomeNumber);
782
	}
783

    
784

    
785
	/**
786
	 * Returns the "key" feature. This feature is the "upper" feature generalizing
787
	 * all features being used within an identification key.
788
	 */
789
	public static final Feature KEY(){
790
		return getTermByUuid(uuidKey);
791
	}
792

    
793

    
794
	/**
795
	 * Returns the "materials_examined" feature. This feature can only be described
796
	 * with {@link TextData text data} or eventually with {@link CategoricalData categorical data}
797
	 * mentioning which material has been examined in order to accomplish
798
	 * the description. This feature applies only to
799
	 * {@link SpecimenDescription specimen descriptions} or to {@link TaxonDescription taxon descriptions}.
800
	 */
801
	public static final Feature MATERIALS_EXAMINED(){
802
		return getTermByUuid(uuidMaterialsExamined);
803
	}
804

    
805
	/**
806
	 * Returns the "materials_methods" feature. This feature can only be described
807
	 * with {@link TextData text data} or eventually with {@link CategoricalData categorical data}
808
	 * mentioning which methods have been adopted to analyze the material in
809
	 * order to accomplish the description. This feature applies only to
810
	 * {@link SpecimenDescription specimen descriptions} or to {@link TaxonDescription taxon descriptions}.
811
	 */
812
	public static final Feature MATERIALS_METHODS(){
813
		return getTermByUuid(uuidMaterialsMethods);
814
	}
815

    
816
	/**
817
	 * Returns the "etymology" feature. This feature can only be described
818
	 * with {@link TextData text data} or eventually with {@link CategoricalData categorical data}
819
	 * giving some information about the history of the taxon name. This feature applies only to
820
	 * {@link TaxonNameDescription taxon name descriptions}.
821
	 */
822
	public static final Feature ETYMOLOGY(){
823
		return getTermByUuid(uuidEtymology);
824
	}
825

    
826
	/**
827
	 * Returns the "diagnosis" feature. This feature can only be described
828
	 * with {@link TextData text data} or eventually with {@link CategoricalData categorical data}.
829
	 * This feature applies only to {@link SpecimenDescription specimen descriptions} or to
830
	 * {@link TaxonDescription taxon descriptions}.
831
	 */
832
	public static final Feature DIAGNOSIS(){
833
		return getTermByUuid(uuidDiagnosis);
834
	}
835

    
836

    
837
	/**
838
	 * Returns the "introduction" feature. This feature can only be described
839
	 * with {@link TextData text data}.
840
	 *
841
	 * @see	#isSupportsTextData()
842
	 */
843
	public static final Feature INTRODUCTION(){
844
		return getTermByUuid(uuidIntroduction);
845
	}
846

    
847
	/**
848
	 * Returns the "protologue" feature. This feature can only be described
849
	 * with {@link TextData text data} reproducing the content of the protologue
850
	 * (or some information about it) of the taxon name. This feature applies only to
851
	 * {@link TaxonNameDescription taxon name descriptions}.
852
	 *
853
	 * @see	#isSupportsTextData()
854
	 */
855
	public static final Feature PROTOLOGUE(){
856
		return getTermByUuid(uuidProtologue);
857
	}
858

    
859
	/**
860
	 * Returns the "common_name" feature. This feature allows to handle only
861
	 * {@link CommonTaxonName common names}.
862
	 *
863
	 * @see	#isSupportsCommonTaxonName()
864
	 */
865
	public static final Feature COMMON_NAME(){
866
		return getTermByUuid(uuidCommonName);
867
	}
868

    
869
	/**
870
	 * Returns the "phenology" feature. This feature can only be described
871
	 * with {@link CategoricalData categorical data} or eventually with {@link TextData text data}
872
	 * containing information time about recurring natural phenomena.
873
	 * This feature only applies to {@link TaxonDescription taxon descriptions}.<BR>
874
	 * The "phenology" feature generalizes all other possible features
875
	 * concerning time information about particular natural phenomena
876
	 * (such as "first flight of butterflies").
877
	 */
878
	public static final Feature PHENOLOGY(){
879
		return getTermByUuid(uuidPhenology);
880
	}
881

    
882
	/**
883
	 * Returns the "occurrence" feature.
884
	 */
885
	public static final Feature OCCURRENCE(){
886
		return getTermByUuid(uuidOccurrence);
887
	}
888

    
889
	/**
890
	 * Returns the "anatomy" feature.
891
	 */
892
	public static final Feature ANATOMY(){
893
		return getTermByUuid(uuidAnatomy);
894
	}
895
	/**
896
	 * Returns the "hostplant" feature.
897
	 */
898
	public static final Feature HOSTPLANT(){
899
		return getTermByUuid(uuidHostPlant);
900
	}
901
	/**
902
	 * Returns the "pathogen agent" feature.
903
	 */
904
	public static final Feature PATHOGEN_AGENT(){
905
		return getTermByUuid(uuidPathogenAgent);
906
	}
907

    
908
	/**
909
	 * Returns the "citation" feature. This feature can only be described
910
	 * with {@link TextData text data}.
911
	 *
912
	 * @see	#isSupportsTextData()
913
	 */
914
	public static final Feature CITATION(){
915
		return getTermByUuid(uuidCitation);
916
	}
917

    
918
	/**
919
	 * Returns the "additional_publication" feature. This feature can only be
920
	 * described with {@link TextData text data} with information about a
921
	 * publication where a {@link TaxonName taxon name} has also been published
922
	 * but which is not the {@link TaxonName#getNomenclaturalReference() nomenclatural reference}.
923
	 * This feature applies only to {@link TaxonNameDescription taxon name descriptions}.
924
	 *
925
	 * @see	#isSupportsTextData()
926
	 */
927
	public static final Feature ADDITIONAL_PUBLICATION(){
928
		return getTermByUuid(uuidAdditionalPublication);
929
	}
930

    
931

    
932
	/**
933
	 * Returns the "uses" feature. This feature only applies
934
	 * to {@link TaxonDescription taxon descriptions}.<BR>
935
	 * The "uses" feature generalizes all other possible features concerning
936
	 * particular uses (for instance "industrial use of seeds").
937
	 */
938
	public static final Feature USES(){
939
		return getTermByUuid(uuidUses);
940
	}
941

    
942
	public static final Feature USERECORD(){
943
		return getTermByUuid(uuidUseRecord);
944
	}
945

    
946
    /**
947
     * Returns the "notes" feature. Used for
948
     * taxonomic notes.
949
     */
950
    public static final Feature NOTES(){
951
        return getTermByUuid(uuidNotes);
952
    }
953

    
954
	/**
955
	 * Returns the "conservation" feature. This feature only applies
956
	 * to {@link SpecimenDescription specimen descriptions} and generalizes
957
	 * methods and conditions for the conservation of {@link Specimen specimens}.<BR>
958
	 */
959
	public static final Feature CONSERVATION(){
960
		return getTermByUuid(uuidConservation);
961
	}
962

    
963

    
964
	/**
965
	 * Returns the "cultivation" feature.
966
	 */
967
	public static final Feature CULTIVATION(){
968
		return getTermByUuid(uuidCultivation);
969
	}
970

    
971

    
972
	/**
973
	 * Returns the "image" feature.
974
	 */
975
	public static final Feature IMAGE(){
976
		return getTermByUuid(uuidImage);
977
	}
978

    
979
	/**
980
	 * Returns the "individuals association" feature.
981
	 */
982
	public static final Feature INDIVIDUALS_ASSOCIATION(){
983
		Feature individuals_association =  getTermByUuid(uuidIndividualsAssociation);
984
		Set<Feature> generalizationOf = new HashSet<>();
985
		generalizationOf.add(SPECIMEN());
986
		generalizationOf.add(OBSERVATION());
987
		individuals_association.setGeneralizationOf(generalizationOf);
988
		return individuals_association;
989

    
990
	}
991

    
992
	public static final Feature SPECIMEN(){
993
		return getTermByUuid(uuidSpecimen);
994
	}
995

    
996
	public static final Feature OBSERVATION(){
997
		return getTermByUuid(uuidObservation);
998
	}
999

    
1000
	/**
1001
	 * The status of a taxon. Usually the status should be determined within a {@link Distribution distribution}.
1002
	 * If this is not possible for some reason (e.g. the area is not well defined) the status feature
1003
	 * may be used.
1004
	 * @return
1005
	 */
1006
	public static final Feature STATUS(){
1007
		return getTermByUuid(uuidStatus);
1008
	}
1009

    
1010
	public static final Feature SYSTEMATICS(){
1011
		return getTermByUuid(uuidSystematics);
1012
	}
1013

    
1014
	public static final Feature LIFEFORM(){
1015
        return getTermByUuid(uuidLifeform);
1016
    }
1017

    
1018
	/**
1019
	 * Returns the "hybrid_parent" feature. This feature can only be used
1020
	 * by {@link TaxonInteraction taxon interactions}.<BR>
1021
	 * <P>
1022
	 * Note: It must be distinguished between hybrid relationships as
1023
	 * relevant nomenclatural relationships between {@link BotanicalName plant names}
1024
	 * on the one side and the biological relation between two {@link Taxon taxa}
1025
	 * as it is here the case on the other one.
1026
	 *
1027
	 * @see	#isSupportsTaxonInteraction()
1028
	 * @see	HybridRelationshipType
1029
	 */
1030
	public static final Feature HYBRID_PARENT(){
1031
		//TODO
1032
		logger.warn("HYBRID_PARENT not yet implemented");
1033
		return null;
1034
	}
1035

    
1036
	@Override
1037
	protected void setDefaultTerms(TermVocabulary<Feature> termVocabulary) {
1038
		if (termMap == null){  //needed because there are multiple feature vocabularies
1039
			termMap = new HashMap<UUID, Feature>();
1040
		}
1041
		for (Feature term : termVocabulary.getTerms()){
1042
			termMap.put(term.getUuid(), term);
1043
		}
1044
	}
1045

    
1046
//*********************************** CLONE *********************************************************/
1047

    
1048
    @Override
1049
    public Object clone() {
1050
        Feature result = (Feature)super.clone();
1051

    
1052
        result.inverseRepresentations = new HashSet<Representation>();
1053
        for (Representation rep: this.inverseRepresentations){
1054
            result.addInverseRepresentation((Representation)rep.clone());
1055
        }
1056

    
1057
        //no changes to: symmetric, transitiv
1058
        return result;
1059
    }
1060

    
1061
}
(10-10/35)