JAL-3878 Annotation operation skeleton.
authorMateusz Warowny <mmzwarowny@dundee.ac.uk>
Tue, 5 Oct 2021 16:07:34 +0000 (18:07 +0200)
committerMateusz Warowny <mmzwarowny@dundee.ac.uk>
Tue, 5 Oct 2021 16:07:34 +0000 (18:07 +0200)
src/jalview/ws2/operations/AnnotationOperation.java [new file with mode: 0644]
src/jalview/ws2/slivka/SlivkaWebService.java

diff --git a/src/jalview/ws2/operations/AnnotationOperation.java b/src/jalview/ws2/operations/AnnotationOperation.java
new file mode 100644 (file)
index 0000000..eeb51ef
--- /dev/null
@@ -0,0 +1,261 @@
+package jalview.ws2.operations;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.concurrent.CancellationException;
+import java.util.concurrent.CompletionStage;
+
+import javax.swing.JMenu;
+import javax.swing.JMenuItem;
+
+import jalview.bin.Cache;
+import jalview.gui.AlignFrame;
+import jalview.gui.WsJobParameters;
+import jalview.io.AnnotationFile;
+import jalview.io.FeaturesFile;
+import jalview.util.MathUtils;
+import jalview.util.MessageManager;
+import jalview.ws.params.ArgumentI;
+import jalview.ws.params.WsParamSetI;
+import jalview.ws2.MenuEntryProviderI;
+import jalview.ws2.ResultSupplier;
+import jalview.ws2.WSJob;
+import jalview.ws2.WSJobStatus;
+import jalview.ws2.WebServiceExecutor;
+import jalview.ws2.WebServiceI;
+import jalview.ws2.WebServiceWorkerI;
+import jalview.ws2.utils.WSJobList;
+
+import static java.lang.String.format;
+
+/**
+ * 
+ * @author mmwarowny
+ *
+ */
+public class AnnotationOperation implements Operation
+{
+  final WebServiceI service;
+
+  final String typeName;
+
+  final ResultSupplier<AnnotationFile> annotationSupplier;
+
+  final ResultSupplier<FeaturesFile> featuresSupplier;
+
+  public AnnotationOperation(WebServiceI service,
+      ResultSupplier<AnnotationFile> annotSupplier,
+      ResultSupplier<FeaturesFile> featSupplier, String operationName)
+  {
+    this.service = service;
+    this.annotationSupplier = annotSupplier;
+    this.featuresSupplier = featSupplier;
+    this.typeName = operationName;
+  }
+
+  @Override
+  public String getName()
+  {
+    return service.getName();
+  }
+
+  @Override
+  public String getTypeName()
+  {
+    return typeName;
+  }
+
+  @Override
+  public String getHostName()
+  {
+    return service.getHostName();
+  }
+
+  @Override
+  public int getMinSequences()
+  {
+    return 0;
+  }
+
+  @Override
+  public int getMaxSequences()
+  {
+    return Integer.MAX_VALUE;
+  }
+
+  @Override
+  public boolean canSubmitGaps()
+  {
+    return false;
+  }
+
+  @Override
+  public boolean isProteinOperation()
+  {
+    return true;
+  }
+
+  @Override
+  public boolean isNucleotideOperation()
+  {
+    return true;
+  }
+
+  @Override
+  public boolean isInteractive()
+  {
+    return false;
+  }
+
+  @Override
+  public MenuEntryProviderI getMenuBuilder()
+  {
+    return this::buildMenu;
+  }
+
+  protected void buildMenu(JMenu parent, AlignFrame frame)
+  {
+    final var calcName = service.getName();
+    WebServiceExecutor wsExecutor = frame.getViewport().getWSExecutor();
+    {
+      var item = new JMenuItem(MessageManager.formatMessage(
+          "label.calcname_with_default_settings", calcName));
+      item.addActionListener((event) -> {
+        WebServiceWorkerI worker = new AnnotationWorker();
+        wsExecutor.submit(worker);
+      });
+      parent.add(item);
+    }
+    if (service.hasParameters())
+    {
+      var item = new JMenuItem(
+          MessageManager.getString("label.edit_settings_and_run"));
+      item.setToolTipText(MessageManager.getString(
+          "label.view_and_change_parameters_before_running_calculation"));
+      item.addActionListener((event) -> {
+        openEditParamsDialog(service, null, null)
+            .thenAcceptAsync((arguments) -> {
+              if (arguments != null)
+              {
+                
+              }
+            });
+      });
+    }
+  }
+
+  private CompletionStage<List<ArgumentI>> openEditParamsDialog(
+      WebServiceI service, WsParamSetI preset, List<ArgumentI> arguments)
+  {
+    WsJobParameters jobParams;
+    if (preset == null && arguments != null && arguments.size() > 0)
+      jobParams = new WsJobParameters(service.getParamStore(), preset,
+          arguments);
+    else
+      jobParams = new WsJobParameters(service.getParamStore(), preset,
+          null);
+    if (preset != null)
+    {
+      jobParams.setName(MessageManager.getString(
+          "label.adjusting_parameters_for_calculation"));
+    }
+    var stage = jobParams.showRunDialog();
+    return stage.thenApply((startJob) -> {
+      if (startJob)
+      {
+        if (jobParams.getPreset() == null)
+          return jobParams.getJobParams();
+        else
+          return jobParams.getPreset().getArguments();
+      }
+      else
+      {
+        return null;
+      }
+    });
+  }
+
+  private class AnnotationWorker implements WebServiceWorkerI
+  {
+    private long uid = MathUtils.getUID();
+
+    private WSJobList jobs = new WSJobList();
+
+    private HashMap<Long, Integer> exceptionCount = new HashMap<>();
+
+    private static final int MAX_RETRY = 5;
+
+    @Override
+    public long getUID()
+    {
+      return uid;
+    }
+
+    @Override
+    public WebServiceI getWebService()
+    {
+      return service;
+    }
+
+    @Override
+    public List<WSJob> getJobs()
+    {
+      return Collections.unmodifiableList(jobs);
+    }
+
+    @Override
+    public void startJobs() throws IOException
+    {
+      
+    }
+
+    @Override
+    public boolean pollJobs() throws IOException
+    {
+      boolean done = true;
+      for (WSJob job : getJobs())
+      {
+        if (!job.getStatus().isDone() && !job.getStatus().isFailed())
+        {
+          Cache.log.debug(format("Polling job %s", job));
+          try
+          {
+            service.updateProgress(job);
+            exceptionCount.remove(job.getUid());
+          } catch (IOException e)
+          {
+            Cache.log.error(format("Polling job %s failed.", job), e);
+            int count = exceptionCount.getOrDefault(job.getUid(),
+                MAX_RETRY);
+            if (--count <= 0)
+            {
+              job.setStatus(WSJobStatus.SERVER_ERROR);
+              Cache.log.warn(format(
+                  "Attempts limit exceeded. Droping job %s.", job));
+            }
+            exceptionCount.put(job.getUid(), count);
+          } catch (OutOfMemoryError e)
+          {
+            job.setStatus(WSJobStatus.BROKEN);
+            Cache.log.error(
+                format("Out of memory when retrieving job %s", job), e);
+          }
+          Cache.log.debug(
+              format("Job %s status is %s", job, job.getStatus()));
+        }
+        done &= job.getStatus().isDone() || job.getStatus().isFailed();
+      }
+      return done;
+    }
+
+    @Override
+    public void done()
+    {
+      // TODO Auto-generated method stub
+
+    }
+
+  }
+}
index bd4cb61..aee6b73 100644 (file)
@@ -15,7 +15,9 @@ import java.util.Set;
 import jalview.bin.Cache;
 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;
@@ -253,6 +255,34 @@ public class SlivkaWebService implements WebServiceI
     return null;
   }
 
+  public FeaturesFile getFeaturesFile(WSJob job) 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);
+      }
+    }
+    return null;
+  }
+
+  public AnnotationFile getAnnotationFile(WSJob job) throws IOException
+  {
+    var slivkaJob = client.getJob(job.getJobId());
+    Collection<RemoteFile> files = slivkaJob.getResults();
+    for (RemoteFile f : files)
+    {
+      if (f.getMediaType().equals("application/jalview-annotations"))
+      {
+        // return new AnnorationFile(...);
+      }
+    }
+    return null;
+  }
+
   @Override
   public String toString()
   {