JAL-3878 Set job status to cancelled on job cancellation.
[jalview.git] / src / jalview / ws2 / slivka / SlivkaWebService.java
index a3aa226..5da7be3 100644 (file)
@@ -1,6 +1,7 @@
 package jalview.ws2.slivka;
 
 import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.util.ArrayList;
@@ -11,10 +12,15 @@ import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
 
+import jalview.api.AlignViewportI;
 import jalview.bin.Cache;
+import jalview.datamodel.Alignment;
+import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.SequenceI;
+import jalview.io.AnnotationFile;
 import jalview.io.DataSourceType;
+import jalview.io.FeaturesFile;
 import jalview.io.FileFormat;
 import jalview.io.FileFormatI;
 import jalview.io.FormatAdapter;
@@ -38,85 +44,107 @@ import uk.ac.dundee.compbio.slivkaclient.SlivkaService;
 public class SlivkaWebService implements WebServiceI
 {
   protected final SlivkaClient client;
+
   protected final SlivkaService service;
+
   protected SlivkaDatastore store = null;
-  protected final String operation;
+
   protected final ArrayList<Operation> operations = new ArrayList<>();
+
   protected int typeFlags = 0;
 
-  protected static final EnumMap<Job.Status, WsJob.JobState> stateMap = new EnumMap<>(Job.Status.class);
-  {
-    stateMap.put(Job.Status.PENDING, WsJob.JobState.QUEUED);
-    stateMap.put(Job.Status.REJECTED, WsJob.JobState.INVALID);
-    stateMap.put(Job.Status.ACCEPTED, WsJob.JobState.QUEUED);
-    stateMap.put(Job.Status.QUEUED, WsJob.JobState.QUEUED);
-    stateMap.put(Job.Status.RUNNING, WsJob.JobState.RUNNING);
-    stateMap.put(Job.Status.COMPLETED, WsJob.JobState.FINISHED);
-    stateMap.put(Job.Status.INTERRUPTED, WsJob.JobState.CANCELLED);
-    stateMap.put(Job.Status.DELETED, WsJob.JobState.CANCELLED);
-    stateMap.put(Job.Status.FAILED, WsJob.JobState.FAILED);
-    stateMap.put(Job.Status.ERROR, WsJob.JobState.SERVERERROR);
-    stateMap.put(Job.Status.UNKNOWN, WsJob.JobState.UNKNOWN);
-  }
-  protected final Set<WsJob.JobState> failedStates = new HashSet<>(Arrays.asList(
-      WsJob.JobState.INVALID, WsJob.JobState.BROKEN, WsJob.JobState.FAILED,
-      WsJob.JobState.SERVERERROR, WsJob.JobState.CANCELLED
-  ));
-
-  public SlivkaWebService(SlivkaClient client, SlivkaService service, String operation) {
+  protected static final EnumMap<Job.Status, WSJobStatus> statusMap = new EnumMap<>(
+          Job.Status.class);
+  {
+    statusMap.put(Job.Status.PENDING, WSJobStatus.SUBMITTED);
+    statusMap.put(Job.Status.REJECTED, WSJobStatus.INVALID);
+    statusMap.put(Job.Status.ACCEPTED, WSJobStatus.QUEUED);
+    statusMap.put(Job.Status.QUEUED, WSJobStatus.QUEUED);
+    statusMap.put(Job.Status.RUNNING, WSJobStatus.RUNNING);
+    statusMap.put(Job.Status.COMPLETED, WSJobStatus.FINISHED);
+    statusMap.put(Job.Status.INTERRUPTED, WSJobStatus.CANCELLED);
+    statusMap.put(Job.Status.DELETED, WSJobStatus.CANCELLED);
+    statusMap.put(Job.Status.FAILED, WSJobStatus.FAILED);
+    statusMap.put(Job.Status.ERROR, WSJobStatus.SERVER_ERROR);
+    statusMap.put(Job.Status.UNKNOWN, WSJobStatus.UNKNOWN);
+  }
+
+  public SlivkaWebService(SlivkaClient client, SlivkaService service)
+  {
     this.client = client;
     this.service = service;
-    this.operation = operation;
   }
 
   @Override
-  public String getHostName() { return client.getUrl().toString(); }
+  public String getHostName()
+  {
+    return client.getUrl().toString();
+  }
 
   @Override
-  public String getName() { return service.getName(); }
+  public String getProviderName()
+  {
+    return "slivka";
+  }
 
   @Override
-  public String getDescription() { return service.getDescription(); }
+  public String getName()
+  {
+    return service.getName();
+  }
 
   @Override
-  public String getOperationType() { return operation; }
+  public String getDescription()
+  {
+    return service.getDescription();
+  }
 
   @Override
-  public List<Operation> getOperations() {
+  public List<Operation> getOperations()
+  {
     return operations;
   }
 
-  void addOperation(Operation operation) {
+  void addOperation(Operation operation)
+  {
     operations.add(operation);
   }
 
-  void removeOperation(Operation operation) {
+  void removeOperation(Operation operation)
+  {
     operations.remove(operation);
   }
 
   @Override
-  public boolean hasParameters() {
+  public boolean hasParameters()
+  {
     return getParamStore().getServiceParameters().size() > 0;
   }
 
   @Override
-  public ParamDatastoreI getParamStore() {
-    if (store == null) {
+  public ParamDatastoreI getParamStore()
+  {
+    if (store == null)
+    {
       store = new SlivkaDatastore(service);
     }
     return store;
   }
 
   @Override
-  public WSJob submit(List<SequenceI> sequences, List<ArgumentI> args) throws IOException
+  public String submit(List<SequenceI> sequences, List<ArgumentI> args)
+          throws IOException
   {
     var request = new uk.ac.dundee.compbio.slivkaclient.JobRequest();
-    for (Parameter param : service.getParameters()) {
-      if (param instanceof Parameter.FileParameter) {
+    for (Parameter param : service.getParameters())
+    {
+      if (param instanceof Parameter.FileParameter)
+      {
         // if finds a file input, gives it sequences stream
         Parameter.FileParameter fileParam = (Parameter.FileParameter) param;
         FileFormat format;
-        switch (fileParam.getMediaType()) {
+        switch (fileParam.getMediaType())
+        {
         case "application/pfam":
           format = FileFormat.Pfam;
           break;
@@ -131,20 +159,22 @@ public class SlivkaWebService implements WebServiceI
           format = FileFormat.Fasta;
           break;
         }
-        InputStream stream = new ByteArrayInputStream(
-                format.getWriter(null)
+        InputStream stream = new ByteArrayInputStream(format.getWriter(null)
                 .print(sequences.toArray(new SequenceI[0]), false)
                 .getBytes());
         request.addFile(param.getId(), stream);
       }
     }
-    if (args != null) {
-      for (ArgumentI arg : args) {
+    if (args != null)
+    {
+      for (ArgumentI arg : args)
+      {
         // multiple choice field names are name$number to avoid duplications
         // the number is stripped here
         String paramId = arg.getName().split("\\$", 2)[0];
         Parameter param = service.getParameter(paramId);
-        if (param instanceof Parameter.FlagParameter) {
+        if (param instanceof Parameter.FlagParameter)
+        {
           if (arg.getValue() != null && !arg.getValue().isBlank())
             request.addData(paramId, true);
           else
@@ -157,27 +187,44 @@ public class SlivkaWebService implements WebServiceI
       }
     }
     var job = service.submitJob(request);
-    return new WSJob("slivka", getName(), job.getId(), getHostName());
+    return job.getId();
   }
 
   @Override
-  public void updateProgress(WSJob job)
-          throws IOException
+  public void updateProgress(WSJob job) throws IOException
   {
-    // TODO Auto-generated method stub
-
+    var slivkaJob = client.getJob(job.getJobId());
+    job.setStatus(statusMap.get(slivkaJob.getStatus()));
+    Collection<RemoteFile> files = slivkaJob.getResults();
+    for (RemoteFile f : files)
+    {
+      if (f.getLabel().equals("log"))
+      {
+        ByteArrayOutputStream stream = new ByteArrayOutputStream();
+        f.writeTo(stream);
+        job.setLog(stream.toString("UTF-8"));
+      }
+      else if (f.getLabel().equals("error-log"))
+      {
+        ByteArrayOutputStream stream = new ByteArrayOutputStream();
+        f.writeTo(stream);
+        job.setErrorLog(stream.toString("UTF-8"));
+      }
+    }
   }
 
   @Override
   public void cancel(WSJob job) throws IOException
   {
+    job.setStatus(WSJobStatus.CANCELLED);
     Cache.log.warn("Slivka does not support job cancellation yet.");
   }
 
   @Override
   public boolean handleSubmissionError(WSJob job, Exception ex)
   {
-    if (ex instanceof ClientProtocolException) {
+    if (ex instanceof ClientProtocolException)
+    {
       Cache.log.error("Job submission failed due to exception.", ex);
       return true;
     }
@@ -191,25 +238,73 @@ public class SlivkaWebService implements WebServiceI
     return false;
   }
 
-  public AlignmentI getAlignment(WSJob job) throws IOException {
+  public AlignmentI getAlignment(WSJob job, List<SequenceI> dataset,
+      AlignViewportI viewport) throws IOException
+  {
     Collection<RemoteFile> files;
-    var slivkaJob = client.getJob(job.getJobID());
+    var slivkaJob = client.getJob(job.getJobId());
     files = slivkaJob.getResults();
-    for (RemoteFile f : files) {
-      if (f.getMediaType().equals("application/clustal")) {
-        return new FormatAdapter().readFile(
-                f.getContentUrl().toString(), DataSourceType.URL, FileFormat.Clustal);
+    for (RemoteFile f : files)
+    {
+      if (f.getMediaType().equals("application/clustal"))
+      {
+        return new FormatAdapter().readFile(f.getContentUrl().toString(),
+                DataSourceType.URL, FileFormat.Clustal);
+      }
+      else if (f.getMediaType().equals("application/fasta"))
+      {
+        return new FormatAdapter().readFile(f.getContentUrl().toString(),
+                DataSourceType.URL, FileFormat.Fasta);
+      }
+    }
+    return null;
+  }
+
+  public FeaturesFile getFeaturesFile(WSJob job,
+      List<SequenceI> dataset, AlignViewportI viewport) throws IOException
+  {
+    var slivkaJob = client.getJob(job.getJobId());
+    Collection<RemoteFile> files = slivkaJob.getResults();
+    for (RemoteFile f : files)
+    {
+      if (f.getMediaType().equals("application/jalview-features"))
+      {
+        return new FeaturesFile(f.getContentUrl().toString(), DataSourceType.URL);
       }
-      else if (f.getMediaType().equals("application/fasta")) {
-        return new FormatAdapter().readFile(
-                f.getContentUrl().toString(), DataSourceType.URL, FileFormat.Fasta);
+    }
+    return null;
+  }
+
+  public List<AlignmentAnnotation> getAnnotationFile(WSJob job,
+      List<SequenceI> dataset, AlignViewportI viewport) throws IOException
+  {
+    var slivkaJob = client.getJob(job.getJobId());
+    Collection<RemoteFile> files = slivkaJob.getResults();
+    for (RemoteFile f : files)
+    {
+      if (f.getMediaType().equals("application/jalview-annotations"))
+      {
+        Alignment aln = new Alignment(dataset.toArray(new SequenceI[0]));
+        AnnotationFile af = new AnnotationFile();
+        boolean valid = af.readAnnotationFileWithCalcId(aln, service.getId(),
+            f.getContentUrl().toString(), DataSourceType.URL);
+        if (valid)
+        {
+          return Arrays.asList(aln.getAlignmentAnnotation());
+        }
+        else
+        {
+          throw new IOException("Unable to read annotations from file " +
+              f.getContentUrl().toString());
+        }
       }
     }
     return null;
   }
 
   @Override
-  public String toString() {
+  public String toString()
+  {
     return String.format("SlivkaWebService[%s]", getName());
   }
 }