final implementation of MaterialOrMethodEvent, Cloning, PreservationMethod, ... ...
[cdmlib.git] / cdmlib-model / src / main / java / eu / etaxonomy / cdm / model / description / WorkingSet.java
1 // $Id$
2 /**
3 * Copyright (C) 2007 EDIT
4 * European Distributed Institute of Taxonomy
5 * http://www.e-taxonomy.eu
6 *
7 * The contents of this file are subject to the Mozilla Public License Version 1.1
8 * See LICENSE.TXT at the top of this package for the full license terms.
9 */
10
11 package eu.etaxonomy.cdm.model.description;
12
13 import java.util.HashSet;
14 import java.util.Iterator;
15 import java.util.List;
16 import java.util.Set;
17
18 import javax.persistence.Entity;
19 import javax.persistence.FetchType;
20 import javax.persistence.JoinColumn;
21 import javax.persistence.JoinTable;
22 import javax.persistence.ManyToMany;
23 import javax.persistence.ManyToOne;
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.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.AnnotatableEntity;
42 import eu.etaxonomy.cdm.model.common.Language;
43 import eu.etaxonomy.cdm.model.common.Representation;
44
45 /**
46 *
47 * The working set class allows the demarcation of a set of descriptions
48 * associated with representations and a set of features and their
49 * dependencies.
50 *
51 * @author h.fradin
52 * @created 12.08.2009
53 * @version 1.0
54 */
55
56 @XmlAccessorType(XmlAccessType.FIELD)
57 @XmlType(name = "WorkingSet", propOrder = {
58 "representations",
59 "descriptiveSystem",
60 "descriptions"
61 })
62 @XmlRootElement(name = "WorkingSet")
63 @Entity
64 @Audited
65
66 public class WorkingSet extends AnnotatableEntity {
67 private static final long serialVersionUID = 3256448866757415686L;
68 private static final Logger logger = Logger.getLogger(WorkingSet.class);
69
70 @XmlElementWrapper(name = "Representations")
71 @XmlElement(name = "Representation")
72 @OneToMany(fetch=FetchType.EAGER)
73 @Cascade( { CascadeType.SAVE_UPDATE, CascadeType.MERGE, CascadeType.DELETE })
74 private Set<Representation> representations = new HashSet<Representation>();
75
76 @XmlElement(name = "DescriptiveSystem")
77 @XmlIDREF
78 @XmlSchemaType(name = "IDREF")
79 @ManyToOne(fetch = FetchType.LAZY)
80 @Cascade({CascadeType.SAVE_UPDATE})
81 private FeatureTree descriptiveSystem;
82
83 @XmlElementWrapper(name = "Descriptions")
84 @XmlElement(name = "Description")
85 @XmlIDREF
86 @XmlSchemaType(name = "IDREF")
87 @ManyToMany(fetch = FetchType.LAZY)
88 @JoinTable(
89 name="WorkingSet_DescriptionBase",
90 joinColumns=@JoinColumn(name="WorkingSet_id"),
91 inverseJoinColumns=@JoinColumn(name="descriptions_id")
92 )
93 @Cascade(CascadeType.SAVE_UPDATE)
94 @NotNull
95 private Set<DescriptionBase> descriptions = new HashSet<DescriptionBase>();
96
97 /**
98 * Class constructor: creates a new empty working set instance.
99 */
100 protected WorkingSet() {
101 super();
102 }
103
104 /**
105 * Creates a new empty working set instance.
106 */
107 public static WorkingSet NewInstance(){
108 return new WorkingSet();
109 }
110
111 public Set<Representation> getRepresentations() {
112 return this.representations;
113 }
114
115 public void addRepresentation(Representation representation) {
116 this.representations.add(representation);
117 }
118
119 public void removeRepresentation(Representation representation) {
120 this.representations.remove(representation);
121 }
122
123 public Representation getRepresentation(Language lang) {
124 for (Representation repr : representations){
125 Language reprLanguage = repr.getLanguage();
126 if (reprLanguage != null && reprLanguage.equals(lang)){
127 return repr;
128 }
129 }
130 return null;
131 }
132
133 /**
134 * @see #getPreferredRepresentation(Language)
135 * @param language
136 * @return
137 */
138 public Representation getPreferredRepresentation(Language language) {
139 Representation repr = getRepresentation(language);
140 if(repr == null){
141 repr = getRepresentation(Language.DEFAULT());
142 }
143 if(repr == null){
144 repr = getRepresentations().iterator().next();
145 }
146 return repr;
147 }
148
149 /**
150 * Returns the Representation in the preferred language. Preferred languages
151 * are specified by the parameter languages, which receives a list of
152 * Language instances in the order of preference. If no representation in
153 * any preferred languages is found the method falls back to return the
154 * Representation in Language.DEFAULT() and if necessary further falls back
155 * to return the first element found if any.
156 *
157 * TODO think about this fall-back strategy &
158 * see also {@link TextData#getPreferredLanguageString(List)}
159 *
160 * @param languages
161 * @return
162 */
163 public Representation getPreferredRepresentation(List<Language> languages) {
164 Representation repr = null;
165 if(languages != null){
166 for(Language language : languages) {
167 repr = getRepresentation(language);
168 if(repr != null){
169 return repr;
170 }
171 }
172 }
173 if(repr == null){
174 repr = getRepresentation(Language.DEFAULT());
175 }
176 if(repr == null){
177 Iterator<Representation> it = getRepresentations().iterator();
178 if(it.hasNext()){
179 repr = getRepresentations().iterator().next();
180 }
181 }
182 return repr;
183 }
184
185 @Transient
186 public String getLabel() {
187 if(getLabel(Language.DEFAULT())!=null){
188 Representation repr = getRepresentation(Language.DEFAULT());
189 return (repr == null)? null :repr.getLabel();
190 }else{
191 for (Representation r : representations){
192 return r.getLabel();
193 }
194 }
195 return super.getUuid().toString();
196 }
197
198 public String getLabel(Language lang) {
199 Representation repr = this.getRepresentation(lang);
200 return (repr == null) ? null : repr.getLabel();
201 }
202
203 public void setLabel(String label){
204 Language lang = Language.DEFAULT();
205 setLabel(label, lang);
206 }
207
208 public void setLabel(String label, Language language){
209 if (language != null){
210 Representation repr = getRepresentation(language);
211 if (repr != null){
212 repr.setLabel(label);
213 }else{
214 repr = Representation.NewInstance(null, label, null, language);
215 }
216 this.addRepresentation(repr);
217 }
218 }
219
220 public FeatureTree getDescriptiveSystem() {
221 return descriptiveSystem;
222 }
223 public void setDescriptiveSystem(FeatureTree descriptiveSystem) {
224 this.descriptiveSystem = descriptiveSystem;
225 }
226
227 /**
228 * Returns the {@link DescriptionBase descriptions} of
229 * <i>this</i> working set.
230 *
231 * @see #addDescription(DescriptionBase)
232 * @see #removeDescription(DescriptionBase)
233 */
234 public Set<DescriptionBase> getDescriptions() {
235 return descriptions;
236 }
237
238 /**
239 * Adds an existing {@link DescriptionBase description} to the set of
240 * {@link #getDescriptions() descriptions} of <i>this</i>
241 * working set.
242 *
243 * @param description the description to be added to <i>this</i> working set
244 * @see #getDescriptions()
245 * @see WorkingSet#addDescription(DescriptionBase)
246 */
247 public boolean addDescription(DescriptionBase description) {
248 boolean result = this.descriptions.add(description);
249 if (! description.getWorkingSets().contains(this)){
250 description.addWorkingSet(this);
251 }
252 return result;
253 }
254
255 /**
256 * Removes one element from the set of {@link #getDescriptions() descriptions} involved
257 * in <i>this</i> working set.<BR>
258 *
259 * @param description the description which should be removed
260 * @see #getDescriptions()
261 * @see #addDescription(DescriptionBase)
262 * @see WorkingSet#removeDescription(DescriptionBase)
263 */
264 public boolean removeDescription(DescriptionBase description) {
265 boolean result = this.descriptions.remove(description);
266 if (description.getWorkingSets().contains(this)){
267 description.removeWorkingSet(this);
268 }
269 return result;
270 }
271
272 //*********************** CLONE ********************************************************/
273
274 /**
275 * Clones <i>this</i> WorkingSet. This is a shortcut that enables to create
276 * a new instance that differs only slightly from <i>this</i> WorkingSet by
277 * modifying only some of the attributes.
278 * The descriptions and the descriptive system are the same, the representations
279 * are cloned.
280 *
281 * @see eu.etaxonomy.cdm.model.common.AnnotatableEntity#clone()
282 * @see java.lang.Object#clone()
283 */
284 @Override
285 public Object clone() {
286 WorkingSet result;
287 try {
288 result = (WorkingSet)super.clone();
289 result.descriptions = new HashSet<DescriptionBase>();
290
291 for (DescriptionBase desc: this.descriptions){
292 result.addDescription(desc);
293 }
294
295 result.representations = new HashSet<Representation>();
296 for (Representation rep : this.representations){
297 result.addRepresentation((Representation)rep.clone());
298 }
299
300 return result;
301 }catch (CloneNotSupportedException e) {
302 logger.warn("Object does not implement cloneable");
303 e.printStackTrace();
304 return null;
305 }
306 }
307
308 }