2 * Copyright (C) 2007 EDIT
3 * European Distributed Institute of Taxonomy
4 * http://www.e-taxonomy.eu
6 * The contents of this file are subject to the Mozilla Public License Version 1.1
7 * See LICENSE.TXT at the top of this package for the full license terms.
9 package eu
.etaxonomy
.cdm
.model
.description
;
11 import java
.util
.ArrayList
;
12 import java
.util
.Arrays
;
13 import java
.util
.List
;
15 import javax
.persistence
.Column
;
16 import javax
.persistence
.Entity
;
17 import javax
.persistence
.FetchType
;
18 import javax
.persistence
.OneToMany
;
19 import javax
.persistence
.Transient
;
20 import javax
.validation
.constraints
.NotEmpty
;
21 import javax
.xml
.bind
.annotation
.XmlAccessType
;
22 import javax
.xml
.bind
.annotation
.XmlAccessorType
;
23 import javax
.xml
.bind
.annotation
.XmlAttribute
;
24 import javax
.xml
.bind
.annotation
.XmlElement
;
25 import javax
.xml
.bind
.annotation
.XmlElementWrapper
;
26 import javax
.xml
.bind
.annotation
.XmlRootElement
;
27 import javax
.xml
.bind
.annotation
.XmlTransient
;
28 import javax
.xml
.bind
.annotation
.XmlType
;
30 import org
.apache
.logging
.log4j
.LogManager
;
31 import org
.apache
.logging
.log4j
.Logger
;
32 import org
.hibernate
.annotations
.Cascade
;
33 import org
.hibernate
.annotations
.CascadeType
;
34 import org
.hibernate
.annotations
.Type
;
35 import org
.hibernate
.envers
.Audited
;
36 import org
.hibernate
.search
.annotations
.Indexed
;
37 import org
.hibernate
.search
.annotations
.IndexedEmbedded
;
39 import eu
.etaxonomy
.cdm
.model
.term
.DefinedTermBase
;
40 import eu
.etaxonomy
.cdm
.validation
.Level2
;
43 * This class represents information pieces expressed in categorical type of
44 * data (in opposition to {@link QuantitativeData quantitative data} on one side and to literal data on
45 * the other side). Only {@link TaxonDescription taxon descriptions} and
46 * {@link SpecimenDescription specimen descriptions} may contain categorical data.<BR>
47 * The "color of petals" {@link Feature feature} for instance can be described with
48 * {@link State state terms} such as "blue" or "white". If the color of petals of a
49 * particular tree is described as "mostly blue" and "exceptionally white" two
50 * {@link StateData state data} instances must be assigned to an instance of the
51 * present class: the first one with the state "blue" and the {@link Modifier modifier}
52 * "mostly" and the second one with the state "white" and the modifier "exceptionally".
53 * Whenever more than one state data belongs to a categorical data they should be
54 * interpreted as being related by the inclusive disjunction "or".
56 * This class corresponds partially to CodedDescriptionType according to
60 * @since 08-Nov-2007 13:06:15
62 @XmlAccessorType(XmlAccessType
.FIELD
)
63 @XmlType(name
= "CategoricalData", propOrder
= {
68 @XmlRootElement(name
= "CategoricalData")
71 @Indexed(index
= "eu.etaxonomy.cdm.model.description.DescriptionElementBase")
72 public class CategoricalData
extends DescriptionElementBase
{
74 private static final long serialVersionUID
= -6298361966947668998L;
75 @SuppressWarnings("unused")
76 private static final Logger logger
= LogManager
.getLogger();
78 //whether the sequence of ordered states is important
79 @XmlElement(name
= "OrderRelevant")
80 private boolean orderRelevant
;
82 @XmlElementWrapper(name
= "States")
83 @XmlElement(name
= "State")
84 @OneToMany(fetch
= FetchType
.LAZY
, mappedBy
="categoricalData", orphanRemoval
=true)
85 @Cascade({ CascadeType
.SAVE_UPDATE
, CascadeType
.MERGE
, CascadeType
.DELETE
})
86 @IndexedEmbedded(depth
= 3)
87 @NotEmpty(groups
= Level2
.class)
88 private List
<StateData
> stateData
= new ArrayList
<>();
90 @XmlAttribute(name
="NoDataStatus")
91 @Column(name
="noDataStatus", length
=10)
92 @Type(type
= "eu.etaxonomy.cdm.hibernate.EnumUserType",
93 parameters
= {@org.hibernate
.annotations
.Parameter(name
= "enumClass", value
= "eu.etaxonomy.cdm.model.description.NoDescriptiveDataStatus")}
95 //see also QuantitativeData.noDataStatus
96 private NoDescriptiveDataStatus noDataStatus
;
98 //****************************** FACTORY METHOD *******************************/
101 * Creates a new empty categorical data instance.
103 public static CategoricalData
NewInstance(){
104 return new CategoricalData();
107 public static CategoricalData
NewInstance(Feature feature
) {
108 return new CategoricalData( new ArrayList
<>() , feature
);
112 * Creates a new empty categorical data instance.
114 public static CategoricalData
NewInstance(DefinedTermBase
<?
> state
, Feature feature
){
115 return new CategoricalData( Arrays
.asList( new DefinedTermBase
<?
>[]{state
}) , feature
);
118 //******************* CONSTRUCTOR *********************************************/
121 * Class constructor: creates a new empty categorical data instance.
123 protected CategoricalData() {
128 * Class constructor: creates a new empty categorical data instance.
130 protected CategoricalData(List
<DefinedTermBase
<?
>> states
, Feature feature
) {
132 for (DefinedTermBase
<?
> state
: states
){
137 // ****************** GETTER / SETTER *********************************************/
140 * Returns the (ordered) list of {@link State states} describing the {@link Feature feature}
141 * corresponding to <i>this</i> categorical data.
143 public List
<StateData
> getStateData(){
144 return this.stateData
;
148 protected void setStateData(List
<StateData
> stateData
){
149 this.stateData
= stateData
;
153 * Adds a {@link State state} to the list of {@link #getStateData() states}
154 * describing the {@link Feature feature} corresponding to <i>this</i> categorical data.
156 * @param state the state to be added to <i>this</i> categorical data
157 * @see #getStateData()
159 @SuppressWarnings("deprecation")
160 public void addStateData(StateData stateData
){
161 this.stateData
.add(stateData
);
162 stateData
.setCategoricalData(this);
166 * Convenience method which creates a state data from a given state with no modifiers
167 * and adds it to the list of state data
168 * @see #addStateData(StateData)
171 public StateData
addStateData(DefinedTermBase
<?
> state
){
172 StateData stateData
= StateData
.NewInstance(state
);
173 addStateData(stateData
);
178 * Removes one element from the set of {@link #getStateData() states}
179 * describing the {@link Feature feature} corresponding to <i>this</i> categorical data.
181 * @param state the state which should be removed
182 * @see #getStateData()
183 * @see #addStateData(State)
185 @SuppressWarnings("deprecation")
186 public void removeStateData(StateData stateData
){
187 this.stateData
.remove(stateData
);
188 stateData
.setCategoricalData(null);
191 //rename to isStateSequenceIntentional ??
193 * Returns the boolean value of the flag indicating whether the sequence of
194 * {@link StateData state data} belonging to <i>this</i> categorical data is intentional
195 * (true) and therefore relevant for interpretation or analysis or not (false).
196 * The use of this flag depends mostly on the {@link Feature feature} of <i>this</i> categorical data.
198 * @return the boolean value of the orderRelevant flag
200 public boolean getOrderRelevant(){
201 return this.orderRelevant
;
204 * @see #getOrderRelevant()
206 public void setOrderRelevant(boolean orderRelevant
){
207 this.orderRelevant
= orderRelevant
;
210 //no data status, #2975
211 public NoDescriptiveDataStatus
getNoDataStatus() {
214 public void setNoDataStatus(NoDescriptiveDataStatus noDataStatus
) {
215 this.noDataStatus
= noDataStatus
;
218 // ********************* CONVENIENCE ******************************************/
221 * Convenience method to test the existence of a given state in the state data.
222 * Note: the method ignores modifiers so state data having the state may still be
223 * modified by its modifiers.
225 * @param state the given {@link State}
226 * @return <code>true</code> if the state exists
228 public boolean hasState(DefinedTermBase
<?
> state
) {
229 return getStatesOnly().contains(state
);
233 * Convenience method returning only the list of states. Leaving out modifiers and modifying text.
236 public List
<eu
.etaxonomy
.cdm
.model
.term
.DefinedTermBase
<?
>> getStatesOnly(){
237 List
<DefinedTermBase
<?
>> result
= new ArrayList
<>();
238 for (StateData stateData
: getStateData()){
239 DefinedTermBase
<?
> state
= stateData
.getState();
248 * Convenience method which to set the list of states (no modifiers or modifying text allowed).
249 * All existing state data are removed.
252 public List
<StateData
> setStateDataOnly(List
<?
extends DefinedTermBase
<?
>> states
){
253 List
<StateData
> stateDataList
= new ArrayList
<>(getStateData());
254 for (StateData stateData
: stateDataList
) {
255 removeStateData(stateData
);
257 for (DefinedTermBase
<?
> state
: states
) {
260 return this.stateData
;
266 public boolean isCharacterData() {
270 //********************************** toString **************************************/
273 public String
toString() {
274 return (getFeature()!=null ?
getFeature().getLabel(): "") +
276 (orderRelevant?
", orderRelevant=" + orderRelevant
:"") +
277 (noDataStatus
!= null ?
", noDataStatus=" + noDataStatus
.getLabel() :"")
281 //*********************************** CLONE *****************************************/
284 * Clones <i>this</i> categorical data. This is a shortcut that enables to create
285 * a new instance that differs only slightly from <i>this</i> categorical data by
286 * modifying only some of the attributes.
287 * @throws CloneNotSupportedException
289 * @see eu.etaxonomy.cdm.model.description.DescriptionElementBase#clone()
290 * @see java.lang.Object#clone()
293 public CategoricalData
clone() {
295 CategoricalData result
= (CategoricalData
)super.clone();
298 result
.stateData
= new ArrayList
<>();
299 for (StateData stateData
: getStateData()){
300 StateData newState
= stateData
.clone();
301 result
.addStateData(newState
);
304 //no changes to: orderRelevant