JAL-1379 refactor Jws2 service client so dynamic services can be of any type of JABA...
[jalview.git] / src / jalview / ws / jws2 / Jws2Client.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8.2)
3  * Copyright (C) 2014 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.jws2;
22
23 import java.awt.event.ActionEvent;
24 import java.awt.event.ActionListener;
25 import java.util.List;
26
27 import javax.swing.JCheckBoxMenuItem;
28 import javax.swing.JMenu;
29 import javax.swing.JMenuItem;
30 import javax.swing.event.MenuEvent;
31 import javax.swing.event.MenuListener;
32
33 import compbio.metadata.Argument;
34 import jalview.api.AlignCalcWorkerI;
35 import jalview.bin.Cache;
36 import jalview.gui.AlignFrame;
37 import jalview.gui.Desktop;
38 import jalview.gui.JvSwingUtils;
39 import jalview.gui.WebserviceInfo;
40 import jalview.gui.WsJobParameters;
41 import jalview.util.MessageManager;
42 import jalview.ws.jws2.dm.AAConSettings;
43 import jalview.ws.jws2.dm.JabaWsParamSet;
44 import jalview.ws.jws2.jabaws2.Jws2Instance;
45 import jalview.ws.params.WsParamSetI;
46 import jalview.ws.uimodel.AlignAnalysisUIText;
47
48 /**
49  * provides metadata for a jabaws2 service instance - resolves names, etc.
50  * 
51  * @author JimP
52  * 
53  */
54 public abstract class Jws2Client extends jalview.ws.WSClient
55 {
56   protected AlignFrame alignFrame;
57
58   protected WsParamSetI preset;
59
60   protected List<Argument> paramset;
61
62   public Jws2Client(AlignFrame _alignFrame, WsParamSetI preset,
63           List<Argument> arguments)
64   {
65     alignFrame = _alignFrame;
66     this.preset = preset;
67     if (preset != null)
68     {
69       if (!((preset instanceof JabaPreset) || preset instanceof JabaWsParamSet))
70       {
71         /*
72          * { this.preset = ((JabaPreset) preset).p; } else if (preset instanceof
73          * JabaWsParamSet) { List<Argument> newargs = new ArrayList<Argument>();
74          * JabaWsParamSet pset = ((JabaWsParamSet) preset); for (Option opt :
75          * pset.getjabaArguments()) { newargs.add(opt); } if (arguments != null
76          * && arguments.size() > 0) { // merge arguments with preset's own
77          * arguments. for (Argument opt : arguments) { newargs.add(opt); } }
78          * paramset = newargs; } else {
79          */
80         throw new Error(
81                 "Implementation error: Can only instantiate Jaba parameter sets.");
82       }
83     }
84     else
85     {
86       // just provided with a bunch of arguments
87       this.paramset = arguments;
88     }
89   }
90
91   boolean processParams(Jws2Instance sh, boolean editParams)
92   {
93     return processParams(sh, editParams, false);
94   }
95
96   protected boolean processParams(Jws2Instance sh, boolean editParams,
97           boolean adjustingExisting)
98   {
99
100     if (editParams)
101     {
102       if (sh.paramStore == null)
103       {
104         sh.paramStore = new JabaParamStore(sh,
105                 Desktop.getUserParameterStore());
106       }
107       WsJobParameters jobParams = (preset == null && paramset != null && paramset
108               .size() > 0) ? new WsJobParameters(null, sh, null, paramset)
109               : new WsJobParameters(sh, preset);
110       if (adjustingExisting)
111       {
112         jobParams.setName(MessageManager
113                 .getString("label.adjusting_parameters_for_calculation"));
114       }
115       if (!jobParams.showRunDialog())
116       {
117         return false;
118       }
119       WsParamSetI prset = jobParams.getPreset();
120       if (prset == null)
121       {
122         paramset = jobParams.isServiceDefaults() ? null : JabaParamStore
123                 .getJabafromJwsArgs(jobParams.getJobParams());
124         this.preset = null;
125       }
126       else
127       {
128         this.preset = prset; // ((JabaPreset) prset).p;
129         paramset = null; // no user supplied parameters.
130       }
131     }
132     return true;
133
134   }
135
136   public Jws2Client()
137   {
138     // anonymous constructor - used for headless method calls only
139   }
140
141   protected WebserviceInfo setWebService(Jws2Instance serv, boolean b)
142   {
143     // serviceHandle = serv;
144     String serviceInstance = serv.action; // serv.service.getClass().getName();
145     WebServiceName = serv.serviceType;
146     WebServiceJobTitle = serv.getActionText();
147     WsURL = serv.hosturl;
148     if (!b)
149     {
150       return new WebserviceInfo(WebServiceJobTitle, WebServiceJobTitle
151               + " using service hosted at " + serv.hosturl + "\n"
152               + (serv.description != null ? serv.description : ""));
153     }
154     return null;
155   }
156
157   /*
158    * Jws2Instance serviceHandle; (non-Javadoc)
159    * 
160    * @see jalview.ws.WSMenuEntryProviderI#attachWSMenuEntry(javax.swing.JMenu,
161    * jalview.gui.AlignFrame)
162    * 
163    * @Override public void attachWSMenuEntry(JMenu wsmenu, AlignFrame
164    * alignFrame) { if (serviceHandle==null) { throw new
165    * Error("Implementation error: No service handle for this Jws2 service."); }
166    * attachWSMenuEntry(wsmenu, serviceHandle, alignFrame); }
167    */
168   /**
169    * add the menu item for a particular jws2 service instance
170    * 
171    * @param wsmenu
172    * @param service
173    * @param alignFrame
174    */
175   abstract void attachWSMenuEntry(JMenu wsmenu, final Jws2Instance service,
176           final AlignFrame alignFrame);
177   
178
179   protected boolean registerAAConWSInstance(final JMenu wsmenu,
180           final Jws2Instance service, final AlignFrame alignFrame)
181   {
182     final AlignAnalysisUIText aaui = service.getAlignAnalysisUI(); // null ; //
183                                                                    // AlignAnalysisUIText.aaConGUI.get(service.serviceType.toString());
184     if (aaui == null)
185     {
186       // not an instantaneous calculation GUI type service
187       return false;
188     }
189     // create the instaneous calculation GUI bits and update state if existing
190     // GUI elements already present
191
192     JCheckBoxMenuItem _aaConEnabled = null;
193     for (int i = 0; i < wsmenu.getItemCount(); i++)
194     {
195       JMenuItem item = wsmenu.getItem(i);
196       if (item instanceof JCheckBoxMenuItem
197               && item.getText().equals(aaui.getAAconToggle()))
198       {
199         _aaConEnabled = (JCheckBoxMenuItem) item;
200       }
201     }
202     // is there an aaCon worker already present - if so, set it to use the
203     // given service handle
204     {
205       List<AlignCalcWorkerI> aaconClient = alignFrame.getViewport()
206               .getCalcManager()
207               .getRegisteredWorkersOfClass(aaui.getClient());
208       if (aaconClient != null && aaconClient.size() > 0)
209       {
210         AbstractJabaCalcWorker worker = (AbstractJabaCalcWorker) aaconClient
211                 .get(0);
212         if (!worker.service.hosturl.equals(service.hosturl))
213         {
214           // javax.swing.SwingUtilities.invokeLater(new Runnable()
215           {
216             // @Override
217             // public void run()
218             {
219               removeCurrentAAConWorkerFor(aaui, alignFrame);
220               buildCurrentAAConWorkerFor(aaui, alignFrame, service);
221             }
222           }// );
223         }
224       }
225     }
226
227     // is there a service already registered ? there shouldn't be if we are
228     // being called correctly
229     if (_aaConEnabled == null)
230     {
231       final JCheckBoxMenuItem aaConEnabled = new JCheckBoxMenuItem(
232               aaui.getAAconToggle());
233
234       aaConEnabled.setToolTipText("<html><p>"
235               + JvSwingUtils.wrapTooltip(aaui.getAAconToggleTooltip()
236                       + "</p>") + "</html>");
237       aaConEnabled.addActionListener(new ActionListener()
238       {
239         @Override
240         public void actionPerformed(ActionEvent arg0)
241         {
242           List<AlignCalcWorkerI> aaconClient = alignFrame.getViewport()
243                   .getCalcManager()
244                   .getRegisteredWorkersOfClass(aaui.getClient());
245           if (aaconClient != null && aaconClient.size() > 0)
246           {
247             removeCurrentAAConWorkerFor(aaui, alignFrame);
248           }
249           else
250           {
251             buildCurrentAAConWorkerFor(aaui, alignFrame);
252
253           }
254         }
255
256       });
257       wsmenu.add(aaConEnabled);
258       final JMenuItem modifyParams = new JMenuItem(aaui.getAAeditSettings());
259       modifyParams.setToolTipText("<html><p>"
260               + JvSwingUtils.wrapTooltip(aaui.getAAeditSettingsTooltip()
261                       + "</p>") + "</html>");
262       modifyParams.addActionListener(new ActionListener()
263       {
264
265         @Override
266         public void actionPerformed(ActionEvent arg0)
267         {
268           showAAConAnnotationSettingsFor(aaui, alignFrame);
269         }
270       });
271       wsmenu.add(modifyParams);
272       wsmenu.addMenuListener(new MenuListener()
273       {
274
275         @Override
276         public void menuSelected(MenuEvent arg0)
277         {
278           // TODO: refactor to the implementing class.
279           if (alignFrame.getViewport().getAlignment().isNucleotide() ? aaui
280                   .isNa() : aaui.isPr())
281           {
282             aaConEnabled.setEnabled(true);
283             modifyParams.setEnabled(true);
284           }
285           else
286           {
287             aaConEnabled.setEnabled(false);
288             modifyParams.setEnabled(false);
289           }
290           List<AlignCalcWorkerI> aaconClient = alignFrame.getViewport()
291                   .getCalcManager()
292                   .getRegisteredWorkersOfClass(aaui.getClient());
293           if (aaconClient != null && aaconClient.size() > 0)
294           {
295             aaConEnabled.setSelected(true);
296           }
297           else
298           {
299             aaConEnabled.setSelected(false);
300           }
301         }
302
303         @Override
304         public void menuDeselected(MenuEvent arg0)
305         {
306           // TODO Auto-generated method stub
307
308         }
309
310         @Override
311         public void menuCanceled(MenuEvent arg0)
312         {
313           // TODO Auto-generated method stub
314
315         }
316       });
317
318     }
319     return true;
320   }
321
322   private static void showAAConAnnotationSettingsFor(
323           final AlignAnalysisUIText aaui, AlignFrame alignFrame)
324   {
325     /*
326      * preferred settings Whether AACon is automatically recalculated Which
327      * AACon server to use What parameters to use
328      */
329     // could actually do a class search for this too
330     AAConSettings fave = (AAConSettings) alignFrame.getViewport()
331             .getCalcIdSettingsFor(aaui.getCalcId());
332     if (fave == null)
333     {
334       fave = createDefaultAAConSettings(aaui);
335     }
336     new SequenceAnnotationWSClient(fave, alignFrame, true);
337
338   }
339
340   private static void buildCurrentAAConWorkerFor(
341           final AlignAnalysisUIText aaui, AlignFrame alignFrame)
342   {
343     buildCurrentAAConWorkerFor(aaui, alignFrame, null);
344   }
345
346   private static void buildCurrentAAConWorkerFor(
347           final AlignAnalysisUIText aaui, AlignFrame alignFrame,
348           Jws2Instance service)
349   {
350     /*
351      * preferred settings Whether AACon is automatically recalculated Which
352      * AACon server to use What parameters to use
353      */
354     AAConSettings fave = (AAConSettings) alignFrame.getViewport()
355             .getCalcIdSettingsFor(aaui.getCalcId());
356     if (fave == null)
357     {
358       fave = createDefaultAAConSettings(aaui, service);
359     }
360     else
361     {
362       if (service != null
363               && !fave.getService().hosturl.equals(service.hosturl))
364       {
365         Cache.log.debug("Changing AACon service to " + service.hosturl
366                 + " from " + fave.getService().hosturl);
367         fave.setService(service);
368       }
369     }
370     new SequenceAnnotationWSClient(fave, alignFrame, false);
371   }
372
373   private static AAConSettings createDefaultAAConSettings(
374           AlignAnalysisUIText aaui)
375   {
376     return createDefaultAAConSettings(aaui, null);
377   }
378
379   private static AAConSettings createDefaultAAConSettings(
380           AlignAnalysisUIText aaui, Jws2Instance service)
381   {
382     if (service != null)
383     {
384       if (!service.serviceType.toString().equals(
385               compbio.ws.client.Services.AAConWS.toString()))
386       {
387         Cache.log
388                 .warn("Ignoring invalid preferred service for AACon calculations (service type was "
389                         + service.serviceType + ")");
390         service = null;
391       }
392       else
393       {
394         // check service is actually in the list of currently avaialable
395         // services
396         if (!Jws2Discoverer.getDiscoverer().getServices().contains(service))
397         {
398           // it isn't ..
399           service = null;
400         }
401       }
402     }
403     if (service == null)
404     {
405       // get the default service for AACon
406       service = Jws2Discoverer.getDiscoverer().getPreferredServiceFor(null,
407               aaui.getServiceType());
408     }
409     if (service == null)
410     {
411       // TODO raise dialog box explaining error, and/or open the JABA
412       // preferences menu.
413       throw new Error("No AACon service found.");
414     }
415     return new AAConSettings(true, service, null, null);
416   }
417
418   private static void removeCurrentAAConWorkerFor(AlignAnalysisUIText aaui,
419           AlignFrame alignFrame)
420   {
421     alignFrame.getViewport().getCalcManager()
422             .removeRegisteredWorkersOfClass(aaui.getClient());
423   }
424
425 }