Clover icon

Coverage Report

  1. Project Clover database Thu Dec 4 2025 14:43:25 GMT
  2. Package jalview.ws.jws1

File JPredThread.java

 

Coverage histogram

../../../img/srcFileCovDistChart0.png
60% of files have more coverage

Code metrics

92
193
19
2
656
526
76
0.39
10.16
9.5
4

Classes

Class Line # Actions
JPredThread 58 98 37
0.00%
JPredThread.JPredJob 62 95 39
0.00%
 

Contributing tests

No tests hitting this source file were found.

Source view

1    /*
2    * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3    * Copyright (C) $$Year-Rel$$ The Jalview Authors
4    *
5    * This file is part of Jalview.
6    *
7    * Jalview is free software: you can redistribute it and/or
8    * modify it under the terms of the GNU General Public License
9    * as published by the Free Software Foundation, either version 3
10    * of the License, or (at your option) any later version.
11    *
12    * Jalview is distributed in the hope that it will be useful, but
13    * WITHOUT ANY WARRANTY; without even the implied warranty
14    * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15    * PURPOSE. See the GNU General Public License for more details.
16    *
17    * You should have received a copy of the GNU General Public License
18    * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
19    * The Jalview Authors are detailed in the 'AUTHORS' file.
20    */
21    package jalview.ws.jws1;
22   
23    import java.util.Hashtable;
24   
25    import jalview.analysis.AlignSeq;
26    import jalview.analysis.AlignmentAnnotationUtils;
27    import jalview.analysis.SeqsetUtils;
28    import jalview.analysis.SeqsetUtils.SequenceInfo;
29    import jalview.bin.Console;
30    import jalview.datamodel.Alignment;
31    import jalview.datamodel.AlignmentAnnotation;
32    import jalview.datamodel.AlignmentI;
33    import jalview.datamodel.AlignmentView;
34    import jalview.datamodel.HiddenColumns;
35    import jalview.datamodel.SequenceI;
36    import jalview.gui.AlignFrame;
37    import jalview.gui.Desktop;
38    import jalview.gui.WebserviceInfo;
39    import jalview.io.DataSourceType;
40    import jalview.io.FileFormatI;
41    import jalview.io.FormatAdapter;
42    import jalview.io.IdentifyFile;
43    import jalview.io.JPredFile;
44    import jalview.io.JnetAnnotationMaker;
45    import jalview.io.PileUpfile;
46    import jalview.util.Comparison;
47    import jalview.util.MessageManager;
48    import jalview.ws.AWsJob;
49    import jalview.ws.JobStateSummary;
50    import jalview.ws.WSClientI;
51   
52    import java.util.Hashtable;
53    import java.util.List;
54    import java.util.Map;
55   
56    import vamsas.objects.simple.JpredResult;
57   
 
58    class JPredThread extends JWS1Thread implements WSClientI
59    {
60    // TODO: put mapping between JPredJob input and input data here -
61    // JNetAnnotation adding is done after result parsing.
 
62    class JPredJob extends WSJob
63    {
64    // TODO: make JPredJob deal only with what was sent to and received from a
65    // JNet service
66    int[] predMap = null; // mapping from sequence(i) to the original
67   
68    // sequence(predMap[i]) being predicted on
69   
70    vamsas.objects.simple.Sequence sequence;
71   
72    vamsas.objects.simple.Msfalignment msa;
73   
74    Object SequenceInfo = null;
75   
76    int msaIndex = 0; // the position of the original sequence in the array of
77   
78    // Sequences in the input object that this job holds a
79    // prediction for
80   
81    /**
82    *
83    * @return true if getResultSet will return a valid alignment and prediction
84    * result.
85    */
 
86  0 toggle @Override
87    public boolean hasResults()
88    {
89  0 if (subjobComplete && result != null && result.isFinished()
90    && ((JpredResult) result).getPredfile() != null
91    && ((JpredResult) result).getAligfile() != null)
92    {
93  0 return true;
94    }
95  0 return false;
96    }
97   
 
98  0 toggle @Override
99    public boolean hasValidInput()
100    {
101  0 if (sequence != null)
102    {
103  0 return true;
104    }
105  0 return false;
106    }
107   
108    /**
109    *
110    * @return null or Object[] { annotated alignment for this prediction,
111    * ColumnSelection for this prediction} or null if no results
112    * available.
113    * @throws Exception
114    */
 
115  0 toggle public Object[] getResultSet() throws Exception
116    {
117  0 if (result == null || !result.isFinished())
118    {
119  0 return null;
120    }
121  0 AlignmentI al = null;
122  0 HiddenColumns alhidden = null;
123  0 int FirstSeq = -1; // the position of the query sequence in Alignment al
124   
125  0 JpredResult result = (JpredResult) this.result;
126   
127  0 Console.debug("Parsing output from JNet job.");
128    // JPredFile prediction = new JPredFile("C:/JalviewX/files/jpred.txt",
129    // "File");
130  0 JPredFile prediction = new JPredFile(result.getPredfile(),
131    DataSourceType.PASTE);
132  0 SequenceI[] preds = prediction.getSeqsAsArray();
133  0 Console.debug("Got prediction profile.");
134   
135  0 if ((this.msa != null) && (result.getAligfile() != null))
136    {
137  0 Console.debug("Getting associated alignment.");
138    // we ignore the returned alignment if we only predicted on a single
139    // sequence
140  0 FileFormatI format = new IdentifyFile()
141    .identify(result.getAligfile(), DataSourceType.PASTE);
142   
143  0 if (format != null)
144    {
145  0 SequenceI sqs[];
146  0 if (predMap != null)
147    {
148  0 Object[] alandcolsel = input
149    .getAlignmentAndHiddenColumns(getGapChar());
150  0 sqs = (SequenceI[]) alandcolsel[0];
151  0 al = new Alignment(sqs);
152  0 alhidden = (HiddenColumns) alandcolsel[1];
153    }
154    else
155    {
156  0 al = new FormatAdapter().readFile(result.getAligfile(),
157    DataSourceType.PASTE, format);
158  0 sqs = new SequenceI[al.getHeight()];
159   
160  0 for (int i = 0, j = al.getHeight(); i < j; i++)
161    {
162  0 sqs[i] = al.getSequenceAt(i);
163    }
164  0 if (!SeqsetUtils.deuniquify((Map<String, SequenceInfo>)SequenceInfo, sqs))
165    {
166  0 throw (new Exception(MessageManager.getString(
167    "exception.couldnt_recover_sequence_properties_for_alignment")));
168    }
169    }
170  0 FirstSeq = 0;
171  0 if (currentView.getDataset() != null)
172    {
173  0 al.setDataset(currentView.getDataset());
174   
175    }
176    else
177    {
178  0 al.setDataset(null);
179    }
180  0 JnetAnnotationMaker.add_annotation(prediction, al, FirstSeq,
181    false, predMap);
182   
183    }
184    else
185    {
186  0 throw (new Exception(MessageManager.formatMessage(
187    "exception.unknown_format_for_file", new String[]
188    { "", result.getAligfile() })));
189    }
190    }
191    else
192    {
193  0 al = new Alignment(preds);
194  0 FirstSeq = prediction.getQuerySeqPosition();
195  0 if (predMap != null)
196    {
197  0 char gc = getGapChar();
198  0 SequenceI[] sqs = (SequenceI[]) input
199    .getAlignmentAndHiddenColumns(gc)[0];
200  0 if (this.msaIndex >= sqs.length)
201    {
202  0 throw new Error(MessageManager.getString(
203    "error.implementation_error_invalid_msa_index_for_job"));
204    }
205   
206    // ///
207    // Uses RemoveGapsCommand
208    // ///
209  0 new jalview.commands.RemoveGapsCommand(
210    MessageManager.getString("label.remove_gaps"),
211    new SequenceI[]
212    { sqs[msaIndex] }, currentView);
213   
214  0 SequenceI profileseq = al.getSequenceAt(FirstSeq);
215  0 profileseq.setSequence(sqs[msaIndex].getSequenceAsString());
216    }
217   
218  0 if (!jalview.analysis.SeqsetUtils.SeqCharacterUnhash(
219    al.getSequenceAt(FirstSeq), (SequenceInfo)SequenceInfo))
220    {
221  0 throw (new Exception(MessageManager.getString(
222    "exception.couldnt_recover_sequence_props_for_jnet_query")));
223    }
224    else
225    {
226  0 if (currentView.getDataset() != null)
227    {
228  0 al.setDataset(currentView.getDataset());
229   
230    }
231    else
232    {
233  0 al.setDataset(null);
234    }
235  0 jalview.io.JnetAnnotationMaker.add_annotation(prediction, al,
236    FirstSeq, true, predMap);
237  0 SequenceI profileseq = al.getSequenceAt(0); // this includes any gaps.
238  0 alignToProfileSeq(al, profileseq);
239  0 if (predMap != null)
240    {
241    // Adjust input view for gaps
242    // propagate insertions into profile
243  0 alhidden = al.propagateInsertions(profileseq, input);
244    }
245    }
246    }
247    // transfer to dataset
248  0 for (AlignmentAnnotation alant : al.getAlignmentAnnotation())
249    {
250  0 if (alant.sequenceRef != null)
251    {
252  0 AlignmentAnnotationUtils.replaceAnnotationOnAlignmentWith(alant, alant.label,
253  0 "jalview.jws1.Jpred" + (this.msa == null ? "" : "MSA"),
254    alant.sequenceRef);
255    }
256    }
257  0 return new Object[] { al, alhidden }; // , FirstSeq, noMsa};
258    }
259   
260    /**
261    * Given an alignment where all other sequences except profileseq are
262    * aligned to the ungapped profileseq, insert gaps in the other sequences to
263    * realign them with the residues in profileseq
264    *
265    * @param al
266    * @param profileseq
267    */
 
268  0 toggle private void alignToProfileSeq(AlignmentI al, SequenceI profileseq)
269    {
270  0 char gc = al.getGapCharacter();
271  0 int[] gapMap = profileseq.gapMap();
272    // insert gaps into profile
273  0 for (int lp = 0, r = 0; r < gapMap.length; r++)
274    {
275  0 if (gapMap[r] - lp > 1)
276    {
277  0 StringBuffer sb = new StringBuffer();
278  0 for (int s = 0, ns = gapMap[r] - lp; s < ns; s++)
279    {
280  0 sb.append(gc);
281    }
282  0 for (int s = 1, ns = al.getHeight(); s < ns; s++)
283    {
284  0 String sq = al.getSequenceAt(s).getSequenceAsString();
285  0 int diff = gapMap[r] - sq.length();
286  0 if (diff > 0)
287    {
288    // pad gaps
289  0 sq = sq + sb;
290  0 while ((diff = gapMap[r] - sq.length()) > 0)
291    {
292  0 sq = sq + ((diff >= sb.length()) ? sb.toString()
293    : sb.substring(0, diff));
294    }
295  0 al.getSequenceAt(s).setSequence(sq);
296    }
297    else
298    {
299  0 al.getSequenceAt(s).setSequence(sq.substring(0, gapMap[r])
300    + sb.toString() + sq.substring(gapMap[r]));
301    }
302    }
303    }
304  0 lp = gapMap[r];
305    }
306    }
307   
 
308  0 toggle public JPredJob(Object SequenceInfo, SequenceI seq, int[] delMap)
309    {
310  0 super();
311  0 this.predMap = delMap;
312  0 String sq = AlignSeq.extractGaps(Comparison.GapChars,
313    seq.getSequenceAsString());
314  0 if (sq.length() >= 20)
315    {
316  0 this.SequenceInfo = SequenceInfo;
317  0 sequence = new vamsas.objects.simple.Sequence();
318  0 sequence.setId(seq.getName());
319  0 sequence.setSeq(sq);
320    }
321    else
322    {
323  0 errorMessage = "Sequence is too short to predict with JPred - need at least 20 amino acids.";
324    }
325    }
326   
 
327  0 toggle public JPredJob(Object SequenceInfo, SequenceI[] msf, int[] delMap)
328    {
329  0 this(SequenceInfo, msf[0], delMap);
330  0 if (sequence != null)
331    {
332  0 if (msf.length > 1)
333    {
334  0 msa = new vamsas.objects.simple.Msfalignment();
335  0 PileUpfile pileup = new PileUpfile();
336  0 msa.setMsf(pileup.print(msf, true));
337    }
338    }
339    }
340   
341    String errorMessage = "";
342   
 
343  0 toggle public String getValidationMessages()
344    {
345  0 return errorMessage + "\n";
346    }
347    }
348   
349    ext.vamsas.Jpred server;
350   
351    String altitle = "";
352   
 
353  0 toggle JPredThread(WebserviceInfo wsinfo, String altitle,
354    ext.vamsas.Jpred server, String wsurl, AlignmentView alview,
355    AlignFrame alframe)
356    {
357  0 super(alframe, wsinfo, alview, wsurl);
358  0 this.altitle = altitle;
359  0 this.server = server;
360    }
361   
 
362  0 toggle JPredThread(WebserviceInfo wsinfo, String altitle,
363    ext.vamsas.Jpred server, String wsurl, SequenceInfo SequenceInfo,
364    SequenceI seq, int[] delMap, AlignmentView alview,
365    AlignFrame alframe)
366    {
367  0 this(wsinfo, altitle, server, wsurl, alview, alframe);
368  0 JPredJob job = new JPredJob(SequenceInfo, seq, delMap);
369  0 if (job.hasValidInput())
370    {
371  0 OutputHeader = wsInfo.getProgressText();
372  0 jobs = new WSJob[] { job };
373  0 job.setJobnum(0);
374    }
375    else
376    {
377  0 wsInfo.appendProgressText(job.getValidationMessages());
378    }
379    }
380   
 
381  0 toggle JPredThread(WebserviceInfo wsinfo, String altitle,
382    ext.vamsas.Jpred server, Map<String, SequenceInfo> SequenceInfo,
383    SequenceI[] msf, int[] delMap, AlignmentView alview,
384    AlignFrame alframe, String wsurl)
385    {
386  0 this(wsinfo, altitle, server, wsurl, alview, alframe);
387  0 JPredJob job = new JPredJob(SequenceInfo, msf, delMap);
388  0 if (job.hasValidInput())
389    {
390  0 jobs = new WSJob[] { job };
391  0 OutputHeader = wsInfo.getProgressText();
392  0 job.setJobnum(0);
393    }
394    else
395    {
396  0 wsInfo.appendProgressText(job.getValidationMessages());
397    }
398    }
399   
 
400  0 toggle @Override
401    public void StartJob(AWsJob j)
402    {
403  0 if (!(j instanceof JPredJob))
404    {
405  0 throw new Error(MessageManager.formatMessage(
406    "error.implementation_error_startjob_called", new String[]
407    { j.getClass().toString() }));
408    }
409  0 try
410    {
411  0 JPredJob job = (JPredJob) j;
412  0 if (job.msa != null)
413    {
414  0 job.setJobId(server.predictOnMsa(job.msa));
415    }
416  0 else if (job.sequence != null)
417    {
418  0 job.setJobId(server.predict(job.sequence)); // debug like : job.jobId =
419    // "/jobs/www-jpred/jp_Yatat29";//
420    }
421   
422  0 if (job.getJobId() != null)
423    {
424  0 if (job.getJobId().startsWith("Broken"))
425    {
426  0 job.result = new JpredResult();
427  0 job.result.setInvalid(true);
428  0 job.result.setStatus(MessageManager
429    .formatMessage("label.submission_params", new String[]
430    { job.getJobId().toString() }));
431  0 throw new Exception(job.getJobId());
432    }
433    else
434    {
435  0 job.setSubmitted(true);
436  0 job.setSubjobComplete(false);
437  0 Console.info(WsUrl + " Job Id '" + job.getJobId() + "'");
438    }
439    }
440    else
441    {
442  0 throw new Exception(MessageManager
443    .getString("exception.server_timeout_try_later"));
444    }
445    } catch (Exception e)
446    {
447    // kill the whole job.
448  0 wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_SERVERERROR);
449  0 if (e.getMessage().indexOf("Exception") > -1)
450    {
451  0 wsInfo.setStatus(j.getJobnum(),
452    WebserviceInfo.STATE_STOPPED_SERVERERROR);
453  0 wsInfo.setProgressText(j.getJobnum(),
454    "Failed to submit the prediction. (Just close the window)\n"
455    + "It is most likely that there is a problem with the server.\n");
456  0 jalview.bin.Console.errPrintln(
457    "JPredWS Client: Failed to submit the prediction. Quite possibly because of a server error - see below)\n"
458    + e.getMessage() + "\n");
459   
460  0 Console.warn("Server Exception", e);
461    }
462    else
463    {
464  0 wsInfo.setStatus(j.getJobnum(), WebserviceInfo.STATE_STOPPED_ERROR);
465    // JBPNote - this could be a popup informing the user of the problem.
466  0 wsInfo.appendProgressText(j.getJobnum(),
467    MessageManager.formatMessage(
468    "info.failed_to_submit_prediction", new String[]
469    { e.getMessage(), wsInfo.getProgressText() }));
470   
471  0 Console.debug("Failed Submission of job " + j.getJobnum(), e);
472   
473    }
474  0 j.setAllowedServerExceptions(-1);
475  0 j.setSubjobComplete(true);
476    }
477    }
478   
 
479  0 toggle @Override
480    public void parseResult()
481    {
482  0 int results = 0; // number of result sets received
483  0 JobStateSummary finalState = new JobStateSummary();
484  0 try
485    {
486  0 for (int j = 0; j < jobs.length; j++)
487    {
488  0 finalState.updateJobPanelState(wsInfo, OutputHeader, jobs[j]);
489  0 if (jobs[j].isSubmitted() && jobs[j].isSubjobComplete()
490    && jobs[j].hasResults())
491    {
492  0 results++;
493    }
494    }
495    } catch (Exception ex)
496    {
497   
498  0 Console.error(
499    "Unexpected exception when processing results for " + altitle,
500    ex);
501  0 wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_ERROR);
502    }
503  0 if (results > 0)
504    {
505  0 wsInfo.showResultsNewFrame
506    .addActionListener(new java.awt.event.ActionListener()
507    {
 
508  0 toggle @Override
509    public void actionPerformed(java.awt.event.ActionEvent evt)
510    {
511  0 displayResults(true);
512    }
513    });
514  0 wsInfo.mergeResults
515    .addActionListener(new java.awt.event.ActionListener()
516    {
 
517  0 toggle @Override
518    public void actionPerformed(java.awt.event.ActionEvent evt)
519    {
520  0 displayResults(false);
521    }
522    });
523  0 wsInfo.setResultsReady();
524    }
525    else
526    {
527  0 wsInfo.setStatus(wsInfo.STATE_STOPPED_ERROR);
528  0 wsInfo.appendInfoText("No jobs ran.");
529  0 wsInfo.setFinishedNoResults();
530    }
531    }
532   
 
533  0 toggle void displayResults(boolean newWindow)
534    {
535    // TODO: cope with multiple subjobs.
536  0 if (jobs != null)
537    {
538  0 Object[] res = null;
539  0 boolean msa = false;
540  0 for (int jn = 0; jn < jobs.length; jn++)
541    {
542  0 Object[] jobres = null;
543  0 JPredJob j = (JPredJob) jobs[jn];
544   
545  0 if (j.hasResults())
546    {
547    // hack - we only deal with all single seuqence predictions or all
548    // profile predictions
549  0 msa = (j.msa != null) ? true : msa;
550  0 try
551    {
552  0 Console.debug("Parsing output of job " + jn);
553  0 jobres = j.getResultSet();
554  0 Console.debug("Finished parsing output.");
555  0 if (jobs.length == 1)
556    {
557  0 res = jobres;
558    }
559    else
560    {
561    // do merge with other job results
562  0 throw new Error(MessageManager.getString(
563    "error.multiple_jnet_subjob_merge_not_implemented"));
564    }
565    } catch (Exception e)
566    {
567  0 Console.error("JNet Client: JPred Annotation Parse Error", e);
568  0 wsInfo.setStatus(j.getJobnum(),
569    WebserviceInfo.STATE_STOPPED_ERROR);
570  0 wsInfo.appendProgressText(j.getJobnum(),
571    MessageManager.formatMessage(
572    "info.invalid_jnet_job_result_data",
573    new String[]
574    { OutputHeader.toString(), j.result.getStatus(),
575    e.getMessage() }));
576  0 j.result.setBroken(true);
577    }
578    }
579    }
580   
581  0 if (res != null)
582    {
583  0 if (newWindow)
584    {
585  0 AlignFrame af;
586  0 ((AlignmentI) res[0])
587    .setSeqrep(((AlignmentI) res[0]).getSequenceAt(0));
588  0 if (input == null)
589    {
590  0 if (res[1] != null)
591    {
592  0 af = new AlignFrame((Alignment) res[0],
593    (HiddenColumns) res[1], AlignFrame.DEFAULT_WIDTH,
594    AlignFrame.DEFAULT_HEIGHT);
595    }
596    else
597    {
598  0 af = new AlignFrame((Alignment) res[0],
599    AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT);
600    }
601    }
602    else
603    {
604    /*
605    * java.lang.Object[] alandcolsel =
606    * input.getAlignmentAndColumnSelection
607    * (alignFrame.getViewport().getGapCharacter()); if
608    * (((SequenceI[])alandcolsel[0])[0].getLength()!=res.getWidth()) {
609    * if (msa) { throw new Error("Implementation Error! ColumnSelection
610    * from input alignment will not map to result alignment!"); } } if
611    * (!msa) { // update hidden regions to account for loss of gaps in
612    * profile. - if any // gapMap returns insert list, interpreted as
613    * delete list by pruneDeletions //((ColumnSelection)
614    * alandcolsel[1]).pruneDeletions(ShiftList.parseMap(((SequenceI[])
615    * alandcolsel[0])[0].gapMap())); }
616    */
617   
618  0 af = new AlignFrame((Alignment) res[0], (HiddenColumns) res[1],
619    AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT);
620    }
621  0 Desktop.addInternalFrame(af, altitle, AlignFrame.DEFAULT_WIDTH,
622    AlignFrame.DEFAULT_HEIGHT);
623    }
624    else
625    {
626  0 Console.info("Append results onto existing alignment.");
627    }
628    }
629    }
630    }
631   
 
632  0 toggle @Override
633    public void pollJob(AWsJob job) throws Exception
634    {
635  0 ((JPredJob) job).result = server.getresult(job.getJobId());
636    }
637   
 
638  0 toggle @Override
639    public boolean isCancellable()
640    {
641  0 return false;
642    }
643   
 
644  0 toggle @Override
645    public void cancelJob()
646    {
647  0 throw new Error(MessageManager.getString("error.implementation_error"));
648    }
649   
 
650  0 toggle @Override
651    public boolean canMergeResults()
652    {
653  0 return false;
654    }
655   
656    }