a57db1de9c58662f10cc62e6417e083675ee1994
[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       if (result.hasSeqrep())
146       {
147         int idx = result.findIndex(result.getSeqrep());
148         if (idx >= 0)
149           alnCpy.setSeqrep(alnCpy.getSequenceAt(idx));
150       }
151       displayResultsNewFrame(alnCpy);
152     });
153     SwingUtilities.invokeLater(infoPanel::setResultsReady);
154   }
155
156   private void displayResultsNewFrame(AlignmentI aln)
157   {
158     AlignFrame frame = new AlignFrame(aln, AlignFrame.DEFAULT_WIDTH,
159             AlignFrame.DEFAULT_HEIGHT);
160     frame.getFeatureRenderer().transferSettings(
161             parentFrame.getFeatureRenderer().getSettings());
162     var actionName = action.getName() != null ? action.getName() : "Search";
163     var title = String.format("%s %s of %s", service.getName(), actionName,
164             parentFrame.getTitle());
165     Desktop.addInternalFrame(frame, title, AlignFrame.DEFAULT_WIDTH,
166             AlignFrame.DEFAULT_HEIGHT);
167   }
168
169   @Override
170   public void taskException(TaskI<AlignmentI> source, Exception e)
171   {
172     Console.error(format("Task %s#%x raised an exception.",
173             service.getName(), source.getUid()), e);
174     infoPanel.appendProgressText(e.getMessage());
175   }
176
177   @Override
178   public void subJobStatusChanged(TaskI<AlignmentI> source, JobI job,
179           JobStatus status)
180   {
181     Console.debug(format("sub-job %x status changed to %s",
182             job.getInternalId(), status));
183     int i = ArrayUtils.indexOf(jobs, job);
184     assert i >= 0 : "job does not exist";
185     if (i < 0)
186       // safeguard that should not happen irl
187       return;
188     int wsStatus;
189     switch (status)
190     {
191     case INVALID:
192     case COMPLETED:
193       wsStatus = WebserviceInfo.STATE_STOPPED_OK;
194       break;
195     case READY:
196     case SUBMITTED:
197     case QUEUED:
198       wsStatus = WebserviceInfo.STATE_QUEUING;
199       break;
200     case RUNNING:
201     case UNKNOWN:
202       wsStatus = WebserviceInfo.STATE_RUNNING;
203       break;
204     case FAILED:
205       wsStatus = WebserviceInfo.STATE_STOPPED_ERROR;
206       break;
207     case CANCELLED:
208       wsStatus = WebserviceInfo.STATE_CANCELLED_OK;
209       break;
210     case SERVER_ERROR:
211       wsStatus = WebserviceInfo.STATE_STOPPED_SERVERERROR;
212       break;
213     default:
214       throw new AssertionError("Non-exhaustive switch statement");
215     }
216     infoPanel.setStatus(tabs[i], wsStatus);
217   }
218
219   @Override
220   public void subJobLogChanged(TaskI<AlignmentI> source, JobI job,
221           String log)
222   {
223     int i = ArrayUtils.indexOf(jobs, job);
224     assert i >= 0 : "job does not exist";
225     if (i < 0)
226       // safeguard that should never happen
227       return;
228     infoPanel.appendProgressText(tabs[i], log.substring(logOffset[i]));
229   }
230
231   @Override
232   public void subJobErrorLogChanged(TaskI<AlignmentI> source, JobI job,
233           String log)
234   {
235     int i = ArrayUtils.indexOf(jobs, job);
236     assert i >= 0 : "job does not exist";
237     if (i < 0)
238       // safeguard that should never happen
239       return;
240     infoPanel.appendProgressText(tabs[i], log.substring(errLogOffset[i]));
241   }
242 }