Clover icon

Coverage Report

  1. Project Clover database Wed Nov 12 2025 09:00:47 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
650
522
76
0.39
10.16
9.5
4

Classes

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