2 * Jalview - A Sequence Alignment Editor and Viewer (Version 2.4)
\r
3 * Copyright (C) 2008 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle
\r
5 * This program is free software; you can redistribute it and/or
\r
6 * modify it under the terms of the GNU General Public License
\r
7 * as published by the Free Software Foundation; either version 2
\r
8 * of the License, or (at your option) any later version.
\r
10 * This program is distributed in the hope that it will be useful,
\r
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
13 * GNU General Public License for more details.
\r
15 * You should have received a copy of the GNU General Public License
\r
16 * along with this program; if not, write to the Free Software
\r
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
\r
23 import jalview.analysis.*;
\r
24 import jalview.bin.*;
\r
25 import jalview.datamodel.*;
\r
26 import jalview.datamodel.Alignment;
\r
27 import jalview.gui.*;
\r
28 import jalview.io.*;
\r
29 import jalview.util.*;
\r
30 import vamsas.objects.simple.JpredResult;
\r
33 extends WSThread implements WSClientI
\r
35 // TODO: put mapping between JPredJob input and input data here - JNetAnnotation adding is done after result parsing.
\r
37 extends WSThread.WSJob
\r
39 // TODO: make JPredJob deal only with what was sent to and received from a JNet service
\r
40 int[] predMap = null; // mapping from sequence(i) to the original sequence(predMap[i]) being predicted on
\r
41 vamsas.objects.simple.Sequence sequence;
\r
42 vamsas.objects.simple.Msfalignment msa;
\r
43 java.util.Hashtable SequenceInfo = null;
\r
44 int msaIndex = 0; // the position of the original sequence in the array of Sequences in the input object that this job holds a prediction for
\r
47 * @return true if getResultSet will return a valid alignment and prediction result.
\r
49 public boolean hasResults()
\r
51 if (subjobComplete && result != null && result.isFinished()
\r
52 && ( (JpredResult) result).getPredfile() != null &&
\r
53 ( (JpredResult) result).getAligfile() != null)
\r
60 boolean hasValidInput()
\r
62 if (sequence != null)
\r
71 * @return null or Object[] { annotated alignment for this prediction, ColumnSelection for this prediction} or null if no results available.
\r
74 public Object[] getResultSet()
\r
77 if (result == null || !result.isFinished())
\r
81 Alignment al = null;
\r
82 ColumnSelection alcsel = null;
\r
83 int FirstSeq = -1; // the position of the query sequence in Alignment al
\r
85 JpredResult result = (JpredResult)this.result;
\r
87 jalview.bin.Cache.log.debug("Parsing output from JNet job.");
\r
88 // JPredFile prediction = new JPredFile("C:/JalviewX/files/jpred.txt", "File");
\r
89 jalview.io.JPredFile prediction = new jalview.io.JPredFile(result.
\r
92 SequenceI[] preds = prediction.getSeqsAsArray();
\r
93 jalview.bin.Cache.log.debug("Got prediction profile.");
\r
95 if ( (this.msa != null) && (result.getAligfile() != null))
\r
97 jalview.bin.Cache.log.debug("Getting associated alignment.");
\r
98 // we ignore the returned alignment if we only predicted on a single sequence
\r
99 String format = new jalview.io.IdentifyFile().Identify(result.
\r
103 if (jalview.io.FormatAdapter.isValidFormat(format))
\r
106 if (predMap != null)
\r
108 Object[] alandcolsel = input.getAlignmentAndColumnSelection(
\r
110 sqs = (SequenceI[]) alandcolsel[0];
\r
111 al = new Alignment(sqs);
\r
112 alcsel = (ColumnSelection) alandcolsel[1];
\r
116 al = new FormatAdapter().readFile(result.getAligfile(),
\r
118 sqs = new SequenceI[al.getHeight()];
\r
120 for (int i = 0, j = al.getHeight(); i < j; i++)
\r
122 sqs[i] = al.getSequenceAt(i);
\r
124 if (!jalview.analysis.SeqsetUtils.deuniquify( (Hashtable)
\r
125 SequenceInfo, sqs))
\r
127 throw (new Exception(
\r
128 "Couldn't recover sequence properties for alignment."));
\r
132 al.setDataset(null);
\r
134 jalview.io.JnetAnnotationMaker.add_annotation(prediction, al,
\r
141 throw (new Exception(
\r
142 "Unknown format " + format + " for file : \n" +
\r
143 result.getAligfile()));
\r
148 al = new Alignment(preds);
\r
149 FirstSeq = prediction.getQuerySeqPosition();
\r
150 if (predMap != null)
\r
152 char gc = getGapChar();
\r
153 SequenceI[] sqs = (SequenceI[]) ( (java.lang.Object[]) input.
\r
154 getAlignmentAndColumnSelection(gc))[
\r
156 if (this.msaIndex >= sqs.length)
\r
158 throw new Error("Implementation Error! Invalid msaIndex for JPredJob on parent MSA input object!");
\r
162 //Uses RemoveGapsCommand
\r
164 new jalview.commands.RemoveGapsCommand("Remove Gaps",
\r
169 SequenceI profileseq = al.getSequenceAt(FirstSeq);
\r
170 profileseq.setSequence(sqs[msaIndex].getSequenceAsString());
\r
173 if (!jalview.analysis.SeqsetUtils.SeqCharacterUnhash(
\r
174 al.getSequenceAt(FirstSeq), SequenceInfo))
\r
176 throw (new Exception(
\r
177 "Couldn't recover sequence properties for JNet Query sequence!"));
\r
181 al.setDataset(null);
\r
182 jalview.io.JnetAnnotationMaker.add_annotation(prediction, al,
\r
185 SequenceI profileseq = al.getSequenceAt(0); // this includes any gaps.
\r
186 alignToProfileSeq(al, profileseq);
\r
187 if (predMap != null)
\r
189 // Adjust input view for gaps
\r
190 // propagate insertions into profile
\r
191 alcsel = propagateInsertions(profileseq, al, input);
\r
195 return new Object[]
\r
197 al, alcsel}; // , FirstSeq, noMsa};
\r
201 * Given an alignment where all other sequences except profileseq are aligned to the ungapped profileseq, insert gaps in the other sequences to realign them with the residues in profileseq
\r
203 * @param profileseq
\r
205 private void alignToProfileSeq(Alignment al, SequenceI profileseq)
\r
207 char gc = al.getGapCharacter();
\r
208 int[] gapMap = profileseq.gapMap();
\r
209 // insert gaps into profile
\r
210 for (int lp = 0, r = 0; r < gapMap.length; r++)
\r
212 if (gapMap[r] - lp > 1)
\r
214 StringBuffer sb = new StringBuffer();
\r
215 for (int s = 0, ns = gapMap[r] - lp; s < ns; s++)
\r
219 for (int s = 1, ns = al.getHeight(); s < ns; s++)
\r
221 String sq = al.getSequenceAt(s).getSequenceAsString();
\r
222 int diff = gapMap[r] - sq.length();
\r
227 while ( (diff = gapMap[r] - sq.length()) > 0)
\r
230 ( (diff >= sb.length()) ? sb.toString() :
\r
231 sb.substring(0, diff));
\r
233 al.getSequenceAt(s).setSequence(sq);
\r
237 al.getSequenceAt(s).setSequence(sq.substring(0, gapMap[r]) +
\r
239 sq.substring(gapMap[r]));
\r
248 * Add gaps into the sequences aligned to profileseq under the given AlignmentView
\r
249 * @param profileseq
\r
253 private ColumnSelection propagateInsertions(SequenceI profileseq,
\r
255 AlignmentView input)
\r
257 char gc = al.getGapCharacter();
\r
258 Object[] alandcolsel = input.getAlignmentAndColumnSelection(gc);
\r
259 ColumnSelection nview = (ColumnSelection) alandcolsel[1];
\r
261 nview.pruneDeletions(ShiftList.parseMap( (origseq = ( (SequenceI[])
\r
262 alandcolsel[0])[0]).gapMap())); // recover original prediction sequence's mapping to view.
\r
263 int[] viscontigs = nview.getVisibleContigs(0, profileseq.getLength());
\r
266 // input.pruneDeletions(ShiftList.parseMap(((SequenceI[]) alandcolsel[0])[0].gapMap()))
\r
267 // add profile to visible contigs
\r
268 for (int v = 0; v < viscontigs.length; v += 2)
\r
270 if (viscontigs[v] > spos)
\r
272 StringBuffer sb = new StringBuffer();
\r
273 for (int s = 0, ns = viscontigs[v] - spos; s < ns; s++)
\r
277 for (int s = 0, ns = al.getHeight(); s < ns; s++)
\r
279 SequenceI sqobj = al.getSequenceAt(s);
\r
280 if (sqobj != profileseq)
\r
282 String sq = al.getSequenceAt(s).getSequenceAsString();
\r
283 if (sq.length() <= spos + offset)
\r
286 int diff = spos + offset - sq.length() - 1;
\r
291 while ( (diff = spos + offset - sq.length() - 1) > 0)
\r
294 ( (diff >= sb.length()) ? sb.toString() :
\r
295 sb.substring(0, diff));
\r
298 sq += sb.toString();
\r
302 al.getSequenceAt(s).setSequence(sq.substring(0, spos + offset) +
\r
304 sq.substring(spos + offset));
\r
308 //offset+=sb.length();
\r
310 spos = viscontigs[v + 1] + 1;
\r
312 if ( (offset + spos) < profileseq.getLength())
\r
314 StringBuffer sb = new StringBuffer();
\r
315 for (int s = 0, ns = profileseq.getLength() - spos - offset; s < ns; s++)
\r
319 for (int s = 1, ns = al.getHeight(); s < ns; s++)
\r
321 String sq = al.getSequenceAt(s).getSequenceAsString();
\r
323 int diff = origseq.getLength() - sq.length();
\r
327 ( (diff >= sb.length()) ? sb.toString() : sb.substring(0, diff));
\r
328 diff = origseq.getLength() - sq.length();
\r
335 public JPredJob(Hashtable SequenceInfo, SequenceI seq, int[] delMap)
\r
338 this.predMap = delMap;
\r
339 String sq = AlignSeq.extractGaps(Comparison.GapChars,
\r
340 seq.getSequenceAsString());
\r
341 if (sq.length() >= 20)
\r
343 this.SequenceInfo = SequenceInfo;
\r
344 sequence = new vamsas.objects.simple.Sequence();
\r
345 sequence.setId(seq.getName());
\r
346 sequence.setSeq(sq);
\r
350 public JPredJob(Hashtable SequenceInfo, SequenceI[] msf, int[] delMap)
\r
352 this(SequenceInfo, msf[0], delMap);
\r
353 if (sequence != null)
\r
355 if (msf.length > 1)
\r
357 msa = new vamsas.objects.simple.Msfalignment();
\r
358 jalview.io.PileUpfile pileup = new jalview.io.PileUpfile();
\r
359 msa.setMsf(pileup.print(msf));
\r
365 ext.vamsas.Jpred server;
\r
366 String altitle = "";
\r
367 JPredThread(WebserviceInfo wsinfo, String altitle, ext.vamsas.Jpred server,
\r
368 String wsurl, AlignmentView alview, AlignFrame alframe)
\r
370 super(alframe, wsinfo, alview, wsurl);
\r
371 this.altitle = altitle;
\r
372 this.server = server;
\r
375 JPredThread(WebserviceInfo wsinfo, String altitle, ext.vamsas.Jpred server,
\r
376 String wsurl, Hashtable SequenceInfo, SequenceI seq, int[] delMap,
\r
377 AlignmentView alview, AlignFrame alframe)
\r
379 this(wsinfo, altitle, server, wsurl, alview, alframe);
\r
380 JPredJob job = new JPredJob(SequenceInfo, seq, delMap);
\r
381 if (job.hasValidInput())
\r
383 OutputHeader = wsInfo.getProgressText();
\r
391 JPredThread(WebserviceInfo wsinfo, String altitle, ext.vamsas.Jpred server,
\r
392 Hashtable SequenceInfo, SequenceI[] msf, int[] delMap,
\r
393 AlignmentView alview, AlignFrame alframe, String wsurl)
\r
395 this(wsinfo, altitle, server, wsurl, alview, alframe);
\r
396 JPredJob job = new JPredJob(SequenceInfo, msf, delMap);
\r
397 if (job.hasValidInput())
\r
402 OutputHeader = wsInfo.getProgressText();
\r
407 void StartJob(WSJob j)
\r
409 if (! (j instanceof JPredJob))
\r
411 throw new Error("Implementation error - StartJob(JpredJob) called on " +
\r
416 JPredJob job = (JPredJob) j;
\r
417 if (job.msa != null)
\r
419 job.jobId = server.predictOnMsa(job.msa);
\r
422 if (job.sequence != null)
\r
424 job.jobId = server.predict(job.sequence); // debug like : job.jobId = "/jobs/www-jpred/jp_Yatat29";//
\r
427 if (job.jobId != null)
\r
429 if (job.jobId.startsWith("Broken"))
\r
431 job.result = (vamsas.objects.simple.Result)new JpredResult();
\r
432 job.result.setInvalid(true);
\r
433 job.result.setStatus("Submission " + job.jobId);
\r
434 throw new Exception(job.jobId);
\r
438 job.submitted = true;
\r
439 job.subjobComplete = false;
\r
440 Cache.log.info(WsUrl + " Job Id '" + job.jobId + "'");
\r
445 throw new Exception("Server timed out - try again later\n");
\r
448 catch (Exception e)
\r
450 // kill the whole job.
\r
451 wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_SERVERERROR);
\r
452 if (e.getMessage().indexOf("Exception") > -1)
\r
454 wsInfo.setStatus(j.jobnum, WebserviceInfo.STATE_STOPPED_SERVERERROR);
\r
455 wsInfo.setProgressText(j.jobnum,
\r
456 "Failed to submit the prediction. (Just close the window)\n"
\r
458 "It is most likely that there is a problem with the server.\n");
\r
459 System.err.println(
\r
460 "JPredWS Client: Failed to submit the prediction. Quite possibly because of a server error - see below)\n" +
\r
461 e.getMessage() + "\n");
\r
463 jalview.bin.Cache.log.warn("Server Exception", e);
\r
467 wsInfo.setStatus(j.jobnum, WebserviceInfo.STATE_STOPPED_ERROR);
\r
468 // JBPNote - this could be a popup informing the user of the problem.
\r
469 wsInfo.appendProgressText(j.jobnum,
\r
470 "Failed to submit the prediction:\n"
\r
472 wsInfo.getProgressText());
\r
474 jalview.bin.Cache.log.debug("Failed Submission of job " + j.jobnum, e);
\r
477 j.allowedServerExceptions = -1;
\r
478 j.subjobComplete = true;
\r
484 int results = 0; // number of result sets received
\r
485 JobStateSummary finalState = new JobStateSummary();
\r
488 for (int j = 0; j < jobs.length; j++)
\r
490 finalState.updateJobPanelState(wsInfo, OutputHeader, jobs[j]);
\r
491 if (jobs[j].submitted && jobs[j].subjobComplete && jobs[j].hasResults())
\r
497 catch (Exception ex)
\r
500 Cache.log.error("Unexpected exception when processing results for " +
\r
502 wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_ERROR);
\r
506 wsInfo.showResultsNewFrame
\r
507 .addActionListener(new java.awt.event.ActionListener()
\r
509 public void actionPerformed(
\r
510 java.awt.event.ActionEvent evt)
\r
512 displayResults(true);
\r
515 wsInfo.mergeResults
\r
516 .addActionListener(new java.awt.event.ActionListener()
\r
518 public void actionPerformed(
\r
519 java.awt.event.ActionEvent evt)
\r
521 displayResults(false);
\r
524 wsInfo.setResultsReady();
\r
528 wsInfo.setFinishedNoResults();
\r
532 void displayResults(boolean newWindow)
\r
534 // TODO: cope with multiple subjobs.
\r
537 Object[] res = null;
\r
538 boolean msa = false;
\r
539 for (int jn = 0; jn < jobs.length; jn++)
\r
541 Object[] jobres = null;
\r
542 JPredJob j = (JPredJob) jobs[jn];
\r
544 if (j.hasResults())
\r
546 // hack - we only deal with all single seuqence predictions or all profile predictions
\r
547 msa = (j.msa != null) ? true : msa;
\r
550 jalview.bin.Cache.log.debug("Parsing output of job " + jn);
\r
551 jobres = j.getResultSet();
\r
552 jalview.bin.Cache.log.debug("Finished parsing output.");
\r
553 if (jobs.length == 1)
\r
559 // do merge with other job results
\r
561 "Multiple JNet subjob merging not yet implemented.");
\r
564 catch (Exception e)
\r
566 jalview.bin.Cache.log.error(
\r
567 "JNet Client: JPred Annotation Parse Error",
\r
569 wsInfo.setStatus(j.jobnum, WebserviceInfo.STATE_STOPPED_ERROR);
\r
570 wsInfo.appendProgressText(j.jobnum,
\r
571 OutputHeader + "\n" +
\r
572 j.result.getStatus() +
\r
573 "\nInvalid JNet job result data!\n" +
\r
575 j.result.setBroken(true);
\r
587 if (res[1] != null)
\r
589 af = new AlignFrame( (Alignment) res[0], (ColumnSelection) res[1],
\r
590 AlignFrame.DEFAULT_WIDTH,
\r
591 AlignFrame.DEFAULT_HEIGHT);
\r
595 af = new AlignFrame( (Alignment) res[0], AlignFrame.DEFAULT_WIDTH,
\r
596 AlignFrame.DEFAULT_HEIGHT);
\r
601 /*java.lang.Object[] alandcolsel = input.getAlignmentAndColumnSelection(alignFrame.getViewport().getGapCharacter());
\r
602 if (((SequenceI[])alandcolsel[0])[0].getLength()!=res.getWidth()) {
\r
604 throw new Error("Implementation Error! ColumnSelection from input alignment will not map to result alignment!");
\r
608 // update hidden regions to account for loss of gaps in profile. - if any
\r
609 // gapMap returns insert list, interpreted as delete list by pruneDeletions
\r
610 //((ColumnSelection) alandcolsel[1]).pruneDeletions(ShiftList.parseMap(((SequenceI[]) alandcolsel[0])[0].gapMap()));
\r
613 af = new AlignFrame( (Alignment) res[0], (ColumnSelection) res[1],
\r
614 AlignFrame.DEFAULT_WIDTH,
\r
615 AlignFrame.DEFAULT_HEIGHT);
\r
617 Desktop.addInternalFrame(af, altitle,
\r
618 AlignFrame.DEFAULT_WIDTH,
\r
619 AlignFrame.DEFAULT_HEIGHT);
\r
623 Cache.log.info("Append results onto existing alignment.");
\r
629 void pollJob(WSJob job)
\r
632 job.result = server.getresult(job.jobId);
\r
635 public boolean isCancellable()
\r
640 public void cancelJob()
\r
642 throw new Error("Implementation error!");
\r
645 public boolean canMergeResults()
\r