Maintain list of webservices and query any Service Discovery services.
[jalview.git] / src / jalview / ws / Discoverer.java
1 package jalview.ws;
2
3 /**
4  * <p>Title: </p>
5  *
6  * <p>Description: </p>
7  *
8  * <p>Copyright: Copyright (c) 2004</p>
9  *
10  * <p>Company: Dundee University</p>
11  *
12  * @author not attributable
13  * @version 1.0
14  */
15 import ext.vamsas.*;
16 import java.util.Vector;
17 import java.util.Hashtable;
18 import java.util.ArrayList;
19
20 public class Discoverer
21     extends Thread implements Runnable
22 {
23   ext.vamsas.IRegistry registry; // the root registry service.
24   private java.beans.PropertyChangeSupport changeSupport = new java.beans.
25       PropertyChangeSupport(this);
26
27   /**
28    * change listeners are notified of "services" property changes
29    *
30    * @param listener to be added that consumes new services Hashtable object.
31    */
32   public void addPropertyChangeListener(
33       java.beans.PropertyChangeListener listener)
34   {
35     changeSupport.addPropertyChangeListener(listener);
36   }
37
38   /**
39    *
40    *
41    * @param listener to be removed
42    */
43   public void removePropertyChangeListener(
44       java.beans.PropertyChangeListener listener)
45   {
46     changeSupport.removePropertyChangeListener(listener);
47   }
48
49   /**
50    * Property change listener firing routine
51    *
52    * @param prop services
53    * @param oldvalue old services hash
54    * @param newvalue new services hash
55    */
56   public void firePropertyChange(String prop, Object oldvalue, Object newvalue)
57   {
58     changeSupport.firePropertyChange(prop, oldvalue, newvalue);
59   }
60
61   /**
62    * Initializes the server field with a valid service implementation.
63    *
64    * @return true if service was located.
65    */
66   private IRegistry locateWebService(java.net.URL WsURL)
67   {
68     IRegistryServiceLocator loc = new IRegistryServiceLocator(); // Default
69     IRegistry server = null;
70     try
71     {
72       server = loc.getRegistryService(WsURL);
73       ( (RegistryServiceSoapBindingStub) server).setTimeout(60000); // One minute timeout
74     }
75     catch (Exception ex)
76     {
77       jalview.bin.Jalview.log.error(
78           "Serious!  Service location failed\nfor URL :" + WsURL +
79           "\n", ex);
80
81       return null;
82     }
83
84     loc.getEngine().setOption("axis", "1");
85
86     return server;
87   }
88
89   static private java.net.URL RootServiceURL = null;
90   static public Vector ServiceURLList = null;
91   static private boolean reallyDiscoverServices = true;
92
93   public static java.util.Hashtable services = null; // vectors of services stored by abstractServiceType string
94   public static java.util.Vector serviceList = null; // flat list of services
95
96   static
97   {
98
99     try
100     {
101       reallyDiscoverServices = jalview.bin.Cache.getDefault("DISCOVER_SERVICES", false);
102       if (reallyDiscoverServices)
103       {
104         RootServiceURL = new java.net.URL(
105             "http://webservices.compbio.dundee.ac.uk:8080/jalTestWS/services/ServiceRegistry");
106         if (ServiceURLList == null)
107         {
108           ServiceURLList = new Vector();
109         }
110         if (!ServiceURLList.contains(RootServiceURL))
111         {
112           ServiceURLList.add(RootServiceURL);
113         }
114       }
115       else
116       {
117         jalview.bin.Jalview.log.debug("Setting default services");
118         services = new Hashtable();
119         // Muscle, Clustal and JPred.
120         ServiceHandle[] defServices = {
121             new ServiceHandle(
122                 "MsaWS",
123                 "Edgar, Robert C. (2004), MUSCLE: multiple sequence alignment " +
124                 "with high accuracy and high throughput, Nucleic Acids Research 32(5), 1792-97.",
125                 "http://www.compbio.dundee.ac.uk/JalviewWS/services/MuscleWS",
126                 "Muscle Multiple Protein Sequence Alignment"
127 ),
128             new ServiceHandle(
129                 "MsaWS",
130                 "Thompson, J.D., Higgins, D.G. and Gibson, T.J. (1994) CLUSTAL W: improving the sensitivity of progressive multiple" +
131                 " sequence alignment through sequence weighting, position specific gap penalties and weight matrix choice." +
132                 " Nucleic Acids Research, 22 4673-4680",
133                 "http://www.compbio.dundee.ac.uk/JalviewWS/services/ClustalWS",
134                 "ClustalW Multiple Sequence Alignment"),
135             new ServiceHandle(
136                 "SecStrPred",
137                 "Cuff J. A and Barton G.J (1999) Application of enhanced " +
138                 "multiple sequence alignment profiles to improve protein secondary structure prediction, " +
139                 "Proteins 40:502-511",
140                 "http://www.compbio.dundee.ac.uk/JalviewWS/services/jpred","JPred Secondary Structure Prediction"
141                 )};
142         services = new Hashtable();
143         serviceList = new Vector();
144         buildServiceLists(defServices, serviceList, services);
145       }
146
147     }
148     catch (Exception e)
149     {
150       System.err.println(
151           "jalview.rootRegistry is not a proper url!\nWas set to " +
152           RootServiceURL + "\n" + e);
153     }
154
155   }
156   // TODO: JBPNote : make this discover more services based on list of
157   // discovery service urls, break cyclic references to the same url and
158   // duplicate service entries (same endpoint *and* same interface)
159   private ServiceHandle[] getServices(java.net.URL location)
160   {
161     ServiceHandles shs = null;
162     try
163     {
164       jalview.bin.Jalview.log.debug("Discovering services using " + location);
165       shs = locateWebService(location).getServices();
166     }
167     catch (Exception e)
168     {
169       System.err.println("failed to locate Services through URL : " +
170                          location + "\n");
171       e.printStackTrace();
172
173     }
174     if ( (shs != null) && shs.getServices().length > 0)
175     {
176       return shs.getServices();
177     }
178     return null;
179   }
180
181   /**
182    * Adds a list of services to the service catalog and categorised catalog
183    * returns true if ServiceURLList was modified with a new DiscoveryService URL
184    * @param sh ServiceHandle[]
185    * @param cat Vector
186    * @param sscat Hashtable
187    * @return boolean
188    */
189   static private boolean buildServiceLists(ServiceHandle[] sh, Vector cat,
190                                     Hashtable sscat)
191   {
192     boolean seenNewDiscovery = false;
193     for (int i = 0, j = sh.length; i < j; i++)
194     {
195       if (!cat.contains(sh[i]))
196       {
197         jalview.bin.Jalview.log.debug("A " + sh[i].getAbstractName() +
198                                       " service called " +
199                                       sh[i].getName() + " exists at " +
200                                       sh[i].getEndpointURL() + "\n");
201         if (!sscat.containsKey(sh[i].getAbstractName()))
202         {
203           sscat.put(sh[i].getAbstractName(), cat = new Vector());
204         }
205         else
206         {
207           cat = (Vector) sscat.get(sh[i].getAbstractName());
208         }
209         cat.add(sh[i]);
210         if (sh[i].getAbstractName().equals("Registry"))
211         {
212           for (int s = 0, sUrls = ServiceURLList.size(); s < sUrls; s++)
213           {
214             java.net.URL disc_serv = null;
215             try
216             {
217               disc_serv = new java.net.URL(sh[i].getEndpointURL());
218               if (!ServiceURLList.contains(disc_serv))
219               {
220                 jalview.bin.Jalview.log.debug(
221                     "Adding new discovery service at " + disc_serv);
222                 ServiceURLList.add(disc_serv);
223                 seenNewDiscovery = true;
224               }
225             }
226             catch (Exception e)
227             {
228               jalview.bin.Jalview.log.debug(
229                   "Ignoring bad discovery service URL " + sh[i].getEndpointURL(),
230                   e);
231             }
232           }
233         }
234       }
235     }
236     return seenNewDiscovery;
237   }
238
239   public void discoverServices()
240   {
241     Hashtable sscat = new Hashtable();
242     Vector cat = new Vector();
243     ServiceHandle sh[] = null;
244     int s_url = 0;
245     if (ServiceURLList==null)
246     {
247       jalview.bin.Jalview.log.debug("No service endpoints to use for service discovery.");
248       return;
249     }
250     while (s_url < ServiceURLList.size())
251     {
252       if ( (sh = getServices( (java.net.URL) ServiceURLList.get(s_url))) != null)
253       {
254
255         buildServiceLists(sh, cat, sscat);
256       }
257       s_url++;
258     }
259     // TODO: decide on correct semantics for services list - PropertyChange
260     // provides a way of passing the new object around
261     // so no need to access original discovery thread.
262     // Curent decision is to change properties then notify listeners with old and new values.
263     Hashtable oldServices = services;
264     Vector oldServicelist = serviceList;
265     services = sscat;
266     serviceList = cat;
267     firePropertyChange("services", oldServices, services);
268   }
269
270   public void run()
271   {
272     discoverServices();
273   }
274 }