multiple web service jobs from visible blocks of an alignment.
authorjprocter <Jim Procter>
Fri, 11 Aug 2006 17:30:22 +0000 (17:30 +0000)
committerjprocter <Jim Procter>
Fri, 11 Aug 2006 17:30:22 +0000 (17:30 +0000)
src/jalview/datamodel/AlignmentOrder.java
src/jalview/datamodel/AlignmentView.java
src/jalview/gui/WebserviceInfo.java
src/jalview/jbgui/GWebserviceInfo.java
src/jalview/ws/Discoverer.java
src/jalview/ws/MsaWSClient.java
src/jalview/ws/MsaWSThread.java [new file with mode: 0644]

index 1fa3b96..231009a 100755 (executable)
@@ -167,7 +167,19 @@ public class AlignmentOrder
     {\r
         return Order;\r
     }\r
-\r
+    /**\r
+     * replaces oldref with newref in the alignment order.\r
+     * @param oldref\r
+     * @param newref\r
+     * @return\r
+     */\r
+    public boolean updateSequence(SequenceI oldref, SequenceI newref) {\r
+      int found=Order.indexOf(oldref);\r
+      if (found>-1) {\r
+        Order.setElementAt(newref, found);\r
+      }\r
+      return found>-1;\r
+    }\r
     /**\r
      * AlignmentOrder\r
      *\r
index 727bc76..3524942 100644 (file)
@@ -19,6 +19,7 @@ public class AlignmentView
      */
     private SeqCigar[] sequences = null;
   private int[] contigs = null;
+  private int width=0;
   public AlignmentView(CigarArray seqcigararray)
   {
     if (!seqcigararray.isSeqCigarArray())
@@ -26,6 +27,7 @@ public class AlignmentView
     //contigs = seqcigararray.applyDeletions();
     contigs = seqcigararray.getDeletedRegions();
     sequences = seqcigararray.getSeqCigarArray();
+    width = seqcigararray.getWidth(); // visible width
   }
 
   public void setSequences(SeqCigar[] sequences)
@@ -66,4 +68,16 @@ public class AlignmentView
     }
     return seqs;
   }
+  /**
+   * 
+   * @return visible number of columns in alignment view
+   */
+  public int getWidth() {
+    return width;
+  }
+
+  protected void setWidth(int width) {
+    this.width = width;
+  }
+  
 }
index 9dadee7..63ef9f0 100755 (executable)
  */\r
 package jalview.gui;\r
 \r
-import jalview.jbgui.*;\r
+import java.util.*;\r
 \r
 import java.awt.*;\r
 import java.awt.event.*;\r
 import java.awt.image.*;\r
-\r
 import javax.swing.*;\r
 \r
+import jalview.jbgui.*;\r
+\r
 \r
 /**\r
  * Base class for web service client thread and gui\r
@@ -35,6 +36,7 @@ import javax.swing.*;
  */\r
 public class WebserviceInfo extends GWebserviceInfo\r
 {\r
+\r
     /** Job is Queued */\r
     public static final int STATE_QUEUING = 0;\r
 \r
@@ -59,7 +61,43 @@ public class WebserviceInfo extends GWebserviceInfo
     jalview.ws.WSClientI thisService;\r
     boolean serviceIsCancellable;\r
     JInternalFrame frame;\r
-\r
+    JTabbedPane subjobs=null;\r
+    java.util.Vector jobPanes = null;\r
+    // tabbed or not\r
+    public synchronized int addJobPane() {\r
+      JScrollPane jobpane = new JScrollPane();\r
+      JTextArea progressText = new JTextArea();\r
+      progressText.setFont(new java.awt.Font("Verdana", 0, 10));\r
+      progressText.setBorder(null);\r
+      progressText.setEditable(false);\r
+      progressText.setText("WS Job");\r
+      progressText.setLineWrap(true);\r
+      progressText.setWrapStyleWord(true);\r
+      jobpane.setName("JobPane");\r
+      jobpane.getViewport().add(progressText, null);\r
+      jobpane.setBorder(null);\r
+      if (jobPanes==null) {\r
+        jobPanes = new Vector();\r
+      }\r
+      int newpane = jobPanes.size();\r
+      jobPanes.add(jobpane);\r
+\r
+      if (newpane==0) {\r
+        this.add(jobpane, BorderLayout.CENTER);\r
+      } else {\r
+        if (newpane==1) {\r
+        // revert to a tabbed pane.\r
+        JScrollPane firstpane;\r
+        this.remove(firstpane=(JScrollPane) jobPanes.get(0));\r
+        subjobs=new JTabbedPane();\r
+          this.add(subjobs, BorderLayout.CENTER);\r
+          subjobs.add(firstpane);\r
+          subjobs.setTitleAt(0, firstpane.getName());\r
+        }\r
+        subjobs.add(jobpane);\r
+      }\r
+      return newpane; // index for accessor methods below\r
+    }\r
     /**\r
      * Creates a new WebserviceInfo object.\r
      *\r
@@ -153,7 +191,38 @@ public class WebserviceInfo extends GWebserviceInfo
     {\r
         currentStatus = status;\r
     }\r
-\r
+    /**\r
+     * subjob status indicator\r
+     * @param jobpane\r
+     * @param status\r
+     */\r
+    public void setStatus(int jobpane, int status) {\r
+      if (jobpane<0 || jobpane>=jobPanes.size()) {\r
+        throw new Error("setStatus called for non-existent job pane."+jobpane);\r
+      }\r
+      switch (status) {\r
+      case STATE_QUEUING:\r
+        setProgressText(jobpane, "QUEUED");\r
+        break;\r
+      case STATE_RUNNING:\r
+        setProgressText(jobpane, "RUNNING");\r
+        break;\r
+      case STATE_STOPPED_OK:\r
+        setProgressText(jobpane, "FINISHED");\r
+      break;\r
+      case STATE_CANCELLED_OK:\r
+        setProgressText(jobpane, "CANCELLED");\r
+        break;\r
+      case STATE_STOPPED_ERROR:\r
+        setProgressText(jobpane, "BROKEN");\r
+        break;\r
+      case STATE_STOPPED_SERVERERROR:\r
+        setProgressText(jobpane, "ALERT");\r
+        break;\r
+        default:\r
+          setProgressText(jobpane, "UNKNOWN STATE");\r
+      }\r
+    }\r
     /**\r
      * DOCUMENT ME!\r
      *\r
@@ -183,25 +252,29 @@ public class WebserviceInfo extends GWebserviceInfo
     {\r
         infoText.append(text);\r
     }\r
-\r
     /**\r
      * DOCUMENT ME!\r
      *\r
      * @return DOCUMENT ME!\r
      */\r
-    public String getProgressText()\r
+    public String getProgressText(int which)\r
     {\r
-        return progressText.getText();\r
+      if (jobPanes == null)\r
+        addJobPane();\r
+      return ( (JTextArea) ( (JScrollPane) jobPanes.get(which)).getViewport().\r
+              getComponent(0)).getText();\r
     }\r
-\r
     /**\r
      * DOCUMENT ME!\r
      *\r
      * @param text DOCUMENT ME!\r
      */\r
-    public void setProgressText(String text)\r
+    public void setProgressText(int which, String text)\r
     {\r
-        progressText.setText(text);\r
+      if (jobPanes == null)\r
+        addJobPane();\r
+      ( (JTextArea) ( (JScrollPane) jobPanes.get(which)).getViewport().\r
+       getComponent(0)).setText(text);\r
     }\r
 \r
     /**\r
@@ -209,9 +282,57 @@ public class WebserviceInfo extends GWebserviceInfo
      *\r
      * @param text DOCUMENT ME!\r
      */\r
+    public void appendProgressText(int which, String text)\r
+    {\r
+      if (jobPanes == null)\r
+        addJobPane();\r
+      ( (JTextArea) ( (JScrollPane) jobPanes.get(which)).getViewport().\r
+       getComponent(0)).append(text);\r
+    }\r
+    /**\r
+     * setProgressText(0, text)\r
+     */\r
+    public void setProgressText(String text)\r
+    {\r
+      setProgressText(0, text);\r
+    }\r
+    /**\r
+     * appendProgressText(0, text)\r
+     */\r
     public void appendProgressText(String text)\r
     {\r
-        progressText.append(text);\r
+      appendProgressText(0, text);\r
+    }\r
+    /**\r
+     * getProgressText(0)\r
+     */\r
+    public String getProgressText()\r
+    {\r
+      return getProgressText(0);\r
+    }\r
+    /**\r
+     * get the tab title for a subjob\r
+     * @param which int\r
+     * @return String\r
+     */\r
+    public String getProgressName(int which) {\r
+      if (jobPanes==null)\r
+        addJobPane();\r
+      if (subjobs!=null)\r
+        return subjobs.getTitleAt(which);\r
+      else\r
+        return ((JScrollPane) jobPanes.get(which)).getViewport().getComponent(0).getName();\r
+    }\r
+    /**\r
+     * set the tab title for a subjob\r
+     * @param name String\r
+     * @param which int\r
+     */\r
+    public void setProgressName(String name, int which) {\r
+      if (subjobs!=null)\r
+        subjobs.setTitleAt(which, name);\r
+      else\r
+        ((JScrollPane) jobPanes.get(which)).getViewport().getComponent(0).setName(name);\r
     }\r
 \r
     /**\r
@@ -246,7 +367,7 @@ public class WebserviceInfo extends GWebserviceInfo
     }\r
 \r
 \r
-    class AnimatedPanel extends JPanel implements Runnable\r
+  class AnimatedPanel extends JPanel implements Runnable\r
     {\r
         long startTime = 0;\r
         BufferedImage offscreen;\r
index e5a163c..3dfb905 100755 (executable)
@@ -33,8 +33,6 @@ public class GWebserviceInfo extends JPanel
 {\r
     protected JTextArea infoText = new JTextArea();\r
     JScrollPane jScrollPane1 = new JScrollPane();\r
-    JScrollPane jScrollPane2 = new JScrollPane();\r
-    protected JTextArea progressText = new JTextArea();\r
     JPanel jPanel1 = new JPanel();\r
     BorderLayout borderLayout1 = new BorderLayout();\r
     BorderLayout borderLayout2 = new BorderLayout();\r
@@ -74,17 +72,10 @@ public class GWebserviceInfo extends JPanel
         infoText.setLineWrap(true);\r
         infoText.setWrapStyleWord(true);\r
         this.setLayout(borderLayout1);\r
-        progressText.setFont(new java.awt.Font("Verdana", 0, 10));\r
-        progressText.setBorder(null);\r
-        progressText.setEditable(false);\r
-        progressText.setText("");\r
-        progressText.setLineWrap(true);\r
-        progressText.setWrapStyleWord(true);\r
         jPanel1.setLayout(borderLayout2);\r
         titlePanel.setBackground(Color.white);\r
         titlePanel.setPreferredSize(new Dimension(0, 60));\r
         titlePanel.setLayout(borderLayout3);\r
-        jScrollPane2.setBorder(null);\r
         jScrollPane1.setBorder(null);\r
         jScrollPane1.setPreferredSize(new Dimension(400, 70));\r
         cancel.setFont(new java.awt.Font("Verdana", 0, 11));\r
@@ -100,11 +91,9 @@ public class GWebserviceInfo extends JPanel
     buttonPanel.setOpaque(false);\r
     showResultsNewFrame.setText("New Frame");\r
     mergeResults.setText("Merge Results");\r
-    this.add(jScrollPane2, BorderLayout.CENTER);\r
         this.add(jPanel1, BorderLayout.NORTH);\r
         jPanel1.add(jScrollPane1, BorderLayout.CENTER);\r
         jScrollPane1.getViewport().add(infoText, null);\r
-        jScrollPane2.getViewport().add(progressText, null);\r
         jPanel1.add(titlePanel, BorderLayout.NORTH);\r
         titlePanel.add(buttonPanel, BorderLayout.EAST);\r
     buttonPanel.add(cancel, new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0\r
index f30cced..bf08dcd 100755 (executable)
@@ -174,6 +174,13 @@ public class Discoverer
 ),
             new ServiceHandle(
                 "MsaWS",
+                "Katoh, K., K. Kuma, K., Toh, H.,  and Miyata, T. (2005) "+
+                "\"MAFFT version 5: improvement in accuracy of multiple sequence alignment.\""+
+               " Nucleic Acids Research, 33 511-518",
+                "http://www.compbio.dundee.ac.uk/JalviewWS/services/MafftWS",
+                "MAFFT Multiple Sequence Alignment"),
+            new ServiceHandle(
+                "MsaWS",
                 "Thompson, J.D., Higgins, D.G. and Gibson, T.J. (1994) CLUSTAL W: improving the sensitivity of progressive multiple" +
                 " sequence alignment through sequence weighting, position specific gap penalties and weight matrix choice." +
                 " Nucleic Acids Research, 22 4673-4680",
index 49c879b..eda71f5 100755 (executable)
@@ -37,7 +37,7 @@ import javax.swing.*;
  * @version $Revision$\r
  */\r
 public class MsaWSClient\r
-    extends WSClient\r
+    extends WSClient \r
 {\r
   /**\r
    * server is a WSDL2Java generated stub for an archetypal MsaWSI service.\r
@@ -63,7 +63,7 @@ public class MsaWSClient
                      Alignment seqdataset,\r
                      AlignFrame _alignFrame)\r
   {\r
-\r
+    super();\r
     alignFrame = _alignFrame;\r
     if (!sh.getAbstractName().equals("MsaWS"))\r
     {\r
@@ -76,7 +76,7 @@ public class MsaWSClient
       return;\r
     }\r
 \r
-    if ((wsInfo = this.setWebService(sh))==null)\r
+    if ((wsInfo = setWebService(sh))==null)\r
      {\r
        JOptionPane.showMessageDialog(Desktop.desktop,\r
                                      "The Multiple Sequence Alignment Service named " +\r
@@ -102,8 +102,10 @@ public class MsaWSClient
     wsInfo.setProgressText( ( (submitGaps) ? "Re-alignment" : "Alignment") +\r
                            " of " + altitle + "\nJob details\n");\r
 \r
-    MsaWSThread musclethread = new MsaWSThread(WebServiceName +\r
-                                               " alignment of " + altitle, msa,\r
+    MsaWSThread musclethread = new MsaWSThread(server, WsURL, wsInfo, alignFrame,\r
+                                               WebServiceName,\r
+                                               WebServiceName+" alignment of " + altitle,\r
+                                               msa,\r
                                                submitGaps, preserveOrder, seqdataset);\r
     wsInfo.setthisService(musclethread);\r
     musclethread.start();\r
@@ -150,393 +152,4 @@ public class MsaWSClient
   {\r
     return "Multiple Sequence Alignment";\r
   }\r
-\r
-  protected class MsaWSThread\r
-      extends Thread implements WSClientI\r
-  {\r
-    String ServiceName = WebServiceName;\r
-    String OutputHeader;\r
-    vamsas.objects.simple.MsaResult result = null;\r
-    vamsas.objects.simple.SequenceSet seqs = new vamsas.objects.simple.\r
-        SequenceSet();\r
-    Hashtable SeqNames = null;\r
-    boolean submitGaps = false; // pass sequences including gaps to alignment service\r
-    boolean preserveOrder = true; // and always store and recover sequence order\r
-    String jobId;\r
-    String alTitle; // name which will be used to form new alignment window.\r
-    int allowedServerExceptions = 3; // thread dies if too many exceptions.\r
-    boolean jobComplete = false;\r
-\r
-    Alignment dataset; // dataset to which the new alignment will be associated.\r
-\r
-    MsaWSThread(String title, AlignmentView _msa, boolean subgaps,\r
-                boolean presorder, Alignment seqset)\r
-    {\r
-      // jbpnote - transformation should be above here - this is per sequence set contig, not for many contigs.\r
-      alTitle = title;\r
-      submitGaps = subgaps;\r
-      preserveOrder = presorder;\r
-      dataset = seqset;\r
-      OutputHeader = wsInfo.getProgressText();\r
-      SeqNames = new Hashtable();\r
-      SeqCigar[] msa = _msa.getSequences();\r
-      vamsas.objects.simple.Sequence[] seqarray = new vamsas.objects.simple.\r
-          Sequence[msa.length];\r
-\r
-      for (int i = 0,n=0; i < msa.length; i++)\r
-      {\r
-        String newname = jalview.analysis.SeqsetUtils.unique_name(i);\r
-        SequenceI mseq = msa[i].getSeq('-');\r
-        // uniquify as we go\r
-        // TODO: JBPNote: this is a ubiquitous transformation - set of jalview seq objects to vamsas sequences with name preservation\r
-        SeqNames.put(newname,\r
-                     jalview.analysis.SeqsetUtils.SeqCharacterHash(mseq));\r
-        seqarray[i] = new vamsas.objects.simple.Sequence();\r
-        seqarray[i].setId(newname);\r
-        seqarray[i].setSeq( (submitGaps) ? mseq.getSequence()\r
-                           : AlignSeq.extractGaps(\r
-                               jalview.util.Comparison.GapChars,\r
-                               mseq.getSequence()));\r
-      }\r
-\r
-      this.seqs = new vamsas.objects.simple.SequenceSet();\r
-      this.seqs.setSeqs(seqarray);\r
-    }\r
-\r
-    public boolean isCancellable()\r
-    {\r
-      return true;\r
-    }\r
-\r
-    public void cancelJob()\r
-    {\r
-      if ( (jobId != null) && !jobId.equals("") && !jobComplete)\r
-      {\r
-        String cancelledMessage = "";\r
-\r
-        try\r
-        {\r
-          vamsas.objects.simple.WsJobId cancelledJob = server.cancel(jobId);\r
-\r
-          if (cancelledJob.getStatus() == 2)\r
-          {\r
-            // CANCELLED_JOB\r
-            cancelledMessage = "Job cancelled.";\r
-            wsInfo.setStatus(WebserviceInfo.STATE_CANCELLED_OK);\r
-            jobComplete = true;\r
-            jobsRunning--;\r
-            result = null;\r
-          }\r
-          else if (cancelledJob.getStatus() == 3)\r
-          {\r
-            // VALID UNSTOPPABLE JOB\r
-            cancelledMessage +=\r
-                "Server cannot cancel this job. just close the window.\n";\r
-          }\r
-\r
-          if (cancelledJob.getJobId() != null)\r
-          {\r
-            cancelledMessage += ("[" + cancelledJob.getJobId() +\r
-                                 "]");\r
-          }\r
-\r
-          cancelledMessage += "\n";\r
-        }\r
-        catch (Exception exc)\r
-        {\r
-          cancelledMessage +=\r
-              ("\nProblems cancelling the job : Exception received...\n" +\r
-               exc + "\n");\r
-          exc.printStackTrace();\r
-        }\r
-\r
-        wsInfo.setProgressText(OutputHeader + cancelledMessage + "\n");\r
-      }\r
-      else\r
-      {\r
-        if (!jobComplete)\r
-        {\r
-          wsInfo.setProgressText(OutputHeader +\r
-                                 "Server cannot cancel this job because it has not been submitted properly. just close the window.\n");\r
-        }\r
-      }\r
-    }\r
-\r
-    public void run()\r
-    {\r
-      StartJob();\r
-\r
-      while (!jobComplete && (allowedServerExceptions > 0))\r
-      {\r
-        try\r
-        {\r
-          if ( (result = server.getResult(jobId)) == null)\r
-          {\r
-            throw (new Exception(\r
-                "Timed out when communicating with server\nTry again later.\n"));\r
-          }\r
-          jalview.bin.Cache.log.debug("Result state " + result.getState() +\r
-                                        "(ServerError=" + result.isServerError() +\r
-                                        ")");\r
-          if (result.isRunning())\r
-          {\r
-            wsInfo.setStatus(WebserviceInfo.STATE_RUNNING);\r
-          }\r
-          else if (result.isQueued())\r
-          {\r
-            wsInfo.setStatus(WebserviceInfo.STATE_QUEUING);\r
-          }\r
-\r
-          if (result.isFinished())\r
-          {\r
-            wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_OK);\r
-            wsInfo.showResultsNewFrame.addActionListener(new java.awt.event.ActionListener()\r
-                {\r
-                  public void actionPerformed(java.awt.event.ActionEvent evt)\r
-                  {\r
-                    displayResults(true);\r
-                  }\r
-                });\r
-           wsInfo.mergeResults.addActionListener(new java.awt.event.ActionListener()\r
-                {\r
-                  public void actionPerformed(java.awt.event.ActionEvent evt)\r
-                  {\r
-                    displayResults(false);\r
-                  }\r
-                });\r
-           wsInfo.setResultsReady();\r
-            parseResult();\r
-            jobComplete = true;\r
-            jobsRunning--;\r
-          }\r
-          else\r
-          {\r
-            if (result.getStatus() != null)\r
-            {\r
-              wsInfo.setProgressText(OutputHeader + "\n"+   result.getStatus());\r
-            }\r
-            if (result.isServerError())\r
-            {\r
-              jobComplete = true;\r
-              jobsRunning--;\r
-\r
-              break;\r
-            }\r
-            if (! (result.isJobFailed() || result.isServerError() ||\r
-                   result.isBroken() || result.isFailed()))\r
-            {\r
-              Thread.sleep(5000);\r
-\r
-              //  System.out.println("I'm alive "+seqid+" "+jobid);\r
-            }\r
-            else\r
-            {\r
-              jobComplete = true;\r
-              jobsRunning--;\r
-              break;\r
-            }\r
-          }\r
-        }\r
-        catch (Exception ex)\r
-        {\r
-          allowedServerExceptions--;\r
-          wsInfo.appendProgressText("\n" + ServiceName +\r
-                                    " Server exception!\n" + ex.getMessage());\r
-          System.err.println(ServiceName + " Server exception: " +\r
-                             ex.getMessage());\r
-\r
-          //          ex.printStackTrace(); JBPNote Debug\r
-          try\r
-          {\r
-            if (allowedServerExceptions > 0)\r
-            {\r
-              Thread.sleep(5000);\r
-            }\r
-          }\r
-          catch (InterruptedException ex1)\r
-          {\r
-          }\r
-        }\r
-        catch(OutOfMemoryError er)\r
-        {\r
-          jobComplete = true;\r
-          wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_ERROR);\r
-          JOptionPane.showInternalMessageDialog(Desktop.desktop,\r
-              "Out of memory handling result!!"\r
-             +"\nSee help files for increasing Java Virtual Machine memory."\r
-             ,"Out of memory", JOptionPane.WARNING_MESSAGE );\r
-          System.out.println("MsaWSClient: "+er);\r
-          System.gc();\r
-        }\r
-      }\r
-\r
-      if (allowedServerExceptions == 0)\r
-      {\r
-        wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_SERVERERROR);\r
-      }\r
-      else\r
-      {\r
-        if (result != null)\r
-        {\r
-          if ( !(result.isJobFailed() || result.isServerError()))\r
-          {\r
-            wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_OK);\r
-          }\r
-\r
-          if (result.isBroken() || result.isFailed())\r
-          {\r
-            wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_ERROR);\r
-          }\r
-\r
-          if (result.isServerError())\r
-          {\r
-            wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_SERVERERROR);\r
-          }\r
-        }\r
-      }\r
-    }\r
-\r
-    void StartJob()\r
-    {\r
-      try\r
-      {\r
-        vamsas.objects.simple.WsJobId jobsubmit = server.align(seqs);\r
-\r
-        if ( (jobsubmit != null) && (jobsubmit.getStatus() == 1))\r
-        {\r
-          jobId = jobsubmit.getJobId();\r
-          System.out.println(WsURL + " Job Id '" + jobId + "'");\r
-        }\r
-        else\r
-        {\r
-          if (jobsubmit == null)\r
-          {\r
-            throw new Exception("Server at " + WsURL +\r
-                                " returned null object, it probably cannot be contacted. Try again later ?");\r
-          }\r
-\r
-          throw new Exception(jobsubmit.getJobId());\r
-        }\r
-      }\r
-      catch (Exception e)\r
-      {\r
-        // TODO: JBPNote catch timeout or other fault types explicitly\r
-        // For unexpected errors\r
-        System.err.println(WebServiceName +\r
-                           "Client: Failed to submit the sequences for alignment (probably a server side problem)\n" +\r
-                           "When contacting Server:" + WsURL + "\n" +\r
-                           e.toString() +\r
-                           "\n");\r
-        this.allowedServerExceptions = 0;\r
-        wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_SERVERERROR);\r
-        wsInfo.appendProgressText(\r
-            "Failed to submit sequences for alignment.\n" +\r
-            "It is most likely that there is a problem with the server.\n" +\r
-            "Just close the window\n");\r
-\r
-        // e.printStackTrace(); // TODO: JBPNote DEBUG\r
-      }\r
-    }\r
-\r
-    private jalview.datamodel.Sequence[] getVamsasAlignment(\r
-        vamsas.objects.simple.Alignment valign)\r
-    {\r
-      vamsas.objects.simple.Sequence[] seqs = valign.getSeqs().getSeqs();\r
-      jalview.datamodel.Sequence[] msa = new jalview.datamodel.Sequence[seqs.\r
-          length];\r
-\r
-      for (int i = 0, j = seqs.length; i < j; i++)\r
-      {\r
-        msa[i] = new jalview.datamodel.Sequence(seqs[i].getId(),\r
-                                                seqs[i].getSeq());\r
-      }\r
-\r
-      return msa;\r
-    }\r
-\r
-    void parseResult()\r
-    {\r
-\r
-      try\r
-      {\r
-        // OutputHeader = output.getText();\r
-        if (result.isFailed())\r
-        {\r
-          OutputHeader += "Job failed.\n";\r
-        }\r
-\r
-        if (result.getStatus() != null)\r
-        {\r
-          OutputHeader += ("\n" + result.getStatus());\r
-        }\r
-\r
-        if (result.getMsa() != null)\r
-        {\r
-          OutputHeader += "\nAlignment Object Method Notes\n";\r
-\r
-          String[] lines = result.getMsa().getMethod();\r
-\r
-          for (int line = 0; line < lines.length; line++)\r
-          {\r
-            OutputHeader += (lines[line] + "\n");\r
-          }\r
-\r
-          // JBPNote The returned files from a webservice could be\r
-          // hidden behind icons in the monitor window that,\r
-          // when clicked, pop up their corresponding data\r
-        }\r
-\r
-        wsInfo.setProgressText(OutputHeader);\r
-      }\r
-      catch (Exception ex)\r
-      {\r
-        ex.printStackTrace();\r
-      }\r
-    }\r
-\r
-    void displayResults(boolean newFrame)\r
-    {\r
-      SequenceI [] seqs = getVamsasAlignment(result.getMsa());\r
-\r
-      if (seqs != null)\r
-       {\r
-         AlignmentOrder msaorder = new AlignmentOrder(seqs);\r
-\r
-         if (preserveOrder)\r
-         {\r
-           jalview.analysis.AlignmentSorter.recoverOrder(seqs);\r
-         }\r
-\r
-         jalview.analysis.SeqsetUtils.deuniquify(SeqNames, seqs);\r
-\r
-         Alignment al = new Alignment(seqs);\r
-         if (dataset!=null)\r
-         {\r
-           al.setDataset(dataset);\r
-         }\r
-\r
-         if(newFrame)\r
-         {\r
-           // TODO: JBPNote Should also rename the query sequence sometime...\r
-           AlignFrame af = new AlignFrame(al);\r
-\r
-         //>>>This is a fix for the moment, until a better solution is found!!<<<\r
-           af.getFeatureRenderer().transferSettings(alignFrame.getFeatureRenderer());\r
-\r
-           af.addSortByOrderMenuItem(ServiceName + " Ordering",\r
-                                     msaorder);\r
-\r
-           Desktop.addInternalFrame(af, alTitle,\r
-                                    AlignFrame.NEW_WINDOW_WIDTH,\r
-                                    AlignFrame.NEW_WINDOW_HEIGHT);\r
-\r
-         }\r
-         else\r
-         {\r
-           System.out.println("MERGE WITH OLD FRAME");\r
-\r
-         }\r
-       }\r
-    }\r
-  }\r
 }\r
diff --git a/src/jalview/ws/MsaWSThread.java b/src/jalview/ws/MsaWSThread.java
new file mode 100644 (file)
index 0000000..b8912e2
--- /dev/null
@@ -0,0 +1,686 @@
+package jalview.ws;
+
+import jalview.datamodel.AlignmentView;
+import jalview.datamodel.AlignmentOrder;
+import jalview.datamodel.ColumnSelection;
+import jalview.gui.WebserviceInfo;
+import jalview.analysis.AlignSeq;
+import jalview.bin.Cache;
+import jalview.gui.AlignFrame;
+import javax.swing.JOptionPane;
+
+import vamsas.objects.simple.MsaResult;
+import vamsas.objects.simple.Result;
+import jalview.datamodel.Alignment;
+import jalview.datamodel.SeqCigar;
+import jalview.gui.Desktop;
+import jalview.datamodel.SequenceI;
+import java.util.Hashtable;
+import java.util.Vector;
+
+/**
+ * <p>
+ * Title:
+ * </p>
+ * 
+ * <p>
+ * Description:
+ * </p>
+ * 
+ * <p>
+ * Copyright: Copyright (c) 2004
+ * </p>
+ * 
+ * <p>
+ * Company: Dundee University
+ * </p>
+ * 
+ * @author not attributable
+ * @version 1.0
+ */
+class MsaWSThread extends Thread implements WSClientI {
+  jalview.gui.AlignFrame alignFrame;
+  
+  WebserviceInfo wsInfo = null;
+  
+  String WebServiceName = null;
+  
+  String OutputHeader;
+  AlignmentView input;
+  boolean submitGaps = false; // pass sequences including gaps to alignment
+  
+  // service
+  
+  boolean preserveOrder = true; // and always store and recover sequence
+  
+  // order
+  
+  class MsaWSJob {
+    int jobnum = 0; // WebServiceInfo pane for this job
+    
+    String jobId; // ws job ticket
+    
+    vamsas.objects.simple.MsaResult result = null;
+    
+    vamsas.objects.simple.SequenceSet seqs = new vamsas.objects.simple.SequenceSet();
+    
+    /**
+     * MsaWSJob
+     * 
+     * @param jobNum
+     *            int
+     * @param jobId
+     *            String
+     */
+    public MsaWSJob(int jobNum, SequenceI[] inSeqs) {
+      this.jobnum = jobNum;
+      prepareInput(inSeqs);
+    }
+    
+    int allowedServerExceptions = 3; // thread dies if too many
+    
+    // exceptions.
+    boolean submitted=false;
+    boolean subjobComplete = false;
+    
+    Hashtable SeqNames = new Hashtable();
+    Vector emptySeqs = new Vector();
+    private void prepareInput(SequenceI[] seqs) {
+      int nseqs = 0;
+      for (int i = 0; i < seqs.length; i++) {
+        if (seqs[i].getStart() < seqs[i].getEnd()) {
+          nseqs++;
+        }
+      }
+      vamsas.objects.simple.Sequence[] seqarray = 
+        (nseqs>0) 
+        ? new vamsas.objects.simple.Sequence[nseqs]
+                                             :null;
+        for (int i = 0, n = 0; i < seqs.length; i++) {
+          
+          String newname = jalview.analysis.SeqsetUtils.unique_name(i); // same
+          // for
+          // any
+          // subjob
+          SeqNames.put(newname, jalview.analysis.SeqsetUtils
+              .SeqCharacterHash(seqs[i]));
+          if (seqs[i].getStart() < seqs[i].getEnd()) {
+            seqarray[n] = new vamsas.objects.simple.Sequence();
+            seqarray[n].setId(newname);
+            seqarray[n++].setSeq((submitGaps) ? seqs[i].getSequence()
+                : AlignSeq.extractGaps(
+                    jalview.util.Comparison.GapChars, seqs[i]
+                                                           .getSequence()));
+          } else {
+            emptySeqs.add(newname);
+          }
+        }
+        this.seqs = new vamsas.objects.simple.SequenceSet();
+        this.seqs.setSeqs(seqarray);
+    }
+    public Object[] getAlignment() {
+      
+      if (result!=null) {
+        SequenceI[] alseqs=null;
+        char alseq_gapchar='-';
+        int alseq_l=0;
+        if (result.getMsa() != null) {
+          alseqs = getVamsasAlignment(result.getMsa());
+          alseq_gapchar=result.getMsa().getGapchar().charAt(0);
+          alseq_l = alseqs.length;
+        }
+        if (emptySeqs.size()>0) {
+          SequenceI[] t_alseqs = new SequenceI[alseq_l+emptySeqs.size()];
+          // get width
+          int i,w=0;
+          if (alseq_l>0) {
+            for (i=0,w=alseqs[0].getLength(); i<alseq_l; i++) {
+              if (w<alseqs[i].getLength())
+                w=alseqs[i].getLength();
+              t_alseqs[i] = alseqs[i];
+              alseqs[i] = null;
+            }
+          }
+          // make a gapped string.
+          StringBuffer insbuff=new StringBuffer(w);
+          for (i=0; i<w; i++)
+            insbuff.append(alseq_gapchar);
+          for (i=0, w=emptySeqs.size(); i<w; i++) {
+            t_alseqs[i+alseqs.length] = new jalview.datamodel.Sequence((String)emptySeqs.get(i), insbuff.toString());
+          }
+          alseqs = t_alseqs;
+        } 
+        AlignmentOrder msaorder = new AlignmentOrder(alseqs);
+        // always recover the order - makes parseResult()'s life easier.
+        jalview.analysis.AlignmentSorter.recoverOrder(alseqs);
+        // account for any missing sequences
+        jalview.analysis.SeqsetUtils.deuniquify(SeqNames, alseqs);
+        return new Object[] { alseqs, msaorder};
+      }
+      return null;
+    }
+  }
+  MsaWSJob jobs[] = null;
+  
+  String alTitle; // name which will be used to form new alignment window.
+  
+  boolean jobComplete = false;
+  
+  Alignment dataset; // dataset to which the new alignment will be
+  
+  // associated.
+  
+  ext.vamsas.MuscleWS server = null;
+  
+  String WsUrl = null;
+  
+  /**
+   * set basic options for this (group) of Msa jobs
+   * 
+   * @param subgaps
+   *            boolean
+   * @param presorder
+   *            boolean
+   */
+  MsaWSThread(ext.vamsas.MuscleWS server, String wsUrl,
+      WebserviceInfo wsinfo, jalview.gui.AlignFrame alFrame, AlignmentView alview,
+      String wsname, boolean subgaps, boolean presorder) {
+    this.server = server;
+    this.WsUrl = wsUrl;
+    this.wsInfo = wsinfo;
+    this.WebServiceName = wsname;
+    this.input = alview;
+    this.submitGaps = subgaps;
+    this.preserveOrder = presorder;
+    this.alignFrame = alFrame;
+  }
+  
+  /**
+   * create one or more Msa jobs to align visible seuqences in _msa
+   * 
+   * @param title
+   *            String
+   * @param _msa
+   *            AlignmentView
+   * @param subgaps
+   *            boolean
+   * @param presorder
+   *            boolean
+   * @param seqset
+   *            Alignment
+   */
+  MsaWSThread(ext.vamsas.MuscleWS server, String wsUrl,
+      WebserviceInfo wsinfo, jalview.gui.AlignFrame alFrame,
+      String wsname, String title, AlignmentView _msa, boolean subgaps,
+      boolean presorder, Alignment seqset) {
+    this(server, wsUrl, wsinfo, alFrame, _msa, wsname, subgaps, presorder);
+    OutputHeader = wsInfo.getProgressText();
+    alTitle = title;
+    dataset = seqset;
+    SeqCigar[] msa = _msa.getSequences();
+    int[] contigs = _msa.getContigs();
+    int njobs=1;
+    if (contigs != null && contigs.length > 0) {
+      int start = 0;
+      njobs=0;
+      int width = _msa.getWidth();
+      for (int contig = 0; contig < contigs.length; contig += 3) {
+        if ((contigs[contig+1] - start) > 0) {
+          njobs++;
+        }
+        width+=contigs[contig+2];// end up with full region width (including hidden regions)
+        start = contigs[contig+1] + contigs[contig + 2];
+      }
+      if (start<width) {
+        njobs++;
+      }
+      jobs = new MsaWSJob[njobs];
+      start=0;
+      int j=0;
+      for (int contig = 0; contig < contigs.length; contig += 3) {
+        if (contigs[contig+1] - start > 0) {
+          SequenceI mseq[] = new SequenceI[msa.length];
+          for (int s = 0; s < mseq.length; s++) {
+            mseq[s] = msa[s].getSeq('-').getSubSequence(start,
+                contigs[contig+1]);
+          }
+          if (j!=0) {
+            jobs[j] = new MsaWSJob(wsinfo.addJobPane(), mseq);
+          } else {
+            jobs[j] = new MsaWSJob(0, mseq);
+          }
+          wsinfo.setProgressName("region "+jobs[j].jobnum,jobs[j].jobnum);
+          wsinfo.setProgressText(jobs[j].jobnum, OutputHeader);
+          j++;
+        }
+        start = contigs[contig+1] + contigs[contig + 2];
+      }
+      if (start<width) {
+        SequenceI mseq[] = new SequenceI[msa.length];
+        for (int s = 0; s < mseq.length; s++) {
+          mseq[s] = msa[s].getSeq('-').getSubSequence(start,
+              width+1);
+        }
+        if (j!=0) {
+          jobs[j] = new MsaWSJob(wsinfo.addJobPane(), mseq);
+        } else {
+          jobs[j] = new MsaWSJob(0, mseq);
+        }
+        wsinfo.setProgressName("region "+jobs[j].jobnum,jobs[j].jobnum);
+        wsinfo.setProgressText(jobs[j].jobnum, OutputHeader);
+        j++;        
+      }
+    } else {
+      SequenceI mseq[] = new SequenceI[msa.length];
+      for (int s = 0; s < mseq.length; s++) {
+        mseq[s] = msa[s].getSeq('-');
+      }
+      jobs = new MsaWSJob[1];
+      wsinfo.setProgressText(OutputHeader); // ensures default text
+      jobs[0] = new MsaWSJob(0, mseq);
+    }
+  }
+  
+  public boolean isCancellable() {
+    return true;
+  }
+  
+  public void cancelJob() {
+    if (!jobComplete && jobs != null) {
+      boolean cancelled = true;
+      for (int job = 0; job < jobs.length; job++) {
+        if (jobs[job].submitted && !jobs[job].subjobComplete)
+        { 
+          String cancelledMessage = "";
+          try {
+            vamsas.objects.simple.WsJobId cancelledJob = server
+            .cancel(jobs[job].jobId);
+            if (cancelledJob.getStatus() == 2) {
+              // CANCELLED_JOB
+              cancelledMessage = "Job cancelled.";
+              jobs[job].subjobComplete = true;
+              jobs[job].result = null;
+              wsInfo.setStatus(jobs[job].jobnum, WebserviceInfo.STATE_CANCELLED_OK);
+            } else if (cancelledJob.getStatus() == 3) {
+              // VALID UNSTOPPABLE JOB
+              cancelledMessage += "Server cannot cancel this job. just close the window.\n";
+              cancelled = false;
+              wsInfo.setStatus(jobs[job].jobnum, WebserviceInfo.STATE_CANCELLED_OK);
+            }
+            
+            if (cancelledJob.getJobId() != null) {
+              cancelledMessage += ("[" + cancelledJob.getJobId() + "]");
+            }
+            
+            cancelledMessage += "\n";
+          } catch (Exception exc) {
+            cancelledMessage += ("\nProblems cancelling the job : Exception received...\n"
+                + exc + "\n");
+            exc.printStackTrace();
+          }
+          wsInfo.setProgressText(jobs[job].jobnum, OutputHeader
+              + cancelledMessage + "\n");
+        }
+      }
+      if (cancelled) {
+        wsInfo.setStatus(WebserviceInfo.STATE_CANCELLED_OK);
+        jobComplete = true;
+      }
+    } else {
+      if (!jobComplete) {
+        wsInfo
+        .setProgressText(OutputHeader
+            + "Server cannot cancel this job because it has not been submitted properly. just close the window.\n");
+      }
+    }
+  }
+  
+  public void run() {
+    
+    while (!jobComplete) {
+      int running=0;
+      int queuing=0;
+      int finished=0;
+      int error=0;
+      int serror=0;
+      for (int j=0; j<jobs.length; j++) {
+        
+        if (!jobs[j].submitted && jobs[j].seqs.getSeqs()!=null)
+          StartJob(jobs[j]);          
+        
+        if (jobs[j].submitted && !jobs[j].subjobComplete) {
+          try {
+            if ((jobs[j].result = server.getResult(jobs[j].jobId)) == null) {
+              throw (new Exception(
+              "Timed out when communicating with server\nTry again later.\n"));
+            }
+            jalview.bin.Cache.log.debug("Job "+j+" Result state " + jobs[j].result.getState()
+                + "(ServerError=" + jobs[j].result.isServerError() + ")");
+          } catch (Exception ex) {
+            // Deal with Transaction exceptions
+            wsInfo.appendProgressText(jobs[j].jobnum, "\n" + WebServiceName
+                + " Server exception!\n" + ex.getMessage());
+            Cache.log.warn(WebServiceName + " job(" + jobs[j].jobnum
+                + ") Server exception: " + ex.getMessage());
+            
+            if (jobs[j].allowedServerExceptions > 0) {
+              jobs[j].allowedServerExceptions--;
+              Cache.log.debug("Sleeping after a server exception.");
+              try {
+                Thread.sleep(5000);
+              }
+              catch (InterruptedException ex1) {
+              }
+            } else {
+              Cache.log.warn("Dropping job "+j+" "+jobs[j].jobId);
+              jobs[j].subjobComplete=true;
+              wsInfo.setStatus(jobs[j].jobnum, WebserviceInfo.STATE_STOPPED_SERVERERROR);
+            }
+          }
+          catch (OutOfMemoryError er) {   
+            jobComplete = true;
+            jobs[j].subjobComplete=true;
+            jobs[j].result=null; // may contain out of date result object
+            wsInfo.setStatus(jobs[j].jobnum,
+                WebserviceInfo.STATE_STOPPED_ERROR);
+            JOptionPane
+            .showInternalMessageDialog(
+                Desktop.desktop,
+                "Out of memory handling result for job !!"
+                + "\nSee help files for increasing Java Virtual Machine memory.",
+                "Out of memory", JOptionPane.WARNING_MESSAGE);
+            Cache.log.error("Out of memory when retrieving Job "+j+" id:" + WsUrl+"/"+jobs[j].jobId, er);
+            System.gc();
+          }
+        }
+        if (jobs[j].result!=null) {
+          String progheader="";
+          // Parse state of job[j]
+          if (jobs[j].result.isRunning()) {
+            running++;
+            wsInfo.setStatus(jobs[j].jobnum,WebserviceInfo.STATE_RUNNING);
+          } else if (jobs[j].result.isQueued()) {
+            queuing++;
+            wsInfo.setStatus(jobs[j].jobnum,WebserviceInfo.STATE_QUEUING);
+          } else if (jobs[j].result.isFinished()) {
+            finished++;
+            jobs[j].subjobComplete = true;
+            wsInfo.setStatus(jobs[j].jobnum,WebserviceInfo.STATE_STOPPED_OK);
+          } else if (jobs[j].result.isFailed()) {
+            progheader += "Job failed.\n";
+            jobs[j].subjobComplete=true;
+            wsInfo.setStatus(jobs[j].jobnum,WebserviceInfo.STATE_STOPPED_ERROR);
+            error++;
+          } else if (jobs[j].result.isServerError()) {
+            serror++;
+            jobs[j].subjobComplete = true;
+            wsInfo.setStatus(jobs[j].jobnum,WebserviceInfo.STATE_STOPPED_SERVERERROR);
+          } else if (jobs[j].result.isBroken() || jobs[j].result.isFailed()) {
+            error++;
+            jobs[j].subjobComplete=true;
+            wsInfo.setStatus(jobs[j].jobnum,WebserviceInfo.STATE_STOPPED_ERROR);
+          }
+          // and pass on any sub-job messages to the user
+          wsInfo.setProgressText(jobs[j].jobnum, OutputHeader);
+          wsInfo.appendProgressText(jobs[j].jobnum, progheader);
+          if (jobs[j].result.getStatus() != null) {
+            wsInfo.appendProgressText(jobs[j].jobnum, jobs[j].result.getStatus());
+          }
+        } else {
+          if (jobs[j].submitted && jobs[j].subjobComplete) {
+            if (jobs[j].allowedServerExceptions==0) {
+              serror++;
+            } else if (jobs[j].result==null) {
+              error++;
+            } 
+          }
+        }
+      }
+      // Decide on overall state based on collected jobs[] states
+      if (running>0) {
+        wsInfo.setStatus(WebserviceInfo.STATE_RUNNING);
+      } else if (queuing>0) {
+        wsInfo.setStatus(WebserviceInfo.STATE_QUEUING);
+      } else {
+        jobComplete=true;
+        if (finished>0) {
+          wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_OK);
+        } else if (error>0) {
+          wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_ERROR);          
+        } else if (serror>0) {
+          wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_SERVERERROR);
+        }
+      }
+      if (!jobComplete) {
+        try {
+          Thread.sleep(5000);
+        }
+        catch (InterruptedException e) {
+          Cache.log.debug("Interrupted sleep waiting for next job poll.",e);
+        }
+        // System.out.println("I'm alive "+alTitle);
+      }
+    }
+    if (jobComplete) {
+      parseResult(); // tidy up and make results available to user
+    }
+  }
+  
+  void StartJob(MsaWSJob j) {
+    if (j.submitted) {
+      if (Cache.log.isDebugEnabled()) {
+        Cache.log.debug("Tried to submit an already submitted job "+j.jobId);
+      }
+      return;
+    }
+    if (j.seqs.getSeqs()==null) {
+      // special case - selection consisted entirely of empty sequences...
+      j.submitted=true;
+      j.result=new MsaResult();
+      j.result.setFinished(true);
+      j.result.setStatus("Empty Alignment Job");
+      j.result.setMsa(null);
+    }
+    try {
+      vamsas.objects.simple.WsJobId jobsubmit = server.align(j.seqs);
+      
+      if ((jobsubmit != null) && (jobsubmit.getStatus() == 1)) {
+        j.jobId = jobsubmit.getJobId();
+        j.submitted=true;
+        j.subjobComplete = false;
+        // System.out.println(WsURL + " Job Id '" + jobId + "'");
+      } else {
+        if (jobsubmit == null) {
+          throw new Exception(
+              "Server at "
+              + WsUrl
+              + " returned null object, it probably cannot be contacted. Try again later ?");
+        }
+        
+        throw new Exception(jobsubmit.getJobId());
+      }
+    } catch (Exception e) {
+      // TODO: JBPNote catch timeout or other fault types explicitly
+      // For unexpected errors
+      System.err
+      .println(WebServiceName
+          + "Client: Failed to submit the sequences for alignment (probably a server side problem)\n"
+          + "When contacting Server:" + WsUrl + "\n"
+          + e.toString() + "\n");
+      j.allowedServerExceptions = 0;
+      wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_SERVERERROR);
+      wsInfo.setStatus(j.jobnum, WebserviceInfo.STATE_STOPPED_SERVERERROR);
+      wsInfo
+      .appendProgressText(
+          j.jobnum,
+          "Failed to submit sequences for alignment.\n"
+          + "It is most likely that there is a problem with the server.\n"
+          + "Just close the window\n");
+      
+      // e.printStackTrace(); // TODO: JBPNote DEBUG
+    }
+  }
+  
+  private jalview.datamodel.Sequence[] getVamsasAlignment(
+      vamsas.objects.simple.Alignment valign) {
+    vamsas.objects.simple.Sequence[] seqs = valign.getSeqs().getSeqs();
+    jalview.datamodel.Sequence[] msa = new jalview.datamodel.Sequence[seqs.length];
+    
+    for (int i = 0, j = seqs.length; i < j; i++) {
+      msa[i] = new jalview.datamodel.Sequence(seqs[i].getId(), seqs[i]
+                                                                    .getSeq());
+    }
+    
+    return msa;
+  }
+  
+  void parseResult() {
+    try {
+      for (int j=0; j<jobs.length; j++) {
+        if (jobs[j].submitted && jobs[j].subjobComplete) {
+          if (jobs[j].result!=null) {
+            vamsas.objects.simple.Alignment valign = jobs[j].result.getMsa();
+            if (valign!= null) {
+              wsInfo.appendProgressText(jobs[j].jobnum,"\nAlignment Object Method Notes\n");
+              String[] lines = valign.getMethod();
+              for (int line = 0; line < lines.length; line++) {
+                wsInfo.appendProgressText(jobs[j].jobnum, lines[line] + "\n");
+              }
+              // JBPNote The returned files from a webservice could be
+              //  hidden behind icons in the monitor window that,
+              // when clicked, pop up their corresponding data
+            }
+          }
+        }
+      }
+    }
+    catch (Exception ex) {
+      
+      Cache.log.error("Unexpected exception when processing results for "+alTitle,ex);
+      wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_ERROR);
+    }
+    
+    wsInfo.showResultsNewFrame
+    .addActionListener(new java.awt.event.ActionListener() {
+      public void actionPerformed(
+          java.awt.event.ActionEvent evt) {
+        displayResults(true);
+      }
+    });
+    wsInfo.mergeResults
+    .addActionListener(new java.awt.event.ActionListener() {
+      public void actionPerformed(
+          java.awt.event.ActionEvent evt) {
+        displayResults(false);
+      }
+    });
+    wsInfo.setResultsReady();
+  }
+  void displayResults(boolean newFrame) {
+    int contigs[] = input.getContigs();
+    SeqCigar[] seqs = input.getSequences();
+    SequenceI[] alignment = new SequenceI[seqs.length];
+    ColumnSelection columnselection = new ColumnSelection();
+    Vector alorders=new Vector();
+    if (contigs != null && contigs.length > 0) {
+      int cshift=0;
+      int start = 0;
+      int nwidth = 0;
+      int j=0;
+      for (int contig = 0; contig < contigs.length; contig += 3) {
+        if (cshift+contigs[contig] - start > 0) {
+          Object[] subalg =  jobs[j++].getAlignment();
+          alorders.add(subalg[1]);
+          SequenceI mseq[] = (SequenceI[]) subalg[0];
+          int width = mseq[0].getLength();
+          for (int s = 0; s < mseq.length; s++) {
+            if (alignment[s]==null) {
+              alignment[s] = mseq[s];
+            } else {
+              alignment[s].setSequence(alignment[s].getSequence()+mseq[s].getSequence());
+              if (alignment[s].getEnd()<mseq[s].getEnd())
+                alignment[s].setEnd(mseq[s].getEnd());
+              ((AlignmentOrder) subalg[1]).updateSequence(mseq[s], alignment[s]);
+            }
+          }
+          nwidth+=width;
+        }
+        // advance to begining of visible region
+        start = cshift+contigs[contig] + contigs[contig + 2];
+        // add hidden segment to right of next region
+        for (int s=0; s<seqs.length; s++) {
+          SequenceI hseq = seqs[s].getSeq('-').getSubSequence(cshift+contigs[contig], start);
+          if (alignment[s]==null) {
+            alignment[s] = hseq;
+          } else {
+            alignment[s].setSequence(alignment[s].getSequence()+hseq.getSequence());
+            alignment[s].setEnd(hseq.getEnd());
+          }
+        }
+        // mark hidden segment as hidden in the new alignment
+        columnselection.hideColumns(nwidth, nwidth+contigs[contig+2]-1);
+        nwidth+=contigs[contig+2];
+        cshift+=contigs[contig+2];
+      }
+      // Do final job - if it exists
+      if (j<jobs.length) {
+        Object[] subalg =  jobs[j].getAlignment();
+        alorders.add(subalg[1]);
+        SequenceI mseq[] = (SequenceI[]) subalg[0];
+        int width = mseq[0].getLength();
+        for (int s = 0; s < mseq.length; s++) {
+          if (alignment[s]==null) {
+            alignment[s] = mseq[s];
+          } else {
+            alignment[s].setSequence(alignment[s].getSequence()+mseq[s].getSequence());
+            alignment[s].setEnd(mseq[s].getEnd());
+            ((AlignmentOrder) subalg[1]).updateSequence(mseq[s], alignment[s]);
+          }
+        }
+        nwidth+=width;  
+      }
+    } else {
+      if (jobs[0].subjobComplete && jobs[0].result!=null) {
+        Object[] alg = jobs[0].getAlignment();
+        alignment = (SequenceI[]) alg[0];
+        alorders.add(alg[1]);
+      } else {
+        alignment = SeqCigar.createAlignmentSequences(seqs, '-', columnselection,null);
+      }
+    }
+    Alignment al = new Alignment(alignment);
+    if (dataset != null) {
+      al.setDataset(dataset);
+    }
+    
+    if (newFrame) {
+      // TODO: JBPNote Should also rename the query sequence
+      // sometime...
+      AlignFrame af = new AlignFrame(al,columnselection);
+      
+      // >>>This is a fix for the moment, until a better solution is
+      // found!!<<<
+      af.getFeatureRenderer().transferSettings(
+          alignFrame.getFeatureRenderer());
+      if (alorders.size()>0) {
+        if (alorders.size()==1) {
+          af.addSortByOrderMenuItem(WebServiceName + " Ordering",
+              (AlignmentOrder) alorders.get(0));
+        } else {
+          for (int i=0,l=alorders.size(); i<l; i++) {
+            af.addSortByOrderMenuItem(WebServiceName + " Region "+i+" Ordering",
+                (AlignmentOrder) alorders.get(i));              
+          }
+        }
+      }
+      
+      Desktop.addInternalFrame(af, alTitle,
+          AlignFrame.NEW_WINDOW_WIDTH,
+          AlignFrame.NEW_WINDOW_HEIGHT);
+      
+    } else {
+      System.out.println("MERGE WITH OLD FRAME");
+      
+    }
+  }
+}