JAL-715 serialise and deserialise multiple rest client strings as a jalview property
authorjprocter <jprocter@compbio.dundee.ac.uk>
Tue, 30 Aug 2011 10:28:27 +0000 (11:28 +0100)
committerjprocter <jprocter@compbio.dundee.ac.uk>
Tue, 30 Aug 2011 10:28:27 +0000 (11:28 +0100)
src/jalview/ws/rest/RestClient.java
src/jalview/ws/rest/RestServiceDescription.java

index 114f51a..ee23790 100644 (file)
@@ -7,6 +7,7 @@ import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
 import java.util.Collection;
 import java.util.Hashtable;
+import java.util.Vector;
 
 import javax.swing.JMenu;
 import javax.swing.JMenuItem;
@@ -341,11 +342,54 @@ public class RestClient extends WSClient implements WSClientI,
     return true;
   }
 
+  protected static Vector<String> services=null;
   public static RestClient[] getRestClients()
   {
-    return new RestClient[] { makeShmmrRestClient() };
+    if (services==null)
+    {
+      services = new Vector<String>();
+      try {
+      for (RestServiceDescription descr: RestServiceDescription.parseDescriptions(jalview.bin.Cache.getDefault("RSBS_SERVICES",makeShmmrRestClient().service.toString()))) 
+      {
+        services.add(descr.toString());
+      }
+      }
+      catch (Exception ex) {
+        System.err.println("Serious - RSBS descriptions in user preferences are corrupt!");
+        ex.printStackTrace();
+      }
+      
+    }
+    RestClient[] lst = new RestClient[services.size()];
+    int i=0;
+    for (String svc:services) {
+      lst[i++] = new RestClient(new RestServiceDescription(svc));
+    }
+    return lst;
+  }
+  public static void main(String args[])
+  {
+    try {
+      RestClient[] clients = getRestClients();
+      System.out.println("Got "+clients.length+" clients.");
+      int i=0;
+      Vector<String> urls=new Vector<String>();
+      for (RestClient cl:clients) {
+        System.out.println(""+(++i)+": "+cl.service.toString());
+        urls.add(cl.service.toString());
+      }
+      setRsbsServices(urls);
+      if (clients.length!=getRestClients().length)
+      {
+        System.err.println("Failed. Differing numbers of clients when stringified and parsed again.");
+      }
+      
+    } catch (Throwable x)
+    {
+      System.err.println("Failed. Unexpected exception.");
+      x.printStackTrace();
+    }
   }
-
   public String getAction()
   {
     return service.details.Action;
@@ -356,4 +400,20 @@ public class RestClient extends WSClient implements WSClientI,
     return service;
   }
 
+  public static Vector<String> getRsbsDescriptions()
+  {
+    Vector<String> rsbsDescrs = new Vector<String>();
+    for (RestClient rsbs:getRestClients())
+    {
+      rsbsDescrs.add(rsbs.getRestDescription().toString());
+    }
+    return rsbsDescrs;
+  }
+
+  public static void setRsbsServices(Vector<String> rsbsUrls)
+  {
+    // TODO: consider validating services ?
+    services = new Vector<String>(rsbsUrls);    
+  }
+
 }
index dec4d7c..9f4495e 100644 (file)
@@ -49,6 +49,13 @@ import com.sun.tools.doclets.internal.toolkit.util.DocFinder.Output;
 public class RestServiceDescription
 {
   /**
+   * create a new rest service description ready to be configured
+   */
+  public RestServiceDescription()
+  {
+    
+  }
+  /**
    * @param details
    * @param postUrl
    * @param urlSuffix
@@ -501,6 +508,7 @@ public class RestServiceDescription
     ;
     boolean valid = true;
     String val = null;
+    int l = warnings.length();
     int i;
     for (String prop : props)
     {
@@ -538,12 +546,11 @@ public class RestServiceDescription
       }
       if (prop.equals("returns"))
       {
-        int l = warnings.length();
         _configureOutputFormatFrom(val, warnings);
-        valid = (l != warnings.length());
       }
     }
-    return valid;
+    // return true if valid is true and warning buffer was not appended to.
+    return valid && (l == warnings.length());
   }
 
   private String _genOutputFormatString()
@@ -598,18 +605,18 @@ public class RestServiceDescription
 
   private String getServiceIOProperties()
   {
-    String[] vls = new String[]
-    { isHseparable() ? "hseparable" : "",
-        isVseparable() ? "vseparable" : "",
-        (new String("gapCharacter='" + gapCharacter + "'")),
-        (new String("returns='" + _genOutputFormatString() + "'")) };
-
-    return arrayToSeparatorList(vls, ",");
+    ArrayList<String> vls = new ArrayList<String>();
+    if (isHseparable()) { vls.add("hseparable");};
+    if (isVseparable()) { vls.add("vseparable");};
+    vls.add(new String("gapCharacter='" + gapCharacter + "'"));
+    vls.add(new String("returns='" + _genOutputFormatString() + "'"));
+    return arrayToSeparatorList(vls.toArray(new String[0]), ",");
   }
 
   public String toString()
   {
     StringBuffer result = new StringBuffer();
+    result.append("|");
     result.append(details.Name);
     result.append('|');
     result.append(details.Action);
@@ -633,31 +640,63 @@ public class RestServiceDescription
     return result.toString();
   }
 
+  /**
+   * processes a service encoded as a string (as generated by RestServiceDescription.toString())
+   * Note - this will only use the first service definition encountered in the string to configure the service.
+   * @param encoding
+   * @param warnings - where warning messages are reported.
+   * @return true if configuration was parsed successfully. 
+   */
   public boolean configureFromEncodedString(String encoding,
           StringBuffer warnings)
   {
-    boolean invalid = false;
     String[] list = separatorListToArray(encoding, "|");
-    details.Name = list[0];
-    details.Action = list[1];
-    details.description = list[2];
-    invalid |= !configureFromServiceInputProperties(list[3], warnings);
-    if (list.length > 5)
+    
+    int nextpos=parseServiceList(list,warnings, 0);
+    if (nextpos>0)
     {
-      urlSuffix = list[4];
-      invalid |= !configureFromInputParamEncodedUrl(list[5], warnings);
+      return true;
+    }
+    return false;
+  }
+  /**
+   * processes the given list from position p, attempting to configure the service from it.
+   * Service lists are formed by concatenating individual stringified services. The first character of a stringified service is '|', enabling this, and the parser will ignore empty fields in a '|' separated list when they fall outside a service definition.
+   * @param list
+   * @param warnings
+   * @param p
+   * @return
+   */
+  protected int parseServiceList(String[] list, StringBuffer warnings, int p)
+  {
+    boolean invalid = false;
+    // look for the first non-empty position - expect it to be service name
+    while (list[p]!=null && list[p].trim().length()==0)
+    {
+      p++;
+    }
+    details.Name = list[p];
+    details.Action = list[p+1];
+    details.description = list[p+2];
+    invalid |= !configureFromServiceInputProperties(list[p+3], warnings);
+    if (list.length-p > 5 && list[p+5]!=null && list[p+5].trim().length()>5)
+    {
+      urlSuffix = list[p+4];
+      invalid |= !configureFromInputParamEncodedUrl(list[p+5], warnings);
+      p+=6;
     }
     else
     {
-      if (list.length > 4)
+      if (list.length-p > 4 && list[p+4]!=null && list[p+4].trim().length()>5)
       {
         urlSuffix = null;
-        invalid |= !configureFromInputParamEncodedUrl(list[4], warnings);
+        invalid |= !configureFromInputParamEncodedUrl(list[p+4], warnings);
+        p+=5;
       }
     }
-    return !invalid;
+    return invalid ? -1 : p;
   }
-
+  
   /**
    * @return string representation of the input parameters, their type and
    *         constraints, appended to the service's base submission URL
@@ -1029,4 +1068,29 @@ public class RestServiceDescription
     return resultData;
   }
 
+  /**
+   * parse a concatenated list of rest service descriptions into an array
+   * @param services
+   * @return zero or more services.
+   * @throws exceptions if the services are improperly encoded.
+   */
+  public static List<RestServiceDescription> parseDescriptions(String services) throws Exception
+  {
+    String[] list = separatorListToArray(services, "|");
+    List<RestServiceDescription> svcparsed = new ArrayList<RestServiceDescription>();
+    int p=0,lastp=0;
+    StringBuffer warnings=new StringBuffer();
+    do {
+      RestServiceDescription rsd = new RestServiceDescription();
+      p=rsd.parseServiceList(list, warnings, lastp=p);
+      if (p>lastp && rsd.isValid())
+      {
+        svcparsed.add(rsd);
+      } else {
+        throw new Exception("Failed to parse user defined RSBS services from :"+services+"\nFirst error was encountered at token "+lastp+" starting "+list[lastp]+":\n"+rsd.getInvalidMessage());
+      }
+    } while (p<lastp && p<list.length-1);
+    return svcparsed;
+  }
+
 }