Project

General

Profile

Download (44.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
package eu.etaxonomy.cdm.model.description;
10

    
11
import java.util.EnumSet;
12
import java.util.HashMap;
13
import java.util.HashSet;
14
import java.util.List;
15
import java.util.Map;
16
import java.util.Set;
17
import java.util.UUID;
18

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

    
37
import org.apache.logging.log4j.LogManager;import org.apache.logging.log4j.Logger;
38
import org.hibernate.annotations.Cascade;
39
import org.hibernate.annotations.CascadeType;
40
import org.hibernate.annotations.Parameter;
41
import org.hibernate.annotations.Type;
42
import org.hibernate.envers.Audited;
43

    
44
import eu.etaxonomy.cdm.model.common.CdmClass;
45
import eu.etaxonomy.cdm.model.common.Language;
46
import eu.etaxonomy.cdm.model.name.NomenclaturalCode;
47
import eu.etaxonomy.cdm.model.name.TaxonName;
48
import eu.etaxonomy.cdm.model.term.AvailableForTermBase;
49
import eu.etaxonomy.cdm.model.term.DefinedTerm;
50
import eu.etaxonomy.cdm.model.term.DefinedTermBase;
51
import eu.etaxonomy.cdm.model.term.Representation;
52
import eu.etaxonomy.cdm.model.term.TermTree;
53
import eu.etaxonomy.cdm.model.term.TermType;
54
import eu.etaxonomy.cdm.model.term.TermVocabulary;
55

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

    
114
	private static final long serialVersionUID = 6754598791831848704L;
115
	@SuppressWarnings("unused")
116
    private static final Logger logger = LogManager.getLogger(Feature.class);
117

    
118
	protected static Map<UUID, Feature> termMap = null;
119

    
120
    @XmlAttribute(name ="supportedDataTypes")
121
    @NotNull
122
    @Type(type = "eu.etaxonomy.cdm.hibernate.EnumSetUserType",
123
        parameters = {@Parameter(name = "enumClass", value = "eu.etaxonomy.cdm.model.common.CdmClass")}
124
    )
125
    private EnumSet<CdmClass> supportedDataTypes = EnumSet.of(CdmClass.TEXT_DATA);  //by default TextData should always be supported
126

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

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

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

    
141
	@ManyToMany(fetch = FetchType.LAZY)
142
    @JoinTable(name="DefinedTermBase_MeasurementUnit")
143
	private final Set<MeasurementUnit> recommendedMeasurementUnits = new HashSet<>();
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

    
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
    public 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
    public 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
    public static final UUID uuidFloweringPeriod = UUID.fromString("03710cb5-606e-444a-a3e6-594268e3cc47");
197
    public static final UUID uuidFruitingPeriod = UUID.fromString("04aa8993-24b4-43e3-888c-5afaa733376e");
198
    public static final UUID uuidAltitude = UUID.fromString("1a28ed59-e15f-4001-b5c2-ea89f0012671");
199

    
200
/* ***************** CONSTRUCTOR AND FACTORY METHODS **********************************/
201

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

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

    
227
    public static Feature NewInstance(String description, String label, String labelAbbrev, Language language){
228
        Feature result = new Feature(description, label, labelAbbrev);
229
        result.getRepresentations().iterator().next().setLanguage(language);
230
        return result;
231
    }
232

    
233
// ********************** CONSTRUCTOR ************************/
234

    
235
    //for hibernate use only
236
    @Deprecated
237
    protected Feature() {
238
        super(TermType.Feature);
239
    }
240

    
241
    /**
242
     * Class constructor: creates a new feature instance with a description (in the {@link Language#DEFAULT() default language}),
243
     * a label and a label abbreviation.
244
     *
245
     * @param   term         the string (in the default language) describing the
246
     *                       new feature to be created
247
     * @param   label        the string identifying the new feature to be created
248
     * @param   labelAbbrev  the string identifying (in abbreviated form) the
249
     *                       new feature to be created
250
     * @see                  #Feature()
251
     */
252
    protected Feature(String term, String label, String labelAbbrev) {
253
        super(TermType.Feature, term, label, labelAbbrev);
254
    }
255

    
256
/* *************************************************************************************/
257

    
258
	@Override
259
	public void resetTerms(){
260
		termMap = null;
261
	}
262

    
263
	/**
264
     * If this feature is available for {@link TaxonDescription taxon descriptions}.
265
     */
266
    @XmlElement(name = "AvailableForTaxon")
267
    public boolean isAvailableForTaxon() {
268
        return getAvailableFor().contains(CdmClass.TAXON);
269
    }
270
    /**
271
     * @see #isAvailableForTaxon()
272
     */
273
    public void setAvailableForTaxon(boolean availableForTaxon) {
274
        setAvailableFor(CdmClass.TAXON, availableForTaxon);
275
    }
276

    
277
    /**
278
     * If this feature is available for {@link NameDescription name descriptions}.
279
     */
280
    @XmlElement(name = "AvailableForTaxonName")
281
    public boolean isAvailableForTaxonName() {
282
        return getAvailableFor().contains(CdmClass.TAXON_NAME);
283
    }
284
    /**
285
     * @see #isAvailableForTaxon()
286
     */
287
    public void setAvailableForTaxonName(boolean availableForTaxonName) {
288
        setAvailableFor(CdmClass.TAXON_NAME, availableForTaxonName);
289
    }
290

    
291
    /**
292
     * If this feature is available for {@link SpecimenDescription specimen descriptions}.
293
     */
294
    @XmlElement(name = "AvailableForOccurrence")
295
    public boolean isAvailableForOccurrence() {
296
        return getAvailableFor().contains(CdmClass.OCCURRENCE);
297
    }
298
    /**
299
     * @see #isAvailableForOccurrence()
300
     */
301
    public void setAvailableForOccurrence(boolean availableForOccurrence) {
302
        setAvailableFor(CdmClass.OCCURRENCE, availableForOccurrence);
303
    }
304

    
305
	/**
306
	 * Returns the boolean value of the flag indicating whether <i>this</i>
307
	 * feature can be described with {@link QuantitativeData quantitative data} (true)
308
	 * or not (false). If this flag is set <i>this</i> feature can only apply to
309
	 * {@link TaxonDescription taxon descriptions} or {@link SpecimenDescription specimen descriptions}.
310
	 *
311
	 * @return  the boolean value of the supportsQuantitativeData flag
312
	 */
313
	@XmlElement(name = "SupportsQuantitativeData")
314
	public boolean isSupportsQuantitativeData() {
315
	    return supportedDataTypes.contains(CdmClass.QUANTITATIVE_DATA);
316
	}
317
	/**
318
	 * @see	#isSupportsQuantitativeData()
319
	 */
320
	public void setSupportsQuantitativeData(boolean supportsQuantitativeData) {
321
        setSupportedClass(CdmClass.QUANTITATIVE_DATA, supportsQuantitativeData);
322
	}
323

    
324
	/**
325
	 * Returns the boolean value of the flag indicating whether <i>this</i>
326
	 * feature can be described with {@link TextData text data} (true)
327
	 * or not (false).
328
	 *
329
	 * @return  the boolean value of the supportsTextData flag
330
	 */
331
	@XmlElement(name = "SupportsTextData")
332
	public boolean isSupportsTextData() {
333
	    return supportedDataTypes.contains(CdmClass.TEXT_DATA);
334
	}
335
	/**
336
	 * @see	#isSupportsTextData()
337
	 */
338
	public void setSupportsTextData(boolean supportsTextData) {
339
        setSupportedClass(CdmClass.TEXT_DATA, supportsTextData);
340
	}
341

    
342
	/**
343
	 * Returns the boolean value of the flag indicating whether <i>this</i>
344
	 * feature can be described with {@link Distribution distribution} objects
345
	 * (true) or not (false). This flag is set if and only if <i>this</i> feature
346
	 * is the {@link #DISTRIBUTION() distribution feature}.
347
	 *
348
	 * @return  the boolean value of the supportsDistribution flag
349
	 */
350
	@XmlElement(name = "SupportsDistribution")
351
	public boolean isSupportsDistribution() {
352
	      return supportedDataTypes.contains(CdmClass.DISTRIBUTION);
353
	}
354
	/**
355
	 * @see	#isSupportsDistribution()
356
	 */
357
	public void setSupportsDistribution(boolean supportsDistribution) {
358
        setSupportedClass(CdmClass.DISTRIBUTION, supportsDistribution);
359
	}
360

    
361
	/**
362
	 * Returns the boolean value of the flag indicating whether <i>this</i>
363
	 * feature can be described with {@link IndividualsAssociation individuals associations}
364
	 * (true) or not (false).
365
	 *
366
	 * @return  the boolean value of the supportsIndividualAssociation flag
367
	 */
368
	@XmlElement(name = "SupportsIndividualAssociation")
369
	public boolean isSupportsIndividualAssociation() {
370
	      return supportedDataTypes.contains(CdmClass.INDIVIDUALS_ASSOCIATION);
371
	}
372
	/**
373
	 * @see	#isSupportsIndividualAssociation()
374
	 */
375
	public void setSupportsIndividualAssociation(
376
			boolean supportsIndividualAssociation) {
377
        setSupportedClass(CdmClass.INDIVIDUALS_ASSOCIATION, supportsIndividualAssociation);
378
	}
379

    
380
	/**
381
	 * Returns the boolean value of the flag indicating whether <i>this</i>
382
	 * feature can be described with {@link TaxonInteraction taxon interactions}
383
	 * (true) or not (false).
384
	 *
385
	 * @return  the boolean value of the supportsTaxonInteraction flag
386
	 */
387
	@XmlElement(name = "SupportsTaxonInteraction")
388
	public boolean isSupportsTaxonInteraction() {
389
	      return supportedDataTypes.contains(CdmClass.TAXON_INTERACTION);
390
	}
391
	/**
392
	 * @see	#isSupportsTaxonInteraction()
393
	 */
394
	public void setSupportsTaxonInteraction(boolean supportsTaxonInteraction) {
395
        setSupportedClass(CdmClass.TAXON_INTERACTION, supportsTaxonInteraction);
396
	}
397

    
398
	/**
399
	 * Returns the boolean value of the flag indicating whether <i>this</i>
400
	 * feature can be described with {@link CommonTaxonName common names}
401
	 * (true) or not (false). This flag is set if and only if <i>this</i> feature
402
	 * is the {@link #COMMON_NAME() common name feature}.
403
	 *
404
	 * @return  the boolean value of the supportsCommonTaxonName flag
405
	 */
406
	@XmlElement(name = "SupportsCommonTaxonName")
407
	public boolean isSupportsCommonTaxonName() {
408
	      return supportedDataTypes.contains(CdmClass.COMMON_TAXON_NAME);
409
	}
410
	/**
411
	 * @see	#isSupportsTaxonInteraction()
412
	 */
413
	public void setSupportsCommonTaxonName(boolean supportsCommonTaxonName) {
414
        setSupportedClass(CdmClass.COMMON_TAXON_NAME, supportsCommonTaxonName);
415
	}
416

    
417
	/**
418
	 * Returns the boolean value of the flag indicating whether <i>this</i>
419
	 * feature can be described with {@link CategoricalData categorical data}
420
	 * (true) or not (false).
421
	 *
422
	 * @return  the boolean value of the supportsCategoricalData flag
423
	 */
424
	@XmlElement(name = "SupportsCategoricalData")
425
	public boolean isSupportsCategoricalData() {
426
		return supportedDataTypes.contains(CdmClass.CATEGORICAL_DATA);
427
	}
428
	/**
429
	 * @see	#supportsCategoricalData()
430
	 */
431
	public void setSupportsCategoricalData(boolean supportsCategoricalData) {
432
        setSupportedClass(CdmClass.CATEGORICAL_DATA, supportsCategoricalData);
433
	}
434

    
435
	/**
436
     * Returns the boolean value of the flag indicating whether <i>this</i>
437
     * feature can be described with {@link TemporalData temporalData}
438
     * (true) or not (false).
439
     *
440
     * @return  the boolean value of the supportsTemporalData flag
441
     */
442
    @XmlElement(name = "SupportsTemporalData")
443
    public boolean isSupportsTemporalData() {
444
          return supportedDataTypes.contains(CdmClass.TEMPORAL_DATA);
445
    }
446
    /**
447
     * @see #isSupportsTemporalData()
448
     */
449
    public void setSupportsTemporalData(boolean supportsTemporalData) {
450
        setSupportedClass(CdmClass.TEMPORAL_DATA, supportsTemporalData);
451
    }
452

    
453
    /**
454
     * Sets the value for supported classes
455
     * @param cdmClass the supported class
456
     * @param value the value if it is supported (<code>true</code>) or not (<code>false</code>)
457
     */
458
    private void setSupportedClass(CdmClass cdmClass, boolean value) {
459
        if (value && !this.supportedDataTypes.contains(cdmClass)){
460
            setSupportedDataTypes(newEnumSet(this.supportedDataTypes, cdmClass, null));
461
        }else if (!value && this.supportedDataTypes.contains(cdmClass)){
462
            setSupportedDataTypes(newEnumSet(this.supportedDataTypes, null, cdmClass));
463
        }else{
464
            return;
465
        }
466
    }
467

    
468
    /**
469
     * for know it is private and the boolean getters and setters should be used instead.
470
     * If you make it public make sure to guarantee that any change to the enum set results
471
     * in a new enum set (see also {@link #newEnumSet(EnumSet, CdmClass, CdmClass)}
472
     * and that the client is aware of the enum set being immutable.
473
     */
474
    private void setSupportedDataTypes(EnumSet<CdmClass> dataTypes){
475
        this.supportedDataTypes = dataTypes;
476
    }
477

    
478

    
479
    /**
480
	 * Returns the set of {@link TermVocabulary term vocabularies} containing the
481
	 * {@link Modifier modifiers} recommended to be used for {@link DescriptionElementBase description elements}
482
	 * with <i>this</i> feature.
483
	 *
484
	 */
485
	@XmlElementWrapper(name = "RecommendedModifierEnumerations")
486
	@XmlElement(name = "RecommendedModifierEnumeration")
487
	@XmlIDREF
488
	@XmlSchemaType(name = "IDREF")
489
	public Set<TermVocabulary<DefinedTerm>> getRecommendedModifierEnumeration() {
490
		return recommendedModifierEnumeration;
491
	}
492

    
493
	/**
494
	 * Adds a {@link TermVocabulary term vocabulary} (with {@link Modifier modifiers}) to the set of
495
	 * {@link #getRecommendedModifierEnumeration() recommended modifier vocabularies} assigned
496
	 * to <i>this</i> feature.
497
	 *
498
	 * @param recommendedModifierEnumeration	the term vocabulary to be added
499
	 * @see    	   								#getRecommendedModifierEnumeration()
500
	 */
501
	public void addRecommendedModifierEnumeration(
502
			TermVocabulary<DefinedTerm> recommendedModifierEnumeration) {
503
		this.recommendedModifierEnumeration.add(recommendedModifierEnumeration);
504
	}
505
	/**
506
	 * Removes one element from the set of {@link #getRecommendedModifierEnumeration() recommended modifier vocabularies}
507
	 * assigned to <i>this</i> feature.
508
	 *
509
	 * @param  recommendedModifierEnumeration	the term vocabulary which should be removed
510
	 * @see     								#getRecommendedModifierEnumeration()
511
	 * @see     								#addRecommendedModifierEnumeration(TermVocabulary)
512
	 */
513
	public void removeRecommendedModifierEnumeration(
514
			TermVocabulary<DefinedTerm> recommendedModifierEnumeration) {
515
		this.recommendedModifierEnumeration.remove(recommendedModifierEnumeration);
516
	}
517

    
518
	/**
519
	 * Returns the set of {@link StatisticalMeasure statistical measures} recommended to be used
520
	 * in case of {@link QuantitativeData quantitative data} with <i>this</i> feature.
521
	 */
522
	@XmlElementWrapper(name = "RecommendedStatisticalMeasures")
523
	@XmlElement(name = "RecommendedStatisticalMeasure")
524
	@XmlIDREF
525
	@XmlSchemaType(name = "IDREF")
526
	public Set<StatisticalMeasure> getRecommendedStatisticalMeasures() {
527
		return recommendedStatisticalMeasures;
528
	}
529

    
530
	/**
531
	 * Adds a {@link StatisticalMeasure statistical measure} to the set of
532
	 * {@link #getRecommendedStatisticalMeasures() recommended statistical measures} assigned
533
	 * to <i>this</i> feature.
534
	 *
535
	 * @param recommendedStatisticalMeasure	the statistical measure to be added
536
	 * @see    	   							#getRecommendedStatisticalMeasures()
537
	 */
538
	public void addRecommendedStatisticalMeasure(
539
			StatisticalMeasure recommendedStatisticalMeasure) {
540
		this.recommendedStatisticalMeasures.add(recommendedStatisticalMeasure);
541
	}
542
	/**
543
	 * Removes one element from the set of {@link #getRecommendedStatisticalMeasures() recommended statistical measures}
544
	 * assigned to <i>this</i> feature.
545
	 *
546
	 * @param  recommendedStatisticalMeasure	the statistical measure which should be removed
547
	 * @see     								#getRecommendedStatisticalMeasures()
548
	 * @see     								#addRecommendedStatisticalMeasure(StatisticalMeasure)
549
	 */
550
	public void removeRecommendedStatisticalMeasure(
551
			StatisticalMeasure recommendedStatisticalMeasure) {
552
		this.recommendedStatisticalMeasures.remove(recommendedStatisticalMeasure);
553
	}
554

    
555
	/**
556
	 * Returns the set of {@link StatisticalMeasure statistical measures} recommended to be used
557
	 * in case of {@link QuantitativeData quantitative data} with <i>this</i> feature.
558
	 */
559
	@XmlElementWrapper(name = "RecommendedMeasurementUnits")
560
	@XmlElement(name = "RecommendedMeasurementUnit")
561
	@XmlIDREF
562
	@XmlSchemaType(name = "IDREF")
563
	public Set<MeasurementUnit> getRecommendedMeasurementUnits() {
564
		return recommendedMeasurementUnits;
565
	}
566

    
567
	/**
568
	 * Adds a {@link StatisticalMeasure statistical measure} to the set of
569
	 * {@link #getRecommendedStatisticalMeasures() recommended statistical measures} assigned
570
	 * to <i>this</i> feature.
571
	 *
572
	 * @param recommendedStatisticalMeasure	the statistical measure to be added
573
	 * @see    	   							#getRecommendedStatisticalMeasures()
574
	 */
575
	public void addRecommendedMeasurementUnit(
576
			MeasurementUnit recommendedMeasurementUnit) {
577
		this.recommendedMeasurementUnits.add(recommendedMeasurementUnit);
578
	}
579
	/**
580
	 * Removes one element from the set of {@link #getRecommendedStatisticalMeasures() recommended statistical measures}
581
	 * assigned to <i>this</i> feature.
582
	 *
583
	 * @param  recommendedStatisticalMeasure	the statistical measure which should be removed
584
	 * @see     								#getRecommendedStatisticalMeasures()
585
	 * @see     								#addRecommendedStatisticalMeasure(StatisticalMeasure)
586
	 */
587
	public void removeRecommendedMeasurementUnit(
588
			MeasurementUnit recommendedMeasurementUnit) {
589
		this.recommendedMeasurementUnits.remove(recommendedMeasurementUnit);
590
	}
591

    
592
	/**
593
	 * Returns the set of {@link TermVocabulary term vocabularies} containing the list of
594
	 * possible {@link State states} to be used in {@link CategoricalData categorical data}
595
	 * with <i>this</i> feature.
596
	 *
597
	 */
598
	@XmlElementWrapper(name = "SupportedCategoricalEnumerations")
599
	@XmlElement(name = "SupportedCategoricalEnumeration")
600
	@XmlIDREF
601
	@XmlSchemaType(name = "IDREF")
602
	public Set<TermVocabulary<State>> getSupportedCategoricalEnumerations() {
603
		return supportedCategoricalEnumerations;
604
	}
605

    
606
	/**
607
	 * Adds a {@link TermVocabulary term vocabulary} to the set of
608
	 * {@link #getSupportedCategoricalEnumerations() supported state vocabularies} assigned
609
	 * to <i>this</i> feature.
610
	 *
611
	 * @param supportedCategoricalEnumeration	the term vocabulary which should be removed
612
	 * @see    	   								#getSupportedCategoricalEnumerations()
613
	 */
614
	public void addSupportedCategoricalEnumeration(
615
			TermVocabulary<State> supportedCategoricalEnumeration) {
616
		this.supportedCategoricalEnumerations.add(supportedCategoricalEnumeration);
617
	}
618
	/**
619
	 * Removes one element from the set of {@link #getSupportedCategoricalEnumerations() supported state vocabularies}
620
	 * assigned to <i>this</i> feature.
621
	 *
622
	 * @param  supportedCategoricalEnumeration	the term vocabulary which should be removed
623
	 * @see     								#getSupportedCategoricalEnumerations()
624
	 * @see     								#addSupportedCategoricalEnumeration(TermVocabulary)
625
	 */
626
	public void removeSupportedCategoricalEnumeration(
627
			TermVocabulary<State> supportedCategoricalEnumeration) {
628
		this.supportedCategoricalEnumerations.remove(supportedCategoricalEnumeration);
629
	}
630

    
631
	@XmlElement(name = "KindOf", namespace = "http://etaxonomy.eu/cdm/model/common/1.0")
632
    @XmlIDREF
633
    @XmlSchemaType(name = "IDREF")
634
    @Override
635
	public Feature getKindOf(){
636
		return super.getKindOf();
637
	}
638

    
639
	@Override
640
    public void setKindOf(Feature kindOf){
641
		super.setKindOf(kindOf);
642
	}
643

    
644
	@Override
645
    @XmlElement(name = "PartOf", namespace = "http://etaxonomy.eu/cdm/model/common/1.0")
646
	@XmlIDREF
647
    @XmlSchemaType(name = "IDREF")
648
	public Feature getPartOf(){
649
		return super.getPartOf();
650
	}
651

    
652
	@Override
653
    public void setPartOf(Feature partOf){
654
		super.setPartOf(partOf);
655
	}
656

    
657
	@Override
658
    @XmlElementWrapper(name = "Generalizations", namespace = "http://etaxonomy.eu/cdm/model/common/1.0")
659
	@XmlElement(name = "GeneralizationOf", namespace = "http://etaxonomy.eu/cdm/model/common/1.0")
660
    @XmlIDREF
661
    @XmlSchemaType(name = "IDREF")
662
	public Set<Feature> getGeneralizationOf(){
663
		return super.getGeneralizationOf();
664
	}
665

    
666
	@Override
667
    protected void setGeneralizationOf(Set<Feature> value){
668
		super.setGeneralizationOf(value);
669
	}
670

    
671
	@Override
672
    @XmlElementWrapper(name = "Includes", namespace = "http://etaxonomy.eu/cdm/model/common/1.0")
673
	@XmlElement(name = "Include", namespace = "http://etaxonomy.eu/cdm/model/common/1.0")
674
	@XmlIDREF
675
    @XmlSchemaType(name = "IDREF")
676
	public Set<Feature> getIncludes(){
677
		return super.getIncludes();
678
	}
679

    
680
	@Override
681
    protected void setIncludes(Set<Feature> includes) {
682
		super.setIncludes(includes);
683
	}
684

    
685
// ***************** Invers Label *****************************************/
686

    
687
	public Set<Representation> getInverseRepresentations() {
688
        return inverseRepresentations;
689
    }
690
    public void addInverseRepresentation(Representation inverseRepresentation) {
691
        this.inverseRepresentations.add(inverseRepresentation);
692
    }
693
    public void removeInverseRepresentation(Representation inverseRepresentation) {
694
        this.inverseRepresentations.remove(inverseRepresentation);
695
    }
696
    /*
697
     * Inverse representation convenience methods similar to TermBase.xxx
698
     * @see eu.etaxonomy.cdm.model.term.TermBase#getLabel()
699
     */
700
    @Transient
701
    public String getInverseLabel() {
702
        if(getInverseLabel(Language.DEFAULT()) != null){
703
            return this.getInverseRepresentation(Language.DEFAULT()).getLabel();
704
        }else{
705
            for (Representation r : inverseRepresentations){
706
                return r.getLabel();
707
            }
708
        }
709
        return super.getUuid().toString();
710
    }
711
    public String getInverseLabel(Language lang) {
712
        Representation r = this.getInverseRepresentation(lang);
713
        if(r==null){
714
            return null;
715
        }else{
716
            return r.getLabel();
717
        }
718
    }
719
    public Representation getInverseRepresentation(Language lang) {
720
        Representation result = null;
721
        for (Representation repr : this.getInverseRepresentations()){
722
            if (lang.equals(repr.getLanguage())){
723
                result = repr;
724
            }
725
        }
726
        return result;
727
    }
728
// ****************** END INVERS REPRESENTATION **************************/
729

    
730
	/**
731
	 * Creates and returns a new feature instance on the basis of a given string
732
	 * list (containing an UUID, an URI, a label and a description) and a given
733
	 * {@link Language language} to be associated with the description. Furthermore
734
	 * the flags concerning the supported subclasses of {@link DescriptionElementBase description elements}
735
	 * are set according to a particular string belonging to the given
736
	 * string list.<BR>
737
	 * This method overrides the readCsvLine method from {@link DefinedTermBase#readCsvLine(List, Language) DefinedTermBase}.
738
	 *
739
	 * @param  csvLine	the string list with elementary information for attributes
740
	 * @param  lang		the language in which the description has been formulated
741
	 * @see     		#NewInstance(String, String, String)
742
	 */
743
	@Override
744
	public Feature readCsvLine(Class<Feature> termClass, List<String> csvLine, TermType termType,
745
	        @SuppressWarnings("rawtypes") Map<UUID,DefinedTermBase> terms, boolean abbrevAsId) {
746
		Feature newInstance = super.readCsvLine(termClass, csvLine, termType, terms, abbrevAsId);
747

    
748
		String text = csvLine.get(4);
749
		if (isNotBlank(text)){
750
		    newInstance.setSymbol(text);
751
		}
752

    
753
		//supported datatypes
754
		text = csvLine.get(5);
755
		if (text != null && text.length() == 8){
756
			if ("1".equals(text.substring(0, 1))){newInstance.setSupportsTextData(true);}
757
			if ("1".equals(text.substring(1, 2))){newInstance.setSupportsQuantitativeData(true);}
758
			if ("1".equals(text.substring(2, 3))){newInstance.setSupportsDistribution(true);}
759
			if ("1".equals(text.substring(3, 4))){newInstance.setSupportsIndividualAssociation(true);}
760
			if ("1".equals(text.substring(4, 5))){newInstance.setSupportsTaxonInteraction(true);}
761
			if ("1".equals(text.substring(5, 6))){newInstance.setSupportsCommonTaxonName(true);}
762
			if ("1".equals(text.substring(6, 7))){newInstance.setSupportsCategoricalData(true);}
763
			if ("1".equals(text.substring(7, 8))){newInstance.setSupportsTemporalData(true);}
764
		}else{
765
		    throw new IllegalStateException("Supported XXX must exist for all 8 subclasses");
766
		}
767

    
768
		//availableFor
769
        text = csvLine.get(6);
770
        if (text != null && text.length() == 3){
771
            if ("1".equals(text.substring(0, 1))){newInstance.setAvailableForTaxon(true);}
772
            if ("1".equals(text.substring(1, 2))){newInstance.setAvailableForOccurrence(true);}
773
            if ("1".equals(text.substring(2, 3))){newInstance.setAvailableForTaxonName(true);}
774
        }else{
775
            throw new IllegalStateException("AvailableFor XXX must exist for all 3 classes");
776
        }
777

    
778
        //recommended measurement unit
779
        text = csvLine.get(7);
780
        if (isNotBlank(text) && text.length() == 36){
781
            if (text.length() != 36){
782
                throw new IllegalStateException("Recommended measurement unit must be a UUID");
783
            }
784
            UUID uuid = UUID.fromString(text);
785
            MeasurementUnit recommendedMeasurementUnit = MeasurementUnit.getTermByUuid(uuid);
786
            if (recommendedMeasurementUnit == null){
787
                throw new IllegalArgumentException("Required recommended measurement unit not found for '"+text+"'");
788
            }else{
789
                newInstance.addRecommendedMeasurementUnit(recommendedMeasurementUnit);
790
            }
791
        }
792

    
793
		return newInstance;
794
	}
795

    
796
//******************************* STATIC METHODS *****************************************
797

    
798
	protected static Feature getTermByUuid(UUID uuid){
799
	    if (termMap == null || termMap.isEmpty()){
800
            return getTermByClassAndUUID(Feature.class, uuid);
801
        } else {
802
			return termMap.get(uuid);
803
        }
804
	}
805

    
806
	/**
807
	 * Returns the "unknown" feature. This feature allows to store values of
808
	 * {@link DescriptionElementBase description elements} even if it is momentarily
809
	 * not known what they mean.
810
	 */
811
	public static final Feature UNKNOWN(){
812
		return getTermByUuid(uuidUnknown);
813
	}
814

    
815
	/**
816
	 * Returns the "description" feature. This feature allows to handle global
817
	 * {@link DescriptionElementBase description elements} for a global {@link DescriptionBase description}.<BR>
818
	 * The "description" feature is the highest level feature.
819
	 */
820
	public static final Feature DESCRIPTION(){
821
		return getTermByUuid(uuidDescription);
822
	}
823

    
824
	/**
825
	 * Returns the "distribution" feature. This feature allows to handle only
826
	 * {@link Distribution distributions}.
827
	 *
828
	 * @see	#isSupportsDistribution()
829
	 */
830
	public static final Feature DISTRIBUTION(){
831
		return getTermByUuid(uuidDistribution);
832
	}
833

    
834
    /**
835
     * Returns the feature for general text-based
836
     * distributions
837
     */
838
    public static final Feature DISTRIBUTION_GENERAL(){
839
        return getTermByUuid(uuidDistributionGeneral);
840
    }
841

    
842
	/**
843
	 * Returns the "discussion" feature. This feature can only be described
844
	 * with {@link TextData text data}.
845
	 *
846
	 * @see	#isSupportsTextData()
847
	 */
848
	public static final Feature DISCUSSION(){
849
		return getTermByUuid(uuidDiscussion);
850
	}
851

    
852
	/**
853
	 * Returns the "ecology" feature. This feature only applies
854
	 * to {@link SpecimenDescription specimen descriptions} or to {@link TaxonDescription taxon descriptions}.<BR>
855
	 * The "ecology" feature generalizes all other possible features concerning
856
	 * ecological matters.
857
	 */
858
	public static final Feature ECOLOGY(){
859
		return getTermByUuid(uuidEcology);
860
	}
861

    
862
	/**
863
	 * Returns the "habitat" feature. This feature only applies
864
	 * to {@link SpecimenDescription specimen descriptions} or to {@link TaxonDescription taxon descriptions}.<BR>
865
	 * The "habitat" feature generalizes all other possible features concerning
866
	 * habitat matters.
867
	 */
868
	public static final Feature HABITAT(){
869
		return getTermByUuid(uuidHabitat);
870
	}
871

    
872
	/**
873
	 * Returns the "habitat & ecology" feature. This feature only applies
874
	 * to {@link SpecimenDescription specimen descriptions} or to {@link TaxonDescription taxon descriptions}.<BR>
875
	 * The "habitat & ecology" feature generalizes all other possible features concerning
876
	 * habitat and ecology matters.
877
	 */
878
	public static final Feature HABITAT_ECOLOGY(){
879
		return getTermByUuid(uuidHabitatAndEcology);
880
	}
881

    
882
	/**
883
	 * Returns the "biology_ecology" feature. This feature only applies
884
	 * to {@link SpecimenDescription specimen descriptions} or to {@link TaxonDescription taxon descriptions}.<BR>
885
	 * The "biology_ecology" feature generalizes all possible features concerning
886
	 * biological aspects of ecological matters.
887
	 *
888
	 * @see #ECOLOGY()
889
	 */
890
	public static final Feature BIOLOGY_ECOLOGY(){
891
		return getTermByUuid(uuidBiologyEcology);
892
	}
893

    
894
	/**
895
	 * Returns the "chromosome number" feature. This feature only applies
896
	 * to {@link SpecimenDescription specimen descriptions} or to {@link TaxonDescription taxon descriptions}.<BR>
897
	 */
898
	public static final Feature CHROMOSOME_NUMBER(){
899
		return getTermByUuid(uuidChromosomeNumber);
900
	}
901

    
902
	/**
903
	 * Returns the "key" feature. This feature is the "upper" feature generalizing
904
	 * all features being used within an identification key.
905
	 */
906
	public static final Feature KEY(){
907
		return getTermByUuid(uuidKey);
908
	}
909

    
910
	/**
911
	 * Returns the "materials_examined" feature. This feature can only be described
912
	 * with {@link TextData text data} or eventually with {@link CategoricalData categorical data}
913
	 * mentioning which material has been examined in order to accomplish
914
	 * the description. This feature applies only to
915
	 * {@link SpecimenDescription specimen descriptions} or to {@link TaxonDescription taxon descriptions}.
916
	 */
917
	public static final Feature MATERIALS_EXAMINED(){
918
		return getTermByUuid(uuidMaterialsExamined);
919
	}
920

    
921
	/**
922
	 * Returns the "materials_methods" feature. This feature can only be described
923
	 * with {@link TextData text data} or eventually with {@link CategoricalData categorical data}
924
	 * mentioning which methods have been adopted to analyze the material in
925
	 * order to accomplish the description. This feature applies only to
926
	 * {@link SpecimenDescription specimen descriptions} or to {@link TaxonDescription taxon descriptions}.
927
	 */
928
	public static final Feature MATERIALS_METHODS(){
929
		return getTermByUuid(uuidMaterialsMethods);
930
	}
931

    
932
	/**
933
	 * Returns the "etymology" feature. This feature can only be described
934
	 * with {@link TextData text data} or eventually with {@link CategoricalData categorical data}
935
	 * giving some information about the history of the taxon name. This feature applies only to
936
	 * {@link TaxonNameDescription taxon name descriptions}.
937
	 */
938
	public static final Feature ETYMOLOGY(){
939
		return getTermByUuid(uuidEtymology);
940
	}
941

    
942
	/**
943
	 * Returns the "diagnosis" feature. This feature can only be described
944
	 * with {@link TextData text data} or eventually with {@link CategoricalData categorical data}.
945
	 * This feature applies only to {@link SpecimenDescription specimen descriptions} or to
946
	 * {@link TaxonDescription taxon descriptions}.
947
	 */
948
	public static final Feature DIAGNOSIS(){
949
		return getTermByUuid(uuidDiagnosis);
950
	}
951

    
952
	/**
953
	 * Returns the "introduction" feature. This feature can only be described
954
	 * with {@link TextData text data}.
955
	 *
956
	 * @see	#isSupportsTextData()
957
	 */
958
	public static final Feature INTRODUCTION(){
959
		return getTermByUuid(uuidIntroduction);
960
	}
961

    
962
	/**
963
	 * Returns the "protologue" feature. This feature can only be described
964
	 * with {@link TextData text data} reproducing the content of the protologue
965
	 * (or some information about it) of the taxon name. This feature applies only to
966
	 * {@link TaxonNameDescription taxon name descriptions}.
967
	 *
968
	 * @see	#isSupportsTextData()
969
	 */
970
	public static final Feature PROTOLOGUE(){
971
		return getTermByUuid(uuidProtologue);
972
	}
973

    
974
	/**
975
	 * Returns the "common_name" feature. This feature allows to handle only
976
	 * {@link CommonTaxonName common names}.
977
	 *
978
	 * @see	#isSupportsCommonTaxonName()
979
	 */
980
	public static final Feature COMMON_NAME(){
981
		return getTermByUuid(uuidCommonName);
982
	}
983

    
984
	/**
985
	 * Returns the "phenology" feature. This feature can only be described
986
	 * with {@link CategoricalData categorical data} or eventually with {@link TextData text data}
987
	 * containing information time about recurring natural phenomena.
988
	 * This feature only applies to {@link TaxonDescription taxon descriptions}.<BR>
989
	 * The "phenology" feature generalizes all other possible features
990
	 * concerning time information about particular natural phenomena
991
	 * (such as "first flight of butterflies").
992
	 */
993
	public static final Feature PHENOLOGY(){
994
		return getTermByUuid(uuidPhenology);
995
	}
996

    
997
	/**
998
	 * Returns the "occurrence" feature.
999
	 */
1000
	public static final Feature OCCURRENCE(){
1001
		return getTermByUuid(uuidOccurrence);
1002
	}
1003

    
1004
	/**
1005
	 * Returns the "anatomy" feature.
1006
	 */
1007
	public static final Feature ANATOMY(){
1008
		return getTermByUuid(uuidAnatomy);
1009
	}
1010

    
1011
	/**
1012
	 * Returns the "hostplant" feature.
1013
	 */
1014
	public static final Feature HOSTPLANT(){
1015
		return getTermByUuid(uuidHostPlant);
1016
	}
1017

    
1018
	/**
1019
	 * Returns the "pathogen agent" feature.
1020
	 */
1021
	public static final Feature PATHOGEN_AGENT(){
1022
		return getTermByUuid(uuidPathogenAgent);
1023
	}
1024

    
1025
	/**
1026
	 * Returns the "citation" feature. This feature can only be described
1027
	 * with {@link TextData text data}.
1028
	 *
1029
	 * @see	#isSupportsTextData()
1030
	 */
1031
	public static final Feature CITATION(){
1032
		return getTermByUuid(uuidCitation);
1033
	}
1034

    
1035
	/**
1036
	 * Returns the "additional_publication" feature. This feature can only be
1037
	 * described with {@link TextData text data} with information about a
1038
	 * publication where a {@link TaxonName taxon name} has also been published
1039
	 * but which is not the {@link TaxonName#getNomenclaturalReference() nomenclatural reference}.
1040
	 * This feature applies only to {@link TaxonNameDescription taxon name descriptions}.
1041
	 *
1042
	 * @see	#isSupportsTextData()
1043
	 */
1044
	public static final Feature ADDITIONAL_PUBLICATION(){
1045
		return getTermByUuid(uuidAdditionalPublication);
1046
	}
1047

    
1048
	/**
1049
	 * Returns the "uses" feature. This feature only applies
1050
	 * to {@link TaxonDescription taxon descriptions}.<BR>
1051
	 * The "uses" feature generalizes all other possible features concerning
1052
	 * particular uses (for instance "industrial use of seeds").
1053
	 */
1054
	public static final Feature USES(){
1055
		return getTermByUuid(uuidUses);
1056
	}
1057

    
1058
	public static final Feature USERECORD(){
1059
		return getTermByUuid(uuidUseRecord);
1060
	}
1061

    
1062
    /**
1063
     * Returns the "notes" feature. Used for
1064
     * taxonomic notes.
1065
     */
1066
    public static final Feature NOTES(){
1067
        return getTermByUuid(uuidNotes);
1068
    }
1069

    
1070
	/**
1071
	 * Returns the "conservation" feature. This feature only applies
1072
	 * to {@link SpecimenDescription specimen descriptions} and generalizes
1073
	 * methods and conditions for the conservation of {@link Specimen specimens}.<BR>
1074
	 */
1075
	public static final Feature CONSERVATION(){
1076
		return getTermByUuid(uuidConservation);
1077
	}
1078

    
1079
	/**
1080
	 * Returns the "cultivation" feature.
1081
	 */
1082
	public static final Feature CULTIVATION(){
1083
		return getTermByUuid(uuidCultivation);
1084
	}
1085

    
1086
	/**
1087
	 * Returns the "image" feature.
1088
	 */
1089
	public static final Feature IMAGE(){
1090
		return getTermByUuid(uuidImage);
1091
	}
1092

    
1093
	/**
1094
	 * Returns the "individuals association" feature.
1095
	 */
1096
	public static final Feature INDIVIDUALS_ASSOCIATION(){
1097
		Feature individuals_association =  getTermByUuid(uuidIndividualsAssociation);
1098
		Set<Feature> generalizationOf = new HashSet<>();
1099
		generalizationOf.add(SPECIMEN());
1100
		generalizationOf.add(OBSERVATION());
1101
		individuals_association.setGeneralizationOf(generalizationOf);
1102
		return individuals_association;
1103

    
1104
	}
1105

    
1106
	public static final Feature SPECIMEN(){
1107
		return getTermByUuid(uuidSpecimen);
1108
	}
1109

    
1110
	public static final Feature OBSERVATION(){
1111
		return getTermByUuid(uuidObservation);
1112
	}
1113

    
1114
	/**
1115
	 * The status of a taxon. Usually the status should be determined within a {@link Distribution distribution}.
1116
	 * If this is not possible for some reason (e.g. the area is not well defined) the status feature
1117
	 * may be used.
1118
	 * @return
1119
	 */
1120
	public static final Feature STATUS(){
1121
		return getTermByUuid(uuidStatus);
1122
	}
1123

    
1124
	public static final Feature SYSTEMATICS(){
1125
		return getTermByUuid(uuidSystematics);
1126
	}
1127

    
1128
	public static final Feature LIFEFORM(){
1129
        return getTermByUuid(uuidLifeform);
1130
    }
1131

    
1132
	public static final Feature FLOWERING_PERIOD(){
1133
	    return getTermByUuid(uuidFloweringPeriod);
1134
	}
1135

    
1136
    public static final Feature FRUITING_PERIOD(){
1137
        return getTermByUuid(uuidFruitingPeriod);
1138
    }
1139

    
1140
	public static final Feature ALTITUDE(){
1141
        return getTermByUuid(uuidAltitude);
1142
    }
1143
//
1144
//	/**
1145
//	 * Returns the "hybrid_parent" feature. This feature can only be used
1146
//	 * by {@link TaxonInteraction taxon interactions}.<BR>
1147
//	 * <P>
1148
//	 * Note: It must be distinguished between hybrid relationships as
1149
//	 * relevant nomenclatural relationships between {@link BotanicalName plant names}
1150
//	 * on the one side and the biological relation between two {@link Taxon taxa}
1151
//	 * as it is here the case on the other one.
1152
//	 *
1153
//	 * @see	#isSupportsTaxonInteraction()
1154
//	 * @see	HybridRelationshipType
1155
//	 */
1156
//	public static final Feature HYBRID_PARENT(){
1157
//		//TODO
1158
//		logger.warn("HYBRID_PARENT not yet implemented");
1159
//		return null;
1160
//	}
1161

    
1162
	@Override
1163
	protected void setDefaultTerms(TermVocabulary<Feature> termVocabulary) {
1164
		if (termMap == null){  //needed because there are multiple feature vocabularies
1165
			termMap = new HashMap<>();
1166
		}
1167
		for (Feature term : termVocabulary.getTerms()){
1168
			termMap.put(term.getUuid(), term);
1169
		}
1170
	}
1171

    
1172
//*********************************** CLONE *********************************************************/
1173

    
1174
    @Override
1175
    public Feature clone() {
1176
        Feature result = (Feature)super.clone();
1177

    
1178
        result.inverseRepresentations = new HashSet<Representation>();
1179
        for (Representation rep: this.inverseRepresentations){
1180
            result.addInverseRepresentation(rep.clone());
1181
        }
1182

    
1183
        //no changes to: symmetric, transitiv
1184
        return result;
1185
    }
1186

    
1187
}
(11-11/38)