e52cefd56fc72d740de8c5bb8c707099d50a5692
[jalview.git] / src / jalview / ws / SeqSearchWSClient.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer
3  * Copyright (C) 2007 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
18  */
19 package jalview.ws;
20
21 import java.awt.Component;
22 import java.awt.event.ActionEvent;
23 import java.awt.event.ActionListener;
24 import java.util.Enumeration;
25 import java.util.Hashtable;
26 import java.util.StringTokenizer;
27 import java.util.Vector;
28
29 import javax.swing.*;
30
31 import ext.vamsas.*;
32 import jalview.datamodel.*;
33 import jalview.gui.*;
34
35 /**
36  * DOCUMENT ME!
37  *
38  * @author $author$
39  * @version $Revision$
40  */
41 public class SeqSearchWSClient
42     extends WSClient
43 {
44   /**
45    * server is a WSDL2Java generated stub for an archetypal MsaWSI service.
46    */
47   ext.vamsas.SeqSearchI server;
48   AlignFrame alignFrame;
49
50   /**
51    * Creates a new MsaWSClient object that uses a service
52    * given by an externally retrieved ServiceHandle
53    *
54    * @param sh service handle of type AbstractName(MsaWS)
55    * @param altitle DOCUMENT ME!
56    * @param msa DOCUMENT ME!
57    * @param submitGaps DOCUMENT ME!
58    * @param preserveOrder DOCUMENT ME!
59    */
60
61   public SeqSearchWSClient(ext.vamsas.ServiceHandle sh, String altitle,
62                      jalview.datamodel.AlignmentView msa, String db,
63                      Alignment seqdataset,
64                      AlignFrame _alignFrame)
65   {
66     super();
67     alignFrame = _alignFrame;
68     // can generalise the two errors below for metadata mapping from interface name to service client name
69     if (!sh.getAbstractName().equals(this.getServiceActionKey()))
70     {
71       JOptionPane.showMessageDialog(Desktop.desktop,
72                                     "The Service called \n" + sh.getName() +
73                                     "\nis not a \nSequence Search Service !",
74                                     "Internal Jalview Error",
75                                     JOptionPane.WARNING_MESSAGE);
76
77       return;
78     }
79
80     if ( (wsInfo = setWebService(sh)) == null)
81     {
82       JOptionPane.showMessageDialog(Desktop.desktop,
83                                     "The Sequence Search Service named " +
84                                     sh.getName() +
85                                     " is unknown", "Internal Jalview Error",
86                                     JOptionPane.WARNING_MESSAGE);
87
88       return;
89     }
90     startSeqSearchClient(altitle, msa, db, seqdataset);
91
92   }
93   /**
94  * non-process web service interaction - use this for calling HEADLESS synchronous service methods
95  * @param sh
96  */
97   public SeqSearchWSClient(ServiceHandle sh)
98   {
99     setWebService(sh, true);
100   }
101
102   public SeqSearchWSClient()
103   {
104
105     super();
106     // add a class reference to the list
107   }
108   private void startSeqSearchClient(String altitle, AlignmentView msa,
109                                 String db,
110                                 Alignment seqdataset)
111   {
112     if (!locateWebService())
113     {
114       return;
115     }
116     String visdb = (db==null || db == "") ? "default" : db; // need a visible name for a sequence db
117     boolean profileSearch = msa.getSequences().length>2 ? true : false;
118     // single sequence or profile from alignment view
119     wsInfo.setProgressText( "Searching "+visdb+(!profileSearch ? " with sequence "+msa.getSequences()[0].getRefSeq().getName()
120               : " with profile") +
121                            " from " + altitle + "\nJob details\n");
122     
123     String jobtitle = WebServiceName+((WebServiceName.indexOf("earch")>-1) ? " " : " search ")+" of "+visdb+(!profileSearch ? " with sequence "+msa.getSequences()[0].getRefSeq().getName()
124             : " with profile") +
125             " from " + altitle;
126     SeqSearchWSThread ssthread = new SeqSearchWSThread(server, WsURL, wsInfo, alignFrame,
127                                             WebServiceName,
128                                             jobtitle,
129                                             msa,
130                                             db,
131                                             seqdataset);
132     wsInfo.setthisService(ssthread);
133     ssthread.start();
134   }
135
136   /**
137    * Initializes the server field with a valid service implementation.
138    *
139    * @return true if service was located.
140    */
141   private boolean locateWebService()
142   {
143     // this can be abstracted using reflection
144     // TODO: MuscleWS transmuted to generic MsaWS client
145     SeqSearchServiceLocator loc = new SeqSearchServiceLocator(); // Default
146
147     try
148     {
149       this.server = (SeqSearchI) loc.getSeqSearchService(new java.net.URL(WsURL));
150       ( (SeqSearchServiceSoapBindingStub)this.server).setTimeout(60000); // One minute timeout
151     }
152     catch (Exception ex)
153     {
154       wsInfo.setProgressText("Serious! " + WebServiceName +
155                              " Service location failed\nfor URL :" + WsURL +
156                              "\n" +
157                              ex.getMessage());
158       wsInfo.setStatus(WebserviceInfo.ERROR);
159       ex.printStackTrace();
160
161       return false;
162     }
163
164     loc.getEngine().setOption("axis", "1");
165
166     return true;
167   }
168
169   protected String getServiceActionKey()
170   {
171     return "SeqSearch";
172   }
173
174   protected String getServiceActionDescription()
175   {
176     return "Sequence Database Search";
177   }
178   // simple caching of db parameters for each service endpoint
179   private static Hashtable dbParamsForEndpoint;
180   static { 
181     dbParamsForEndpoint = new Hashtable();
182   }
183   public String[] getSupportedDatabases() throws Exception
184   {
185     
186     // check that we haven't already been to this service endpoint
187     if (dbParamsForEndpoint.containsKey(WsURL))
188     {
189       return (String[]) dbParamsForEndpoint.get(WsURL);
190     }
191     if (!locateWebService())
192     {
193       throw new Exception("Cannot contact service endpoint at "+WsURL); 
194     }
195     String database = server.getDatabase();
196     if (database==null)
197     {
198       dbParamsForEndpoint.put(WsURL, new String[] {});
199       return null;
200     }
201     StringTokenizer en = new StringTokenizer(database.trim(), ",| ");
202     String[] dbs = new String[en.countTokens()];
203     for (int i=0; i<dbs.length; i++)
204     {
205       dbs[i++] = en.nextToken().trim();
206     }
207     dbParamsForEndpoint.put(WsURL, dbs);
208     return dbs;
209   }
210   public void attachWSMenuEntry(JMenu wsmenu, final ServiceHandle sh,
211           final AlignFrame af)
212   {
213     // look for existing database service submenus on wsmenu
214     Hashtable dbsrchs = new Hashtable();
215     Vector newdbsrch = new Vector();
216     Component entries[] =  wsmenu.getComponents();
217     for (int i = 0; entries!=null && i<entries.length; i++)
218     {
219       if (entries[i] instanceof JMenu)
220       {
221         dbsrchs.put(entries[i].getName(), entries[i]);
222       }
223     }
224     JMenu defmenu=(JMenu) dbsrchs.get("Default Database");
225     if (defmenu==null)
226     {
227       dbsrchs.put("Default Database", defmenu = new JMenu("Default Database"));
228       newdbsrch.addElement(defmenu);
229     }
230       
231       String dbs[] = null;
232       try {
233         dbs = new jalview.ws.SeqSearchWSClient(sh).getSupportedDatabases();
234       } catch (Exception e)
235       {
236         jalview.bin.Cache.log.warn("Database list request failed, so disabling SeqSearch Service client "+sh.getName()+" at "+sh.getEndpointURL(), e);
237         return;
238       }
239       JMenuItem method;
240       // do default entry
241       defmenu.add(method = new JMenuItem(sh.getName()));
242       method.setToolTipText(sh.getEndpointURL());
243       method.addActionListener(new ActionListener()
244       {
245         public void actionPerformed(ActionEvent e)
246         {
247           // use same input gatherer as for secondary structure prediction
248           // we could actually parameterise the gatherer method here...
249           AlignmentView msa = af.gatherSeqOrMsaForSecStrPrediction();
250           new jalview.ws.SeqSearchWSClient(sh, af.getTitle(), msa, null, 
251                   af.getViewport().getAlignment().getDataset(),
252                   af);
253           }
254         }
255       );
256       // add entry for each database the service supports
257       for (int db=0; dbs!=null && db<dbs.length; db++)
258       {
259         JMenu dbmenu = (JMenu) dbsrchs.get(dbs[db]);
260         if (dbmenu==null)
261         {
262           dbsrchs.put(dbs[db], dbmenu = new JMenu(dbs[db]));
263           newdbsrch.addElement(dbmenu);
264         }
265         // add the client handler code for this service
266         dbmenu.add(method = new JMenuItem(sh.getName()));
267         method.setToolTipText(sh.getEndpointURL());
268         final String searchdb = dbs[db];
269         method.addActionListener(new ActionListener()
270         {
271           public void actionPerformed(ActionEvent e)
272           {
273             AlignmentView msa = af.gatherSeqOrMsaForSecStrPrediction();
274             new jalview.ws.SeqSearchWSClient(sh, af.getTitle(), msa, searchdb, 
275                       af.getViewport().getAlignment().getDataset(),
276                       af);
277           }
278         });
279       }
280     // add the databases onto the seqsearch menu
281     Enumeration e = newdbsrch.elements();
282     while (e.hasMoreElements())
283     {
284       Object el = e.nextElement();
285       if (el instanceof JMenu)
286       {
287         wsmenu.add((JMenu) el);
288       } else {
289         wsmenu.add((JMenuItem) el);
290       }
291     }
292     
293   }
294 }