Class |
Line # |
Actions |
|||
---|---|---|---|---|---|
RestClient | 51 | 99 | 44 |
1 | /* | |
2 | * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$) | |
3 | * Copyright (C) $$Year-Rel$$ The Jalview Authors | |
4 | * | |
5 | * This file is part of Jalview. | |
6 | * | |
7 | * Jalview is free software: you can redistribute it and/or | |
8 | * modify it under the terms of the GNU General Public License | |
9 | * as published by the Free Software Foundation, either version 3 | |
10 | * of the License, or (at your option) any later version. | |
11 | * | |
12 | * Jalview is distributed in the hope that it will be useful, but | |
13 | * WITHOUT ANY WARRANTY; without even the implied warranty | |
14 | * of MERCHANTABILITY or FITNESS FOR A PARTICULAR | |
15 | * PURPOSE. See the GNU General Public License for more details. | |
16 | * | |
17 | * You should have received a copy of the GNU General Public License | |
18 | * along with Jalview. If not, see <http://www.gnu.org/licenses/>. | |
19 | * The Jalview Authors are detailed in the 'AUTHORS' file. | |
20 | */ | |
21 | package jalview.ws.rest; | |
22 | ||
23 | import jalview.bin.Cache; | |
24 | import jalview.datamodel.AlignmentView; | |
25 | import jalview.gui.AlignFrame; | |
26 | import jalview.gui.AlignViewport; | |
27 | import jalview.gui.AlignmentPanel; | |
28 | import jalview.gui.Desktop; | |
29 | import jalview.gui.JvOptionPane; | |
30 | import jalview.gui.WebserviceInfo; | |
31 | import jalview.io.packed.DataProvider.JvDataType; | |
32 | import jalview.util.MessageManager; | |
33 | import jalview.ws.WSClient; | |
34 | import jalview.ws.WSClientI; | |
35 | import jalview.ws.WSMenuEntryProviderI; | |
36 | ||
37 | import java.awt.event.ActionEvent; | |
38 | import java.awt.event.ActionListener; | |
39 | import java.util.Hashtable; | |
40 | import java.util.Vector; | |
41 | ||
42 | import javax.swing.JMenu; | |
43 | import javax.swing.JMenuItem; | |
44 | import javax.swing.event.MenuEvent; | |
45 | import javax.swing.event.MenuListener; | |
46 | ||
47 | /** | |
48 | * @author JimP | |
49 | * | |
50 | */ | |
51 | public class RestClient extends WSClient | |
52 | implements WSClientI, WSMenuEntryProviderI | |
53 | { | |
54 | RestServiceDescription service; | |
55 | ||
56 | 2704 | public RestClient(RestServiceDescription rsd) |
57 | { | |
58 | 2704 | service = rsd; |
59 | } | |
60 | ||
61 | /** | |
62 | * parent alignframe for this job | |
63 | */ | |
64 | AlignFrame af; | |
65 | ||
66 | /** | |
67 | * alignment view which provides data for job. | |
68 | */ | |
69 | AlignViewport av; | |
70 | ||
71 | /** | |
72 | * get the alignFrame for the associated input data if it exists. | |
73 | * | |
74 | * @return | |
75 | */ | |
76 | 0 | protected AlignFrame recoverAlignFrameForView() |
77 | { | |
78 | 0 | return jalview.gui.Desktop.getAlignFrameFor(av); |
79 | } | |
80 | ||
81 | 0 | public RestClient(RestServiceDescription service2, AlignFrame alignFrame) |
82 | { | |
83 | 0 | this(service2, alignFrame, false); |
84 | } | |
85 | ||
86 | boolean headless = false; | |
87 | ||
88 | 1 | public RestClient(RestServiceDescription service2, AlignFrame alignFrame, |
89 | boolean nogui) | |
90 | { | |
91 | 1 | service = service2; |
92 | 1 | af = alignFrame; |
93 | 1 | av = alignFrame.getViewport(); |
94 | 1 | headless = nogui; |
95 | 1 | constructJob(); |
96 | } | |
97 | ||
98 | 1 | public void setWebserviceInfo(boolean headless) |
99 | { | |
100 | 1 | WebServiceJobTitle = MessageManager |
101 | .formatMessage("label.webservice_job_title", new String[] | |
102 | { service.details.Action, service.details.Name }); | |
103 | 1 | WebServiceName = service.details.Name; |
104 | 1 | WebServiceReference = "No reference - go to url for more info"; |
105 | 1 | if (service.details.description != null) |
106 | { | |
107 | 1 | WebServiceReference = service.details.description; |
108 | } | |
109 | 1 | if (!headless) |
110 | { | |
111 | 0 | wsInfo = new WebserviceInfo(WebServiceJobTitle, |
112 | WebServiceName + "\n" + WebServiceReference, true); | |
113 | 0 | wsInfo.setRenderAsHtml(true); |
114 | } | |
115 | ||
116 | } | |
117 | ||
118 | 0 | @Override |
119 | public boolean isCancellable() | |
120 | { | |
121 | // TODO define process for cancelling rsbws jobs | |
122 | 0 | return false; |
123 | } | |
124 | ||
125 | 0 | @Override |
126 | public boolean canMergeResults() | |
127 | { | |
128 | // TODO process service definition to identify if the results might be | |
129 | // mergeable | |
130 | // TODO: change comparison for annotation merge | |
131 | 0 | return false; |
132 | } | |
133 | ||
134 | 0 | @Override |
135 | public void cancelJob() | |
136 | { | |
137 | 0 | jalview.bin.Console |
138 | .errPrintln("Cannot cancel this job type: " + service); | |
139 | } | |
140 | ||
141 | 2694 | @Override |
142 | public void attachWSMenuEntry(final JMenu wsmenu, | |
143 | final AlignFrame alignFrame) | |
144 | { | |
145 | 2694 | JMenuItem submit = new JMenuItem(service.details.Name); |
146 | 2694 | submit.setToolTipText(MessageManager |
147 | .formatMessage("label.rest_client_submit", new String[] | |
148 | { service.details.Action, service.details.Name })); | |
149 | 2694 | submit.addActionListener(new ActionListener() |
150 | { | |
151 | ||
152 | 0 | @Override |
153 | public void actionPerformed(ActionEvent e) | |
154 | { | |
155 | 0 | new RestClient(service, alignFrame); |
156 | } | |
157 | ||
158 | }); | |
159 | 2694 | wsmenu.add(submit); |
160 | // TODO: menu listener should enable/disable entry depending upon selection | |
161 | // state of the alignment | |
162 | 2694 | wsmenu.addMenuListener(new MenuListener() |
163 | { | |
164 | ||
165 | 0 | @Override |
166 | public void menuSelected(MenuEvent e) | |
167 | { | |
168 | // TODO Auto-generated method stub | |
169 | ||
170 | } | |
171 | ||
172 | 0 | @Override |
173 | public void menuDeselected(MenuEvent e) | |
174 | { | |
175 | // TODO Auto-generated method stub | |
176 | ||
177 | } | |
178 | ||
179 | 0 | @Override |
180 | public void menuCanceled(MenuEvent e) | |
181 | { | |
182 | // TODO Auto-generated method stub | |
183 | ||
184 | } | |
185 | ||
186 | }); | |
187 | ||
188 | } | |
189 | ||
190 | /** | |
191 | * record of initial undoredo hash for the alignFrame providing data for this | |
192 | * job. | |
193 | */ | |
194 | long[] undoredo = null; | |
195 | ||
196 | /** | |
197 | * Compare the original input data to the data currently presented to the | |
198 | * user. // LOGIC: compare undo/redo - if same, merge regardless (coping with | |
199 | * any changes in hidden columns as normal) // if different undo/redo then | |
200 | * compare region that was submitted // if same, then merge as before, if | |
201 | * different then prompt user to open a new window. | |
202 | * | |
203 | * @return | |
204 | */ | |
205 | 0 | protected boolean isAlignmentModified() |
206 | { | |
207 | 0 | if (undoredo == null || av == null || av.getAlignment() == null) |
208 | { | |
209 | // always return modified if we don't have access to live GUI elements | |
210 | // anymore. | |
211 | 0 | return true; |
212 | } | |
213 | 0 | if (av.isUndoRedoHashModified(undoredo)) |
214 | { | |
215 | // alignment has been modified in some way. | |
216 | 0 | return true; |
217 | } | |
218 | // TODO: look deeper into modification of selection state, etc that may | |
219 | // affect RestJobThread.realiseResults(boolean merge); | |
220 | 0 | return false; |
221 | ||
222 | } | |
223 | ||
224 | /** | |
225 | * TODO: combine to form a dataset+alignment+annotation context | |
226 | */ | |
227 | AlignmentView _input; | |
228 | ||
229 | /** | |
230 | * input data context | |
231 | */ | |
232 | jalview.io.packed.JalviewDataset jds; | |
233 | ||
234 | /** | |
235 | * informative name for results | |
236 | */ | |
237 | public String viewTitle; | |
238 | ||
239 | 1 | protected void constructJob() |
240 | { | |
241 | 1 | service.setInvolvesFlags(); |
242 | // record all aspects of alignment view so we can merge back or recreate | |
243 | // later | |
244 | 1 | undoredo = av.getUndoRedoHash(); |
245 | /** | |
246 | * delete ? Vector sgs = av.getAlignment().getGroups(); if (sgs!=null) { | |
247 | * _sgs = new SequenceGroup[sgs.size()]; sgs.copyInto(_sgs); } else { _sgs = | |
248 | * new SequenceGroup[0]; } | |
249 | */ | |
250 | 1 | boolean selExists = (av.getSelectionGroup() != null) |
251 | && (av.getSelectionGroup().getSize() > 1); | |
252 | // TODO: JAL-715: refactor to alignViewport methods and revise to full | |
253 | // focus+context+dataset input data staging model | |
254 | 1 | if (selExists) |
255 | { | |
256 | 0 | if (service.partitiondata) |
257 | { | |
258 | 0 | if (av.getAlignment().getGroups() != null |
259 | && av.getAlignment().getGroups().size() > 0) | |
260 | { | |
261 | // intersect groups with selected region | |
262 | 0 | _input = new AlignmentView(av.getAlignment(), |
263 | av.getAlignment().getHiddenColumns(), | |
264 | av.getSelectionGroup(), av.hasHiddenColumns(), true, | |
265 | true); | |
266 | 0 | viewTitle = MessageManager.formatMessage( |
267 | "label.select_visible_region_of", new String[] | |
268 | 0 | { (av.hasHiddenColumns() |
269 | ? MessageManager.getString("label.visible") | |
270 | : ""), | |
271 | af.getTitle() }); | |
272 | } | |
273 | else | |
274 | { | |
275 | // use selected region to partition alignment | |
276 | 0 | _input = new AlignmentView(av.getAlignment(), |
277 | av.getAlignment().getHiddenColumns(), | |
278 | av.getSelectionGroup(), av.hasHiddenColumns(), false, | |
279 | true); | |
280 | } | |
281 | 0 | viewTitle = MessageManager.formatMessage( |
282 | "label.select_unselect_visible_regions_from", new String[] | |
283 | 0 | { (av.hasHiddenColumns() |
284 | ? MessageManager.getString("label.visible") | |
285 | : ""), | |
286 | af.getTitle() }); | |
287 | } | |
288 | else | |
289 | { | |
290 | // just take selected region intersection | |
291 | 0 | _input = new AlignmentView(av.getAlignment(), |
292 | av.getAlignment().getHiddenColumns(), | |
293 | av.getSelectionGroup(), av.hasHiddenColumns(), true, true); | |
294 | 0 | viewTitle = MessageManager.formatMessage( |
295 | "label.select_visible_region_of", new String[] | |
296 | 0 | { (av.hasHiddenColumns() |
297 | ? MessageManager.getString("label.visible") | |
298 | : ""), | |
299 | af.getTitle() }); | |
300 | } | |
301 | } | |
302 | else | |
303 | { | |
304 | // standard alignment view without selection present | |
305 | 1 | _input = new AlignmentView(av.getAlignment(), |
306 | av.getAlignment().getHiddenColumns(), null, | |
307 | av.hasHiddenColumns(), false, true); | |
308 | 1 | viewTitle = "" |
309 | 1 | + (av.hasHiddenColumns() |
310 | ? (new StringBuffer(" ") | |
311 | .append(MessageManager | |
312 | .getString("label.visible_region_of")) | |
313 | .toString()) | |
314 | : "") | |
315 | + af.getTitle(); | |
316 | } | |
317 | ||
318 | 1 | RestJobThread jobsthread = new RestJobThread(this); |
319 | ||
320 | 1 | if (jobsthread.isValid()) |
321 | { | |
322 | 1 | setWebserviceInfo(headless); |
323 | 1 | if (!headless) |
324 | { | |
325 | 0 | wsInfo.setthisService(this); |
326 | 0 | jobsthread.setWebServiceInfo(wsInfo); |
327 | } | |
328 | 1 | jobsthread.start(); |
329 | } | |
330 | else | |
331 | { | |
332 | // TODO: try to tell the user why the job couldn't be started. | |
333 | 0 | JvOptionPane.showMessageDialog(Desktop.desktop, |
334 | 0 | (jobsthread.hasWarnings() ? jobsthread.getWarnings() |
335 | : MessageManager.getString( | |
336 | "label.job_couldnt_be_started_check_input")), | |
337 | MessageManager | |
338 | .getString("label.unable_start_web_service_analysis"), | |
339 | JvOptionPane.WARNING_MESSAGE); | |
340 | } | |
341 | } | |
342 | ||
343 | 8 | public static RestClient makeShmmrRestClient() |
344 | { | |
345 | 8 | String action = "Analysis", |
346 | description = "Sequence Harmony and Multi-Relief (Brandt et al. 2010)", | |
347 | name = MessageManager.getString("label.multiharmony"); | |
348 | 8 | Hashtable<String, InputType> iparams = new Hashtable<String, InputType>(); |
349 | 8 | jalview.ws.rest.params.JobConstant toolp; |
350 | // toolp = new jalview.ws.rest.JobConstant("tool","jalview"); | |
351 | // iparams.put(toolp.token, toolp); | |
352 | // toolp = new jalview.ws.rest.params.JobConstant("mbjob[method]","shmr"); | |
353 | // iparams.put(toolp.token, toolp); | |
354 | // toolp = new | |
355 | // jalview.ws.rest.params.JobConstant("mbjob[description]","step 1"); | |
356 | // iparams.put(toolp.token, toolp); | |
357 | // toolp = new jalview.ws.rest.params.JobConstant("start_search","1"); | |
358 | // iparams.put(toolp.token, toolp); | |
359 | // toolp = new jalview.ws.rest.params.JobConstant("blast","0"); | |
360 | // iparams.put(toolp.token, toolp); | |
361 | ||
362 | 8 | jalview.ws.rest.params.Alignment aliinput = new jalview.ws.rest.params.Alignment(); |
363 | // SHMR server has a 65K limit for content pasted into the 'ali' parameter, | |
364 | // so we always upload our files. | |
365 | 8 | aliinput.token = "ali_file"; |
366 | 8 | aliinput.writeAsFile = true; |
367 | 8 | iparams.put(aliinput.token, aliinput); |
368 | 8 | jalview.ws.rest.params.SeqGroupIndexVector sgroups = new jalview.ws.rest.params.SeqGroupIndexVector(); |
369 | 8 | sgroups.setMinsize(2); |
370 | 8 | sgroups.min = 2;// need at least two group defined to make a partition |
371 | 8 | iparams.put("groups", sgroups); |
372 | 8 | sgroups.token = "groups"; |
373 | 8 | sgroups.sep = " "; |
374 | 8 | RestServiceDescription shmrService = new RestServiceDescription(action, |
375 | description, name, | |
376 | "http://zeus.few.vu.nl/programs/shmrwww/index.php?tool=jalview", // ?tool=jalview&mbjob[method]=shmr&mbjob[description]=step1", | |
377 | "?tool=jalview", iparams, true, false, '-'); | |
378 | // a priori knowledge of the data returned from the service | |
379 | 8 | shmrService.addResultDatatype(JvDataType.ANNOTATION); |
380 | 8 | return new RestClient(shmrService); |
381 | } | |
382 | ||
383 | 0 | public AlignmentPanel recoverAlignPanelForView() |
384 | { | |
385 | 0 | AlignmentPanel[] aps = Desktop |
386 | .getAlignmentPanels(av.getSequenceSetId()); | |
387 | 0 | for (AlignmentPanel alp : aps) |
388 | { | |
389 | 0 | if (alp.av == av) |
390 | { | |
391 | 0 | return alp; |
392 | } | |
393 | } | |
394 | 0 | return null; |
395 | } | |
396 | ||
397 | 0 | public boolean isShowResultsInNewView() |
398 | { | |
399 | // TODO make this a property of the service | |
400 | 0 | return true; |
401 | } | |
402 | ||
403 | protected static Vector<String> services = null; | |
404 | ||
405 | public static final String RSBS_SERVICES = "RSBS_SERVICES"; | |
406 | ||
407 | 2696 | public static RestClient[] getRestClients() |
408 | { | |
409 | 2696 | if (services == null) |
410 | { | |
411 | 6 | services = new Vector<String>(); |
412 | 6 | try |
413 | { | |
414 | 6 | for (RestServiceDescription descr : RestServiceDescription |
415 | .parseDescriptions(Cache.getDefault(RSBS_SERVICES, | |
416 | makeShmmrRestClient().service.toString()))) | |
417 | { | |
418 | 6 | services.add(descr.toString()); |
419 | } | |
420 | } catch (Exception ex) | |
421 | { | |
422 | 0 | jalview.bin.Console.errPrintln( |
423 | "Serious - RSBS descriptions in user preferences are corrupt!"); | |
424 | 0 | ex.printStackTrace(); |
425 | } | |
426 | ||
427 | } | |
428 | 2696 | RestClient[] lst = new RestClient[services.size()]; |
429 | 2696 | int i = 0; |
430 | 2696 | for (String svc : services) |
431 | { | |
432 | 2696 | lst[i++] = new RestClient(new RestServiceDescription(svc)); |
433 | } | |
434 | 2696 | return lst; |
435 | } | |
436 | ||
437 | 2694 | public String getAction() |
438 | { | |
439 | 2694 | return service.details.Action; |
440 | } | |
441 | ||
442 | 2 | public RestServiceDescription getRestDescription() |
443 | { | |
444 | 2 | return service; |
445 | } | |
446 | ||
447 | 0 | public static Vector<String> getRsbsDescriptions() |
448 | { | |
449 | 0 | Vector<String> rsbsDescrs = new Vector<String>(); |
450 | 0 | for (RestClient rsbs : getRestClients()) |
451 | { | |
452 | 0 | rsbsDescrs.add(rsbs.getRestDescription().toString()); |
453 | } | |
454 | 0 | return rsbsDescrs; |
455 | } | |
456 | ||
457 | 1 | public static void setRsbsServices(Vector<String> rsbsUrls) |
458 | { | |
459 | 1 | if (rsbsUrls != null) |
460 | { | |
461 | // TODO: consider validating services ? | |
462 | 1 | services = new Vector<String>(rsbsUrls); |
463 | 1 | StringBuffer sprop = new StringBuffer(); |
464 | 1 | for (String s : services) |
465 | { | |
466 | 1 | sprop.append(s); |
467 | } | |
468 | 1 | Cache.setProperty(RSBS_SERVICES, sprop.toString()); |
469 | } | |
470 | else | |
471 | { | |
472 | 0 | Cache.removeProperty(RSBS_SERVICES); |
473 | } | |
474 | } | |
475 | ||
476 | } |