Clover icon

Coverage Report

  1. Project Clover database Thu Nov 28 2024 18:06:40 GMT
  2. Package jalview.ws.rest

File RestClient.java

 

Coverage histogram

../../../img/srcFileCovDistChart6.png
38% of files have more coverage

Code metrics

34
99
23
1
476
326
44
0.44
4.3
23
1.91

Classes

Class Line # Actions
RestClient 51 99 44
0.519230851.9%
 

Contributing tests

This file is covered by 211 tests. .

Source view

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  3528 toggle public RestClient(RestServiceDescription rsd)
57    {
58  3528 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 toggle protected AlignFrame recoverAlignFrameForView()
77    {
78  0 return jalview.gui.Desktop.getAlignFrameFor(av);
79    }
80   
 
81  0 toggle public RestClient(RestServiceDescription service2, AlignFrame alignFrame)
82    {
83  0 this(service2, alignFrame, false);
84    }
85   
86    boolean headless = false;
87   
 
88  1 toggle 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 toggle 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 toggle @Override
119    public boolean isCancellable()
120    {
121    // TODO define process for cancelling rsbws jobs
122  0 return false;
123    }
124   
 
125  0 toggle @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 toggle @Override
135    public void cancelJob()
136    {
137  0 jalview.bin.Console
138    .errPrintln("Cannot cancel this job type: " + service);
139    }
140   
 
141  3518 toggle @Override
142    public void attachWSMenuEntry(final JMenu wsmenu,
143    final AlignFrame alignFrame)
144    {
145  3518 JMenuItem submit = new JMenuItem(service.details.Name);
146  3518 submit.setToolTipText(MessageManager
147    .formatMessage("label.rest_client_submit", new String[]
148    { service.details.Action, service.details.Name }));
149  3518 submit.addActionListener(new ActionListener()
150    {
151   
 
152  0 toggle @Override
153    public void actionPerformed(ActionEvent e)
154    {
155  0 new RestClient(service, alignFrame);
156    }
157   
158    });
159  3518 wsmenu.add(submit);
160    // TODO: menu listener should enable/disable entry depending upon selection
161    // state of the alignment
162  3518 wsmenu.addMenuListener(new MenuListener()
163    {
164   
 
165  0 toggle @Override
166    public void menuSelected(MenuEvent e)
167    {
168    // TODO Auto-generated method stub
169   
170    }
171   
 
172  0 toggle @Override
173    public void menuDeselected(MenuEvent e)
174    {
175    // TODO Auto-generated method stub
176   
177    }
178   
 
179  0 toggle @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 toggle 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 toggle 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 toggle 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 toggle 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 toggle 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  3520 toggle public static RestClient[] getRestClients()
408    {
409  3520 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  3520 RestClient[] lst = new RestClient[services.size()];
429  3520 int i = 0;
430  3520 for (String svc : services)
431    {
432  3520 lst[i++] = new RestClient(new RestServiceDescription(svc));
433    }
434  3520 return lst;
435    }
436   
 
437  3518 toggle public String getAction()
438    {
439  3518 return service.details.Action;
440    }
441   
 
442  2 toggle public RestServiceDescription getRestDescription()
443    {
444  2 return service;
445    }
446   
 
447  0 toggle 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 toggle 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    }