2 * Jalview - A Sequence Alignment Editor and Viewer
3 * Copyright (C) 2006 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23 import jalview.analysis.*;
25 import jalview.datamodel.*;
26 import jalview.datamodel.Alignment;
28 import vamsas.objects.simple.MsaResult;
40 * Copyright: Copyright (c) 2004
44 * Company: Dundee University
47 * @author not attributable
51 extends WSThread implements WSClientI
53 boolean submitGaps = false; // pass sequences including gaps to alignment
57 boolean preserveOrder = true; // and always store and recover sequence
61 class MsaWSJob extends WSThread.WSJob
63 // hold special input for this
64 vamsas.objects.simple.SequenceSet seqs = new vamsas.objects.simple.
75 public MsaWSJob(int jobNum, SequenceI[] inSeqs)
78 if (!prepareInput(inSeqs, 2))
81 subjobComplete = true;
82 result = new MsaResult();
83 result.setFinished(true);
84 result.setStatus("Job never ran - input returned to user.");
89 Hashtable SeqNames = new Hashtable();
90 Vector emptySeqs = new Vector();
92 * prepare input sequences for MsaWS service
93 * @param seqs jalview sequences to be prepared
94 * @param minlen minimum number of residues required for this MsaWS service
95 * @return true if seqs contains sequences to be submitted to service.
97 private boolean prepareInput(SequenceI[] seqs, int minlen)
102 throw new Error("Implementation error: minlen must be zero or more.");
104 for (int i = 0; i < seqs.length; i++)
106 if (seqs[i].getEnd() - seqs[i].getStart() > minlen - 1)
111 boolean valid = nseqs > 1; // need at least two seqs
112 vamsas.objects.simple.Sequence[] seqarray =
114 ? new vamsas.objects.simple.Sequence[nseqs]
116 for (int i = 0, n = 0; i < seqs.length; i++)
119 String newname = jalview.analysis.SeqsetUtils.unique_name(i); // same
123 SeqNames.put(newname, jalview.analysis.SeqsetUtils
124 .SeqCharacterHash(seqs[i]));
125 if (valid && seqs[i].getEnd() - seqs[i].getStart() > minlen - 1)
127 seqarray[n] = new vamsas.objects.simple.Sequence();
128 seqarray[n].setId(newname);
129 seqarray[n++].setSeq( (submitGaps) ? seqs[i].getSequenceAsString()
130 : AlignSeq.extractGaps(
131 jalview.util.Comparison.GapChars, seqs[i]
132 .getSequenceAsString()));
137 if (seqs[i].getEnd() >= seqs[i].getStart())
139 empty = (submitGaps) ? seqs[i].getSequenceAsString()
140 : AlignSeq.extractGaps(
141 jalview.util.Comparison.GapChars, seqs[i]
142 .getSequenceAsString());
144 emptySeqs.add(new String[]
148 this.seqs = new vamsas.objects.simple.SequenceSet();
149 this.seqs.setSeqs(seqarray);
155 * @return true if getAlignment will return a valid alignment result.
157 public boolean hasResults()
159 if (subjobComplete && result != null && result.isFinished()
160 && ((MsaResult) result).getMsa() != null && ((MsaResult) result).getMsa().getSeqs() != null)
167 public Object[] getAlignment()
170 if (result != null && result.isFinished())
172 SequenceI[] alseqs = null;
173 char alseq_gapchar = '-';
175 if (((MsaResult) result).getMsa() != null)
177 alseqs = getVamsasAlignment(((MsaResult) result).getMsa());
178 alseq_gapchar = ((MsaResult) result).getMsa().getGapchar().charAt(0);
179 alseq_l = alseqs.length;
181 if (emptySeqs.size() > 0)
183 SequenceI[] t_alseqs = new SequenceI[alseq_l + emptySeqs.size()];
188 for (i = 0, w = alseqs[0].getLength(); i < alseq_l; i++)
190 if (w < alseqs[i].getLength())
192 w = alseqs[i].getLength();
194 t_alseqs[i] = alseqs[i];
198 // check that aligned width is at least as wide as emptySeqs width.
200 for (i = 0, w = emptySeqs.size(); i < w; i++)
202 String[] es = (String[]) emptySeqs.get(i);
203 if (es != null && es[1] != null)
205 int sw = es[1].length();
212 // make a gapped string.
213 StringBuffer insbuff = new StringBuffer(w);
214 for (i = 0; i < nw; i++)
216 insbuff.append(alseq_gapchar);
220 for (i = 0; i < alseq_l; i++)
222 int sw = t_alseqs[i].getLength();
226 alseqs[i].setSequence(t_alseqs[i].getSequenceAsString() +
227 insbuff.substring(0, sw - nw));
231 for (i = 0, w = emptySeqs.size(); i < w; i++)
233 String[] es = (String[]) emptySeqs.get(i);
237 alseq_l] = new jalview.datamodel.Sequence(es[0],
238 insbuff.toString(), 1, 0);
242 if (es[1].length() < nw)
245 alseq_l] = new jalview.datamodel.Sequence(es[0],
246 es[1] + insbuff.substring(0, nw - es[1].length()), 1,
252 alseq_l] = new jalview.datamodel.Sequence(es[0], es[1]);
258 AlignmentOrder msaorder = new AlignmentOrder(alseqs);
259 // always recover the order - makes parseResult()'s life easier.
260 jalview.analysis.AlignmentSorter.recoverOrder(alseqs);
261 // account for any missing sequences
262 jalview.analysis.SeqsetUtils.deuniquify(SeqNames, alseqs);
270 * mark subjob as cancelled and set result object appropriatly
274 subjobComplete = true;
279 * @return boolean true if job can be submitted.
281 boolean hasValidInput() {
282 if (seqs.getSeqs()!=null)
289 String alTitle; // name which will be used to form new alignment window.
290 Alignment dataset; // dataset to which the new alignment will be
294 ext.vamsas.MuscleWS server = null;
296 * set basic options for this (group) of Msa jobs
303 MsaWSThread(ext.vamsas.MuscleWS server, String wsUrl,
304 WebserviceInfo wsinfo, jalview.gui.AlignFrame alFrame,
305 AlignmentView alview,
306 String wsname, boolean subgaps, boolean presorder)
308 this.server = server;
310 this.wsInfo = wsinfo;
311 this.WebServiceName = wsname;
313 this.submitGaps = subgaps;
314 this.preserveOrder = presorder;
315 this.alignFrame = alFrame;
319 * create one or more Msa jobs to align visible seuqences in _msa
332 MsaWSThread(ext.vamsas.MuscleWS server, String wsUrl,
333 WebserviceInfo wsinfo, jalview.gui.AlignFrame alFrame,
334 String wsname, String title, AlignmentView _msa, boolean subgaps,
335 boolean presorder, Alignment seqset)
337 this(server, wsUrl, wsinfo, alFrame, _msa, wsname, subgaps, presorder);
338 OutputHeader = wsInfo.getProgressText();
342 SequenceI[][] conmsa = _msa.getVisibleContigs('-');
345 int njobs = conmsa.length;
346 jobs = new MsaWSJob[njobs];
347 for (int j = 0; j < njobs; j++)
351 jobs[j] = new MsaWSJob(wsinfo.addJobPane(), conmsa[j]);
355 jobs[j] = new MsaWSJob(0, conmsa[j]);
358 wsinfo.setProgressName("region " + jobs[j].jobnum, jobs[j].jobnum);
359 wsinfo.setProgressText(jobs[j].jobnum, OutputHeader);
363 public boolean isCancellable()
368 public void cancelJob()
370 if (!jobComplete && jobs != null)
372 boolean cancelled = true;
373 for (int job = 0; job < jobs.length; job++)
375 if (jobs[job].submitted && !jobs[job].subjobComplete)
377 String cancelledMessage = "";
380 vamsas.objects.simple.WsJobId cancelledJob = server
381 .cancel(jobs[job].jobId);
382 if (cancelledJob.getStatus() == 2)
385 cancelledMessage = "Job cancelled.";
386 ((MsaWSJob) jobs[job]).cancel();
387 wsInfo.setStatus(jobs[job].jobnum,
388 WebserviceInfo.STATE_CANCELLED_OK);
390 else if (cancelledJob.getStatus() == 3)
392 // VALID UNSTOPPABLE JOB
394 "Server cannot cancel this job. just close the window.\n";
396 // wsInfo.setStatus(jobs[job].jobnum,
397 // WebserviceInfo.STATE_RUNNING);
400 if (cancelledJob.getJobId() != null)
402 cancelledMessage += ("[" + cancelledJob.getJobId() + "]");
405 cancelledMessage += "\n";
407 catch (Exception exc)
410 ("\nProblems cancelling the job : Exception received...\n"
412 Cache.log.warn("Exception whilst cancelling "+jobs[job].jobId,exc);
414 wsInfo.setProgressText(jobs[job].jobnum, OutputHeader
415 + cancelledMessage + "\n");
420 wsInfo.setStatus(WebserviceInfo.STATE_CANCELLED_OK);
423 this.interrupt(); // kick thread to update job states.
430 .setProgressText(OutputHeader
431 + "Server cannot cancel this job because it has not been submitted properly. just close the window.\n");
435 void pollJob(WSJob job) throws Exception {
436 ((MsaWSJob) job).result = server.getResult(((MsaWSJob) job).jobId);
438 void StartJob(WSJob job)
440 if (!(job instanceof MsaWSJob)) {
441 throw new Error("StartJob(MsaWSJob) called on a WSJobInstance "+job.getClass());
443 MsaWSJob j = (MsaWSJob) job;
446 if (Cache.log.isDebugEnabled())
448 Cache.log.debug("Tried to submit an already submitted job " + j.jobId);
452 if (j.seqs.getSeqs() == null)
454 // special case - selection consisted entirely of empty sequences...
456 j.result = new MsaResult();
457 j.result.setFinished(true);
458 j.result.setStatus("Empty Alignment Job");
459 ((MsaResult) j.result).setMsa(null);
463 vamsas.objects.simple.WsJobId jobsubmit = server.align(j.seqs);
465 if ( (jobsubmit != null) && (jobsubmit.getStatus() == 1))
467 j.jobId = jobsubmit.getJobId();
469 j.subjobComplete = false;
470 // System.out.println(WsURL + " Job Id '" + jobId + "'");
474 if (jobsubmit == null)
480 " returned null object, it probably cannot be contacted. Try again later ?");
483 throw new Exception(jobsubmit.getJobId());
488 // TODO: JBPNote catch timeout or other fault types explicitly
489 // For unexpected errors
491 .println(WebServiceName
492 + "Client: Failed to submit the sequences for alignment (probably a server side problem)\n"
493 + "When contacting Server:" + WsUrl + "\n"
494 + e.toString() + "\n");
495 j.allowedServerExceptions = 0;
496 wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_SERVERERROR);
497 wsInfo.setStatus(j.jobnum, WebserviceInfo.STATE_STOPPED_SERVERERROR);
501 "Failed to submit sequences for alignment.\n"
502 + "It is most likely that there is a problem with the server.\n"
503 + "Just close the window\n");
505 // e.printStackTrace(); // TODO: JBPNote DEBUG
509 private jalview.datamodel.Sequence[] getVamsasAlignment(
510 vamsas.objects.simple.Alignment valign)
512 vamsas.objects.simple.Sequence[] seqs = valign.getSeqs().getSeqs();
513 jalview.datamodel.Sequence[] msa = new jalview.datamodel.Sequence[seqs.
516 for (int i = 0, j = seqs.length; i < j; i++)
518 msa[i] = new jalview.datamodel.Sequence(seqs[i].getId(), seqs[i]
527 int results = 0; // number of result sets received
528 JobStateSummary finalState = new JobStateSummary();
531 for (int j = 0; j < jobs.length; j++)
533 finalState.updateJobPanelState(wsInfo, OutputHeader, jobs[j]);
534 if (jobs[j].submitted && jobs[j].subjobComplete && jobs[j].hasResults())
537 vamsas.objects.simple.Alignment valign = ((MsaResult) jobs[j].result).getMsa();
540 wsInfo.appendProgressText(jobs[j].jobnum,
541 "\nAlignment Object Method Notes\n");
542 String[] lines = valign.getMethod();
543 for (int line = 0; line < lines.length; line++)
545 wsInfo.appendProgressText(jobs[j].jobnum, lines[line] + "\n");
547 // JBPNote The returned files from a webservice could be
548 // hidden behind icons in the monitor window that,
549 // when clicked, pop up their corresponding data
557 Cache.log.error("Unexpected exception when processing results for " +
559 wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_ERROR);
563 wsInfo.showResultsNewFrame
564 .addActionListener(new java.awt.event.ActionListener()
566 public void actionPerformed(
567 java.awt.event.ActionEvent evt)
569 displayResults(true);
573 .addActionListener(new java.awt.event.ActionListener()
575 public void actionPerformed(
576 java.awt.event.ActionEvent evt)
578 displayResults(false);
581 wsInfo.setResultsReady();
583 wsInfo.setFinishedNoResults();
586 void displayResults(boolean newFrame)
588 // view input or result data for each block
589 Vector alorders = new Vector();
590 SequenceI[][] results=new SequenceI[jobs.length][];
591 AlignmentOrder[] orders = new AlignmentOrder[jobs.length];
593 for (int j=0; j<jobs.length; j++) {
594 if (jobs[j].hasResults()) {
595 Object[] res = ( (MsaWSJob) jobs[j]).getAlignment();
596 alorders.add(res[1]);
597 results[j] = (SequenceI[]) res[0];
598 orders[j] = (AlignmentOrder) res[1];
599 // SequenceI[] alignment = input.getUpdated
604 Object[] newview = input.getUpdatedView(results, orders, '-');
605 // trash references to original result data
606 for (int j=0; j<jobs.length; j++) {
610 SequenceI[] alignment = (SequenceI[]) newview[0];
611 ColumnSelection columnselection = (ColumnSelection) newview[1];
612 Alignment al = new Alignment(alignment);
615 al.setDataset(dataset);
618 // JBNote- TODO: warn user if a block is input rather than aligned data ?
622 AlignFrame af = new AlignFrame(al, columnselection,
623 AlignFrame.DEFAULT_WIDTH,
624 AlignFrame.DEFAULT_HEIGHT);
626 // >>>This is a fix for the moment, until a better solution is
628 af.getFeatureRenderer().transferSettings(
629 alignFrame.getFeatureRenderer());
631 if (alorders.size() > 0)
633 if (alorders.size() == 1)
635 af.addSortByOrderMenuItem(WebServiceName + " Ordering",
636 (AlignmentOrder) alorders.get(0));
640 // construct a non-redundant ordering set
641 Vector names = new Vector();
642 for (int i = 0, l = alorders.size(); i < l; i++)
644 String orderName = new String(" Region " + i);
649 if ( ( (AlignmentOrder) alorders.get(i)).equals( ( (
650 AlignmentOrder) alorders.get(j))))
654 orderName += "," + j;
662 if (i == 0 && j == 1)
664 names.add(new String(""));
668 names.add(orderName);
671 for (int i = 0, l = alorders.size(); i < l; i++)
673 af.addSortByOrderMenuItem(WebServiceName
674 +( (String) names.get(i)) +
676 (AlignmentOrder) alorders.get(i));
681 Desktop.addInternalFrame(af, alTitle,
682 AlignFrame.DEFAULT_WIDTH,
683 AlignFrame.DEFAULT_HEIGHT);
688 System.out.println("MERGE WITH OLD FRAME");
693 public boolean canMergeResults()