minor
[cdmlib.git] / cdmlib-model / src / main / java / eu / etaxonomy / cdm / model / description / DescriptionBase.java
index d2dedc28773d50e358c065d4f593dc93dd53ad80..a08d978a4293797bf517a9922b153d05cf2f0719 100644 (file)
@@ -16,7 +16,8 @@ import javax.persistence.Entity;
 import javax.persistence.FetchType;
 import javax.persistence.Inheritance;
 import javax.persistence.InheritanceType;
-
+import javax.persistence.JoinTable;
+import javax.persistence.ManyToMany;
 import javax.persistence.OneToMany;
 import javax.persistence.Transient;
 import javax.xml.bind.annotation.XmlAccessType;
@@ -24,31 +25,32 @@ import javax.xml.bind.annotation.XmlAccessorType;
 import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlElementWrapper;
 import javax.xml.bind.annotation.XmlElements;
+import javax.xml.bind.annotation.XmlIDREF;
+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.envers.Audited;
 
-import eu.etaxonomy.cdm.model.agent.Institution;
-import eu.etaxonomy.cdm.model.agent.Person;
-import eu.etaxonomy.cdm.model.agent.Team;
 import eu.etaxonomy.cdm.model.common.IdentifiableEntity;
 import eu.etaxonomy.cdm.model.name.TaxonNameBase;
 import eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationBase;
-import eu.etaxonomy.cdm.model.reference.BibtexReference;
 import eu.etaxonomy.cdm.model.reference.ReferenceBase;
-import eu.etaxonomy.cdm.model.reference.StrictReferenceBase;
-import eu.etaxonomy.cdm.model.taxon.Synonym;
-import eu.etaxonomy.cdm.model.taxon.SynonymRelationship;
-import eu.etaxonomy.cdm.model.taxon.SynonymRelationshipType;
+import eu.etaxonomy.cdm.model.taxon.Taxon;
+import eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy;
 
 /**
  * The upmost (abstract) class for a description as a whole (with possibly
- * several elementary information data) for a specimen, a taxon or even a
- * taxon name.
+ * several {@link DescriptionElementBase elementary information data})
+ * for a {@link SpecimenOrObservationBase specimen}, a {@link Taxon taxon}
+ * or even a {@link TaxonNameBase taxon name}.
  * <P>
- * This class corresponds to DescriptionsSectionType according to SDD
+ * This class corresponds to: <ul>
+ * <li> DescriptionsSectionType according to the the SDD schema
+ * <li> MeasurementOrFact according to the ABCD schema
+ * </ul>
  * 
  * @author m.doering
  * @version 1.0
@@ -59,22 +61,41 @@ import eu.etaxonomy.cdm.model.taxon.SynonymRelationshipType;
 @XmlType(name = "DescriptionBase", propOrder = {
     "describedSpecimenOrObservations",
     "descriptionSources",
-    "descriptionElements"
+    "descriptiveSystem",
+    "descriptionElements",
+    "imageGallery"
 })
 @Entity
+@Audited
 @Inheritance(strategy=InheritanceType.SINGLE_TABLE)
-public abstract class DescriptionBase extends IdentifiableEntity {
-       
+public abstract class DescriptionBase<S extends IIdentifiableEntityCacheStrategy> extends IdentifiableEntity<S> {
+       private static final long serialVersionUID = 5504218413819040193L;
        private static final Logger logger = Logger.getLogger(DescriptionBase.class);
        
        @XmlElementWrapper(name = "DescribedSpecimenOrObservations")
        @XmlElement(name = "DescribedSpecimenOrObservation")
+       @XmlIDREF
+       @XmlSchemaType(name="IDREF")
+       @ManyToMany(fetch = FetchType.LAZY)
+       @Cascade(CascadeType.SAVE_UPDATE)
        private Set<SpecimenOrObservationBase> describedSpecimenOrObservations = new HashSet<SpecimenOrObservationBase>();
        
        @XmlElementWrapper(name = "DescriptionSources")
        @XmlElement(name = "DescriptionSource")
+       @XmlIDREF
+       @XmlSchemaType(name="IDREF")
+       @ManyToMany(fetch = FetchType.LAZY)  //FIXME what is the difference between this and IdentifiableEntity.sources
        private Set<ReferenceBase> descriptionSources = new HashSet<ReferenceBase>();
        
+       @XmlElementWrapper(name = "DescriptiveSystem")
+       @XmlElement(name = "Feature")
+       @XmlIDREF
+       @XmlSchemaType(name="IDREF")
+       @ManyToMany(fetch = FetchType.LAZY)  //FIXME
+    //@Cascade( { CascadeType.SAVE_UPDATE, CascadeType.MERGE })
+    @JoinTable(name = "DescriptionBase_Feature")
+       private Set<Feature> descriptiveSystem = new HashSet<Feature>();
+       
        @XmlElementWrapper(name = "DescriptionElements")
     @XmlElements({
         @XmlElement(name = "CategorialData", namespace = "http://etaxonomy.eu/cdm/model/description/1.0", type = CategoricalData.class),
@@ -85,53 +106,64 @@ public abstract class DescriptionBase extends IdentifiableEntity {
         @XmlElement(name = "TaxonInteraction", namespace = "http://etaxonomy.eu/cdm/model/description/1.0", type = TaxonInteraction.class),
         @XmlElement(name = "TextData", namespace = "http://etaxonomy.eu/cdm/model/description/1.0", type = TextData.class)
     })
+    @OneToMany(fetch=FetchType.LAZY, mappedBy = "inDescription")
+       @Cascade( { CascadeType.SAVE_UPDATE, CascadeType.MERGE, CascadeType.DELETE, CascadeType.DELETE_ORPHAN })
        private Set<DescriptionElementBase> descriptionElements = new HashSet<DescriptionElementBase>();
 
+       @XmlElement(name = "ImageGallery")
+       private boolean imageGallery;
+       
+       
        /**
         * Returns the set of {@link SpecimenOrObservationBase specimens or observations} involved in
-        * <i>this</i> description as a whole. Taxon descriptions are also often based
-        * on concrete specimens or observations. 
+        * <i>this</i> description as a whole. {@link TaxonDescription Taxon descriptions} are also often based
+        * on concrete specimens or observations. For {@link TaxonNameDescription taxon name descriptions}
+        * this set should be empty.
         * 
         * @see    #addDescribedSpecimenOrObservations(SpecimenOrObservationBase)
         * @see    #removeDescribedSpecimenOrObservations(SpecimenOrObservationBase)
         */
-       //@ManyToMany  //FIXME
-       @Transient 
        public Set<SpecimenOrObservationBase> getDescribedSpecimenOrObservations() {
                return describedSpecimenOrObservations;
        }
-
-       /** 
-        * @see    #getDescribedSpecimenOrObservations()
-        * @see    #addDescribedSpecimenOrObservations(SpecimenOrObservationBase)
-        */
-       public void setDescribedSpecimenOrObservations(
-                       Set<SpecimenOrObservationBase> describedSpecimenOrObservations) {
-               this.describedSpecimenOrObservations = describedSpecimenOrObservations;
-       }
        
        /**
         * Adds an existing {@link SpecimenOrObservationBase specimen or observation} to the set of
         * {@link #getDescribedSpecimenOrObservations() specimens or observations} described in <i>this</i>
-        * description or which <i>this</i> description is based on.
+        * description or which <i>this</i> description is based on.<BR>
+        * Due to bidirectionality if <i>this</i> description is a {@link SpecimenDescription specimen description},
+        * <i>this</i> description will also be added to the set of specimen
+        * descriptions corresponding to the given additional specimen or observation.
         * 
         * @param describedSpecimenOrObservation        the specimen or observation to be added to <i>this</i> description
         * @see                                                                         #getDescribedSpecimenOrObservations()
+        * @see                                                                         SpecimenOrObservationBase#addDescription(DescriptionBase)
         */
-       public void addDescribedSpecimenOrObservations(SpecimenOrObservationBase describedSpecimenOrObservation) {
+       public void addDescribedSpecimenOrObservation(SpecimenOrObservationBase describedSpecimenOrObservation) {
+               logger.debug("addDescribedSpecimenOrObservations");
                this.describedSpecimenOrObservations.add(describedSpecimenOrObservation);
+               if (! describedSpecimenOrObservation.getDescriptions().contains(this)){
+                       describedSpecimenOrObservation.addDescription(this);
+               }
        }
        
        /** 
         * Removes one element from the set of {@link #getDescribedSpecimenOrObservations() specimens or observations} involved
-        * in <i>this</i> description.
+        * in <i>this</i> description.<BR>
+        * Due to bidirectionality if <i>this</i> description is a {@link SpecimenDescription specimen description},
+        * <i>this</i> description will also be removed from the set of specimen
+        * descriptions corresponding to the given specimen or observation.
         *
-        * @param  describedSpecimenOrObservation   the specimen or observation which should be deleted
+        * @param  describedSpecimenOrObservation   the specimen or observation which should be removed
         * @see                                                                 #getDescribedSpecimenOrObservations()
         * @see                                                                 #addDescribedSpecimenOrObservations(SpecimenOrObservationBase)
+        * @see                                                                 SpecimenOrObservationBase#removeDescription(DescriptionBase)
         */
-       public void removeDescribedSpecimenOrObservations(SpecimenOrObservationBase describedSpecimenOrObservation) {
+       public void removeDescribedSpecimenOrObservation(SpecimenOrObservationBase describedSpecimenOrObservation) {
                this.describedSpecimenOrObservations.remove(describedSpecimenOrObservation);
+               if (describedSpecimenOrObservation.getDescriptions().contains(this)){
+                       describedSpecimenOrObservation.removeDescription(this);
+               }
        }
 
        /**
@@ -142,21 +174,10 @@ public abstract class DescriptionBase extends IdentifiableEntity {
         * @see    #addDescriptionSource(ReferenceBase)
         * @see    #removeDescriptionSource(ReferenceBase)
         */
-//     @ManyToMany  //FIXME
-//     @Cascade( { CascadeType.SAVE_UPDATE })
-       @Transient
        public Set<ReferenceBase> getDescriptionSources() {
                return this.descriptionSources;
        }
        
-       /** 
-        * @see    #getDescriptionSources()
-        * @see    #addDescriptionSource(ReferenceBase)
-        */
-       protected void setDescriptionSources(Set<ReferenceBase> descriptionSources) {
-               this.descriptionSources = descriptionSources;
-       }
-       
        /**
         * Adds an existing {@link ReferenceBase reference} to the set of
         * {@link #getDescriptionSources() references} used as sources for <i>this</i>
@@ -181,6 +202,49 @@ public abstract class DescriptionBase extends IdentifiableEntity {
                this.descriptionSources.remove(descriptionSource);
        }
 
+       /**
+        * Returns the set of {@link Feature feature} used as 
+        * features/characters/descriptors for <i>this</i> description.
+        * 
+        * @see    #addFeature(Feature)
+        * @see    #removeFeature(Feature)
+        */
+       public Set<Feature> getDescriptiveSystem() {
+               return this.descriptiveSystem;
+       }
+       
+       /** 
+        * @see    #getDescriptiveSystem()
+        * @see    #addDescriptiveSystem(Feature)
+        */
+       public void setDescriptiveSystem(Set<Feature> descriptiveSystem) {
+               this.descriptiveSystem = descriptiveSystem;
+       }
+       
+       /**
+        * Adds an existing {@link Feature feature} to the set of
+        * {@link #getDescriptiveSystem() descriptiveSystem} used as features for
+        * <i>this</i> description.
+        * 
+        * @param feature       the feature to be added to the descriptive system
+        * @see     #getDescriptiveSystem()
+        */
+       public void addFeature(Feature feature) {
+               this.descriptiveSystem.add(feature);
+       }
+       
+       /** 
+        * Removes one element from the set of {@link #getDescriptiveSystem() features} used as
+        * features for <i>this</i> description.
+        *
+        * @param  feature      the feature which should be deleted
+        * @see     #getDescriptiveSystem()
+        * @see     addFeature(Feature)
+        */
+       public void removeFeature(Feature feature) {
+               this.descriptiveSystem.remove(feature);
+       }
+       
        /**
         * Returns the set of {@link DescriptionElementBase elementary description data} which constitute
         * <i>this</i> description as a whole. 
@@ -188,32 +252,25 @@ public abstract class DescriptionBase extends IdentifiableEntity {
         * @see    #addElement(DescriptionElementBase)
         * @see    #removeElement(DescriptionElementBase)
         */
-       @OneToMany(fetch=FetchType.LAZY)
-       @Cascade( { CascadeType.SAVE_UPDATE })
        public Set<DescriptionElementBase> getElements() {
                return this.descriptionElements;
        }
 
-       /** 
-        * @see    #getElements()
-        * @see    #addElement(DescriptionElementBase)
-        */
-       protected void setElements(Set<DescriptionElementBase> element) {
-               this.descriptionElements = element;
-               if (element == null){
-                       this.setElements(new HashSet<DescriptionElementBase>());
-               }
-       }
-
        /**
         * Adds an existing {@link DescriptionElementBase elementary description} to the set of
         * {@link #getElements() elementary description data} which constitute <i>this</i>
         * description as a whole.
+        * If the elementary descriptions already belongs to a description it is first removed from
+        * the old description.
         * 
         * @param element       the elementary description to be added to <i>this</i> description
         * @see                         #getDescriptionSources()
         */
        public void addElement(DescriptionElementBase element) {
+               if (element.getInDescription() != null){
+                       element.getInDescription().removeElement(element);
+               }
+               element.setInDescription(this);
                this.descriptionElements.add(element);
        }
 
@@ -227,6 +284,7 @@ public abstract class DescriptionBase extends IdentifiableEntity {
         */
        public void removeElement(DescriptionElementBase element) {
                this.descriptionElements.remove(element);
+               element.setInDescription(null);
        }
        
        /**
@@ -241,20 +299,28 @@ public abstract class DescriptionBase extends IdentifiableEntity {
                return this.descriptionElements.size();
        }
        
+    /**
+        * @return the imageGallery
+        */
+       public boolean isImageGallery() {
+               return imageGallery;
+       }
+
        /**
-        * Generates a string that identifies <i>this</i> description.
-        * This string may be stored in the inherited
-        * {@link common.IdentifiableEntity#getTitleCache() titleCache} attribute.<BR>
-        * This method overrides the generic and inherited generateTitle method
-        * from {@link IdentifiableEntity IdentifiableEntity}.
-        *
-        * @return  the string identifying <i>this</i> description
-        * @see         eu.etaxonomy.cdm.model.common.IdentifiableEntity#generateTitle()
-        * @see         eu.etaxonomy.cdm.model.common.IdentifiableEntity#getTitleCache()
+        * @param imageGallery the imageGallery to set
         */
-       @Override
-       public String generateTitle() {
-               //TODO generate title "generate Title not yet implemented"
-               return this.toString();
+       public void setImageGallery(boolean imageGallery) {
+               this.imageGallery = imageGallery;
+       }
+       
+       @Transient
+       public boolean hasStructuredData(){
+               for (DescriptionElementBase element : this.getElements()){
+                       if (element.isInstanceOf(QuantitativeData.class) ||
+                                       element.isInstanceOf(CategoricalData.class)){
+                               return true;
+                       }
+               }
+               return false;
        }
 }