Merging r13268 through r14040 from trunk/cdmlib into branches/cdmlib-unitils3
[cdmlib.git] / cdmlib-model / src / main / java / eu / etaxonomy / cdm / model / description / StateData.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.Map;
16 import java.util.Set;
17
18 import javax.persistence.Entity;
19 import javax.persistence.FetchType;
20 import javax.persistence.ManyToMany;
21 import javax.persistence.ManyToOne;
22 import javax.persistence.OneToMany;
23 import javax.validation.constraints.NotNull;
24 import javax.xml.bind.annotation.XmlAccessType;
25 import javax.xml.bind.annotation.XmlAccessorType;
26 import javax.xml.bind.annotation.XmlElement;
27 import javax.xml.bind.annotation.XmlElementWrapper;
28 import javax.xml.bind.annotation.XmlIDREF;
29 import javax.xml.bind.annotation.XmlRootElement;
30 import javax.xml.bind.annotation.XmlSchemaType;
31 import javax.xml.bind.annotation.XmlType;
32 import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
33
34 import org.apache.log4j.Logger;
35 import org.hibernate.annotations.Cascade;
36 import org.hibernate.annotations.CascadeType;
37 import org.hibernate.envers.Audited;
38
39 import eu.etaxonomy.cdm.jaxb.MultilanguageTextAdapter;
40 import eu.etaxonomy.cdm.model.common.IMultiLanguageTextHolder;
41 import eu.etaxonomy.cdm.model.common.Language;
42 import eu.etaxonomy.cdm.model.common.LanguageString;
43 import eu.etaxonomy.cdm.model.common.MultilanguageText;
44 import eu.etaxonomy.cdm.model.common.TermVocabulary;
45 import eu.etaxonomy.cdm.model.common.VersionableEntity;
46
47 /**
48 * This class represents the assignment of values ({@link State state terms}) to {@link Feature features}
49 * corresponding to {@link CategoricalData categorical data}. A state data instance
50 * constitutes an atomized part of an information piece (categorical data) so
51 * that several state data instances may belong to one categorical data
52 * instance.
53 * <P>
54 * This class corresponds to CharacterStateDataType according to the SDD schema.
55 *
56 * @author m.doering
57 * @version 1.0
58 * @created 08-Nov-2007 13:06:53
59 */
60 @XmlAccessorType(XmlAccessType.FIELD)
61 @XmlType(name = "StateData", propOrder = {
62 "state",
63 "modifiers",
64 "modifyingText"
65 })
66 @XmlRootElement(name = "StateData")
67 @Entity
68 @Audited
69 public class StateData extends VersionableEntity implements IModifiable, IMultiLanguageTextHolder, Cloneable{
70 private static final long serialVersionUID = -4380314126624505415L;
71 private static final Logger logger = Logger.getLogger(StateData.class);
72
73 @XmlElement(name = "State")
74 @XmlIDREF
75 @XmlSchemaType(name = "IDREF")
76 @ManyToOne(fetch = FetchType.LAZY)
77 private State state;
78
79 @XmlElementWrapper(name = "Modifiers")
80 @XmlElement(name = "Modifier")
81 @ManyToMany(fetch = FetchType.LAZY)
82 @Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE})
83 // @NotNull // avoids creating a UNIQUE key for this field -> not needed for ManyToMany
84 private Set<Modifier> modifiers = new HashSet<Modifier>();
85
86 @XmlElement(name = "ModifyingText")
87 @XmlJavaTypeAdapter(MultilanguageTextAdapter.class)
88 @OneToMany(fetch = FetchType.LAZY)
89 @Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE})
90 private Map<Language,LanguageString> modifyingText = new HashMap<Language,LanguageString>();
91
92 //********************* FACTORY METHODS ************************\
93
94 /**
95 * Creates a new empty state data instance.
96 */
97 public static StateData NewInstance(){
98 return new StateData();
99 }
100
101
102 /**
103 * Creates a new empty state data instance.
104 */
105 public static StateData NewInstance(State state){
106 return new StateData();
107 }
108
109 /**
110 * Creates a new empty state data instance.
111 */
112 public static StateData NewInstance(String term, String label, String labelAbbrev){
113 State state = State.NewInstance(term, label, labelAbbrev);
114 return NewInstance(state);
115 }
116
117 //*************************** CONSTRUCTOR ************************\
118
119 /**
120 * Class constructor: creates a new empty state data instance.
121 */
122 public StateData() {
123 super();
124 }
125
126 //************************** GETTER /SETTER *************************\
127
128 /**
129 * Returns the {@link State state term} used in <i>this</i> state data.
130 */
131 public State getState(){
132 return this.state;
133 }
134 /**
135 * @see #getState()
136 */
137 public void setState(State state){
138 this.state = state;
139 }
140
141
142 /**
143 * Returns the set of {@link Modifier modifiers} used to qualify the validity
144 * of <i>this</i> state data. This is only metainformation.
145 */
146 public Set<Modifier> getModifiers(){
147 return this.modifiers;
148 }
149
150 /**
151 * Adds a {@link Modifier modifier} to the set of {@link #getModifiers() modifiers}
152 * used to qualify the validity of <i>this</i> state data.
153 *
154 * @param modifier the modifier to be added to <i>this</i> state data
155 * @see #getModifiers()
156 */
157 public void addModifier(Modifier modifier){
158 this.modifiers.add(modifier);
159 }
160 /**
161 * Removes one element from the set of {@link #getModifiers() modifiers}
162 * used to qualify the validity of <i>this</i> state data.
163 *
164 * @param modifier the modifier which should be removed
165 * @see #getModifiers()
166 * @see #addModifier(Modifier)
167 */
168 public void removeModifier(Modifier modifier){
169 this.modifiers.remove(modifier);
170 }
171
172
173 /**
174 * Returns the {@link MultilanguageText multilanguage text} used to qualify the validity
175 * of <i>this</i> state data. The different {@link LanguageString language strings}
176 * contained in the multilanguage text should all have the same meaning.<BR>
177 * A multilanguage text does not belong to a controlled {@link TermVocabulary term vocabulary}
178 * as a {@link Modifier modifier} does.
179 * <P>
180 * NOTE: the actual content of <i>this</i> state data is NOT
181 * stored in the modifying text. This is only metainformation
182 * (like "Some experts express doubt about this assertion").
183 */
184 public Map<Language,LanguageString> getModifyingText(){
185 return this.modifyingText;
186 }
187
188 /**
189 * Creates a {@link LanguageString language string} based on the given text string
190 * and the given {@link Language language} and adds it to the {@link MultilanguageText multilanguage text}
191 * used to qualify the validity of <i>this</i> state data.
192 *
193 *
194 * @param text the string describing the validity
195 * in a particular language
196 * @param language the language in which the text string is formulated
197 *
198 * @see #getModifyingText()
199 * @see #putModifyingText(LanguageString)
200 * @deprecated should follow the put semantic of maps, this method will be removed in v4.0
201 * Use the {@link #putModifyingText(Language, String) putModifyingText} method instead
202 */
203 @Deprecated
204 public LanguageString addModifyingText(String text, Language language){
205 return this.putModifyingText(language, text);
206 }
207
208 /**
209 * Creates a {@link LanguageString language string} based on the given text string
210 * and the given {@link Language language} and adds it to the {@link MultilanguageText multilanguage text}
211 * used to qualify the validity of <i>this</i> state data.
212 *
213 * @param language the language in which the text string is formulated
214 * @param text the string describing the validity
215 * in a particular language
216 *
217 * @see #getModifyingText()
218 * @see #addModifyingText(LanguageString)
219 */
220 public LanguageString putModifyingText(Language language, String text){
221 return this.modifyingText.put(language, LanguageString.NewInstance(text, language));
222 }
223 /**
224 * Adds a translated {@link LanguageString text in a particular language}
225 * to the {@link MultilanguageText multilanguage text} used to qualify the validity
226 * of <i>this</i> state data.
227 *
228 * @param text the language string describing the validity
229 * in a particular language
230 * @see #getModifyingText()
231 * @see #putModifyingText(Language, String)
232 * @deprecated should follow the put semantic of maps, this method will be removed in v4.0
233 * Use the {@link #putModifyingText(LanguagString) putModifyingText} method instead
234 */
235 @Deprecated
236 public LanguageString addModifyingText(LanguageString text){
237 return this.putModifyingText(text);
238 }
239
240 /**
241 * Adds a translated {@link LanguageString text in a particular language}
242 * to the {@link MultilanguageText multilanguage text} used to qualify the validity
243 * of <i>this</i> state data.
244 *
245 * @param text the language string describing the validity
246 * in a particular language
247 * @see #getModifyingText()
248 * @see #putModifyingText(Language, String)
249 */
250 public LanguageString putModifyingText(LanguageString text){
251 return this.modifyingText.put(text.getLanguage(),text);
252 }
253 /**
254 * Removes from the {@link MultilanguageText multilanguage text} used to qualify the validity
255 * of <i>this</i> state data the one {@link LanguageString language string}
256 * with the given {@link Language language}.
257 *
258 * @param lang the language in which the language string to be removed
259 * has been formulated
260 * @see #getModifyingText()
261 */
262 public LanguageString removeModifyingText(Language lang){
263 return this.modifyingText.remove(lang);
264 }
265
266 //*********************************** CLONE *****************************************/
267
268 /**
269 * Clones <i>this</i> state data. This is a shortcut that enables to create
270 * a new instance that differs only slightly from <i>this</i> state data by
271 * modifying only some of the attributes.
272 *
273 * @see eu.etaxonomy.cdm.model.common.VersionableEntity#clone()
274 * @see java.lang.Object#clone()
275 */
276 @Override
277 public Object clone() {
278
279 try {
280 StateData result = (StateData)super.clone();
281
282 //modifiers
283 result.modifiers = new HashSet<Modifier>();
284 for (Modifier modifier : getModifiers()){
285 result.modifiers.add(modifier);
286 }
287
288 //modifying text
289 result.modifyingText = new HashMap<Language, LanguageString>();
290 for (Language language : getModifyingText().keySet()){
291 //TODO clone needed? See also IndividualsAssociation
292 LanguageString newLanguageString = (LanguageString)getModifyingText().get(language).clone();
293 result.modifyingText.put(language, newLanguageString);
294 }
295
296 return result;
297 //no changes to: state
298 } catch (CloneNotSupportedException e) {
299 logger.warn("Object does not implement cloneable");
300 e.printStackTrace();
301 return null;
302 }
303 }
304 }