LazyInitError in Representation.getLanguage and minor changes
[cdmlib.git] / cdmlib-model / src / main / java / eu / etaxonomy / cdm / model / common / DefinedTermBase.java
index 7bbc805184ca125b8ae06ed0813cbd584a33d61a..88aefc78b0ad13766067265b8505601ca81edba0 100644 (file)
@@ -12,211 +12,301 @@ package eu.etaxonomy.cdm.model.common;
 import org.apache.log4j.Logger;
 import org.hibernate.annotations.Cascade;
 import org.hibernate.annotations.CascadeType;
-import org.springframework.beans.factory.annotation.Autowired;
+import org.hibernate.collection.AbstractPersistentCollection;
+import org.hibernate.search.annotations.Indexed;
 
 import au.com.bytecode.opencsv.CSVWriter;
-import eu.etaxonomy.cdm.model.common.init.TermLoader;
+import eu.etaxonomy.cdm.model.common.init.ITermInitializer;
+import eu.etaxonomy.cdm.model.media.Media;
+import eu.etaxonomy.cdm.model.name.NomenclaturalCode;
 
+import java.lang.reflect.Field;
 import java.util.*;
 
 import javax.persistence.*;
+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.XmlTransient;
+import javax.xml.bind.annotation.XmlType;
+
 
 /**
- * workaround for enumerations, base type according to TDWG.  For linear ordering
+ * walkaround for enumerations, base type according to TDWG.  For linear ordering
  * use partOf relation and BreadthFirst. Default iterator order should therefore
  * be BreadthFirst (not DepthFirst)
  * @author m.doering
  * @version 1.0
  * @created 08-Nov-2007 13:06:19
  */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "DefinedTermBase", propOrder = {
+    "kindOf",
+    "generalizationOf",
+    "partOf",
+    "includes",
+    "media",
+    "vocabulary"
+})
+@XmlRootElement(name = "DefinedTermBase")
 @Entity
+//@Audited
 @Inheritance(strategy=InheritanceType.SINGLE_TABLE)
-public abstract class DefinedTermBase extends TermBase implements IDefTerm{
-       static Logger logger = Logger.getLogger(DefinedTermBase.class);
-       //public static IDefinedTermDao dao;
-       //public static ITermService termService;
-       //Map for preloading all DefinedTerms
-       static protected Map<UUID, DefinedTermBase> definedTermsMap = null;
-
-       private DefinedTermBase kindOf;
-       private Set<DefinedTermBase> generalizationOf = new HashSet<DefinedTermBase>();
-       private DefinedTermBase partOf;
-       private Set<DefinedTermBase> includes = new HashSet<DefinedTermBase>();
-       private Set<Media> media = new HashSet<Media>();
-       private TermVocabulary vocabulary;
-       
-       public static void initTermList(ITermLister termLister){
-               logger.debug("initTermList");
-               if (definedTermsMap == null){
-                       if (termLister == null){   //e.g. when used in tests with no database connection
-                               definedTermsMap = new HashMap<UUID, DefinedTermBase>();
-                               try {
-                                       String strUuidEnglish = "e9f8cdb7-6819-44e8-95d3-e2d0690c3523";
-                                       UUID uuidEnglish = UUID.fromString(strUuidEnglish);
-                                       Language english = new Language(uuidEnglish);
-                                       definedTermsMap.put(english.getUuid(), english);
-                                       TermLoader.setDefinedTermsMap(definedTermsMap);
-                                       new TermLoader().loadAllDefaultTerms();
-                               } catch (Exception e) {
-                                       logger.error("Error ocurred when loading terms");
-                               }                               
-                               
-                       }else{
-                               List<DefinedTermBase> list = termLister.listTerms();
-                               definedTermsMap = new HashMap<UUID, DefinedTermBase>();
-                               for (DefinedTermBase dtb: list){
-                                       definedTermsMap.put(dtb.getUuid(), dtb);
-                               }
-                       }
-               }
-               logger.debug("initTermList - end");
-       }
+@Indexed
+public abstract class DefinedTermBase<T extends DefinedTermBase> extends TermBase implements ILoadableTerm<T>, IDefinedTerm<T> {
+       private static final long serialVersionUID = 2931811562248571531L;
+       private static final Logger logger = Logger.getLogger(DefinedTermBase.class);
+               
+       @XmlElement(name = "KindOf")
+    @XmlIDREF
+    @XmlSchemaType(name = "IDREF")
+       private T kindOf;
+       /**
+        * FIXME - Hibernate retuns this as a collection of CGLibProxy$$DefinedTermBase objects 
+        * which can't be cast to instances of T - can we explicitly initialize these terms using 
+        * Hibernate.initialize(), does this imply a distinct load, and find methods in the dao?
+        */
+       @XmlElement(name = "GeneralizationOf")
+    @XmlIDREF
+    @XmlSchemaType(name = "IDREF")
+       private Set<T> generalizationOf = new HashSet<T>();
        
-       public static DefinedTermBase findByUuid(UUID uuid){
-               //in tests tems may no be initialised by database access
-               if (!isInitialized()){
-                       initTermList(null);
-               }
-               return definedTermsMap.get(uuid);
-       }
+       @XmlElement(name = "PartOf")
+    @XmlIDREF
+    @XmlSchemaType(name = "IDREF")
+       private T partOf;
        
-       public static boolean isInitialized(){
-               return (definedTermsMap != null);
-       }
+       /**
+        * FIXME - Hibernate retuns this as a collection of CGLibProxy$$DefinedTermBase objects 
+        * which can't be cast to instances of T - can we explicitly initialize these terms using 
+        * Hibernate.initialize(), does this imply a distinct load, and find methods in the dao?
+        */
+       @XmlElementWrapper(name = "Includes")
+       @XmlElement(name = "Include")
+    private Set<T> includes = new HashSet<T>();
        
-       public static Map<UUID, DefinedTermBase> getDefinedTerms(){
-               return definedTermsMap;
-       }
+       @XmlElementWrapper(name = "Media")
+       @XmlElement(name = "Medium")
+    @XmlIDREF
+    @XmlSchemaType(name = "IDREF")
+       private Set<Media> media = new HashSet<Media>();
        
+       @XmlElement(name = "TermVocabulary")
+       @XmlIDREF
+       @XmlSchemaType(name = "IDREF")
+       protected TermVocabulary<T> vocabulary; 
        
-//     public static void setDao(IDefinedTermDao dao) {
-//             logger.warn("Setting DefinedTerm static dao");
-//             DefinedTermBase.dao = dao;
-//     }
-//     
-//     public static void setService(ITermService service) {
-//             logger.warn("Setting DefinedTerm static service");
-//             DefinedTermBase.termService = service;
-//     }
+// ************** Constructor ******************************************/
        
        public DefinedTermBase() {
                super();
        }
-       public DefinedTermBase(String term, String label) {
-               super(term, label);
+       public DefinedTermBase(String term, String label, String labelAbbrev) {
+               super(term, label, labelAbbrev);
        }
 
+       protected abstract void setDefaultTerms(TermVocabulary<T> termVocabulary);
 
        /* (non-Javadoc)
-        * @see eu.etaxonomy.cdm.model.common.IDefTerm#readCsvLine(java.util.List)
+        * @see eu.etaxonomy.cdm.model.common.ILoadableTerm#readCsvLine(java.util.List)
+        */
+       /* (non-Javadoc)
+        * @see eu.etaxonomy.cdm.model.common.IDefinedTerm#readCsvLine(java.lang.Class, java.util.List, java.util.Map)
         */
-       public void readCsvLine(List<String> csvLine) {
-               readCsvLine(csvLine, Language.ENGLISH());
+       public T readCsvLine(Class<T> termClass, List<String> csvLine, Map<UUID,DefinedTermBase> terms) {
+               try {
+                       T newInstance = termClass.newInstance();
+                   return readCsvLine(newInstance, csvLine, Language.ENGLISH());
+               } catch (Exception e) {
+                       logger.error(e);
+                       for(StackTraceElement ste : e.getStackTrace()) {
+                               logger.error(ste);
+                       }
+               }
+               
+           return null;
        }
-       public void readCsvLine(List<String> csvLine, Language lang) {
-               this.setUuid(UUID.fromString(csvLine.get(0)));
-               this.setUri(csvLine.get(1));
-               this.addRepresentation(new Representation(csvLine.get(3), csvLine.get(2).trim(), lang) );
+
+       protected static <TERM extends DefinedTermBase> TERM readCsvLine(TERM newInstance, List<String> csvLine, Language lang) {
+                       newInstance.setUuid(UUID.fromString(csvLine.get(0)));
+                       newInstance.setUri(csvLine.get(1));
+                       String label = csvLine.get(2).trim();
+                       String text = csvLine.get(3);
+                       String abbreviatedLabel = csvLine.get(4);
+                       newInstance.addRepresentation(Representation.NewInstance(text, label, abbreviatedLabel, lang) );
+                       return newInstance;
        }
 
        /* (non-Javadoc)
-        * @see eu.etaxonomy.cdm.model.common.IDefTerm#writeCsvLine(au.com.bytecode.opencsv.CSVWriter)
+        * @see eu.etaxonomy.cdm.model.common.ILoadableTerm#writeCsvLine(au.com.bytecode.opencsv.CSVWriter)
         */
-       public void writeCsvLine(CSVWriter writer) {
+       public void writeCsvLine(CSVWriter writer, T term) {
                String [] line = new String[4];
-               line[0] = getUuid().toString();
-               line[1] = getUri();
-               line[2] = getLabel();
-               line[3] = getDescription();
+               line[0] = term.getUuid().toString();
+               line[1] = term.getUri();
+               line[2] = term.getLabel();
+               line[3] = term.getDescription();
                writer.writeNext(line);
        }
        
+       /* (non-Javadoc)
+        * @see eu.etaxonomy.cdm.model.common.IDefinedTerm#getByUuid(java.util.UUID)
+        */
        @Transient
-       //@ManyToOne
-       //@Cascade({CascadeType.SAVE_UPDATE})
-       public DefinedTermBase getKindOf(){
+       public T getByUuid(UUID uuid){
+               return this.vocabulary.findTermByUuid(uuid);
+       }
+       
+       
+       /* (non-Javadoc)
+        * @see eu.etaxonomy.cdm.model.common.IDefinedTerm#getKindOf()
+        */
+       @ManyToOne(fetch = FetchType.LAZY, targetEntity = DefinedTermBase.class)
+       @Cascade({CascadeType.SAVE_UPDATE})
+       public T getKindOf(){
                return this.kindOf;
        }
-       public void setKindOf(DefinedTermBase kindOf){
+       
+       /* (non-Javadoc)
+        * @see eu.etaxonomy.cdm.model.common.IDefinedTerm#setKindOf(T)
+        */
+       public void setKindOf(T kindOf){
                this.kindOf = kindOf;
        }
 
-       @Transient
-       //@OneToMany(fetch=FetchType.LAZY)
-       //@Cascade({CascadeType.SAVE_UPDATE})
-       public Set<DefinedTermBase> getGeneralizationOf(){
+       /* (non-Javadoc)
+        * @see eu.etaxonomy.cdm.model.common.IDefinedTerm#getGeneralizationOf()
+        */
+       @OneToMany(fetch=FetchType.LAZY, mappedBy = "kindOf", targetEntity = DefinedTermBase.class)
+       @Cascade({CascadeType.SAVE_UPDATE})
+       public Set<T> getGeneralizationOf(){
                return this.generalizationOf;
        }
-       public void setGeneralizationOf(Set<DefinedTermBase> generalizationOf) {
+       
+       /* (non-Javadoc)
+        * @see eu.etaxonomy.cdm.model.common.IDefinedTerm#setGeneralizationOf(java.util.Set)
+        */
+       public void setGeneralizationOf(Set<T> generalizationOf) {
                this.generalizationOf = generalizationOf;
        }
+       
+       /* (non-Javadoc)
+        * @see eu.etaxonomy.cdm.model.common.IDefinedTerm#addGeneralizationOf(T)
+        */
+       public void addGeneralizationOf(T generalization) {
+               generalization.setKindOf(this);
+               this.generalizationOf.add(generalization);
+       }
+       
+       /* (non-Javadoc)
+        * @see eu.etaxonomy.cdm.model.common.IDefinedTerm#removeGeneralization(T)
+        */
+       public void removeGeneralization(T generalization) {
+               if(generalizationOf.contains(generalization)){
+                       generalization.setKindOf(null);
+                   this.generalizationOf.remove(generalization);
+               }
+       }
 
 
-       @Transient
-       //@ManyToOne
-       //@Cascade({CascadeType.SAVE_UPDATE})
-       public DefinedTermBase getPartOf(){
+       /* (non-Javadoc)
+        * @see eu.etaxonomy.cdm.model.common.IDefinedTerm#getPartOf()
+        */
+       @ManyToOne(fetch = FetchType.LAZY, targetEntity = DefinedTermBase.class)
+       @Cascade({CascadeType.SAVE_UPDATE})
+       public T getPartOf(){
                return this.partOf;
        }
-       public void setPartOf(DefinedTermBase partOf){
+       /* (non-Javadoc)
+        * @see eu.etaxonomy.cdm.model.common.IDefinedTerm#setPartOf(T)
+        */
+       public void setPartOf(T partOf){
                this.partOf = partOf;
        }
 
-       @Transient
-       //@OneToMany(fetch=FetchType.LAZY)
-       //@Cascade({CascadeType.SAVE_UPDATE})
-       public Set<DefinedTermBase> getIncludes(){
+       
+       /* (non-Javadoc)
+        * @see eu.etaxonomy.cdm.model.common.IDefinedTerm#getIncludes()
+        */
+       @OneToMany(fetch=FetchType.LAZY, mappedBy = "partOf", targetEntity = DefinedTermBase.class)
+       @Cascade({CascadeType.SAVE_UPDATE})
+       public Set<T> getIncludes(){
                return this.includes;
        }
-       public void setIncludes(Set<DefinedTermBase> includes) {
+       /* (non-Javadoc)
+        * @see eu.etaxonomy.cdm.model.common.IDefinedTerm#setIncludes(java.util.Set)
+        */
+       public void setIncludes(Set<T> includes) {
                this.includes = includes;
        }
-       public void addIncludes(DefinedTermBase includes) {
+       /* (non-Javadoc)
+        * @see eu.etaxonomy.cdm.model.common.IDefinedTerm#addIncludes(T)
+        */
+       public void addIncludes(T includes) {
+               includes.setPartOf(this);
                this.includes.add(includes);
        }
-       public void removeIncludes(TermBase includes) {
-               this.includes.remove(includes);
+       /* (non-Javadoc)
+        * @see eu.etaxonomy.cdm.model.common.IDefinedTerm#removeIncludes(T)
+        */
+       public void removeIncludes(T includes) {
+               if(this.includes.contains(includes)) {
+                       includes.setPartOf(null);
+                   this.includes.remove(includes);
+               }
        }
 
 
-       @OneToMany
+       /* (non-Javadoc)
+        * @see eu.etaxonomy.cdm.model.common.IDefinedTerm#getMedia()
+        */
+       @ManyToMany(fetch = FetchType.LAZY)
        @Cascade({CascadeType.SAVE_UPDATE})
        public Set<Media> getMedia(){
                return this.media;
        }
+       /* (non-Javadoc)
+        * @see eu.etaxonomy.cdm.model.common.IDefinedTerm#setMedia(java.util.Set)
+        */
        public void setMedia(Set<Media> media) {
                this.media = media;
        }
+       /* (non-Javadoc)
+        * @see eu.etaxonomy.cdm.model.common.IDefinedTerm#addMedia(eu.etaxonomy.cdm.model.media.Media)
+        */
        public void addMedia(Media media) {
                this.media.add(media);
        }
+       /* (non-Javadoc)
+        * @see eu.etaxonomy.cdm.model.common.IDefinedTerm#removeMedia(eu.etaxonomy.cdm.model.media.Media)
+        */
        public void removeMedia(Media media) {
                this.media.remove(media);
        }
 
-       
        /* (non-Javadoc)
         * @see eu.etaxonomy.cdm.model.common.IDefTerm#getVocabulary()
         */
-       @ManyToOne(fetch=FetchType.EAGER)
+       /* (non-Javadoc)
+        * @see eu.etaxonomy.cdm.model.common.IDefinedTerm#getVocabulary()
+        */
+       @XmlTransient
+       @ManyToOne(fetch=FetchType.LAZY)
        @Cascade( { CascadeType.SAVE_UPDATE })
-       public TermVocabulary getVocabulary() {
+       public TermVocabulary<T> getVocabulary() {
                return this.vocabulary;
        }
        /* (non-Javadoc)
         * @see eu.etaxonomy.cdm.model.common.IDefTerm#setVocabulary(eu.etaxonomy.cdm.model.common.TermVocabulary)
         */
-       public void setVocabulary(TermVocabulary newVocabulary) {
-               // Hibernate bidirectional cascade hack: 
-               // http://opensource.atlassian.com/projects/hibernate/browse/HHH-1054
-               if(this.vocabulary == newVocabulary) return;
-               if (this.vocabulary != null) { 
-                       this.vocabulary.terms.remove(this);
-               }
-               if (newVocabulary!= null) { 
-                       newVocabulary.terms.add(this);
-               }
+       /* (non-Javadoc)
+        * @see eu.etaxonomy.cdm.model.common.IDefinedTerm#setVocabulary(eu.etaxonomy.cdm.model.common.TermVocabulary)
+        */
+       public void setVocabulary(TermVocabulary<T> newVocabulary) {
                this.vocabulary = newVocabulary;                
-       }
-       
+       }       
 }
\ No newline at end of file