From 4cfc4dee569d96ac8ce3c1c394318a460a1d0a87 Mon Sep 17 00:00:00 2001 From: Mateusz Warowny Date: Tue, 5 Oct 2021 18:07:34 +0200 Subject: [PATCH] JAL-3878 Annotation operation skeleton. --- .../ws2/operations/AnnotationOperation.java | 261 ++++++++++++++++++++ src/jalview/ws2/slivka/SlivkaWebService.java | 30 +++ 2 files changed, 291 insertions(+) create mode 100644 src/jalview/ws2/operations/AnnotationOperation.java diff --git a/src/jalview/ws2/operations/AnnotationOperation.java b/src/jalview/ws2/operations/AnnotationOperation.java new file mode 100644 index 0000000..eeb51ef --- /dev/null +++ b/src/jalview/ws2/operations/AnnotationOperation.java @@ -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 annotationSupplier; + + final ResultSupplier featuresSupplier; + + public AnnotationOperation(WebServiceI service, + ResultSupplier annotSupplier, + ResultSupplier 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> openEditParamsDialog( + WebServiceI service, WsParamSetI preset, List 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 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 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 + + } + + } +} diff --git a/src/jalview/ws2/slivka/SlivkaWebService.java b/src/jalview/ws2/slivka/SlivkaWebService.java index bd4cb61..aee6b73 100644 --- a/src/jalview/ws2/slivka/SlivkaWebService.java +++ b/src/jalview/ws2/slivka/SlivkaWebService.java @@ -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 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 files = slivkaJob.getResults(); + for (RemoteFile f : files) + { + if (f.getMediaType().equals("application/jalview-annotations")) + { + // return new AnnorationFile(...); + } + } + return null; + } + @Override public String toString() { -- 1.7.10.2