Project

General

Profile

Download (12.2 KB) Statistics
| Branch: | Tag: | Revision:
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
import java.util.HashSet;
13
import java.util.Iterator;
14
import java.util.List;
15
import java.util.Set;
16

    
17
import javax.persistence.Entity;
18
import javax.persistence.FetchType;
19
import javax.persistence.JoinTable;
20
import javax.persistence.ManyToMany;
21
import javax.persistence.ManyToOne;
22
import javax.persistence.OneToMany;
23
import javax.persistence.Transient;
24
import javax.validation.constraints.NotNull;
25
import javax.xml.bind.annotation.XmlAccessType;
26
import javax.xml.bind.annotation.XmlAccessorType;
27
import javax.xml.bind.annotation.XmlElement;
28
import javax.xml.bind.annotation.XmlElementWrapper;
29
import javax.xml.bind.annotation.XmlIDREF;
30
import javax.xml.bind.annotation.XmlRootElement;
31
import javax.xml.bind.annotation.XmlSchemaType;
32
import javax.xml.bind.annotation.XmlType;
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.model.common.IdentifiableEntity;
40
import eu.etaxonomy.cdm.model.common.Language;
41
import eu.etaxonomy.cdm.model.common.Representation;
42
import eu.etaxonomy.cdm.model.location.NamedArea;
43
import eu.etaxonomy.cdm.model.name.Rank;
44
import eu.etaxonomy.cdm.model.taxon.TaxonNode;
45
import eu.etaxonomy.cdm.strategy.cache.description.DescriptiveDataSetDefaultCacheStrategy;
46

    
47
/**
48
 *
49
 * The working set class allows the demarcation of a set of descriptions
50
 * associated with representations and a set of features and their
51
 * dependencies.
52
 *
53
 * @author h.fradin
54
 * @since 12.08.2009
55
 */
56

    
57
@XmlAccessorType(XmlAccessType.FIELD)
58
@XmlType(name = "DescriptiveDataSet", propOrder = {
59
    "representations",
60
    "descriptiveSystem",
61
    "descriptions",
62
    "taxonSubtreeFilter",
63
    "geoFilter",
64
    "minRank",
65
    "maxRank"
66
})
67
@XmlRootElement(name = "DescriptiveDataSet")
68
@Entity
69
@Audited
70
public class DescriptiveDataSet extends IdentifiableEntity<DescriptiveDataSetDefaultCacheStrategy> {
71
	private static final long serialVersionUID = 3256448866757415686L;
72
	private static final Logger logger = Logger.getLogger(DescriptiveDataSet.class);
73

    
74
	@XmlElementWrapper(name = "Representations")
75
	@XmlElement(name = "Representation")
76
    @OneToMany(fetch=FetchType.EAGER)
77
	@Cascade( { CascadeType.SAVE_UPDATE, CascadeType.MERGE, CascadeType.DELETE })
78
	private Set<Representation> representations = new HashSet<>();
79

    
80
	@XmlElement(name = "DescriptiveSystem")
81
	@XmlIDREF
82
	@XmlSchemaType(name = "IDREF")
83
	@ManyToOne(fetch = FetchType.LAZY)
84
	@Cascade({CascadeType.SAVE_UPDATE,CascadeType.MERGE})
85
	private FeatureTree<Character> descriptiveSystem;
86

    
87
	@XmlElementWrapper(name = "Descriptions")
88
	@XmlElement(name = "Description")
89
    @XmlIDREF
90
    @XmlSchemaType(name = "IDREF")
91
    @ManyToMany(fetch = FetchType.LAZY)
92
	@Cascade({CascadeType.SAVE_UPDATE,CascadeType.MERGE})
93
	@NotNull
94
	private Set<DescriptionBase> descriptions = new HashSet<>();
95

    
96
    @XmlElementWrapper(name = "SubtreeTaxonFilter")
97
    @XmlElement(name = "Subtree")
98
    @XmlIDREF
99
    @XmlSchemaType(name = "IDREF")
100
    @ManyToMany(fetch = FetchType.LAZY)
101
    @Cascade({CascadeType.SAVE_UPDATE,CascadeType.MERGE})
102
    @NotNull
103
    //a positive filter that defines that all taxa in the subtree belong to
104
    //the dataset. If the filter is NOT set, taxa need to be explicitly defined
105
    //via the descriptions set. If the filter is set all taxa not having
106
    //a description in descriptions yet are considered to have an empty description
107
    //TODO what, if a taxon is removed from the subtree but a description exists in
108
    //descriptions
109
    private Set<TaxonNode> taxonSubtreeFilter = new HashSet<>();
110

    
111
    @XmlElementWrapper(name = "GeoFilter")
112
    @XmlElement(name = "FilteredArea")
113
    @XmlIDREF
114
    @XmlSchemaType(name = "IDREF")
115
    @ManyToMany(fetch = FetchType.LAZY)
116
    @Cascade({CascadeType.SAVE_UPDATE,CascadeType.MERGE})
117
    @JoinTable(name="DescriptiveDataSet_NamedArea")
118
    @NotNull
119
    private Set<NamedArea> geoFilter = new HashSet<>();
120

    
121
    @XmlElement(name = "minRank")
122
    @XmlIDREF
123
    @XmlSchemaType(name = "IDREF")
124
    @ManyToOne(fetch = FetchType.LAZY)
125
    private Rank minRank;
126

    
127
    @XmlElement(name = "maxRank")
128
    @XmlIDREF
129
    @XmlSchemaType(name = "IDREF")
130
    @ManyToOne(fetch = FetchType.LAZY)
131
    private Rank maxRank;
132

    
133
// ******************* FACTORY *********************************************/
134

    
135
	public static DescriptiveDataSet NewInstance(){
136
        return new DescriptiveDataSet();
137
    }
138

    
139

    
140
// *******************CONSTRUCTOR **********************************/
141
	/**
142
	 * Class constructor: creates a new empty working set instance.
143
	 */
144
	protected DescriptiveDataSet() {
145
		super();
146
		this.cacheStrategy = new DescriptiveDataSetDefaultCacheStrategy();
147
	}
148

    
149
// ******************** GETTER / SETTER ************************/
150

    
151

    
152
	public Set<TaxonNode> getTaxonSubtreeFilter() {
153
        return taxonSubtreeFilter;
154
    }
155

    
156
    public void setTaxonSubtreeFilter(Set<TaxonNode> taxonSubtreeFilter) {
157
        this.taxonSubtreeFilter = taxonSubtreeFilter;
158
    }
159

    
160
    public void  addTaxonSubtree(TaxonNode subtree) {
161
        this.taxonSubtreeFilter.add(subtree);
162
    }
163

    
164
    public void  removeTaxonSubtree(TaxonNode subtree) {
165
        this.taxonSubtreeFilter.remove(subtree);
166
    }
167

    
168
    //geo filter
169
    public Set<NamedArea> getGeoFilter() {
170
        return geoFilter;
171
    }
172
    public void setGeoFilter(Set<NamedArea> geoFilter) {
173
        this.geoFilter = geoFilter;
174
    }
175
    public void addGeoFilterArea(NamedArea area){
176
        this.geoFilter.add(area);
177
    }
178
    public boolean removeGeoFilterArea(NamedArea area) {
179
        return this.geoFilter.remove(area);
180
    }
181

    
182
    //min rank
183
    public Rank getMinRank() {
184
        return minRank;
185
    }
186
    public void setMinRank(Rank minRank) {
187
        this.minRank = minRank;
188
    }
189

    
190
    //max rank
191
    public Rank getMaxRank() {
192
        return maxRank;
193
    }
194
    public void setMaxRank(Rank maxRank) {
195
        this.maxRank = maxRank;
196
    }
197

    
198
    //representations
199
	public Set<Representation> getRepresentations() {
200
		return this.representations;
201
	}
202
	public void addRepresentation(Representation representation) {
203
		this.representations.add(representation);
204
	}
205
	public void removeRepresentation(Representation representation) {
206
		this.representations.remove(representation);
207
	}
208

    
209
	public Representation getRepresentation(Language lang) {
210
		for (Representation repr : representations){
211
			Language reprLanguage = repr.getLanguage();
212
			if (reprLanguage != null && reprLanguage.equals(lang)){
213
				return repr;
214
			}
215
		}
216
		return null;
217
	}
218

    
219
	/**
220
	 * @see #getPreferredRepresentation(Language)
221
	 * @param language
222
	 * @return
223
	 */
224
	public Representation getPreferredRepresentation(Language language) {
225
		if (representations.size() == 0){
226
		    return null;
227
		}
228
	    Representation repr = getRepresentation(language);
229
		if(repr == null){
230
			repr = getRepresentation(Language.DEFAULT());
231
		}
232
		if(repr == null){
233
			repr = getRepresentations().iterator().next();
234
		}
235
		return repr;
236
	}
237

    
238
	/**
239
	 * Returns the Representation in the preferred language. Preferred languages
240
	 * are specified by the parameter languages, which receives a list of
241
	 * Language instances in the order of preference. If no representation in
242
	 * any preferred languages is found the method falls back to return the
243
	 * Representation in Language.DEFAULT() and if necessary further falls back
244
	 * to return the first element found if any.
245
	 *
246
	 * TODO think about this fall-back strategy &
247
	 * see also {@link TextData#getPreferredLanguageString(List)}
248
	 *
249
	 * @param languages
250
	 * @return
251
	 */
252
	public Representation getPreferredRepresentation(List<Language> languages) {
253
		Representation repr = null;
254
		if(languages != null){
255
			for(Language language : languages) {
256
				repr = getRepresentation(language);
257
				if(repr != null){
258
					return repr;
259
				}
260
			}
261
		}
262
		if(repr == null){
263
			repr = getRepresentation(Language.DEFAULT());
264
		}
265
		if(repr == null){
266
			Iterator<Representation> it = getRepresentations().iterator();
267
			if(it.hasNext()){
268
				repr = getRepresentations().iterator().next();
269
			}
270
		}
271
		return repr;
272
	}
273

    
274
	@Transient
275
	public String getLabel() {
276
		if(getLabel(Language.DEFAULT())!=null){
277
			Representation repr = getRepresentation(Language.DEFAULT());
278
			return (repr == null)? null :repr.getLabel();
279
		}else{
280
			for (Representation r : representations){
281
				return r.getLabel();
282
			}
283
		}
284
		return super.getUuid().toString();
285
	}
286

    
287
	public String getLabel(Language lang) {
288
		Representation repr = this.getRepresentation(lang);
289
		return (repr == null) ? null : repr.getLabel();
290
	}
291

    
292
	public void setLabel(String label){
293
		Language lang = Language.DEFAULT();
294
		setLabel(label, lang);
295
	}
296

    
297
	public void setLabel(String label, Language language){
298
		if (language != null){
299
			Representation repr = getRepresentation(language);
300
			if (repr != null){
301
				repr.setLabel(label);
302
			}else{
303
				repr = Representation.NewInstance(null, label, null, language);
304
			}
305
			this.addRepresentation(repr);
306
		}
307
	}
308

    
309
	public FeatureTree<Character> getDescriptiveSystem() {
310
		return descriptiveSystem;
311
	}
312
	public void setDescriptiveSystem(FeatureTree<Character> descriptiveSystem) {
313
		this.descriptiveSystem = descriptiveSystem;
314
	}
315

    
316
	/**
317
	 * Returns the {@link DescriptionBase descriptions} of
318
	 * <i>this</i> working set.
319
	 *
320
	 * @see    #addDescription(DescriptionBase)
321
	 * @see    #removeDescription(DescriptionBase)
322
	 */
323
	public Set<DescriptionBase> getDescriptions() {
324
		return descriptions;
325
	}
326

    
327
	/**
328
	 * Adds an existing {@link DescriptionBase description} to the set of
329
	 * {@link #getDescriptions() descriptions} of <i>this</i>
330
	 * working set.
331
	 *
332
	 * @param description	the description to be added to <i>this</i> working set
333
	 * @see    	   			#getDescriptions()
334
	 * @see    	   			DescriptiveDataSet#addDescription(DescriptionBase)
335
	 */
336
	public boolean addDescription(DescriptionBase description) {
337
		boolean result = this.descriptions.add(description);
338
		if (! description.getDescriptiveDataSets().contains(this)){
339
			description.addDescriptiveDataSet(this);
340
		}
341
		return result;
342
	}
343

    
344
	/**
345
	 * Removes one element from the set of {@link #getDescriptions() descriptions} involved
346
	 * in <i>this</i> working set.<BR>
347
	 *
348
	 * @param  description	the description which should be removed
349
	 * @see     		 	#getDescriptions()
350
	 * @see     		  	#addDescription(DescriptionBase)
351
	 * @see     		  	DescriptiveDataSet#removeDescription(DescriptionBase)
352
	 */
353
	public boolean removeDescription(DescriptionBase description) {
354
		boolean result = this.descriptions.remove(description);
355
		if (description.getDescriptiveDataSets().contains(this)){
356
			description.removeDescriptiveDataSet(this);
357
		}
358
		return result;
359
	}
360

    
361
	//*********************** CLONE ********************************************************/
362

    
363
	/**
364
	 * Clones <i>this</i> DescriptiveDataSet. This is a shortcut that enables to create
365
	 * a new instance that differs only slightly from <i>this</i> DescriptiveDataSet by
366
	 * modifying only some of the attributes.
367
	 * The descriptions and the descriptive system are the same, the representations
368
	 * are cloned.
369
	 *
370
	 * @see eu.etaxonomy.cdm.model.common.AnnotatableEntity#clone()
371
	 * @see java.lang.Object#clone()
372
	 */
373
	@Override
374
	public Object clone() {
375
		DescriptiveDataSet result;
376
		try {
377
			result = (DescriptiveDataSet)super.clone();
378

    
379
			//descriptions
380
			result.descriptions = new HashSet<>();
381
			for (DescriptionBase<?> desc: this.descriptions){
382
				result.addDescription(desc);
383
			}
384

    
385
			//representations
386
			result.representations = new HashSet<>();
387
			for (Representation rep : this.representations){
388
				result.addRepresentation((Representation)rep.clone());
389
			}
390

    
391
			//subtree filter
392
            result.taxonSubtreeFilter = new HashSet<>();
393
            for (TaxonNode subtree : this.taxonSubtreeFilter){
394
                result.addTaxonSubtree(subtree);
395
            }
396

    
397
            //geo filter
398
            result.geoFilter = new HashSet<>();
399
            for (NamedArea area : this.geoFilter){
400
                result.addGeoFilterArea(area);
401
            }
402

    
403
			return result;
404
		}catch (CloneNotSupportedException e) {
405
			logger.warn("Object does not implement cloneable");
406
			e.printStackTrace();
407
			return null;
408
		}
409
	}
410

    
411
}
(7-7/37)