JAL-4199 Update slivka client
[jalview.git] / src / jalview / ws2 / client / slivka / SlivkaWSClient.java
index 16c9d3a..7dcdae1 100644 (file)
@@ -6,14 +6,24 @@ import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
 import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+import java.util.Collections;
 import java.util.EnumMap;
 import java.util.List;
+import java.util.Map;
 import java.util.regex.Pattern;
 
+import jalview.api.FeatureColourI;
 import jalview.bin.Cache;
+import jalview.bin.Console;
+import jalview.datamodel.Alignment;
+import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.SequenceI;
+import jalview.datamodel.features.FeatureMatcherSetI;
+import jalview.io.AnnotationFile;
 import jalview.io.DataSourceType;
+import jalview.io.FeaturesFile;
 import jalview.io.FileFormat;
 import jalview.io.FormatAdapter;
 import jalview.ws.params.ArgumentI;
@@ -21,22 +31,25 @@ import jalview.ws2.api.Credentials;
 import jalview.ws2.api.JobStatus;
 import jalview.ws2.api.WebServiceJobHandle;
 import jalview.ws2.client.api.AlignmentWebServiceClientI;
+import jalview.ws2.client.api.AnnotationWebServiceClientI;
 import jalview.ws2.client.api.WebServiceClientI;
 import uk.ac.dundee.compbio.slivkaclient.Job;
 import uk.ac.dundee.compbio.slivkaclient.Parameter;
 import uk.ac.dundee.compbio.slivkaclient.SlivkaClient;
 import uk.ac.dundee.compbio.slivkaclient.SlivkaService;
 
+import static java.lang.String.format;
+
 public class SlivkaWSClient implements WebServiceClientI
 {
   final SlivkaService service;
 
   final SlivkaClient client;
 
-  SlivkaWSClient(SlivkaService service)
+  SlivkaWSClient(SlivkaClient client, SlivkaService service)
   {
     this.service = service;
-    this.client = service.getClient();
+    this.client = client;
   }
 
   @Override
@@ -52,13 +65,14 @@ public class SlivkaWSClient implements WebServiceClientI
   }
 
   // pattern for matching media types
-  static final Pattern mediaTypePattern = Pattern.compile("(?:text|application)\\/(?:x-)?(\\w+)");
+  static final Pattern mediaTypePattern = Pattern.compile(
+      "(?:text|application)\\/(?:x-)?([\\w-]+)");
 
   @Override
   public WebServiceJobHandle submit(List<SequenceI> sequences,
       List<ArgumentI> args, Credentials credentials) throws IOException
   {
-    var request = new uk.ac.dundee.compbio.slivkaclient.JobRequest();
+    var request = new uk.ac.dundee.compbio.slivkaclient.RequestValues();
     for (Parameter param : service.getParameters())
     {
       // TODO: restrict input sequences parameter name to "sequences"
@@ -81,7 +95,7 @@ public class SlivkaWSClient implements WebServiceClientI
         }
         if (format == null)
         {
-          Cache.log.warn(String.format(
+          Console.warn(String.format(
               "Unknown input format %s, assuming fasta.",
               fileParam.getMediaType()));
           format = FileFormat.Fasta;
@@ -102,7 +116,7 @@ public class SlivkaWSClient implements WebServiceClientI
         Parameter param = service.getParameter(paramId);
         if (param instanceof Parameter.FlagParameter)
         {
-          if (arg.getValue() != null && !arg.getValue().isBlank())
+          if (arg.getValue() != null && !arg.getValue().isEmpty())
             request.addData(paramId, true);
           else
             request.addData(paramId, false);
@@ -117,8 +131,8 @@ public class SlivkaWSClient implements WebServiceClientI
         }
       }
     }
-    var job = service.submitJob(request);
-    return createJobHandle(job.getId());
+    var jobId = client.submitJob(service, request);
+    return createJobHandle(jobId);
   }
 
   protected WebServiceJobHandle createJobHandle(String jobId)
@@ -131,8 +145,7 @@ public class SlivkaWSClient implements WebServiceClientI
   @Override
   public JobStatus getStatus(WebServiceJobHandle job) throws IOException
   {
-    var slivkaJob = client.getJob(job.getJobId());
-    return statusMap.getOrDefault(slivkaJob.getStatus(), JobStatus.UNKNOWN);
+    return statusMap.getOrDefault(client.fetchJobStatus(job.getJobId()), JobStatus.UNKNOWN);
   }
 
   protected static final EnumMap<Job.Status, JobStatus> statusMap = new EnumMap<>(Job.Status.class);
@@ -154,14 +167,13 @@ public class SlivkaWSClient implements WebServiceClientI
   @Override
   public String getLog(WebServiceJobHandle job) throws IOException
   {
-    var slivkaJob = client.getJob(job.getJobId());
-    for (var f : slivkaJob.getResults())
+    for (var f : client.fetchFilesList(job.getJobId()))
     {
       if (f.getLabel().equals("log"))
       {
         ByteArrayOutputStream stream = new ByteArrayOutputStream();
-        f.writeTo(stream);
-        return stream.toString(StandardCharsets.UTF_8);
+        client.writeFileTo(f, stream);
+        return stream.toString("UTF-8");
       }
     }
     return "";
@@ -170,14 +182,13 @@ public class SlivkaWSClient implements WebServiceClientI
   @Override
   public String getErrorLog(WebServiceJobHandle job) throws IOException
   {
-    var slivkaJob = client.getJob(job.getJobId());
-    for (var f : slivkaJob.getResults())
+    for (var f : client.fetchFilesList(job.getJobId()))
     {
       if (f.getLabel().equals("error-log"))
       {
         ByteArrayOutputStream stream = new ByteArrayOutputStream();
-        f.writeTo(stream);
-        return stream.toString(StandardCharsets.UTF_8);
+        client.writeFileTo(f, stream);
+        return stream.toString("UTF-8");
       }
     }
     return "";
@@ -187,7 +198,7 @@ public class SlivkaWSClient implements WebServiceClientI
   public void cancel(WebServiceJobHandle job)
       throws IOException, UnsupportedOperationException
   {
-    throw new UnsupportedOperationException(
+    Console.warn(
         "slivka client does not support job cancellation");
   }
 }
@@ -196,16 +207,15 @@ class SlivkaAlignmentWSClient extends SlivkaWSClient
     implements AlignmentWebServiceClientI
 {
 
-  SlivkaAlignmentWSClient(SlivkaService service)
+  SlivkaAlignmentWSClient(SlivkaClient client, SlivkaService service)
   {
-    super(service);
+    super(client, service);
   }
 
   @Override
   public AlignmentI getAlignment(WebServiceJobHandle job) throws IOException
   {
-    var slivkaJob = client.getJob(job.getJobId());
-    for (var f : slivkaJob.getResults())
+    for (var f : client.fetchFilesList(job.getJobId()))
     {
       // TODO: restrict result file label to "alignment"
       FileFormat format;
@@ -222,8 +232,56 @@ class SlivkaAlignmentWSClient extends SlivkaWSClient
       return new FormatAdapter().readFile(f.getContentUrl().toString(),
           DataSourceType.URL, format);
     }
-    Cache.log.warn("No alignment found on the server");
+    Console.warn("No alignment found on the server");
     throw new IOException("no alignment found");
   }
 
-}
\ No newline at end of file
+}
+
+class SlivkaAnnotationWSClient extends SlivkaWSClient
+    implements AnnotationWebServiceClientI
+{
+  SlivkaAnnotationWSClient(SlivkaClient client, SlivkaService service)
+  {
+    super(client, service);
+  }
+
+  @Override
+  public List<AlignmentAnnotation> attachAnnotations(WebServiceJobHandle job,
+      List<SequenceI> sequences, Map<String, FeatureColourI> colours,
+      Map<String, FeatureMatcherSetI> filters) throws IOException
+  {
+    var aln = new Alignment(sequences.toArray(new SequenceI[sequences.size()]));
+    boolean featPresent = false, annotPresent = false;
+    for (var f : client.fetchFilesList(job.getJobId()))
+    {
+      // TODO: restrict file label to "annotations" or "features"
+      var match = mediaTypePattern.matcher(f.getMediaType());
+      if (!match.find())
+        continue;
+      String fmt = match.group(1);
+      if (fmt.equalsIgnoreCase("jalview-annotations"))
+      {
+        annotPresent = new AnnotationFile().readAnnotationFileWithCalcId(
+            aln, service.getId(), f.getContentUrl().toString(),
+            DataSourceType.URL);
+        if (annotPresent)
+          Console.debug(format("loaded annotations for %s", service.getId()));
+      }
+      else if (fmt.equalsIgnoreCase("jalview-features"))
+      {
+        FeaturesFile ff = new FeaturesFile(f.getContentUrl().toString(),
+            DataSourceType.URL);
+        featPresent = ff.parse(aln, colours, true);
+        if (featPresent)
+          Console.debug(format("loaded features for %s", service.getId()));
+      }
+    }
+    if (!annotPresent)
+      Console.debug(format("no annotations found for %s", service.getId()));
+    if (!featPresent)
+      Console.debug(format("no features found for %s", service.getId()));
+    return aln.getAlignmentAnnotation() != null ? Arrays.asList(aln.getAlignmentAnnotation())
+        : Collections.emptyList();
+  }
+}