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.
10 package eu
.etaxonomy
.cdm
.model
.term
;
14 import java
.util
.HashSet
;
15 import java
.util
.Iterator
;
16 import java
.util
.List
;
18 import java
.util
.SortedSet
;
19 import java
.util
.TreeSet
;
20 import java
.util
.UUID
;
22 import javax
.persistence
.Entity
;
23 import javax
.persistence
.FetchType
;
24 import javax
.persistence
.Inheritance
;
25 import javax
.persistence
.InheritanceType
;
26 import javax
.persistence
.OneToMany
;
27 import javax
.persistence
.Transient
;
28 import javax
.xml
.bind
.annotation
.XmlAccessType
;
29 import javax
.xml
.bind
.annotation
.XmlAccessorType
;
30 import javax
.xml
.bind
.annotation
.XmlElement
;
31 import javax
.xml
.bind
.annotation
.XmlElementWrapper
;
32 import javax
.xml
.bind
.annotation
.XmlIDREF
;
33 import javax
.xml
.bind
.annotation
.XmlRootElement
;
34 import javax
.xml
.bind
.annotation
.XmlSchemaType
;
35 import javax
.xml
.bind
.annotation
.XmlType
;
37 import org
.apache
.log4j
.Logger
;
38 import org
.hibernate
.annotations
.Cascade
;
39 import org
.hibernate
.annotations
.CascadeType
;
40 import org
.hibernate
.annotations
.Type
;
41 import org
.hibernate
.envers
.Audited
;
42 import org
.hibernate
.search
.annotations
.Analyze
;
43 import org
.hibernate
.search
.annotations
.Field
;
44 import org
.hibernate
.search
.annotations
.IndexedEmbedded
;
46 import eu
.etaxonomy
.cdm
.common
.CdmUtils
;
47 import eu
.etaxonomy
.cdm
.model
.common
.Language
;
51 * A single enumeration must only contain DefinedTerm instances of one kind
52 * (this means a subclass of DefinedTerm).
54 * @since 08-Nov-2007 13:06:23
56 @XmlAccessorType(XmlAccessType
.FIELD
)
57 @XmlType(name
= "TermVocabulary", propOrder
= {
61 @XmlRootElement(name
= "TermVocabulary")
63 //@Indexed disabled to reduce clutter in indexes, since this type is not used by any search
64 //@Indexed(index = "eu.etaxonomy.cdm.model.common.TermVocabulary")
66 @Inheritance(strategy
=InheritanceType
.SINGLE_TABLE
)
67 public class TermVocabulary
<T
extends DefinedTermBase
> extends TermBase
implements Iterable
<T
> {
68 private static final long serialVersionUID
= 1925052321596648672L;
69 private static final Logger logger
= Logger
.getLogger(TermVocabulary
.class);
71 //The vocabulary source (e.g. ontology) defining the terms to be loaded when a database is created for the first time.
72 // Software can go and grap these terms incl labels and description.
73 // UUID needed? Further vocs can be setup through our own ontology.
74 @XmlElement(name
= "TermSourceURI")
75 @Type(type
="uriUserType")
76 @Field(analyze
= Analyze
.NO
)
77 private URI termSourceUri
;
81 @XmlElementWrapper(name
= "Terms")
82 @XmlElement(name
= "Term")
84 @XmlSchemaType(name
= "IDREF")
85 @OneToMany(mappedBy
="vocabulary", fetch
=FetchType
.LAZY
, targetEntity
= DefinedTermBase
.class)
86 @Type(type
="DefinedTermBase")
87 @Cascade({CascadeType
.SAVE_UPDATE
, CascadeType
.MERGE
})
88 @IndexedEmbedded(depth
= 2)
89 protected Set
<T
> terms
= getNewTermSet();
91 // ********************************* FACTORY METHODS *****************************************/
94 public static TermVocabulary
NewInstance(TermType type
){
95 return new TermVocabulary(type
);
98 public static <T
extends DefinedTermBase
<T
>> TermVocabulary
<T
> NewInstance(TermType type
, Class
<T
> clazz
){
99 return new TermVocabulary
<T
>(type
);
102 public static TermVocabulary
NewInstance(TermType type
, String description
, String label
, String abbrev
, URI termSourceUri
){
103 return new TermVocabulary(type
, description
, label
, abbrev
, termSourceUri
);
106 // ************************* CONSTRUCTOR *************************************************
108 //for hibernate use only
110 protected TermVocabulary() {
111 super(TermType
.Unknown
);
114 protected TermVocabulary(TermType type
) {
118 protected TermVocabulary(TermType type
, String term
, String label
, String labelAbbrev
, URI termSourceUri
) {
119 super(type
, term
, label
, labelAbbrev
);
120 setTermSourceUri(termSourceUri
);
124 // ******************* METHODS *************************************************/
126 public T
findTermByUuid(UUID uuid
){
128 if(t
.getUuid().equals(uuid
)) {
136 Set
<T
> getNewTermSet() {
137 return new HashSet
<T
>();
140 public Set
<T
> getTerms() {
144 public void addTerm(T term
) {
146 term
.setVocabulary(this);
147 this.terms
.add(term
);
149 public void removeTerm(T term
) {
150 this.terms
.remove(term
);
151 term
.setVocabulary(null);
154 public URI
getTermSourceUri() {
155 return termSourceUri
;
157 public void setTermSourceUri(URI vocabularyUri
) {
158 this.termSourceUri
= vocabularyUri
;
162 * Returns the first term found having the defined idInVocabulary.
163 * If number of terms with given idInVoc > 1 the result is not deterministic.
165 * @return the term with the given idInVoc
167 public T
getTermByIdInvocabulary(String idInVoc
) {
168 for (T term
: getTerms() ){
169 if (CdmUtils
.nullSafeEqual(idInVoc
, term
.getIdInVocabulary())){
177 public Iterator
<T
> iterator() {
178 return terms
.iterator(); // OLD: new TermIterator<T>(this.terms);
187 * Returns all terms of this vocabulary sorted by their representation defined by the given language.
188 * If such an representation does not exist, the representation of the default language is testing instead for ordering.
192 public SortedSet
<T
> getTermsOrderedByLabels(Language language
){
193 TermLanguageComparator
<T
> comp
= new TermLanguageComparator
<T
>();
194 comp
.setCompareLanguage(language
);
196 SortedSet
<T
> result
= new TreeSet
<T
>(comp
);
197 result
.addAll(getTerms());
202 public TermVocabulary
<T
> readCsvLine(List
<String
> csvLine
) {
203 return readCsvLine(csvLine
, Language
.CSV_LANGUAGE());
206 public TermVocabulary
<T
> readCsvLine(List
<String
> csvLine
, Language lang
) {
207 this.setUuid(UUID
.fromString(csvLine
.get(0)));
208 String uriStr
= CdmUtils
.Ne(csvLine
.get(1));
209 this.setUri(uriStr
== null?
null: URI
.create(uriStr
));
210 String label
= csvLine
.get(2).trim();
211 String description
= csvLine
.get(3);
213 //see http://dev.e-taxonomy.eu/trac/ticket/3550
214 this.addRepresentation(Representation
.NewInstance(description
, label
, null, lang
) );
216 TermType termType
= TermType
.getByKey(csvLine
.get(4));
217 if (termType
== null){
218 throw new IllegalArgumentException("TermType can not be mapped: " + csvLine
.get(4));
220 this.setTermType(termType
);
226 * Throws {@link IllegalArgumentException} if the given
227 * term has not the same term type as this term or if term type is null.
230 private void checkTermType(IHasTermType term
) {
231 IHasTermType
.checkTermTypes(term
, this);
234 //*********************** CLONE ********************************************************/
237 * Clones <i>this</i> TermVocabulary. This is a shortcut that enables to create
238 * a new instance that differs only slightly from <i>this</i> TermVocabulary.
239 * The terms of the original vocabulary are cloned
241 * @see eu.etaxonomy.cdm.model.term.TermBase#clone()
242 * @see java.lang.Object#clone()
245 public Object
clone() {
246 TermVocabulary
<T
> result
;
248 result
= (TermVocabulary
<T
>) super.clone();
250 }catch (CloneNotSupportedException e
) {
251 logger
.warn("Object does not implement cloneable");
255 result
.terms
= new HashSet
<T
>();
256 for (T term
: this.terms
){
257 result
.addTerm((T
)term
.clone());