From 12dc7e70977962f00e584b39eda098897d51f432 Mon Sep 17 00:00:00 2001 From: Mateusz Warowny Date: Mon, 8 Nov 2021 16:01:52 +0100 Subject: [PATCH] JAL-3878 Separate gui elements from operations. Separation went well for alignment operation but not so much for the annotations. GUI progress bar needs to be moved outside the operation and be controlled by the worker listener. Addition of the results to the frame needs to be moved out from the #done method, but it's strongly wired to the align frame code and cannot be nicely packed into AnnotationResult object. --- src/jalview/gui/AlignFrame.java | 7 +- src/jalview/ws2/WebServiceDiscoverer.java | 12 +- src/jalview/ws2/WebServiceI.java | 10 +- src/jalview/ws2/WebServiceInfoUpdater.java | 34 +- src/jalview/ws2/WebServiceWorkerI.java | 8 +- src/jalview/ws2/WebServiceWorkerListener.java | 16 + src/jalview/ws2/WebServiceWorkerListenersList.java | 73 ++++ src/jalview/ws2/gui/AlignmentMenuBuilder.java | 377 ++++++++++++++++++ src/jalview/ws2/gui/AnnotationMenuBuilder.java | 190 +++++++++ src/jalview/ws2/operations/AlignmentOperation.java | 405 +++++--------------- .../ws2/operations/AnnotationOperation.java | 132 +------ .../ws2/operations/AnnotationServiceWorker.java | 7 +- src/jalview/ws2/operations/Operation.java | 8 + src/jalview/ws2/slivka/SlivkaWSDiscoverer.java | 33 +- src/jalview/ws2/slivka/SlivkaWebService.java | 24 +- 15 files changed, 855 insertions(+), 481 deletions(-) create mode 100644 src/jalview/ws2/WebServiceWorkerListener.java create mode 100644 src/jalview/ws2/WebServiceWorkerListenersList.java create mode 100644 src/jalview/ws2/gui/AlignmentMenuBuilder.java create mode 100644 src/jalview/ws2/gui/AnnotationMenuBuilder.java diff --git a/src/jalview/gui/AlignFrame.java b/src/jalview/gui/AlignFrame.java index 3d00450..3336663 100644 --- a/src/jalview/gui/AlignFrame.java +++ b/src/jalview/gui/AlignFrame.java @@ -918,8 +918,8 @@ public class AlignFrame extends GAlignFrame } @Override - public void servicesChanged(WebServiceDiscoverer discoverer, - Collection services) + public void operationsChanged(WebServiceDiscoverer discoverer, + List list) { buildWebServicesMenu(); } @@ -4731,8 +4731,7 @@ public class AlignFrame extends GAlignFrame if (discoverer.hasServices()) { var builder = new WebServicesMenuBuilder(); - for (var service : discoverer.getServices()) - builder.addAllOperations(service.getOperations()); + builder.addAllOperations(discoverer.getOperations()); builder.addSelectedHostChangeListener((name, op) -> { menu.removeAll(); builder.buildMenu(menu, this); diff --git a/src/jalview/ws2/WebServiceDiscoverer.java b/src/jalview/ws2/WebServiceDiscoverer.java index 635bec9..513610c 100644 --- a/src/jalview/ws2/WebServiceDiscoverer.java +++ b/src/jalview/ws2/WebServiceDiscoverer.java @@ -7,6 +7,8 @@ import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CopyOnWriteArrayList; +import jalview.ws2.operations.Operation; + public interface WebServiceDiscoverer { public static final int STATUS_OK = 1; @@ -25,7 +27,7 @@ public interface WebServiceDiscoverer public int getStatusForUrl(String url); - public List getServices(); + public List getOperations(); public boolean hasServices(); @@ -40,8 +42,8 @@ public interface WebServiceDiscoverer @FunctionalInterface static interface ServiceChangeListener { - public void servicesChanged(WebServiceDiscoverer discoverer, - Collection services); + public void operationsChanged(WebServiceDiscoverer discoverer, + List list); } List serviceListeners = new CopyOnWriteArrayList<>(); @@ -58,11 +60,11 @@ public interface WebServiceDiscoverer serviceListeners.remove(listener); } - default void fireServicesChanged(List services) + default void fireOperationsChanged(List list) { for (var listener : serviceListeners) { - listener.servicesChanged(this, services); + listener.operationsChanged(this, list); } } } diff --git a/src/jalview/ws2/WebServiceI.java b/src/jalview/ws2/WebServiceI.java index 6781668..a09233f 100755 --- a/src/jalview/ws2/WebServiceI.java +++ b/src/jalview/ws2/WebServiceI.java @@ -24,13 +24,11 @@ public interface WebServiceI public String getProviderName(); - public String getName(); + String getName(); - public String getDescription(); + String getDescription(); - public List getOperations(); - - public boolean hasParameters(); + boolean hasParameters(); public ParamDatastoreI getParamStore(); @@ -39,8 +37,6 @@ public interface WebServiceI public void updateProgress(WSJob job) throws IOException; - // public ResultSupplier getResultSupplier(Class type); - public void cancel(WSJob job) throws IOException; /** diff --git a/src/jalview/ws2/WebServiceInfoUpdater.java b/src/jalview/ws2/WebServiceInfoUpdater.java index 8152abf..c9557c6 100644 --- a/src/jalview/ws2/WebServiceInfoUpdater.java +++ b/src/jalview/ws2/WebServiceInfoUpdater.java @@ -8,12 +8,14 @@ import jalview.gui.WebserviceInfo; public class WebServiceInfoUpdater implements PropertyChangeListener { + private final WebServiceWorkerI worker; private final WebserviceInfo wsInfo; private String outputHeader = ""; - public WebServiceInfoUpdater(WebserviceInfo wsInfo) + public WebServiceInfoUpdater(WebServiceWorkerI worker, WebserviceInfo wsInfo) { + this.worker = worker; this.wsInfo = wsInfo; } @@ -76,6 +78,7 @@ public class WebServiceInfoUpdater implements PropertyChangeListener break; } wsInfo.setStatus(job.getJobNum(), wsInfoStatus); + updateWSInfoGlobalStatus(); } private void logChanged(PropertyChangeEvent evt) @@ -96,4 +99,33 @@ public class WebServiceInfoUpdater implements PropertyChangeListener newLog.substring(oldLog.length())); } + + private void updateWSInfoGlobalStatus() + { + var jobs = worker.getJobs(); + if (jobs.countRunning() > 0) + { + wsInfo.setStatus(WebserviceInfo.STATE_RUNNING); + } + else if (jobs.countQueuing() > 0 + || jobs.countSubmitted() < jobs.size()) + { + wsInfo.setStatus(WebserviceInfo.STATE_QUEUING); + } + else + { + if (jobs.countSuccessful() > 0) + { + wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_OK); + } + else if (jobs.countCancelled() > 0) + { + wsInfo.setStatus(WebserviceInfo.STATE_CANCELLED_OK); + } + else if (jobs.countFailed() > 0) + { + wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_ERROR); + } + } + } } diff --git a/src/jalview/ws2/WebServiceWorkerI.java b/src/jalview/ws2/WebServiceWorkerI.java index 22b4c73..38c82a2 100644 --- a/src/jalview/ws2/WebServiceWorkerI.java +++ b/src/jalview/ws2/WebServiceWorkerI.java @@ -3,11 +3,13 @@ package jalview.ws2; import java.io.IOException; import java.util.List; +import jalview.ws2.utils.WSJobList; + public interface WebServiceWorkerI extends PollableTaskI -{ +{ long getUID(); - List getJobs(); + WSJobList getJobs(); void start() throws IOException; @@ -32,4 +34,6 @@ public interface WebServiceWorkerI extends PollableTaskI * either normally or exceptionally. */ void done(); + + public void addListener(WebServiceWorkerListener listener); } diff --git a/src/jalview/ws2/WebServiceWorkerListener.java b/src/jalview/ws2/WebServiceWorkerListener.java new file mode 100644 index 0000000..16ee7bd --- /dev/null +++ b/src/jalview/ws2/WebServiceWorkerListener.java @@ -0,0 +1,16 @@ +package jalview.ws2; + +public interface WebServiceWorkerListener +{ + void workerStarted(WebServiceWorkerI source); + + void workerNotStarted(WebServiceWorkerI source); + + void jobCreated(WebServiceWorkerI source, WSJob job); + + void pollException(WebServiceWorkerI source, WSJob job, Exception e); + + void workerCompleting(WebServiceWorkerI source); + + void workerCompleted(WebServiceWorkerI source); +} diff --git a/src/jalview/ws2/WebServiceWorkerListenersList.java b/src/jalview/ws2/WebServiceWorkerListenersList.java new file mode 100644 index 0000000..a09c958 --- /dev/null +++ b/src/jalview/ws2/WebServiceWorkerListenersList.java @@ -0,0 +1,73 @@ +package jalview.ws2; + +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.function.Consumer; + +public class WebServiceWorkerListenersList +{ + private WebServiceWorkerI owner; + private List listeners = new CopyOnWriteArrayList<>(); + + public WebServiceWorkerListenersList(WebServiceWorkerI worker) + { + this.owner = worker; + } + + public void addListener(WebServiceWorkerListener listener) + { + listeners.add(listener); + } + + public void removeListener(WebServiceWorkerListener listener) + { + listeners.remove(listener); + } + + public void fireWorkerStarted() + { + for (var listener : listeners) + listener.workerStarted(owner); + } + + public void fireWorkerNotStarted() + { + for (var listener : listeners) + listener.workerNotStarted(owner); + } + + public void fireJobCreated(WSJob job) + { + for (var listener : listeners) + listener.jobCreated(owner, job); + } + + public void firePollException(WSJob job, Exception e) + { + for (var listener : listeners) + listener.pollException(owner, job, e); + } + + public void fireWorkerCompleting() + { + for (var listener : listeners) + listener.workerCompleting(owner); + } + + public void fireWorkerCompleted() + { + for (var listener : listeners) + listener.workerCompleted(owner); + } + + public List getListeners() + { + return listeners; + } + + public void forEach(Consumer consumer) + { + for (var listener : listeners) + consumer.accept(listener); + } +} diff --git a/src/jalview/ws2/gui/AlignmentMenuBuilder.java b/src/jalview/ws2/gui/AlignmentMenuBuilder.java new file mode 100644 index 0000000..f3dfb68 --- /dev/null +++ b/src/jalview/ws2/gui/AlignmentMenuBuilder.java @@ -0,0 +1,377 @@ +package jalview.ws2.gui; + +import static java.lang.String.format; + +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Objects; +import java.util.concurrent.CompletionStage; +import java.util.function.Consumer; + +import javax.swing.JMenu; +import javax.swing.JMenuItem; +import javax.swing.ToolTipManager; + +import jalview.datamodel.Alignment; +import jalview.datamodel.AlignmentI; +import jalview.datamodel.AlignmentOrder; +import jalview.datamodel.AlignmentView; +import jalview.datamodel.HiddenColumns; +import jalview.gui.AlignFrame; +import jalview.gui.AlignViewport; +import jalview.gui.Desktop; +import jalview.gui.JvOptionPane; +import jalview.gui.JvSwingUtils; +import jalview.gui.WebserviceInfo; +import jalview.gui.WsJobParameters; +import jalview.util.MathUtils; +import jalview.util.MessageManager; +import jalview.ws.params.ArgumentI; +import jalview.ws.params.ParamDatastoreI; +import jalview.ws.params.WsParamSetI; +import jalview.ws2.MenuEntryProviderI; +import jalview.ws2.PollingTaskExecutor; +import jalview.ws2.WSJob; +import jalview.ws2.WebServiceInfoUpdater; +import jalview.ws2.WebServiceWorkerI; +import jalview.ws2.WebServiceWorkerListener; +import jalview.ws2.operations.AlignmentOperation; +import jalview.ws2.operations.AlignmentOperation.AlignmentResult; +import jalview.ws2.operations.AlignmentOperation.AlignmentWorker; + + +public class AlignmentMenuBuilder implements MenuEntryProviderI +{ + AlignmentOperation operation; + + public AlignmentMenuBuilder(AlignmentOperation operation) + { + this.operation = operation; + } + + public void buildMenu(JMenu parent, AlignFrame frame) + { + if (operation.canSubmitGaps()) + { + var alignSubmenu = new JMenu(operation.getName()); + buildMenu(alignSubmenu, frame, false); + parent.add(alignSubmenu); + var realignSubmenu = new JMenu(MessageManager.formatMessage( + "label.realign_with_params", operation.getName())); + realignSubmenu.setToolTipText(MessageManager + .getString("label.align_sequences_to_existing_alignment")); + buildMenu(realignSubmenu, frame, true); + parent.add(realignSubmenu); + } + else + { + buildMenu(parent, frame, false); + } + } + + protected void buildMenu(JMenu parent, AlignFrame frame, + boolean submitGaps) + { + final String action = submitGaps ? "Align" : "Realign"; + final var calcName = operation.getName(); + + { + var item = new JMenuItem(MessageManager.formatMessage( + "label.calcname_with_default_settings", calcName)); + item.setToolTipText(MessageManager + .formatMessage("label.action_with_default_settings", action)); + item.addActionListener((event) -> { + final AlignmentView msa = frame.gatherSequencesForAlignment(); + if (msa != null) + { + startWorker(frame, msa, Collections.emptyList(), submitGaps); + } + }); + parent.add(item); + } + + if (operation.hasParameters()) + { + var item = new JMenuItem( + MessageManager.getString("label.edit_settings_and_run")); + item.setToolTipText(MessageManager.getString( + "label.view_and_change_parameters_before_alignment")); + item.addActionListener((event) -> { + AlignmentView msa = frame.gatherSequencesForAlignment(); + if (msa != null) + { + openEditParamsDialog(operation.getParamStore(), null, null) + .thenAcceptAsync((arguments) -> { + if (arguments != null) + { + startWorker(frame, msa, arguments, submitGaps); + } + }); + } + }); + parent.add(item); + } + + var presets = operation.getParamStore().getPresets(); + if (presets != null && presets.size() > 0) + { + final var presetList = new JMenu(MessageManager + .formatMessage("label.run_with_preset_params", calcName)); + final var showToolTipFor = ToolTipManager.sharedInstance() + .getDismissDelay(); + for (final var preset : presets) + { + var item = new JMenuItem(preset.getName()); + final int QUICK_TOOLTIP = 1500; + item.addMouseListener(new MouseAdapter() + { + @Override + public void mouseEntered(MouseEvent e) + { + ToolTipManager.sharedInstance().setDismissDelay(QUICK_TOOLTIP); + } + + @Override + public void mouseExited(MouseEvent e) + { + ToolTipManager.sharedInstance().setDismissDelay(showToolTipFor); + } + }); + String tooltip = JvSwingUtils.wrapTooltip(true, + format("%s
%s", + MessageManager.getString( + preset.isModifiable() ? "label.user_preset" + : "label.service_preset"), + preset.getDescription())); + item.setToolTipText(tooltip); + item.addActionListener((event) -> { + AlignmentView msa = frame.gatherSequencesForAlignment(); + startWorker(frame, msa, preset.getArguments(), submitGaps); + }); + presetList.add(item); + } + parent.add(presetList); + } + } + + private CompletionStage> openEditParamsDialog( + ParamDatastoreI paramStore, WsParamSetI preset, + List arguments) + { + WsJobParameters jobParams; + if (preset == null && arguments != null && arguments.size() > 0) + jobParams = new WsJobParameters(paramStore, preset, arguments); + else + jobParams = new WsJobParameters(paramStore, 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 void startWorker(AlignFrame frame, AlignmentView msa, + List arguments, boolean submitGaps) + { + AlignViewport viewport = frame.getViewport(); + PollingTaskExecutor executor = frame.getViewport().getWSExecutor(); + if (msa != null) + { + + String panelInfo = String.format("%s using service hosted at %s%n%s", + operation.getName(), operation.getHostName(), + Objects.requireNonNullElse(operation.getDescription(), "")); + var wsInfo = new WebserviceInfo(operation.getName(), panelInfo, false); + + final String alnTitle = frame.getTitle(); + AlignmentWorker worker = operation.new AlignmentWorker(msa, + arguments, frame.getTitle(), submitGaps, true, + viewport); + String outputHeader = String.format("%s of %s%nJob details%n", + submitGaps ? "Re-alignment" : "Alignment", alnTitle); + + var awl = new AlignmentWorkerListener(worker, wsInfo, frame, + outputHeader); + worker.setResultConsumer(awl); + worker.addListener(awl); + + executor.submit(worker); + } + + } + + private class AlignmentWorkerListener + implements WebServiceWorkerListener, Consumer + { + + final WebServiceWorkerI worker; + final WebserviceInfo wsInfo; + final AlignFrame frame; + WebServiceInfoUpdater updater; + String outputHeader; + final long progbarId = MathUtils.getUID(); + + private AlignmentWorkerListener(WebServiceWorkerI worker, WebserviceInfo wsInfo, + AlignFrame frame, String header) + { + this.worker = worker; + this.wsInfo = wsInfo; + this.frame = frame; + this.outputHeader = header; + this.updater = new WebServiceInfoUpdater(worker, wsInfo); + updater.setOutputHeader(outputHeader); + } + + @Override + public void workerStarted(WebServiceWorkerI source) + { + // wsInfo.setThisService() should happen here + wsInfo.setVisible(true); + } + + @Override + public void workerNotStarted(WebServiceWorkerI source) + { + wsInfo.setVisible(false); + // TODO show notification dialog. + JvOptionPane.showMessageDialog(frame, + MessageManager.getString("info.invalid_msa_input_mininfo"), + MessageManager.getString("info.invalid_msa_notenough"), + JvOptionPane.INFORMATION_MESSAGE); + } + + @Override + public void jobCreated(WebServiceWorkerI source, WSJob job) + { + int tabIndex = wsInfo.addJobPane(); + wsInfo.setProgressName(String.format("region %d", job.getJobNum()), + tabIndex); + wsInfo.setProgressText(tabIndex, outputHeader); + job.addPropertyChangeListener(updater); + } + + @Override + public void pollException(WebServiceWorkerI source, WSJob job, Exception e) + { + wsInfo.appendProgressText(job.getJobNum(), + MessageManager.formatMessage("info.server_exception", + operation.getName(), e.getMessage())); + } + + @Override + public void workerCompleting(WebServiceWorkerI source) + { + // TODO Auto-generated method stub + wsInfo.setProgressBar( + MessageManager.getString("status.collecting_job_results"), + progbarId); + } + + @Override + public void workerCompleted(WebServiceWorkerI source) + { + wsInfo.removeProgressBar(progbarId); + + } + + @Override + public void accept(AlignmentResult out) + { + if (out != null) + { + wsInfo.showResultsNewFrame.addActionListener(evt -> displayNewFrame( + new Alignment(out.getAln()), out.getAlorders(), out.getHidden())); + wsInfo.setResultsReady(); + } + else + { + wsInfo.setFinishedNoResults(); + } + } + + private void displayNewFrame(AlignmentI aln, + List alorders, HiddenColumns hidden) + { + AlignFrame frame = new AlignFrame(aln, hidden, + AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT); + // TODO store feature renderer settings in worker object + // frame.getFeatureRenderer().transferSettings(featureSettings); + var regions = sortOrders(alorders); + if (alorders.size() == 1) + { + frame.addSortByOrderMenuItem( + format("%s Ordering", operation.getName()), alorders.get(0)); + } + else + { + for (int i = 0; i < alorders.size(); i++) + { + final int j = i; + Iterable iter = () -> regions.get(j).stream() + .map(it -> Integer.toString(it)).iterator(); + var orderName = format("%s Region %s Ordering", operation.getName(), + String.join(",", iter)); + frame.addSortByOrderMenuItem(orderName, alorders.get(i)); + } + } + + /* TODO + * If alignment was requested from one half of a SplitFrame, show in a + * SplitFrame with the other pane similarly aligned. + */ + + Desktop.addInternalFrame(frame, frame.getTitle(), AlignFrame.DEFAULT_WIDTH, + AlignFrame.DEFAULT_HEIGHT); + } + + + private List> sortOrders(List alorders) + { + List> regions = new ArrayList<>(); + for (int i = 0; i < alorders.size(); i++) + { + List regs = new ArrayList<>(); + regs.add(i); + int j = i + 1; + while (j < alorders.size()) + { + if (alorders.get(i).equals(alorders.get(j))) + { + alorders.remove(j); + regs.add(j); + } + else + { + j++; + } + } + regions.add(regs); + } + return regions; + } + + + } +} + diff --git a/src/jalview/ws2/gui/AnnotationMenuBuilder.java b/src/jalview/ws2/gui/AnnotationMenuBuilder.java new file mode 100644 index 0000000..a1b2316 --- /dev/null +++ b/src/jalview/ws2/gui/AnnotationMenuBuilder.java @@ -0,0 +1,190 @@ +package jalview.ws2.gui; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.CompletionStage; + +import javax.swing.JCheckBoxMenuItem; +import javax.swing.JMenu; +import javax.swing.JMenuItem; +import javax.swing.event.MenuEvent; +import javax.swing.event.MenuListener; + +import jalview.api.AlignCalcManagerI2; +import jalview.api.AlignmentViewPanel; +import jalview.gui.AlignFrame; +import jalview.gui.AlignViewport; +import jalview.gui.WsJobParameters; +import jalview.util.MessageManager; +import jalview.ws.params.ArgumentI; +import jalview.ws.params.ParamDatastoreI; +import jalview.ws.params.WsParamSetI; +import jalview.ws2.MenuEntryProviderI; +import jalview.ws2.PollingTaskExecutor; +import jalview.ws2.operations.AnnotationOperation; +import jalview.ws2.operations.AnnotationServiceWorker; + +public class AnnotationMenuBuilder implements MenuEntryProviderI +{ + final AnnotationOperation operation; + + public AnnotationMenuBuilder(AnnotationOperation operation) + { + this.operation = operation; + } + + @Override + public void buildMenu(JMenu parent, AlignFrame frame) + { + if (operation.isInteractive()) + buildInteractiveMenu(parent, frame); + else + buildClassicMenu(parent, frame); + } + + protected void buildClassicMenu(JMenu parent, AlignFrame frame) + { + final var calcName = operation.getName(); + PollingTaskExecutor wsExecutor = frame.getViewport().getWSExecutor(); + final var calcManager = frame.getViewport().getCalcManager(); + { + var item = new JMenuItem(MessageManager.formatMessage( + "label.calcname_with_default_settings", calcName)); + item.addActionListener((event) -> { + var worker = createWorker(Collections.emptyList(), frame, calcManager); + calcManager.startWorker(worker); + }); + parent.add(item); + } + if (operation.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(operation.getParamStore(), null, null) + .thenAcceptAsync((arguments) -> { + if (arguments != null) + { + var worker = createWorker(arguments, frame, calcManager); + calcManager.startWorker(worker); + } + }); + }); + parent.add(item); + } + } + + protected void buildInteractiveMenu(JMenu parent, AlignFrame frame) + { + final var calcName = operation.getName(); + final var calcManager = frame.getViewport().getCalcManager(); + final var arguments = new ArrayList(); + final JCheckBoxMenuItem runItem; + { + // TODO use MessageManager and set tool tip text + runItem = new JCheckBoxMenuItem( + String.format("%s calculations", calcName)); + runItem.addActionListener((event) -> { + calcManager.removeWorkersForName(calcName); + var worker = createWorker(arguments, frame, calcManager); + calcManager.registerWorker(worker); + }); + parent.add(runItem); + } + JMenuItem _editItem = null; + if (operation.hasParameters()) + { + // TODO use MessageManager and set tool tip text + _editItem = new JMenuItem( + String.format("Edit %s settings", calcName)); + _editItem.addActionListener((event) -> { + openEditParamsDialog(operation.getParamStore(), null, null) + .thenAcceptAsync((args) -> { + if (arguments != null) + { + arguments.clear(); + arguments.addAll(args); + calcManager.removeWorkersForName(calcName); + var worker = createWorker(arguments, frame, calcManager); + calcManager.registerWorker(worker); + } + }); + }); + parent.add(_editItem); + } + final var editItem = _editItem; + + parent.addMenuListener(new MenuListener() + { + @Override + public void menuSelected(MenuEvent e) + { + var isNuc = frame.getViewport().getAlignment().isNucleotide(); + var menuEnabled = (isNuc && operation.isNucleotideOperation()) || + (!isNuc && operation.isProteinOperation()); + runItem.setEnabled(menuEnabled); + if (editItem != null) + editItem.setEnabled(menuEnabled); + boolean currentlyRunning = calcManager.getWorkersForName(calcName).size() > 0; + runItem.setSelected(currentlyRunning); + } + + @Override + public void menuDeselected(MenuEvent e) {} + + @Override + public void menuCanceled(MenuEvent e) {} + }); + } + + + private CompletionStage> openEditParamsDialog( + ParamDatastoreI paramStore, WsParamSetI preset, + List arguments) + { + WsJobParameters jobParams; + if (preset == null && arguments != null && arguments.size() > 0) + jobParams = new WsJobParameters(paramStore, preset, arguments); + else + jobParams = new WsJobParameters(paramStore, 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 AnnotationServiceWorker createWorker( + List arguments, AlignFrame frame, AlignCalcManagerI2 calcManager) + { + /* What is the purpose of AlignViewport and AlignmentViewPanel? */ + AlignViewport viewport = frame.getCurrentView(); + AlignmentViewPanel alignPanel = frame.alignPanel; + return new AnnotationServiceWorker(operation, + arguments, viewport, alignPanel, frame, frame, + calcManager); + } + +} diff --git a/src/jalview/ws2/operations/AlignmentOperation.java b/src/jalview/ws2/operations/AlignmentOperation.java index 89aeb79..1f0a602 100644 --- a/src/jalview/ws2/operations/AlignmentOperation.java +++ b/src/jalview/ws2/operations/AlignmentOperation.java @@ -14,11 +14,14 @@ import java.util.List; import java.util.Map; import java.util.Objects; import java.util.concurrent.CompletionStage; +import java.util.function.Consumer; import javax.swing.JMenu; import javax.swing.JMenuItem; import javax.swing.ToolTipManager; +import org.eclipse.jetty.http.HttpGenerator.Result; + import jalview.analysis.AlignSeq; import jalview.analysis.AlignmentSorter; import jalview.analysis.SeqsetUtils; @@ -40,6 +43,7 @@ import jalview.gui.WsJobParameters; import jalview.util.MathUtils; import jalview.util.MessageManager; import jalview.ws.params.ArgumentI; +import jalview.ws.params.ParamDatastoreI; import jalview.ws.params.WsParamSetI; import jalview.ws2.MenuEntryProviderI; import jalview.ws2.ResultSupplier; @@ -49,6 +53,9 @@ import jalview.ws2.PollingTaskExecutor; import jalview.ws2.WebServiceI; import jalview.ws2.WebServiceInfoUpdater; import jalview.ws2.WebServiceWorkerI; +import jalview.ws2.WebServiceWorkerListener; +import jalview.ws2.WebServiceWorkerListenersList; +import jalview.ws2.gui.AlignmentMenuBuilder; import jalview.ws2.utils.WSJobList; /** @@ -58,12 +65,14 @@ import jalview.ws2.utils.WSJobList; */ public class AlignmentOperation implements Operation { - final WebServiceI service; + private final WebServiceI service; - final ResultSupplier supplier; + private final ResultSupplier supplier; + - public AlignmentOperation(WebServiceI service, - ResultSupplier supplier) + public AlignmentOperation( + WebServiceI service, + ResultSupplier supplier) { this.service = service; this.supplier = supplier; @@ -74,6 +83,12 @@ public class AlignmentOperation implements Operation { return service.getName(); } + + @Override + public String getDescription() + { + return service.getDescription(); + } @Override public String getTypeName() @@ -86,6 +101,18 @@ public class AlignmentOperation implements Operation { return service.getHostName(); } + + @Override + public boolean hasParameters() + { + return service.hasParameters(); + } + + @Override + public ParamDatastoreI getParamStore() + { + return service.getParamStore(); + } @Override public int getMinSequences() @@ -121,7 +148,7 @@ public class AlignmentOperation implements Operation public boolean canSubmitGaps() { // hack copied from original jabaws code, don't blame me - return service.getName().contains("lustal"); + return getName().contains("lustal"); } @Override @@ -145,164 +172,9 @@ public class AlignmentOperation implements Operation @Override public MenuEntryProviderI getMenuBuilder() { - return this::buildMenu; - } - - protected void buildMenu(JMenu parent, AlignFrame frame) - { - if (canSubmitGaps()) - { - var alignSubmenu = new JMenu(service.getName()); - buildMenu(alignSubmenu, frame, false); - parent.add(alignSubmenu); - var realignSubmenu = new JMenu(MessageManager.formatMessage( - "label.realign_with_params", service.getName())); - realignSubmenu.setToolTipText(MessageManager - .getString("label.align_sequences_to_existing_alignment")); - buildMenu(realignSubmenu, frame, true); - parent.add(realignSubmenu); - } - else - { - buildMenu(parent, frame, false); - } + return new AlignmentMenuBuilder(this); } - protected void buildMenu(JMenu parent, AlignFrame frame, - boolean submitGaps) - { - final String action = submitGaps ? "Align" : "Realign"; - final var calcName = service.getName(); - - String title = frame.getTitle(); - PollingTaskExecutor executor = frame.getViewport().getWSExecutor(); - { - var item = new JMenuItem(MessageManager.formatMessage( - "label.calcname_with_default_settings", calcName)); - item.setToolTipText(MessageManager - .formatMessage("label.action_with_default_settings", action)); - item.addActionListener((event) -> { - final AlignmentView msa = frame.gatherSequencesForAlignment(); - final AlignViewport viewport = frame.getViewport(); - final AlignmentI alignment = frame.getViewport().getAlignment(); - if (msa != null) - { - WebServiceWorkerI worker = new AlignmentWorker(msa, - Collections.emptyList(), title, submitGaps, true, - alignment, viewport); - executor.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_alignment")); - item.addActionListener((event) -> { - final AlignmentView msa = frame.gatherSequencesForAlignment(); - final AlignViewport viewport = frame.getViewport(); - final AlignmentI alignment = frame.getViewport().getAlignment(); - if (msa != null) - { - openEditParamsDialog(service, null, null) - .thenAcceptAsync((arguments) -> { - if (arguments != null) - { - WebServiceWorkerI worker = new AlignmentWorker(msa, - arguments, title, submitGaps, true, alignment, - viewport); - executor.submit(worker); - } - }); - } - }); - parent.add(item); - } - - var presets = service.getParamStore().getPresets(); - if (presets != null && presets.size() > 0) - { - final var presetList = new JMenu(MessageManager - .formatMessage("label.run_with_preset_params", calcName)); - final var showToolTipFor = ToolTipManager.sharedInstance() - .getDismissDelay(); - for (final var preset : presets) - { - var item = new JMenuItem(preset.getName()); - final int QUICK_TOOLTIP = 1500; - item.addMouseListener(new MouseAdapter() - { - @Override - public void mouseEntered(MouseEvent e) - { - ToolTipManager.sharedInstance().setDismissDelay(QUICK_TOOLTIP); - } - - @Override - public void mouseExited(MouseEvent e) - { - ToolTipManager.sharedInstance().setDismissDelay(showToolTipFor); - } - }); - String tooltip = JvSwingUtils.wrapTooltip(true, - format("%s
%s", - MessageManager.getString( - preset.isModifiable() ? "label.user_preset" - : "label.service_preset"), - preset.getDescription())); - item.setToolTipText(tooltip); - item.addActionListener((event) -> { - final AlignmentView msa = frame.gatherSequencesForAlignment(); - final AlignViewport viewport = frame.getViewport(); - final AlignmentI alignment = frame.getViewport().getAlignment(); - if (msa != null) - { - WebServiceWorkerI worker = new AlignmentWorker(msa, - preset.getArguments(), title, submitGaps, true, - alignment, viewport); - executor.submit(worker); - } - }); - presetList.add(item); - } - parent.add(presetList); - } - } - - 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); - 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; - } - }); - } /** * Implementation of the web service worker performing multiple sequence @@ -311,7 +183,7 @@ public class AlignmentOperation implements Operation * @author mmwarowny * */ - private class AlignmentWorker implements WebServiceWorkerI + public class AlignmentWorker implements WebServiceWorkerI { private long uid = MathUtils.getUID(); @@ -338,20 +210,18 @@ public class AlignmentOperation implements Operation private Map inputs = new LinkedHashMap<>(); - private WebserviceInfo wsInfo; - private Map exceptionCount = new HashMap<>(); - + private final int MAX_RETRY = 5; - AlignmentWorker(AlignmentView msa, List args, + public AlignmentWorker(AlignmentView msa, List args, String alnTitle, boolean submitGaps, boolean preserveOrder, - AlignmentI alignment, AlignViewport viewport) + AlignViewport viewport) { this.msa = msa; - this.dataset = alignment.getDataset(); + this.dataset = viewport.getAlignment().getDataset(); List cf = Objects.requireNonNullElse( - alignment.getCodonFrames(), Collections.emptyList()); + viewport.getAlignment().getCodonFrames(), Collections.emptyList()); this.codonFrame.addAll(cf); this.args = args; this.alnTitle = alnTitle; @@ -359,11 +229,6 @@ public class AlignmentOperation implements Operation this.preserveOrder = preserveOrder; this.viewport = viewport; this.gapCharacter = viewport.getGapCharacter(); - - String panelInfo = String.format("%s using service hosted at %s%n%s", - service.getName(), service.getHostName(), - Objects.requireNonNullElse(service.getDescription(), "")); - wsInfo = new WebserviceInfo(service.getName(), panelInfo, false); } @Override @@ -379,40 +244,30 @@ public class AlignmentOperation implements Operation } @Override - public List getJobs() + public WSJobList getJobs() { - return Collections.unmodifiableList(jobs); + return jobs; } @Override public void start() throws IOException { Cache.log.info(format("Starting new %s job.", service.getName())); - String outputHeader = String.format("%s of %s%nJob details%n", - submitGaps ? "Re-alignment" : "Alignment", alnTitle); SequenceI[][] conmsa = msa.getVisibleContigs('-'); if (conmsa == null) { return; } - WebServiceInfoUpdater updater = new WebServiceInfoUpdater(wsInfo); - updater.setOutputHeader(outputHeader); int numValid = 0; for (int i = 0; i < conmsa.length; i++) { JobInput input = JobInput.create(conmsa[i], 2, submitGaps); WSJob job = new WSJob(service.getProviderName(), service.getName(), service.getHostName()); - job.setJobNum(wsInfo.addJobPane()); - if (conmsa.length > 1) - { - wsInfo.setProgressName(String.format("region %d", i), - job.getJobNum()); - } - wsInfo.setProgressText(job.getJobNum(), outputHeader); - job.addPropertyChangeListener(updater); + job.setJobNum(i); inputs.put(job.getUid(), input); jobs.add(job); + listeners.fireJobCreated(job); if (input.isInputValid()) { int count; @@ -450,17 +305,11 @@ public class AlignmentOperation implements Operation } if (numValid > 0) { - // wsInfo.setThisService() should happen here - wsInfo.setVisible(true); + listeners.fireWorkerStarted(); } else { - wsInfo.setVisible(false); - // TODO show notification dialog. - // JvOptionPane.showMessageDialog(frame, - // MessageManager.getString("info.invalid_msa_input_mininfo"), - // MessageManager.getString("info.invalid_msa_notenough"), - // JvOptionPane.INFORMATION_MESSAGE); + listeners.fireWorkerNotStarted(); } } @@ -480,9 +329,7 @@ public class AlignmentOperation implements Operation } catch (IOException e) { Cache.log.error(format("Polling job %s failed.", job), e); - wsInfo.appendProgressText(job.getJobNum(), - MessageManager.formatMessage("info.server_exception", - service.getName(), e.getMessage())); + listeners.firePollException(job, e); int count = exceptionCount.getOrDefault(job.getUid(), MAX_RETRY); if (--count <= 0) @@ -503,45 +350,14 @@ public class AlignmentOperation implements Operation } done &= job.getStatus().isDone() || job.getStatus().isFailed(); } - updateWSInfoGlobalStatus(); return done; } - private void updateWSInfoGlobalStatus() - { - if (jobs.countRunning() > 0) - { - wsInfo.setStatus(WebserviceInfo.STATE_RUNNING); - } - else if (jobs.countQueuing() > 0 - || jobs.countSubmitted() < jobs.size()) - { - wsInfo.setStatus(WebserviceInfo.STATE_QUEUING); - } - else - { - if (jobs.countSuccessful() > 0) - { - wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_OK); - } - else if (jobs.countCancelled() > 0) - { - wsInfo.setStatus(WebserviceInfo.STATE_CANCELLED_OK); - } - else if (jobs.countFailed() > 0) - { - wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_ERROR); - } - } - } @Override public void done() { - long progbarId = MathUtils.getUID(); - wsInfo.setProgressBar( - MessageManager.getString("status.collecting_job_results"), - progbarId); + listeners.fireWorkerCompleting(); Map results = new LinkedHashMap<>(); for (WSJob job : getJobs()) { @@ -549,7 +365,8 @@ public class AlignmentOperation implements Operation continue; try { - AlignmentI alignment = supplier.getResult(job, dataset.getSequences(), viewport); + AlignmentI alignment = supplier.getResult(job, + dataset.getSequences(), viewport); if (alignment != null) { results.put(job.getUid(), alignment); @@ -564,39 +381,19 @@ public class AlignmentOperation implements Operation } } } - updateWSInfoGlobalStatus(); if (results.size() > 0) { - OutputWrapper out = prepareOutput(results); - wsInfo.showResultsNewFrame.addActionListener(evt -> displayNewFrame( - new Alignment(out.aln), out.alorders, out.hidden)); - wsInfo.setResultsReady(); + AlignmentResult out = prepareResult(results); + resultConsumer.accept(out); } else { - wsInfo.setFinishedNoResults(); + resultConsumer.accept(null); } - wsInfo.removeProgressBar(progbarId); + listeners.fireWorkerCompleted(); } - private class OutputWrapper - { - AlignmentI aln; - - List alorders; - - HiddenColumns hidden; - - OutputWrapper(AlignmentI aln, List alorders, - HiddenColumns hidden) - { - this.aln = aln; - this.alorders = alorders; - this.hidden = hidden; - } - } - - private OutputWrapper prepareOutput(Map alignments) + private AlignmentResult prepareResult(Map alignments) { List alorders = new ArrayList<>(); SequenceI[][] results = new SequenceI[jobs.size()][]; @@ -665,7 +462,7 @@ public class AlignmentOperation implements Operation aln.setDataset(dataset); propagateDatasetMappings(aln); - return new OutputWrapper(aln, alorders, hidden); + return new AlignmentResult(aln, alorders, hidden); // displayNewFrame(aln, alorders, hidden); } @@ -691,65 +488,53 @@ public class AlignmentOperation implements Operation } } } + + private Consumer resultConsumer; + + public void setResultConsumer(Consumer consumer) + { + this.resultConsumer = consumer; + } - private void displayNewFrame(AlignmentI aln, - List alorders, HiddenColumns hidden) + private WebServiceWorkerListenersList listeners = + new WebServiceWorkerListenersList(this); + + @Override + public void addListener(WebServiceWorkerListener listener) { - AlignFrame frame = new AlignFrame(aln, hidden, - AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT); - // TODO store feature renderer settings in worker object - // frame.getFeatureRenderer().transferSettings(featureSettings); - var regions = sortOrders(alorders); - if (alorders.size() == 1) - { - frame.addSortByOrderMenuItem( - format("%s Ordering", service.getName()), alorders.get(0)); - } - else - { - for (int i = 0; i < alorders.size(); i++) - { - final int j = i; - Iterable iter = () -> regions.get(j).stream() - .map(it -> Integer.toString(it)).iterator(); - var orderName = format("%s Region %s Ordering", service.getName(), - String.join(",", iter)); - frame.addSortByOrderMenuItem(orderName, alorders.get(i)); - } - } + listeners.addListener(listener); + } + } + + public class AlignmentResult + { + AlignmentI aln; - /* TODO - * If alignment was requested from one half of a SplitFrame, show in a - * SplitFrame with the other pane similarly aligned. - */ + List alorders; - Desktop.addInternalFrame(frame, alnTitle, AlignFrame.DEFAULT_WIDTH, - AlignFrame.DEFAULT_HEIGHT); + HiddenColumns hidden; + + AlignmentResult(AlignmentI aln, List alorders, + HiddenColumns hidden) + { + this.aln = aln; + this.alorders = alorders; + this.hidden = hidden; } - private List> sortOrders(List alorders) + public AlignmentI getAln() { - List> regions = new ArrayList<>(); - for (int i = 0; i < alorders.size(); i++) - { - List regs = new ArrayList<>(); - regs.add(i); - int j = i + 1; - while (j < alorders.size()) - { - if (alorders.get(i).equals(alorders.get(j))) - { - alorders.remove(j); - regs.add(j); - } - else - { - j++; - } - } - regions.add(regs); - } - return regions; + return aln; + } + + public List getAlorders() + { + return alorders; + } + + public HiddenColumns getHidden() + { + return hidden; } } diff --git a/src/jalview/ws2/operations/AnnotationOperation.java b/src/jalview/ws2/operations/AnnotationOperation.java index 55ed03b..c1d2c7e 100644 --- a/src/jalview/ws2/operations/AnnotationOperation.java +++ b/src/jalview/ws2/operations/AnnotationOperation.java @@ -21,11 +21,13 @@ import jalview.io.FeaturesFile; import jalview.util.Format; import jalview.util.MessageManager; import jalview.ws.params.ArgumentI; +import jalview.ws.params.ParamDatastoreI; import jalview.ws.params.WsParamSetI; import jalview.ws2.MenuEntryProviderI; import jalview.ws2.ResultSupplier; import jalview.ws2.PollingTaskExecutor; import jalview.ws2.WebServiceI; +import jalview.ws2.gui.AnnotationMenuBuilder; /** * @@ -65,6 +67,12 @@ public class AnnotationOperation implements Operation { return service.getName(); } + + @Override + public String getDescription() + { + return service.getDescription(); + } @Override public String getTypeName() @@ -77,6 +85,18 @@ public class AnnotationOperation implements Operation { return service.getHostName(); } + + @Override + public boolean hasParameters() + { + return service.hasParameters(); + } + + @Override + public ParamDatastoreI getParamStore() + { + return service.getParamStore(); + } @Override public int getMinSequences() @@ -145,119 +165,9 @@ public class AnnotationOperation implements Operation @Override public MenuEntryProviderI getMenuBuilder() { - if (isInteractive()) - return this::buildInteractiveMenu; - else - return this::buildClassicMenu; - } - - protected void buildClassicMenu(JMenu parent, AlignFrame frame) - { - final var calcName = service.getName(); - PollingTaskExecutor wsExecutor = frame.getViewport().getWSExecutor(); - final var calcManager = frame.getViewport().getCalcManager(); - { - var item = new JMenuItem(MessageManager.formatMessage( - "label.calcname_with_default_settings", calcName)); - item.addActionListener((event) -> { - var worker = createWorker(Collections.emptyList(), frame, calcManager); - calcManager.startWorker(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) - { - var worker = createWorker(arguments, frame, calcManager); - calcManager.startWorker(worker); - } - }); - }); - parent.add(item); - } - } - - protected void buildInteractiveMenu(JMenu parent, AlignFrame frame) - { - final var calcName = service.getName(); - final var calcManager = frame.getViewport().getCalcManager(); - final var arguments = new ArrayList(); - final JCheckBoxMenuItem runItem; - { - // TODO use MessageManager and set tool tip text - runItem = new JCheckBoxMenuItem( - String.format("%s calculations", calcName)); - runItem.addActionListener((event) -> { - calcManager.removeWorkersForName(calcName); - var worker = createWorker(arguments, frame, calcManager); - calcManager.registerWorker(worker); - }); - parent.add(runItem); - } - JMenuItem _editItem = null; - if (service.hasParameters()) - { - // TODO use MessageManager and set tool tip text - _editItem = new JMenuItem( - String.format("Edit %s settings", calcName)); - _editItem.addActionListener((event) -> { - openEditParamsDialog(service, null, null) - .thenAcceptAsync((args) -> { - if (arguments != null) - { - arguments.clear(); - arguments.addAll(args); - calcManager.removeWorkersForName(calcName); - var worker = createWorker(arguments, frame, calcManager); - calcManager.registerWorker(worker); - } - }); - }); - parent.add(_editItem); - } - final var editItem = _editItem; - - parent.addMenuListener(new MenuListener() - { - @Override - public void menuSelected(MenuEvent e) - { - var isNuc = frame.getViewport().getAlignment().isNucleotide(); - var menuEnabled = (isNuc && isNucleotideOperation()) || - (!isNuc && isProteinOperation()); - runItem.setEnabled(menuEnabled); - if (editItem != null) - editItem.setEnabled(menuEnabled); - boolean currentlyRunning = calcManager.getWorkersForName(calcName).size() > 0; - runItem.setSelected(currentlyRunning); - } - - @Override - public void menuDeselected(MenuEvent e) {} - - @Override - public void menuCanceled(MenuEvent e) {} - }); + return new AnnotationMenuBuilder(this); } - private AnnotationServiceWorker createWorker( - List arguments, AlignFrame frame, AlignCalcManagerI2 calcManager) - { - /* What is the purpose of AlignViewport and AlignmentViewPanel? */ - AlignViewport viewport = frame.getCurrentView(); - AlignmentViewPanel alignPanel = frame.alignPanel; - return new AnnotationServiceWorker(this, service, - arguments, viewport, alignPanel, frame, frame, - calcManager); - } private CompletionStage> openEditParamsDialog( WebServiceI service, WsParamSetI preset, List arguments) diff --git a/src/jalview/ws2/operations/AnnotationServiceWorker.java b/src/jalview/ws2/operations/AnnotationServiceWorker.java index 034b581..97b4199 100644 --- a/src/jalview/ws2/operations/AnnotationServiceWorker.java +++ b/src/jalview/ws2/operations/AnnotationServiceWorker.java @@ -68,12 +68,13 @@ public class AnnotationServiceWorker implements PollableAlignCalcWorkerI private int exceptionCount = MAX_RETRY; private static final int MAX_RETRY = 5; - AnnotationServiceWorker(AnnotationOperation operation, WebServiceI service, + public AnnotationServiceWorker(AnnotationOperation operation, List args, AlignViewport viewport, AlignmentViewPanel alignPanel, - IProgressIndicator progressIndicator, AlignFrame frame, AlignCalcManagerI2 calcMan) + IProgressIndicator progressIndicator, AlignFrame frame, + AlignCalcManagerI2 calcMan) { this.operation = operation; - this.service = service; + this.service = operation.service; this.args = args; this.viewport = viewport; this.alignPanel = alignPanel; diff --git a/src/jalview/ws2/operations/Operation.java b/src/jalview/ws2/operations/Operation.java index ff559d4..f02bb59 100644 --- a/src/jalview/ws2/operations/Operation.java +++ b/src/jalview/ws2/operations/Operation.java @@ -1,14 +1,21 @@ package jalview.ws2.operations; +import jalview.ws.params.ParamDatastoreI; import jalview.ws2.MenuEntryProviderI; public interface Operation { public String getName(); + + public String getDescription(); public String getTypeName(); public String getHostName(); + + public boolean hasParameters(); + + public ParamDatastoreI getParamStore(); public int getMinSequences(); @@ -29,4 +36,5 @@ public interface Operation public boolean getFilterNonStandardSymbols(); public boolean getNeedsAlignedSequences(); + } diff --git a/src/jalview/ws2/slivka/SlivkaWSDiscoverer.java b/src/jalview/ws2/slivka/SlivkaWSDiscoverer.java index c0c7502..8534f06 100644 --- a/src/jalview/ws2/slivka/SlivkaWSDiscoverer.java +++ b/src/jalview/ws2/slivka/SlivkaWSDiscoverer.java @@ -22,7 +22,7 @@ public class SlivkaWSDiscoverer implements WebServiceDiscoverer private static SlivkaWSDiscoverer instance = null; - private List services = List.of(); + private List operations = List.of(); private SlivkaWSDiscoverer() { @@ -96,14 +96,16 @@ public class SlivkaWSDiscoverer implements WebServiceDiscoverer } } - public List getServices() + @Override + public List getOperations() { - return Collections.unmodifiableList(services); + return Collections.unmodifiableList(operations); } + @Override public boolean hasServices() { - return !isRunning() && services.size() > 0; + return !isRunning() && operations.size() > 0; } public boolean isRunning() @@ -133,16 +135,16 @@ public class SlivkaWSDiscoverer implements WebServiceDiscoverer reloadServices(); return SlivkaWSDiscoverer.this; }); - task.thenRun(() -> fireServicesChanged(getServices())); + task.thenRun(() -> fireOperationsChanged(getOperations())); discoveryTasks.add(task); return task; } - private List reloadServices() + private List reloadServices() { Cache.log.info("Reloading Slivka services"); - fireServicesChanged(Collections.emptyList()); - ArrayList allServices = new ArrayList<>(); + fireOperationsChanged(Collections.emptyList()); + ArrayList allOperations= new ArrayList<>(); for (String url : getUrls()) { SlivkaClient client = new SlivkaClient(url); @@ -158,19 +160,20 @@ public class SlivkaWSDiscoverer implements WebServiceDiscoverer for (SlivkaService service : services) { SlivkaWebService instance = new SlivkaWebService(client, service); + Operation op = null; for (String classifier : service.classifiers) { String[] path = classifier.split("\\s*::\\s*"); if (path.length >= 3 && path[0].toLowerCase().equals("operation") && path[1].toLowerCase().equals("analysis")) { - Operation op = null; switch (path[path.length - 1].toLowerCase()) { case "sequence alignment analysis (conservation)": AnnotationOperation anop; op = anop = new AnnotationOperation(instance, - instance::getAnnotations, instance::getFeaturesFile, "Conservation"); + instance::getAnnotations, instance::getFeaturesFile, + "Conservation"); anop.setAlignmentAnalysis(true); anop.setInteractive(true); break; @@ -184,20 +187,18 @@ public class SlivkaWSDiscoverer implements WebServiceDiscoverer } if (op != null) { - instance.addOperation(op); break; } } } - if (instance.operations.size() > 0) - { - allServices.add(instance); + if (op != null) { + allOperations.add(op); } } } - this.services = allServices; + this.operations = allOperations; Cache.log.info("Reloading slivka services finished"); - return allServices; + return allOperations; } @Override diff --git a/src/jalview/ws2/slivka/SlivkaWebService.java b/src/jalview/ws2/slivka/SlivkaWebService.java index 4c58b61..9f04290 100644 --- a/src/jalview/ws2/slivka/SlivkaWebService.java +++ b/src/jalview/ws2/slivka/SlivkaWebService.java @@ -46,12 +46,8 @@ public class SlivkaWebService implements WebServiceI protected final SlivkaClient client; protected final SlivkaService service; - - protected SlivkaDatastore store = null; - - protected final ArrayList operations = new ArrayList<>(); - - protected int typeFlags = 0; + + protected ParamDatastoreI store; protected static final EnumMap statusMap = new EnumMap<>( Job.Status.class); @@ -100,22 +96,6 @@ public class SlivkaWebService implements WebServiceI } @Override - public List getOperations() - { - return operations; - } - - void addOperation(Operation operation) - { - operations.add(operation); - } - - void removeOperation(Operation operation) - { - operations.remove(operation); - } - - @Override public boolean hasParameters() { return getParamStore().getServiceParameters().size() > 0; -- 1.7.10.2