package jalview.ws.jws2; import static java.lang.String.format; import java.util.Hashtable; import java.util.List; import jalview.analysis.SeqsetUtils; import jalview.bin.Cache; import jalview.datamodel.Alignment; import jalview.datamodel.AlignmentAnnotation; import jalview.datamodel.AlignmentI; import jalview.datamodel.AlignmentView; import jalview.datamodel.HiddenColumns; import jalview.datamodel.SequenceI; import jalview.gui.AlignFrame; import jalview.gui.Desktop; import jalview.gui.WebserviceInfo; import jalview.io.JPredFile; import jalview.io.JnetAnnotationMaker; import jalview.util.MessageManager; import jalview.ws.AWSThread; import jalview.ws.AWsJob; import jalview.ws.JobStateSummary; import jalview.ws.WSClientI; import jalview.ws.api.CancellableI; import jalview.ws.api.JPredMutlipleAlignmentServiceI; import jalview.ws.gui.WsJob; import jalview.ws.gui.WsJob.JobState; class JPredJob extends WsJob { Hashtable sequenceInfo; List msf; int[] delMap; AlignmentI alignment = null; HiddenColumns hiddenCols = null; public JPredJob(Hashtable sequenceInfo, SequenceI[] msf, int[] delMap) { this.sequenceInfo = sequenceInfo; this.msf = List.of(msf); this.delMap = delMap; } @Override public boolean hasValidInput() { return true; } @Override public boolean hasResults() { return (isSubjobComplete() && alignment != null); } } public class JPredThread extends AWSThread implements WSClientI { private JPredMutlipleAlignmentServiceI server; private String title; private Hashtable sequenceInfo; private SequenceI[] msf; private int[] delMap; public JPredThread(WebserviceInfo wsInfo, String title, JPredMutlipleAlignmentServiceI server, Hashtable sequenceInfo, SequenceI[] msf, int[] delMap, AlignmentView view, AlignFrame frame, String wsURL) { super(frame, wsInfo, view, wsURL); this.server = server; this.title = title; this.sequenceInfo = sequenceInfo; this.msf = msf; this.delMap = delMap; JPredJob job = new JPredJob(sequenceInfo, msf, delMap); this.jobs = new JPredJob[] { job }; } @Override public boolean isCancellable() { return server instanceof CancellableI; } @Override public boolean canMergeResults() { return false; } @Override public void cancelJob() { // TODO Auto-generated method stub } @Override public void pollJob(AWsJob job_) throws Exception { var job = (JPredJob) job_; server.updateStatus(job); server.updateJobProgress(job); } @Override public void StartJob(AWsJob job_) { if (!(job_ instanceof JPredJob)) throw new RuntimeException("Invalid job type"); var job = (JPredJob) job_; if (job.isSubmitted()) { return; } try { try { var jobHandle = server.align(job.msf); if (jobHandle != null) job.setJobHandle(jobHandle); } catch (Throwable th) { if (!server.handleSubmitError(th, job, wsInfo)) { throw th; } } if (job.getJobId() != null) { job.setSubmitted(true); job.setSubjobComplete(false); return; } else { throw new Exception(MessageManager.formatMessage( "exception.web_service_returned_null_try_later", new String[] { WsUrl })); } } catch (Throwable th) { // For unexpected errors System.err.println(WebServiceName + "Client: Failed to submit the sequences for alignment (probably a server side problem)\n" + "When contacting Server:" + WsUrl + "\n"); th.printStackTrace(System.err); wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_SERVERERROR); wsInfo.setStatus(job.getJobnum(), WebserviceInfo.STATE_STOPPED_SERVERERROR); } finally { if (!job.isSubmitted()) { job.setAllowedServerExceptions(0); wsInfo.appendProgressText(job.getJobnum(), MessageManager.getString( "info.failed_to_submit_sequences_for_alignment")); } } } @Override public void parseResult() { long progbar = (long) (Math.random() * ~(1L << 63)); wsInfo.setProgressBar( MessageManager.getString("status.collecting_job_results"), progbar); int results = 0; var finalState = new JobStateSummary(); try { for (int i = 0; i < jobs.length; i++) { final var job = (JPredJob) jobs[i]; finalState.updateJobPanelState(wsInfo, OutputHeader, job); if (job.isFinished()) { try { server.updateJobProgress(job); } catch (Exception e) { Cache.log.warn(format( "Exception when retrieving remaining Job progress data " + "for job %s on server %s", job.getJobId(), WsUrl)); e.printStackTrace(); } // removed the waiting loop Cache.log.debug(format("Job Execution file for job: %s " + "on server %s%n%s", job.getJobId(), WsUrl, job.getStatus())); try { prepareJobResult(job); } catch (Exception e) { if (!server.handleCollectionException(e, job, wsInfo)) { Cache.log.error("Could not get alignment for job.", e); job.setState(JobState.SERVERERROR); } } } finalState.updateJobPanelState(wsInfo, OutputHeader, job); if (job.isSubmitted() && job.isSubjobComplete() && job.hasResults()) { results++; } } } catch (Exception e) { Cache.log.error( "Unexpected exception when processing results for " + title, e); wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_ERROR); } if (results > 0) { wsInfo.showResultsNewFrame.addActionListener( (evt) -> displayResults(true)); wsInfo.mergeResults.addActionListener( (evt) -> displayResults(false)); wsInfo.setResultsReady(); } else { wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_ERROR); wsInfo.appendInfoText("No jobs ran."); wsInfo.setFinishedNoResults(); } updateGlobalStatus(finalState); wsInfo.removeProgressBar(progbar); } private void prepareJobResult(JPredJob job) throws Exception { HiddenColumns hiddenCols = null; int firstSeq = -1; AlignmentI alignment; var prediction = server.getPrediction(job.getJobHandle()); var preds = prediction.getSeqsAsArray(); if (job.delMap != null) { Object[] alandcolsel = input .getAlignmentAndHiddenColumns(getGapChar()); alignment = new Alignment((SequenceI[]) alandcolsel[0]); hiddenCols = (HiddenColumns) alandcolsel[1]; } else { alignment = server.getAlignment(job.getJobHandle()); var seqs = new SequenceI[alignment.getHeight()]; for (int i = 0; i < alignment.getHeight(); i++) { seqs[i] = alignment.getSequenceAt(i); } if (!SeqsetUtils.deuniquify(sequenceInfo, seqs)) { throw (new Exception(MessageManager.getString( "exception.couldnt_recover_sequence_properties_for_alignment"))); } } firstSeq = 0; if (currentView.getDataset() != null) { alignment.setDataset(currentView.getDataset()); } else { alignment.setDataset(null); } JnetAnnotationMaker.add_annotation(prediction, alignment, firstSeq, false, job.delMap); for (var annot : alignment.getAlignmentAnnotation()) { if (annot.sequenceRef != null) { replaceAnnotationOnAlignmentWith(annot, annot.label, "jalview.ws.JPred", annot.sequenceRef); } } job.alignment = alignment; job.hiddenCols = hiddenCols; } private static void replaceAnnotationOnAlignmentWith( AlignmentAnnotation newAnnot, String typeName, String calcId, SequenceI aSeq) { SequenceI dsseq = aSeq.getDatasetSequence(); while (dsseq.getDatasetSequence() != null) { dsseq = dsseq.getDatasetSequence(); } // look for same annotation on dataset and lift this one over List dsan = dsseq.getAlignmentAnnotations(calcId, typeName); if (dsan != null && dsan.size() > 0) { for (AlignmentAnnotation dssan : dsan) { dsseq.removeAlignmentAnnotation(dssan); } } AlignmentAnnotation dssan = new AlignmentAnnotation(newAnnot); dsseq.addAlignmentAnnotation(dssan); dssan.adjustForAlignment(); } private void displayResults(boolean newWindow) { if (jobs == null || jobs.length == 0) { return; } var job = (JPredJob) jobs[0]; if (job.hasResults() && newWindow) { AlignFrame frame; job.alignment.setSeqrep(job.alignment.getSequenceAt(0)); frame = new AlignFrame(job.alignment, job.hiddenCols, AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT); Desktop.addInternalFrame(frame, title, AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT); } } }