X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=src%2Fjalview%2Fws%2Fjws2%2FJPredThread.java;fp=src%2Fjalview%2Fws%2Fjws2%2FJPredThread.java;h=d10ca8a82751868e64328ad63a65e2aaf8941482;hb=eb6d7c560434c986f1dc76f6243d1493688f397e;hp=0000000000000000000000000000000000000000;hpb=e1ec9d45cb7e3c1e5258dd8135a269dab535cde3;p=jalview.git diff --git a/src/jalview/ws/jws2/JPredThread.java b/src/jalview/ws/jws2/JPredThread.java new file mode 100644 index 0000000..d10ca8a --- /dev/null +++ b/src/jalview/ws/jws2/JPredThread.java @@ -0,0 +1,406 @@ +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.commands.RemoveGapsCommand; +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.JPredServiceI; +import jalview.ws.gui.WsJob; +import jalview.ws.gui.WsJob.JobState; + + +public class JPredThread extends AWSThread implements WSClientI +{ + + private static class JPredJob extends WsJob + { + private final Hashtable sequenceInfo; + private final List msf; + private final int[] delMap; + private AlignmentI alignment = null; + private HiddenColumns hiddenCols = null; + + private 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 boolean isMSA() + { + return msf.size() > 1; + } + } + + + private JPredServiceI server; + private String title; + private Hashtable sequenceInfo; + private SequenceI[] msf; + private int[] delMap; + + public JPredThread(WebserviceInfo wsInfo, String title, + JPredServiceI 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.predict(job.msf, job.isMSA()); + 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); + } + + static final int msaIndex = 0; + + 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.msf.size() > 1) + { + 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); + } + else + { + alignment = new Alignment(preds); + firstSeq = prediction.getQuerySeqPosition(); + if (job.delMap != null) + { + Object[] alanndcolsel = input.getAlignmentAndHiddenColumns(getGapChar()); + SequenceI[] seqs = (SequenceI[]) alanndcolsel[0]; + new RemoveGapsCommand(MessageManager.getString("label.remove_gaps"), + new SequenceI[] {seqs[msaIndex]}, currentView); + SequenceI profileSeq = alignment.getSequenceAt(firstSeq); + profileSeq.setSequence(seqs[msaIndex].getSequenceAsString()); + } + if (!SeqsetUtils.SeqCharacterUnhash( + alignment.getSequenceAt(firstSeq), sequenceInfo)) + { + throw new Exception(MessageManager.getString( + "exception.couldnt_recover_sequence_props_for_jnet_query")); + } + alignment.setDataset(currentView.getDataset()); + JnetAnnotationMaker.add_annotation(prediction, alignment, firstSeq, true, + job.delMap); + SequenceI profileSeq = alignment.getSequenceAt(0); + alignToProfileSeq(alignment, profileSeq); + if (job.delMap != null) + { + hiddenCols = alignment.propagateInsertions(profileSeq, input); + } + } + + 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 static void alignToProfileSeq(AlignmentI al, SequenceI profileseq) + { + char gc = al.getGapCharacter(); + int[] gapMap = profileseq.gapMap(); + // insert gaps into profile + for (int lp = 0, r = 0; r < gapMap.length; r++) + { + if (gapMap[r] - lp > 1) + { + StringBuffer sb = new StringBuffer(); + for (int s = 0, ns = gapMap[r] - lp; s < ns; s++) + { + sb.append(gc); + } + for (int s = 1, ns = al.getHeight(); s < ns; s++) + { + String sq = al.getSequenceAt(s).getSequenceAsString(); + int diff = gapMap[r] - sq.length(); + if (diff > 0) + { + // pad gaps + sq = sq + sb; + while ((diff = gapMap[r] - sq.length()) > 0) + { + sq = sq + ((diff >= sb.length()) ? sb.toString() + : sb.substring(0, diff)); + } + al.getSequenceAt(s).setSequence(sq); + } + else + { + al.getSequenceAt(s).setSequence(sq.substring(0, gapMap[r]) + + sb.toString() + sq.substring(gapMap[r])); + } + } + } + lp = gapMap[r]; + } + } + + private void displayResults(boolean newWindow) + { + if (jobs == null || jobs.length == 0) + { + return; + } + var job = (JPredJob) jobs[0]; + if (job.hasResults() && newWindow) + { + job.alignment.setSeqrep(job.alignment.getSequenceAt(0)); + AlignFrame frame = new AlignFrame(job.alignment, job.hiddenCols, + AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT); + Desktop.addInternalFrame(frame, title, AlignFrame.DEFAULT_WIDTH, + AlignFrame.DEFAULT_HEIGHT); + } + } + +}