Merge branch 'hotfix/3.12.4' into develop
[cdmlib.git] / cdmlib-model / src / main / java / eu / etaxonomy / cdm / model / molecular / Sequence.java
index 1bff2cb68de7c8ffcf320236a2a88a51ec0ab984..6bc65a7d576c0ff16d071e9af8a44378b882ef95 100644 (file)
@@ -14,12 +14,13 @@ import java.net.URISyntaxException;
 import java.util.HashSet;
 import java.util.Set;
 
+import javax.persistence.Column;
 import javax.persistence.Entity;
 import javax.persistence.FetchType;
 import javax.persistence.ManyToMany;
 import javax.persistence.ManyToOne;
+import javax.persistence.OneToMany;
 import javax.persistence.Transient;
-import javax.validation.constraints.Size;
 import javax.xml.bind.annotation.XmlAccessType;
 import javax.xml.bind.annotation.XmlAccessorType;
 import javax.xml.bind.annotation.XmlAttribute;
@@ -28,6 +29,7 @@ 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;
 
 import org.apache.log4j.Logger;
@@ -76,7 +78,7 @@ import eu.etaxonomy.cdm.model.reference.Reference;
     "boldProcessId",
     "haplotype",
     "contigFile",
-    "singleReads",
+    "singleReadAlignments",
     "citations"
 })
 @XmlRootElement(name = "Sequencing")
@@ -107,7 +109,7 @@ public class Sequence extends AnnotatableEntity implements Cloneable{
     @XmlIDREF
     @XmlSchemaType(name = "IDREF")
     @ManyToOne(fetch = FetchType.LAZY)
-       @Cascade({CascadeType.SAVE_UPDATE})
+       @Cascade({CascadeType.SAVE_UPDATE,CascadeType.MERGE})
        private Media contigFile;
 
        /** @see #getConsensusSequence() */
@@ -123,21 +125,21 @@ public class Sequence extends AnnotatableEntity implements Cloneable{
 
        /** @see #getGeneticAccessionNumber()*/
        @XmlElement(name = "GeneticAccessionNumber")
-       @Size(max=20)
+    @Column(length=20)
        private String geneticAccessionNumber;
 
        /** @see #getBoldProcessId() */
        @XmlElement(name = "BoldProcessId")
-       @Size(max=20)
+    @Column(length=20)
        private String boldProcessId;
 
-    @XmlElementWrapper(name = "SingleReads")
-    @XmlElement(name = "SingleRead")
+    @XmlElementWrapper(name = "SingleReadAlignments")
+    @XmlElement(name = "SingleReadAlignment")
     @XmlIDREF
     @XmlSchemaType(name = "IDREF")
-    @ManyToMany(fetch = FetchType.LAZY)
-    @Cascade({CascadeType.SAVE_UPDATE})
-       private Set<SingleRead> singleReads = new HashSet<SingleRead>();
+    @OneToMany(mappedBy="consensusAlignment", fetch = FetchType.LAZY, orphanRemoval=true)
+    @Cascade({CascadeType.SAVE_UPDATE,CascadeType.MERGE})
+       private Set<SingleReadAlignment> singleReadAlignments = new HashSet<SingleReadAlignment>();
 
        /** @see #getDnaMarker() */
        @XmlElement(name = "DnaMarker")
@@ -150,7 +152,7 @@ public class Sequence extends AnnotatableEntity implements Cloneable{
 
        /** @see #getHaplotype() */
        @XmlElement(name = "Haplotype")
-       @Size(max=100)
+    @Column(length=100)
        private String haplotype;
 
        /** @see #getCitations() */
@@ -159,7 +161,7 @@ public class Sequence extends AnnotatableEntity implements Cloneable{
     @XmlIDREF
     @XmlSchemaType(name = "IDREF")
     @ManyToMany(fetch = FetchType.LAZY)
-    @Cascade({CascadeType.SAVE_UPDATE})
+    @Cascade({CascadeType.SAVE_UPDATE,CascadeType.MERGE})
        private Set<Reference> citations = new HashSet<Reference>();
 
 //     //should be calculated in case sequence is set
@@ -406,27 +408,78 @@ public class Sequence extends AnnotatableEntity implements Cloneable{
         * @see #getConsensusSequence()
         * @see #getContigFile()
         */
-       public Set<SingleRead> getSingleReads() {
-               return singleReads;
+       public Set<SingleReadAlignment> getSingleReadAlignments() {
+               return singleReadAlignments;
        }
        /**
         * @see #getSingleReads()
         */
-       public void addSingleRead(SingleRead singleRead) {
-               this.singleReads.add(singleRead);
+       public void addSingleReadAlignment(SingleReadAlignment singleReadAlignment) {
+               this.singleReadAlignments.add(singleReadAlignment);
+               if (! this.equals(singleReadAlignment.getConsensusSequence())){
+                       singleReadAlignment.setConsensusAlignment(this);
+               };
        }
        /**
         * @see #getSingleReads()
         */
+       public void removeSingleReadAlignment(SingleReadAlignment singleReadAlignment) {
+               this.singleReadAlignments.remove(singleReadAlignment);
+               if (this.equals(singleReadAlignment.getConsensusSequence())){
+                       singleReadAlignment.setConsensusAlignment(null);
+                       singleReadAlignment.setSingleRead(null);
+               }
+       }
+//     /**
+//      * @see #getSingleReads()
+//      */
+//     //TODO private as long it is unclear how bidirectionality is handled
+//     @SuppressWarnings("unused")
+//     private void setSingleReadAlignments(Set<SingleReadAlignment> singleReadAlignments) {
+//             this.singleReadAlignments = singleReadAlignments;
+//     }
+
+// *********************** CONVENIENCE ***********************************/
+
+       /**
+        * Convenience method to add a single read to a consensus sequence
+        * by creating a {@link SingleReadAlignment}.
+        * @param singleRead the {@link SingleRead} to add
+        * @return the created SingleReadAlignment
+        */
+       public SingleReadAlignment addSingleRead(SingleRead singleRead) {
+               SingleReadAlignment alignment = SingleReadAlignment.NewInstance(this, singleRead);
+               return alignment;
+       }
+
        public void removeSingleRead(SingleRead singleRead) {
-               this.singleReads.remove(singleRead);
+               Set<SingleReadAlignment> toRemove = new HashSet<SingleReadAlignment>();
+               for (SingleReadAlignment align : this.singleReadAlignments){
+                       if (align.getSingleRead() != null && align.getSingleRead().equals(singleRead)){
+                               toRemove.add(align);
+                       }
+               }
+               for (SingleReadAlignment align : toRemove){
+                       removeSingleReadAlignment(align);
+               }
+               return;
        }
+
        /**
-        * @see #getSingleReads()
+        * Convenience method that returns all single reads this consensus sequence
+        * is based on via {@link SingleReadAlignment}s.
+        * @return set of related single reads
         */
-       //TODO private as long it is unclear how bidirectionality is handled
-       private void setSingleReads(Set<SingleRead> singleReads) {
-               this.singleReads = singleReads;
+       @XmlTransient
+       @Transient
+       public Set<SingleRead> getSingleReads(){
+               Set<SingleRead> singleReads = new HashSet<SingleRead>();
+               for (SingleReadAlignment align : this.singleReadAlignments){
+                       if (align.getSingleRead() != null){  // == null should not happen
+                               singleReads.add(align.getSingleRead());
+                       }
+               }
+               return singleReads;
        }
 
 
@@ -457,9 +510,9 @@ public class Sequence extends AnnotatableEntity implements Cloneable{
        @Transient
        public Set<Media> getPherograms(){
                Set<Media> result = new HashSet<Media>();
-               for (SingleRead singleSeq : singleReads){
-                       if (singleSeq.getPherogram() != null){
-                               result.add(singleSeq.getPherogram());
+               for (SingleReadAlignment singleReadAlign : singleReadAlignments){
+                       if (singleReadAlign.getSingleRead() != null &&  singleReadAlign.getSingleRead().getPherogram() != null){
+                               result.add(singleReadAlign.getSingleRead().getPherogram());
                        }
                }
                return result;
@@ -540,14 +593,15 @@ public class Sequence extends AnnotatableEntity implements Cloneable{
 
 
                //single sequences
-               result.singleReads = new HashSet<SingleRead>();
-               for (SingleRead seq: this.singleReads){
-                       result.singleReads.add(seq);
+               result.singleReadAlignments = new HashSet<SingleReadAlignment>();
+               for (SingleReadAlignment singleReadAlign: this.singleReadAlignments){
+                       SingleReadAlignment newAlignment = (SingleReadAlignment)singleReadAlign.clone();
+                       result.singleReadAlignments.add(newAlignment);
                }
 
                //citations  //TODO do we really want to copy these ??
                result.citations = new HashSet<Reference>();
-               for (Reference ref: this.citations){
+               for (Reference<?> ref: this.citations){
                        result.citations.add(ref);
                }