fixing residue clip bug in MsaWSThread and adding minimum sequence length constraints.
[jalview.git] / src / jalview / ws / MsaWSThread.java
index d51bc76..090af4e 100644 (file)
@@ -74,7 +74,14 @@ class MsaWSThread extends Thread implements WSClientI {
      */
     public MsaWSJob(int jobNum, SequenceI[] inSeqs) {
       this.jobnum = jobNum;
-      prepareInput(inSeqs);
+      if (!prepareInput(inSeqs,2)) {
+        submitted=true;
+        subjobComplete=true;
+        result = new MsaResult();
+        result.setFinished(true);
+        result.setStatus("Job never ran - input returned to user.");
+      }
+        
     }
     
     int allowedServerExceptions = 3; // thread dies if too many
@@ -85,15 +92,24 @@ class MsaWSThread extends Thread implements WSClientI {
     
     Hashtable SeqNames = new Hashtable();
     Vector emptySeqs = new Vector();
-    private void prepareInput(SequenceI[] seqs) {
+    /**
+     * prepare input sequences for MsaWS service
+     * @param seqs jalview sequences to be prepared
+     * @param minlen minimum number of residues required for this MsaWS service
+     * @return true if seqs contains sequences to be submitted to service.
+     */
+    private boolean prepareInput(SequenceI[] seqs, int minlen) {
       int nseqs = 0;
+      if (minlen<0)
+        throw new Error("Implementation error: minlen must be zero or more.");
       for (int i = 0; i < seqs.length; i++) {
-        if (seqs[i].getStart() < seqs[i].getEnd()) {
+        if (seqs[i].getEnd()-seqs[i].getStart()>minlen-1) {
           nseqs++;
         }
       }
+      boolean valid=nseqs>1; // need at least two seqs
       vamsas.objects.simple.Sequence[] seqarray = 
-        (nseqs>0) 
+          (valid) 
         ? new vamsas.objects.simple.Sequence[nseqs]
                                              :null;
         for (int i = 0, n = 0; i < seqs.length; i++) {
@@ -104,7 +120,7 @@ class MsaWSThread extends Thread implements WSClientI {
           // subjob
           SeqNames.put(newname, jalview.analysis.SeqsetUtils
               .SeqCharacterHash(seqs[i]));
-          if (seqs[i].getStart() < seqs[i].getEnd()) {
+          if (valid && seqs[i].getEnd()-seqs[i].getStart()>minlen-1) {
             seqarray[n] = new vamsas.objects.simple.Sequence();
             seqarray[n].setId(newname);
             seqarray[n++].setSeq((submitGaps) ? seqs[i].getSequence()
@@ -112,11 +128,19 @@ class MsaWSThread extends Thread implements WSClientI {
                     jalview.util.Comparison.GapChars, seqs[i]
                                                            .getSequence()));
           } else {
-            emptySeqs.add(newname);
+            String empty=null;
+            if (seqs[i].getEnd()>=seqs[i].getStart()) {
+              empty = (submitGaps) ? seqs[i].getSequence()
+                    : AlignSeq.extractGaps(
+                        jalview.util.Comparison.GapChars, seqs[i]
+                                                               .getSequence());              
+            }
+            emptySeqs.add(new String[] { newname, empty});
           }
         }
         this.seqs = new vamsas.objects.simple.SequenceSet();
         this.seqs.setSeqs(seqarray);
+        return valid;
     }
     /**
      * 
@@ -150,12 +174,40 @@ class MsaWSThread extends Thread implements WSClientI {
               alseqs[i] = null;
             }
           }
+          // check that aligned width is at least as wide as emptySeqs width.
+          int ow=w,nw=w;
+          for (i=0, w=emptySeqs.size(); i<w; i++) {
+            String[] es=(String[]) emptySeqs.get(i);
+            if (es!=null && es[1]!=null) {
+              int sw=es[1].length();
+              if (nw<sw)
+                nw=sw;
+            }
+          }
           // make a gapped string.
           StringBuffer insbuff=new StringBuffer(w);
-          for (i=0; i<w; i++)
+          for (i=0; i<nw; i++)
             insbuff.append(alseq_gapchar);
+          if (ow<nw) {
+            for (i=0; i<alseq_l; i++) {
+              int sw=t_alseqs[i].getLength();
+              if (nw>sw) {
+                // pad at end
+                alseqs[i].setSequence(t_alseqs[i].getSequence()+insbuff.substring(0,sw-nw));
+              }
+            }
+          }
           for (i=0, w=emptySeqs.size(); i<w; i++) {
-            t_alseqs[i+alseqs.length] = new jalview.datamodel.Sequence((String)emptySeqs.get(i), insbuff.toString());
+            String[] es=(String[]) emptySeqs.get(i);
+            if (es[1]==null)
+              t_alseqs[i+alseq_l] = new jalview.datamodel.Sequence(es[0], insbuff.toString(),1,0);
+            else {
+              if (es[1].length()<nw) {
+                t_alseqs[i+alseq_l] = new jalview.datamodel.Sequence(es[0], es[1]+insbuff.substring(0, nw-es[1].length()),1,1+es[1].length());
+              } else {
+                t_alseqs[i+alseq_l] = new jalview.datamodel.Sequence(es[0], es[1]);
+              }
+            }
           }
           alseqs = t_alseqs;
         } 
@@ -607,7 +659,7 @@ class MsaWSThread extends Thread implements WSClientI {
               alignment[s] = mseq[s];
             } else {
               alignment[s].setSequence(alignment[s].getSequence()+mseq[s].getSequence());
-              if (alignment[s].getEnd()<mseq[s].getEnd())
+              if (mseq[s].getStart()<=mseq[s].getEnd())
                 alignment[s].setEnd(mseq[s].getEnd());
               ((AlignmentOrder) subalg[1]).updateSequence(mseq[s], alignment[s]);
             }
@@ -623,7 +675,8 @@ class MsaWSThread extends Thread implements WSClientI {
             alignment[s] = hseq;
           } else {
             alignment[s].setSequence(alignment[s].getSequence()+hseq.getSequence());
-            alignment[s].setEnd(hseq.getEnd());
+            if (hseq.getEnd()>=hseq.getStart())
+              alignment[s].setEnd(hseq.getEnd());
           }
         }
         // mark hidden segment as hidden in the new alignment
@@ -632,7 +685,7 @@ class MsaWSThread extends Thread implements WSClientI {
         cshift+=contigs[contig+2];
       }
       // Do final job - if it exists
-      if (j<jobs.length) {
+      if (j<jobs.length && jobs[j].hasResults()) {
         Object[] subalg =  jobs[j].getAlignment();
         alorders.add(subalg[1]);
         SequenceI mseq[] = (SequenceI[]) subalg[0];
@@ -642,7 +695,8 @@ class MsaWSThread extends Thread implements WSClientI {
             alignment[s] = mseq[s];
           } else {
             alignment[s].setSequence(alignment[s].getSequence()+mseq[s].getSequence());
-            alignment[s].setEnd(mseq[s].getEnd());
+            if (mseq[s].getEnd()>=mseq[s].getStart())
+              alignment[s].setEnd(mseq[s].getEnd());
             ((AlignmentOrder) subalg[1]).updateSequence(mseq[s], alignment[s]);
           }
         }