Project

General

Profile

Download (37.8 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.JoinTable;
23
import javax.persistence.ManyToMany;
24
import javax.persistence.OneToMany;
25
import javax.persistence.Transient;
26
import javax.xml.bind.annotation.XmlAccessType;
27
import javax.xml.bind.annotation.XmlAccessorType;
28
import javax.xml.bind.annotation.XmlElement;
29
import javax.xml.bind.annotation.XmlElementWrapper;
30
import javax.xml.bind.annotation.XmlIDREF;
31
import javax.xml.bind.annotation.XmlRootElement;
32
import javax.xml.bind.annotation.XmlSchemaType;
33
import javax.xml.bind.annotation.XmlType;
34

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

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

    
53

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

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

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

    
113
	private boolean supportsQuantitativeData;
114

    
115
	private boolean supportsDistribution;
116

    
117
	private boolean supportsIndividualAssociation;
118

    
119
	private boolean supportsTaxonInteraction;
120

    
121
	private boolean supportsCategoricalData;
122

    
123
	private boolean supportsCommonTaxonName;
124

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

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

    
139

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

    
144

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

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

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

    
190

    
191
/* ***************** CONSTRUCTOR AND FACTORY METHODS **********************************/
192

    
193
	//for hibernate use only
194
	@Deprecated
195
	protected Feature() {
196
		super(TermType.Feature);
197
	}
198

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

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

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

    
239
/* *************************************************************************************/
240

    
241
	@Override
242
	public void resetTerms(){
243
		termMap = null;
244
	}
245

    
246

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

    
260
	/**
261
	 * @see	#isSupportsQuantitativeData()
262
	 */
263
	public void setSupportsQuantitativeData(boolean supportsQuantitativeData) {
264
		this.supportsQuantitativeData = supportsQuantitativeData;
265
	}
266

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

    
279
	/**
280
	 * @see	#isSupportsTextData()
281
	 */
282
	public void setSupportsTextData(boolean supportsTextData) {
283
		this.supportsTextData = supportsTextData;
284
	}
285

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

    
299
	/**
300
	 * @see	#isSupportsDistribution()
301
	 */
302
	public void setSupportsDistribution(boolean supportsDistribution) {
303
		this.supportsDistribution = supportsDistribution;
304
	}
305

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

    
318
	/**
319
	 * @see	#isSupportsIndividualAssociation()
320
	 */
321
	public void setSupportsIndividualAssociation(
322
			boolean supportsIndividualAssociation) {
323
		this.supportsIndividualAssociation = supportsIndividualAssociation;
324
	}
325

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

    
338
	/**
339
	 * @see	#isSupportsTaxonInteraction()
340
	 */
341
	public void setSupportsTaxonInteraction(boolean supportsTaxonInteraction) {
342
		this.supportsTaxonInteraction = supportsTaxonInteraction;
343
	}
344

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

    
358
	/**
359
	 * @see	#isSupportsTaxonInteraction()
360
	 */
361
	public void setSupportsCommonTaxonName(boolean supportsCommonTaxonName) {
362
		this.supportsCommonTaxonName = supportsCommonTaxonName;
363
	}
364

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

    
377
	/**
378
	 * @see	#supportsCategoricalData()
379
	 */
380
	public void setSupportsCategoricalData(boolean supportsCategoricalData) {
381
		this.supportsCategoricalData = supportsCategoricalData;
382
	}
383

    
384

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

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

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

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

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

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

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

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

    
537
	@XmlElement(name = "KindOf", namespace = "http://etaxonomy.eu/cdm/model/common/1.0")
538
    @XmlIDREF
539
    @XmlSchemaType(name = "IDREF")
540
    @Override
541
	public Feature getKindOf(){
542
		return super.getKindOf();
543
	}
544

    
545
	@Override
546
    public void setKindOf(Feature kindOf){
547
		super.setKindOf(kindOf);
548
	}
549

    
550
	@Override
551
    @XmlElement(name = "PartOf", namespace = "http://etaxonomy.eu/cdm/model/common/1.0")
552
	@XmlIDREF
553
    @XmlSchemaType(name = "IDREF")
554
	public Feature getPartOf(){
555
		return super.getPartOf();
556
	}
557

    
558
	@Override
559
    public void setPartOf(Feature partOf){
560
		super.setPartOf(partOf);
561
	}
562

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

    
572
	@Override
573
    protected void setGeneralizationOf(Set<Feature> value){
574
		super.setGeneralizationOf(value);
575
	}
576

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

    
586
	@Override
587
    protected void setIncludes(Set<Feature> includes) {
588
		super.setIncludes(includes);
589
	}
590

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

    
633

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

    
665
//******************************* STATIC METHODS *****************************************
666

    
667
	protected static Feature getTermByUuid(UUID uuid){
668
	    if (termMap == null || termMap.isEmpty()){
669
            return getTermByClassAndUUID(Feature.class, uuid);
670
        } else {
671
			return termMap.get(uuid);
672
        }
673
	}
674

    
675
	/**
676
	 * Returns the "unknown" feature. This feature allows to store values of
677
	 * {@link DescriptionElementBase description elements} even if it is momentarily
678
	 * not known what they mean.
679
	 */
680
	public static final Feature UNKNOWN(){
681
		return getTermByUuid(uuidUnknown);
682
	}
683

    
684
	/**
685
	 * Returns the "description" feature. This feature allows to handle global
686
	 * {@link DescriptionElementBase description elements} for a global {@link DescriptionBase description}.<BR>
687
	 * The "description" feature is the highest level feature.
688
	 */
689
	public static final Feature DESCRIPTION(){
690
		return getTermByUuid(uuidDescription);
691
	}
692

    
693
	/**
694
	 * Returns the "distribution" feature. This feature allows to handle only
695
	 * {@link Distribution distributions}.
696
	 *
697
	 * @see	#isSupportsDistribution()
698
	 */
699
	public static final Feature DISTRIBUTION(){
700
		return getTermByUuid(uuidDistribution);
701
	}
702

    
703
	/**
704
	 * Returns the "discussion" feature. This feature can only be described
705
	 * with {@link TextData text data}.
706
	 *
707
	 * @see	#isSupportsTextData()
708
	 */
709
	public static final Feature DISCUSSION(){
710
		return getTermByUuid(uuidDiscussion);
711
	}
712

    
713
	/**
714
	 * Returns the "ecology" feature. This feature only applies
715
	 * to {@link SpecimenDescription specimen descriptions} or to {@link TaxonDescription taxon descriptions}.<BR>
716
	 * The "ecology" feature generalizes all other possible features concerning
717
	 * ecological matters.
718
	 */
719
	public static final Feature ECOLOGY(){
720
		return getTermByUuid(uuidEcology);
721
	}
722

    
723
	/**
724
	 * Returns the "habitat" feature. This feature only applies
725
	 * to {@link SpecimenDescription specimen descriptions} or to {@link TaxonDescription taxon descriptions}.<BR>
726
	 * The "habitat" feature generalizes all other possible features concerning
727
	 * habitat matters.
728
	 */
729
	public static final Feature HABITAT(){
730
		return getTermByUuid(uuidHabitat);
731
	}
732

    
733

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

    
744
	/**
745
	 * Returns the "biology_ecology" feature. This feature only applies
746
	 * to {@link SpecimenDescription specimen descriptions} or to {@link TaxonDescription taxon descriptions}.<BR>
747
	 * The "biology_ecology" feature generalizes all possible features concerning
748
	 * biological aspects of ecological matters.
749
	 *
750
	 * @see #ECOLOGY()
751
	 */
752
	public static final Feature BIOLOGY_ECOLOGY(){
753
		return getTermByUuid(uuidBiologyEcology);
754
	}
755

    
756
	/**
757
	 * Returns the "chromosome number" feature. This feature only applies
758
	 * to {@link SpecimenDescription specimen descriptions} or to {@link TaxonDescription taxon descriptions}.<BR>
759
	 */
760
	public static final Feature CHROMOSOME_NUMBER(){
761
		return getTermByUuid(uuidChromosomeNumber);
762
	}
763

    
764

    
765
	/**
766
	 * Returns the "key" feature. This feature is the "upper" feature generalizing
767
	 * all features being used within an identification key.
768
	 */
769
	public static final Feature KEY(){
770
		return getTermByUuid(uuidKey);
771
	}
772

    
773

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

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

    
796
	/**
797
	 * Returns the "etymology" feature. This feature can only be described
798
	 * with {@link TextData text data} or eventually with {@link CategoricalData categorical data}
799
	 * giving some information about the history of the taxon name. This feature applies only to
800
	 * {@link TaxonNameDescription taxon name descriptions}.
801
	 */
802
	public static final Feature ETYMOLOGY(){
803
		return getTermByUuid(uuidEtymology);
804
	}
805

    
806
	/**
807
	 * Returns the "diagnosis" feature. This feature can only be described
808
	 * with {@link TextData text data} or eventually with {@link CategoricalData categorical data}.
809
	 * This feature applies only to {@link SpecimenDescription specimen descriptions} or to
810
	 * {@link TaxonDescription taxon descriptions}.
811
	 */
812
	public static final Feature DIAGNOSIS(){
813
		return getTermByUuid(uuidDiagnosis);
814
	}
815

    
816

    
817
	/**
818
	 * Returns the "introduction" feature. This feature can only be described
819
	 * with {@link TextData text data}.
820
	 *
821
	 * @see	#isSupportsTextData()
822
	 */
823
	public static final Feature INTRODUCTION(){
824
		return getTermByUuid(uuidIntroduction);
825
	}
826

    
827
	/**
828
	 * Returns the "protologue" feature. This feature can only be described
829
	 * with {@link TextData text data} reproducing the content of the protologue
830
	 * (or some information about it) of the taxon name. This feature applies only to
831
	 * {@link TaxonNameDescription taxon name descriptions}.
832
	 *
833
	 * @see	#isSupportsTextData()
834
	 */
835
	public static final Feature PROTOLOGUE(){
836
		return getTermByUuid(uuidProtologue);
837
	}
838

    
839
	/**
840
	 * Returns the "common_name" feature. This feature allows to handle only
841
	 * {@link CommonTaxonName common names}.
842
	 *
843
	 * @see	#isSupportsCommonTaxonName()
844
	 */
845
	public static final Feature COMMON_NAME(){
846
		return getTermByUuid(uuidCommonName);
847
	}
848

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

    
862
	/**
863
	 * Returns the "occurrence" feature.
864
	 */
865
	public static final Feature OCCURRENCE(){
866
		return getTermByUuid(uuidOccurrence);
867
	}
868

    
869
	/**
870
	 * Returns the "anatomy" feature.
871
	 */
872
	public static final Feature ANATOMY(){
873
		return getTermByUuid(uuidAnatomy);
874
	}
875
	/**
876
	 * Returns the "hostplant" feature.
877
	 */
878
	public static final Feature HOSTPLANT(){
879
		return getTermByUuid(uuidHostPlant);
880
	}
881
	/**
882
	 * Returns the "pathogen agent" feature.
883
	 */
884
	public static final Feature PATHOGEN_AGENT(){
885
		return getTermByUuid(uuidPathogenAgent);
886
	}
887

    
888
	/**
889
	 * Returns the "citation" feature. This feature can only be described
890
	 * with {@link TextData text data}.
891
	 *
892
	 * @see	#isSupportsTextData()
893
	 */
894
	public static final Feature CITATION(){
895
		return getTermByUuid(uuidCitation);
896
	}
897

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

    
911

    
912
	/**
913
	 * Returns the "uses" feature. This feature only applies
914
	 * to {@link TaxonDescription taxon descriptions}.<BR>
915
	 * The "uses" feature generalizes all other possible features concerning
916
	 * particular uses (for instance "industrial use of seeds").
917
	 */
918
	public static final Feature USES(){
919
		return getTermByUuid(uuidUses);
920
	}
921

    
922
	public static final Feature USERECORD(){
923
		return getTermByUuid(uuidUseRecord);
924
	}
925

    
926

    
927
	/**
928
	 * Returns the "conservation" feature. This feature only applies
929
	 * to {@link SpecimenDescription specimen descriptions} and generalizes
930
	 * methods and conditions for the conservation of {@link Specimen specimens}.<BR>
931
	 */
932
	public static final Feature CONSERVATION(){
933
		return getTermByUuid(uuidConservation);
934
	}
935

    
936

    
937
	/**
938
	 * Returns the "cultivation" feature.
939
	 */
940
	public static final Feature CULTIVATION(){
941
		return getTermByUuid(uuidCultivation);
942
	}
943

    
944

    
945
	/**
946
	 * Returns the "image" feature.
947
	 */
948
	public static final Feature IMAGE(){
949
		return getTermByUuid(uuidImage);
950
	}
951

    
952
	/**
953
	 * Returns the "individuals association" feature.
954
	 */
955
	public static final Feature INDIVIDUALS_ASSOCIATION(){
956
		Feature individuals_association =  getTermByUuid(uuidIndividualsAssociation);
957
		Set<Feature> generalizationOf = new HashSet<Feature>();
958
		generalizationOf.add(SPECIMEN());
959
		generalizationOf.add(OBSERVATION());
960
		individuals_association.setGeneralizationOf(generalizationOf);
961
		return individuals_association;
962

    
963
	}
964

    
965
	public static final Feature SPECIMEN(){
966
		return getTermByUuid(uuidSpecimen);
967
	}
968

    
969
	public static final Feature OBSERVATION(){
970
		return getTermByUuid(uuidObservation);
971
	}
972

    
973
	/**
974
	 * The status of a taxon. Usually the status should be determined within a {@link Distribution distribution}.
975
	 * If this is not possible for some reason (e.g. the area is not well defined) the status feature
976
	 * may be used.
977
	 * @return
978
	 */
979
	public static final Feature STATUS(){
980
		return getTermByUuid(uuidStatus);
981
	}
982

    
983
	public static final Feature SYSTEMATICS(){
984
		return getTermByUuid(uuidSystematics);
985
	}
986

    
987
	/**
988
	 * Returns the "hybrid_parent" feature. This feature can only be used
989
	 * by {@link TaxonInteraction taxon interactions}.<BR>
990
	 * <P>
991
	 * Note: It must be distinguished between hybrid relationships as
992
	 * relevant nomenclatural relationships between {@link BotanicalName plant names}
993
	 * on the one side and the biological relation between two {@link Taxon taxa}
994
	 * as it is here the case on the other one.
995
	 *
996
	 * @see	#isSupportsTaxonInteraction()
997
	 * @see	HybridRelationshipType
998
	 */
999
	public static final Feature HYBRID_PARENT(){
1000
		//TODO
1001
		logger.warn("HYBRID_PARENT not yet implemented");
1002
		return null;
1003
	}
1004

    
1005
	@Override
1006
	protected void setDefaultTerms(TermVocabulary<Feature> termVocabulary) {
1007
		if (termMap == null){  //needed because there are multiple feature vocabularies
1008
			termMap = new HashMap<UUID, Feature>();
1009
		}
1010
		for (Feature term : termVocabulary.getTerms()){
1011
			termMap.put(term.getUuid(), term);
1012
		}
1013
	}
1014

    
1015
//*********************************** CLONE *********************************************************/
1016

    
1017
    @Override
1018
    public Object clone() {
1019
        Feature result = (Feature)super.clone();
1020

    
1021
        result.inverseRepresentations = new HashSet<Representation>();
1022
        for (Representation rep: this.inverseRepresentations){
1023
            result.addInverseRepresentation((Representation)rep.clone());
1024
        }
1025

    
1026
        //no changes to: symmetric, transitiv
1027
        return result;
1028
    }
1029

    
1030
}
(8-8/36)