Changed DefinedTermBase.media form OneToMany to ManyToMany #560
[cdmlib.git] / cdmlib-model / src / main / java / eu / etaxonomy / cdm / model / common / DefinedTermBase.java
index 37427b4885870d789018b1b193864da76e2dedcd..f17b90d3fd6a27a752002dd7f4c2518be101fd17 100644 (file)
@@ -9,19 +9,21 @@
 
 package eu.etaxonomy.cdm.model.common;
 
-import org.apache.log4j.Logger;
-import org.hibernate.annotations.Cascade;
-import org.hibernate.annotations.CascadeType;
-import org.hibernate.collection.AbstractPersistentCollection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.UUID;
 
-import au.com.bytecode.opencsv.CSVWriter;
-import eu.etaxonomy.cdm.model.common.init.DefaultVocabularyStore;
-import eu.etaxonomy.cdm.model.common.init.IVocabularyStore;
-import eu.etaxonomy.cdm.model.media.Media;
-import java.lang.reflect.Field;
-import java.util.*;
-
-import javax.persistence.*;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.Inheritance;
+import javax.persistence.InheritanceType;
+import javax.persistence.ManyToMany;
+import javax.persistence.ManyToOne;
+import javax.persistence.OneToMany;
+import javax.persistence.Transient;
+import javax.validation.constraints.NotNull;
 import javax.xml.bind.annotation.XmlAccessType;
 import javax.xml.bind.annotation.XmlAccessorType;
 import javax.xml.bind.annotation.XmlElement;
@@ -29,9 +31,29 @@ 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.XmlSeeAlso;
 import javax.xml.bind.annotation.XmlTransient;
 import javax.xml.bind.annotation.XmlType;
 
+import org.apache.log4j.Logger;
+import org.hibernate.annotations.Cascade;
+import org.hibernate.annotations.CascadeType;
+import org.hibernate.envers.Audited;
+
+import au.com.bytecode.opencsv.CSVWriter;
+import eu.etaxonomy.cdm.model.agent.InstitutionType;
+import eu.etaxonomy.cdm.model.description.Feature;
+import eu.etaxonomy.cdm.model.description.MeasurementUnit;
+import eu.etaxonomy.cdm.model.description.StatisticalMeasure;
+import eu.etaxonomy.cdm.model.description.TextFormat;
+import eu.etaxonomy.cdm.model.location.NamedAreaType;
+import eu.etaxonomy.cdm.model.location.ReferenceSystem;
+import eu.etaxonomy.cdm.model.media.Media;
+import eu.etaxonomy.cdm.model.media.RightsTerm;
+import eu.etaxonomy.cdm.model.name.NomenclaturalCode;
+import eu.etaxonomy.cdm.model.occurrence.DerivationEventType;
+import eu.etaxonomy.cdm.model.occurrence.PreservationMethod;
+
 
 /**
  * walkaround for enumerations, base type according to TDWG.  For linear ordering
@@ -43,53 +65,97 @@ import javax.xml.bind.annotation.XmlType;
  */
 @XmlAccessorType(XmlAccessType.FIELD)
 @XmlType(name = "DefinedTermBase", propOrder = {
-    "kindOf",
-    "generalizationOf",
-    "partOf",
-    "includes",
     "media",
     "vocabulary"
 })
 @XmlRootElement(name = "DefinedTermBase")
+@XmlSeeAlso({
+       AnnotationType.class,
+       DerivationEventType.class,
+       ExtensionType.class,
+    Feature.class,
+    InstitutionType.class,
+    Language.class,
+    MarkerType.class,
+    MeasurementUnit.class,
+    NamedAreaType.class,
+    NomenclaturalCode.class,
+    PreservationMethod.class,
+    ReferenceSystem.class,
+    RightsTerm.class,
+    StatisticalMeasure.class,
+    TextFormat.class
+})
 @Entity
+@Audited
 @Inheritance(strategy=InheritanceType.SINGLE_TABLE)
-public abstract class DefinedTermBase<T extends DefinedTermBase> extends TermBase implements ILoadableTerm{
-       static Logger logger = Logger.getLogger(DefinedTermBase.class);
-       
-       static protected IVocabularyStore vocabularyStore = new DefaultVocabularyStore();
-
-       public static void setVocabularyStore(IVocabularyStore vocabularyStore){
-               DefinedTermBase.vocabularyStore = vocabularyStore;
-       }
-       
-       @XmlElement(name = "KindOf")
-       private DefinedTermBase kindOf;
-       
-       @XmlElement(name = "GeneralizationOf")
-       private Set<DefinedTermBase> generalizationOf = new HashSet<DefinedTermBase>();
+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")
+       @XmlTransient
+    @ManyToOne(fetch = FetchType.LAZY, targetEntity = DefinedTermBase.class)
+    @Cascade(CascadeType.SAVE_UPDATE)
+       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?
+        */
+//     @XmlElementWrapper(name = "Generalizations")
+//     @XmlElement(name = "GeneralizationOf")
+//    @XmlIDREF
+//    @XmlSchemaType(name = "IDREF")
+       @XmlTransient
+    @OneToMany(fetch=FetchType.LAZY, mappedBy = "kindOf", targetEntity = DefinedTermBase.class)
+       @Cascade({CascadeType.SAVE_UPDATE})
+       private Set<T> generalizationOf = new HashSet<T>();
        
-       @XmlElement(name = "PartOf")
-       private DefinedTermBase partOf;
+//     @XmlElement(name = "PartOf")
+//     @XmlIDREF
+//  @XmlSchemaType(name = "IDREF")
+       @XmlTransient
+       @ManyToOne(fetch = FetchType.LAZY, targetEntity = DefinedTermBase.class)
+       @Cascade(CascadeType.SAVE_UPDATE)
+       protected T partOf;
        
-       @XmlElementWrapper(name = "Includes")
-       @XmlElement(name = "Include")
-       private Set<DefinedTermBase> includes = new HashSet<DefinedTermBase>();
+       /**
+        * 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")
+//     @XmlIDREF
+//    @XmlSchemaType(name = "IDREF")
+       @XmlTransient
+       @OneToMany(fetch=FetchType.LAZY, mappedBy = "partOf", targetEntity = DefinedTermBase.class)
+       @Cascade({CascadeType.SAVE_UPDATE})
+       private Set<T> includes = new HashSet<T>();
        
+       /**
+        * FIXME should be many-to-many?
+        */
        @XmlElementWrapper(name = "Media")
        @XmlElement(name = "Medium")
     @XmlIDREF
     @XmlSchemaType(name = "IDREF")
+    @ManyToMany(fetch = FetchType.LAZY)
+       @OneToMany(fetch = FetchType.LAZY)
+       @Cascade({CascadeType.SAVE_UPDATE})
        private Set<Media> media = new HashSet<Media>();
        
        @XmlElement(name = "TermVocabulary")
        @XmlIDREF
        @XmlSchemaType(name = "IDREF")
-       protected TermVocabulary<T> vocabulary;
+       @ManyToOne(fetch=FetchType.LAZY)
+       @Cascade(CascadeType.SAVE_UPDATE)
+       protected TermVocabulary<T> vocabulary; 
        
-
-       public static DefinedTermBase findByUuid(UUID uuid){
-               return vocabularyStore.getTermByUuid(uuid);
-       }
+//***************************** CONSTRUCTOR *******************************************/       
        
        public DefinedTermBase() {
                super();
@@ -98,91 +164,152 @@ public abstract class DefinedTermBase<T extends DefinedTermBase> extends TermBas
                super(term, label, labelAbbrev);
        }
 
+//******************************* METHODS ******************************************************/
+       
+       public abstract void resetTerms();
 
+       protected abstract void setDefaultTerms(TermVocabulary<T> termVocabulary);
+       
+       
        /* (non-Javadoc)
         * @see eu.etaxonomy.cdm.model.common.ILoadableTerm#readCsvLine(java.util.List)
         */
-       public ILoadableTerm readCsvLine(List<String> csvLine) {
-               return 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.CSV_LANGUAGE());
+               } catch (Exception e) {
+                       logger.error(e);
+                       for(StackTraceElement ste : e.getStackTrace()) {
+                               logger.error(ste);
+                       }
+               }
+               
+           return null;
        }
-       public ILoadableTerm readCsvLine(List<String> csvLine, Language lang) {
-               this.setUuid(UUID.fromString(csvLine.get(0)));
-               this.setUri(csvLine.get(1));
-               String label = csvLine.get(2).trim();
-               String text = csvLine.get(3);
-               String abbreviatedLabel = null;
-               this.addRepresentation(Representation.NewInstance(text, label, abbreviatedLabel, lang) );
-               return this;
+
+       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.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(){
-               return this.kindOf;
+       public T getByUuid(UUID uuid){
+               return this.vocabulary.findTermByUuid(uuid);
        }
-       public void setKindOf(DefinedTermBase kindOf){
+       
+       /* (non-Javadoc)
+        * @see eu.etaxonomy.cdm.model.common.IDefinedTerm#getKindOf()
+        */
+       public T getKindOf(){
+               return (T)DefinedTermBase.deproxy(this.kindOf, this.getClass());
+       }
+
+       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()
+        */
+       public Set<T> getGeneralizationOf(){
                return this.generalizationOf;
        }
-       public void setGeneralizationOf(Set<DefinedTermBase> generalizationOf) {
-               this.generalizationOf = generalizationOf;
+       
+       protected void setGeneralizationOf(Set<T> value) {
+               this.generalizationOf = value;
+       }
+       
+       /* (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(){
-               return this.partOf;
+       /* (non-Javadoc)
+        * @see eu.etaxonomy.cdm.model.common.IDefinedTerm#getPartOf()
+        */
+       public T getPartOf(){
+               return (T)DefinedTermBase.deproxy(this.partOf, this.getClass());
        }
-       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()
+        */
+       public Set<T> getIncludes(){
                return this.includes;
        }
-       public void setIncludes(Set<DefinedTermBase> includes) {
+       
+       protected 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
-       @Cascade({CascadeType.SAVE_UPDATE})
+       /* (non-Javadoc)
+        * @see eu.etaxonomy.cdm.model.common.IDefinedTerm#getMedia()
+        */
        public Set<Media> getMedia(){
                return this.media;
        }
-       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);
        }
@@ -190,74 +317,18 @@ public abstract class DefinedTermBase<T extends DefinedTermBase> extends TermBas
                this.media.remove(media);
        }
 
-       /* (non-Javadoc)
-        * @see eu.etaxonomy.cdm.model.common.IDefTerm#getVocabulary()
-        */
-       @Transient
-       @XmlTransient
-       public TermVocabulary 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);
-               }
-               this.vocabulary = newVocabulary;                
-       }
-       
-       
-       /* (non-Javadoc)
-        * @see eu.etaxonomy.cdm.model.common.IDefTerm#getVocabulary()
+       /**
+        * @return
         */
-       @ManyToOne(fetch=FetchType.LAZY)
-       @Cascade( { CascadeType.SAVE_UPDATE })
-       protected TermVocabulary getPersistentVocabulary() {
+       public TermVocabulary<T> getVocabulary() {
                return this.vocabulary;
        }
-       /* (non-Javadoc)
-        * @see eu.etaxonomy.cdm.model.common.IDefTerm#setVocabulary(eu.etaxonomy.cdm.model.common.TermVocabulary)
+
+       //for bedirectional use only, use vocabulary.addTerm instead
+       /**
+        * @param newVocabulary
         */
-       protected void setPersistentVocabulary(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) { 
-                       try {
-                               Field fieldInitializing = AbstractPersistentCollection.class.getDeclaredField("initializing");
-                               fieldInitializing.setAccessible(true);
-                               if (AbstractPersistentCollection.class.isAssignableFrom(newVocabulary.terms.getClass())){
-                                       boolean initValue = fieldInitializing.getBoolean(newVocabulary.terms);
-                                       if (initValue == false){
-                                               newVocabulary.terms.add(this);
-                                       }else{
-                                               //nothing
-                                       }
-                               }else{
-                                       newVocabulary.terms.add(this);
-                               }
-                       } catch (SecurityException e) {
-                               e.printStackTrace();
-                       } catch (IllegalArgumentException e) {
-                               e.printStackTrace();
-                       } catch (NoSuchFieldException e) {
-                               e.printStackTrace();
-                       } catch (IllegalAccessException e) {
-                               e.printStackTrace();
-                       }
-               }
+       protected void setVocabulary(TermVocabulary<T> newVocabulary) {
                this.vocabulary = newVocabulary;                
-       }
-       
+       }       
 }
\ No newline at end of file