rejigged change support to make it (more) reliable
authorjprocter <Jim Procter>
Sat, 19 Jun 2010 16:43:39 +0000 (16:43 +0000)
committerjprocter <Jim Procter>
Sat, 19 Jun 2010 16:43:39 +0000 (16:43 +0000)
src/jalview/gui/AlignFrame.java
src/jalview/gui/Desktop.java
src/jalview/ws/jws1/Discoverer.java
src/jalview/ws/jws2/Jws2Discoverer.java

index 87776d3..6ee243e 100755 (executable)
@@ -30,6 +30,7 @@ import javax.swing.*;
 import javax.swing.event.MenuEvent;
 
 import jalview.analysis.*;
+import jalview.bin.Cache;
 import jalview.commands.*;
 import jalview.datamodel.*;
 import jalview.io.*;
@@ -514,16 +515,16 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   /* Set up intrinsic listeners for dynamically generated GUI bits. */
   private void addServiceListeners()
   {
-    final java.beans.PropertyChangeListener thisListener, thatListener;
+    final java.beans.PropertyChangeListener thisListener;
     // Do this once to get current state
     BuildWebServiceMenu();
-    Desktop.discoverer
-            .addPropertyChangeListener(thisListener = new java.beans.PropertyChangeListener()
+    Desktop.instance.addJalviewPropertyChangeListener("services",
+            thisListener=new java.beans.PropertyChangeListener()
             {
               public void propertyChange(PropertyChangeEvent evt)
               {
-                // System.out.println("Discoverer property change.");
-                if (evt.getPropertyName().equals("services"))
+                // // System.out.println("Discoverer property change.");
+                // if (evt.getPropertyName().equals("services"))
                 {
                   SwingUtilities.invokeLater(new Runnable()
                   {
@@ -532,7 +533,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
                     public void run()
                     {
                       System.err
-                              .println("Change support JWS1: build services again.");
+                              .println("Rebuild WS Menu for service change");
                       BuildWebServiceMenu();
                     }
 
@@ -540,26 +541,13 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
                 }
               }
             });
-    jalview.ws.jws2.Jws2Discoverer.getDiscoverer()
-            .addPropertyChangeListener(
-                    thatListener = new java.beans.PropertyChangeListener()
-                    {
-                      public void propertyChange(PropertyChangeEvent evt)
-                      {
-                        System.err
-                                .println("Change support JWS2: build services again.");
-                        BuildWebServiceMenu();
-                      }
-                    });
     addInternalFrameListener(new javax.swing.event.InternalFrameAdapter()
     {
       public void internalFrameClosed(
               javax.swing.event.InternalFrameEvent evt)
       {
-        // System.out.println("deregistering discoverer listener");
-        Desktop.discoverer.removePropertyChangeListener(thisListener);
-        jalview.ws.jws2.Jws2Discoverer.getDiscoverer()
-                .removePropertyChangeListener(thatListener);
+        System.out.println("deregistering discoverer listener");
+        Desktop.instance.removeJalviewPropertyChangeListener("services",thisListener);
         closeMenuItem_actionPerformed(true);
       };
     });
@@ -3843,7 +3831,9 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
       // object broker mechanism.
       Vector wsmenu = new Vector();
       final IProgressIndicator af = this;
-      if ((Discoverer.services != null) && (Discoverer.services.size() > 0))
+      if (Cache.getDefault("SHOW_JWS1_SERVICES", true)
+              && Discoverer.services != null
+              && (Discoverer.services.size() > 0))
       {
         // TODO: refactor to allow list of AbstractName/Handler bindings to be
         // stored or retrieved from elsewhere
@@ -3901,6 +3891,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
       }
 
       // TODO: move into separate menu builder class.
+      if (Cache.getDefault("SHOW_JWS2_SERVICES", true))
       {
         Jws2Discoverer jws2servs = Jws2Discoverer.getDiscoverer();
         if (jws2servs != null)
@@ -3911,13 +3902,6 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
             jws2servs.attachWSMenuEntry(jws2men, this);
             wsmenu.add(jws2men);
           }
-          else
-          {
-            if (!jws2servs.isRunning())
-            {
-              new Thread(jws2servs).start();
-            }
-          }
         }
       }
       resetWebServiceMenu();
@@ -3959,8 +3943,11 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
    */
   private void build_urlServiceMenu(JMenu webService)
   {
-    jalview.ws.EnfinEnvision2OneWay.getInstance().attachWSMenuEntry(
-            webService, this);
+    if (Cache.getDefault("SHOW_ENFIN_SERVICES", true))
+    {
+      jalview.ws.EnfinEnvision2OneWay.getInstance().attachWSMenuEntry(
+              webService, this);
+    }
   }
 
   /*
index 3ba50c5..23b18b0 100755 (executable)
@@ -24,6 +24,8 @@ import java.awt.*;
 import java.awt.datatransfer.*;
 import java.awt.dnd.*;
 import java.awt.event.*;
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
 import java.io.BufferedInputStream;
 import java.io.BufferedOutputStream;
 import java.io.File;
@@ -40,7 +42,8 @@ import javax.swing.event.MenuEvent;
 import javax.swing.event.MenuListener;
 
 /**
- * DOCUMENT ME!
+ * Jalview Desktop
+ * 
  * 
  * @author $author$
  * @version $Revision$
@@ -48,15 +51,117 @@ import javax.swing.event.MenuListener;
 public class Desktop extends jalview.jbgui.GDesktop implements
         DropTargetListener, ClipboardOwner, IProgressIndicator
 {
-  /** DOCUMENT ME!! */
+
+  private class JalviewChangeSupport implements PropertyChangeListener
+  {
+    @Override
+    public void propertyChange(PropertyChangeEvent evt)
+    {
+      // Handle change events - most are simply routed to other sources
+      changeSupport.firePropertyChange(evt);
+    }
+
+    /**
+     * change listeners are notified of changes to resources so they can update
+     * their state. E.g. - the 'services' property notifies when the available
+     * set of web service endpoints have changed.
+     */
+    private java.beans.PropertyChangeSupport changeSupport = new java.beans.PropertyChangeSupport(
+            this);
+
+    /**
+     * @param propertyName
+     * @param listener
+     * @see java.beans.PropertyChangeSupport#addPropertyChangeListener(java.lang.String,
+     *      java.beans.PropertyChangeListener)
+     */
+    public void addJalviewPropertyChangeListener(String propertyName,
+            PropertyChangeListener listener)
+    {
+      changeSupport.addPropertyChangeListener(propertyName, listener);
+    }
+
+    /**
+     * @param listener
+     * @see java.beans.PropertyChangeSupport#addPropertyChangeListener(
+     *      java.beans.PropertyChangeListener)
+     */
+    public void addJalviewPropertyChangeListener(
+            PropertyChangeListener listener)
+    {
+      changeSupport.addPropertyChangeListener(listener);
+    }
+
+    /*
+     * @param propertyName
+     * 
+     * @param oldValue
+     * 
+     * @param newValue
+     * 
+     * @see
+     * java.beans.PropertyChangeSupport#firePropertyChange(java.lang.String,
+     * java.lang.Object, java.lang.Object) public void firePropertyChange(String
+     * propertyName, Object oldValue, Object newValue) {
+     * changeSupport.firePropertyChange(propertyName, oldValue, newValue); }
+     */
+
+    /**
+     * @param propertyName
+     * @param listener
+     * @see java.beans.PropertyChangeSupport#removePropertyChangeListener(java.lang.String,
+     *      java.beans.PropertyChangeListener)
+     */
+    public void removeJalviewPropertyChangeListener(String propertyName,
+            PropertyChangeListener listener)
+    {
+      changeSupport.removePropertyChangeListener(propertyName, listener);
+    }
+
+  }
+
+  private JalviewChangeSupport changeSupport = new JalviewChangeSupport();
+
+  /**
+   * @param listener
+   * @see jalview.gui.Desktop.JalviewChangeSupport#addJalviewPropertyChangeListener(java.beans.PropertyChangeListener)
+   */
+  public void addJalviewPropertyChangeListener(
+          PropertyChangeListener listener)
+  {
+    changeSupport.addJalviewPropertyChangeListener(listener);
+  }
+
+  /**
+   * @param propertyName
+   * @param listener
+   * @see jalview.gui.Desktop.JalviewChangeSupport#addJalviewPropertyChangeListener(java.lang.String,
+   *      java.beans.PropertyChangeListener)
+   */
+  public void addJalviewPropertyChangeListener(String propertyName,
+          PropertyChangeListener listener)
+  {
+    changeSupport.addJalviewPropertyChangeListener(propertyName, listener);
+  }
+
+  /**
+   * @param propertyName
+   * @param listener
+   * @see jalview.gui.Desktop.JalviewChangeSupport#removeJalviewPropertyChangeListener(java.lang.String,
+   *      java.beans.PropertyChangeListener)
+   */
+  public void removeJalviewPropertyChangeListener(String propertyName,
+          PropertyChangeListener listener)
+  {
+    changeSupport.removeJalviewPropertyChangeListener(propertyName,
+            listener);
+  }
+
+  /** Singleton Desktop instance */
   public static Desktop instance;
 
-  // Need to decide if the Memory Usage is to be included in
-  // Next release or not.
   public static MyDesktopPane desktop;
 
-  // public static JDesktopPane desktop;
-
   static int openFrameCount = 0;
 
   static final int xOffset = 30;
@@ -70,84 +175,105 @@ public class Desktop extends jalview.jbgui.GDesktop implements
   public static boolean internalCopy = false;
 
   static int fileLoadingCount = 0;
-  class MyDesktopManager implements DesktopManager {
-         
-          private DesktopManager delegate;
-        
-          public MyDesktopManager(DesktopManager delegate) {
-             this.delegate = delegate;
-          }
-        
-          public void activateFrame(JInternalFrame f) {
-             try {
-                delegate.activateFrame(f);
-             } catch (NullPointerException npe) {
-                 Point p = getMousePosition();
-                 instance.showPasteMenu(p.x,p.y);
-             }
-          }
-
-       public void beginDraggingFrame(JComponent f) {
-               delegate.beginDraggingFrame(f);
-       }
-
-       public void beginResizingFrame(JComponent f, int direction) {
-               delegate.beginResizingFrame(f, direction);
-       }
-
-       public void closeFrame(JInternalFrame f) {
-               delegate.closeFrame(f);
-       }
-
-       public void deactivateFrame(JInternalFrame f) {
-               delegate.deactivateFrame(f);
-       }
-
-       public void deiconifyFrame(JInternalFrame f) {
-               delegate.deiconifyFrame(f);
-       }
-
-       public void dragFrame(JComponent f, int newX, int newY) {
-               delegate.dragFrame(f, newX, newY);
-       }
-
-       public void endDraggingFrame(JComponent f) {
-               delegate.endDraggingFrame(f);
-       }
-
-       public void endResizingFrame(JComponent f) {
-               delegate.endResizingFrame(f);
-       }
-
-       public void iconifyFrame(JInternalFrame f) {
-               delegate.iconifyFrame(f);
-       }
-
-       public void maximizeFrame(JInternalFrame f) {
-               delegate.maximizeFrame(f);
-       }
-
-       public void minimizeFrame(JInternalFrame f) {
-               delegate.minimizeFrame(f);
-       }
-
-       public void openFrame(JInternalFrame f) {
-               delegate.openFrame(f);
-       }
-
-       public void resizeFrame(JComponent f, int newX, int newY, int newWidth,
-                       int newHeight) {
-               delegate.resizeFrame(f, newX, newY, newWidth, newHeight);
-       }
-
-       public void setBoundsForFrame(JComponent f, int newX, int newY,
-                       int newWidth, int newHeight) {
-               delegate.setBoundsForFrame(f, newX, newY, newWidth, newHeight);
-       }
-        
-          // All other methods, simply delegate
-        
-       }
+
+  class MyDesktopManager implements DesktopManager
+  {
+
+    private DesktopManager delegate;
+
+    public MyDesktopManager(DesktopManager delegate)
+    {
+      this.delegate = delegate;
+    }
+
+    public void activateFrame(JInternalFrame f)
+    {
+      try
+      {
+        delegate.activateFrame(f);
+      } catch (NullPointerException npe)
+      {
+        Point p = getMousePosition();
+        instance.showPasteMenu(p.x, p.y);
+      }
+    }
+
+    public void beginDraggingFrame(JComponent f)
+    {
+      delegate.beginDraggingFrame(f);
+    }
+
+    public void beginResizingFrame(JComponent f, int direction)
+    {
+      delegate.beginResizingFrame(f, direction);
+    }
+
+    public void closeFrame(JInternalFrame f)
+    {
+      delegate.closeFrame(f);
+    }
+
+    public void deactivateFrame(JInternalFrame f)
+    {
+      delegate.deactivateFrame(f);
+    }
+
+    public void deiconifyFrame(JInternalFrame f)
+    {
+      delegate.deiconifyFrame(f);
+    }
+
+    public void dragFrame(JComponent f, int newX, int newY)
+    {
+      delegate.dragFrame(f, newX, newY);
+    }
+
+    public void endDraggingFrame(JComponent f)
+    {
+      delegate.endDraggingFrame(f);
+    }
+
+    public void endResizingFrame(JComponent f)
+    {
+      delegate.endResizingFrame(f);
+    }
+
+    public void iconifyFrame(JInternalFrame f)
+    {
+      delegate.iconifyFrame(f);
+    }
+
+    public void maximizeFrame(JInternalFrame f)
+    {
+      delegate.maximizeFrame(f);
+    }
+
+    public void minimizeFrame(JInternalFrame f)
+    {
+      delegate.minimizeFrame(f);
+    }
+
+    public void openFrame(JInternalFrame f)
+    {
+      delegate.openFrame(f);
+    }
+
+    public void resizeFrame(JComponent f, int newX, int newY, int newWidth,
+            int newHeight)
+    {
+      delegate.resizeFrame(f, newX, newY, newWidth, newHeight);
+    }
+
+    public void setBoundsForFrame(JComponent f, int newX, int newY,
+            int newWidth, int newHeight)
+    {
+      delegate.setBoundsForFrame(f, newX, newY, newWidth, newHeight);
+    }
+
+    // All other methods, simply delegate
+
+  }
+
   /**
    * Creates a new Desktop object.
    */
@@ -177,7 +303,8 @@ public class Desktop extends jalview.jbgui.GDesktop implements
 
     // This line prevents Windows Look&Feel resizing all new windows to maximum
     // if previous window was maximised
-    desktop.setDesktopManager(new MyDesktopManager(new DefaultDesktopManager()));
+    desktop.setDesktopManager(new MyDesktopManager(
+            new DefaultDesktopManager()));
     Rectangle dims = getLastKnownDimensions("");
     if (dims != null)
     {
@@ -231,7 +358,6 @@ public class Desktop extends jalview.jbgui.GDesktop implements
       }
     });
 
-    discoverer = new jalview.ws.jws1.Discoverer(); // Only gets started if gui is
     // displayed.
     // Thread off a new instance of the file chooser - this reduces the time it
     // takes to open it later on.
@@ -1752,7 +1878,7 @@ public class Desktop extends jalview.jbgui.GDesktop implements
 
     public void paintComponent(Graphics g)
     {
-      if (showMemoryUsage && g != null)
+      if (showMemoryUsage && g != null && df != null)
       {
         if (percentUsage < 20)
           g.setColor(Color.red);
@@ -1965,15 +2091,66 @@ public class Desktop extends jalview.jbgui.GDesktop implements
 
   public void startServiceDiscovery()
   {
-    discoverer.start();
-    
-    try {
-      new Thread(jalview.ws.EnfinEnvision2OneWay.getInstance()).start();
+    startServiceDiscovery(false);
+  }
+
+  public void startServiceDiscovery(boolean blocking)
+  {
+    boolean alive = true;
+    Thread t0 = null, t1 = null, t2 = null;
+
+    // todo: changesupport handlers need to be transferred
+    if (discoverer == null)
+    {
+      discoverer = new jalview.ws.jws1.Discoverer();
+      // register PCS handler for desktop.
+      discoverer.addPropertyChangeListener(changeSupport);
+    }
+    if (Cache.getDefault("SHOW_JWS1_SERVICES", true))
+    {
+      (t0 = new Thread(discoverer)).start();
+    }
+
+    try
+    {
+      if (Cache.getDefault("SHOW_ENVISION2_SERVICES", true))
+      {
+        // EnfinEnvision web service menu entries are rebuild every time the
+        // menu is shown, so no changeSupport events are needed.
+        jalview.ws.EnfinEnvision2OneWay.getInstance();
+        (t1 = new Thread(jalview.ws.EnfinEnvision2OneWay.getInstance()))
+                .start();
+      }
     } catch (Exception e)
     {
-      Cache.log.info("Exception when trying to launch Envision2 workflow discovery.",e);
+      Cache.log
+              .info(
+                      "Exception when trying to launch Envision2 workflow discovery.",
+                      e);
       Cache.log.info(e.getStackTrace());
     }
-    new Thread(jalview.ws.jws2.Jws2Discoverer.getDiscoverer()).start();
+    if (Cache.getDefault("SHOW_JWS2_SERVICES", true))
+    {
+      jalview.ws.jws2.Jws2Discoverer.getDiscoverer()
+              .addPropertyChangeListener(changeSupport);
+      (t2 = new Thread(jalview.ws.jws2.Jws2Discoverer.getDiscoverer()))
+              .start();
+    }
+    if (blocking)
+    {
+      while (alive)
+      {
+        try
+        {
+          Thread.sleep(15);
+        } catch (Exception e)
+        {
+        }
+        alive = (t1 != null && t1.isAlive())
+                || (t2 != null && t2.isAlive())
+                || (t0 != null && t0.isAlive());
+      }
+    }
   }
+
 }
index 90581dc..0638b69 100644 (file)
@@ -44,13 +44,12 @@ import javax.swing.*;
 
 import ext.vamsas.*;
 
-public class Discoverer extends Thread implements Runnable
+public class Discoverer implements Runnable
 {
   ext.vamsas.IRegistry registry; // the root registry service.
 
   private java.beans.PropertyChangeSupport changeSupport = new java.beans.PropertyChangeSupport(
           this);
-
   /**
    * change listeners are notified of "services" property changes
    * 
@@ -387,7 +386,7 @@ public class Discoverer extends Thread implements Runnable
     // Vector oldServicelist = serviceList;
     services = sscat;
     serviceList = cat;
-    firePropertyChange("services", oldServices, services);
+    changeSupport.firePropertyChange("services", oldServices, services);
   }
 
   /**
index 6aa4607..784ff49 100644 (file)
@@ -6,6 +6,7 @@ import java.beans.PropertyChangeEvent;
 import java.beans.PropertyChangeListener;
 import java.net.ConnectException;
 import java.util.HashSet;
+import java.util.StringTokenizer;
 import java.util.Vector;
 
 import javax.swing.JMenu;
@@ -60,15 +61,16 @@ public class Jws2Discoverer implements Runnable, WSMenuEntryProviderI
   }
 
   boolean running = false;
-
+  Thread oldthread=null;
   @Override
   public void run()
   {
-    if (running)
+    if (running && oldthread!=null && oldthread.isAlive())
     {
       return;
     }
     running = true;
+    oldthread = Thread.currentThread();
     try
     {
       Class foo = getClass().getClassLoader().loadClass(
@@ -77,56 +79,59 @@ public class Jws2Discoverer implements Runnable, WSMenuEntryProviderI
     {
       System.err
               .println("Not enabling Jalview Webservices version 2: client jar is not available."
-                      +"\nPlease check that your webstart JNLP file is up to date!");
+                      + "\nPlease check that your webstart JNLP file is up to date!");
       running = false;
       return;
     }
-    // Cache.initLogger();
-    // Cache.log.setLevel(Level.DEBUG);
-    // TODO: Document and PACK JWS2
-    String jwsservers = Cache.getDefault("JWS2HOSTURLS",
-            "http://webservices.compbio.dundee.ac.uk:8084/jws2");
-    try
+    if (services != null)
     {
-      if (Jws2Base.validURL(jwsservers))
+      services.removeAllElements();
+    }
+    for (String jwsservers : getServiceUrls())
+    {
+      try
       {
-        // look for services
-        for (Services srv : Jws2Base.Services.values())
+        if (Jws2Base.validURL(jwsservers))
         {
-          MsaWS service = null;
-          try
-          {
-            service = Jws2Base.connect(jwsservers, srv);
-          } catch (Exception e)
+          // look for services
+          for (Services srv : Jws2Base.Services.values())
           {
-            System.err.println("Jws2 Discoverer: Problem with "
-                    + jwsservers + " with service " + srv + ":\n"
-                    + e.getMessage());
-            if (!(e instanceof javax.xml.ws.WebServiceException))
+            MsaWS service = null;
+            try
             {
-              e.printStackTrace();
+              service = Jws2Base.connect(jwsservers, srv);
+            } catch (Exception e)
+            {
+              System.err.println("Jws2 Discoverer: Problem on "
+                      + jwsservers + " with service " + srv + ":\n"
+                      + e.getMessage());
+              if (!(e instanceof javax.xml.ws.WebServiceException))
+              {
+                e.printStackTrace();
+              }
+            }
+            ;
+            if (service != null)
+            {
+              addService(jwsservers, srv, service);
             }
           }
-          ;
-          if (service != null)
-          {
-            addService(jwsservers, srv, service);
-          }
-        }
 
-      }
-      else
+        }
+        else
+        {
+          Cache.log.info("Ignoring invalid Jws2 service url " + jwsservers);
+        }
+      } catch (Exception e)
+      {
+        e.printStackTrace();
+        Cache.log.warn("Exception when discovering Jws2 services.", e);
+      } catch (Error e)
       {
-        Cache.log.info("Ignoring invalid Jws2 service url " + jwsservers);
+        Cache.log.error("Exception when discovering Jws2 services.", e);
       }
-    } catch (Exception e)
-    {
-      e.printStackTrace();
-      Cache.log.warn("Exception when discovering Jws2 services.", e);
-    } catch (Error e)
-    {
-      Cache.log.error("Exception when discovering Jws2 services.", e);
     }
+    oldthread = null;
     running = false;
     changeSupport.firePropertyChange("services", new Vector(), services);
   }
@@ -280,4 +285,78 @@ 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)
+  {
+    if (urls != null)
+    {
+      StringBuffer urlbuffer = new StringBuffer();
+      String sep = "";
+      for (String url : urls)
+      {
+        urlbuffer.append(sep);
+        urlbuffer.append(url);
+        sep = ",";
+      }
+      Cache.setProperty(JWS2HOSTURLS, urlbuffer.toString());
+    }
+    else
+    {
+      Cache.removeProperty(JWS2HOSTURLS);
+    }
+  }
+
+  public static Vector<String> getServiceUrls()
+  {
+    String surls = Cache.getDefault(JWS2HOSTURLS,
+            "http://webservices.compbio.dundee.ac.uk:8084/jws2");
+    Vector<String> urls = new Vector<String>();
+    try
+    {
+      StringTokenizer st = new StringTokenizer(surls, ",");
+      while (st.hasMoreElements())
+      {
+        String url = null;
+        try
+        {
+          java.net.URL u = new java.net.URL(url = st.nextToken());
+          if (!urls.contains(url))
+          {
+            urls.add(url);
+          }
+          else
+          {
+            jalview.bin.Cache.log.info("Ignoring duplicate url in "
+                    + JWS2HOSTURLS + " list");
+          }
+        } catch (Exception ex)
+        {
+          jalview.bin.Cache.log
+                  .warn("Problem whilst trying to make a URL from '"
+                          + ((url != null) ? url : "<null>") + "'");
+          jalview.bin.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);
+        }
+      }
+    } catch (Exception ex)
+    {
+      jalview.bin.Cache.log.warn(
+              "Error parsing comma separated list of urls in "
+                      + JWS2HOSTURLS + " preference.", ex);
+    }
+    if (urls.size() >= 0)
+    {
+      return urls;
+    }
+    return null;
+  }
+
 }