ref #9932 add representation language dependent factory methods to some terms
[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 package eu.etaxonomy.cdm.model.description;
10
11 import java.util.EnumSet;
12 import java.util.HashMap;
13 import java.util.HashSet;
14 import java.util.List;
15 import java.util.Map;
16 import java.util.Set;
17 import java.util.UUID;
18
19 import javax.persistence.Entity;
20 import javax.persistence.FetchType;
21 import javax.persistence.JoinColumn;
22 import javax.persistence.JoinTable;
23 import javax.persistence.ManyToMany;
24 import javax.persistence.OneToMany;
25 import javax.persistence.Transient;
26 import javax.validation.constraints.NotNull;
27 import javax.xml.bind.annotation.XmlAccessType;
28 import javax.xml.bind.annotation.XmlAccessorType;
29 import javax.xml.bind.annotation.XmlAttribute;
30 import javax.xml.bind.annotation.XmlElement;
31 import javax.xml.bind.annotation.XmlElementWrapper;
32 import javax.xml.bind.annotation.XmlIDREF;
33 import javax.xml.bind.annotation.XmlRootElement;
34 import javax.xml.bind.annotation.XmlSchemaType;
35 import javax.xml.bind.annotation.XmlType;
36
37 import org.apache.log4j.Logger;
38 import org.hibernate.annotations.Cascade;
39 import org.hibernate.annotations.CascadeType;
40 import org.hibernate.annotations.Parameter;
41 import org.hibernate.annotations.Type;
42 import org.hibernate.envers.Audited;
43
44 import eu.etaxonomy.cdm.model.common.AvailableForTermBase;
45 import eu.etaxonomy.cdm.model.common.CdmClass;
46 import eu.etaxonomy.cdm.model.common.Language;
47 import eu.etaxonomy.cdm.model.name.NomenclaturalCode;
48 import eu.etaxonomy.cdm.model.name.TaxonName;
49 import eu.etaxonomy.cdm.model.term.DefinedTerm;
50 import eu.etaxonomy.cdm.model.term.DefinedTermBase;
51 import eu.etaxonomy.cdm.model.term.Representation;
52 import eu.etaxonomy.cdm.model.term.TermTree;
53 import eu.etaxonomy.cdm.model.term.TermType;
54 import eu.etaxonomy.cdm.model.term.TermVocabulary;
55
56 /**
57 * The class for individual properties (also designed as character, type or
58 * category) of observed phenomena able to be described or measured. It also
59 * covers categories of informations on {@link TaxonName taxon names} not
60 * taken in account in {@link NomenclaturalCode nomenclature}.<BR>
61 * Descriptions require features in order to be structured and disaggregated
62 * in {@link DescriptionElementBase description elements}.<BR>
63 * Experts do not use the word feature for the actual description
64 * but only for the property itself. Therefore naming this class FeatureType
65 * would have leaded to confusion.
66 * <P>
67 * Since features are {@link DefinedTermBase defined terms} they have a hierarchical
68 * structure that allows to specify ("kind of") or generalize
69 * ("generalization of") features. "Kind of" / "generalization of" relations
70 * are bidirectional (a feature F1 is a "Kind of" a feature F2 if and only
71 * if the feature F2 is a "generalization of" the feature F1. This hierarchical
72 * structure has nothing in common with {@link TermTree feature trees} used for determination.
73 * <P>
74 * A standard set of feature instances will be automatically
75 * created as the project starts. But this class allows to extend this standard
76 * set by creating new instances of additional features if needed.<BR>
77 * <P>
78 * This class corresponds to DescriptionsSectionType according to the SDD
79 * schema.
80 *
81 * @author m.doering
82 * @since 08-Nov-2007 13:06:24
83 */
84 @XmlAccessorType(XmlAccessType.PROPERTY)
85 @XmlType(name="Feature", factoryMethod="NewInstance", propOrder = {
86 "kindOf",
87 "generalizationOf",
88 "partOf",
89 "includes",
90 "availableForTaxon",
91 "availableForTaxonName",
92 "availableForOccurrence",
93 "supportsTextData",
94 "supportsQuantitativeData",
95 "supportsDistribution",
96 "supportsIndividualAssociation",
97 "supportsTaxonInteraction",
98 "supportsCommonTaxonName",
99 "supportsCategoricalData",
100 "supportsTemporalData",
101 "recommendedModifierEnumeration",
102 "recommendedStatisticalMeasures",
103 "supportedCategoricalEnumerations",
104 "recommendedMeasurementUnits",
105 "inverseRepresentations"
106 })
107 @XmlRootElement(name = "Feature")
108 @Entity
109 //@Indexed disabled to reduce clutter in indexes, since this type is not used by any search
110 //@Indexed(index = "eu.etaxonomy.cdm.model.term.DefinedTermBase")
111 @Audited
112 public class Feature extends AvailableForTermBase<Feature> {
113
114 private static final long serialVersionUID = 6754598791831848704L;
115 @SuppressWarnings("unused")
116 private static final Logger logger = Logger.getLogger(Feature.class);
117
118 protected static Map<UUID, Feature> termMap = null;
119
120 @XmlAttribute(name ="supportedDataTypes")
121 @NotNull
122 @Type(type = "eu.etaxonomy.cdm.hibernate.EnumSetUserType",
123 parameters = {@Parameter(name = "enumClass", value = "eu.etaxonomy.cdm.model.common.CdmClass")}
124 )
125 private EnumSet<CdmClass> supportedDataTypes = EnumSet.of(CdmClass.TEXT_DATA); //by default TextData should always be supported
126
127 /* for M:M see #4843 */
128 @ManyToMany(fetch = FetchType.LAZY)
129 @JoinTable(name="DefinedTermBase_RecommendedModifierEnumeration")
130 private final Set<TermVocabulary<DefinedTerm>> recommendedModifierEnumeration = new HashSet<>();
131
132 @ManyToMany(fetch = FetchType.LAZY)
133 @JoinTable(name="DefinedTermBase_StatisticalMeasure")
134 private final Set<StatisticalMeasure> recommendedStatisticalMeasures = new HashSet<>();
135
136 /* for M:M see #4843 */
137 @ManyToMany(fetch = FetchType.LAZY)
138 @JoinTable(name="DefinedTermBase_SupportedCategoricalEnumeration")
139 private final Set<TermVocabulary<State>> supportedCategoricalEnumerations = new HashSet<>();
140
141 @ManyToMany(fetch = FetchType.LAZY)
142 @JoinTable(name="DefinedTermBase_MeasurementUnit")
143 private final Set<MeasurementUnit> recommendedMeasurementUnits = new HashSet<>();
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
158 private static final UUID uuidUnknown = UUID.fromString("910307f1-dc3c-452c-a6dd-af5ac7cd365c");
159 public static final UUID uuidDescription = UUID.fromString("9087cdcd-8b08-4082-a1de-34c9ba9fb493");
160 private static final UUID uuidDistribution = UUID.fromString("9fc9d10c-ba50-49ee-b174-ce83fc3f80c6");
161 private static final UUID uuidDistributionGeneral = UUID.fromString("fd8c64f0-6ea5-44b0-9f70-e95833d6076e");
162 private static final UUID uuidEcology = UUID.fromString("aa923827-d333-4cf5-9a5f-438ae0a4746b");
163 public static final UUID uuidHabitat = UUID.fromString("fb16929f-bc9c-456f-9d40-dec987b36438");
164 private static final UUID uuidHabitatAndEcology = UUID.fromString("9fdc4663-4d56-47d0-90b5-c0bf251bafbb");
165 private static final UUID uuidChromosomeNumber = UUID.fromString("6f677e98-d8d5-4bc5-80bf-affdb7e3945a");
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 public static final UUID uuidStatus = UUID.fromString("86d40635-2a63-4ad6-be75-9faa4a6a57fb");
192 private static final UUID uuidSystematics = UUID.fromString("bd9aca17-cd0e-4418-a3a1-1a4b80dbc162");
193 private static final UUID uuidUseRecord = UUID.fromString("8125a59d-b4d5-4485-89ea-67306297b599");
194 private static final UUID uuidNotes = UUID.fromString("b5780b45-6439-4f3c-9818-d89d26d36eb2");
195 public static final UUID uuidLifeform = UUID.fromString("db9228d3-8bbf-4460-abfe-0b1326c82f8e");
196 public static final UUID uuidFloweringPeriod = UUID.fromString("03710cb5-606e-444a-a3e6-594268e3cc47");
197 public static final UUID uuidFruitingPeriod = UUID.fromString("04aa8993-24b4-43e3-888c-5afaa733376e");
198 public static final UUID uuidAltitude = UUID.fromString("1a28ed59-e15f-4001-b5c2-ea89f0012671");
199
200 /* ***************** CONSTRUCTOR AND FACTORY METHODS **********************************/
201
202 /**
203 * Creates a new empty feature instance.
204 *
205 * @see #NewInstance(String, String, String)
206 */
207 public static Feature NewInstance() {
208 return new Feature();
209 }
210
211 /**
212 * Creates a new feature instance with a description (in the {@link Language#DEFAULT() default language}),
213 * a label and a label abbreviation.
214 *
215 * @param description the string (in the default language) describing the
216 * new feature to be created
217 * @param label the string identifying the new feature to be created
218 * @param labelAbbrev the string identifying (in abbreviated form) the
219 * new feature to be created
220 * @see #readCsvLine(List, Language)
221 * @see #NewInstance()
222 */
223 public static Feature NewInstance(String description, String label, String labelAbbrev){
224 return new Feature(description, label, labelAbbrev);
225 }
226
227 public static Feature NewInstance(String description, String label, String labelAbbrev, Language language){
228 Feature result = new Feature(description, label, labelAbbrev);
229 result.getRepresentations().iterator().next().setLanguage(language);
230 return result;
231 }
232
233 // ********************** CONSTRUCTOR ************************/
234
235 //for hibernate use only
236 @Deprecated
237 protected Feature() {
238 super(TermType.Feature);
239 }
240
241 /**
242 * Class constructor: creates a new feature instance with a description (in the {@link Language#DEFAULT() default language}),
243 * a label and a label abbreviation.
244 *
245 * @param term the string (in the default language) describing the
246 * new feature to be created
247 * @param label the string identifying the new feature to be created
248 * @param labelAbbrev the string identifying (in abbreviated form) the
249 * new feature to be created
250 * @see #Feature()
251 */
252 protected Feature(String term, String label, String labelAbbrev) {
253 super(TermType.Feature, term, label, labelAbbrev);
254 }
255
256 /* *************************************************************************************/
257
258 @Override
259 public void resetTerms(){
260 termMap = null;
261 }
262
263 /**
264 * If this feature is available for {@link TaxonDescription taxon descriptions}.
265 */
266 @XmlElement(name = "AvailableForTaxon")
267 public boolean isAvailableForTaxon() {
268 return getAvailableFor().contains(CdmClass.TAXON);
269 }
270 /**
271 * @see #isAvailableForTaxon()
272 */
273 public void setAvailableForTaxon(boolean availableForTaxon) {
274 setAvailableFor(CdmClass.TAXON, availableForTaxon);
275 }
276
277 /**
278 * If this feature is available for {@link NameDescription name descriptions}.
279 */
280 @XmlElement(name = "AvailableForTaxonName")
281 public boolean isAvailableForTaxonName() {
282 return getAvailableFor().contains(CdmClass.TAXON_NAME);
283 }
284 /**
285 * @see #isAvailableForTaxon()
286 */
287 public void setAvailableForTaxonName(boolean availableForTaxonName) {
288 setAvailableFor(CdmClass.TAXON_NAME, availableForTaxonName);
289 }
290
291 /**
292 * If this feature is available for {@link SpecimenDescription specimen descriptions}.
293 */
294 @XmlElement(name = "AvailableForOccurrence")
295 public boolean isAvailableForOccurrence() {
296 return getAvailableFor().contains(CdmClass.OCCURRENCE);
297 }
298 /**
299 * @see #isAvailableForOccurrence()
300 */
301 public void setAvailableForOccurrence(boolean availableForOccurrence) {
302 setAvailableFor(CdmClass.OCCURRENCE, availableForOccurrence);
303 }
304
305 /**
306 * Returns the boolean value of the flag indicating whether <i>this</i>
307 * feature can be described with {@link QuantitativeData quantitative data} (true)
308 * or not (false). If this flag is set <i>this</i> feature can only apply to
309 * {@link TaxonDescription taxon descriptions} or {@link SpecimenDescription specimen descriptions}.
310 *
311 * @return the boolean value of the supportsQuantitativeData flag
312 */
313 @XmlElement(name = "SupportsQuantitativeData")
314 public boolean isSupportsQuantitativeData() {
315 return supportedDataTypes.contains(CdmClass.QUANTITATIVE_DATA);
316 }
317 /**
318 * @see #isSupportsQuantitativeData()
319 */
320 public void setSupportsQuantitativeData(boolean supportsQuantitativeData) {
321 setSupportedClass(CdmClass.QUANTITATIVE_DATA, supportsQuantitativeData);
322 }
323
324 /**
325 * Returns the boolean value of the flag indicating whether <i>this</i>
326 * feature can be described with {@link TextData text data} (true)
327 * or not (false).
328 *
329 * @return the boolean value of the supportsTextData flag
330 */
331 @XmlElement(name = "SupportsTextData")
332 public boolean isSupportsTextData() {
333 return supportedDataTypes.contains(CdmClass.TEXT_DATA);
334 }
335 /**
336 * @see #isSupportsTextData()
337 */
338 public void setSupportsTextData(boolean supportsTextData) {
339 setSupportedClass(CdmClass.TEXT_DATA, supportsTextData);
340 }
341
342 /**
343 * Returns the boolean value of the flag indicating whether <i>this</i>
344 * feature can be described with {@link Distribution distribution} objects
345 * (true) or not (false). This flag is set if and only if <i>this</i> feature
346 * is the {@link #DISTRIBUTION() distribution feature}.
347 *
348 * @return the boolean value of the supportsDistribution flag
349 */
350 @XmlElement(name = "SupportsDistribution")
351 public boolean isSupportsDistribution() {
352 return supportedDataTypes.contains(CdmClass.DISTRIBUTION);
353 }
354 /**
355 * @see #isSupportsDistribution()
356 */
357 public void setSupportsDistribution(boolean supportsDistribution) {
358 setSupportedClass(CdmClass.DISTRIBUTION, supportsDistribution);
359 }
360
361 /**
362 * Returns the boolean value of the flag indicating whether <i>this</i>
363 * feature can be described with {@link IndividualsAssociation individuals associations}
364 * (true) or not (false).
365 *
366 * @return the boolean value of the supportsIndividualAssociation flag
367 */
368 @XmlElement(name = "SupportsIndividualAssociation")
369 public boolean isSupportsIndividualAssociation() {
370 return supportedDataTypes.contains(CdmClass.INDIVIDUALS_ASSOCIATION);
371 }
372 /**
373 * @see #isSupportsIndividualAssociation()
374 */
375 public void setSupportsIndividualAssociation(
376 boolean supportsIndividualAssociation) {
377 setSupportedClass(CdmClass.INDIVIDUALS_ASSOCIATION, supportsIndividualAssociation);
378 }
379
380 /**
381 * Returns the boolean value of the flag indicating whether <i>this</i>
382 * feature can be described with {@link TaxonInteraction taxon interactions}
383 * (true) or not (false).
384 *
385 * @return the boolean value of the supportsTaxonInteraction flag
386 */
387 @XmlElement(name = "SupportsTaxonInteraction")
388 public boolean isSupportsTaxonInteraction() {
389 return supportedDataTypes.contains(CdmClass.TAXON_INTERACTION);
390 }
391 /**
392 * @see #isSupportsTaxonInteraction()
393 */
394 public void setSupportsTaxonInteraction(boolean supportsTaxonInteraction) {
395 setSupportedClass(CdmClass.TAXON_INTERACTION, supportsTaxonInteraction);
396 }
397
398 /**
399 * Returns the boolean value of the flag indicating whether <i>this</i>
400 * feature can be described with {@link CommonTaxonName common names}
401 * (true) or not (false). This flag is set if and only if <i>this</i> feature
402 * is the {@link #COMMON_NAME() common name feature}.
403 *
404 * @return the boolean value of the supportsCommonTaxonName flag
405 */
406 @XmlElement(name = "SupportsCommonTaxonName")
407 public boolean isSupportsCommonTaxonName() {
408 return supportedDataTypes.contains(CdmClass.COMMON_TAXON_NAME);
409 }
410 /**
411 * @see #isSupportsTaxonInteraction()
412 */
413 public void setSupportsCommonTaxonName(boolean supportsCommonTaxonName) {
414 setSupportedClass(CdmClass.COMMON_TAXON_NAME, supportsCommonTaxonName);
415 }
416
417 /**
418 * Returns the boolean value of the flag indicating whether <i>this</i>
419 * feature can be described with {@link CategoricalData categorical data}
420 * (true) or not (false).
421 *
422 * @return the boolean value of the supportsCategoricalData flag
423 */
424 @XmlElement(name = "SupportsCategoricalData")
425 public boolean isSupportsCategoricalData() {
426 return supportedDataTypes.contains(CdmClass.CATEGORICAL_DATA);
427 }
428 /**
429 * @see #supportsCategoricalData()
430 */
431 public void setSupportsCategoricalData(boolean supportsCategoricalData) {
432 setSupportedClass(CdmClass.CATEGORICAL_DATA, supportsCategoricalData);
433 }
434
435 /**
436 * Returns the boolean value of the flag indicating whether <i>this</i>
437 * feature can be described with {@link TemporalData temporalData}
438 * (true) or not (false).
439 *
440 * @return the boolean value of the supportsTemporalData flag
441 */
442 @XmlElement(name = "SupportsTemporalData")
443 public boolean isSupportsTemporalData() {
444 return supportedDataTypes.contains(CdmClass.TEMPORAL_DATA);
445 }
446 /**
447 * @see #isSupportsTemporalData()
448 */
449 public void setSupportsTemporalData(boolean supportsTemporalData) {
450 setSupportedClass(CdmClass.TEMPORAL_DATA, supportsTemporalData);
451 }
452
453 /**
454 * Sets the value for supported classes
455 * @param cdmClass the supported class
456 * @param value the value if it is supported (<code>true</code>) or not (<code>false</code>)
457 */
458 private void setSupportedClass(CdmClass cdmClass, boolean value) {
459 if (value && !this.supportedDataTypes.contains(cdmClass)){
460 setSupportedDataTypes(newEnumSet(this.supportedDataTypes, cdmClass, null));
461 }else if (!value && this.supportedDataTypes.contains(cdmClass)){
462 setSupportedDataTypes(newEnumSet(this.supportedDataTypes, null, cdmClass));
463 }else{
464 return;
465 }
466 }
467
468 /**
469 * for know it is private and the boolean getters and setters should be used instead.
470 * If you make it public make sure to guarantee that any change to the enum set results
471 * in a new enum set (see also {@link #newEnumSet(EnumSet, CdmClass, CdmClass)}
472 * and that the client is aware of the enum set being immutable.
473 */
474 private void setSupportedDataTypes(EnumSet<CdmClass> dataTypes){
475 this.supportedDataTypes = dataTypes;
476 }
477
478
479 /**
480 * Returns the set of {@link TermVocabulary term vocabularies} containing the
481 * {@link Modifier modifiers} recommended to be used for {@link DescriptionElementBase description elements}
482 * with <i>this</i> feature.
483 *
484 */
485 @XmlElementWrapper(name = "RecommendedModifierEnumerations")
486 @XmlElement(name = "RecommendedModifierEnumeration")
487 @XmlIDREF
488 @XmlSchemaType(name = "IDREF")
489 public Set<TermVocabulary<DefinedTerm>> getRecommendedModifierEnumeration() {
490 return recommendedModifierEnumeration;
491 }
492
493 /**
494 * Adds a {@link TermVocabulary term vocabulary} (with {@link Modifier modifiers}) to the set of
495 * {@link #getRecommendedModifierEnumeration() recommended modifier vocabularies} assigned
496 * to <i>this</i> feature.
497 *
498 * @param recommendedModifierEnumeration the term vocabulary to be added
499 * @see #getRecommendedModifierEnumeration()
500 */
501 public void addRecommendedModifierEnumeration(
502 TermVocabulary<DefinedTerm> recommendedModifierEnumeration) {
503 this.recommendedModifierEnumeration.add(recommendedModifierEnumeration);
504 }
505 /**
506 * Removes one element from the set of {@link #getRecommendedModifierEnumeration() recommended modifier vocabularies}
507 * assigned to <i>this</i> feature.
508 *
509 * @param recommendedModifierEnumeration the term vocabulary which should be removed
510 * @see #getRecommendedModifierEnumeration()
511 * @see #addRecommendedModifierEnumeration(TermVocabulary)
512 */
513 public void removeRecommendedModifierEnumeration(
514 TermVocabulary<DefinedTerm> recommendedModifierEnumeration) {
515 this.recommendedModifierEnumeration.remove(recommendedModifierEnumeration);
516 }
517
518 /**
519 * Returns the set of {@link StatisticalMeasure statistical measures} recommended to be used
520 * in case of {@link QuantitativeData quantitative data} with <i>this</i> feature.
521 */
522 @XmlElementWrapper(name = "RecommendedStatisticalMeasures")
523 @XmlElement(name = "RecommendedStatisticalMeasure")
524 @XmlIDREF
525 @XmlSchemaType(name = "IDREF")
526 public Set<StatisticalMeasure> getRecommendedStatisticalMeasures() {
527 return recommendedStatisticalMeasures;
528 }
529
530 /**
531 * Adds a {@link StatisticalMeasure statistical measure} to the set of
532 * {@link #getRecommendedStatisticalMeasures() recommended statistical measures} assigned
533 * to <i>this</i> feature.
534 *
535 * @param recommendedStatisticalMeasure the statistical measure to be added
536 * @see #getRecommendedStatisticalMeasures()
537 */
538 public void addRecommendedStatisticalMeasure(
539 StatisticalMeasure recommendedStatisticalMeasure) {
540 this.recommendedStatisticalMeasures.add(recommendedStatisticalMeasure);
541 }
542 /**
543 * Removes one element from the set of {@link #getRecommendedStatisticalMeasures() recommended statistical measures}
544 * assigned to <i>this</i> feature.
545 *
546 * @param recommendedStatisticalMeasure the statistical measure which should be removed
547 * @see #getRecommendedStatisticalMeasures()
548 * @see #addRecommendedStatisticalMeasure(StatisticalMeasure)
549 */
550 public void removeRecommendedStatisticalMeasure(
551 StatisticalMeasure recommendedStatisticalMeasure) {
552 this.recommendedStatisticalMeasures.remove(recommendedStatisticalMeasure);
553 }
554
555 /**
556 * Returns the set of {@link StatisticalMeasure statistical measures} recommended to be used
557 * in case of {@link QuantitativeData quantitative data} with <i>this</i> feature.
558 */
559 @XmlElementWrapper(name = "RecommendedMeasurementUnits")
560 @XmlElement(name = "RecommendedMeasurementUnit")
561 @XmlIDREF
562 @XmlSchemaType(name = "IDREF")
563 public Set<MeasurementUnit> getRecommendedMeasurementUnits() {
564 return recommendedMeasurementUnits;
565 }
566
567 /**
568 * Adds a {@link StatisticalMeasure statistical measure} to the set of
569 * {@link #getRecommendedStatisticalMeasures() recommended statistical measures} assigned
570 * to <i>this</i> feature.
571 *
572 * @param recommendedStatisticalMeasure the statistical measure to be added
573 * @see #getRecommendedStatisticalMeasures()
574 */
575 public void addRecommendedMeasurementUnit(
576 MeasurementUnit recommendedMeasurementUnit) {
577 this.recommendedMeasurementUnits.add(recommendedMeasurementUnit);
578 }
579 /**
580 * Removes one element from the set of {@link #getRecommendedStatisticalMeasures() recommended statistical measures}
581 * assigned to <i>this</i> feature.
582 *
583 * @param recommendedStatisticalMeasure the statistical measure which should be removed
584 * @see #getRecommendedStatisticalMeasures()
585 * @see #addRecommendedStatisticalMeasure(StatisticalMeasure)
586 */
587 public void removeRecommendedMeasurementUnit(
588 MeasurementUnit recommendedMeasurementUnit) {
589 this.recommendedMeasurementUnits.remove(recommendedMeasurementUnit);
590 }
591
592 /**
593 * Returns the set of {@link TermVocabulary term vocabularies} containing the list of
594 * possible {@link State states} to be used in {@link CategoricalData categorical data}
595 * with <i>this</i> feature.
596 *
597 */
598 @XmlElementWrapper(name = "SupportedCategoricalEnumerations")
599 @XmlElement(name = "SupportedCategoricalEnumeration")
600 @XmlIDREF
601 @XmlSchemaType(name = "IDREF")
602 public Set<TermVocabulary<State>> getSupportedCategoricalEnumerations() {
603 return supportedCategoricalEnumerations;
604 }
605
606 /**
607 * Adds a {@link TermVocabulary term vocabulary} to the set of
608 * {@link #getSupportedCategoricalEnumerations() supported state vocabularies} assigned
609 * to <i>this</i> feature.
610 *
611 * @param supportedCategoricalEnumeration the term vocabulary which should be removed
612 * @see #getSupportedCategoricalEnumerations()
613 */
614 public void addSupportedCategoricalEnumeration(
615 TermVocabulary<State> supportedCategoricalEnumeration) {
616 this.supportedCategoricalEnumerations.add(supportedCategoricalEnumeration);
617 }
618 /**
619 * Removes one element from the set of {@link #getSupportedCategoricalEnumerations() supported state vocabularies}
620 * assigned to <i>this</i> feature.
621 *
622 * @param supportedCategoricalEnumeration the term vocabulary which should be removed
623 * @see #getSupportedCategoricalEnumerations()
624 * @see #addSupportedCategoricalEnumeration(TermVocabulary)
625 */
626 public void removeSupportedCategoricalEnumeration(
627 TermVocabulary<State> supportedCategoricalEnumeration) {
628 this.supportedCategoricalEnumerations.remove(supportedCategoricalEnumeration);
629 }
630
631 @XmlElement(name = "KindOf", namespace = "http://etaxonomy.eu/cdm/model/common/1.0")
632 @XmlIDREF
633 @XmlSchemaType(name = "IDREF")
634 @Override
635 public Feature getKindOf(){
636 return super.getKindOf();
637 }
638
639 @Override
640 public void setKindOf(Feature kindOf){
641 super.setKindOf(kindOf);
642 }
643
644 @Override
645 @XmlElement(name = "PartOf", namespace = "http://etaxonomy.eu/cdm/model/common/1.0")
646 @XmlIDREF
647 @XmlSchemaType(name = "IDREF")
648 public Feature getPartOf(){
649 return super.getPartOf();
650 }
651
652 @Override
653 public void setPartOf(Feature partOf){
654 super.setPartOf(partOf);
655 }
656
657 @Override
658 @XmlElementWrapper(name = "Generalizations", namespace = "http://etaxonomy.eu/cdm/model/common/1.0")
659 @XmlElement(name = "GeneralizationOf", namespace = "http://etaxonomy.eu/cdm/model/common/1.0")
660 @XmlIDREF
661 @XmlSchemaType(name = "IDREF")
662 public Set<Feature> getGeneralizationOf(){
663 return super.getGeneralizationOf();
664 }
665
666 @Override
667 protected void setGeneralizationOf(Set<Feature> value){
668 super.setGeneralizationOf(value);
669 }
670
671 @Override
672 @XmlElementWrapper(name = "Includes", namespace = "http://etaxonomy.eu/cdm/model/common/1.0")
673 @XmlElement(name = "Include", namespace = "http://etaxonomy.eu/cdm/model/common/1.0")
674 @XmlIDREF
675 @XmlSchemaType(name = "IDREF")
676 public Set<Feature> getIncludes(){
677 return super.getIncludes();
678 }
679
680 @Override
681 protected void setIncludes(Set<Feature> includes) {
682 super.setIncludes(includes);
683 }
684
685 // ***************** Invers Label *****************************************/
686
687 public Set<Representation> getInverseRepresentations() {
688 return inverseRepresentations;
689 }
690 public void addInverseRepresentation(Representation inverseRepresentation) {
691 this.inverseRepresentations.add(inverseRepresentation);
692 }
693 public void removeInverseRepresentation(Representation inverseRepresentation) {
694 this.inverseRepresentations.remove(inverseRepresentation);
695 }
696 /*
697 * Inverse representation convenience methods similar to TermBase.xxx
698 * @see eu.etaxonomy.cdm.model.term.TermBase#getLabel()
699 */
700 @Transient
701 public String getInverseLabel() {
702 if(getInverseLabel(Language.DEFAULT()) != null){
703 return this.getInverseRepresentation(Language.DEFAULT()).getLabel();
704 }else{
705 for (Representation r : inverseRepresentations){
706 return r.getLabel();
707 }
708 }
709 return super.getUuid().toString();
710 }
711 public String getInverseLabel(Language lang) {
712 Representation r = this.getInverseRepresentation(lang);
713 if(r==null){
714 return null;
715 }else{
716 return r.getLabel();
717 }
718 }
719 public Representation getInverseRepresentation(Language lang) {
720 Representation result = null;
721 for (Representation repr : this.getInverseRepresentations()){
722 if (lang.equals(repr.getLanguage())){
723 result = repr;
724 }
725 }
726 return result;
727 }
728 // ****************** END INVERS REPRESENTATION **************************/
729
730 /**
731 * Creates and returns a new feature instance on the basis of a given string
732 * list (containing an UUID, an URI, a label and a description) and a given
733 * {@link Language language} to be associated with the description. Furthermore
734 * the flags concerning the supported subclasses of {@link DescriptionElementBase description elements}
735 * are set according to a particular string belonging to the given
736 * string list.<BR>
737 * This method overrides the readCsvLine method from {@link DefinedTermBase#readCsvLine(List, Language) DefinedTermBase}.
738 *
739 * @param csvLine the string list with elementary information for attributes
740 * @param lang the language in which the description has been formulated
741 * @see #NewInstance(String, String, String)
742 */
743 @Override
744 public Feature readCsvLine(Class<Feature> termClass, List<String> csvLine, TermType termType,
745 @SuppressWarnings("rawtypes") Map<UUID,DefinedTermBase> terms, boolean abbrevAsId) {
746 Feature newInstance = super.readCsvLine(termClass, csvLine, termType, terms, abbrevAsId);
747
748 String text = csvLine.get(4);
749 if (isNotBlank(text)){
750 newInstance.setSymbol(text);
751 }
752
753 //supported datatypes
754 text = csvLine.get(5);
755 if (text != null && text.length() == 8){
756 if ("1".equals(text.substring(0, 1))){newInstance.setSupportsTextData(true);}
757 if ("1".equals(text.substring(1, 2))){newInstance.setSupportsQuantitativeData(true);}
758 if ("1".equals(text.substring(2, 3))){newInstance.setSupportsDistribution(true);}
759 if ("1".equals(text.substring(3, 4))){newInstance.setSupportsIndividualAssociation(true);}
760 if ("1".equals(text.substring(4, 5))){newInstance.setSupportsTaxonInteraction(true);}
761 if ("1".equals(text.substring(5, 6))){newInstance.setSupportsCommonTaxonName(true);}
762 if ("1".equals(text.substring(6, 7))){newInstance.setSupportsCategoricalData(true);}
763 if ("1".equals(text.substring(7, 8))){newInstance.setSupportsTemporalData(true);}
764 }else{
765 throw new IllegalStateException("Supported XXX must exist for all 8 subclasses");
766 }
767
768 //availableFor
769 text = csvLine.get(6);
770 if (text != null && text.length() == 3){
771 if ("1".equals(text.substring(0, 1))){newInstance.setAvailableForTaxon(true);}
772 if ("1".equals(text.substring(1, 2))){newInstance.setAvailableForOccurrence(true);}
773 if ("1".equals(text.substring(2, 3))){newInstance.setAvailableForTaxonName(true);}
774 }else{
775 throw new IllegalStateException("AvailableFor XXX must exist for all 3 classes");
776 }
777
778 //recommended measurement unit
779 text = csvLine.get(7);
780 if (isNotBlank(text) && text.length() == 36){
781 if (text.length() != 36){
782 throw new IllegalStateException("Recommended measurement unit must be a UUID");
783 }
784 UUID uuid = UUID.fromString(text);
785 MeasurementUnit recommendedMeasurementUnit = MeasurementUnit.getTermByUuid(uuid);
786 if (recommendedMeasurementUnit == null){
787 throw new IllegalArgumentException("Required recommended measurement unit not found for '"+text+"'");
788 }else{
789 newInstance.addRecommendedMeasurementUnit(recommendedMeasurementUnit);
790 }
791 }
792
793 return newInstance;
794 }
795
796 //******************************* STATIC METHODS *****************************************
797
798 protected static Feature getTermByUuid(UUID uuid){
799 if (termMap == null || termMap.isEmpty()){
800 return getTermByClassAndUUID(Feature.class, uuid);
801 } else {
802 return termMap.get(uuid);
803 }
804 }
805
806 /**
807 * Returns the "unknown" feature. This feature allows to store values of
808 * {@link DescriptionElementBase description elements} even if it is momentarily
809 * not known what they mean.
810 */
811 public static final Feature UNKNOWN(){
812 return getTermByUuid(uuidUnknown);
813 }
814
815 /**
816 * Returns the "description" feature. This feature allows to handle global
817 * {@link DescriptionElementBase description elements} for a global {@link DescriptionBase description}.<BR>
818 * The "description" feature is the highest level feature.
819 */
820 public static final Feature DESCRIPTION(){
821 return getTermByUuid(uuidDescription);
822 }
823
824 /**
825 * Returns the "distribution" feature. This feature allows to handle only
826 * {@link Distribution distributions}.
827 *
828 * @see #isSupportsDistribution()
829 */
830 public static final Feature DISTRIBUTION(){
831 return getTermByUuid(uuidDistribution);
832 }
833
834 /**
835 * Returns the feature for general text-based
836 * distributions
837 */
838 public static final Feature DISTRIBUTION_GENERAL(){
839 return getTermByUuid(uuidDistributionGeneral);
840 }
841
842 /**
843 * Returns the "discussion" feature. This feature can only be described
844 * with {@link TextData text data}.
845 *
846 * @see #isSupportsTextData()
847 */
848 public static final Feature DISCUSSION(){
849 return getTermByUuid(uuidDiscussion);
850 }
851
852 /**
853 * Returns the "ecology" feature. This feature only applies
854 * to {@link SpecimenDescription specimen descriptions} or to {@link TaxonDescription taxon descriptions}.<BR>
855 * The "ecology" feature generalizes all other possible features concerning
856 * ecological matters.
857 */
858 public static final Feature ECOLOGY(){
859 return getTermByUuid(uuidEcology);
860 }
861
862 /**
863 * Returns the "habitat" feature. This feature only applies
864 * to {@link SpecimenDescription specimen descriptions} or to {@link TaxonDescription taxon descriptions}.<BR>
865 * The "habitat" feature generalizes all other possible features concerning
866 * habitat matters.
867 */
868 public static final Feature HABITAT(){
869 return getTermByUuid(uuidHabitat);
870 }
871
872 /**
873 * Returns the "habitat & ecology" feature. This feature only applies
874 * to {@link SpecimenDescription specimen descriptions} or to {@link TaxonDescription taxon descriptions}.<BR>
875 * The "habitat & ecology" feature generalizes all other possible features concerning
876 * habitat and ecology matters.
877 */
878 public static final Feature HABITAT_ECOLOGY(){
879 return getTermByUuid(uuidHabitatAndEcology);
880 }
881
882 /**
883 * Returns the "biology_ecology" feature. This feature only applies
884 * to {@link SpecimenDescription specimen descriptions} or to {@link TaxonDescription taxon descriptions}.<BR>
885 * The "biology_ecology" feature generalizes all possible features concerning
886 * biological aspects of ecological matters.
887 *
888 * @see #ECOLOGY()
889 */
890 public static final Feature BIOLOGY_ECOLOGY(){
891 return getTermByUuid(uuidBiologyEcology);
892 }
893
894 /**
895 * Returns the "chromosome number" feature. This feature only applies
896 * to {@link SpecimenDescription specimen descriptions} or to {@link TaxonDescription taxon descriptions}.<BR>
897 */
898 public static final Feature CHROMOSOME_NUMBER(){
899 return getTermByUuid(uuidChromosomeNumber);
900 }
901
902 /**
903 * Returns the "key" feature. This feature is the "upper" feature generalizing
904 * all features being used within an identification key.
905 */
906 public static final Feature KEY(){
907 return getTermByUuid(uuidKey);
908 }
909
910 /**
911 * Returns the "materials_examined" feature. This feature can only be described
912 * with {@link TextData text data} or eventually with {@link CategoricalData categorical data}
913 * mentioning which material has been examined in order to accomplish
914 * the description. This feature applies only to
915 * {@link SpecimenDescription specimen descriptions} or to {@link TaxonDescription taxon descriptions}.
916 */
917 public static final Feature MATERIALS_EXAMINED(){
918 return getTermByUuid(uuidMaterialsExamined);
919 }
920
921 /**
922 * Returns the "materials_methods" feature. This feature can only be described
923 * with {@link TextData text data} or eventually with {@link CategoricalData categorical data}
924 * mentioning which methods have been adopted to analyze the material in
925 * order to accomplish the description. This feature applies only to
926 * {@link SpecimenDescription specimen descriptions} or to {@link TaxonDescription taxon descriptions}.
927 */
928 public static final Feature MATERIALS_METHODS(){
929 return getTermByUuid(uuidMaterialsMethods);
930 }
931
932 /**
933 * Returns the "etymology" feature. This feature can only be described
934 * with {@link TextData text data} or eventually with {@link CategoricalData categorical data}
935 * giving some information about the history of the taxon name. This feature applies only to
936 * {@link TaxonNameDescription taxon name descriptions}.
937 */
938 public static final Feature ETYMOLOGY(){
939 return getTermByUuid(uuidEtymology);
940 }
941
942 /**
943 * Returns the "diagnosis" feature. This feature can only be described
944 * with {@link TextData text data} or eventually with {@link CategoricalData categorical data}.
945 * This feature applies only to {@link SpecimenDescription specimen descriptions} or to
946 * {@link TaxonDescription taxon descriptions}.
947 */
948 public static final Feature DIAGNOSIS(){
949 return getTermByUuid(uuidDiagnosis);
950 }
951
952 /**
953 * Returns the "introduction" feature. This feature can only be described
954 * with {@link TextData text data}.
955 *
956 * @see #isSupportsTextData()
957 */
958 public static final Feature INTRODUCTION(){
959 return getTermByUuid(uuidIntroduction);
960 }
961
962 /**
963 * Returns the "protologue" feature. This feature can only be described
964 * with {@link TextData text data} reproducing the content of the protologue
965 * (or some information about it) of the taxon name. This feature applies only to
966 * {@link TaxonNameDescription taxon name descriptions}.
967 *
968 * @see #isSupportsTextData()
969 */
970 public static final Feature PROTOLOGUE(){
971 return getTermByUuid(uuidProtologue);
972 }
973
974 /**
975 * Returns the "common_name" feature. This feature allows to handle only
976 * {@link CommonTaxonName common names}.
977 *
978 * @see #isSupportsCommonTaxonName()
979 */
980 public static final Feature COMMON_NAME(){
981 return getTermByUuid(uuidCommonName);
982 }
983
984 /**
985 * Returns the "phenology" feature. This feature can only be described
986 * with {@link CategoricalData categorical data} or eventually with {@link TextData text data}
987 * containing information time about recurring natural phenomena.
988 * This feature only applies to {@link TaxonDescription taxon descriptions}.<BR>
989 * The "phenology" feature generalizes all other possible features
990 * concerning time information about particular natural phenomena
991 * (such as "first flight of butterflies").
992 */
993 public static final Feature PHENOLOGY(){
994 return getTermByUuid(uuidPhenology);
995 }
996
997 /**
998 * Returns the "occurrence" feature.
999 */
1000 public static final Feature OCCURRENCE(){
1001 return getTermByUuid(uuidOccurrence);
1002 }
1003
1004 /**
1005 * Returns the "anatomy" feature.
1006 */
1007 public static final Feature ANATOMY(){
1008 return getTermByUuid(uuidAnatomy);
1009 }
1010
1011 /**
1012 * Returns the "hostplant" feature.
1013 */
1014 public static final Feature HOSTPLANT(){
1015 return getTermByUuid(uuidHostPlant);
1016 }
1017
1018 /**
1019 * Returns the "pathogen agent" feature.
1020 */
1021 public static final Feature PATHOGEN_AGENT(){
1022 return getTermByUuid(uuidPathogenAgent);
1023 }
1024
1025 /**
1026 * Returns the "citation" feature. This feature can only be described
1027 * with {@link TextData text data}.
1028 *
1029 * @see #isSupportsTextData()
1030 */
1031 public static final Feature CITATION(){
1032 return getTermByUuid(uuidCitation);
1033 }
1034
1035 /**
1036 * Returns the "additional_publication" feature. This feature can only be
1037 * described with {@link TextData text data} with information about a
1038 * publication where a {@link TaxonName taxon name} has also been published
1039 * but which is not the {@link TaxonName#getNomenclaturalReference() nomenclatural reference}.
1040 * This feature applies only to {@link TaxonNameDescription taxon name descriptions}.
1041 *
1042 * @see #isSupportsTextData()
1043 */
1044 public static final Feature ADDITIONAL_PUBLICATION(){
1045 return getTermByUuid(uuidAdditionalPublication);
1046 }
1047
1048 /**
1049 * Returns the "uses" feature. This feature only applies
1050 * to {@link TaxonDescription taxon descriptions}.<BR>
1051 * The "uses" feature generalizes all other possible features concerning
1052 * particular uses (for instance "industrial use of seeds").
1053 */
1054 public static final Feature USES(){
1055 return getTermByUuid(uuidUses);
1056 }
1057
1058 public static final Feature USERECORD(){
1059 return getTermByUuid(uuidUseRecord);
1060 }
1061
1062 /**
1063 * Returns the "notes" feature. Used for
1064 * taxonomic notes.
1065 */
1066 public static final Feature NOTES(){
1067 return getTermByUuid(uuidNotes);
1068 }
1069
1070 /**
1071 * Returns the "conservation" feature. This feature only applies
1072 * to {@link SpecimenDescription specimen descriptions} and generalizes
1073 * methods and conditions for the conservation of {@link Specimen specimens}.<BR>
1074 */
1075 public static final Feature CONSERVATION(){
1076 return getTermByUuid(uuidConservation);
1077 }
1078
1079 /**
1080 * Returns the "cultivation" feature.
1081 */
1082 public static final Feature CULTIVATION(){
1083 return getTermByUuid(uuidCultivation);
1084 }
1085
1086 /**
1087 * Returns the "image" feature.
1088 */
1089 public static final Feature IMAGE(){
1090 return getTermByUuid(uuidImage);
1091 }
1092
1093 /**
1094 * Returns the "individuals association" feature.
1095 */
1096 public static final Feature INDIVIDUALS_ASSOCIATION(){
1097 Feature individuals_association = getTermByUuid(uuidIndividualsAssociation);
1098 Set<Feature> generalizationOf = new HashSet<>();
1099 generalizationOf.add(SPECIMEN());
1100 generalizationOf.add(OBSERVATION());
1101 individuals_association.setGeneralizationOf(generalizationOf);
1102 return individuals_association;
1103
1104 }
1105
1106 public static final Feature SPECIMEN(){
1107 return getTermByUuid(uuidSpecimen);
1108 }
1109
1110 public static final Feature OBSERVATION(){
1111 return getTermByUuid(uuidObservation);
1112 }
1113
1114 /**
1115 * The status of a taxon. Usually the status should be determined within a {@link Distribution distribution}.
1116 * If this is not possible for some reason (e.g. the area is not well defined) the status feature
1117 * may be used.
1118 * @return
1119 */
1120 public static final Feature STATUS(){
1121 return getTermByUuid(uuidStatus);
1122 }
1123
1124 public static final Feature SYSTEMATICS(){
1125 return getTermByUuid(uuidSystematics);
1126 }
1127
1128 public static final Feature LIFEFORM(){
1129 return getTermByUuid(uuidLifeform);
1130 }
1131
1132 public static final Feature FLOWERING_PERIOD(){
1133 return getTermByUuid(uuidFloweringPeriod);
1134 }
1135
1136 public static final Feature FRUITING_PERIOD(){
1137 return getTermByUuid(uuidFruitingPeriod);
1138 }
1139
1140 public static final Feature ALTITUDE(){
1141 return getTermByUuid(uuidAltitude);
1142 }
1143 //
1144 // /**
1145 // * Returns the "hybrid_parent" feature. This feature can only be used
1146 // * by {@link TaxonInteraction taxon interactions}.<BR>
1147 // * <P>
1148 // * Note: It must be distinguished between hybrid relationships as
1149 // * relevant nomenclatural relationships between {@link BotanicalName plant names}
1150 // * on the one side and the biological relation between two {@link Taxon taxa}
1151 // * as it is here the case on the other one.
1152 // *
1153 // * @see #isSupportsTaxonInteraction()
1154 // * @see HybridRelationshipType
1155 // */
1156 // public static final Feature HYBRID_PARENT(){
1157 // //TODO
1158 // logger.warn("HYBRID_PARENT not yet implemented");
1159 // return null;
1160 // }
1161
1162 @Override
1163 protected void setDefaultTerms(TermVocabulary<Feature> termVocabulary) {
1164 if (termMap == null){ //needed because there are multiple feature vocabularies
1165 termMap = new HashMap<>();
1166 }
1167 for (Feature term : termVocabulary.getTerms()){
1168 termMap.put(term.getUuid(), term);
1169 }
1170 }
1171
1172 //*********************************** CLONE *********************************************************/
1173
1174 @Override
1175 public Feature clone() {
1176 Feature result = (Feature)super.clone();
1177
1178 result.inverseRepresentations = new HashSet<Representation>();
1179 for (Representation rep: this.inverseRepresentations){
1180 result.addInverseRepresentation(rep.clone());
1181 }
1182
1183 //no changes to: symmetric, transitiv
1184 return result;
1185 }
1186
1187 }