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