hide term vocabulary constructors and create factory methods instead
[cdmlib.git] / cdmlib-model / src / main / java / eu / etaxonomy / cdm / model / common / TermVocabulary.java
index 6372868db112bdc610460a5d677a0bc772b9df48..de46f8749b5b8b6102fcdc8e1687f82e0cee707c 100644 (file)
 package eu.etaxonomy.cdm.model.common;
 
 
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.TreeSet;
+import java.util.UUID;
+
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.Inheritance;
+import javax.persistence.InheritanceType;
+import javax.persistence.OneToMany;
+import javax.persistence.Transient;
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlElementWrapper;
+import javax.xml.bind.annotation.XmlIDREF;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlSchemaType;
+import javax.xml.bind.annotation.XmlType;
+
 import org.apache.log4j.Logger;
 import org.hibernate.annotations.Cascade;
 import org.hibernate.annotations.CascadeType;
 import org.hibernate.annotations.Type;
-import java.util.*;
-
-import javax.persistence.*;
+import org.hibernate.envers.Audited;
+import org.hibernate.search.annotations.Field;
+import org.hibernate.search.annotations.Indexed;
+import org.hibernate.search.annotations.IndexedEmbedded;
 
 
 /**
  * A single enumeration must only contain DefinedTerm instances of one kind
- * (=class)
+ * (this means a subclass of DefinedTerm).
  * @author m.doering
  * @version 1.0
  * @created 08-Nov-2007 13:06:23
  */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "TermVocabulary", propOrder = {
+    "termSourceUri",
+    "terms"
+})
+@XmlRootElement(name = "TermVocabulary")
 @Entity
+@Indexed(index = "eu.etaxonomy.cdm.model.common.TermVocabulary")
+@Audited
 @Inheritance(strategy=InheritanceType.SINGLE_TABLE)
 public class TermVocabulary<T extends DefinedTermBase> extends TermBase implements Iterable<T> {
-       static Logger logger = Logger.getLogger(TermVocabulary.class);
-       
-       private static final UUID uuidLanguage = UUID.fromString("17ba1c02-256d-47cf-bed0-2964ec1108ba");
-       private static final UUID uuidRank = UUID.fromString("b17451eb-4278-4179-af68-44f27aa3d151");
-       private static final UUID uuidContinent = UUID.fromString("ed4e5948-172a-424c-83d6-6fc7c7da70ed");
-       
-       
-       public static TermVocabulary findByUuid(UUID uuid){
-               //in tests tems may no be initialised by database access
-//             if (!isInitialized()){
-//                     initTermList(null);
-//             }
-//             return termVocabularyMap.get(uuid);
-               //TODO
-               logger.error("Not yet implemented");
-               return null;
-       }
-       public static final TermVocabulary getUUID(UUID uuid){
-               return (TermVocabulary)findByUuid(uuid);
-       }
-       public static final TermVocabulary LANGUAGE(){
-               return getUUID(uuidLanguage);
-       }
+       private static final long serialVersionUID = 1925052321596648672L;
+       @SuppressWarnings("unused")
+       private static final Logger logger = Logger.getLogger(TermVocabulary.class);
 
        //The vocabulary source (e.g. ontology) defining the terms to be loaded when a database is created for the first time.  
        // Software can go and grap these terms incl labels and description. 
        // UUID needed? Further vocs can be setup through our own ontology.
+       @XmlElement(name = "TermSourceURI")
+       @Field(index=org.hibernate.search.annotations.Index.UN_TOKENIZED)
        private String termSourceUri;
-       protected Class termClass;
+       
 
+       //TODO Changed
+       @XmlElementWrapper(name = "Terms")
+       @XmlElement(name = "Term")
+    @XmlIDREF
+    @XmlSchemaType(name = "IDREF")
+    @OneToMany(mappedBy="vocabulary", fetch=FetchType.LAZY, targetEntity = DefinedTermBase.class)
+       @Type(type="DefinedTermBase")
+       @Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE})
+       @IndexedEmbedded(depth = 2)
        protected Set<T> terms = getNewTermSet();
        
-       //to be overriden by subclasses, e.g. OrderedTermVocabulary
-       @Transient
-       protected Set<T> getNewTermSet(){
-               return new HashSet<T>();
+// ********************************* FACTORY METHODS *****************************************/
+
+       public static TermVocabulary NewInstance(String description, String label, String abbrev, String termSourceUri){
+               return new TermVocabulary(description, label, abbrev, termSourceUri);
        }
        
-       public TermVocabulary() {
-               super();
+// ************************* CONSTRUCTOR *************************************************     
+
+       protected TermVocabulary() {
        }
-       public TermVocabulary(String term, String label, String termSourceUri) {
-               super(term, label);
+       
+       protected TermVocabulary(String term, String label, String labelAbbrev, String termSourceUri) {
+               super(term, label, labelAbbrev);
                setTermSourceUri(termSourceUri);
        }
        
-       @OneToMany(mappedBy="vocabulary")
-       @Type(type="DefinedTermBase")
-       @Cascade({CascadeType.SAVE_UPDATE})
-       public Set<T> getTerms() {
-               Set<T> result = getNewTermSet();
-               result.addAll(terms);
-               return result;
+
+// ******************* METHODS *************************************************/      
+       
+       public T findTermByUuid(UUID uuid){
+               for(T t : terms) {
+                       if(t.getUuid().equals(uuid)) {
+                               return t;
+                       }
+               }
+               return null;
        }
-       protected void setTerms(Set<T> terms) {
-               this.terms = terms;
+
+       @Transient
+       Set<T> getNewTermSet() {
+               return new HashSet<T>();
        }
-       public void addTerm(T term) throws WrongTermTypeException {
-               if (terms.size()<1){
-                       // no term yet in the list. First term defines the vocabulary kind
-                       termClass=term.getClass();
-               }else if (term.getClass()!=termClass){
-                               // check if new term in this vocabulary matches the previous ones
-                               throw new WrongTermTypeException(term.getClass().getCanonicalName());
-               }
+
+       public Set<T> getTerms() {
+               return terms;
+       }
+       
+       public void addTerm(T term) {
                term.setVocabulary(this);
+               this.terms.add(term);
        }
        public void removeTerm(T term) {
+               this.terms.remove(term);
                term.setVocabulary(null);
        }
 
@@ -108,32 +138,6 @@ public class TermVocabulary<T extends DefinedTermBase> extends TermBase implemen
        }
        
        
-       public Class getTermClass() {
-               return termClass;
-       }
-       private void setTermClass(Class termClass) {
-               this.termClass = termClass;
-       } 
-       
-       
-//     // inner iterator class for the iterable interface
-//     private class TermIterator<T> implements Iterator<T> {
-//                // FIXME: using a list here is probably not safe. Sth passed by value, an array, would be better
-//                // but arrays cause generics problems: http://forum.java.sun.com/thread.jspa?threadID=651276&messageID=3832182
-//                // hack for now ;(
-//                private Set<T> array;
-//                private int i= 0;
-//                // ctor
-//                public TermIterator(Set<T> array) {
-//                   // check for null being passed in etc.
-//                   this.array= array;
-//                }
-//                // interface implementation
-//                public boolean hasNext() { return i < array.size(); }
-//                public T next() { return array.get(i++); }
-//                public void remove() { throw new UnsupportedOperationException(); }
-//     }
-
        public Iterator<T> iterator() {
                return terms.iterator();  // OLD: new TermIterator<T>(this.terms);
        }
@@ -141,5 +145,36 @@ public class TermVocabulary<T extends DefinedTermBase> extends TermBase implemen
        public int size(){
                return terms.size();
        }
+       
+       
+       /**
+        * Returns all terms of this vocabulary sorted by their representation defined by the given language.
+        * If such an representation does not exist, the representation of the default language is testing instead for ordering.
+        * @param language
+        * @return
+        */
+       public SortedSet<T> getTermsOrderedByLabels(Language language){
+               TermLanguageComparator<T> comp = new TermLanguageComparator<T>();
+               comp.setCompareLanguage(language);
+               
+               SortedSet<T> result = new TreeSet<T>(comp);
+               result.addAll(getTerms());
+               return result;
+       }
+       
+       
+       /* (non-Javadoc)
+        * @see eu.etaxonomy.cdm.model.common.ILoadableTerm#readCsvLine(java.util.List)
+        */
+       public TermVocabulary<T> readCsvLine(List<String> csvLine) {
+               return readCsvLine(csvLine, Language.CSV_LANGUAGE());
+       }
+       
+       public TermVocabulary<T> readCsvLine(List<String> csvLine, Language lang) {
+               this.setUuid(UUID.fromString(csvLine.get(0)));
+               this.setUri(csvLine.get(1));
+               //this.addRepresentation(Representation.NewInstance(csvLine.get(3), csvLine.get(2).trim(), lang) );
+               return this;
+       }
     
 }
\ No newline at end of file