Project

General

Profile

Download (38.7 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.HybridRelationshipType;
48
import eu.etaxonomy.cdm.model.name.NomenclaturalCode;
49
import eu.etaxonomy.cdm.model.name.TaxonName;
50
import eu.etaxonomy.cdm.model.taxon.Taxon;
51

    
52

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

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

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

    
113
	private boolean supportsQuantitativeData;
114

    
115
	private boolean supportsDistribution;
116

    
117
	private boolean supportsIndividualAssociation;
118

    
119
	private boolean supportsTaxonInteraction;
120

    
121
	private boolean supportsCategoricalData;
122

    
123
	private boolean supportsCommonTaxonName;
124

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

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

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

    
139

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

    
144

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

    
156
    private static final UUID uuidUnknown = UUID.fromString("910307f1-dc3c-452c-a6dd-af5ac7cd365c");
157
    public static final UUID uuidDescription = UUID.fromString("9087cdcd-8b08-4082-a1de-34c9ba9fb493");
158
    private static final UUID uuidDistribution = UUID.fromString("9fc9d10c-ba50-49ee-b174-ce83fc3f80c6");
159
    private static final UUID uuidDistributionGeneral = UUID.fromString("fd8c64f0-6ea5-44b0-9f70-e95833d6076e");
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
    public static final UUID uuidLifeform = UUID.fromString("db9228d3-8bbf-4460-abfe-0b1326c82f8e");
194

    
195

    
196
/* ***************** CONSTRUCTOR AND FACTORY METHODS **********************************/
197

    
198

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

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

    
224

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

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

    
246
/* *************************************************************************************/
247

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

    
253

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
391

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
598
// ***************** Invers Label *****************************************/
599

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

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

    
674
//******************************* STATIC METHODS *****************************************
675

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

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

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

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

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

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

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

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

    
750

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

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

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

    
781

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

    
790

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

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

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

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

    
833

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

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

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

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

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

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

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

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

    
928

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

    
939
	public static final Feature USERECORD(){
940
		return getTermByUuid(uuidUseRecord);
941
	}
942

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

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

    
960

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

    
968

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

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

    
987
	}
988

    
989
	public static final Feature SPECIMEN(){
990
		return getTermByUuid(uuidSpecimen);
991
	}
992

    
993
	public static final Feature OBSERVATION(){
994
		return getTermByUuid(uuidObservation);
995
	}
996

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

    
1007
	public static final Feature SYSTEMATICS(){
1008
		return getTermByUuid(uuidSystematics);
1009
	}
1010

    
1011
	public static final Feature LIFEFORM(){
1012
        return getTermByUuid(uuidLifeform);
1013
    }
1014

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

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

    
1043
//*********************************** CLONE *********************************************************/
1044

    
1045
    @Override
1046
    public Object clone() {
1047
        Feature result = (Feature)super.clone();
1048

    
1049
        result.inverseRepresentations = new HashSet<Representation>();
1050
        for (Representation rep: this.inverseRepresentations){
1051
            result.addInverseRepresentation((Representation)rep.clone());
1052
        }
1053

    
1054
        //no changes to: symmetric, transitiv
1055
        return result;
1056
    }
1057

    
1058
}
(9-9/37)