1 package jalview.ws.jws2;
4 import java.awt.event.ActionEvent;
5 import java.awt.event.ActionListener;
6 import java.beans.PropertyChangeEvent;
7 import java.beans.PropertyChangeListener;
8 import java.io.Closeable;
9 import java.net.ConnectException;
11 import java.util.HashSet;
12 import java.util.Hashtable;
13 import java.util.StringTokenizer;
14 import java.util.Vector;
16 import javax.swing.JMenu;
17 import javax.swing.JMenuItem;
18 import javax.swing.event.MenuEvent;
19 import javax.swing.event.MenuListener;
21 import org.apache.log4j.Level;
23 import jalview.bin.Cache;
24 import jalview.datamodel.AlignmentView;
25 import jalview.gui.AlignFrame;
26 import jalview.gui.Desktop;
27 import jalview.ws.WSMenuEntryProviderI;
28 import jalview.ws.params.ParamDatastoreI;
29 import compbio.data.msa.MsaWS;
30 import compbio.metadata.Option;
31 import compbio.metadata.Preset;
32 import compbio.metadata.PresetManager;
33 import compbio.metadata.RunnerConfig;
34 import compbio.ws.client.Jws2Client;
35 import compbio.ws.client.Services;
38 * discoverer for jws2 services. Follows the lightweight service discoverer
39 * pattern (archetyped by EnfinEnvision2OneWay)
44 public class Jws2Discoverer implements Runnable, WSMenuEntryProviderI
46 private java.beans.PropertyChangeSupport changeSupport = new java.beans.PropertyChangeSupport(
50 * change listeners are notified of "services" property changes
53 * to be added that consumes new services Hashtable object.
55 public void addPropertyChangeListener(
56 java.beans.PropertyChangeListener listener)
58 changeSupport.addPropertyChangeListener(listener);
67 public void removePropertyChangeListener(
68 java.beans.PropertyChangeListener listener)
70 changeSupport.removePropertyChangeListener(listener);
73 boolean running = false;
75 Thread oldthread = null;
79 if (running && oldthread != null && oldthread.isAlive())
84 oldthread = Thread.currentThread();
87 Class foo = getClass().getClassLoader().loadClass(
88 "compbio.ws.client.Jws2Client");
89 } catch (ClassNotFoundException e)
92 .println("Not enabling Jalview Webservices version 2: client jar is not available."
93 + "\nPlease check that your webstart JNLP file is up to date!");
99 services.removeAllElements();
101 for (String jwsservers : getServiceUrls())
105 if (Jws2Client.validURL(jwsservers))
108 for (Services srv : Services.values())
110 MsaWS service = null;
113 service = Jws2Client.connect(jwsservers, srv);
114 } catch (Exception e)
116 System.err.println("Jws2 Discoverer: Problem on "
117 + jwsservers + " with service " + srv + ":\n"
119 if (!(e instanceof javax.xml.ws.WebServiceException))
127 addService(jwsservers, srv, service);
134 Cache.log.info("Ignoring invalid Jws2 service url " + jwsservers);
136 } catch (Exception e)
139 Cache.log.warn("Exception when discovering Jws2 services.", e);
142 Cache.log.error("Exception when discovering Jws2 services.", e);
147 changeSupport.firePropertyChange("services", new Vector(), services);
151 * record this service endpoint so we can use it
157 private void addService(String jwsservers, Services srv, MsaWS service2)
159 if (services == null)
161 services = new Vector<Jws2Instance>();
163 System.out.println("Discovered service: " + jwsservers + " "
165 Jws2Instance service = new Jws2Instance(jwsservers, srv.toString(), service2);
167 services.add(service);
168 // retrieve the presets and parameter set and cache now
169 service.getParamStore().getPresets();
170 service.hasParameters();
173 public class Jws2Instance
175 public String hosturl;
177 public String serviceType;
179 public MsaWS service;
181 public Jws2Instance(String hosturl, String serviceType, MsaWS service)
184 this.hosturl = hosturl;
185 this.serviceType = serviceType;
186 this.service = service;
189 PresetManager presets = null;
191 public JabaParamStore paramStore = null;
194 * non thread safe - gets the presets for this service (blocks whilst it
195 * calls the service to get the preset set)
197 * @return service presets or null if exceptions were raised.
199 public PresetManager getPresets()
205 presets = service.getPresets();
206 } catch (Exception ex)
209 .println("Exception when retrieving presets for service "
210 + serviceType + " at " + hosturl);
216 public String getHost()
220 * try { URL serviceurl = new URL(hosturl); if (serviceurl.getPort()!=80)
221 * { return serviceurl.getHost()+":"+serviceurl.getPort(); } return
222 * serviceurl.getHost(); } catch (Exception e) {
223 * System.err.println("Failed to parse service URL '" + hosturl +
224 * "' as a valid URL!"); } return null;
229 * @return short description of what the service will do
231 public String getActionText()
233 return "Align with " + serviceType;
237 * non-thread safe - blocks whilst accessing service to get complete set of
238 * available options and parameters
242 public RunnerConfig getRunnerConfig()
244 return service.getRunnerOptions();
248 protected void finalize() throws Throwable
254 Closeable svc = (Closeable) service;
257 } catch (Exception e)
265 public ParamDatastoreI getParamStore()
267 if (paramStore == null)
271 paramStore = new JabaParamStore(this,
272 (Desktop.instance != null ? Desktop
273 .getUserParameterStore() : null));
274 } catch (Exception ex)
282 public String getUri()
284 // this is only valid for Jaba 1.0 - this formula might have to change!
285 return hosturl+(hosturl.lastIndexOf("/")==(hosturl.length()-1) ? "/" : "") +serviceType;
287 private boolean hasParams=false,lookedForParams=false;
289 public boolean hasParameters()
291 if (!lookedForParams)
293 lookedForParams=true;
296 hasParams = (getRunnerConfig().getArguments().size() > 0);
297 } catch (Exception e)
307 * holds list of services.
309 protected Vector<Jws2Instance> services;
312 * find or add a submenu with the given title in the given menu
316 * @return the new or existing submenu
318 private JMenu findOrCreateMenu(JMenu menu, String submenu)
320 JMenu submenuinstance = null;
321 for (int i = 0, iSize = menu.getMenuComponentCount(); i < iSize; i++)
323 if (menu.getMenuComponent(i) instanceof JMenu
324 && ((JMenu) menu.getMenuComponent(i)).getText().equals(
327 submenuinstance = (JMenu) menu.getMenuComponent(i);
330 if (submenuinstance == null)
332 submenuinstance = new JMenu(submenu);
333 menu.add(submenuinstance);
335 return submenuinstance;
339 public void attachWSMenuEntry(JMenu wsmenu, final AlignFrame alignFrame)
341 // dynamically regenerate service list.
342 final JMenu jws2al = new JMenu("JABAWS Alignment");
343 jws2al.addMenuListener(new MenuListener()
345 // TODO: future: add menu listener to parent menu - so submenus are
346 // populated *before* they are selected.
348 public void menuSelected(MenuEvent e)
350 populateWSMenuEntry(jws2al, alignFrame);
354 public void menuDeselected(MenuEvent e)
356 // TODO Auto-generated method stub
361 public void menuCanceled(MenuEvent e)
363 // TODO Auto-generated method stub
372 private void populateWSMenuEntry(JMenu jws2al, final AlignFrame alignFrame)
374 if (running || services == null || services.size() == 0)
378 boolean byhost = Cache.getDefault("WSMENU_BYHOST", true), bytype = Cache
379 .getDefault("WSMENU_BYTYPE", true);
381 * eventually, JWS2 services will appear under the same align/etc submenus.
382 * for moment we keep them separate.
385 MsaWSClient msacl = new MsaWSClient();
386 Vector hostLabels = new Vector();
388 String lasthost=null;
389 for (final Jws2Instance service : services)
392 String host = service.getHost();
393 String type = service.serviceType;
396 atpoint = findOrCreateMenu(atpoint, host);
397 if (atpoint.getToolTipText() == null)
399 atpoint.setToolTipText("Services at " + host);
404 atpoint = findOrCreateMenu(atpoint, type);
405 if (atpoint.getToolTipText() == null)
407 atpoint.setToolTipText(service.getActionText());
410 if (!byhost && !hostLabels.contains(host + service.serviceType+service.getActionText()))
411 //!hostLabels.contains(host + (bytype ? service.serviceType+service.getActionText() : "")))
413 // add a marker indicating where this service is hosted
414 // relies on services from the same host being listed in a contiguous
417 atpoint.addSeparator();
418 if (lasthost==null || !lasthost.equals(host))
420 atpoint.add(hitm = new JMenuItem(host));
421 hitm.setForeground(Color.blue);
424 hostLabels.addElement(host + service.serviceType+service.getActionText() );
425 // hostLabels.addElement(host + (bytype ? service.serviceType+service.getActionText() : ""));
427 msacl.attachWSMenuEntry(atpoint, service, alignFrame);
429 * JMenuItem sitem = new JMenuItem(service.serviceType);
430 * sitem.setToolTipText("Hosted at " + service.hosturl);
431 * sitem.addActionListener(new ActionListener() {
433 * @Override public void actionPerformed(ActionEvent e) { AlignmentView
434 * msa = alignFrame.gatherSequencesForAlignment(); MsaWSClient client =
435 * new MsaWSClient(service, "JWS2 Alignment of " + alignFrame.getTitle(),
436 * msa, false, true, alignFrame.getViewport().getAlignment().getDataset(),
442 public static void main(String[] args)
444 Thread runner = new Thread(getDiscoverer());
445 getDiscoverer().addPropertyChangeListener(new PropertyChangeListener()
448 public void propertyChange(PropertyChangeEvent evt)
450 System.out.println("Changesupport: There are now "
451 + getDiscoverer().services.size() + " services");
455 while (runner.isAlive())
460 } catch (InterruptedException e)
467 private static Jws2Discoverer discoverer;
469 public static Jws2Discoverer getDiscoverer()
471 if (discoverer == null)
473 discoverer = new Jws2Discoverer();
478 public boolean hasServices()
480 // TODO Auto-generated method stub
481 return !running && services != null && services.size() > 0;
484 public boolean isRunning()
490 * the jalview .properties entry for JWS2 URLS
492 final static String JWS2HOSTURLS = "JWS2HOSTURLS";
494 public static void setServiceUrls(Vector<String> urls)
498 StringBuffer urlbuffer = new StringBuffer();
500 for (String url : urls)
502 urlbuffer.append(sep);
503 urlbuffer.append(url);
506 Cache.setProperty(JWS2HOSTURLS, urlbuffer.toString());
510 Cache.removeProperty(JWS2HOSTURLS);
514 public static Vector<String> getServiceUrls()
516 String surls = Cache.getDefault(JWS2HOSTURLS,
517 "http://www.compbio.dundee.ac.uk/jabaws");
518 Vector<String> urls = new Vector<String>();
521 StringTokenizer st = new StringTokenizer(surls, ",");
522 while (st.hasMoreElements())
527 java.net.URL u = new java.net.URL(url = st.nextToken());
528 if (!urls.contains(url))
534 jalview.bin.Cache.log.info("Ignoring duplicate url in "
535 + JWS2HOSTURLS + " list");
537 } catch (Exception ex)
539 jalview.bin.Cache.log
540 .warn("Problem whilst trying to make a URL from '"
541 + ((url != null) ? url : "<null>") + "'");
542 jalview.bin.Cache.log
543 .warn("This was probably due to a malformed comma separated list"
546 + " entry of $(HOME)/.jalview_properties)");
547 jalview.bin.Cache.log.debug("Exception was ", ex);
550 } catch (Exception ex)
552 jalview.bin.Cache.log.warn(
553 "Error parsing comma separated list of urls in "
554 + JWS2HOSTURLS + " preference.", ex);
556 if (urls.size() >= 0)
563 public Vector<Jws2Instance> getServices()
565 return (services == null) ? new Vector<Jws2Instance>()
566 : new Vector<Jws2Instance>(services);
570 * test the given URL with the JabaWS test code
575 public static boolean testServiceUrl(URL foo)
579 compbio.ws.client.WSTester.main(new String[]
580 { "-h=" + foo.toString() });
581 } catch (Exception e)
584 } catch (OutOfMemoryError e)