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