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.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;
-public class SearchServiceGuiHandler implements TaskEventListener<AlignmentI>
+class SearchServiceGuiHandler implements TaskEventListener<AlignmentI>
{
private final AlignFrame parentFrame;
-
- public SearchServiceGuiHandler(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<AlignmentI> source,
List<? extends JobI> subJobs)
{
- Console.info("task started with " + subJobs.size() + " jobs");
- // TODO Auto-generated method stub
-
+ 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<AlignmentI> source, JobStatus status)
{
- Console.info("task status " + status);
- // TODO Auto-generated method stub
-
+ 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<AlignmentI> source, AlignmentI result)
{
- Console.info("task completed");
- displayResultsNewFrame(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));
+ 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<AlignmentI> source, Exception e)
{
- Console.info("task failed", e);
- // TODO Auto-generated method stub
-
+ Console.error(format("Task %s#%x raised an exception.",
+ service.getName(), source.getUid()), e);
+ infoPanel.appendProgressText(e.getMessage());
}
@Override
public void taskRestarted(TaskI<AlignmentI> source)
{
- Console.info("task restarted");
- // TODO Auto-generated method stub
-
+ // search services non-restartable
}
@Override
public void subJobStatusChanged(TaskI<AlignmentI> source, JobI job,
JobStatus status)
{
- Console.info("sub-job " + job.getInternalId() + " status " + status);
- // TODO Auto-generated method stub
-
+ 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<AlignmentI> source, JobI job,
String log)
{
- // TODO Auto-generated method stub
-
+ 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<AlignmentI> source, JobI job,
String log)
{
- // TODO Auto-generated method stub
-
- }
-
- private void displayResultsNewFrame(AlignmentI aln)
- {
- AlignFrame frame = new AlignFrame(aln, AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT);
- frame.getFeatureRenderer().transferSettings(
- parentFrame.getFeatureRenderer().getSettings());
- Desktop.addInternalFrame(frame, "title", AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT);
+ 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]));
}
}