JAL-919, JAL-715 - prototype service editing dialog using jalview parameter model...
[jalview.git] / src / jalview / ws / rest / RestServiceDescription.java
index 20895a2..dec4d7c 100644 (file)
@@ -64,12 +64,15 @@ public class RestServiceDescription
   {
     super();
     this.details = new UIinfo();
-    details.Action = action;
-    details.description = description;
-    details.Name = name;
-    this.postUrl = postUrl;
-    this.urlSuffix = urlSuffix;
-    this.inputParams = inputParams;
+    details.Action = action == null ? "" : action;
+    details.description = description == null ? "" : description;
+    details.Name = name == null ? "" : name;
+    this.postUrl = postUrl == null ? "" : postUrl;
+    this.urlSuffix = urlSuffix == null ? "" : urlSuffix;
+    if (inputParams != null)
+    {
+      this.inputParams = inputParams;
+    }
     this.hseparable = hseparable;
     this.vseparable = vseparable;
     this.gapCharacter = gapCharacter;
@@ -229,7 +232,7 @@ public class RestServiceDescription
   /**
    * input info given as key/value pairs - mapped to post arguments
    */
-  Map<String, InputType> inputParams = new HashMap<String,InputType>();
+  Map<String, InputType> inputParams = new HashMap<String, InputType>();
 
   /**
    * assigns the given inputType it to its corresponding input parameter token
@@ -318,30 +321,20 @@ public class RestServiceDescription
 
   public RestServiceDescription(RestServiceDescription toedit)
   {
-    // Rather then do the above, we cheat and use our human readable serialization code to clone everything
+    // Rather then do the above, we cheat and use our human readable
+    // serialization code to clone everything
     this(toedit.toString());
     /**
-    if (toedit == null)
-    {
-      return;
-    }
-    /**
-    urlSuffix = toedit.urlSuffix;
-    postUrl = toedit.postUrl;
-    hseparable = toedit.hseparable;
-    vseparable = toedit.vseparable;
-    gapCharacter = toedit.gapCharacter;
-    details = new RestServiceDescription.UIinfo();
-    details.Action = toedit.details.Action;
-    details.description = toedit.details.description;
-    details.Name = toedit.details.Name;
-    for (InputType itype: toedit.inputParams.values())
-    {
-      inputParams.put(itype.token, itype.clone());
-      
-    }
-            
-       */
+     * if (toedit == null) { return; } /** urlSuffix = toedit.urlSuffix; postUrl
+     * = toedit.postUrl; hseparable = toedit.hseparable; vseparable =
+     * toedit.vseparable; gapCharacter = toedit.gapCharacter; details = new
+     * RestServiceDescription.UIinfo(); details.Action = toedit.details.Action;
+     * details.description = toedit.details.description; details.Name =
+     * toedit.details.Name; for (InputType itype: toedit.inputParams.values()) {
+     * inputParams.put(itype.token, itype.clone());
+     * 
+     * }
+     */
     // TODO Implement copy constructor NOW*/
   }
 
@@ -380,12 +373,13 @@ public class RestServiceDescription
       return null;
     java.util.ArrayList<String> jv = new ArrayList<String>();
     int cp = 0, pos, escape;
-    boolean wasescaped = false;
+    boolean wasescaped = false,wasquoted=false;
     String lstitem = null;
     while ((pos = list.indexOf(separator, cp)) >= cp)
     {
-      escape = (pos>0 && list.charAt(pos - 1) == '\\') ? -1 : 0;
-      if (wasescaped)
+      
+      escape = (pos > 0 && list.charAt(pos - 1) == '\\') ? -1 : 0;
+      if (wasescaped || wasquoted)
       {
         // append to previous pos
         jv.set(jv.size() - 1,
@@ -399,11 +393,20 @@ public class RestServiceDescription
       }
       cp = pos + seplen;
       wasescaped = escape == -1;
+      if (!wasescaped)
+      {
+        // last separator may be in an unmatched quote
+        if (java.util.regex.Pattern.matches("('[^']*')*[^']*'",lstitem))
+        {
+          wasquoted=true;
+        }
+      }
+      
     }
     if (cp < list.length())
     {
       String c = list.substring(cp);
-      if (wasescaped)
+      if (wasescaped || wasquoted)
       {
         // append final separator
         jv.set(jv.size() - 1, lstitem + separator + c);
@@ -455,7 +458,7 @@ public class RestServiceDescription
       {
         if (list[i] != null)
         {
-          if (v.length()>0)
+          if (v.length() > 0)
           {
             v.append(separator);
           }
@@ -496,7 +499,7 @@ public class RestServiceDescription
       return true;
     }
     ;
-    boolean valid=true;
+    boolean valid = true;
     String val = null;
     int i;
     for (String prop : props)
@@ -521,9 +524,9 @@ public class RestServiceDescription
       }
       if (prop.equals("gapCharacter"))
       {
-        if (val == null || val.length()==0 || val.length() > 1)
+        if (val == null || val.length() == 0 || val.length() > 1)
         {
-          valid=false;
+          valid = false;
           warnings.append((warnings.length() > 0 ? "\n" : "")
                   + ("Invalid service property: gapCharacter=' ' (single character) - was given '"
                           + val + "'"));
@@ -535,9 +538,9 @@ public class RestServiceDescription
       }
       if (prop.equals("returns"))
       {
-        int l=warnings.length();
+        int l = warnings.length();
         _configureOutputFormatFrom(val, warnings);
-        valid =  (l!=warnings.length());
+        valid = (l != warnings.length());
       }
     }
     return valid;
@@ -546,7 +549,7 @@ public class RestServiceDescription
   private String _genOutputFormatString()
   {
     String buff = "";
-    if (resultData==null)
+    if (resultData == null)
     {
       return "";
     }
@@ -564,9 +567,10 @@ public class RestServiceDescription
   private void _configureOutputFormatFrom(String outstring,
           StringBuffer warnings)
   {
-    if (outstring.indexOf(";")==-1) {
+    if (outstring.indexOf(";") == -1)
+    {
       // we add a token, for simplicity
-      outstring = outstring+";";
+      outstring = outstring + ";";
     }
     StringTokenizer st = new StringTokenizer(outstring, ";");
     String tok = "";
@@ -637,7 +641,7 @@ public class RestServiceDescription
     details.Name = list[0];
     details.Action = list[1];
     details.description = list[2];
-    invalid|=!configureFromServiceInputProperties(list[3], warnings);
+    invalid |= !configureFromServiceInputProperties(list[3], warnings);
     if (list.length > 5)
     {
       urlSuffix = list[4];
@@ -645,8 +649,11 @@ public class RestServiceDescription
     }
     else
     {
-      urlSuffix = null;
-      invalid |= !configureFromInputParamEncodedUrl(list[4], warnings);
+      if (list.length > 4)
+      {
+        urlSuffix = null;
+        invalid |= !configureFromInputParamEncodedUrl(list[4], warnings);
+      }
     }
     return !invalid;
   }
@@ -746,7 +753,8 @@ public class RestServiceDescription
         iprmparams = iprm.substring(colon + 1);
         iprm = iprm.substring(0, colon);
       }
-      valid = parseTypeString(prms.group(0), tok,  iprm, iprmparams, iparams, warnings);
+      valid = parseTypeString(prms.group(0), tok, iprm, iprmparams,
+              iparams, warnings);
     }
     if (valid)
     {
@@ -764,19 +772,25 @@ public class RestServiceDescription
     return valid;
   }
 
-  public static boolean parseTypeString(String fullstring, String tok, String iprm, String iprmparams,
-           Map<String, InputType> iparams, StringBuffer warnings)
+  public static Class[] getInputTypes()
   {
-    boolean valid=true;
-    InputType jinput;
     // TODO - find a better way of maintaining this classlist
-    for (Class type : new Class[]
+    return new Class[]
     { jalview.ws.rest.params.Alignment.class,
         jalview.ws.rest.params.AnnotationFile.class,
         SeqGroupIndexVector.class,
         jalview.ws.rest.params.SeqIdVector.class,
         jalview.ws.rest.params.SeqVector.class,
-        jalview.ws.rest.params.Tree.class })
+        jalview.ws.rest.params.Tree.class };
+  }
+
+  public static boolean parseTypeString(String fullstring, String tok,
+          String iprm, String iprmparams, Map<String, InputType> iparams,
+          StringBuffer warnings)
+  {
+    boolean valid = true;
+    InputType jinput;
+    for (Class type : getInputTypes())
     {
       try
       {
@@ -786,20 +800,20 @@ public class RestServiceDescription
           ArrayList<String> al = new ArrayList<String>();
           for (String prprm : separatorListToArray(iprmparams, ","))
           {
+            // hack to ensure that strings like "sep=','" containing unescaped commas as values are concatenated
             al.add(prprm.trim());
           }
           if (!jinput.configureFromURLtokenString(al, warnings))
           {
             valid = false;
-            warnings.append("Failed to parse '" + fullstring
-                    + "' as a " + jinput.getURLtokenPrefix()
-                    + " input tag.\n");
+            warnings.append("Failed to parse '" + fullstring + "' as a "
+                    + jinput.getURLtokenPrefix() + " input tag.\n");
           }
           else
           {
             jinput.token = tok;
             iparams.put(tok, jinput);
-            valid=true;
+            valid = true;
           }
           break;
         }
@@ -812,9 +826,20 @@ public class RestServiceDescription
     return valid;
   }
 
-
   public static void main(String argv[])
   {
+    // test separator list
+    try {
+      assert(separatorListToArray("foo=',',min='foo',max='1,2,3',fa=','", ",").length==4);
+      if (separatorListToArray("minsize='2', sep=','", ",").length==2)
+      {
+        assert(false);
+      }
+      
+    } catch (AssertionError x)
+    {
+      System.err.println("separatorListToArray is faulty.");
+    }
     if (argv.length == 0)
     {
       if (!testRsdExchange("Test using default Shmmr service",
@@ -971,7 +996,7 @@ public class RestServiceDescription
     return jobId + urlSuffix;
   }
 
-  private List<JvDataType> resultData=new ArrayList<JvDataType>();
+  private List<JvDataType> resultData = new ArrayList<JvDataType>();
 
   /**
    * 
@@ -1003,5 +1028,5 @@ public class RestServiceDescription
   {
     return resultData;
   }
-  
+
 }