Merge branch 'Jalview-JS/develop' into merge_js_develop
[jalview.git] / src / jalview / ws / jws1 / SeqSearchWSClient.java
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.jws1;
22
23 import jalview.datamodel.AlignmentI;
24 import jalview.datamodel.AlignmentView;
25 import jalview.gui.AlignFrame;
26 import jalview.gui.Desktop;
27 import jalview.gui.JvOptionPane;
28 import jalview.gui.WebserviceInfo;
29 import jalview.util.MessageManager;
30
31 import java.awt.Component;
32 import java.awt.event.ActionEvent;
33 import java.awt.event.ActionListener;
34 import java.util.Enumeration;
35 import java.util.Hashtable;
36 import java.util.StringTokenizer;
37 import java.util.Vector;
38
39 import javax.swing.JMenu;
40 import javax.swing.JMenuItem;
41
42 import ext.vamsas.SeqSearchServiceLocator;
43 import ext.vamsas.SeqSearchServiceSoapBindingStub;
44 import ext.vamsas.ServiceHandle;
45
46 /**
47  * DOCUMENT ME!
48  * 
49  * @author $author$
50  * @version $Revision$
51  */
52 public class SeqSearchWSClient extends WS1Client
53 {
54   /**
55    * server is a WSDL2Java generated stub for an archetypal MsaWSI service.
56    */
57   ext.vamsas.SeqSearchI server;
58
59   /**
60    * Creates a new MsaWSClient object that uses a service given by an externally
61    * retrieved ServiceHandle
62    * 
63    * @param sh
64    *          service handle of type AbstractName(MsaWS)
65    * @param altitle
66    *          DOCUMENT ME!
67    * @param msa
68    *          DOCUMENT ME!
69    * @param submitGaps
70    *          DOCUMENT ME!
71    * @param preserveOrder
72    *          DOCUMENT ME!
73    */
74
75   public SeqSearchWSClient(ext.vamsas.ServiceHandle sh, String altitle,
76           jalview.datamodel.AlignmentView msa, String db,
77           AlignmentI seqdataset, AlignFrame _alignFrame)
78   {
79     super();
80     alignFrame = _alignFrame;
81     // can generalise the two errors below for metadata mapping from interface
82     // name to service client name
83     if (!sh.getAbstractName().equals(this.getServiceActionKey()))
84     {
85       JvOptionPane.showMessageDialog(Desktop.getDesktopPane(),
86               MessageManager.formatMessage(
87                       "label.service_called_is_not_seq_search_service",
88                       new String[]
89                       { sh.getName() }),
90               MessageManager.getString("label.internal_jalview_error"),
91               JvOptionPane.WARNING_MESSAGE);
92
93       return;
94     }
95
96     if ((wsInfo = setWebService(sh)) == null)
97     {
98       JvOptionPane.showMessageDialog(Desktop.getDesktopPane(),
99               MessageManager.formatMessage(
100                       "label.seq_search_service_is_unknown", new String[]
101                       { sh.getName() }),
102               MessageManager.getString("label.internal_jalview_error"),
103               JvOptionPane.WARNING_MESSAGE);
104
105       return;
106     }
107     startSeqSearchClient(altitle, msa, db, seqdataset);
108
109   }
110
111   /**
112    * non-process web service interaction - use this for calling HEADLESS
113    * synchronous service methods
114    * 
115    * @param sh
116    */
117   public SeqSearchWSClient(ServiceHandle sh)
118   {
119     setWebService(sh, true);
120   }
121
122   public SeqSearchWSClient()
123   {
124
125     super();
126     // add a class reference to the list
127   }
128
129   private void startSeqSearchClient(String altitle, AlignmentView msa,
130           String db, AlignmentI seqdataset)
131   {
132     if (!locateWebService())
133     {
134       return;
135     }
136     String visdb = (db == null || db == "") ? "default" : db; // need a visible
137     // name for a
138     // sequence db
139     boolean profileSearch = msa.getSequences().length > 2 ? true : false;
140     // single sequence or profile from alignment view
141     wsInfo.setProgressText("Searching " + visdb
142             + (!profileSearch
143                     ? " with sequence "
144                             + msa.getSequences()[0].getRefSeq().getName()
145                     : " with profile")
146             + " from " + altitle + "\nJob details\n");
147
148     String jobtitle = WebServiceName
149             + ((WebServiceName.indexOf("earch") > -1) ? " " : " search ")
150             + " of " + visdb
151             + (!profileSearch
152                     ? " with sequence "
153                             + msa.getSequences()[0].getRefSeq().getName()
154                     : " with profile")
155             + " from " + altitle;
156     SeqSearchWSThread ssthread = new SeqSearchWSThread(server, WsURL,
157             wsInfo, alignFrame, WebServiceName, jobtitle, msa, db,
158             seqdataset);
159     wsInfo.setthisService(ssthread);
160     ssthread.start();
161   }
162
163   /**
164    * Initializes the server field with a valid service implementation.
165    * 
166    * @return true if service was located.
167    */
168   private boolean locateWebService()
169   {
170     // this can be abstracted using reflection
171     // TODO: MuscleWS transmuted to generic MsaWS client
172     SeqSearchServiceLocator loc = new SeqSearchServiceLocator(); // Default
173
174     try
175     {
176       this.server = loc.getSeqSearchService(new java.net.URL(WsURL));
177       ((SeqSearchServiceSoapBindingStub) this.server).setTimeout(60000); // One
178       // minute
179       // timeout
180     } catch (Exception ex)
181     {
182       wsInfo.setProgressText("Serious! " + WebServiceName
183               + " Service location failed\nfor URL :" + WsURL + "\n"
184               + ex.getMessage());
185       wsInfo.setStatus(WebserviceInfo.ERROR);
186       ex.printStackTrace();
187
188       return false;
189     }
190
191     loc.getEngine().setOption("axis", "1");
192
193     return true;
194   }
195
196   protected String getServiceActionKey()
197   {
198     return "SeqSearch";
199   }
200
201   protected String getServiceActionDescription()
202   {
203     return "Sequence Database Search";
204   }
205
206   // simple caching of db parameters for each service endpoint
207   private static Hashtable dbParamsForEndpoint;
208   static
209   {
210     dbParamsForEndpoint = new Hashtable();
211   }
212
213   public String[] getSupportedDatabases() throws Exception
214   {
215
216     // check that we haven't already been to this service endpoint
217     if (dbParamsForEndpoint.containsKey(WsURL))
218     {
219       return (String[]) dbParamsForEndpoint.get(WsURL);
220     }
221     if (!locateWebService())
222     {
223       throw new Exception(MessageManager.formatMessage(
224               "exception.cannot_contact_service_endpoint_at", new String[]
225               { WsURL }));
226     }
227     String database = server.getDatabase();
228     if (database == null)
229     {
230       dbParamsForEndpoint.put(WsURL, new String[] {});
231       return null;
232     }
233     StringTokenizer en = new StringTokenizer(database.trim(), ",| ");
234     String[] dbs = new String[en.countTokens()];
235     for (int i = 0; i < dbs.length; i++)
236     {
237       dbs[i++] = en.nextToken().trim();
238     }
239     dbParamsForEndpoint.put(WsURL, dbs);
240     return dbs;
241   }
242
243   @Override
244   public void attachWSMenuEntry(JMenu wsmenu, final ServiceHandle sh,
245           final AlignFrame af)
246   {
247     // look for existing database service submenus on wsmenu
248     Hashtable dbsrchs = new Hashtable();
249     Vector newdbsrch = new Vector();
250     Component entries[] = wsmenu.getComponents();
251     for (int i = 0; entries != null && i < entries.length; i++)
252     {
253       if (entries[i] instanceof JMenu)
254       {
255         dbsrchs.put(entries[i].getName(), entries[i]);
256       }
257     }
258     JMenu defmenu = (JMenu) dbsrchs.get("Default Database");
259     if (defmenu == null)
260     {
261       dbsrchs.put("Default Database",
262               defmenu = new JMenu("Default Database"));
263       newdbsrch.addElement(defmenu);
264     }
265
266     String dbs[] = null;
267     try
268     {
269       dbs = new jalview.ws.jws1.SeqSearchWSClient(sh)
270               .getSupportedDatabases();
271     } catch (Exception e)
272     {
273       jalview.bin.Cache.log.warn(
274               "Database list request failed, so disabling SeqSearch Service client "
275                       + sh.getName() + " at " + sh.getEndpointURL(),
276               e);
277       return;
278     }
279     JMenuItem method;
280     // do default entry
281     defmenu.add(method = new JMenuItem(sh.getName()));
282     method.setToolTipText(sh.getEndpointURL());
283     method.addActionListener(new ActionListener()
284     {
285       @Override
286       public void actionPerformed(ActionEvent e)
287       {
288         // use same input gatherer as for secondary structure prediction
289         // we could actually parameterise the gatherer method here...
290         AlignmentView msa = af.gatherSeqOrMsaForSecStrPrediction();
291         new jalview.ws.jws1.SeqSearchWSClient(sh, af.getTitle(), msa, null,
292                 af.getViewport().getAlignment().getDataset(), af);
293       }
294     });
295     // add entry for each database the service supports
296     for (int db = 0; dbs != null && db < dbs.length; db++)
297     {
298       JMenu dbmenu = (JMenu) dbsrchs.get(dbs[db]);
299       if (dbmenu == null)
300       {
301         dbsrchs.put(dbs[db], dbmenu = new JMenu(dbs[db]));
302         newdbsrch.addElement(dbmenu);
303       }
304       // add the client handler code for this service
305       dbmenu.add(method = new JMenuItem(sh.getName()));
306       method.setToolTipText(sh.getEndpointURL());
307       final String searchdb = dbs[db];
308       method.addActionListener(new ActionListener()
309       {
310         @Override
311         public void actionPerformed(ActionEvent e)
312         {
313           AlignmentView msa = af.gatherSeqOrMsaForSecStrPrediction();
314           new jalview.ws.jws1.SeqSearchWSClient(sh, af.getTitle(), msa,
315                   searchdb, af.getViewport().getAlignment().getDataset(),
316                   af);
317         }
318       });
319     }
320     // add the databases onto the seqsearch menu
321     Enumeration e = newdbsrch.elements();
322     while (e.hasMoreElements())
323     {
324       Object el = e.nextElement();
325       if (el instanceof JMenu)
326       {
327         wsmenu.add((JMenu) el);
328       }
329       else
330       {
331         wsmenu.add((JMenuItem) el);
332       }
333     }
334
335   }
336 }