ref #8162 move FeatureTree and FeatureNode to term package
[cdmlib.git] / cdmlib-model / src / main / java / eu / etaxonomy / cdm / model / description / Feature.java
1 /**
2 * Copyright (C) 2007 EDIT
3 * European Distributed Institute of Taxonomy
4 * http://www.e-taxonomy.eu
5 *
6 * The contents of this file are subject to the Mozilla Public License Version 1.1
7 * See LICENSE.TXT at the top of this package for the full license terms.
8 */
9
10 package eu.etaxonomy.cdm.model.description;
11
12
13 import java.util.HashMap;
14 import java.util.HashSet;
15 import java.util.List;
16 import java.util.Map;
17 import java.util.Set;
18 import java.util.UUID;
19
20 import javax.persistence.Entity;
21 import javax.persistence.FetchType;
22 import javax.persistence.JoinColumn;
23 import javax.persistence.JoinTable;
24 import javax.persistence.ManyToMany;
25 import javax.persistence.OneToMany;
26 import javax.persistence.Transient;
27 import javax.xml.bind.annotation.XmlAccessType;
28 import javax.xml.bind.annotation.XmlAccessorType;
29 import javax.xml.bind.annotation.XmlElement;
30 import javax.xml.bind.annotation.XmlElementWrapper;
31 import javax.xml.bind.annotation.XmlIDREF;
32 import javax.xml.bind.annotation.XmlRootElement;
33 import javax.xml.bind.annotation.XmlSchemaType;
34 import javax.xml.bind.annotation.XmlType;
35
36 import org.apache.log4j.Logger;
37 import org.hibernate.annotations.Cascade;
38 import org.hibernate.annotations.CascadeType;
39 import org.hibernate.envers.Audited;
40
41 import eu.etaxonomy.cdm.model.common.Language;
42 import eu.etaxonomy.cdm.model.name.HybridRelationshipType;
43 import eu.etaxonomy.cdm.model.name.NomenclaturalCode;
44 import eu.etaxonomy.cdm.model.name.TaxonName;
45 import eu.etaxonomy.cdm.model.taxon.Taxon;
46 import eu.etaxonomy.cdm.model.term.DefinedTerm;
47 import eu.etaxonomy.cdm.model.term.DefinedTermBase;
48 import eu.etaxonomy.cdm.model.term.FeatureTree;
49 import eu.etaxonomy.cdm.model.term.Representation;
50 import eu.etaxonomy.cdm.model.term.TermType;
51 import eu.etaxonomy.cdm.model.term.TermVocabulary;
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 TaxonName 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 * @since 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 "inverseRepresentations"
100 })
101 @XmlRootElement(name = "Feature")
102 @Entity
103 //@Indexed disabled to reduce clutter in indexes, since this type is not used by any search
104 //@Indexed(index = "eu.etaxonomy.cdm.model.term.DefinedTermBase")
105 @Audited
106 public class Feature extends DefinedTermBase<Feature> {
107 private static final long serialVersionUID = 6754598791831848704L;
108 private static final Logger logger = Logger.getLogger(Feature.class);
109
110 protected static Map<UUID, Feature> termMap = null;
111
112 private boolean supportsTextData = true; //by default text data should be always supported
113
114 private boolean supportsQuantitativeData;
115
116 private boolean supportsDistribution;
117
118 private boolean supportsIndividualAssociation;
119
120 private boolean supportsTaxonInteraction;
121
122 private boolean supportsCategoricalData;
123
124 private boolean supportsCommonTaxonName;
125
126 /* for M:M see #4843 */
127 @ManyToMany(fetch = FetchType.LAZY)
128 @JoinTable(name="DefinedTermBase_RecommendedModifierEnumeration")
129 private final Set<TermVocabulary<DefinedTerm>> recommendedModifierEnumeration = new HashSet<>();
130
131 @ManyToMany(fetch = FetchType.LAZY)
132 @JoinTable(name="DefinedTermBase_StatisticalMeasure")
133 private final Set<StatisticalMeasure> recommendedStatisticalMeasures = new HashSet<>();
134
135 /* for M:M see #4843 */
136 @ManyToMany(fetch = FetchType.LAZY)
137 @JoinTable(name="DefinedTermBase_SupportedCategoricalEnumeration")
138 private final Set<TermVocabulary<State>> supportedCategoricalEnumerations = new HashSet<>();
139
140
141 @ManyToMany(fetch = FetchType.LAZY)
142 @JoinTable(name="DefinedTermBase_MeasurementUnit")
143 private final Set<MeasurementUnit> recommendedMeasurementUnits = new HashSet<>();
144
145
146 //copy from RelationshipTermBase
147 @XmlElementWrapper(name = "InverseRepresentations")
148 @XmlElement(name = "Representation")
149 @OneToMany(fetch = FetchType.LAZY, orphanRemoval=true)
150 @JoinTable(name="DefinedTermBase_InverseRepresentation", //see also RelationshipTermBase.inverseRepresentations
151 joinColumns=@JoinColumn(name="DefinedTermBase_id")
152 // inverseJoinColumns
153 )
154 @Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE, CascadeType.DELETE})
155 // @IndexedEmbedded(depth = 2)
156 private Set<Representation> inverseRepresentations = new HashSet<>();
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 private 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 private 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
197
198 /* ***************** CONSTRUCTOR AND FACTORY METHODS **********************************/
199
200
201 /**
202 * Creates a new empty feature instance.
203 *
204 * @see #NewInstance(String, String, String)
205 */
206 public static Feature NewInstance() {
207 return new Feature();
208 }
209
210 /**
211 * Creates a new feature instance with a description (in the {@link Language#DEFAULT() default language}),
212 * a label and a label abbreviation.
213 *
214 * @param description the string (in the default language) describing the
215 * new feature to be created
216 * @param label the string identifying the new feature to be created
217 * @param labelAbbrev the string identifying (in abbreviated form) the
218 * new feature to be created
219 * @see #readCsvLine(List, Language)
220 * @see #NewInstance()
221 */
222 public static Feature NewInstance(String description, String label, String labelAbbrev){
223 return new Feature(description, label, labelAbbrev);
224 }
225
226
227 //for hibernate use only
228 @Deprecated
229 protected Feature() {
230 super(TermType.Feature);
231 }
232
233 /**
234 * Class constructor: creates a new feature instance with a description (in the {@link Language#DEFAULT() default language}),
235 * a label and a label abbreviation.
236 *
237 * @param term the string (in the default language) describing the
238 * new feature to be created
239 * @param label the string identifying the new feature to be created
240 * @param labelAbbrev the string identifying (in abbreviated form) the
241 * new feature to be created
242 * @see #Feature()
243 */
244 protected Feature(String term, String label, String labelAbbrev) {
245 super(TermType.Feature, term, label, labelAbbrev);
246 }
247
248 /* *************************************************************************************/
249
250 @Override
251 public void resetTerms(){
252 termMap = null;
253 }
254
255
256 /**
257 * Returns the boolean value of the flag indicating whether <i>this</i>
258 * feature can be described with {@link QuantitativeData quantitative data} (true)
259 * or not (false). If this flag is set <i>this</i> feature can only apply to
260 * {@link TaxonDescription taxon descriptions} or {@link SpecimenDescription specimen descriptions}.
261 *
262 * @return the boolean value of the supportsQuantitativeData flag
263 */
264 @XmlElement(name = "SupportsQuantitativeData")
265 public boolean isSupportsQuantitativeData() {
266 return supportsQuantitativeData;
267 }
268
269 /**
270 * @see #isSupportsQuantitativeData()
271 */
272 public void setSupportsQuantitativeData(boolean supportsQuantitativeData) {
273 this.supportsQuantitativeData = supportsQuantitativeData;
274 }
275
276 /**
277 * Returns the boolean value of the flag indicating whether <i>this</i>
278 * feature can be described with {@link TextData text data} (true)
279 * or not (false).
280 *
281 * @return the boolean value of the supportsTextData flag
282 */
283 @XmlElement(name = "SupportsTextData")
284 public boolean isSupportsTextData() {
285 return supportsTextData;
286 }
287
288 /**
289 * @see #isSupportsTextData()
290 */
291 public void setSupportsTextData(boolean supportsTextData) {
292 this.supportsTextData = supportsTextData;
293 }
294
295 /**
296 * Returns the boolean value of the flag indicating whether <i>this</i>
297 * feature can be described with {@link Distribution distribution} objects
298 * (true) or not (false). This flag is set if and only if <i>this</i> feature
299 * is the {@link #DISTRIBUTION() distribution feature}.
300 *
301 * @return the boolean value of the supportsDistribution flag
302 */
303 @XmlElement(name = "SupportsDistribution")
304 public boolean isSupportsDistribution() {
305 return supportsDistribution;
306 }
307
308 /**
309 * @see #isSupportsDistribution()
310 */
311 public void setSupportsDistribution(boolean supportsDistribution) {
312 this.supportsDistribution = supportsDistribution;
313 }
314
315 /**
316 * Returns the boolean value of the flag indicating whether <i>this</i>
317 * feature can be described with {@link IndividualsAssociation individuals associations}
318 * (true) or not (false).
319 *
320 * @return the boolean value of the supportsIndividualAssociation flag
321 */
322 @XmlElement(name = "SupportsIndividualAssociation")
323 public boolean isSupportsIndividualAssociation() {
324 return supportsIndividualAssociation;
325 }
326
327 /**
328 * @see #isSupportsIndividualAssociation()
329 */
330 public void setSupportsIndividualAssociation(
331 boolean supportsIndividualAssociation) {
332 this.supportsIndividualAssociation = supportsIndividualAssociation;
333 }
334
335 /**
336 * Returns the boolean value of the flag indicating whether <i>this</i>
337 * feature can be described with {@link TaxonInteraction taxon interactions}
338 * (true) or not (false).
339 *
340 * @return the boolean value of the supportsTaxonInteraction flag
341 */
342 @XmlElement(name = "SupportsTaxonInteraction")
343 public boolean isSupportsTaxonInteraction() {
344 return supportsTaxonInteraction;
345 }
346
347 /**
348 * @see #isSupportsTaxonInteraction()
349 */
350 public void setSupportsTaxonInteraction(boolean supportsTaxonInteraction) {
351 this.supportsTaxonInteraction = supportsTaxonInteraction;
352 }
353
354 /**
355 * Returns the boolean value of the flag indicating whether <i>this</i>
356 * feature can be described with {@link CommonTaxonName common names}
357 * (true) or not (false). This flag is set if and only if <i>this</i> feature
358 * is the {@link #COMMON_NAME() common name feature}.
359 *
360 * @return the boolean value of the supportsCommonTaxonName flag
361 */
362 @XmlElement(name = "SupportsCommonTaxonName")
363 public boolean isSupportsCommonTaxonName() {
364 return supportsCommonTaxonName;
365 }
366
367 /**
368 * @see #isSupportsTaxonInteraction()
369 */
370 public void setSupportsCommonTaxonName(boolean supportsCommonTaxonName) {
371 this.supportsCommonTaxonName = supportsCommonTaxonName;
372 }
373
374 /**
375 * Returns the boolean value of the flag indicating whether <i>this</i>
376 * feature can be described with {@link CategoricalData categorical data}
377 * (true) or not (false).
378 *
379 * @return the boolean value of the supportsCategoricalData flag
380 */
381 @XmlElement(name = "SupportsCategoricalData")
382 public boolean isSupportsCategoricalData() {
383 return supportsCategoricalData;
384 }
385
386 /**
387 * @see #supportsCategoricalData()
388 */
389 public void setSupportsCategoricalData(boolean supportsCategoricalData) {
390 this.supportsCategoricalData = supportsCategoricalData;
391 }
392
393
394 /**
395 * Returns the set of {@link TermVocabulary term vocabularies} containing the
396 * {@link Modifier modifiers} recommended to be used for {@link DescriptionElementBase description elements}
397 * with <i>this</i> feature.
398 *
399 */
400 @XmlElementWrapper(name = "RecommendedModifierEnumerations")
401 @XmlElement(name = "RecommendedModifierEnumeration")
402 @XmlIDREF
403 @XmlSchemaType(name = "IDREF")
404 public Set<TermVocabulary<DefinedTerm>> getRecommendedModifierEnumeration() {
405 return recommendedModifierEnumeration;
406 }
407
408 /**
409 * Adds a {@link TermVocabulary term vocabulary} (with {@link Modifier modifiers}) to the set of
410 * {@link #getRecommendedModifierEnumeration() recommended modifier vocabularies} assigned
411 * to <i>this</i> feature.
412 *
413 * @param recommendedModifierEnumeration the term vocabulary to be added
414 * @see #getRecommendedModifierEnumeration()
415 */
416 public void addRecommendedModifierEnumeration(
417 TermVocabulary<DefinedTerm> recommendedModifierEnumeration) {
418 this.recommendedModifierEnumeration.add(recommendedModifierEnumeration);
419 }
420 /**
421 * Removes one element from the set of {@link #getRecommendedModifierEnumeration() recommended modifier vocabularies}
422 * assigned to <i>this</i> feature.
423 *
424 * @param recommendedModifierEnumeration the term vocabulary which should be removed
425 * @see #getRecommendedModifierEnumeration()
426 * @see #addRecommendedModifierEnumeration(TermVocabulary)
427 */
428 public void removeRecommendedModifierEnumeration(
429 TermVocabulary<DefinedTerm> recommendedModifierEnumeration) {
430 this.recommendedModifierEnumeration.remove(recommendedModifierEnumeration);
431 }
432
433 /**
434 * Returns the set of {@link StatisticalMeasure statistical measures} recommended to be used
435 * in case of {@link QuantitativeData quantitative data} with <i>this</i> feature.
436 */
437 @XmlElementWrapper(name = "RecommendedStatisticalMeasures")
438 @XmlElement(name = "RecommendedStatisticalMeasure")
439 @XmlIDREF
440 @XmlSchemaType(name = "IDREF")
441 public Set<StatisticalMeasure> getRecommendedStatisticalMeasures() {
442 return recommendedStatisticalMeasures;
443 }
444
445 /**
446 * Adds a {@link StatisticalMeasure statistical measure} to the set of
447 * {@link #getRecommendedStatisticalMeasures() recommended statistical measures} assigned
448 * to <i>this</i> feature.
449 *
450 * @param recommendedStatisticalMeasure the statistical measure to be added
451 * @see #getRecommendedStatisticalMeasures()
452 */
453 public void addRecommendedStatisticalMeasure(
454 StatisticalMeasure recommendedStatisticalMeasure) {
455 this.recommendedStatisticalMeasures.add(recommendedStatisticalMeasure);
456 }
457 /**
458 * Removes one element from the set of {@link #getRecommendedStatisticalMeasures() recommended statistical measures}
459 * assigned to <i>this</i> feature.
460 *
461 * @param recommendedStatisticalMeasure the statistical measure which should be removed
462 * @see #getRecommendedStatisticalMeasures()
463 * @see #addRecommendedStatisticalMeasure(StatisticalMeasure)
464 */
465 public void removeRecommendedStatisticalMeasure(
466 StatisticalMeasure recommendedStatisticalMeasure) {
467 this.recommendedStatisticalMeasures.remove(recommendedStatisticalMeasure);
468 }
469
470 /**
471 * Returns the set of {@link StatisticalMeasure statistical measures} recommended to be used
472 * in case of {@link QuantitativeData quantitative data} with <i>this</i> feature.
473 */
474 @XmlElementWrapper(name = "RecommendedMeasurementUnits")
475 @XmlElement(name = "RecommendedMeasurementUnit")
476 @XmlIDREF
477 @XmlSchemaType(name = "IDREF")
478 public Set<MeasurementUnit> getRecommendedMeasurementUnits() {
479 return recommendedMeasurementUnits;
480 }
481
482 /**
483 * Adds a {@link StatisticalMeasure statistical measure} to the set of
484 * {@link #getRecommendedStatisticalMeasures() recommended statistical measures} assigned
485 * to <i>this</i> feature.
486 *
487 * @param recommendedStatisticalMeasure the statistical measure to be added
488 * @see #getRecommendedStatisticalMeasures()
489 */
490 public void addRecommendedMeasurementUnit(
491 MeasurementUnit recommendedMeasurementUnit) {
492 this.recommendedMeasurementUnits.add(recommendedMeasurementUnit);
493 }
494 /**
495 * Removes one element from the set of {@link #getRecommendedStatisticalMeasures() recommended statistical measures}
496 * assigned to <i>this</i> feature.
497 *
498 * @param recommendedStatisticalMeasure the statistical measure which should be removed
499 * @see #getRecommendedStatisticalMeasures()
500 * @see #addRecommendedStatisticalMeasure(StatisticalMeasure)
501 */
502 public void removeRecommendedMeasurementUnit(
503 MeasurementUnit recommendedMeasurementUnit) {
504 this.recommendedMeasurementUnits.remove(recommendedMeasurementUnit);
505 }
506
507 /**
508 * Returns the set of {@link TermVocabulary term vocabularies} containing the list of
509 * possible {@link State states} to be used in {@link CategoricalData categorical data}
510 * with <i>this</i> feature.
511 *
512 */
513 @XmlElementWrapper(name = "SupportedCategoricalEnumerations")
514 @XmlElement(name = "SupportedCategoricalEnumeration")
515 @XmlIDREF
516 @XmlSchemaType(name = "IDREF")
517 public Set<TermVocabulary<State>> getSupportedCategoricalEnumerations() {
518 return supportedCategoricalEnumerations;
519 }
520
521 /**
522 * Adds a {@link TermVocabulary term vocabulary} to the set of
523 * {@link #getSupportedCategoricalEnumerations() supported state vocabularies} assigned
524 * to <i>this</i> feature.
525 *
526 * @param supportedCategoricalEnumeration the term vocabulary which should be removed
527 * @see #getSupportedCategoricalEnumerations()
528 */
529 public void addSupportedCategoricalEnumeration(
530 TermVocabulary<State> supportedCategoricalEnumeration) {
531 this.supportedCategoricalEnumerations.add(supportedCategoricalEnumeration);
532 }
533 /**
534 * Removes one element from the set of {@link #getSupportedCategoricalEnumerations() supported state vocabularies}
535 * assigned to <i>this</i> feature.
536 *
537 * @param supportedCategoricalEnumeration the term vocabulary which should be removed
538 * @see #getSupportedCategoricalEnumerations()
539 * @see #addSupportedCategoricalEnumeration(TermVocabulary)
540 */
541 public void removeSupportedCategoricalEnumeration(
542 TermVocabulary<State> supportedCategoricalEnumeration) {
543 this.supportedCategoricalEnumerations.remove(supportedCategoricalEnumeration);
544 }
545
546 @XmlElement(name = "KindOf", namespace = "http://etaxonomy.eu/cdm/model/common/1.0")
547 @XmlIDREF
548 @XmlSchemaType(name = "IDREF")
549 @Override
550 public Feature getKindOf(){
551 return super.getKindOf();
552 }
553
554 @Override
555 public void setKindOf(Feature kindOf){
556 super.setKindOf(kindOf);
557 }
558
559 @Override
560 @XmlElement(name = "PartOf", namespace = "http://etaxonomy.eu/cdm/model/common/1.0")
561 @XmlIDREF
562 @XmlSchemaType(name = "IDREF")
563 public Feature getPartOf(){
564 return super.getPartOf();
565 }
566
567 @Override
568 public void setPartOf(Feature partOf){
569 super.setPartOf(partOf);
570 }
571
572 @Override
573 @XmlElementWrapper(name = "Generalizations", namespace = "http://etaxonomy.eu/cdm/model/common/1.0")
574 @XmlElement(name = "GeneralizationOf", namespace = "http://etaxonomy.eu/cdm/model/common/1.0")
575 @XmlIDREF
576 @XmlSchemaType(name = "IDREF")
577 public Set<Feature> getGeneralizationOf(){
578 return super.getGeneralizationOf();
579 }
580
581 @Override
582 protected void setGeneralizationOf(Set<Feature> value){
583 super.setGeneralizationOf(value);
584 }
585
586 @Override
587 @XmlElementWrapper(name = "Includes", namespace = "http://etaxonomy.eu/cdm/model/common/1.0")
588 @XmlElement(name = "Include", namespace = "http://etaxonomy.eu/cdm/model/common/1.0")
589 @XmlIDREF
590 @XmlSchemaType(name = "IDREF")
591 public Set<Feature> getIncludes(){
592 return super.getIncludes();
593 }
594
595 @Override
596 protected void setIncludes(Set<Feature> includes) {
597 super.setIncludes(includes);
598 }
599
600 // ***************** Invers Label *****************************************/
601
602 public Set<Representation> getInverseRepresentations() {
603 return inverseRepresentations;
604 }
605 public void addInverseRepresentation(Representation inverseRepresentation) {
606 this.inverseRepresentations.add(inverseRepresentation);
607 }
608 public void removeInverseRepresentation(Representation inverseRepresentation) {
609 this.inverseRepresentations.remove(inverseRepresentation);
610 }
611 /*
612 * Inverse representation convenience methods similar to TermBase.xxx
613 * @see eu.etaxonomy.cdm.model.term.TermBase#getLabel()
614 */
615 @Transient
616 public String getInverseLabel() {
617 if(getInverseLabel(Language.DEFAULT()) != null){
618 return this.getInverseRepresentation(Language.DEFAULT()).getLabel();
619 }else{
620 for (Representation r : inverseRepresentations){
621 return r.getLabel();
622 }
623 }
624 return super.getUuid().toString();
625 }
626 public String getInverseLabel(Language lang) {
627 Representation r = this.getInverseRepresentation(lang);
628 if(r==null){
629 return null;
630 }else{
631 return r.getLabel();
632 }
633 }
634 public Representation getInverseRepresentation(Language lang) {
635 Representation result = null;
636 for (Representation repr : this.getInverseRepresentations()){
637 if (lang.equals(repr.getLanguage())){
638 result = repr;
639 }
640 }
641 return result;
642 }
643 // ****************** END INVERS REPRESENTATION **************************/
644
645 /**
646 * Creates and returns a new feature instance on the basis of a given string
647 * list (containing an UUID, an URI, a label and a description) and a given
648 * {@link Language language} to be associated with the description. Furthermore
649 * the flags concerning the supported subclasses of {@link DescriptionElementBase description elements}
650 * are set according to a particular string belonging to the given
651 * string list.<BR>
652 * This method overrides the readCsvLine method from {@link DefinedTermBase#readCsvLine(List, Language) DefinedTermBase}.
653 *
654 * @param csvLine the string list with elementary information for attributes
655 * @param lang the language in which the description has been formulated
656 * @see #NewInstance(String, String, String)
657 */
658 @Override
659 public Feature readCsvLine(Class<Feature> termClass, List<String> csvLine, TermType termType,
660 Map<UUID,DefinedTermBase> terms, boolean abbrevAsId) {
661 Feature newInstance = super.readCsvLine(termClass, csvLine, termType, terms, abbrevAsId);
662 String text = csvLine.get(4);
663 if (text != null && text.length() >= 6){
664 if ("1".equals(text.substring(0, 1))){newInstance.setSupportsTextData(true);}
665 if ("1".equals(text.substring(1, 2))){newInstance.setSupportsQuantitativeData(true);}
666 if ("1".equals(text.substring(2, 3))){newInstance.setSupportsDistribution(true);}
667 if ("1".equals(text.substring(3, 4))){newInstance.setSupportsIndividualAssociation(true);}
668 if ("1".equals(text.substring(4, 5))){newInstance.setSupportsTaxonInteraction(true);}
669 if ("1".equals(text.substring(5, 6))){newInstance.setSupportsCommonTaxonName(true);}
670 if (text.length() > 6 && "1".equals(text.substring(6, 7))){newInstance.setSupportsCategoricalData(true);}
671 //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
672 newInstance.getRepresentation(Language.DEFAULT()).setAbbreviatedLabel(null);
673 }
674 return newInstance;
675 }
676
677 //******************************* STATIC METHODS *****************************************
678
679 protected static Feature getTermByUuid(UUID uuid){
680 if (termMap == null || termMap.isEmpty()){
681 return getTermByClassAndUUID(Feature.class, uuid);
682 } else {
683 return termMap.get(uuid);
684 }
685 }
686
687 /**
688 * Returns the "unknown" feature. This feature allows to store values of
689 * {@link DescriptionElementBase description elements} even if it is momentarily
690 * not known what they mean.
691 */
692 public static final Feature UNKNOWN(){
693 return getTermByUuid(uuidUnknown);
694 }
695
696 /**
697 * Returns the "description" feature. This feature allows to handle global
698 * {@link DescriptionElementBase description elements} for a global {@link DescriptionBase description}.<BR>
699 * The "description" feature is the highest level feature.
700 */
701 public static final Feature DESCRIPTION(){
702 return getTermByUuid(uuidDescription);
703 }
704
705 /**
706 * Returns the "distribution" feature. This feature allows to handle only
707 * {@link Distribution distributions}.
708 *
709 * @see #isSupportsDistribution()
710 */
711 public static final Feature DISTRIBUTION(){
712 return getTermByUuid(uuidDistribution);
713 }
714
715 /**
716 * Returns the feature for general text-based
717 * distributions
718 */
719 public static final Feature DISTRIBUTION_GENERAL(){
720 return getTermByUuid(uuidDistributionGeneral);
721 }
722
723 /**
724 * Returns the "discussion" feature. This feature can only be described
725 * with {@link TextData text data}.
726 *
727 * @see #isSupportsTextData()
728 */
729 public static final Feature DISCUSSION(){
730 return getTermByUuid(uuidDiscussion);
731 }
732
733 /**
734 * Returns the "ecology" feature. This feature only applies
735 * to {@link SpecimenDescription specimen descriptions} or to {@link TaxonDescription taxon descriptions}.<BR>
736 * The "ecology" feature generalizes all other possible features concerning
737 * ecological matters.
738 */
739 public static final Feature ECOLOGY(){
740 return getTermByUuid(uuidEcology);
741 }
742
743 /**
744 * Returns the "habitat" feature. This feature only applies
745 * to {@link SpecimenDescription specimen descriptions} or to {@link TaxonDescription taxon descriptions}.<BR>
746 * The "habitat" feature generalizes all other possible features concerning
747 * habitat matters.
748 */
749 public static final Feature HABITAT(){
750 return getTermByUuid(uuidHabitat);
751 }
752
753
754 /**
755 * Returns the "habitat & ecology" feature. This feature only applies
756 * to {@link SpecimenDescription specimen descriptions} or to {@link TaxonDescription taxon descriptions}.<BR>
757 * The "habitat & ecology" feature generalizes all other possible features concerning
758 * habitat and ecology matters.
759 */
760 public static final Feature HABITAT_ECOLOGY(){
761 return getTermByUuid(uuidHabitatAndEcology);
762 }
763
764 /**
765 * Returns the "biology_ecology" feature. This feature only applies
766 * to {@link SpecimenDescription specimen descriptions} or to {@link TaxonDescription taxon descriptions}.<BR>
767 * The "biology_ecology" feature generalizes all possible features concerning
768 * biological aspects of ecological matters.
769 *
770 * @see #ECOLOGY()
771 */
772 public static final Feature BIOLOGY_ECOLOGY(){
773 return getTermByUuid(uuidBiologyEcology);
774 }
775
776 /**
777 * Returns the "chromosome number" feature. This feature only applies
778 * to {@link SpecimenDescription specimen descriptions} or to {@link TaxonDescription taxon descriptions}.<BR>
779 */
780 public static final Feature CHROMOSOME_NUMBER(){
781 return getTermByUuid(uuidChromosomeNumber);
782 }
783
784
785 /**
786 * Returns the "key" feature. This feature is the "upper" feature generalizing
787 * all features being used within an identification key.
788 */
789 public static final Feature KEY(){
790 return getTermByUuid(uuidKey);
791 }
792
793
794 /**
795 * Returns the "materials_examined" feature. This feature can only be described
796 * with {@link TextData text data} or eventually with {@link CategoricalData categorical data}
797 * mentioning which material has been examined in order to accomplish
798 * the description. This feature applies only to
799 * {@link SpecimenDescription specimen descriptions} or to {@link TaxonDescription taxon descriptions}.
800 */
801 public static final Feature MATERIALS_EXAMINED(){
802 return getTermByUuid(uuidMaterialsExamined);
803 }
804
805 /**
806 * Returns the "materials_methods" feature. This feature can only be described
807 * with {@link TextData text data} or eventually with {@link CategoricalData categorical data}
808 * mentioning which methods have been adopted to analyze the material in
809 * order to accomplish the description. This feature applies only to
810 * {@link SpecimenDescription specimen descriptions} or to {@link TaxonDescription taxon descriptions}.
811 */
812 public static final Feature MATERIALS_METHODS(){
813 return getTermByUuid(uuidMaterialsMethods);
814 }
815
816 /**
817 * Returns the "etymology" feature. This feature can only be described
818 * with {@link TextData text data} or eventually with {@link CategoricalData categorical data}
819 * giving some information about the history of the taxon name. This feature applies only to
820 * {@link TaxonNameDescription taxon name descriptions}.
821 */
822 public static final Feature ETYMOLOGY(){
823 return getTermByUuid(uuidEtymology);
824 }
825
826 /**
827 * Returns the "diagnosis" feature. This feature can only be described
828 * with {@link TextData text data} or eventually with {@link CategoricalData categorical data}.
829 * This feature applies only to {@link SpecimenDescription specimen descriptions} or to
830 * {@link TaxonDescription taxon descriptions}.
831 */
832 public static final Feature DIAGNOSIS(){
833 return getTermByUuid(uuidDiagnosis);
834 }
835
836
837 /**
838 * Returns the "introduction" feature. This feature can only be described
839 * with {@link TextData text data}.
840 *
841 * @see #isSupportsTextData()
842 */
843 public static final Feature INTRODUCTION(){
844 return getTermByUuid(uuidIntroduction);
845 }
846
847 /**
848 * Returns the "protologue" feature. This feature can only be described
849 * with {@link TextData text data} reproducing the content of the protologue
850 * (or some information about it) of the taxon name. This feature applies only to
851 * {@link TaxonNameDescription taxon name descriptions}.
852 *
853 * @see #isSupportsTextData()
854 */
855 public static final Feature PROTOLOGUE(){
856 return getTermByUuid(uuidProtologue);
857 }
858
859 /**
860 * Returns the "common_name" feature. This feature allows to handle only
861 * {@link CommonTaxonName common names}.
862 *
863 * @see #isSupportsCommonTaxonName()
864 */
865 public static final Feature COMMON_NAME(){
866 return getTermByUuid(uuidCommonName);
867 }
868
869 /**
870 * Returns the "phenology" feature. This feature can only be described
871 * with {@link CategoricalData categorical data} or eventually with {@link TextData text data}
872 * containing information time about recurring natural phenomena.
873 * This feature only applies to {@link TaxonDescription taxon descriptions}.<BR>
874 * The "phenology" feature generalizes all other possible features
875 * concerning time information about particular natural phenomena
876 * (such as "first flight of butterflies").
877 */
878 public static final Feature PHENOLOGY(){
879 return getTermByUuid(uuidPhenology);
880 }
881
882 /**
883 * Returns the "occurrence" feature.
884 */
885 public static final Feature OCCURRENCE(){
886 return getTermByUuid(uuidOccurrence);
887 }
888
889 /**
890 * Returns the "anatomy" feature.
891 */
892 public static final Feature ANATOMY(){
893 return getTermByUuid(uuidAnatomy);
894 }
895 /**
896 * Returns the "hostplant" feature.
897 */
898 public static final Feature HOSTPLANT(){
899 return getTermByUuid(uuidHostPlant);
900 }
901 /**
902 * Returns the "pathogen agent" feature.
903 */
904 public static final Feature PATHOGEN_AGENT(){
905 return getTermByUuid(uuidPathogenAgent);
906 }
907
908 /**
909 * Returns the "citation" feature. This feature can only be described
910 * with {@link TextData text data}.
911 *
912 * @see #isSupportsTextData()
913 */
914 public static final Feature CITATION(){
915 return getTermByUuid(uuidCitation);
916 }
917
918 /**
919 * Returns the "additional_publication" feature. This feature can only be
920 * described with {@link TextData text data} with information about a
921 * publication where a {@link TaxonName taxon name} has also been published
922 * but which is not the {@link TaxonName#getNomenclaturalReference() nomenclatural reference}.
923 * This feature applies only to {@link TaxonNameDescription taxon name descriptions}.
924 *
925 * @see #isSupportsTextData()
926 */
927 public static final Feature ADDITIONAL_PUBLICATION(){
928 return getTermByUuid(uuidAdditionalPublication);
929 }
930
931
932 /**
933 * Returns the "uses" feature. This feature only applies
934 * to {@link TaxonDescription taxon descriptions}.<BR>
935 * The "uses" feature generalizes all other possible features concerning
936 * particular uses (for instance "industrial use of seeds").
937 */
938 public static final Feature USES(){
939 return getTermByUuid(uuidUses);
940 }
941
942 public static final Feature USERECORD(){
943 return getTermByUuid(uuidUseRecord);
944 }
945
946 /**
947 * Returns the "notes" feature. Used for
948 * taxonomic notes.
949 */
950 public static final Feature NOTES(){
951 return getTermByUuid(uuidNotes);
952 }
953
954 /**
955 * Returns the "conservation" feature. This feature only applies
956 * to {@link SpecimenDescription specimen descriptions} and generalizes
957 * methods and conditions for the conservation of {@link Specimen specimens}.<BR>
958 */
959 public static final Feature CONSERVATION(){
960 return getTermByUuid(uuidConservation);
961 }
962
963
964 /**
965 * Returns the "cultivation" feature.
966 */
967 public static final Feature CULTIVATION(){
968 return getTermByUuid(uuidCultivation);
969 }
970
971
972 /**
973 * Returns the "image" feature.
974 */
975 public static final Feature IMAGE(){
976 return getTermByUuid(uuidImage);
977 }
978
979 /**
980 * Returns the "individuals association" feature.
981 */
982 public static final Feature INDIVIDUALS_ASSOCIATION(){
983 Feature individuals_association = getTermByUuid(uuidIndividualsAssociation);
984 Set<Feature> generalizationOf = new HashSet<>();
985 generalizationOf.add(SPECIMEN());
986 generalizationOf.add(OBSERVATION());
987 individuals_association.setGeneralizationOf(generalizationOf);
988 return individuals_association;
989
990 }
991
992 public static final Feature SPECIMEN(){
993 return getTermByUuid(uuidSpecimen);
994 }
995
996 public static final Feature OBSERVATION(){
997 return getTermByUuid(uuidObservation);
998 }
999
1000 /**
1001 * The status of a taxon. Usually the status should be determined within a {@link Distribution distribution}.
1002 * If this is not possible for some reason (e.g. the area is not well defined) the status feature
1003 * may be used.
1004 * @return
1005 */
1006 public static final Feature STATUS(){
1007 return getTermByUuid(uuidStatus);
1008 }
1009
1010 public static final Feature SYSTEMATICS(){
1011 return getTermByUuid(uuidSystematics);
1012 }
1013
1014 public static final Feature LIFEFORM(){
1015 return getTermByUuid(uuidLifeform);
1016 }
1017
1018 /**
1019 * Returns the "hybrid_parent" feature. This feature can only be used
1020 * by {@link TaxonInteraction taxon interactions}.<BR>
1021 * <P>
1022 * Note: It must be distinguished between hybrid relationships as
1023 * relevant nomenclatural relationships between {@link BotanicalName plant names}
1024 * on the one side and the biological relation between two {@link Taxon taxa}
1025 * as it is here the case on the other one.
1026 *
1027 * @see #isSupportsTaxonInteraction()
1028 * @see HybridRelationshipType
1029 */
1030 public static final Feature HYBRID_PARENT(){
1031 //TODO
1032 logger.warn("HYBRID_PARENT not yet implemented");
1033 return null;
1034 }
1035
1036 @Override
1037 protected void setDefaultTerms(TermVocabulary<Feature> termVocabulary) {
1038 if (termMap == null){ //needed because there are multiple feature vocabularies
1039 termMap = new HashMap<UUID, Feature>();
1040 }
1041 for (Feature term : termVocabulary.getTerms()){
1042 termMap.put(term.getUuid(), term);
1043 }
1044 }
1045
1046 //*********************************** CLONE *********************************************************/
1047
1048 @Override
1049 public Object clone() {
1050 Feature result = (Feature)super.clone();
1051
1052 result.inverseRepresentations = new HashSet<Representation>();
1053 for (Representation rep: this.inverseRepresentations){
1054 result.addInverseRepresentation((Representation)rep.clone());
1055 }
1056
1057 //no changes to: symmetric, transitiv
1058 return result;
1059 }
1060
1061 }