refactored to create generic polling thread and subjobs
[jalview.git] / src / jalview / ws / MsaWSThread.java
1 package jalview.ws;
2
3 import java.util.*;
4
5 import javax.swing.*;
6
7 import jalview.analysis.*;
8 import jalview.bin.*;
9 import jalview.datamodel.*;
10 import jalview.datamodel.Alignment;
11 import jalview.gui.*;
12 import vamsas.objects.simple.MsaResult;
13
14 /**
15  * <p>
16  * Title:
17  * </p>
18  *
19  * <p>
20  * Description:
21  * </p>
22  *
23  * <p>
24  * Copyright: Copyright (c) 2004
25  * </p>
26  *
27  * <p>
28  * Company: Dundee University
29  * </p>
30  *
31  * @author not attributable
32  * @version 1.0
33  */
34 class MsaWSThread
35     extends WSThread implements WSClientI
36 {
37   boolean submitGaps = false; // pass sequences including gaps to alignment
38
39   // service
40
41   boolean preserveOrder = true; // and always store and recover sequence
42
43   // order
44
45   class MsaWSJob extends WSThread.WSJob
46   {
47     // hold special input for this
48     vamsas.objects.simple.SequenceSet seqs = new vamsas.objects.simple.
49         SequenceSet();
50
51     /**
52      * MsaWSJob
53      *
54      * @param jobNum
55      *            int
56      * @param jobId
57      *            String
58      */
59     public MsaWSJob(int jobNum, SequenceI[] inSeqs)
60     {
61       this.jobnum = jobNum;
62       if (!prepareInput(inSeqs, 2))
63       {
64         submitted = true;
65         subjobComplete = true;
66         result = new MsaResult();
67         result.setFinished(true);
68         result.setStatus("Job never ran - input returned to user.");
69       }
70
71     }
72
73     Hashtable SeqNames = new Hashtable();
74     Vector emptySeqs = new Vector();
75     /**
76      * prepare input sequences for MsaWS service
77      * @param seqs jalview sequences to be prepared
78      * @param minlen minimum number of residues required for this MsaWS service
79      * @return true if seqs contains sequences to be submitted to service.
80      */
81     private boolean prepareInput(SequenceI[] seqs, int minlen)
82     {
83       int nseqs = 0;
84       if (minlen < 0)
85       {
86         throw new Error("Implementation error: minlen must be zero or more.");
87       }
88       for (int i = 0; i < seqs.length; i++)
89       {
90         if (seqs[i].getEnd() - seqs[i].getStart() > minlen - 1)
91         {
92           nseqs++;
93         }
94       }
95       boolean valid = nseqs > 1; // need at least two seqs
96       vamsas.objects.simple.Sequence[] seqarray =
97           (valid)
98           ? new vamsas.objects.simple.Sequence[nseqs]
99           : null;
100       for (int i = 0, n = 0; i < seqs.length; i++)
101       {
102
103         String newname = jalview.analysis.SeqsetUtils.unique_name(i); // same
104         // for
105         // any
106         // subjob
107         SeqNames.put(newname, jalview.analysis.SeqsetUtils
108                      .SeqCharacterHash(seqs[i]));
109         if (valid && seqs[i].getEnd() - seqs[i].getStart() > minlen - 1)
110         {
111           seqarray[n] = new vamsas.objects.simple.Sequence();
112           seqarray[n].setId(newname);
113           seqarray[n++].setSeq( (submitGaps) ? seqs[i].getSequence()
114                                : AlignSeq.extractGaps(
115                                    jalview.util.Comparison.GapChars, seqs[i]
116                                    .getSequence()));
117         }
118         else
119         {
120           String empty = null;
121           if (seqs[i].getEnd() >= seqs[i].getStart())
122           {
123             empty = (submitGaps) ? seqs[i].getSequence()
124                 : AlignSeq.extractGaps(
125                     jalview.util.Comparison.GapChars, seqs[i]
126                     .getSequence());
127           }
128           emptySeqs.add(new String[]
129                         {newname, empty});
130         }
131       }
132       this.seqs = new vamsas.objects.simple.SequenceSet();
133       this.seqs.setSeqs(seqarray);
134       return valid;
135     }
136
137     /**
138      *
139      * @return true if getAlignment will return a valid alignment result.
140      */
141     public boolean hasResults()
142     {
143       if (subjobComplete && result != null && result.isFinished()
144           && ((MsaResult) result).getMsa() != null && ((MsaResult) result).getMsa().getSeqs() != null)
145       {
146         return true;
147       }
148       return false;
149     }
150
151     public Object[] getAlignment()
152     {
153
154       if (result != null && result.isFinished())
155       {
156         SequenceI[] alseqs = null;
157         char alseq_gapchar = '-';
158         int alseq_l = 0;
159         if (((MsaResult) result).getMsa() != null)
160         {
161           alseqs = getVamsasAlignment(((MsaResult) result).getMsa());
162           alseq_gapchar = ((MsaResult) result).getMsa().getGapchar().charAt(0);
163           alseq_l = alseqs.length;
164         }
165         if (emptySeqs.size() > 0)
166         {
167           SequenceI[] t_alseqs = new SequenceI[alseq_l + emptySeqs.size()];
168           // get width
169           int i, w = 0;
170           if (alseq_l > 0)
171           {
172             for (i = 0, w = alseqs[0].getLength(); i < alseq_l; i++)
173             {
174               if (w < alseqs[i].getLength())
175               {
176                 w = alseqs[i].getLength();
177               }
178               t_alseqs[i] = alseqs[i];
179               alseqs[i] = null;
180             }
181           }
182           // check that aligned width is at least as wide as emptySeqs width.
183           int ow = w, nw = w;
184           for (i = 0, w = emptySeqs.size(); i < w; i++)
185           {
186             String[] es = (String[]) emptySeqs.get(i);
187             if (es != null && es[1] != null)
188             {
189               int sw = es[1].length();
190               if (nw < sw)
191               {
192                 nw = sw;
193               }
194             }
195           }
196           // make a gapped string.
197           StringBuffer insbuff = new StringBuffer(w);
198           for (i = 0; i < nw; i++)
199           {
200             insbuff.append(alseq_gapchar);
201           }
202           if (ow < nw)
203           {
204             for (i = 0; i < alseq_l; i++)
205             {
206               int sw = t_alseqs[i].getLength();
207               if (nw > sw)
208               {
209                 // pad at end
210                 alseqs[i].setSequence(t_alseqs[i].getSequence() +
211                                       insbuff.substring(0, sw - nw));
212               }
213             }
214           }
215           for (i = 0, w = emptySeqs.size(); i < w; i++)
216           {
217             String[] es = (String[]) emptySeqs.get(i);
218             if (es[1] == null)
219             {
220               t_alseqs[i +
221                   alseq_l] = new jalview.datamodel.Sequence(es[0],
222                   insbuff.toString(), 1, 0);
223             }
224             else
225             {
226               if (es[1].length() < nw)
227               {
228                 t_alseqs[i +
229                     alseq_l] = new jalview.datamodel.Sequence(es[0],
230                     es[1] + insbuff.substring(0, nw - es[1].length()), 1,
231                     1 + es[1].length());
232               }
233               else
234               {
235                 t_alseqs[i +
236                     alseq_l] = new jalview.datamodel.Sequence(es[0], es[1]);
237               }
238             }
239           }
240           alseqs = t_alseqs;
241         }
242         AlignmentOrder msaorder = new AlignmentOrder(alseqs);
243         // always recover the order - makes parseResult()'s life easier.
244         jalview.analysis.AlignmentSorter.recoverOrder(alseqs);
245         // account for any missing sequences
246         jalview.analysis.SeqsetUtils.deuniquify(SeqNames, alseqs);
247         return new Object[]
248             {
249             alseqs, msaorder};
250       }
251       return null;
252     }
253     /**
254      * mark subjob as cancelled and set result object appropriatly
255      */
256     void cancel() {
257       cancelled=true;
258       subjobComplete = true;
259       result = null;
260     }
261     /**
262      *
263      * @return boolean true if job can be submitted.
264      */
265     boolean hasValidInput() {
266       if (seqs.getSeqs()!=null)
267         return true;
268       return false;
269     }
270   }
271
272
273   String alTitle; // name which will be used to form new alignment window.
274   Alignment dataset; // dataset to which the new alignment will be
275
276   // associated.
277
278   ext.vamsas.MuscleWS server = null;
279   /**
280    * set basic options for this (group) of Msa jobs
281    *
282    * @param subgaps
283    *            boolean
284    * @param presorder
285    *            boolean
286    */
287   MsaWSThread(ext.vamsas.MuscleWS server, String wsUrl,
288               WebserviceInfo wsinfo, jalview.gui.AlignFrame alFrame,
289               AlignmentView alview,
290               String wsname, boolean subgaps, boolean presorder)
291   {
292     this.server = server;
293     this.WsUrl = wsUrl;
294     this.wsInfo = wsinfo;
295     this.WebServiceName = wsname;
296     this.input = alview;
297     this.submitGaps = subgaps;
298     this.preserveOrder = presorder;
299     this.alignFrame = alFrame;
300   }
301
302   /**
303    * create one or more Msa jobs to align visible seuqences in _msa
304    *
305    * @param title
306    *            String
307    * @param _msa
308    *            AlignmentView
309    * @param subgaps
310    *            boolean
311    * @param presorder
312    *            boolean
313    * @param seqset
314    *            Alignment
315    */
316   MsaWSThread(ext.vamsas.MuscleWS server, String wsUrl,
317               WebserviceInfo wsinfo, jalview.gui.AlignFrame alFrame,
318               String wsname, String title, AlignmentView _msa, boolean subgaps,
319               boolean presorder, Alignment seqset)
320   {
321     this(server, wsUrl, wsinfo, alFrame, _msa, wsname, subgaps, presorder);
322     OutputHeader = wsInfo.getProgressText();
323     alTitle = title;
324     dataset = seqset;
325     SeqCigar[] msa = _msa.getSequences();
326     int[] contigs = _msa.getContigs();
327     int njobs = 1;
328     if (contigs != null && contigs.length > 0)
329     {
330       int start = 0;
331       njobs = 0;
332       int width = _msa.getWidth();
333       for (int contig = 0; contig < contigs.length; contig += 3)
334       {
335         if ( (contigs[contig + 1] - start) > 0)
336         {
337           njobs++;
338         }
339         width += contigs[contig + 2]; // end up with full region width (including hidden regions)
340         start = contigs[contig + 1] + contigs[contig + 2];
341       }
342       if (start < width)
343       {
344         njobs++;
345       }
346       jobs = new MsaWSJob[njobs];
347       start = 0;
348       int j = 0;
349       for (int contig = 0; contig < contigs.length; contig += 3)
350       {
351         if (contigs[contig + 1] - start > 0)
352         {
353           SequenceI mseq[] = new SequenceI[msa.length];
354           for (int s = 0; s < mseq.length; s++)
355           {
356             mseq[s] = msa[s].getSeq('-').getSubSequence(start,
357                 contigs[contig + 1]);
358           }
359           if (j != 0)
360           {
361             jobs[j] = new MsaWSJob(wsinfo.addJobPane(), mseq);
362           }
363           else
364           {
365             jobs[j] = new MsaWSJob(0, mseq);
366           }
367           wsinfo.setProgressName("region " + jobs[j].jobnum, jobs[j].jobnum);
368           wsinfo.setProgressText(jobs[j].jobnum, OutputHeader);
369           j++;
370         }
371         start = contigs[contig + 1] + contigs[contig + 2];
372       }
373       if (start < width)
374       {
375         SequenceI mseq[] = new SequenceI[msa.length];
376         for (int s = 0; s < mseq.length; s++)
377         {
378           mseq[s] = msa[s].getSeq('-').getSubSequence(start,
379               width + 1);
380         }
381         if (j != 0)
382         {
383           jobs[j] = new MsaWSJob(wsinfo.addJobPane(), mseq);
384         }
385         else
386         {
387           jobs[j] = new MsaWSJob(0, mseq);
388         }
389         wsinfo.setProgressName("region " + jobs[j].jobnum, jobs[j].jobnum);
390         wsinfo.setProgressText(jobs[j].jobnum, OutputHeader);
391         j++;
392       }
393     }
394     else
395     {
396       SequenceI mseq[] = new SequenceI[msa.length];
397       for (int s = 0; s < mseq.length; s++)
398       {
399         mseq[s] = msa[s].getSeq('-');
400       }
401       jobs = new MsaWSJob[1];
402       wsinfo.setProgressText(OutputHeader); // ensures default text
403       jobs[0] = new MsaWSJob(0, mseq);
404     }
405   }
406
407   public boolean isCancellable()
408   {
409     return true;
410   }
411
412   public void cancelJob()
413   {
414     if (!jobComplete && jobs != null)
415     {
416       boolean cancelled = true;
417       for (int job = 0; job < jobs.length; job++)
418       {
419         if (jobs[job].submitted && !jobs[job].subjobComplete)
420         {
421           String cancelledMessage = "";
422           try
423           {
424             vamsas.objects.simple.WsJobId cancelledJob = server
425                 .cancel(jobs[job].jobId);
426             if (cancelledJob.getStatus() == 2)
427             {
428               // CANCELLED_JOB
429               cancelledMessage = "Job cancelled.";
430               ((MsaWSJob) jobs[job]).cancel();
431               wsInfo.setStatus(jobs[job].jobnum,
432                                WebserviceInfo.STATE_CANCELLED_OK);
433             }
434             else if (cancelledJob.getStatus() == 3)
435             {
436               // VALID UNSTOPPABLE JOB
437               cancelledMessage +=
438                   "Server cannot cancel this job. just close the window.\n";
439               cancelled = false;
440               // wsInfo.setStatus(jobs[job].jobnum,
441               //                 WebserviceInfo.STATE_RUNNING);
442             }
443
444             if (cancelledJob.getJobId() != null)
445             {
446               cancelledMessage += ("[" + cancelledJob.getJobId() + "]");
447             }
448
449             cancelledMessage += "\n";
450           }
451           catch (Exception exc)
452           {
453             cancelledMessage +=
454                 ("\nProblems cancelling the job : Exception received...\n"
455                  + exc + "\n");
456             Cache.log.warn("Exception whilst cancelling "+jobs[job].jobId,exc);
457           }
458           wsInfo.setProgressText(jobs[job].jobnum, OutputHeader
459                                  + cancelledMessage + "\n");
460         }
461       }
462       if (cancelled)
463       {
464         wsInfo.setStatus(WebserviceInfo.STATE_CANCELLED_OK);
465         jobComplete = true;
466       }
467       this.interrupt(); // kick thread to update job states.
468     }
469     else
470     {
471       if (!jobComplete)
472       {
473         wsInfo
474             .setProgressText(OutputHeader
475                              + "Server cannot cancel this job because it has not been submitted properly. just close the window.\n");
476       }
477     }
478   }
479   void pollJob(WSJob job) throws Exception {
480     ((MsaWSJob) job).result = server.getResult(((MsaWSJob) job).jobId);
481   }
482   void StartJob(WSJob job)
483   {
484     if (!(job instanceof MsaWSJob)) {
485       throw new Error("StartJob(MsaWSJob) called on a WSJobInstance "+job.getClass());
486     }
487     MsaWSJob j = (MsaWSJob) job;
488     if (j.submitted)
489     {
490       if (Cache.log.isDebugEnabled())
491       {
492         Cache.log.debug("Tried to submit an already submitted job " + j.jobId);
493       }
494       return;
495     }
496     if (j.seqs.getSeqs() == null)
497     {
498       // special case - selection consisted entirely of empty sequences...
499       j.submitted = true;
500       j.result = new MsaResult();
501       j.result.setFinished(true);
502       j.result.setStatus("Empty Alignment Job");
503       ((MsaResult) j.result).setMsa(null);
504     }
505     try
506     {
507       vamsas.objects.simple.WsJobId jobsubmit = server.align(j.seqs);
508
509       if ( (jobsubmit != null) && (jobsubmit.getStatus() == 1))
510       {
511         j.jobId = jobsubmit.getJobId();
512         j.submitted = true;
513         j.subjobComplete = false;
514         // System.out.println(WsURL + " Job Id '" + jobId + "'");
515       }
516       else
517       {
518         if (jobsubmit == null)
519         {
520           throw new Exception(
521               "Server at "
522               + WsUrl
523               +
524               " returned null object, it probably cannot be contacted. Try again later ?");
525         }
526
527         throw new Exception(jobsubmit.getJobId());
528       }
529     }
530     catch (Exception e)
531     {
532       // TODO: JBPNote catch timeout or other fault types explicitly
533       // For unexpected errors
534       System.err
535           .println(WebServiceName
536                    + "Client: Failed to submit the sequences for alignment (probably a server side problem)\n"
537                    + "When contacting Server:" + WsUrl + "\n"
538                    + e.toString() + "\n");
539       j.allowedServerExceptions = 0;
540       wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_SERVERERROR);
541       wsInfo.setStatus(j.jobnum, WebserviceInfo.STATE_STOPPED_SERVERERROR);
542       wsInfo
543           .appendProgressText(
544               j.jobnum,
545               "Failed to submit sequences for alignment.\n"
546               + "It is most likely that there is a problem with the server.\n"
547               + "Just close the window\n");
548
549       // e.printStackTrace(); // TODO: JBPNote DEBUG
550     }
551   }
552
553   private jalview.datamodel.Sequence[] getVamsasAlignment(
554       vamsas.objects.simple.Alignment valign)
555   {
556     vamsas.objects.simple.Sequence[] seqs = valign.getSeqs().getSeqs();
557     jalview.datamodel.Sequence[] msa = new jalview.datamodel.Sequence[seqs.
558         length];
559
560     for (int i = 0, j = seqs.length; i < j; i++)
561     {
562       msa[i] = new jalview.datamodel.Sequence(seqs[i].getId(), seqs[i]
563                                               .getSeq());
564     }
565
566     return msa;
567   }
568
569   void parseResult()
570   {
571     int results = 0; // number of result sets received
572     JobStateSummary finalState = new JobStateSummary();
573     try
574     {
575       for (int j = 0; j < jobs.length; j++)
576       {
577         finalState.updateJobPanelState(wsInfo, OutputHeader, jobs[j]);
578         if (jobs[j].submitted && jobs[j].subjobComplete && jobs[j].hasResults())
579         {
580           results++;
581           vamsas.objects.simple.Alignment valign = ((MsaResult) jobs[j].result).getMsa();
582           if (valign != null)
583           {
584             wsInfo.appendProgressText(jobs[j].jobnum,
585                                       "\nAlignment Object Method Notes\n");
586             String[] lines = valign.getMethod();
587             for (int line = 0; line < lines.length; line++)
588             {
589               wsInfo.appendProgressText(jobs[j].jobnum, lines[line] + "\n");
590             }
591             // JBPNote The returned files from a webservice could be
592             //  hidden behind icons in the monitor window that,
593             // when clicked, pop up their corresponding data
594           }
595         }
596       }
597     }
598     catch (Exception ex)
599     {
600
601       Cache.log.error("Unexpected exception when processing results for " +
602                       alTitle, ex);
603       wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_ERROR);
604     }
605     if (results > 0)
606     {
607       wsInfo.showResultsNewFrame
608           .addActionListener(new java.awt.event.ActionListener()
609       {
610         public void actionPerformed(
611             java.awt.event.ActionEvent evt)
612         {
613           displayResults(true);
614         }
615       });
616       wsInfo.mergeResults
617           .addActionListener(new java.awt.event.ActionListener()
618       {
619         public void actionPerformed(
620             java.awt.event.ActionEvent evt)
621         {
622           displayResults(false);
623         }
624       });
625       wsInfo.setResultsReady();
626     } else
627       wsInfo.setFinishedNoResults();
628   }
629
630   void displayResults(boolean newFrame)
631   {
632     // view input or result data for each block
633     // warn user if a block is input rather than aligned data ?
634
635     int contigs[] = input.getContigs();
636     SeqCigar[] seqs = input.getSequences();
637     SequenceI[] alignment = new SequenceI[seqs.length];
638     ColumnSelection columnselection = new ColumnSelection();
639     Vector alorders = new Vector();
640     if (contigs != null && contigs.length > 0)
641     {
642       int start = 0;
643       int nwidth = 0;
644       int owidth = input.getWidth();
645       int j = 0;
646       for (int contig = 0; contig < contigs.length; contig += 3)
647       {
648         owidth += contigs[contig + 2]; // recover final column width
649         if (contigs[contig + 1] - start > 0)
650         {
651           int width = 0; // subalignment width
652           if (jobs[j].hasResults())
653           {
654             Object[] subalg = ((MsaWSJob) jobs[j++]).getAlignment();
655             alorders.add(subalg[1]);
656             SequenceI mseq[] = (SequenceI[]) subalg[0];
657             width = mseq[0].getLength();
658             for (int s = 0; s < mseq.length; s++)
659             {
660               if (alignment[s] == null)
661               {
662                 alignment[s] = mseq[s];
663               }
664               else
665               {
666                 alignment[s].setSequence(alignment[s].getSequence() +
667                                          mseq[s].getSequence());
668                 if (mseq[s].getStart() <= mseq[s].getEnd())
669                 {
670                   alignment[s].setEnd(mseq[s].getEnd());
671                 }
672                 ( (AlignmentOrder) subalg[1]).updateSequence(mseq[s],
673                     alignment[s]);
674               }
675             }
676           }
677           else
678           {
679             // recover input data or place gaps
680             if (true)
681             {
682               // recover input data
683               for (int s = 0; s < seqs.length; s++)
684               {
685                 SequenceI oseq = seqs[s].getSeq('-').getSubSequence(start,
686                     contigs[contig + 1]);
687                 if (width < oseq.getLength())
688                 {
689                   width = oseq.getLength();
690                 }
691                 if (alignment[s] == null)
692                 {
693                   alignment[s] = oseq;
694                 }
695                 else
696                 {
697                   alignment[s].setSequence(alignment[s].getSequence() +
698                                            oseq.getSequence());
699                   if (oseq.getEnd() >= oseq.getStart())
700                   {
701                     alignment[s].setEnd(oseq.getEnd());
702                   }
703                 }
704               }
705
706             }
707             j++;
708           }
709           nwidth += width;
710         }
711         // advance to begining of visible region
712         start = contigs[contig + 1] + contigs[contig + 2];
713         // add hidden segment to right of next region
714         for (int s = 0; s < seqs.length; s++)
715         {
716           SequenceI hseq = seqs[s].getSeq('-').getSubSequence(contigs[contig +
717               1], start);
718           if (alignment[s] == null)
719           {
720             alignment[s] = hseq;
721           }
722           else
723           {
724             alignment[s].setSequence(alignment[s].getSequence() +
725                                      hseq.getSequence());
726             if (hseq.getEnd() >= hseq.getStart())
727             {
728               alignment[s].setEnd(hseq.getEnd());
729             }
730           }
731         }
732         // mark hidden segment as hidden in the new alignment
733         columnselection.hideColumns(nwidth, nwidth + contigs[contig + 2] - 1);
734         nwidth += contigs[contig + 2];
735       }
736       // Do final job - if it exists
737       if (j < jobs.length)
738       {
739         int width = 0;
740         if (jobs[j].hasResults())
741         {
742           Object[] subalg = ((MsaWSJob) jobs[j]).getAlignment();
743           alorders.add(subalg[1]);
744           SequenceI mseq[] = (SequenceI[]) subalg[0];
745           width = mseq[0].getLength();
746           for (int s = 0; s < mseq.length; s++)
747           {
748             if (alignment[s] == null)
749             {
750               alignment[s] = mseq[s];
751             }
752             else
753             {
754               alignment[s].setSequence(alignment[s].getSequence() +
755                                        mseq[s].getSequence());
756               if (mseq[s].getEnd() >= mseq[s].getStart())
757               {
758                 alignment[s].setEnd(mseq[s].getEnd());
759               }
760               ( (AlignmentOrder) subalg[1]).updateSequence(mseq[s], alignment[s]);
761             }
762           }
763         }
764         else
765         {
766           if (start < owidth)
767           {
768             // recover input data or place gaps
769             if (true)
770             {
771               // recover input data
772               for (int s = 0; s < seqs.length; s++)
773               {
774                 SequenceI oseq = seqs[s].getSeq('-').getSubSequence(start,
775                     owidth + 1);
776                 if (width < oseq.getLength())
777                 {
778                   width = oseq.getLength();
779                 }
780                 if (alignment[s] == null)
781                 {
782                   alignment[s] = oseq;
783                 }
784                 else
785                 {
786                   alignment[s].setSequence(alignment[s].getSequence() +
787                                            oseq.getSequence());
788                   if (oseq.getEnd() >= oseq.getStart())
789                   {
790                     alignment[s].setEnd(oseq.getEnd());
791                   }
792                 }
793               }
794               nwidth += width;
795             }
796             else
797             {
798               // place gaps.
799               throw new Error("Padding not yet implemented.");
800             }
801           }
802         }
803       }
804     }
805     else
806     {
807       if (jobs[0].hasResults())
808       {
809         Object[] alg = ((MsaWSJob) jobs[0]).getAlignment();
810         alignment = (SequenceI[]) alg[0];
811         alorders.add(alg[1]);
812       }
813       else
814       {
815         alignment = SeqCigar.createAlignmentSequences(seqs, '-',
816             columnselection, null);
817       }
818     }
819     Alignment al = new Alignment(alignment);
820     if (dataset != null)
821     {
822       al.setDataset(dataset);
823     }
824
825     if (newFrame)
826     {
827       // TODO: JBPNote Should also rename the query sequence
828       // sometime...
829       AlignFrame af = new AlignFrame(al, columnselection);
830
831       // >>>This is a fix for the moment, until a better solution is
832       // found!!<<<
833       af.getFeatureRenderer().transferSettings(
834           alignFrame.getFeatureRenderer());
835       if (alorders.size() > 0)
836       {
837         if (alorders.size() == 1)
838         {
839           af.addSortByOrderMenuItem(WebServiceName + " Ordering",
840                                     (AlignmentOrder) alorders.get(0));
841         }
842         else
843         {
844           // construct a non-redundant ordering set
845           Vector names = new Vector();
846           for (int i = 0, l = alorders.size(); i < l; i++)
847           {
848             String orderName = new String("Region " + i);
849             int j = i + 1;
850             int r = l;
851             while (j < l)
852             {
853               if ( ( (AlignmentOrder) alorders.get(i)).equals( ( (
854                   AlignmentOrder) alorders.get(j))))
855               {
856                 alorders.remove(j);
857                 l--;
858                 orderName += "," + j;
859               }
860               else
861               {
862                 j++;
863               }
864             }
865
866             if (i == 0 && j == 1)
867             {
868               names.add(new String(""));
869             }
870             else
871             {
872               names.add(orderName);
873             }
874           }
875           for (int i = 0, l = alorders.size(); i < l; i++)
876           {
877             af.addSortByOrderMenuItem(WebServiceName + ( (String) names.get(i)) +
878                                       " Ordering",
879                                       (AlignmentOrder) alorders.get(i));
880           }
881         }
882       }
883
884       Desktop.addInternalFrame(af, alTitle,
885                                AlignFrame.NEW_WINDOW_WIDTH,
886                                AlignFrame.NEW_WINDOW_HEIGHT);
887
888     }
889     else
890     {
891       System.out.println("MERGE WITH OLD FRAME");
892
893     }
894   }
895 }