JAL-1342 new command-line parameter -jabaws <URL>
authorgmungoc <g.m.carstairs@dundee.ac.uk>
Wed, 19 Nov 2014 12:55:39 +0000 (12:55 +0000)
committergmungoc <g.m.carstairs@dundee.ac.uk>
Wed, 19 Nov 2014 12:55:39 +0000 (12:55 +0000)
src/jalview/bin/Cache.java
src/jalview/bin/Jalview.java
src/jalview/gui/Desktop.java
src/jalview/gui/WsJobParameters.java
src/jalview/gui/WsPreferences.java
src/jalview/ws/jws2/JabaWsServerQuery.java
src/jalview/ws/jws2/Jws2Discoverer.java
test/jalview/ws/jabaws/JalviewJabawsTestUtils.java

index 24ed1b4..3b0a23e 100755 (executable)
@@ -150,6 +150,7 @@ import org.apache.log4j.SimpleLayout;
  * <li>FOLLOW_SELECTIONS (true) Controls whether a new alignment view should
  * respond to selections made in other alignments containing the same sequences.
  * </li>
+ * <li>JWS2HOSTURLS comma-separated list of URLs to try for JABAWS services</li>
  * <li>SHOW_WSDISCOVERY_ERRORS (true) Controls if the web service URL discovery
  * warning dialog box is displayed.</li>
  * <li>ANNOTATIONCOLOUR_MIN (orange) Shade used for minimum value of annotation
index 184c267..f80f341 100755 (executable)
@@ -24,6 +24,7 @@ import jalview.gui.AlignFrame;
 import jalview.gui.Desktop;
 import jalview.util.MessageManager;
 import jalview.util.Platform;
+import jalview.ws.jws2.Jws2Discoverer;
 
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
@@ -34,6 +35,7 @@ import java.io.IOException;
 import java.io.OutputStreamWriter;
 import java.io.PrintWriter;
 import java.lang.reflect.Constructor;
+import java.net.MalformedURLException;
 import java.net.URI;
 import java.net.URL;
 import java.net.URLDecoder;
@@ -106,40 +108,7 @@ public class Jalview
 
     if (aparser.contains("help") || aparser.contains("h"))
     {
-      System.out
-              .println("Usage: jalview -open [FILE] [OUTPUT_FORMAT] [OUTPUT_FILE]\n\n"
-                      + "-nodisplay\tRun Jalview without User Interface.\n"
-                      + "-props FILE\tUse the given Jalview properties file instead of users default.\n"
-                      + "-colour COLOURSCHEME\tThe colourscheme to be applied to the alignment\n"
-                      + "-annotations FILE\tAdd precalculated annotations to the alignment.\n"
-                      + "-tree FILE\tLoad the given newick format tree file onto the alignment\n"
-                      + "-features FILE\tUse the given file to mark features on the alignment.\n"
-                      + "-fasta FILE\tCreate alignment file FILE in Fasta format.\n"
-                      + "-clustal FILE\tCreate alignment file FILE in Clustal format.\n"
-                      + "-pfam FILE\tCreate alignment file FILE in PFAM format.\n"
-                      + "-msf FILE\tCreate alignment file FILE in MSF format.\n"
-                      + "-pileup FILE\tCreate alignment file FILE in Pileup format\n"
-                      + "-pir FILE\tCreate alignment file FILE in PIR format.\n"
-                      + "-blc FILE\tCreate alignment file FILE in BLC format.\n"
-                      + "-jalview FILE\tCreate alignment file FILE in Jalview format.\n"
-                      + "-png FILE\tCreate PNG image FILE from alignment.\n"
-                      + "-imgMap FILE\tCreate HTML file FILE with image map of PNG image.\n"
-                      + "-eps FILE\tCreate EPS file FILE from alignment.\n"
-                      + "-questionnaire URL\tQueries the given URL for information about any Jalview user questionnaires.\n"
-                      + "-noquestionnaire\tTurn off questionnaire check.\n"
-                      + "-nousagestats\tTurn off google analytics tracking for this session.\n"
-                      + "-sortbytree OR -nosortbytree\tEnable or disable sorting of the given alignment by the given tree\n"
-                      // +
-                      // "-setprop PROPERTY=VALUE\tSet the given Jalview property, after all other properties files have been read\n\t (quote the 'PROPERTY=VALUE' pair to ensure spaces are passed in correctly)"
-                      + "-dasserver nickname=URL\tAdd and enable a das server with given nickname\n\t\t\t(alphanumeric or underscores only) for retrieval of features for all alignments.\n"
-                      + "\t\t\tSources that also support the sequence command may be specified by prepending the URL with sequence:\n"
-                      + "\t\t\t e.g. sequence:http://localdas.somewhere.org/das/source)\n"
-                      + "-fetchfrom nickname\tQuery nickname for features for the alignments and display them.\n"
-                      // +
-                      // "-vdoc vamsas-document\tImport vamsas document into new session or join existing session with same URN\n"
-                      // + "-vses vamsas-session\tJoin session with given URN\n"
-                      + "-groovy FILE\tExecute groovy script in FILE, after all other arguments have been processed (if FILE is the text 'STDIN' then the file will be read from STDIN)\n"
-                      + "\n~Read documentation in Application or visit http://www.jalview.org for description of Features and Annotations file~\n\n");
+      showUsage();
       System.exit(0);
     }
     if (aparser.contains("nodisplay") || aparser.contains("nogui")
@@ -150,6 +119,20 @@ public class Jalview
     }
     Cache.loadProperties(aparser.getValue("props")); // must do this before
     // anything else!
+
+    final String jabawsUrl = aparser.getValue("jabaws");
+    if (jabawsUrl != null)
+    {
+      try
+      {
+        Jws2Discoverer.getDiscoverer().setPreferredUrl(jabawsUrl);
+      } catch (MalformedURLException e)
+      {
+        System.err.println("Invalid jabaws parameter: " + jabawsUrl
+                + " ignored");
+      }
+    }
+
     String defs = aparser.getValue("setprop");
     while (defs != null)
     {
@@ -619,6 +602,45 @@ public class Jalview
     }
   }
 
+  private static void showUsage()
+  {
+    System.out
+            .println("Usage: jalview -open [FILE] [OUTPUT_FORMAT] [OUTPUT_FILE]\n\n"
+                    + "-nodisplay\tRun Jalview without User Interface.\n"
+                    + "-props FILE\tUse the given Jalview properties file instead of users default.\n"
+                    + "-colour COLOURSCHEME\tThe colourscheme to be applied to the alignment\n"
+                    + "-annotations FILE\tAdd precalculated annotations to the alignment.\n"
+                    + "-tree FILE\tLoad the given newick format tree file onto the alignment\n"
+                    + "-features FILE\tUse the given file to mark features on the alignment.\n"
+                    + "-fasta FILE\tCreate alignment file FILE in Fasta format.\n"
+                    + "-clustal FILE\tCreate alignment file FILE in Clustal format.\n"
+                    + "-pfam FILE\tCreate alignment file FILE in PFAM format.\n"
+                    + "-msf FILE\tCreate alignment file FILE in MSF format.\n"
+                    + "-pileup FILE\tCreate alignment file FILE in Pileup format\n"
+                    + "-pir FILE\tCreate alignment file FILE in PIR format.\n"
+                    + "-blc FILE\tCreate alignment file FILE in BLC format.\n"
+                    + "-jalview FILE\tCreate alignment file FILE in Jalview format.\n"
+                    + "-png FILE\tCreate PNG image FILE from alignment.\n"
+                    + "-imgMap FILE\tCreate HTML file FILE with image map of PNG image.\n"
+                    + "-eps FILE\tCreate EPS file FILE from alignment.\n"
+                    + "-questionnaire URL\tQueries the given URL for information about any Jalview user questionnaires.\n"
+                    + "-noquestionnaire\tTurn off questionnaire check.\n"
+                    + "-nousagestats\tTurn off google analytics tracking for this session.\n"
+                    + "-sortbytree OR -nosortbytree\tEnable or disable sorting of the given alignment by the given tree\n"
+                    // +
+                    // "-setprop PROPERTY=VALUE\tSet the given Jalview property, after all other properties files have been read\n\t (quote the 'PROPERTY=VALUE' pair to ensure spaces are passed in correctly)"
+                    + "-jabaws URL\tSpecify URL for Jabaws services (e.g. for a local installation).\n"
+                    + "-dasserver nickname=URL\tAdd and enable a das server with given nickname\n\t\t\t(alphanumeric or underscores only) for retrieval of features for all alignments.\n"
+                    + "\t\t\tSources that also support the sequence command may be specified by prepending the URL with sequence:\n"
+                    + "\t\t\t e.g. sequence:http://localdas.somewhere.org/das/source)\n"
+                    + "-fetchfrom nickname\tQuery nickname for features for the alignments and display them.\n"
+                    // +
+                    // "-vdoc vamsas-document\tImport vamsas document into new session or join existing session with same URN\n"
+                    // + "-vses vamsas-session\tJoin session with given URN\n"
+                    + "-groovy FILE\tExecute groovy script in FILE, after all other arguments have been processed (if FILE is the text 'STDIN' then the file will be read from STDIN)\n"
+                    + "\n~Read documentation in Application or visit http://www.jalview.org for description of Features and Annotations file~\n\n");
+  }
+
   private static void startUsageStats(final Desktop desktop)
   {
     /**
index 23ba893..7a1202c 100644 (file)
@@ -2602,7 +2602,7 @@ public class Desktop extends jalview.jbgui.GDesktop implements
                                                 + ermsg
                                                 + "</td></tr></table>"
                                                 + "<p>It may be that you have invalid JABA URLs<br/>in your web service preferences,"
-                                                + " or mis-configured HTTP proxy settings.</p>"
+                                                + "<br>or as a command-line argument, or mis-configured HTTP proxy settings.</p>"
                                                 + "<p>Check the <em>Connections</em> and <em>Web services</em> tab<br/>of the"
                                                 + " Tools->Preferences dialog box to change them.</p></html>"),
                                 "Web Service Configuration Problem",
index 00d9c79..4a74c9c 100644 (file)
@@ -956,7 +956,7 @@ public class WsJobParameters extends JPanel implements ItemListener,
     {
       Vector<String> services = new Vector<String>();
       services.addElement(args[p++]);
-      Jws2Discoverer.setServiceUrls(services);
+      Jws2Discoverer.getDiscoverer().setServiceUrls(services);
     }
     try
     {
index 0674352..527750c 100644 (file)
@@ -33,6 +33,7 @@ import java.awt.Dimension;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
 import java.net.URL;
+import java.util.List;
 import java.util.Vector;
 
 import javax.swing.JLabel;
@@ -52,7 +53,9 @@ public class WsPreferences extends GWsPreferences
     initFromPreferences();
   }
 
-  Vector<String> wsUrls, oldUrls, rsbsUrls, oldRsbsUrls;
+  List<String> wsUrls;
+
+  Vector<String> oldUrls, rsbsUrls, oldRsbsUrls;
 
   private boolean needWsMenuUpdate;
 
@@ -62,8 +65,8 @@ public class WsPreferences extends GWsPreferences
   private void initFromPreferences()
   {
 
-    wsUrls = jalview.ws.jws2.Jws2Discoverer.getServiceUrls();
-    if (wsUrls != null)
+    wsUrls = Jws2Discoverer.getDiscoverer().getServiceUrls();
+    if (!wsUrls.isEmpty())
     {
       oldUrls = new Vector<String>(wsUrls);
     }
@@ -235,7 +238,7 @@ public class WsPreferences extends GWsPreferences
 
   private void updateServiceList()
   {
-    jalview.ws.jws2.Jws2Discoverer.setServiceUrls(wsUrls);
+    Jws2Discoverer.getDiscoverer().setServiceUrls(wsUrls);
   }
 
   private void updateRsbsServiceList()
@@ -256,7 +259,7 @@ public class WsPreferences extends GWsPreferences
     int sel = wsList.getSelectedRow();
     if (sel > -1)
     {
-      wsUrls.removeElementAt(sel);
+      wsUrls.remove(sel);
       update++;
       updateList();
     }
@@ -274,21 +277,22 @@ public class WsPreferences extends GWsPreferences
     int sel = wsList.getSelectedRow();
     if (sel > -1)
     {
-      String url = editUrl(wsUrls.elementAt(sel), MessageManager.getString("label.edit_jabaws_url"));
+      String url = editUrl(wsUrls.get(sel),
+              MessageManager.getString("label.edit_jabaws_url"));
       if (url != null)
       {
         int present = wsUrls.indexOf(url);
         if (present == -1)
         {
           update++;
-          wsUrls.setElementAt(url, sel);
+          wsUrls.set(sel, url);
           updateList();
         }
         else
         {
           if (present != sel)
           {
-            wsUrls.removeElementAt(sel);
+            wsUrls.remove(sel);
             updateList();
           }
         }
@@ -406,8 +410,8 @@ public class WsPreferences extends GWsPreferences
     if (p > -1 && p < wsUrls.size() - 1)
     {
       String t = wsUrls.get(p + 1);
-      wsUrls.setElementAt(wsUrls.elementAt(p), p + 1);
-      wsUrls.setElementAt(t, p);
+      wsUrls.set(p + 1, wsUrls.get(p));
+      wsUrls.set(p, t);
       updateList();
       wsList.getSelectionModel().setSelectionInterval(p + 1, p + 1);
       update++;
@@ -428,8 +432,8 @@ public class WsPreferences extends GWsPreferences
     if (p > 0)
     {
       String t = wsUrls.get(p - 1);
-      wsUrls.setElementAt(wsUrls.elementAt(p), p - 1);
-      wsUrls.setElementAt(t, p);
+      wsUrls.set(p - 1, wsUrls.get(p));
+      wsUrls.set(p, t);
       updateList();
       wsList.getSelectionModel().setSelectionInterval(p - 1, p - 1);
       update++;
@@ -487,7 +491,7 @@ public class WsPreferences extends GWsPreferences
 
       if (validate == JOptionPane.OK_OPTION)
       {
-        if (jalview.ws.jws2.Jws2Discoverer.testServiceUrl(foo))
+        if (Jws2Discoverer.testServiceUrl(foo))
         {
           return foo.toString();
         }
@@ -544,11 +548,11 @@ public class WsPreferences extends GWsPreferences
         int selind = wsList.getSelectedRow();
         if (selind > -1)
         {
-          wsUrls.insertElementAt(url, selind);
+          wsUrls.add(selind, url);
         }
         else
         {
-          wsUrls.addElement(url);
+          wsUrls.add(url);
         }
         update++;
         updateList();
@@ -651,8 +655,8 @@ public class WsPreferences extends GWsPreferences
   @Override
   protected void resetWs_actionPerformed(ActionEvent e)
   {
-    jalview.ws.jws2.Jws2Discoverer.setServiceUrls(null);
-    Vector nwsUrls = jalview.ws.jws2.Jws2Discoverer.getServiceUrls();
+    Jws2Discoverer.getDiscoverer().setServiceUrls(null);
+    List<String> nwsUrls = Jws2Discoverer.getDiscoverer().getServiceUrls();
     if (!wsUrls.equals(nwsUrls))
     {
       update++;
index a08a233..74dce4d 100644 (file)
@@ -27,6 +27,9 @@ import jalview.bin.Cache;
 import jalview.ws.jws2.jabaws2.Jws2Instance;
 import jalview.ws.jws2.jabaws2.Jws2InstanceFactory;
 
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URL;
 import java.util.HashSet;
 import java.util.Set;
 
@@ -44,7 +47,7 @@ public class JabaWsServerQuery implements Runnable
 
   Jws2Discoverer jws2Discoverer = null;
 
-  String jwsservers = null;
+  String jwsserver = null;
 
   boolean quit = false, running = false;
 
@@ -65,10 +68,10 @@ public class JabaWsServerQuery implements Runnable
     this.quit = quit;
   }
 
-  public JabaWsServerQuery(Jws2Discoverer jws2Discoverer, String jwsservers)
+  public JabaWsServerQuery(Jws2Discoverer jws2Discoverer, String server)
   {
     this.jws2Discoverer = jws2Discoverer;
-    this.jwsservers = jwsservers;
+    this.jwsserver = server;
   }
 
   Services[] JABAWS1SERVERS = new Services[]
@@ -92,7 +95,9 @@ public class JabaWsServerQuery implements Runnable
     running = true;
     try
     {
-      if (Jws2Client.validURL(jwsservers))
+      // TODO this test doesn't seem to attempt a connection - should it?
+      // would save a lot of failed tries with UnknownHostException
+      if (isValidUrl(jwsserver))
       {
         compbio.data.msa.RegistryWS registry = null;
         Set svccategories = null;
@@ -109,7 +114,7 @@ public class JabaWsServerQuery implements Runnable
         try
         {
           // JBPNote: why is RegistryWS in compbio.data.msa ?
-          registry = Jws2Client.connectToRegistry(jwsservers);
+          registry = Jws2Client.connectToRegistry(jwsserver);
           if (registry != null)
           {
             // System.err.println("Test Services Output\n"
@@ -137,7 +142,7 @@ public class JabaWsServerQuery implements Runnable
           ex.printStackTrace();
           // if that failed, then we are probably working with a JABAWS1 server.
           // in that case, look for each service endpoint
-          System.err.println("JWS2 Discoverer: " + jwsservers
+          System.err.println("JWS2 Discoverer: " + jwsserver
                   + " is a JABAWS1 server. Using hardwired list.");
           for (Services srv : JABAWS1SERVERS)
           {
@@ -161,18 +166,18 @@ public class JabaWsServerQuery implements Runnable
             JABAService service = null;
             try
             {
-              service = Jws2Client.connect(jwsservers, srv);
+              service = Jws2Client.connect(jwsserver, srv);
             } catch (Exception e)
             {
               System.err.println("Jws2 Discoverer: Problem on "
-                      + jwsservers + " with service " + srv + ":\n"
+                      + jwsserver + " with service " + srv + ":\n"
                       + e.getMessage());
               if (!(e instanceof javax.xml.ws.WebServiceException))
               {
                 e.printStackTrace();
               }
               // For moment, report service as a problem.
-              jws2Discoverer.addInvalidServiceUrl(jwsservers);
+              jws2Discoverer.addInvalidServiceUrl(jwsserver);
             }
             ;
             if (service != null)
@@ -184,16 +189,16 @@ public class JabaWsServerQuery implements Runnable
 
                 String description = registry.getServiceDescription(srv);
 
-                svc = Jws2InstanceFactory.newJws2Instance(jwsservers,
+                svc = Jws2InstanceFactory.newJws2Instance(jwsserver,
                         srv.toString(), cat.name, description, service);
               }
               if (svc == null)
               {
-                svc = Jws2InstanceFactory.newJws2Instance(jwsservers,
+                svc = Jws2InstanceFactory.newJws2Instance(jwsserver,
                         srv.toString(), cat.name,
                         "JABAWS 1 Alignment Service", service);
               }
-              jws2Discoverer.addService(jwsservers, svc);
+              jws2Discoverer.addService(jwsserver, svc);
             }
 
           }
@@ -201,25 +206,53 @@ public class JabaWsServerQuery implements Runnable
 
         if (noservices)
         {
-          jws2Discoverer.addUrlwithnoservices(jwsservers);
+          jws2Discoverer.addUrlwithnoservices(jwsserver);
         }
       }
       else
       {
-        jws2Discoverer.addInvalidServiceUrl(jwsservers);
-        Cache.log.info("Ignoring invalid Jws2 service url " + jwsservers);
+        jws2Discoverer.addInvalidServiceUrl(jwsserver);
+        Cache.log.info("Ignoring invalid Jws2 service url " + jwsserver);
       }
     } catch (Exception e)
     {
       e.printStackTrace();
       Cache.log.warn("Exception when discovering Jws2 services.", e);
-      jws2Discoverer.addInvalidServiceUrl(jwsservers);
+      jws2Discoverer.addInvalidServiceUrl(jwsserver);
     } catch (Error e)
     {
       Cache.log.error("Exception when discovering Jws2 services.", e);
-      jws2Discoverer.addInvalidServiceUrl(jwsservers);
+      jws2Discoverer.addInvalidServiceUrl(jwsserver);
     }
     running = false;
   }
 
+  /**
+   * Check if the URL is valid and responding.
+   * 
+   * @return
+   */
+  private boolean isValidUrl(String server)
+  {
+    // return Jws2Client.validURL(jwsserver); // checks syntax only
+    boolean result = false;
+    if (server != null) {
+      try {
+        URL url = new URL(server);
+        url.openStream().close();
+        result = true;
+      } catch (MalformedURLException e)
+      {
+        System.err.println("Invalid server URL: " + server);
+        result = false;
+      } catch (IOException e)
+      {
+        System.err.println("Error connecting to server: " + server + ": "
+                + e.toString());
+        result = false;
+      }
+    }
+    return result;
+  }
+
 }
index 910b749..a111d68 100644 (file)
@@ -34,6 +34,8 @@ import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
 import java.beans.PropertyChangeEvent;
 import java.beans.PropertyChangeListener;
+import java.beans.PropertyChangeSupport;
+import java.net.MalformedURLException;
 import java.net.URL;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -60,9 +62,48 @@ import compbio.ws.client.Services;
  */
 public class Jws2Discoverer implements Runnable, WSMenuEntryProviderI
 {
-  private java.beans.PropertyChangeSupport changeSupport = new java.beans.PropertyChangeSupport(
+  public static final String COMPBIO_JABAWS = "http://www.compbio.dundee.ac.uk/jabaws";
+
+  /*
+   * the .jalview_properties entry for JWS2 URLS
+   */
+  final static String JWS2HOSTURLS = "JWS2HOSTURLS";
+
+  /*
+   * Singleton instance
+   */
+  private static Jws2Discoverer discoverer;
+
+  /*
+   * Override for testing only
+   */
+  private static List<String> testUrls = null;
+
+  // preferred url has precedence over others
+  private String preferredUrl;
+
+  private PropertyChangeSupport changeSupport = new PropertyChangeSupport(
           this);
 
+  Vector<String> invalidServiceUrls = null, urlsWithoutServices = null,
+          validServiceUrls = null;
+
+  boolean running = false, aborted = false;
+
+  Thread oldthread = null;
+
+  /**
+   * holds list of services.
+   */
+  protected Vector<Jws2Instance> services;
+
+  /**
+   * Private constructor enforces use of singleton via getDiscoverer()
+   */
+  private Jws2Discoverer()
+  {
+  }
+
   /**
    * change listeners are notified of "services" property changes
    * 
@@ -87,8 +128,6 @@ public class Jws2Discoverer implements Runnable, WSMenuEntryProviderI
     changeSupport.removePropertyChangeListener(listener);
   }
 
-  boolean running = false, aborted = false;
-
   /**
    * @return the aborted
    */
@@ -104,10 +143,8 @@ public class Jws2Discoverer implements Runnable, WSMenuEntryProviderI
   public void setAborted(boolean aborted)
   {
     this.aborted = aborted;
-  }
-
-  Thread oldthread = null;
 
+  }
   public void run()
   {
 
@@ -135,7 +172,7 @@ public class Jws2Discoverer implements Runnable, WSMenuEntryProviderI
 
     // first set up exclusion list if needed
     final Set<String> ignoredServices = new HashSet<String>();
-    for (String ignored : jalview.bin.Cache.getDefault(
+    for (String ignored : Cache.getDefault(
             "IGNORED_JABAWS_SERVICETYPES", "")
             .split("\\|"))
     {
@@ -176,9 +213,9 @@ public class Jws2Discoverer implements Runnable, WSMenuEntryProviderI
     ArrayList<String> svctypes = new ArrayList<String>();
 
     List<JabaWsServerQuery> qrys = new ArrayList<JabaWsServerQuery>();
-    for (final String jwsservers : getServiceUrls())
+    for (final String jwsserver : getServiceUrls())
     {
-      JabaWsServerQuery squery = new JabaWsServerQuery(this, jwsservers);
+      JabaWsServerQuery squery = new JabaWsServerQuery(this, jwsserver);
       if (svctypes.size() == 0)
       {
         // TODO: remove this ugly hack to get Canonical JABA service ordering
@@ -233,7 +270,7 @@ public class Jws2Discoverer implements Runnable, WSMenuEntryProviderI
         Jws2Instance[] svcs = new Jws2Instance[services.size()];
         int[] spos = new int[services.size()];
         int ipos = 0;
-        Vector svcUrls = getServiceUrls();
+        List<String> svcUrls = getServiceUrls();
         for (Jws2Instance svc : services)
         {
           svcs[ipos] = svc;
@@ -290,11 +327,6 @@ public class Jws2Discoverer implements Runnable, WSMenuEntryProviderI
   }
 
   /**
-   * holds list of services.
-   */
-  protected Vector<Jws2Instance> services;
-
-  /**
    * attach all available web services to the appropriate submenu in the given
    * JMenu
    */
@@ -545,7 +577,7 @@ public class Jws2Discoverer implements Runnable, WSMenuEntryProviderI
   {
     if (args.length > 0)
     {
-      testUrls = new Vector<String>();
+      testUrls = new ArrayList<String>();
       for (String url : args)
       {
         testUrls.add(url);
@@ -592,8 +624,11 @@ public class Jws2Discoverer implements Runnable, WSMenuEntryProviderI
     }
   }
 
-  private static Jws2Discoverer discoverer;
-
+  /**
+   * Returns the singleton instance of this class.
+   * 
+   * @return
+   */
   public static Jws2Discoverer getDiscoverer()
   {
     if (discoverer == null)
@@ -605,7 +640,6 @@ public class Jws2Discoverer implements Runnable, WSMenuEntryProviderI
 
   public boolean hasServices()
   {
-    // TODO Auto-generated method stub
     return !running && services != null && services.size() > 0;
   }
 
@@ -614,24 +648,19 @@ public class Jws2Discoverer implements Runnable, WSMenuEntryProviderI
     return running;
   }
 
-  /**
-   * the jalview .properties entry for JWS2 URLS
-   */
-  final static String JWS2HOSTURLS = "JWS2HOSTURLS";
-
-  public static void setServiceUrls(Vector<String> urls)
+  public void setServiceUrls(List<String> wsUrls)
   {
-    if (urls != null)
+    if (wsUrls != null && !wsUrls.isEmpty())
     {
-      StringBuffer urlbuffer = new StringBuffer();
+      StringBuilder urls = new StringBuilder(128);
       String sep = "";
-      for (String url : urls)
+      for (String url : wsUrls)
       {
-        urlbuffer.append(sep);
-        urlbuffer.append(url);
+        urls.append(sep);
+        urls.append(url);
         sep = ",";
       }
-      Cache.setProperty(JWS2HOSTURLS, urlbuffer.toString());
+      Cache.setProperty(JWS2HOSTURLS, urls.toString());
     }
     else
     {
@@ -639,18 +668,27 @@ public class Jws2Discoverer implements Runnable, WSMenuEntryProviderI
     }
   }
 
-  private static Vector<String> testUrls = null;
-
-  public static Vector<String> getServiceUrls()
+  /**
+   * Returns web service URLs, in the order in which they should be tried (or an
+   * empty list).
+   * 
+   * @return
+   */
+  public List<String> getServiceUrls()
   {
     if (testUrls != null)
     {
       // return test urls, if there are any, instead of touching cache
       return testUrls;
     }
-    String surls = Cache.getDefault(JWS2HOSTURLS,
-            "http://www.compbio.dundee.ac.uk/jabaws");
-    Vector<String> urls = new Vector<String>();
+    List<String> urls = new ArrayList<String>();
+
+    if (this.preferredUrl != null)
+    {
+      urls.add(preferredUrl);
+    }
+
+    String surls = Cache.getDefault(JWS2HOSTURLS, COMPBIO_JABAWS);
     try
     {
       StringTokenizer st = new StringTokenizer(surls, ",");
@@ -659,40 +697,37 @@ public class Jws2Discoverer implements Runnable, WSMenuEntryProviderI
         String url = null;
         try
         {
-          java.net.URL u = new java.net.URL(url = st.nextToken());
+          url = st.nextToken();
+          new URL(url);
           if (!urls.contains(url))
           {
             urls.add(url);
           }
           else
           {
-            jalview.bin.Cache.log.info("Ignoring duplicate url in "
+            Cache.log.info("Ignoring duplicate url " + url + " in "
                     + JWS2HOSTURLS + " list");
           }
-        } catch (Exception ex)
+        } catch (MalformedURLException ex)
         {
-          jalview.bin.Cache.log
+          Cache.log
                   .warn("Problem whilst trying to make a URL from '"
                           + ((url != null) ? url : "<null>") + "'");
-          jalview.bin.Cache.log
+          Cache.log
                   .warn("This was probably due to a malformed comma separated list"
                           + " in the "
                           + JWS2HOSTURLS
                           + " entry of $(HOME)/.jalview_properties)");
-          jalview.bin.Cache.log.debug("Exception was ", ex);
+          Cache.log.debug("Exception was ", ex);
         }
       }
     } catch (Exception ex)
     {
-      jalview.bin.Cache.log.warn(
+      Cache.log.warn(
               "Error parsing comma separated list of urls in "
                       + JWS2HOSTURLS + " preference.", ex);
     }
-    if (urls.size() >= 0)
-    {
-      return urls;
-    }
-    return null;
+    return urls;
   }
 
   public Vector<Jws2Instance> getServices()
@@ -750,9 +785,6 @@ public class Jws2Discoverer implements Runnable, WSMenuEntryProviderI
     return thr;
   }
 
-  Vector<String> invalidServiceUrls = null, urlsWithoutServices = null,
-          validServiceUrls = null;
-
   /**
    * @return the invalidServiceUrls
    */
@@ -865,7 +897,9 @@ public class Jws2Discoverer implements Runnable, WSMenuEntryProviderI
       return 1;
     }
     if (urlsWithoutServices != null && urlsWithoutServices.contains(url))
+    {
       return 0;
+    }
     if (invalidServiceUrls != null && invalidServiceUrls.contains(url))
     {
       return -1;
@@ -979,4 +1013,21 @@ public class Jws2Discoverer implements Runnable, WSMenuEntryProviderI
   {
     setPreferredServiceFor(null, serviceType, serviceAction, selectedServer);
   }
+
+  /**
+   * Set a URL to try before any others. For use with command-line parameter to
+   * configure a local Jabaws installation without the need to add to property
+   * files.
+   * 
+   * @param value
+   * @throws MalformedURLException
+   */
+  public void setPreferredUrl(String value) throws MalformedURLException
+  {
+    if (value != null && value.trim().length() > 0)
+    {
+      new URL(value);
+      preferredUrl = value;
+    }
+  }
 }
index 295c3bf..c206323 100644 (file)
@@ -20,7 +20,8 @@
  */
 package jalview.ws.jabaws;
 
-import static org.junit.Assert.*;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 import jalview.ws.jws2.Jws2Discoverer;
 
 import java.util.Vector;
@@ -73,7 +74,7 @@ public class JalviewJabawsTestUtils
         services.add(url);
       }
       ;
-      Jws2Discoverer.setServiceUrls(services);
+      Jws2Discoverer.getDiscoverer().setServiceUrls(services);
     }
     try
     {