package jalview.ws2.gui; import java.util.List; import javax.swing.SwingUtilities; import jalview.bin.Console; import jalview.datamodel.Alignment; import jalview.datamodel.AlignmentAnnotation; import jalview.datamodel.AlignmentI; import jalview.datamodel.HiddenColumns; import jalview.gui.AlignFrame; import jalview.gui.Desktop; import jalview.gui.JvOptionPane; import jalview.gui.WebserviceInfo; import jalview.util.ArrayUtils; import jalview.util.MessageManager; import jalview.ws2.actions.api.ActionI; import jalview.ws2.actions.api.JobI; import jalview.ws2.actions.api.TaskEventListener; import jalview.ws2.actions.api.TaskI; import jalview.ws2.api.JobStatus; import jalview.ws2.api.WebService; import jalview.ws2.helpers.WSClientTaskWrapper; import static java.lang.String.format; class SearchServiceGuiHandler implements TaskEventListener { private final AlignFrame parentFrame; private final ActionI action; private final WebService service; private WebserviceInfo infoPanel; private JobI[] jobs = new JobI[0]; private int[] tabs = new int[0]; private int[] logOffset = new int[0]; private int[] errLogOffset = new int[0]; public SearchServiceGuiHandler(ActionI action, AlignFrame parentFrame) { this.parentFrame = parentFrame; this.action = action; this.service = action.getWebService(); var info = String.format("%s search using service at %s%n%s", service.getName(), service.getUrl(), service.getDescription()); this.infoPanel = new WebserviceInfo(service.getName(), info, false); } @Override public void taskStarted(TaskI source, List subJobs) { Console.debug(format("task %s#%x started with %d sub-jobs", service.getName(), source.getUid(), subJobs.size())); jobs = subJobs.toArray(new JobI[subJobs.size()]); tabs = new int[subJobs.size()]; logOffset = new int[subJobs.size()]; errLogOffset = new int[subJobs.size()]; for (int i = 0; i < subJobs.size(); i++) { JobI job = jobs[i]; int tabIndex = infoPanel.addJobPane(); tabs[i] = tabIndex; infoPanel.setProgressName(format("region %d", i), tabIndex); infoPanel.setProgressText(tabIndex, "Job details:\n"); // jobs should not have states other than invalid or ready at this point if (job.getStatus() == JobStatus.INVALID) infoPanel.setStatus(tabIndex, WebserviceInfo.STATE_STOPPED_OK); else if (job.getStatus() == JobStatus.READY) infoPanel.setStatus(tabIndex, WebserviceInfo.STATE_QUEUING); } } @Override public void taskStatusChanged(TaskI source, JobStatus status) { Console.debug(format("task %s#%x status changed to %s", service.getName(), source.getUid(), status)); switch (status) { case INVALID: infoPanel.setVisible(false); JvOptionPane.showMessageDialog(parentFrame, MessageManager.getString("info.invalid_search_input"), MessageManager.getString("info.invalid_search_input"), JvOptionPane.INFORMATION_MESSAGE); break; case READY: infoPanel.setthisService(new WSClientTaskWrapper(source)); infoPanel.setVisible(true); // intentional no break case SUBMITTED: case QUEUED: infoPanel.setStatus(WebserviceInfo.STATE_QUEUING); break; case RUNNING: case UNKNOWN: // unsure what to do with unknown infoPanel.setStatus(WebserviceInfo.STATE_RUNNING); break; case COMPLETED: infoPanel.setProgressBar( MessageManager.getString("status.collecting_job_results"), jobs[0].getInternalId()); infoPanel.setStatus(WebserviceInfo.STATE_STOPPED_OK); break; case FAILED: infoPanel.removeProgressBar(jobs[0].getInternalId()); infoPanel.setStatus(WebserviceInfo.STATE_STOPPED_ERROR); break; case CANCELLED: infoPanel.setStatus(WebserviceInfo.STATE_CANCELLED_OK); break; case SERVER_ERROR: infoPanel.removeProgressBar(jobs[0].getInternalId()); infoPanel.setStatus(WebserviceInfo.STATE_STOPPED_SERVERERROR); break; } } @Override public void taskCompleted(TaskI source, AlignmentI result) { Console.debug(format("task %s#%x completed", service.getName(), source.getUid())); SwingUtilities.invokeLater( () -> infoPanel.removeProgressBar(jobs[0].getInternalId())); if (result == null) { SwingUtilities.invokeLater(infoPanel::setFinishedNoResults); return; } infoPanel.showResultsNewFrame.addActionListener(evt -> { // copy alignment for each frame to have its own instance var alnCpy = new Alignment(result); alnCpy.setGapCharacter(result.getGapCharacter()); alnCpy.setDataset(result.getDataset()); for (AlignmentAnnotation annotation : result.getAlignmentAnnotation()) alnCpy.addAnnotation(new AlignmentAnnotation(annotation)); if (result.hasSeqrep()) { int idx = result.findIndex(result.getSeqrep()); if (idx >= 0) alnCpy.setSeqrep(alnCpy.getSequenceAt(idx)); } if (result.getHiddenColumns() != null) alnCpy.setHiddenColumns(new HiddenColumns(result.getHiddenColumns())); displayResultsNewFrame(alnCpy); }); SwingUtilities.invokeLater(infoPanel::setResultsReady); } private void displayResultsNewFrame(AlignmentI aln) { AlignFrame frame = new AlignFrame(aln, AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT); frame.getFeatureRenderer().transferSettings( parentFrame.getFeatureRenderer().getSettings()); var actionName = action.getName() != null ? action.getName() : "Search"; var title = String.format("%s %s of %s", service.getName(), actionName, parentFrame.getTitle()); Desktop.addInternalFrame(frame, title, AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT); } @Override public void taskException(TaskI source, Exception e) { Console.error(format("Task %s#%x raised an exception.", service.getName(), source.getUid()), e); infoPanel.appendProgressText(e.getMessage()); } @Override public void subJobStatusChanged(TaskI source, JobI job, JobStatus status) { Console.debug(format("sub-job %x status changed to %s", job.getInternalId(), status)); int i = ArrayUtils.indexOf(jobs, job); assert i >= 0 : "job does not exist"; if (i < 0) // safeguard that should not happen irl return; int wsStatus; switch (status) { case INVALID: case COMPLETED: wsStatus = WebserviceInfo.STATE_STOPPED_OK; break; case READY: case SUBMITTED: case QUEUED: wsStatus = WebserviceInfo.STATE_QUEUING; break; case RUNNING: case UNKNOWN: wsStatus = WebserviceInfo.STATE_RUNNING; break; case FAILED: wsStatus = WebserviceInfo.STATE_STOPPED_ERROR; break; case CANCELLED: wsStatus = WebserviceInfo.STATE_CANCELLED_OK; break; case SERVER_ERROR: wsStatus = WebserviceInfo.STATE_STOPPED_SERVERERROR; break; default: throw new AssertionError("Non-exhaustive switch statement"); } infoPanel.setStatus(tabs[i], wsStatus); } @Override public void subJobLogChanged(TaskI source, JobI job, String log) { int i = ArrayUtils.indexOf(jobs, job); assert i >= 0 : "job does not exist"; if (i < 0) // safeguard that should never happen return; infoPanel.appendProgressText(tabs[i], log.substring(logOffset[i])); } @Override public void subJobErrorLogChanged(TaskI source, JobI job, String log) { int i = ArrayUtils.indexOf(jobs, job); assert i >= 0 : "job does not exist"; if (i < 0) // safeguard that should never happen return; infoPanel.appendProgressText(tabs[i], log.substring(errLogOffset[i])); } }