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.Representation;
49
import eu.etaxonomy.cdm.model.term.TermType;
50
import eu.etaxonomy.cdm.model.term.TermVocabulary;
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
 * @since 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.term.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="DefinedTermBase_InverseRepresentation",  //see also RelationshipTermBase.inverseRepresentations
150
        joinColumns=@JoinColumn(name="DefinedTermBase_id")
151
        //  inverseJoinColumns
152
    )
153
    @Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE, CascadeType.DELETE})
154
//    @IndexedEmbedded(depth = 2)
155
    private Set<Representation> inverseRepresentations = new HashSet<>();
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 uuidDistributionGeneral = UUID.fromString("fd8c64f0-6ea5-44b0-9f70-e95833d6076e");
161
    private static final UUID uuidEcology = UUID.fromString("aa923827-d333-4cf5-9a5f-438ae0a4746b");
162
    private static final UUID uuidHabitat = UUID.fromString("fb16929f-bc9c-456f-9d40-dec987b36438");
163
    private static final UUID uuidHabitatAndEcology = UUID.fromString("9fdc4663-4d56-47d0-90b5-c0bf251bafbb");
164
    private static final UUID uuidChromosomeNumber = UUID.fromString("6f677e98-d8d5-4bc5-80bf-affdb7e3945a");
165

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

    
196

    
197
/* ***************** CONSTRUCTOR AND FACTORY METHODS **********************************/
198

    
199

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

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

    
225

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

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

    
247
/* *************************************************************************************/
248

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

    
254

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
392

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
599
// ***************** Invers Label *****************************************/
600

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

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

    
676
//******************************* STATIC METHODS *****************************************
677

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

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

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

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

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

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

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

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

    
752

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

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

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

    
783

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

    
792

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

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

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

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

    
835

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

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

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

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

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

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

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

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

    
930

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

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

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

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

    
962

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

    
970

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

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

    
989
	}
990

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

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

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

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

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

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

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

    
1045
//*********************************** CLONE *********************************************************/
1046

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

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

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

    
1060
}
(10-10/37)