2 * Copyright (C) 2007 EDIT
3 * European Distributed Institute of Taxonomy
4 * http://www.e-taxonomy.eu
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.
9 package eu
.etaxonomy
.cdm
.model
.description
;
11 import java
.util
.EnumSet
;
12 import java
.util
.HashMap
;
13 import java
.util
.HashSet
;
14 import java
.util
.List
;
17 import java
.util
.UUID
;
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
;
37 import org
.apache
.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
;
44 import eu
.etaxonomy
.cdm
.model
.common
.AvailableForTermBase
;
45 import eu
.etaxonomy
.cdm
.model
.common
.CdmClass
;
46 import eu
.etaxonomy
.cdm
.model
.common
.Language
;
47 import eu
.etaxonomy
.cdm
.model
.name
.NomenclaturalCode
;
48 import eu
.etaxonomy
.cdm
.model
.name
.TaxonName
;
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
;
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.
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.
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>
78 * This class corresponds to DescriptionsSectionType according to the SDD
82 * @since 08-Nov-2007 13:06:24
84 @XmlAccessorType(XmlAccessType
.PROPERTY
)
85 @XmlType(name
="Feature", factoryMethod
="NewInstance", propOrder
= {
91 "availableForTaxonName",
92 "availableForOccurrence",
94 "supportsQuantitativeData",
95 "supportsDistribution",
96 "supportsIndividualAssociation",
97 "supportsTaxonInteraction",
98 "supportsCommonTaxonName",
99 "supportsCategoricalData",
100 "supportsTemporalData",
101 "recommendedModifierEnumeration",
102 "recommendedStatisticalMeasures",
103 "supportedCategoricalEnumerations",
104 "recommendedMeasurementUnits",
105 "inverseRepresentations"
107 @XmlRootElement(name
= "Feature")
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")
112 public class Feature
extends AvailableForTermBase
<Feature
> {
114 private static final long serialVersionUID
= 6754598791831848704L;
115 @SuppressWarnings("unused")
116 private static final Logger logger
= Logger
.getLogger(Feature
.class);
118 protected static Map
<UUID
, Feature
> termMap
= null;
120 @XmlAttribute(name
="supportedDataTypes")
122 @Type(type
= "eu.etaxonomy.cdm.hibernate.EnumSetUserType",
123 parameters
= {@Parameter(name
= "enumClass", value
= "eu.etaxonomy.cdm.model.common.CdmClass")}
125 private EnumSet
<CdmClass
> supportedDataTypes
= EnumSet
.of(CdmClass
.TEXT_DATA
); //by default TextData should always be supported
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
<>();
132 @ManyToMany(fetch
= FetchType
.LAZY
)
133 @JoinTable(name
="DefinedTermBase_StatisticalMeasure")
134 private final Set
<StatisticalMeasure
> recommendedStatisticalMeasures
= new HashSet
<>();
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
<>();
141 @ManyToMany(fetch
= FetchType
.LAZY
)
142 @JoinTable(name
="DefinedTermBase_MeasurementUnit")
143 private final Set
<MeasurementUnit
> recommendedMeasurementUnits
= new HashSet
<>();
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
153 @Cascade({CascadeType
.SAVE_UPDATE
, CascadeType
.MERGE
, CascadeType
.DELETE
})
154 // @IndexedEmbedded(depth = 2)
155 private Set
<Representation
> inverseRepresentations
= new HashSet
<>();
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");
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");
200 /* ***************** CONSTRUCTOR AND FACTORY METHODS **********************************/
203 * Creates a new empty feature instance.
205 * @see #NewInstance(String, String, String)
207 public static Feature
NewInstance() {
208 return new Feature();
212 * Creates a new feature instance with a description (in the {@link Language#DEFAULT() default language}),
213 * a label and a label abbreviation.
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()
223 public static Feature
NewInstance(String description
, String label
, String labelAbbrev
){
224 return new Feature(description
, label
, labelAbbrev
);
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
);
233 // ********************** CONSTRUCTOR ************************/
235 //for hibernate use only
237 protected Feature() {
238 super(TermType
.Feature
);
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.
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
252 protected Feature(String term
, String label
, String labelAbbrev
) {
253 super(TermType
.Feature
, term
, label
, labelAbbrev
);
256 /* *************************************************************************************/
259 public void resetTerms(){
264 * If this feature is available for {@link TaxonDescription taxon descriptions}.
266 @XmlElement(name
= "AvailableForTaxon")
267 public boolean isAvailableForTaxon() {
268 return getAvailableFor().contains(CdmClass
.TAXON
);
271 * @see #isAvailableForTaxon()
273 public void setAvailableForTaxon(boolean availableForTaxon
) {
274 setAvailableFor(CdmClass
.TAXON
, availableForTaxon
);
278 * If this feature is available for {@link NameDescription name descriptions}.
280 @XmlElement(name
= "AvailableForTaxonName")
281 public boolean isAvailableForTaxonName() {
282 return getAvailableFor().contains(CdmClass
.TAXON_NAME
);
285 * @see #isAvailableForTaxon()
287 public void setAvailableForTaxonName(boolean availableForTaxonName
) {
288 setAvailableFor(CdmClass
.TAXON_NAME
, availableForTaxonName
);
292 * If this feature is available for {@link SpecimenDescription specimen descriptions}.
294 @XmlElement(name
= "AvailableForOccurrence")
295 public boolean isAvailableForOccurrence() {
296 return getAvailableFor().contains(CdmClass
.OCCURRENCE
);
299 * @see #isAvailableForOccurrence()
301 public void setAvailableForOccurrence(boolean availableForOccurrence
) {
302 setAvailableFor(CdmClass
.OCCURRENCE
, availableForOccurrence
);
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}.
311 * @return the boolean value of the supportsQuantitativeData flag
313 @XmlElement(name
= "SupportsQuantitativeData")
314 public boolean isSupportsQuantitativeData() {
315 return supportedDataTypes
.contains(CdmClass
.QUANTITATIVE_DATA
);
318 * @see #isSupportsQuantitativeData()
320 public void setSupportsQuantitativeData(boolean supportsQuantitativeData
) {
321 setSupportedClass(CdmClass
.QUANTITATIVE_DATA
, supportsQuantitativeData
);
325 * Returns the boolean value of the flag indicating whether <i>this</i>
326 * feature can be described with {@link TextData text data} (true)
329 * @return the boolean value of the supportsTextData flag
331 @XmlElement(name
= "SupportsTextData")
332 public boolean isSupportsTextData() {
333 return supportedDataTypes
.contains(CdmClass
.TEXT_DATA
);
336 * @see #isSupportsTextData()
338 public void setSupportsTextData(boolean supportsTextData
) {
339 setSupportedClass(CdmClass
.TEXT_DATA
, supportsTextData
);
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}.
348 * @return the boolean value of the supportsDistribution flag
350 @XmlElement(name
= "SupportsDistribution")
351 public boolean isSupportsDistribution() {
352 return supportedDataTypes
.contains(CdmClass
.DISTRIBUTION
);
355 * @see #isSupportsDistribution()
357 public void setSupportsDistribution(boolean supportsDistribution
) {
358 setSupportedClass(CdmClass
.DISTRIBUTION
, supportsDistribution
);
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).
366 * @return the boolean value of the supportsIndividualAssociation flag
368 @XmlElement(name
= "SupportsIndividualAssociation")
369 public boolean isSupportsIndividualAssociation() {
370 return supportedDataTypes
.contains(CdmClass
.INDIVIDUALS_ASSOCIATION
);
373 * @see #isSupportsIndividualAssociation()
375 public void setSupportsIndividualAssociation(
376 boolean supportsIndividualAssociation
) {
377 setSupportedClass(CdmClass
.INDIVIDUALS_ASSOCIATION
, supportsIndividualAssociation
);
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).
385 * @return the boolean value of the supportsTaxonInteraction flag
387 @XmlElement(name
= "SupportsTaxonInteraction")
388 public boolean isSupportsTaxonInteraction() {
389 return supportedDataTypes
.contains(CdmClass
.TAXON_INTERACTION
);
392 * @see #isSupportsTaxonInteraction()
394 public void setSupportsTaxonInteraction(boolean supportsTaxonInteraction
) {
395 setSupportedClass(CdmClass
.TAXON_INTERACTION
, supportsTaxonInteraction
);
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}.
404 * @return the boolean value of the supportsCommonTaxonName flag
406 @XmlElement(name
= "SupportsCommonTaxonName")
407 public boolean isSupportsCommonTaxonName() {
408 return supportedDataTypes
.contains(CdmClass
.COMMON_TAXON_NAME
);
411 * @see #isSupportsTaxonInteraction()
413 public void setSupportsCommonTaxonName(boolean supportsCommonTaxonName
) {
414 setSupportedClass(CdmClass
.COMMON_TAXON_NAME
, supportsCommonTaxonName
);
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).
422 * @return the boolean value of the supportsCategoricalData flag
424 @XmlElement(name
= "SupportsCategoricalData")
425 public boolean isSupportsCategoricalData() {
426 return supportedDataTypes
.contains(CdmClass
.CATEGORICAL_DATA
);
429 * @see #supportsCategoricalData()
431 public void setSupportsCategoricalData(boolean supportsCategoricalData
) {
432 setSupportedClass(CdmClass
.CATEGORICAL_DATA
, supportsCategoricalData
);
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).
440 * @return the boolean value of the supportsTemporalData flag
442 @XmlElement(name
= "SupportsTemporalData")
443 public boolean isSupportsTemporalData() {
444 return supportedDataTypes
.contains(CdmClass
.TEMPORAL_DATA
);
447 * @see #isSupportsTemporalData()
449 public void setSupportsTemporalData(boolean supportsTemporalData
) {
450 setSupportedClass(CdmClass
.TEMPORAL_DATA
, supportsTemporalData
);
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>)
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
));
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.
474 private void setSupportedDataTypes(EnumSet
<CdmClass
> dataTypes
){
475 this.supportedDataTypes
= dataTypes
;
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.
485 @XmlElementWrapper(name
= "RecommendedModifierEnumerations")
486 @XmlElement(name
= "RecommendedModifierEnumeration")
488 @XmlSchemaType(name
= "IDREF")
489 public Set
<TermVocabulary
<DefinedTerm
>> getRecommendedModifierEnumeration() {
490 return recommendedModifierEnumeration
;
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.
498 * @param recommendedModifierEnumeration the term vocabulary to be added
499 * @see #getRecommendedModifierEnumeration()
501 public void addRecommendedModifierEnumeration(
502 TermVocabulary
<DefinedTerm
> recommendedModifierEnumeration
) {
503 this.recommendedModifierEnumeration
.add(recommendedModifierEnumeration
);
506 * Removes one element from the set of {@link #getRecommendedModifierEnumeration() recommended modifier vocabularies}
507 * assigned to <i>this</i> feature.
509 * @param recommendedModifierEnumeration the term vocabulary which should be removed
510 * @see #getRecommendedModifierEnumeration()
511 * @see #addRecommendedModifierEnumeration(TermVocabulary)
513 public void removeRecommendedModifierEnumeration(
514 TermVocabulary
<DefinedTerm
> recommendedModifierEnumeration
) {
515 this.recommendedModifierEnumeration
.remove(recommendedModifierEnumeration
);
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.
522 @XmlElementWrapper(name
= "RecommendedStatisticalMeasures")
523 @XmlElement(name
= "RecommendedStatisticalMeasure")
525 @XmlSchemaType(name
= "IDREF")
526 public Set
<StatisticalMeasure
> getRecommendedStatisticalMeasures() {
527 return recommendedStatisticalMeasures
;
531 * Adds a {@link StatisticalMeasure statistical measure} to the set of
532 * {@link #getRecommendedStatisticalMeasures() recommended statistical measures} assigned
533 * to <i>this</i> feature.
535 * @param recommendedStatisticalMeasure the statistical measure to be added
536 * @see #getRecommendedStatisticalMeasures()
538 public void addRecommendedStatisticalMeasure(
539 StatisticalMeasure recommendedStatisticalMeasure
) {
540 this.recommendedStatisticalMeasures
.add(recommendedStatisticalMeasure
);
543 * Removes one element from the set of {@link #getRecommendedStatisticalMeasures() recommended statistical measures}
544 * assigned to <i>this</i> feature.
546 * @param recommendedStatisticalMeasure the statistical measure which should be removed
547 * @see #getRecommendedStatisticalMeasures()
548 * @see #addRecommendedStatisticalMeasure(StatisticalMeasure)
550 public void removeRecommendedStatisticalMeasure(
551 StatisticalMeasure recommendedStatisticalMeasure
) {
552 this.recommendedStatisticalMeasures
.remove(recommendedStatisticalMeasure
);
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.
559 @XmlElementWrapper(name
= "RecommendedMeasurementUnits")
560 @XmlElement(name
= "RecommendedMeasurementUnit")
562 @XmlSchemaType(name
= "IDREF")
563 public Set
<MeasurementUnit
> getRecommendedMeasurementUnits() {
564 return recommendedMeasurementUnits
;
568 * Adds a {@link StatisticalMeasure statistical measure} to the set of
569 * {@link #getRecommendedStatisticalMeasures() recommended statistical measures} assigned
570 * to <i>this</i> feature.
572 * @param recommendedStatisticalMeasure the statistical measure to be added
573 * @see #getRecommendedStatisticalMeasures()
575 public void addRecommendedMeasurementUnit(
576 MeasurementUnit recommendedMeasurementUnit
) {
577 this.recommendedMeasurementUnits
.add(recommendedMeasurementUnit
);
580 * Removes one element from the set of {@link #getRecommendedStatisticalMeasures() recommended statistical measures}
581 * assigned to <i>this</i> feature.
583 * @param recommendedStatisticalMeasure the statistical measure which should be removed
584 * @see #getRecommendedStatisticalMeasures()
585 * @see #addRecommendedStatisticalMeasure(StatisticalMeasure)
587 public void removeRecommendedMeasurementUnit(
588 MeasurementUnit recommendedMeasurementUnit
) {
589 this.recommendedMeasurementUnits
.remove(recommendedMeasurementUnit
);
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.
598 @XmlElementWrapper(name
= "SupportedCategoricalEnumerations")
599 @XmlElement(name
= "SupportedCategoricalEnumeration")
601 @XmlSchemaType(name
= "IDREF")
602 public Set
<TermVocabulary
<State
>> getSupportedCategoricalEnumerations() {
603 return supportedCategoricalEnumerations
;
607 * Adds a {@link TermVocabulary term vocabulary} to the set of
608 * {@link #getSupportedCategoricalEnumerations() supported state vocabularies} assigned
609 * to <i>this</i> feature.
611 * @param supportedCategoricalEnumeration the term vocabulary which should be removed
612 * @see #getSupportedCategoricalEnumerations()
614 public void addSupportedCategoricalEnumeration(
615 TermVocabulary
<State
> supportedCategoricalEnumeration
) {
616 this.supportedCategoricalEnumerations
.add(supportedCategoricalEnumeration
);
619 * Removes one element from the set of {@link #getSupportedCategoricalEnumerations() supported state vocabularies}
620 * assigned to <i>this</i> feature.
622 * @param supportedCategoricalEnumeration the term vocabulary which should be removed
623 * @see #getSupportedCategoricalEnumerations()
624 * @see #addSupportedCategoricalEnumeration(TermVocabulary)
626 public void removeSupportedCategoricalEnumeration(
627 TermVocabulary
<State
> supportedCategoricalEnumeration
) {
628 this.supportedCategoricalEnumerations
.remove(supportedCategoricalEnumeration
);
631 @XmlElement(name
= "KindOf", namespace
= "http://etaxonomy.eu/cdm/model/common/1.0")
633 @XmlSchemaType(name
= "IDREF")
635 public Feature
getKindOf(){
636 return super.getKindOf();
640 public void setKindOf(Feature kindOf
){
641 super.setKindOf(kindOf
);
645 @XmlElement(name
= "PartOf", namespace
= "http://etaxonomy.eu/cdm/model/common/1.0")
647 @XmlSchemaType(name
= "IDREF")
648 public Feature
getPartOf(){
649 return super.getPartOf();
653 public void setPartOf(Feature partOf
){
654 super.setPartOf(partOf
);
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")
661 @XmlSchemaType(name
= "IDREF")
662 public Set
<Feature
> getGeneralizationOf(){
663 return super.getGeneralizationOf();
667 protected void setGeneralizationOf(Set
<Feature
> value
){
668 super.setGeneralizationOf(value
);
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")
675 @XmlSchemaType(name
= "IDREF")
676 public Set
<Feature
> getIncludes(){
677 return super.getIncludes();
681 protected void setIncludes(Set
<Feature
> includes
) {
682 super.setIncludes(includes
);
685 // ***************** Invers Label *****************************************/
687 public Set
<Representation
> getInverseRepresentations() {
688 return inverseRepresentations
;
690 public void addInverseRepresentation(Representation inverseRepresentation
) {
691 this.inverseRepresentations
.add(inverseRepresentation
);
693 public void removeInverseRepresentation(Representation inverseRepresentation
) {
694 this.inverseRepresentations
.remove(inverseRepresentation
);
697 * Inverse representation convenience methods similar to TermBase.xxx
698 * @see eu.etaxonomy.cdm.model.term.TermBase#getLabel()
701 public String
getInverseLabel() {
702 if(getInverseLabel(Language
.DEFAULT()) != null){
703 return this.getInverseRepresentation(Language
.DEFAULT()).getLabel();
705 for (Representation r
: inverseRepresentations
){
709 return super.getUuid().toString();
711 public String
getInverseLabel(Language lang
) {
712 Representation r
= this.getInverseRepresentation(lang
);
719 public Representation
getInverseRepresentation(Language lang
) {
720 Representation result
= null;
721 for (Representation repr
: this.getInverseRepresentations()){
722 if (lang
.equals(repr
.getLanguage())){
728 // ****************** END INVERS REPRESENTATION **************************/
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
737 * This method overrides the readCsvLine method from {@link DefinedTermBase#readCsvLine(List, Language) DefinedTermBase}.
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)
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
);
748 String text
= csvLine
.get(4);
749 if (isNotBlank(text
)){
750 newInstance
.setSymbol(text
);
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);}
765 throw new IllegalStateException("Supported XXX must exist for all 8 subclasses");
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);}
775 throw new IllegalStateException("AvailableFor XXX must exist for all 3 classes");
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");
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
+"'");
789 newInstance
.addRecommendedMeasurementUnit(recommendedMeasurementUnit
);
796 //******************************* STATIC METHODS *****************************************
798 protected static Feature
getTermByUuid(UUID uuid
){
799 if (termMap
== null || termMap
.isEmpty()){
800 return getTermByClassAndUUID(Feature
.class, uuid
);
802 return termMap
.get(uuid
);
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.
811 public static final Feature
UNKNOWN(){
812 return getTermByUuid(uuidUnknown
);
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.
820 public static final Feature
DESCRIPTION(){
821 return getTermByUuid(uuidDescription
);
825 * Returns the "distribution" feature. This feature allows to handle only
826 * {@link Distribution distributions}.
828 * @see #isSupportsDistribution()
830 public static final Feature
DISTRIBUTION(){
831 return getTermByUuid(uuidDistribution
);
835 * Returns the feature for general text-based
838 public static final Feature
DISTRIBUTION_GENERAL(){
839 return getTermByUuid(uuidDistributionGeneral
);
843 * Returns the "discussion" feature. This feature can only be described
844 * with {@link TextData text data}.
846 * @see #isSupportsTextData()
848 public static final Feature
DISCUSSION(){
849 return getTermByUuid(uuidDiscussion
);
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.
858 public static final Feature
ECOLOGY(){
859 return getTermByUuid(uuidEcology
);
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
868 public static final Feature
HABITAT(){
869 return getTermByUuid(uuidHabitat
);
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.
878 public static final Feature
HABITAT_ECOLOGY(){
879 return getTermByUuid(uuidHabitatAndEcology
);
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.
890 public static final Feature
BIOLOGY_ECOLOGY(){
891 return getTermByUuid(uuidBiologyEcology
);
895 * Returns the "chromosome number" feature. This feature only applies
896 * to {@link SpecimenDescription specimen descriptions} or to {@link TaxonDescription taxon descriptions}.<BR>
898 public static final Feature
CHROMOSOME_NUMBER(){
899 return getTermByUuid(uuidChromosomeNumber
);
903 * Returns the "key" feature. This feature is the "upper" feature generalizing
904 * all features being used within an identification key.
906 public static final Feature
KEY(){
907 return getTermByUuid(uuidKey
);
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}.
917 public static final Feature
MATERIALS_EXAMINED(){
918 return getTermByUuid(uuidMaterialsExamined
);
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}.
928 public static final Feature
MATERIALS_METHODS(){
929 return getTermByUuid(uuidMaterialsMethods
);
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}.
938 public static final Feature
ETYMOLOGY(){
939 return getTermByUuid(uuidEtymology
);
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}.
948 public static final Feature
DIAGNOSIS(){
949 return getTermByUuid(uuidDiagnosis
);
953 * Returns the "introduction" feature. This feature can only be described
954 * with {@link TextData text data}.
956 * @see #isSupportsTextData()
958 public static final Feature
INTRODUCTION(){
959 return getTermByUuid(uuidIntroduction
);
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}.
968 * @see #isSupportsTextData()
970 public static final Feature
PROTOLOGUE(){
971 return getTermByUuid(uuidProtologue
);
975 * Returns the "common_name" feature. This feature allows to handle only
976 * {@link CommonTaxonName common names}.
978 * @see #isSupportsCommonTaxonName()
980 public static final Feature
COMMON_NAME(){
981 return getTermByUuid(uuidCommonName
);
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").
993 public static final Feature
PHENOLOGY(){
994 return getTermByUuid(uuidPhenology
);
998 * Returns the "occurrence" feature.
1000 public static final Feature
OCCURRENCE(){
1001 return getTermByUuid(uuidOccurrence
);
1005 * Returns the "anatomy" feature.
1007 public static final Feature
ANATOMY(){
1008 return getTermByUuid(uuidAnatomy
);
1012 * Returns the "hostplant" feature.
1014 public static final Feature
HOSTPLANT(){
1015 return getTermByUuid(uuidHostPlant
);
1019 * Returns the "pathogen agent" feature.
1021 public static final Feature
PATHOGEN_AGENT(){
1022 return getTermByUuid(uuidPathogenAgent
);
1026 * Returns the "citation" feature. This feature can only be described
1027 * with {@link TextData text data}.
1029 * @see #isSupportsTextData()
1031 public static final Feature
CITATION(){
1032 return getTermByUuid(uuidCitation
);
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}.
1042 * @see #isSupportsTextData()
1044 public static final Feature
ADDITIONAL_PUBLICATION(){
1045 return getTermByUuid(uuidAdditionalPublication
);
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").
1054 public static final Feature
USES(){
1055 return getTermByUuid(uuidUses
);
1058 public static final Feature
USERECORD(){
1059 return getTermByUuid(uuidUseRecord
);
1063 * Returns the "notes" feature. Used for
1066 public static final Feature
NOTES(){
1067 return getTermByUuid(uuidNotes
);
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>
1075 public static final Feature
CONSERVATION(){
1076 return getTermByUuid(uuidConservation
);
1080 * Returns the "cultivation" feature.
1082 public static final Feature
CULTIVATION(){
1083 return getTermByUuid(uuidCultivation
);
1087 * Returns the "image" feature.
1089 public static final Feature
IMAGE(){
1090 return getTermByUuid(uuidImage
);
1094 * Returns the "individuals association" feature.
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
;
1106 public static final Feature
SPECIMEN(){
1107 return getTermByUuid(uuidSpecimen
);
1110 public static final Feature
OBSERVATION(){
1111 return getTermByUuid(uuidObservation
);
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
1120 public static final Feature
STATUS(){
1121 return getTermByUuid(uuidStatus
);
1124 public static final Feature
SYSTEMATICS(){
1125 return getTermByUuid(uuidSystematics
);
1128 public static final Feature
LIFEFORM(){
1129 return getTermByUuid(uuidLifeform
);
1132 public static final Feature
FLOWERING_PERIOD(){
1133 return getTermByUuid(uuidFloweringPeriod
);
1136 public static final Feature
FRUITING_PERIOD(){
1137 return getTermByUuid(uuidFruitingPeriod
);
1140 public static final Feature
ALTITUDE(){
1141 return getTermByUuid(uuidAltitude
);
1145 // * Returns the "hybrid_parent" feature. This feature can only be used
1146 // * by {@link TaxonInteraction taxon interactions}.<BR>
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.
1153 // * @see #isSupportsTaxonInteraction()
1154 // * @see HybridRelationshipType
1156 // public static final Feature HYBRID_PARENT(){
1158 // logger.warn("HYBRID_PARENT not yet implemented");
1163 protected void setDefaultTerms(TermVocabulary
<Feature
> termVocabulary
) {
1164 if (termMap
== null){ //needed because there are multiple feature vocabularies
1165 termMap
= new HashMap
<>();
1167 for (Feature term
: termVocabulary
.getTerms()){
1168 termMap
.put(term
.getUuid(), term
);
1172 //*********************************** CLONE *********************************************************/
1175 public Feature
clone() {
1176 Feature result
= (Feature
)super.clone();
1178 result
.inverseRepresentations
= new HashSet
<Representation
>();
1179 for (Representation rep
: this.inverseRepresentations
){
1180 result
.addInverseRepresentation(rep
.clone());
1183 //no changes to: symmetric, transitiv