Set job title correctly and pass reason why
[jalview.git] / src / jalview / ws / rest / RestClient.java
1 /**
2  * 
3  */
4 package jalview.ws.rest;
5
6 import java.awt.event.ActionEvent;
7 import java.awt.event.ActionListener;
8 import java.util.Hashtable;
9
10 import javax.swing.JMenu;
11 import javax.swing.JMenuItem;
12 import javax.swing.JOptionPane;
13 import javax.swing.event.MenuEvent;
14 import javax.swing.event.MenuListener;
15
16 import jalview.datamodel.AlignmentView;
17 import jalview.gui.AlignFrame;
18 import jalview.gui.AlignViewport;
19 import jalview.gui.AlignmentPanel;
20 import jalview.gui.Desktop;
21 import jalview.gui.WebserviceInfo;
22 import jalview.io.packed.DataProvider.JvDataType;
23 import jalview.ws.WSClient;
24 import jalview.ws.WSClientI;
25 import jalview.ws.WSMenuEntryProviderI;
26
27 /**
28  * @author JimP
29  * 
30  */
31 public class RestClient extends WSClient implements WSClientI,
32         WSMenuEntryProviderI
33 {
34   RestServiceDescription service;
35
36   public RestClient(RestServiceDescription rsd)
37   {
38     service = rsd;
39   }
40
41   /**
42    * parent alignframe for this job
43    */
44   AlignFrame af;
45
46   /**
47    * alignment view which provides data for job.
48    */
49   AlignViewport av;
50
51   /**
52    * get the alignFrame for the associated input data if it exists.
53    * 
54    * @return
55    */
56   protected AlignFrame recoverAlignFrameForView()
57   {
58     return jalview.gui.Desktop.getAlignFrameFor(av);
59   }
60
61   public RestClient(RestServiceDescription service2, AlignFrame alignFrame)
62   {
63     service = service2;
64     af = alignFrame;
65     av = alignFrame.getViewport();
66     constructJob();
67   }
68
69   public void setWebserviceInfo(boolean headless)
70   {
71     WebServiceJobTitle = service.details.Action + " using "
72             + service.details.Name;
73     WebServiceName = service.details.Name;
74     WebServiceReference = "No reference - go to url for more info";
75     if (service.details.description != null)
76     {
77       WebServiceReference = service.details.description;
78     }
79     if (!headless)
80     {
81       wsInfo = new WebserviceInfo(WebServiceJobTitle, WebServiceName + "\n"
82               + WebServiceReference);
83       wsInfo.setRenderAsHtml(true);
84     }
85
86   }
87
88   @Override
89   public boolean isCancellable()
90   {
91     // TODO define process for cancelling rsbws jobs
92     return false;
93   }
94
95   @Override
96   public boolean canMergeResults()
97   {
98     // TODO process service definition to identify if the results might be
99     // mergeable
100     // TODO: change comparison for annotation merge
101     return false;
102   }
103
104   @Override
105   public void cancelJob()
106   {
107     System.err.println("Cannot cancel this job type: " + service);
108   }
109
110   @Override
111   public void attachWSMenuEntry(final JMenu wsmenu,
112           final AlignFrame alignFrame)
113   {
114     JMenuItem submit = new JMenuItem(service.details.Name);
115     submit.setToolTipText(service.details.Action+" using "+service.details.Name);
116     submit.addActionListener(new ActionListener()
117     {
118
119       @Override
120       public void actionPerformed(ActionEvent e)
121       {
122         new RestClient(service, alignFrame);
123       }
124
125     });
126     wsmenu.add(submit);
127     // TODO: menu listener should enable/disable entry depending upon selection
128     // state of the alignment
129     wsmenu.addMenuListener(new MenuListener()
130     {
131
132       @Override
133       public void menuSelected(MenuEvent e)
134       {
135         // TODO Auto-generated method stub
136
137       }
138
139       @Override
140       public void menuDeselected(MenuEvent e)
141       {
142         // TODO Auto-generated method stub
143
144       }
145
146       @Override
147       public void menuCanceled(MenuEvent e)
148       {
149         // TODO Auto-generated method stub
150
151       }
152
153     });
154
155   }
156
157   /**
158    * record of initial undoredo hash for the alignFrame providing data for this
159    * job.
160    */
161   long[] undoredo = null;
162
163   /**
164    * Compare the original input data to the data currently presented to the
165    * user. // LOGIC: compare undo/redo - if same, merge regardless (coping with
166    * any changes in hidden columns as normal) // if different undo/redo then
167    * compare region that was submitted // if same, then merge as before, if
168    * different then prompt user to open a new window.
169    * 
170    * @return
171    */
172   protected boolean isAlignmentModified()
173   {
174     if (undoredo == null || av==null || av.getAlignment()==null)
175     {
176       // always return modified if we don't have access to live GUI elements anymore.
177       return true;
178     }
179     if (av.isUndoRedoHashModified(undoredo))
180     {
181       // alignment has been modified in some way. 
182       return true;
183     }
184     // TODO: look deeper into modification of selection state, etc that may affect RestJobThread.realiseResults(boolean merge); 
185     return false;
186
187   }
188
189   /**
190    * TODO: combine to form a dataset+alignment+annotation context
191    */
192   AlignmentView _input;
193
194   /**
195    * input data context
196    */
197   jalview.io.packed.JalviewDataset jds;
198
199   /**
200    * informative name for results
201    */
202   public String viewTitle;
203
204   protected void constructJob()
205   {
206     service.setInvolvesFlags();
207     // record all aspects of alignment view so we can merge back or recreate
208     // later
209     undoredo = av.getUndoRedoHash();
210     /**
211      * delete ? Vector sgs = av.getAlignment().getGroups(); if (sgs!=null) {
212      * _sgs = new SequenceGroup[sgs.size()]; sgs.copyInto(_sgs); } else { _sgs =
213      * new SequenceGroup[0]; }
214      */
215     boolean selExists = (av.getSelectionGroup() != null)
216             && (av.getSelectionGroup().getSize() > 1);
217     // TODO: JAL-715: refactor to alignViewport methods and revise to full focus+context+dataset input data staging model
218     if (selExists)
219     {
220       if (service.partitiondata)
221       {
222         if (av.getAlignment().getGroups()!=null && av.getAlignment().getGroups().size() > 0)
223         {
224           // intersect groups with selected region
225           _input = new AlignmentView(av.getAlignment(), 
226                   av.getColumnSelection(), 
227                   av.getSelectionGroup(), 
228                   av.hasHiddenColumns(), 
229                   true, 
230                   true);
231           viewTitle = "selected "+(av.hasHiddenColumns() ? "visible" : "") + " region of "+af.getTitle();
232         }
233         else
234         {
235           // use selected region to partition alignment
236           _input = new AlignmentView(av.getAlignment(), 
237                   av.getColumnSelection(), 
238                   av.getSelectionGroup(), 
239                   av.hasHiddenColumns(), 
240                   false, 
241                   true);
242         }
243         viewTitle = "select and unselected "+(av.hasHiddenColumns() ? "visible" : "") + " regions from "+af.getTitle();
244       }
245       else
246       {
247         // just take selected region intersection
248         _input = new AlignmentView(av.getAlignment(), 
249                 av.getColumnSelection(), 
250                 av.getSelectionGroup(), 
251                 av.hasHiddenColumns(), 
252                 true, 
253                 true);
254         viewTitle = "selected "+(av.hasHiddenColumns() ? "visible" : "") + " region of "+af.getTitle();
255       }
256     } else {
257       // standard alignment view without selection present
258       _input = new AlignmentView(av.getAlignment(), 
259               av.getColumnSelection(), 
260               null, 
261               av.hasHiddenColumns(), 
262               false, 
263               true);
264       viewTitle = ""+(av.hasHiddenColumns() ? "visible region of " : "") + af.getTitle();
265     }
266     
267     RestJobThread jobsthread = new RestJobThread(this);
268     
269     if (jobsthread.isValid())
270     {
271       setWebserviceInfo(false);
272       wsInfo.setthisService(this);
273       jobsthread.setWebServiceInfo(wsInfo);
274       jobsthread.start();
275     }
276     else
277     {
278       // TODO: try to tell the user why the job couldn't be started.
279       JOptionPane.showMessageDialog(Desktop.desktop,
280               (jobsthread.hasWarnings() ? jobsthread.getWarnings() : "The Job couldn't be started. Please check your input, and the Jalview console for any warning messages."),
281               "Unable to start web service analysis", JOptionPane.WARNING_MESSAGE);
282     }
283   }
284
285   public static RestClient makeShmmrRestClient()
286   {
287     String action = "Analysis", description = "Sequence Harmony and Multi-Relief (UNSTABLE!)", name = "Sequence Harmony";
288     Hashtable<String, InputType> iparams = new Hashtable<String, InputType>();
289     jalview.ws.rest.params.JobConstant toolp;
290     //toolp = new jalview.ws.rest.JobConstant("tool","jalview");
291     //iparams.put(toolp.token, toolp);
292     toolp = new jalview.ws.rest.params.JobConstant("mbjob[method]","shmr");
293     iparams.put(toolp.token, toolp);
294     toolp = new jalview.ws.rest.params.JobConstant("mbjob[description]","step 1");
295     iparams.put(toolp.token, toolp);
296     toolp = new jalview.ws.rest.params.JobConstant("start_search","1");
297     iparams.put(toolp.token, toolp);
298     toolp = new jalview.ws.rest.params.JobConstant("blast","0");
299     iparams.put(toolp.token, toolp);
300     
301     jalview.ws.rest.params.Alignment aliinput = new jalview.ws.rest.params.Alignment();
302     aliinput.token = "ali";//_file";
303     aliinput.writeAsFile=false;//true;
304     //aliinput.token = "ali_file";
305     //aliinput.writeAsFile=true;
306     iparams.put(aliinput.token, aliinput);
307     jalview.ws.rest.params.SeqGroupIndexVector sgroups = new jalview.ws.rest.params.SeqGroupIndexVector();
308     sgroups.setMinsize(2);
309     sgroups.min=2;// need at least two group defined to make a partition
310     iparams.put("groups", sgroups);
311     sgroups.token = "groups";
312     sgroups.sep = " ";
313     RestServiceDescription shmrService = new RestServiceDescription(
314             action,
315             description,
316             name,
317             "http://www.ibi.vu.nl/programs/shmrwww/index.php?tool=jalview",// ?tool=jalview&mbjob[method]=shmr&mbjob[description]=step1",
318             "?tool=jalview", iparams, true, false, '-');
319     // a priori knowledge of the data returned from the service
320     shmrService.addResultDatatype(JvDataType.ANNOTATION);
321     return new RestClient(shmrService);
322   }
323
324   public AlignmentPanel recoverAlignPanelForView()
325   {
326     AlignmentPanel[] aps = Desktop.getAlignmentPanels(av.getSequenceSetId());
327     for (AlignmentPanel alp:aps)
328     {
329       if (alp.av == av)
330       {
331         return alp;
332       }
333     }
334     return null;
335   }
336
337   public boolean isShowResultsInNewView()
338   {
339     // TODO make this a property of the service
340     return true;
341   }
342
343 }