49df4662b49f8c993d2a2b6a52ba8079b931fdc4
[jalview.git] / src / jalview / ws2 / gui / SearchServiceGuiHandler.java
1 package jalview.ws2.gui;
2
3 import java.util.List;
4
5 import javax.swing.SwingUtilities;
6
7 import jalview.bin.Console;
8 import jalview.datamodel.Alignment;
9 import jalview.datamodel.AlignmentAnnotation;
10 import jalview.datamodel.AlignmentI;
11 import jalview.gui.AlignFrame;
12 import jalview.gui.Desktop;
13 import jalview.gui.JvOptionPane;
14 import jalview.gui.WebserviceInfo;
15 import jalview.util.ArrayUtils;
16 import jalview.util.MessageManager;
17 import jalview.ws2.actions.api.ActionI;
18 import jalview.ws2.actions.api.JobI;
19 import jalview.ws2.actions.api.TaskEventListener;
20 import jalview.ws2.actions.api.TaskI;
21 import jalview.ws2.api.JobStatus;
22 import jalview.ws2.api.WebService;
23 import jalview.ws2.helpers.WSClientTaskWrapper;
24
25 import static java.lang.String.format;
26
27 class SearchServiceGuiHandler implements TaskEventListener<AlignmentI>
28 {
29   private final AlignFrame parentFrame;
30
31   private final ActionI<?> action;
32
33   private final WebService<?> service;
34
35   private WebserviceInfo infoPanel;
36
37   private JobI[] jobs = new JobI[0];
38
39   private int[] tabs = new int[0];
40
41   private int[] logOffset = new int[0];
42
43   private int[] errLogOffset = new int[0];
44
45   public SearchServiceGuiHandler(ActionI<?> action, AlignFrame parentFrame)
46   {
47     this.parentFrame = parentFrame;
48     this.action = action;
49     this.service = action.getWebService();
50     var info = String.format("%s search using service at %s%n%s",
51             service.getName(), service.getUrl(), service.getDescription());
52     this.infoPanel = new WebserviceInfo(service.getName(), info, false);
53   }
54
55   @Override
56   public void taskStarted(TaskI<AlignmentI> source,
57           List<? extends JobI> subJobs)
58   {
59     Console.debug(format("task %s#%x started with %d sub-jobs",
60             service.getName(), source.getUid(), subJobs.size()));
61     jobs = subJobs.toArray(new JobI[subJobs.size()]);
62     tabs = new int[subJobs.size()];
63     logOffset = new int[subJobs.size()];
64     errLogOffset = new int[subJobs.size()];
65     for (int i = 0; i < subJobs.size(); i++)
66     {
67       JobI job = jobs[i];
68       int tabIndex = infoPanel.addJobPane();
69       tabs[i] = tabIndex;
70       infoPanel.setProgressName(format("region %d", i), tabIndex);
71       infoPanel.setProgressText(tabIndex, "Job details:\n");
72       // jobs should not have states other than invalid or ready at this point
73       if (job.getStatus() == JobStatus.INVALID)
74         infoPanel.setStatus(tabIndex, WebserviceInfo.STATE_STOPPED_OK);
75       else if (job.getStatus() == JobStatus.READY)
76         infoPanel.setStatus(tabIndex, WebserviceInfo.STATE_QUEUING);
77     }
78   }
79
80   @Override
81   public void taskStatusChanged(TaskI<AlignmentI> source, JobStatus status)
82   {
83     Console.debug(format("task %s#%x status changed to %s",
84             service.getName(), source.getUid(), status));
85     switch (status)
86     {
87     case INVALID:
88       infoPanel.setVisible(false);
89       JvOptionPane.showMessageDialog(parentFrame,
90               MessageManager.getString("info.invalid_search_input"),
91               MessageManager.getString("info.invalid_search_input"),
92               JvOptionPane.INFORMATION_MESSAGE);
93       break;
94     case READY:
95       infoPanel.setthisService(new WSClientTaskWrapper(source));
96       infoPanel.setVisible(true);
97       // intentional no break
98     case SUBMITTED:
99     case QUEUED:
100       infoPanel.setStatus(WebserviceInfo.STATE_QUEUING);
101       break;
102     case RUNNING:
103     case UNKNOWN: // unsure what to do with unknown
104       infoPanel.setStatus(WebserviceInfo.STATE_RUNNING);
105       break;
106     case COMPLETED:
107       infoPanel.setProgressBar(
108               MessageManager.getString("status.collecting_job_results"),
109               jobs[0].getInternalId());
110       infoPanel.setStatus(WebserviceInfo.STATE_STOPPED_OK);
111       break;
112     case FAILED:
113       infoPanel.removeProgressBar(jobs[0].getInternalId());
114       infoPanel.setStatus(WebserviceInfo.STATE_STOPPED_ERROR);
115       break;
116     case CANCELLED:
117       infoPanel.setStatus(WebserviceInfo.STATE_CANCELLED_OK);
118       break;
119     case SERVER_ERROR:
120       infoPanel.removeProgressBar(jobs[0].getInternalId());
121       infoPanel.setStatus(WebserviceInfo.STATE_STOPPED_SERVERERROR);
122       break;
123     }
124   }
125
126   @Override
127   public void taskCompleted(TaskI<AlignmentI> source, AlignmentI result)
128   {
129     Console.debug(format("task %s#%x completed", service.getName(),
130             source.getUid()));
131     SwingUtilities.invokeLater(
132             () -> infoPanel.removeProgressBar(jobs[0].getInternalId()));
133     if (result == null)
134     {
135       SwingUtilities.invokeLater(infoPanel::setFinishedNoResults);
136       return;
137     }
138     infoPanel.showResultsNewFrame.addActionListener(evt -> {
139       // copy alignment for each frame to have its own instance
140       var alnCpy = new Alignment(result);
141       alnCpy.setGapCharacter(result.getGapCharacter());
142       alnCpy.setDataset(result.getDataset());
143       for (AlignmentAnnotation annotation : result.getAlignmentAnnotation())
144         alnCpy.addAnnotation(new AlignmentAnnotation(annotation));
145       displayResultsNewFrame(alnCpy);
146     });
147     SwingUtilities.invokeLater(infoPanel::setResultsReady);
148   }
149
150   private void displayResultsNewFrame(AlignmentI aln)
151   {
152     AlignFrame frame = new AlignFrame(aln, AlignFrame.DEFAULT_WIDTH,
153             AlignFrame.DEFAULT_HEIGHT);
154     frame.getFeatureRenderer().transferSettings(
155             parentFrame.getFeatureRenderer().getSettings());
156     var actionName = action.getName() != null ? action.getName() : "Search";
157     var title = String.format("%s %s of %s", service.getName(), actionName,
158             parentFrame.getTitle());
159     Desktop.addInternalFrame(frame, title, AlignFrame.DEFAULT_WIDTH,
160             AlignFrame.DEFAULT_HEIGHT);
161   }
162
163   @Override
164   public void taskException(TaskI<AlignmentI> source, Exception e)
165   {
166     Console.error(format("Task %s#%x raised an exception.",
167             service.getName(), source.getUid()), e);
168     infoPanel.appendProgressText(e.getMessage());
169   }
170
171   @Override
172   public void subJobStatusChanged(TaskI<AlignmentI> source, JobI job,
173           JobStatus status)
174   {
175     Console.debug(format("sub-job %x status changed to %s",
176             job.getInternalId(), status));
177     int i = ArrayUtils.indexOf(jobs, job);
178     assert i >= 0 : "job does not exist";
179     if (i < 0)
180       // safeguard that should not happen irl
181       return;
182     int wsStatus;
183     switch (status)
184     {
185     case INVALID:
186     case COMPLETED:
187       wsStatus = WebserviceInfo.STATE_STOPPED_OK;
188       break;
189     case READY:
190     case SUBMITTED:
191     case QUEUED:
192       wsStatus = WebserviceInfo.STATE_QUEUING;
193       break;
194     case RUNNING:
195     case UNKNOWN:
196       wsStatus = WebserviceInfo.STATE_RUNNING;
197       break;
198     case FAILED:
199       wsStatus = WebserviceInfo.STATE_STOPPED_ERROR;
200       break;
201     case CANCELLED:
202       wsStatus = WebserviceInfo.STATE_CANCELLED_OK;
203       break;
204     case SERVER_ERROR:
205       wsStatus = WebserviceInfo.STATE_STOPPED_SERVERERROR;
206       break;
207     default:
208       throw new AssertionError("Non-exhaustive switch statement");
209     }
210     infoPanel.setStatus(tabs[i], wsStatus);
211   }
212
213   @Override
214   public void subJobLogChanged(TaskI<AlignmentI> source, JobI job,
215           String log)
216   {
217     int i = ArrayUtils.indexOf(jobs, job);
218     assert i >= 0 : "job does not exist";
219     if (i < 0)
220       // safeguard that should never happen
221       return;
222     infoPanel.appendProgressText(tabs[i], log.substring(logOffset[i]));
223   }
224
225   @Override
226   public void subJobErrorLogChanged(TaskI<AlignmentI> source, JobI job,
227           String log)
228   {
229     int i = ArrayUtils.indexOf(jobs, job);
230     assert i >= 0 : "job does not exist";
231     if (i < 0)
232       // safeguard that should never happen
233       return;
234     infoPanel.appendProgressText(tabs[i], log.substring(errLogOffset[i]));
235   }
236 }