f72edf461ac8b4c2bb5c861619d14940b023c2c5
[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.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.HybridRelationshipType;
48 import eu.etaxonomy.cdm.model.name.NomenclaturalCode;
49 import eu.etaxonomy.cdm.model.name.TaxonName;
50 import eu.etaxonomy.cdm.model.taxon.Taxon;
51
52
53 /**
54 * The class for individual properties (also designed as character, type or
55 * category) of observed phenomena able to be described or measured. It also
56 * covers categories of informations on {@link TaxonName taxon names} not
57 * taken in account in {@link NomenclaturalCode nomenclature}.<BR>
58 * Descriptions require features in order to be structured and disaggregated
59 * in {@link DescriptionElementBase description elements}.<BR>
60 * Experts do not use the word feature for the actual description
61 * but only for the property itself. Therefore naming this class FeatureType
62 * would have leaded to confusion.
63 * <P>
64 * Since features are {@link DefinedTermBase defined terms} they have a hierarchical
65 * structure that allows to specify ("kind of") or generalize
66 * ("generalization of") features. "Kind of" / "generalization of" relations
67 * are bidirectional (a feature F1 is a "Kind of" a feature F2 if and only
68 * if the feature F2 is a "generalization of" the feature F1. This hierarchical
69 * structure has nothing in common with {@link FeatureTree feature trees} used for determination.
70 * <P>
71 * A standard set of feature instances will be automatically
72 * created as the project starts. But this class allows to extend this standard
73 * set by creating new instances of additional features if needed.<BR>
74 * <P>
75 * This class corresponds to DescriptionsSectionType according to the SDD
76 * schema.
77 *
78 * @author m.doering
79 * @since 08-Nov-2007 13:06:24
80 */
81 @XmlAccessorType(XmlAccessType.PROPERTY)
82 @XmlType(name="Feature", factoryMethod="NewInstance", propOrder = {
83 "kindOf",
84 "generalizationOf",
85 "partOf",
86 "includes",
87 "supportsTextData",
88 "supportsQuantitativeData",
89 "supportsDistribution",
90 "supportsIndividualAssociation",
91 "supportsTaxonInteraction",
92 "supportsCommonTaxonName",
93 "supportsCategoricalData",
94 "recommendedModifierEnumeration",
95 "recommendedStatisticalMeasures",
96 "supportedCategoricalEnumerations",
97 "recommendedMeasurementUnits",
98 "inverseRepresentations"
99 })
100 @XmlRootElement(name = "Feature")
101 @Entity
102 //@Indexed disabled to reduce clutter in indexes, since this type is not used by any search
103 //@Indexed(index = "eu.etaxonomy.cdm.model.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<>();
129
130 @ManyToMany(fetch = FetchType.LAZY)
131 @JoinTable(name="DefinedTermBase_StatisticalMeasure")
132 private final Set<StatisticalMeasure> recommendedStatisticalMeasures = new HashSet<>();
133
134 /* for M:M see #4843 */
135 @ManyToMany(fetch = FetchType.LAZY)
136 @JoinTable(name="DefinedTermBase_SupportedCategoricalEnumeration")
137 private final Set<TermVocabulary<State>> supportedCategoricalEnumerations = new HashSet<>();
138
139
140 @ManyToMany(fetch = FetchType.LAZY)
141 @JoinTable(name="DefinedTermBase_MeasurementUnit")
142 private final Set<MeasurementUnit> recommendedMeasurementUnits = new HashSet<>();
143
144
145 //copy from RelationshipTermBase
146 @XmlElementWrapper(name = "InverseRepresentations")
147 @XmlElement(name = "Representation")
148 @OneToMany(fetch = FetchType.LAZY, orphanRemoval=true)
149 @JoinTable(name="DefinedTermBase_InverseRepresentation", //see also RelationshipTermBase.inverseRepresentations
150 joinColumns=@JoinColumn(name="DefinedTermBase_id")
151 // inverseJoinColumns
152 )
153 @Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE, CascadeType.DELETE})
154 // @IndexedEmbedded(depth = 2)
155 private Set<Representation> inverseRepresentations = new HashSet<>();
156
157 private static final UUID uuidUnknown = UUID.fromString("910307f1-dc3c-452c-a6dd-af5ac7cd365c");
158 public static final UUID uuidDescription = UUID.fromString("9087cdcd-8b08-4082-a1de-34c9ba9fb493");
159 private static final UUID uuidDistribution = UUID.fromString("9fc9d10c-ba50-49ee-b174-ce83fc3f80c6");
160 private static final UUID uuidDistributionGeneral = UUID.fromString("fd8c64f0-6ea5-44b0-9f70-e95833d6076e");
161 private static final UUID uuidEcology = UUID.fromString("aa923827-d333-4cf5-9a5f-438ae0a4746b");
162 private static final UUID uuidHabitat = UUID.fromString("fb16929f-bc9c-456f-9d40-dec987b36438");
163 private static final UUID uuidHabitatAndEcology = UUID.fromString("9fdc4663-4d56-47d0-90b5-c0bf251bafbb");
164 private static final UUID uuidChromosomeNumber = UUID.fromString("6f677e98-d8d5-4bc5-80bf-affdb7e3945a");
165
166 private static final UUID uuidBiologyEcology = UUID.fromString("9832e24f-b670-43b4-ac7c-20a7261a1d8c");
167 private static final UUID uuidKey = UUID.fromString("a677f827-22b9-4205-bb37-11cb48dd9106");
168 private static final UUID uuidMaterialsExamined = UUID.fromString("7c0c7571-a864-47c1-891d-01f59000dae1");
169 private static final UUID uuidMaterialsMethods = UUID.fromString("1e87d9c3-0844-4a03-9686-773e2ccb3ab6");
170 private static final UUID uuidEtymology = UUID.fromString("dd653d48-355c-4aec-a4e7-724f6eb29f8d");
171 private static final UUID uuidDiagnosis = UUID.fromString("d43d8501-ceab-4caa-9e51-e87138528fac");
172 private static final UUID uuidProtologue = UUID.fromString("71b356c5-1e3f-4f5d-9b0f-c2cf8ae7779f");
173 public static final UUID uuidCommonName = UUID.fromString("fc810911-51f0-4a46-ab97-6562fe263ae5");
174 private static final UUID uuidPhenology = UUID.fromString("a7786d3e-7c58-4141-8416-346d4c80c4a2");
175 private static final UUID uuidOccurrence = UUID.fromString("5deff505-1a32-4817-9a74-50e6936fd630");
176 private static final UUID uuidCitation = UUID.fromString("99b2842f-9aa7-42fa-bd5f-7285311e0101");
177 private static final UUID uuidAdditionalPublication = UUID.fromString("2c355c16-cb04-4858-92bf-8da8d56dea95");
178 public static final UUID uuidUses = UUID.fromString("e5374d39-b210-47c7-bec1-bee05b5f1cb6");
179 private static final UUID uuidConservation = UUID.fromString("4518fc20-2492-47de-b345-777d2b83c9cf");
180 private static final UUID uuidCultivation = UUID.fromString("e28965b2-a367-48c5-b954-8afc8ac2c69b");
181 private static final UUID uuidIntroduction = UUID.fromString("e75255ca-8ff4-4905-baad-f842927fe1d3");
182 private static final UUID uuidDiscussion = UUID.fromString("d3c4cbb6-0025-4322-886b-cd0156753a25");
183 public static final UUID uuidImage = UUID.fromString("84193b2c-327f-4cce-90ef-c8da18fd5bb5");
184 private static final UUID uuidAnatomy = UUID.fromString("94213b2c-e67a-4d37-25ef-e8d316edfba1");
185 private static final UUID uuidHostPlant = UUID.fromString("6e9de1d5-05f0-40d5-8786-2fe30d0d894d");
186 private static final UUID uuidPathogenAgent = UUID.fromString("002d05f2-fd72-49f1-ba4d-196cf09240b5");
187 private static final UUID uuidIndividualsAssociation = UUID.fromString("e2308f37-ddc5-447d-b483-5e2171dd85fd");
188 public static final UUID uuidSpecimen = UUID.fromString("8200e050-d5fd-4cac-8a76-4b47afb13809");
189 private static final UUID uuidObservation = UUID.fromString("f59e747d-0b4f-4bf7-b69a-cbd50bc78595");
190 private static final UUID uuidStatus = UUID.fromString("86d40635-2a63-4ad6-be75-9faa4a6a57fb");
191 private static final UUID uuidSystematics = UUID.fromString("bd9aca17-cd0e-4418-a3a1-1a4b80dbc162");
192 private static final UUID uuidUseRecord = UUID.fromString("8125a59d-b4d5-4485-89ea-67306297b599");
193 private static final UUID uuidNotes = UUID.fromString("b5780b45-6439-4f3c-9818-d89d26d36eb2");
194 public static final UUID uuidLifeform = UUID.fromString("db9228d3-8bbf-4460-abfe-0b1326c82f8e");
195
196
197 /* ***************** CONSTRUCTOR AND FACTORY METHODS **********************************/
198
199
200 /**
201 * Creates a new empty feature instance.
202 *
203 * @see #NewInstance(String, String, String)
204 */
205 public static Feature NewInstance() {
206 return new Feature();
207 }
208
209 /**
210 * Creates a new feature instance with a description (in the {@link Language#DEFAULT() default language}),
211 * a label and a label abbreviation.
212 *
213 * @param description the string (in the default language) describing the
214 * new feature to be created
215 * @param label the string identifying the new feature to be created
216 * @param labelAbbrev the string identifying (in abbreviated form) the
217 * new feature to be created
218 * @see #readCsvLine(List, Language)
219 * @see #NewInstance()
220 */
221 public static Feature NewInstance(String description, String label, String labelAbbrev){
222 return new Feature(description, label, labelAbbrev);
223 }
224
225
226 //for hibernate use only
227 @Deprecated
228 protected Feature() {
229 super(TermType.Feature);
230 }
231
232 /**
233 * Class constructor: creates a new feature instance with a description (in the {@link Language#DEFAULT() default language}),
234 * a label and a label abbreviation.
235 *
236 * @param term the string (in the default language) describing the
237 * new feature to be created
238 * @param label the string identifying the new feature to be created
239 * @param labelAbbrev the string identifying (in abbreviated form) the
240 * new feature to be created
241 * @see #Feature()
242 */
243 protected Feature(String term, String label, String labelAbbrev) {
244 super(TermType.Feature, term, label, labelAbbrev);
245 }
246
247 /* *************************************************************************************/
248
249 @Override
250 public void resetTerms(){
251 termMap = null;
252 }
253
254
255 /**
256 * Returns the boolean value of the flag indicating whether <i>this</i>
257 * feature can be described with {@link QuantitativeData quantitative data} (true)
258 * or not (false). If this flag is set <i>this</i> feature can only apply to
259 * {@link TaxonDescription taxon descriptions} or {@link SpecimenDescription specimen descriptions}.
260 *
261 * @return the boolean value of the supportsQuantitativeData flag
262 */
263 @XmlElement(name = "SupportsQuantitativeData")
264 public boolean isSupportsQuantitativeData() {
265 return supportsQuantitativeData;
266 }
267
268 /**
269 * @see #isSupportsQuantitativeData()
270 */
271 public void setSupportsQuantitativeData(boolean supportsQuantitativeData) {
272 this.supportsQuantitativeData = supportsQuantitativeData;
273 }
274
275 /**
276 * Returns the boolean value of the flag indicating whether <i>this</i>
277 * feature can be described with {@link TextData text data} (true)
278 * or not (false).
279 *
280 * @return the boolean value of the supportsTextData flag
281 */
282 @XmlElement(name = "SupportsTextData")
283 public boolean isSupportsTextData() {
284 return supportsTextData;
285 }
286
287 /**
288 * @see #isSupportsTextData()
289 */
290 public void setSupportsTextData(boolean supportsTextData) {
291 this.supportsTextData = supportsTextData;
292 }
293
294 /**
295 * Returns the boolean value of the flag indicating whether <i>this</i>
296 * feature can be described with {@link Distribution distribution} objects
297 * (true) or not (false). This flag is set if and only if <i>this</i> feature
298 * is the {@link #DISTRIBUTION() distribution feature}.
299 *
300 * @return the boolean value of the supportsDistribution flag
301 */
302 @XmlElement(name = "SupportsDistribution")
303 public boolean isSupportsDistribution() {
304 return supportsDistribution;
305 }
306
307 /**
308 * @see #isSupportsDistribution()
309 */
310 public void setSupportsDistribution(boolean supportsDistribution) {
311 this.supportsDistribution = supportsDistribution;
312 }
313
314 /**
315 * Returns the boolean value of the flag indicating whether <i>this</i>
316 * feature can be described with {@link IndividualsAssociation individuals associations}
317 * (true) or not (false).
318 *
319 * @return the boolean value of the supportsIndividualAssociation flag
320 */
321 @XmlElement(name = "SupportsIndividualAssociation")
322 public boolean isSupportsIndividualAssociation() {
323 return supportsIndividualAssociation;
324 }
325
326 /**
327 * @see #isSupportsIndividualAssociation()
328 */
329 public void setSupportsIndividualAssociation(
330 boolean supportsIndividualAssociation) {
331 this.supportsIndividualAssociation = supportsIndividualAssociation;
332 }
333
334 /**
335 * Returns the boolean value of the flag indicating whether <i>this</i>
336 * feature can be described with {@link TaxonInteraction taxon interactions}
337 * (true) or not (false).
338 *
339 * @return the boolean value of the supportsTaxonInteraction flag
340 */
341 @XmlElement(name = "SupportsTaxonInteraction")
342 public boolean isSupportsTaxonInteraction() {
343 return supportsTaxonInteraction;
344 }
345
346 /**
347 * @see #isSupportsTaxonInteraction()
348 */
349 public void setSupportsTaxonInteraction(boolean supportsTaxonInteraction) {
350 this.supportsTaxonInteraction = supportsTaxonInteraction;
351 }
352
353 /**
354 * Returns the boolean value of the flag indicating whether <i>this</i>
355 * feature can be described with {@link CommonTaxonName common names}
356 * (true) or not (false). This flag is set if and only if <i>this</i> feature
357 * is the {@link #COMMON_NAME() common name feature}.
358 *
359 * @return the boolean value of the supportsCommonTaxonName flag
360 */
361 @XmlElement(name = "SupportsCommonTaxonName")
362 public boolean isSupportsCommonTaxonName() {
363 return supportsCommonTaxonName;
364 }
365
366 /**
367 * @see #isSupportsTaxonInteraction()
368 */
369 public void setSupportsCommonTaxonName(boolean supportsCommonTaxonName) {
370 this.supportsCommonTaxonName = supportsCommonTaxonName;
371 }
372
373 /**
374 * Returns the boolean value of the flag indicating whether <i>this</i>
375 * feature can be described with {@link CategoricalData categorical data}
376 * (true) or not (false).
377 *
378 * @return the boolean value of the supportsCategoricalData flag
379 */
380 @XmlElement(name = "SupportsCategoricalData")
381 public boolean isSupportsCategoricalData() {
382 return supportsCategoricalData;
383 }
384
385 /**
386 * @see #supportsCategoricalData()
387 */
388 public void setSupportsCategoricalData(boolean supportsCategoricalData) {
389 this.supportsCategoricalData = supportsCategoricalData;
390 }
391
392
393 /**
394 * Returns the set of {@link TermVocabulary term vocabularies} containing the
395 * {@link Modifier modifiers} recommended to be used for {@link DescriptionElementBase description elements}
396 * with <i>this</i> feature.
397 *
398 */
399 @XmlElementWrapper(name = "RecommendedModifierEnumerations")
400 @XmlElement(name = "RecommendedModifierEnumeration")
401 @XmlIDREF
402 @XmlSchemaType(name = "IDREF")
403 public Set<TermVocabulary<DefinedTerm>> getRecommendedModifierEnumeration() {
404 return recommendedModifierEnumeration;
405 }
406
407 /**
408 * Adds a {@link TermVocabulary term vocabulary} (with {@link Modifier modifiers}) to the set of
409 * {@link #getRecommendedModifierEnumeration() recommended modifier vocabularies} assigned
410 * to <i>this</i> feature.
411 *
412 * @param recommendedModifierEnumeration the term vocabulary to be added
413 * @see #getRecommendedModifierEnumeration()
414 */
415 public void addRecommendedModifierEnumeration(
416 TermVocabulary<DefinedTerm> recommendedModifierEnumeration) {
417 this.recommendedModifierEnumeration.add(recommendedModifierEnumeration);
418 }
419 /**
420 * Removes one element from the set of {@link #getRecommendedModifierEnumeration() recommended modifier vocabularies}
421 * assigned to <i>this</i> feature.
422 *
423 * @param recommendedModifierEnumeration the term vocabulary which should be removed
424 * @see #getRecommendedModifierEnumeration()
425 * @see #addRecommendedModifierEnumeration(TermVocabulary)
426 */
427 public void removeRecommendedModifierEnumeration(
428 TermVocabulary<DefinedTerm> recommendedModifierEnumeration) {
429 this.recommendedModifierEnumeration.remove(recommendedModifierEnumeration);
430 }
431
432 /**
433 * Returns the set of {@link StatisticalMeasure statistical measures} recommended to be used
434 * in case of {@link QuantitativeData quantitative data} with <i>this</i> feature.
435 */
436 @XmlElementWrapper(name = "RecommendedStatisticalMeasures")
437 @XmlElement(name = "RecommendedStatisticalMeasure")
438 @XmlIDREF
439 @XmlSchemaType(name = "IDREF")
440 public Set<StatisticalMeasure> getRecommendedStatisticalMeasures() {
441 return recommendedStatisticalMeasures;
442 }
443
444 /**
445 * Adds a {@link StatisticalMeasure statistical measure} to the set of
446 * {@link #getRecommendedStatisticalMeasures() recommended statistical measures} assigned
447 * to <i>this</i> feature.
448 *
449 * @param recommendedStatisticalMeasure the statistical measure to be added
450 * @see #getRecommendedStatisticalMeasures()
451 */
452 public void addRecommendedStatisticalMeasure(
453 StatisticalMeasure recommendedStatisticalMeasure) {
454 this.recommendedStatisticalMeasures.add(recommendedStatisticalMeasure);
455 }
456 /**
457 * Removes one element from the set of {@link #getRecommendedStatisticalMeasures() recommended statistical measures}
458 * assigned to <i>this</i> feature.
459 *
460 * @param recommendedStatisticalMeasure the statistical measure which should be removed
461 * @see #getRecommendedStatisticalMeasures()
462 * @see #addRecommendedStatisticalMeasure(StatisticalMeasure)
463 */
464 public void removeRecommendedStatisticalMeasure(
465 StatisticalMeasure recommendedStatisticalMeasure) {
466 this.recommendedStatisticalMeasures.remove(recommendedStatisticalMeasure);
467 }
468
469 /**
470 * Returns the set of {@link StatisticalMeasure statistical measures} recommended to be used
471 * in case of {@link QuantitativeData quantitative data} with <i>this</i> feature.
472 */
473 @XmlElementWrapper(name = "RecommendedMeasurementUnits")
474 @XmlElement(name = "RecommendedMeasurementUnit")
475 @XmlIDREF
476 @XmlSchemaType(name = "IDREF")
477 public Set<MeasurementUnit> getRecommendedMeasurementUnits() {
478 return recommendedMeasurementUnits;
479 }
480
481 /**
482 * Adds a {@link StatisticalMeasure statistical measure} to the set of
483 * {@link #getRecommendedStatisticalMeasures() recommended statistical measures} assigned
484 * to <i>this</i> feature.
485 *
486 * @param recommendedStatisticalMeasure the statistical measure to be added
487 * @see #getRecommendedStatisticalMeasures()
488 */
489 public void addRecommendedMeasurementUnit(
490 MeasurementUnit recommendedMeasurementUnit) {
491 this.recommendedMeasurementUnits.add(recommendedMeasurementUnit);
492 }
493 /**
494 * Removes one element from the set of {@link #getRecommendedStatisticalMeasures() recommended statistical measures}
495 * assigned to <i>this</i> feature.
496 *
497 * @param recommendedStatisticalMeasure the statistical measure which should be removed
498 * @see #getRecommendedStatisticalMeasures()
499 * @see #addRecommendedStatisticalMeasure(StatisticalMeasure)
500 */
501 public void removeRecommendedMeasurementUnit(
502 MeasurementUnit recommendedMeasurementUnit) {
503 this.recommendedMeasurementUnits.remove(recommendedMeasurementUnit);
504 }
505
506 /**
507 * Returns the set of {@link TermVocabulary term vocabularies} containing the list of
508 * possible {@link State states} to be used in {@link CategoricalData categorical data}
509 * with <i>this</i> feature.
510 *
511 */
512 @XmlElementWrapper(name = "SupportedCategoricalEnumerations")
513 @XmlElement(name = "SupportedCategoricalEnumeration")
514 @XmlIDREF
515 @XmlSchemaType(name = "IDREF")
516 public Set<TermVocabulary<State>> getSupportedCategoricalEnumerations() {
517 return supportedCategoricalEnumerations;
518 }
519
520 /**
521 * Adds a {@link TermVocabulary term vocabulary} to the set of
522 * {@link #getSupportedCategoricalEnumerations() supported state vocabularies} assigned
523 * to <i>this</i> feature.
524 *
525 * @param supportedCategoricalEnumeration the term vocabulary which should be removed
526 * @see #getSupportedCategoricalEnumerations()
527 */
528 public void addSupportedCategoricalEnumeration(
529 TermVocabulary<State> supportedCategoricalEnumeration) {
530 this.supportedCategoricalEnumerations.add(supportedCategoricalEnumeration);
531 }
532 /**
533 * Removes one element from the set of {@link #getSupportedCategoricalEnumerations() supported state vocabularies}
534 * assigned to <i>this</i> feature.
535 *
536 * @param supportedCategoricalEnumeration the term vocabulary which should be removed
537 * @see #getSupportedCategoricalEnumerations()
538 * @see #addSupportedCategoricalEnumeration(TermVocabulary)
539 */
540 public void removeSupportedCategoricalEnumeration(
541 TermVocabulary<State> supportedCategoricalEnumeration) {
542 this.supportedCategoricalEnumerations.remove(supportedCategoricalEnumeration);
543 }
544
545 @XmlElement(name = "KindOf", namespace = "http://etaxonomy.eu/cdm/model/common/1.0")
546 @XmlIDREF
547 @XmlSchemaType(name = "IDREF")
548 @Override
549 public Feature getKindOf(){
550 return super.getKindOf();
551 }
552
553 @Override
554 public void setKindOf(Feature kindOf){
555 super.setKindOf(kindOf);
556 }
557
558 @Override
559 @XmlElement(name = "PartOf", namespace = "http://etaxonomy.eu/cdm/model/common/1.0")
560 @XmlIDREF
561 @XmlSchemaType(name = "IDREF")
562 public Feature getPartOf(){
563 return super.getPartOf();
564 }
565
566 @Override
567 public void setPartOf(Feature partOf){
568 super.setPartOf(partOf);
569 }
570
571 @Override
572 @XmlElementWrapper(name = "Generalizations", namespace = "http://etaxonomy.eu/cdm/model/common/1.0")
573 @XmlElement(name = "GeneralizationOf", namespace = "http://etaxonomy.eu/cdm/model/common/1.0")
574 @XmlIDREF
575 @XmlSchemaType(name = "IDREF")
576 public Set<Feature> getGeneralizationOf(){
577 return super.getGeneralizationOf();
578 }
579
580 @Override
581 protected void setGeneralizationOf(Set<Feature> value){
582 super.setGeneralizationOf(value);
583 }
584
585 @Override
586 @XmlElementWrapper(name = "Includes", namespace = "http://etaxonomy.eu/cdm/model/common/1.0")
587 @XmlElement(name = "Include", namespace = "http://etaxonomy.eu/cdm/model/common/1.0")
588 @XmlIDREF
589 @XmlSchemaType(name = "IDREF")
590 public Set<Feature> getIncludes(){
591 return super.getIncludes();
592 }
593
594 @Override
595 protected void setIncludes(Set<Feature> includes) {
596 super.setIncludes(includes);
597 }
598
599 // ***************** Invers Label *****************************************/
600
601 public Set<Representation> getInverseRepresentations() {
602 return inverseRepresentations;
603 }
604 public void addInverseRepresentation(Representation inverseRepresentation) {
605 this.inverseRepresentations.add(inverseRepresentation);
606 }
607 public void removeInverseRepresentation(Representation inverseRepresentation) {
608 this.inverseRepresentations.remove(inverseRepresentation);
609 }
610 /*
611 * Inverse representation convenience methods similar to TermBase.xxx
612 * @see eu.etaxonomy.cdm.model.common.TermBase#getLabel()
613 */
614 @Transient
615 public String getInverseLabel() {
616 if(getInverseLabel(Language.DEFAULT()) != null){
617 return this.getInverseRepresentation(Language.DEFAULT()).getLabel();
618 }else{
619 for (Representation r : inverseRepresentations){
620 return r.getLabel();
621 }
622 }
623 return super.getUuid().toString();
624 }
625 public String getInverseLabel(Language lang) {
626 Representation r = this.getInverseRepresentation(lang);
627 if(r==null){
628 return null;
629 }else{
630 return r.getLabel();
631 }
632 }
633 public Representation getInverseRepresentation(Language lang) {
634 Representation result = null;
635 for (Representation repr : this.getInverseRepresentations()){
636 if (lang.equals(repr.getLanguage())){
637 result = repr;
638 }
639 }
640 return result;
641 }
642 // ****************** END INVERS REPRESENTATION **************************/
643
644 /**
645 * Creates and returns a new feature instance on the basis of a given string
646 * list (containing an UUID, an URI, a label and a description) and a given
647 * {@link Language language} to be associated with the description. Furthermore
648 * the flags concerning the supported subclasses of {@link DescriptionElementBase description elements}
649 * are set according to a particular string belonging to the given
650 * string list.<BR>
651 * This method overrides the readCsvLine method from {@link DefinedTermBase#readCsvLine(List, Language) DefinedTermBase}.
652 *
653 * @param csvLine the string list with elementary information for attributes
654 * @param lang the language in which the description has been formulated
655 * @see #NewInstance(String, String, String)
656 */
657 @Override
658 public Feature readCsvLine(Class<Feature> termClass, List<String> csvLine, TermType termType,
659 Map<UUID,DefinedTermBase> terms, boolean abbrevAsId) {
660 Feature newInstance = super.readCsvLine(termClass, csvLine, termType, terms, abbrevAsId);
661 String text = csvLine.get(4);
662 if (text != null && text.length() >= 6){
663 if ("1".equals(text.substring(0, 1))){newInstance.setSupportsTextData(true);}
664 if ("1".equals(text.substring(1, 2))){newInstance.setSupportsQuantitativeData(true);}
665 if ("1".equals(text.substring(2, 3))){newInstance.setSupportsDistribution(true);}
666 if ("1".equals(text.substring(3, 4))){newInstance.setSupportsIndividualAssociation(true);}
667 if ("1".equals(text.substring(4, 5))){newInstance.setSupportsTaxonInteraction(true);}
668 if ("1".equals(text.substring(5, 6))){newInstance.setSupportsCommonTaxonName(true);}
669 if (text.length() > 6 && "1".equals(text.substring(6, 7))){newInstance.setSupportsCategoricalData(true);}
670 //there is no abbreviated label for features yet, if there is one in future we need to increment the index for supportXXX form 4 to 5
671 newInstance.getRepresentation(Language.DEFAULT()).setAbbreviatedLabel(null);
672 }
673 return newInstance;
674 }
675
676 //******************************* STATIC METHODS *****************************************
677
678 protected static Feature getTermByUuid(UUID uuid){
679 if (termMap == null || termMap.isEmpty()){
680 return getTermByClassAndUUID(Feature.class, uuid);
681 } else {
682 return termMap.get(uuid);
683 }
684 }
685
686 /**
687 * Returns the "unknown" feature. This feature allows to store values of
688 * {@link DescriptionElementBase description elements} even if it is momentarily
689 * not known what they mean.
690 */
691 public static final Feature UNKNOWN(){
692 return getTermByUuid(uuidUnknown);
693 }
694
695 /**
696 * Returns the "description" feature. This feature allows to handle global
697 * {@link DescriptionElementBase description elements} for a global {@link DescriptionBase description}.<BR>
698 * The "description" feature is the highest level feature.
699 */
700 public static final Feature DESCRIPTION(){
701 return getTermByUuid(uuidDescription);
702 }
703
704 /**
705 * Returns the "distribution" feature. This feature allows to handle only
706 * {@link Distribution distributions}.
707 *
708 * @see #isSupportsDistribution()
709 */
710 public static final Feature DISTRIBUTION(){
711 return getTermByUuid(uuidDistribution);
712 }
713
714 /**
715 * Returns the feature for general text-based
716 * distributions
717 */
718 public static final Feature DISTRIBUTION_GENERAL(){
719 return getTermByUuid(uuidDistributionGeneral);
720 }
721
722 /**
723 * Returns the "discussion" feature. This feature can only be described
724 * with {@link TextData text data}.
725 *
726 * @see #isSupportsTextData()
727 */
728 public static final Feature DISCUSSION(){
729 return getTermByUuid(uuidDiscussion);
730 }
731
732 /**
733 * Returns the "ecology" feature. This feature only applies
734 * to {@link SpecimenDescription specimen descriptions} or to {@link TaxonDescription taxon descriptions}.<BR>
735 * The "ecology" feature generalizes all other possible features concerning
736 * ecological matters.
737 */
738 public static final Feature ECOLOGY(){
739 return getTermByUuid(uuidEcology);
740 }
741
742 /**
743 * Returns the "habitat" feature. This feature only applies
744 * to {@link SpecimenDescription specimen descriptions} or to {@link TaxonDescription taxon descriptions}.<BR>
745 * The "habitat" feature generalizes all other possible features concerning
746 * habitat matters.
747 */
748 public static final Feature HABITAT(){
749 return getTermByUuid(uuidHabitat);
750 }
751
752
753 /**
754 * Returns the "habitat & ecology" feature. This feature only applies
755 * to {@link SpecimenDescription specimen descriptions} or to {@link TaxonDescription taxon descriptions}.<BR>
756 * The "habitat & ecology" feature generalizes all other possible features concerning
757 * habitat and ecology matters.
758 */
759 public static final Feature HABITAT_ECOLOGY(){
760 return getTermByUuid(uuidHabitatAndEcology);
761 }
762
763 /**
764 * Returns the "biology_ecology" feature. This feature only applies
765 * to {@link SpecimenDescription specimen descriptions} or to {@link TaxonDescription taxon descriptions}.<BR>
766 * The "biology_ecology" feature generalizes all possible features concerning
767 * biological aspects of ecological matters.
768 *
769 * @see #ECOLOGY()
770 */
771 public static final Feature BIOLOGY_ECOLOGY(){
772 return getTermByUuid(uuidBiologyEcology);
773 }
774
775 /**
776 * Returns the "chromosome number" feature. This feature only applies
777 * to {@link SpecimenDescription specimen descriptions} or to {@link TaxonDescription taxon descriptions}.<BR>
778 */
779 public static final Feature CHROMOSOME_NUMBER(){
780 return getTermByUuid(uuidChromosomeNumber);
781 }
782
783
784 /**
785 * Returns the "key" feature. This feature is the "upper" feature generalizing
786 * all features being used within an identification key.
787 */
788 public static final Feature KEY(){
789 return getTermByUuid(uuidKey);
790 }
791
792
793 /**
794 * Returns the "materials_examined" feature. This feature can only be described
795 * with {@link TextData text data} or eventually with {@link CategoricalData categorical data}
796 * mentioning which material has been examined in order to accomplish
797 * the description. This feature applies only to
798 * {@link SpecimenDescription specimen descriptions} or to {@link TaxonDescription taxon descriptions}.
799 */
800 public static final Feature MATERIALS_EXAMINED(){
801 return getTermByUuid(uuidMaterialsExamined);
802 }
803
804 /**
805 * Returns the "materials_methods" feature. This feature can only be described
806 * with {@link TextData text data} or eventually with {@link CategoricalData categorical data}
807 * mentioning which methods have been adopted to analyze the material in
808 * order to accomplish the description. This feature applies only to
809 * {@link SpecimenDescription specimen descriptions} or to {@link TaxonDescription taxon descriptions}.
810 */
811 public static final Feature MATERIALS_METHODS(){
812 return getTermByUuid(uuidMaterialsMethods);
813 }
814
815 /**
816 * Returns the "etymology" feature. This feature can only be described
817 * with {@link TextData text data} or eventually with {@link CategoricalData categorical data}
818 * giving some information about the history of the taxon name. This feature applies only to
819 * {@link TaxonNameDescription taxon name descriptions}.
820 */
821 public static final Feature ETYMOLOGY(){
822 return getTermByUuid(uuidEtymology);
823 }
824
825 /**
826 * Returns the "diagnosis" feature. This feature can only be described
827 * with {@link TextData text data} or eventually with {@link CategoricalData categorical data}.
828 * This feature applies only to {@link SpecimenDescription specimen descriptions} or to
829 * {@link TaxonDescription taxon descriptions}.
830 */
831 public static final Feature DIAGNOSIS(){
832 return getTermByUuid(uuidDiagnosis);
833 }
834
835
836 /**
837 * Returns the "introduction" feature. This feature can only be described
838 * with {@link TextData text data}.
839 *
840 * @see #isSupportsTextData()
841 */
842 public static final Feature INTRODUCTION(){
843 return getTermByUuid(uuidIntroduction);
844 }
845
846 /**
847 * Returns the "protologue" feature. This feature can only be described
848 * with {@link TextData text data} reproducing the content of the protologue
849 * (or some information about it) of the taxon name. This feature applies only to
850 * {@link TaxonNameDescription taxon name descriptions}.
851 *
852 * @see #isSupportsTextData()
853 */
854 public static final Feature PROTOLOGUE(){
855 return getTermByUuid(uuidProtologue);
856 }
857
858 /**
859 * Returns the "common_name" feature. This feature allows to handle only
860 * {@link CommonTaxonName common names}.
861 *
862 * @see #isSupportsCommonTaxonName()
863 */
864 public static final Feature COMMON_NAME(){
865 return getTermByUuid(uuidCommonName);
866 }
867
868 /**
869 * Returns the "phenology" feature. This feature can only be described
870 * with {@link CategoricalData categorical data} or eventually with {@link TextData text data}
871 * containing information time about recurring natural phenomena.
872 * This feature only applies to {@link TaxonDescription taxon descriptions}.<BR>
873 * The "phenology" feature generalizes all other possible features
874 * concerning time information about particular natural phenomena
875 * (such as "first flight of butterflies").
876 */
877 public static final Feature PHENOLOGY(){
878 return getTermByUuid(uuidPhenology);
879 }
880
881 /**
882 * Returns the "occurrence" feature.
883 */
884 public static final Feature OCCURRENCE(){
885 return getTermByUuid(uuidOccurrence);
886 }
887
888 /**
889 * Returns the "anatomy" feature.
890 */
891 public static final Feature ANATOMY(){
892 return getTermByUuid(uuidAnatomy);
893 }
894 /**
895 * Returns the "hostplant" feature.
896 */
897 public static final Feature HOSTPLANT(){
898 return getTermByUuid(uuidHostPlant);
899 }
900 /**
901 * Returns the "pathogen agent" feature.
902 */
903 public static final Feature PATHOGEN_AGENT(){
904 return getTermByUuid(uuidPathogenAgent);
905 }
906
907 /**
908 * Returns the "citation" feature. This feature can only be described
909 * with {@link TextData text data}.
910 *
911 * @see #isSupportsTextData()
912 */
913 public static final Feature CITATION(){
914 return getTermByUuid(uuidCitation);
915 }
916
917 /**
918 * Returns the "additional_publication" feature. This feature can only be
919 * described with {@link TextData text data} with information about a
920 * publication where a {@link TaxonName taxon name} has also been published
921 * but which is not the {@link TaxonName#getNomenclaturalReference() nomenclatural reference}.
922 * This feature applies only to {@link TaxonNameDescription taxon name descriptions}.
923 *
924 * @see #isSupportsTextData()
925 */
926 public static final Feature ADDITIONAL_PUBLICATION(){
927 return getTermByUuid(uuidAdditionalPublication);
928 }
929
930
931 /**
932 * Returns the "uses" feature. This feature only applies
933 * to {@link TaxonDescription taxon descriptions}.<BR>
934 * The "uses" feature generalizes all other possible features concerning
935 * particular uses (for instance "industrial use of seeds").
936 */
937 public static final Feature USES(){
938 return getTermByUuid(uuidUses);
939 }
940
941 public static final Feature USERECORD(){
942 return getTermByUuid(uuidUseRecord);
943 }
944
945 /**
946 * Returns the "notes" feature. Used for
947 * taxonomic notes.
948 */
949 public static final Feature NOTES(){
950 return getTermByUuid(uuidNotes);
951 }
952
953 /**
954 * Returns the "conservation" feature. This feature only applies
955 * to {@link SpecimenDescription specimen descriptions} and generalizes
956 * methods and conditions for the conservation of {@link Specimen specimens}.<BR>
957 */
958 public static final Feature CONSERVATION(){
959 return getTermByUuid(uuidConservation);
960 }
961
962
963 /**
964 * Returns the "cultivation" feature.
965 */
966 public static final Feature CULTIVATION(){
967 return getTermByUuid(uuidCultivation);
968 }
969
970
971 /**
972 * Returns the "image" feature.
973 */
974 public static final Feature IMAGE(){
975 return getTermByUuid(uuidImage);
976 }
977
978 /**
979 * Returns the "individuals association" feature.
980 */
981 public static final Feature INDIVIDUALS_ASSOCIATION(){
982 Feature individuals_association = getTermByUuid(uuidIndividualsAssociation);
983 Set<Feature> generalizationOf = new HashSet<>();
984 generalizationOf.add(SPECIMEN());
985 generalizationOf.add(OBSERVATION());
986 individuals_association.setGeneralizationOf(generalizationOf);
987 return individuals_association;
988
989 }
990
991 public static final Feature SPECIMEN(){
992 return getTermByUuid(uuidSpecimen);
993 }
994
995 public static final Feature OBSERVATION(){
996 return getTermByUuid(uuidObservation);
997 }
998
999 /**
1000 * The status of a taxon. Usually the status should be determined within a {@link Distribution distribution}.
1001 * If this is not possible for some reason (e.g. the area is not well defined) the status feature
1002 * may be used.
1003 * @return
1004 */
1005 public static final Feature STATUS(){
1006 return getTermByUuid(uuidStatus);
1007 }
1008
1009 public static final Feature SYSTEMATICS(){
1010 return getTermByUuid(uuidSystematics);
1011 }
1012
1013 public static final Feature LIFEFORM(){
1014 return getTermByUuid(uuidLifeform);
1015 }
1016
1017 /**
1018 * Returns the "hybrid_parent" feature. This feature can only be used
1019 * by {@link TaxonInteraction taxon interactions}.<BR>
1020 * <P>
1021 * Note: It must be distinguished between hybrid relationships as
1022 * relevant nomenclatural relationships between {@link BotanicalName plant names}
1023 * on the one side and the biological relation between two {@link Taxon taxa}
1024 * as it is here the case on the other one.
1025 *
1026 * @see #isSupportsTaxonInteraction()
1027 * @see HybridRelationshipType
1028 */
1029 public static final Feature HYBRID_PARENT(){
1030 //TODO
1031 logger.warn("HYBRID_PARENT not yet implemented");
1032 return null;
1033 }
1034
1035 @Override
1036 protected void setDefaultTerms(TermVocabulary<Feature> termVocabulary) {
1037 if (termMap == null){ //needed because there are multiple feature vocabularies
1038 termMap = new HashMap<UUID, Feature>();
1039 }
1040 for (Feature term : termVocabulary.getTerms()){
1041 termMap.put(term.getUuid(), term);
1042 }
1043 }
1044
1045 //*********************************** CLONE *********************************************************/
1046
1047 @Override
1048 public Object clone() {
1049 Feature result = (Feature)super.clone();
1050
1051 result.inverseRepresentations = new HashSet<Representation>();
1052 for (Representation rep: this.inverseRepresentations){
1053 result.addInverseRepresentation((Representation)rep.clone());
1054 }
1055
1056 //no changes to: symmetric, transitiv
1057 return result;
1058 }
1059
1060 }