1 package jalview.ws.jws2;
3 import static java.lang.String.format;
5 import java.util.Hashtable;
8 import jalview.analysis.SeqsetUtils;
9 import jalview.bin.Cache;
10 import jalview.commands.RemoveGapsCommand;
11 import jalview.datamodel.Alignment;
12 import jalview.datamodel.AlignmentAnnotation;
13 import jalview.datamodel.AlignmentI;
14 import jalview.datamodel.AlignmentView;
15 import jalview.datamodel.HiddenColumns;
16 import jalview.datamodel.SequenceI;
17 import jalview.gui.AlignFrame;
18 import jalview.gui.Desktop;
19 import jalview.gui.WebserviceInfo;
20 import jalview.io.JPredFile;
21 import jalview.io.JnetAnnotationMaker;
22 import jalview.util.MessageManager;
23 import jalview.ws.AWSThread;
24 import jalview.ws.AWsJob;
25 import jalview.ws.JobStateSummary;
26 import jalview.ws.WSClientI;
27 import jalview.ws.api.CancellableI;
28 import jalview.ws.api.JPredServiceI;
29 import jalview.ws.gui.WsJob;
30 import jalview.ws.gui.WsJob.JobState;
33 public class JPredThread extends AWSThread implements WSClientI
36 private static class JPredJob extends WsJob
38 private final Hashtable<?, ?> sequenceInfo;
39 private final List<SequenceI> msf;
40 private final int[] delMap;
41 private AlignmentI alignment = null;
42 private HiddenColumns hiddenCols = null;
44 private JPredJob(Hashtable<?, ?> sequenceInfo, SequenceI[] msf, int[] delMap)
46 this.sequenceInfo = sequenceInfo;
47 this.msf = List.of(msf);
52 public boolean hasValidInput()
58 public boolean hasResults()
60 return (isSubjobComplete() && alignment != null);
63 public boolean isMSA()
65 return msf.size() > 1;
70 private JPredServiceI server;
72 private Hashtable<?, ?> sequenceInfo;
73 private SequenceI[] msf;
76 public JPredThread(WebserviceInfo wsInfo, String title,
77 JPredServiceI server, Hashtable<?, ?> sequenceInfo,
78 SequenceI[] msf, int[] delMap, AlignmentView view, AlignFrame frame,
81 super(frame, wsInfo, view, wsURL);
84 this.sequenceInfo = sequenceInfo;
87 JPredJob job = new JPredJob(sequenceInfo, msf, delMap);
88 this.jobs = new JPredJob[] { job };
92 public boolean isCancellable()
94 return server instanceof CancellableI;
98 public boolean canMergeResults()
104 public void cancelJob()
106 // TODO Auto-generated method stub
111 public void pollJob(AWsJob job_) throws Exception
113 var job = (JPredJob) job_;
114 server.updateStatus(job);
115 server.updateJobProgress(job);
119 public void StartJob(AWsJob job_)
121 if (!(job_ instanceof JPredJob))
122 throw new RuntimeException("Invalid job type");
123 var job = (JPredJob) job_;
124 if (job.isSubmitted())
131 var jobHandle = server.predict(job.msf, job.isMSA());
132 if (jobHandle != null)
133 job.setJobHandle(jobHandle);
135 catch (Throwable th) {
136 if (!server.handleSubmitError(th, job, wsInfo)) {
140 if (job.getJobId() != null) {
141 job.setSubmitted(true);
142 job.setSubjobComplete(false);
146 throw new Exception(MessageManager.formatMessage(
147 "exception.web_service_returned_null_try_later",
154 // For unexpected errors
155 System.err.println(WebServiceName
156 + "Client: Failed to submit the sequences for alignment (probably a server side problem)\n"
157 + "When contacting Server:" + WsUrl + "\n");
158 th.printStackTrace(System.err);
159 wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_SERVERERROR);
160 wsInfo.setStatus(job.getJobnum(),
161 WebserviceInfo.STATE_STOPPED_SERVERERROR);
166 if (!job.isSubmitted())
168 job.setAllowedServerExceptions(0);
169 wsInfo.appendProgressText(job.getJobnum(), MessageManager.getString(
170 "info.failed_to_submit_sequences_for_alignment"));
176 public void parseResult()
178 long progbar = (long) (Math.random() * ~(1L << 63));
179 wsInfo.setProgressBar(
180 MessageManager.getString("status.collecting_job_results"), progbar);
182 var finalState = new JobStateSummary();
185 for (int i = 0; i < jobs.length; i++) {
186 final var job = (JPredJob) jobs[i];
187 finalState.updateJobPanelState(wsInfo, OutputHeader, job);
188 if (job.isFinished()) {
190 server.updateJobProgress(job);
192 catch (Exception e) {
193 Cache.log.warn(format(
194 "Exception when retrieving remaining Job progress data " +
195 "for job %s on server %s", job.getJobId(), WsUrl));
198 // removed the waiting loop
199 Cache.log.debug(format("Job Execution file for job: %s " +
200 "on server %s%n%s", job.getJobId(), WsUrl, job.getStatus()));
202 prepareJobResult(job);
204 catch (Exception e) {
205 if (!server.handleCollectionException(e, job, wsInfo)) {
206 Cache.log.error("Could not get alignment for job.", e);
207 job.setState(JobState.SERVERERROR);
211 finalState.updateJobPanelState(wsInfo, OutputHeader, job);
212 if (job.isSubmitted() && job.isSubjobComplete() && job.hasResults()) {
217 catch (Exception e) {
219 "Unexpected exception when processing results for " + title, e);
220 wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_ERROR);
223 wsInfo.showResultsNewFrame.addActionListener(
224 (evt) -> displayResults(true));
225 wsInfo.mergeResults.addActionListener(
226 (evt) -> displayResults(false));
227 wsInfo.setResultsReady();
230 wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_ERROR);
231 wsInfo.appendInfoText("No jobs ran.");
232 wsInfo.setFinishedNoResults();
234 updateGlobalStatus(finalState);
235 wsInfo.removeProgressBar(progbar);
238 static final int msaIndex = 0;
240 private void prepareJobResult(JPredJob job) throws Exception
242 HiddenColumns hiddenCols = null;
244 AlignmentI alignment;
245 var prediction = server.getPrediction(job.getJobHandle());
246 var preds = prediction.getSeqsAsArray();
248 if (job.msf.size() > 1)
250 if (job.delMap != null)
252 Object[] alandcolsel = input
253 .getAlignmentAndHiddenColumns(getGapChar());
254 alignment = new Alignment((SequenceI[]) alandcolsel[0]);
255 hiddenCols = (HiddenColumns) alandcolsel[1];
259 alignment = server.getAlignment(job.getJobHandle());
260 var seqs = new SequenceI[alignment.getHeight()];
261 for (int i = 0; i < alignment.getHeight(); i++)
263 seqs[i] = alignment.getSequenceAt(i);
265 if (!SeqsetUtils.deuniquify(sequenceInfo, seqs))
267 throw (new Exception(MessageManager.getString(
268 "exception.couldnt_recover_sequence_properties_for_alignment")));
272 if (currentView.getDataset() != null)
274 alignment.setDataset(currentView.getDataset());
278 alignment.setDataset(null);
280 JnetAnnotationMaker.add_annotation(prediction, alignment, firstSeq, false,
285 alignment = new Alignment(preds);
286 firstSeq = prediction.getQuerySeqPosition();
287 if (job.delMap != null)
289 Object[] alanndcolsel = input.getAlignmentAndHiddenColumns(getGapChar());
290 SequenceI[] seqs = (SequenceI[]) alanndcolsel[0];
291 new RemoveGapsCommand(MessageManager.getString("label.remove_gaps"),
292 new SequenceI[] {seqs[msaIndex]}, currentView);
293 SequenceI profileSeq = alignment.getSequenceAt(firstSeq);
294 profileSeq.setSequence(seqs[msaIndex].getSequenceAsString());
296 if (!SeqsetUtils.SeqCharacterUnhash(
297 alignment.getSequenceAt(firstSeq), sequenceInfo))
299 throw new Exception(MessageManager.getString(
300 "exception.couldnt_recover_sequence_props_for_jnet_query"));
302 alignment.setDataset(currentView.getDataset());
303 JnetAnnotationMaker.add_annotation(prediction, alignment, firstSeq, true,
305 SequenceI profileSeq = alignment.getSequenceAt(0);
306 alignToProfileSeq(alignment, profileSeq);
307 if (job.delMap != null)
309 hiddenCols = alignment.propagateInsertions(profileSeq, input);
313 for (var annot : alignment.getAlignmentAnnotation())
315 if (annot.sequenceRef != null)
317 replaceAnnotationOnAlignmentWith(annot, annot.label,
318 "jalview.ws.JPred", annot.sequenceRef);
321 job.alignment = alignment;
322 job.hiddenCols = hiddenCols;
325 private static void replaceAnnotationOnAlignmentWith(
326 AlignmentAnnotation newAnnot, String typeName, String calcId,
329 SequenceI dsseq = aSeq.getDatasetSequence();
330 while (dsseq.getDatasetSequence() != null)
332 dsseq = dsseq.getDatasetSequence();
334 // look for same annotation on dataset and lift this one over
335 List<AlignmentAnnotation> dsan = dsseq.getAlignmentAnnotations(calcId,
337 if (dsan != null && dsan.size() > 0)
339 for (AlignmentAnnotation dssan : dsan)
341 dsseq.removeAlignmentAnnotation(dssan);
344 AlignmentAnnotation dssan = new AlignmentAnnotation(newAnnot);
345 dsseq.addAlignmentAnnotation(dssan);
346 dssan.adjustForAlignment();
349 private static void alignToProfileSeq(AlignmentI al, SequenceI profileseq)
351 char gc = al.getGapCharacter();
352 int[] gapMap = profileseq.gapMap();
353 // insert gaps into profile
354 for (int lp = 0, r = 0; r < gapMap.length; r++)
356 if (gapMap[r] - lp > 1)
358 StringBuffer sb = new StringBuffer();
359 for (int s = 0, ns = gapMap[r] - lp; s < ns; s++)
363 for (int s = 1, ns = al.getHeight(); s < ns; s++)
365 String sq = al.getSequenceAt(s).getSequenceAsString();
366 int diff = gapMap[r] - sq.length();
371 while ((diff = gapMap[r] - sq.length()) > 0)
373 sq = sq + ((diff >= sb.length()) ? sb.toString()
374 : sb.substring(0, diff));
376 al.getSequenceAt(s).setSequence(sq);
380 al.getSequenceAt(s).setSequence(sq.substring(0, gapMap[r])
381 + sb.toString() + sq.substring(gapMap[r]));
389 private void displayResults(boolean newWindow)
391 if (jobs == null || jobs.length == 0)
395 var job = (JPredJob) jobs[0];
396 if (job.hasResults() && newWindow)
398 job.alignment.setSeqrep(job.alignment.getSequenceAt(0));
399 AlignFrame frame = new AlignFrame(job.alignment, job.hiddenCols,
400 AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT);
401 Desktop.addInternalFrame(frame, title, AlignFrame.DEFAULT_WIDTH,
402 AlignFrame.DEFAULT_HEIGHT);