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