From: Mateusz Warowny Date: Fri, 12 Nov 2021 15:00:02 +0000 (+0100) Subject: JAL-3878 Add javadocs to created classes and reformat code. X-Git-Url: http://source.jalview.org/gitweb/?a=commitdiff_plain;h=2bbba7f7426314bfd6a1f206861542244b5f511a;p=jalview.git JAL-3878 Add javadocs to created classes and reformat code. --- diff --git a/src/jalview/gui/WebServicesMenuBuilder.java b/src/jalview/gui/WebServicesMenuBuilder.java index 2a17bf4..2aae0ff 100644 --- a/src/jalview/gui/WebServicesMenuBuilder.java +++ b/src/jalview/gui/WebServicesMenuBuilder.java @@ -19,6 +19,11 @@ import jalview.util.MessageManager; import jalview.ws2.WebServiceI; import jalview.ws2.operations.Operation; +/** + * + * @author mmwarowny + * + */ public class WebServicesMenuBuilder { @FunctionalInterface @@ -68,7 +73,7 @@ public class WebServicesMenuBuilder var keysSet = new HashSet<>(oneshotOperations.keySet()); keysSet.addAll(interactiveOperations.keySet()); var keys = new ArrayList<>(keysSet); - keys.sort(Comparator.naturalOrder()); + keys.sort(Comparator. naturalOrder()); for (String opType : keys) { var submenu = new JMenu(opType); @@ -87,12 +92,12 @@ public class WebServicesMenuBuilder } private void addOneshotOperations(List operations, JMenu submenu, - AlignFrame frame) + AlignFrame frame) { operations = new ArrayList<>(operations); operations.sort(Comparator - .comparing(o -> o.getHostName()) - .thenComparing(o -> o.getName())); + . comparing(o -> o.getHostName()) + . thenComparing(o -> o.getName())); String lastHost = null; for (final Operation op : operations) { @@ -123,7 +128,7 @@ public class WebServicesMenuBuilder groupedOperations.get(op.getName()).add(op); } var keys = new ArrayList<>(groupedOperations.keySet()); - keys.sort(Comparator.naturalOrder()); + keys.sort(Comparator. naturalOrder()); for (String opName : keys) { var ops = groupedOperations.get(opName); @@ -155,7 +160,8 @@ public class WebServicesMenuBuilder MessageManager.getString("label.choose_jabaws_server"))); for (final Operation op : ops) { - if (op == selectedOperation) continue; + if (op == selectedOperation) + continue; var hostItem = new JMenuItem(op.getHostName()); hostItem.setForeground(Color.blue); hostItem.addActionListener(e -> { diff --git a/src/jalview/ws2/MenuEntryProviderI.java b/src/jalview/ws2/MenuEntryProviderI.java index a5e2d0f..b6f0e9c 100755 --- a/src/jalview/ws2/MenuEntryProviderI.java +++ b/src/jalview/ws2/MenuEntryProviderI.java @@ -4,8 +4,25 @@ import javax.swing.JMenu; import jalview.gui.AlignFrame; +/** + * Functional interface provided by {@link jalview.ws2.operations.Operation} + * instances to construct the menu entry for the operations. The instances are + * passed to the {@link jalview.gui.WebServicesMenuBuilder} and called during + * menu construction. + * + * @author mmwarowny + */ @FunctionalInterface public interface MenuEntryProviderI { + /** + * Build menu entries directly under the given menu. This method is called by + * {@link jalview.gui.WebServicesMenuBuilder} during menu construction. + * + * @param parent + * parent menu + * @param frame + * current alignFrame + */ public void buildMenu(JMenu parent, AlignFrame frame); } diff --git a/src/jalview/ws2/PollableTaskI.java b/src/jalview/ws2/PollableTaskI.java index 88c7371..d097974 100644 --- a/src/jalview/ws2/PollableTaskI.java +++ b/src/jalview/ws2/PollableTaskI.java @@ -1,12 +1,51 @@ package jalview.ws2; +/** + * The {@code PollableTaskI} interface should be implemented by classes + * representing a background task that must be polled repeatedly to check for + * completion. Those are typically jobs that run on a remote host and need to be + * periodically checked for status updates. + * + * The life-cycle of a task consist of calling {@link #start} method once to + * start the process, followed by repeated calls to {@link #poll} that should + * check for execution status and finally {@link #done} method that finalizes + * the process. + * + * The instances can be started with {@link PollingTaskExecutor} which manages + * start up, polling and finalization of the task using a thread executor. + * + * @author mmwarowny + * + */ public interface PollableTaskI { + /** + * Called by the executor once and the beginning to start the task. May throw + * any exception, in such case the task will be interrupted. + * + * @throws Exception + */ void start() throws Exception; + /** + * Called repeatedly by the executor to check for task completion. The + * implementation should check the remote host for job status updates and + * return true when the task is finished. If any exception is thrown, the task + * is interrupted. + * + * @return whether the task is done + * @throws Exception + */ boolean poll() throws Exception; + /** + * @return whether the task is done + */ boolean isDone(); + /** + * Called once the task is done running ({@link #poll} returned true) to + * finalize the task and collect the results. + */ void done(); } diff --git a/src/jalview/ws2/PollableTaskListenerI.java b/src/jalview/ws2/PollableTaskListenerI.java index e5a3682..d69b2d9 100644 --- a/src/jalview/ws2/PollableTaskListenerI.java +++ b/src/jalview/ws2/PollableTaskListenerI.java @@ -1,14 +1,57 @@ package jalview.ws2; +/** + * Classes listening to the pollable task events must implement + * {@link PollableTaskListenerI}. They can be added to the + * {@link PollingTaskExecutor} to respond to the task execution events. + * + * @author mmwarowny + * + */ public interface PollableTaskListenerI { + /** + * Called when a new task is submitted for execution after its + * {@link PollableTask#start} method was called successfully. + * + * @param task + * submitted task + */ public void submitted(PollableTaskI task); + /** + * Called when a new task failed to start and raised an uncaught exception. + * + * @param task + * task that failed + * @param e + * raised exception + */ public void submissionFailed(PollableTaskI task, Exception e); + /** + * Called when polling resulted in an uncaught exception. + * + * @param task + * task that failed + * @param e + * raised exception + */ public void pollFailed(PollableTaskI task, Exception e); + /** + * Called when a task is cancelled. + * + * @param task + * cancelled task + */ public void cancelled(PollableTaskI task); + /** + * Called when the task finished execution either successfully or not. + * + * @param task + * finished task + */ public void done(PollableTaskI task); } diff --git a/src/jalview/ws2/PollingTaskExecutor.java b/src/jalview/ws2/PollingTaskExecutor.java index 3e04c17..c003e49 100644 --- a/src/jalview/ws2/PollingTaskExecutor.java +++ b/src/jalview/ws2/PollingTaskExecutor.java @@ -8,11 +8,31 @@ import java.util.concurrent.TimeUnit; import jalview.bin.Cache; +/** + * An object that executes submitted {@link PollableTaskI} tasks using + * {@link SchedulekExecutorservice}. The task is first started using its + * {@link PollableTaskI#start} method and then repeatedly polled every second + * with {@link PollableTaskI#poll}. + * + * The {@link PollingTaskExecutor} automates the process of running tasks and + * provides convenient interface to listen to events associated with task + * execution. + * + * @author mmwarowny + * + */ public class PollingTaskExecutor { private ScheduledExecutorService executor = Executors - .newSingleThreadScheduledExecutor(); - + .newSingleThreadScheduledExecutor(); + + /** + * Submit the task for execution. Calls task's {@code start} method and, if + * started successfully, schedules next poll after one second. + * + * @param task + * task to submit + */ public void submit(final PollableTaskI task) { executor.submit(() -> { @@ -30,6 +50,14 @@ public class PollingTaskExecutor }); } + /** + * Poll the task by calling it's {@code poll} method. If not finished, the + * next poll is scheduled to happen after one second, otherwise task's + * {@code done} method is called immediately. + * + * @param task + * task to poll + */ private void poll(PollableTaskI task) { boolean done; @@ -55,11 +83,21 @@ public class PollingTaskExecutor private WebServiceThreadSupport wsThreadSupport = new WebServiceThreadSupport(); + /** + * Add listener of the task related events. + * + * @param listener + * listener to add + */ public void addThreadListener(PollableTaskListenerI listener) { wsThreadSupport.addListener(listener); } + /** + * @param listener + * listener to be removed + */ public void removeThreadListener(PollableTaskListenerI listener) { wsThreadSupport.removeListener(listener); diff --git a/src/jalview/ws2/ResultSupplier.java b/src/jalview/ws2/ResultSupplier.java index 3642d8e..68979c2 100644 --- a/src/jalview/ws2/ResultSupplier.java +++ b/src/jalview/ws2/ResultSupplier.java @@ -7,6 +7,17 @@ import jalview.api.AlignViewportI; import jalview.datamodel.AlignmentI; import jalview.datamodel.SequenceI; +/** + * A generic function which supplies job result from the remote job to the + * worker object when the job is finished. Typically, the interface is + * implemented by one of the {@link WebServiceI} object methods and passed to + * the {@link WebServiceWorkerI} object on its creation. + * + * @author mmwarowny + * + * @param + * result type + */ @FunctionalInterface public interface ResultSupplier { diff --git a/src/jalview/ws2/WSJob.java b/src/jalview/ws2/WSJob.java index 0de6b22..979eaf9 100755 --- a/src/jalview/ws2/WSJob.java +++ b/src/jalview/ws2/WSJob.java @@ -70,6 +70,11 @@ public final class WSJob implements Serializable jobId, creationTime); } + /** + * Get the ordinal numer of the job. + * + * @return job number + */ public int getJobNum() { return jobNum; diff --git a/src/jalview/ws2/WebServiceDiscoverer.java b/src/jalview/ws2/WebServiceDiscoverer.java index 513610c..2dfa1ef 100644 --- a/src/jalview/ws2/WebServiceDiscoverer.java +++ b/src/jalview/ws2/WebServiceDiscoverer.java @@ -9,6 +9,20 @@ import java.util.concurrent.CopyOnWriteArrayList; import jalview.ws2.operations.Operation; +/** + * The discoverer and the supplier of the operations/web services available + * on the remote hosts. Each web service client used should have it's + * implementation of the discoverer acting as an intermediary between the servers + * and jalview application. There is no need for more than one discoverer + * per web client per application, therefore singletons can be used. + * + * The discoverer stores a list of url endpoints where the services can be + * found and builds instances of {@link jalview.ws2.operations.Operation} + * with associated implementations of {@link jalview.ws2.WebServiceI}. + * + * @author mmwarowny + * + */ public interface WebServiceDiscoverer { public static final int STATUS_OK = 1; @@ -19,47 +33,131 @@ public interface WebServiceDiscoverer public static final int STATUS_UNKNOWN = -2; + /** + * Get the list of urls that this discoverer will use. + */ public List getUrls(); + /** + * Set the list of urls where this discoverer will search for services. + */ public void setUrls(List wsUrls); + /** + * Test if the url is a valid url for that service discoverer. + */ public boolean testUrl(URL url); + /** + * Get the availability status of the services at the url. Return one of the + * status codes {@code STATUS_OK}, {@code STATUS_NO_SERVICES}, + * {@code STATUS_INVALID} or {@code STATUS_UNKNOWN}. + * + * @return status code for the services availability + */ public int getStatusForUrl(String url); + /** + * Get the list of operations found on the servers. + * + * @return list of operations found + */ public List getOperations(); + /** + * @return whether there are services found + */ public boolean hasServices(); + /** + * Check if service discovery is still in progress. List of operations may be + * incomplete when the discoverer is running. + * + * @return whether the discoverer is running + */ public boolean isRunning(); + /** + * Check if the discoverer is done searching for services. List of operations + * should be complete if this methods returns true. + * + * @return whether the discoverer finished + */ public boolean isDone(); + /** + * Start the service discovery and return a future which will be set with this + * discoverer when the process is completed. This method should be called once + * on startup and then every time the urls list is updated. + * + * @return future that will be set on discovery completion + */ public CompletableFuture startDiscoverer(); + /** + * Get the error messages that occurred during service discovery. + * + * @return error message + */ public String getErrorMessages(); + /** + * An interface for the listeners observing the changes to the operations + * list. + * + * @author mmwarowny + */ @FunctionalInterface static interface ServiceChangeListener { + /** + * Called whenever the operations list of the observed discoverer changes + * with that discoverer as the first argument and current operations list as + * the second. Operations list can be empty if there are no services or the + * list was cleared at the beginning of the discovery. + * + * @param discoverer + * @param list + */ public void operationsChanged(WebServiceDiscoverer discoverer, - List list); + List list); } List serviceListeners = new CopyOnWriteArrayList<>(); + /** + * Add an operations list observer that will be notified of any changes. + * + * @param listener + * operations list listener + */ public default void addServiceChangeListener( - ServiceChangeListener listener) + ServiceChangeListener listener) { serviceListeners.add(listener); } + /** + * Remove the listener from the observers list. + * + * @param listener + * listener to be removed + */ public default void removeServiceChangeListener( - ServiceChangeListener listener) + ServiceChangeListener listener) { serviceListeners.remove(listener); } + /** + * Called whenever the list of operations changes. Notifies all listeners of + * the change to the operations list. Typically, should be called with an + * empty list at the beginning of the service discovery process and for the + * second time with the list of discovered operations after that. + * + * @param list + * new list of discovered operations + */ default void fireOperationsChanged(List list) { for (var listener : serviceListeners) diff --git a/src/jalview/ws2/WebServiceI.java b/src/jalview/ws2/WebServiceI.java index a09233f..cdb201e 100755 --- a/src/jalview/ws2/WebServiceI.java +++ b/src/jalview/ws2/WebServiceI.java @@ -20,21 +20,75 @@ import jalview.ws2.operations.Operation; */ public interface WebServiceI { + /** + * Get the hostname/url of the remote server which is supplying the service. + * + * @return host name + */ public String getHostName(); + /** + * Get the short name of the service supplier. + * + * @return short service supplier name + */ public String getProviderName(); + /** + * Get the name of the service + * + * @return service name + */ String getName(); + /** + * Get the description of the service. + * + * @return service description + */ String getDescription(); + /** + * Return whether the service provider user-adjustable parameters. + * + * @return whether service has parameters + */ boolean hasParameters(); + /** + * Get a {@link ParamDatastoreI} object containing service parameters and + * presets. + * + * @return service parameters and presets + */ public ParamDatastoreI getParamStore(); + /** + * Submit new job to the service with the supplied input sequences and + * arguments. Implementations should perform all data parsing necessary for + * the job submission and start a new job on the remote server. + * + * @param sequences + * input sequences + * @param args + * user provided arguments + * @return job id + * @throws IOException + * submission failed due to a connection error + */ public String submit(List sequences, List args) - throws IOException; + throws IOException; + /** + * Update the progress of the running job according to the state reported by + * the server. Implementations should fetch the current job status from the + * server and update status and log messages on the provided job object. + * + * @param job + * job to update + * @throws IOException + * server error occurred + */ public void updateProgress(WSJob job) throws IOException; public void cancel(WSJob job) throws IOException; diff --git a/src/jalview/ws2/WebServiceInfoUpdater.java b/src/jalview/ws2/WebServiceInfoUpdater.java index c9557c6..a4d0f70 100644 --- a/src/jalview/ws2/WebServiceInfoUpdater.java +++ b/src/jalview/ws2/WebServiceInfoUpdater.java @@ -6,6 +6,17 @@ import java.util.Objects; import jalview.gui.WebserviceInfo; +/** + * A helper class that can be attached as a listener to the {@link WSJob} + * object. It updates the job status in the {@link jalview.gui.WebServiceInfo} + * window according to the state changes of the job object. + * + * The {@link WebServiceInfoUpdater} object allows to decouple GUI updates + * from the web service worker logic. + * + * @author mmwarowny + * + */ public class WebServiceInfoUpdater implements PropertyChangeListener { private final WebServiceWorkerI worker; diff --git a/src/jalview/ws2/WebServiceWorkerI.java b/src/jalview/ws2/WebServiceWorkerI.java index 38c82a2..6f3ef9f 100644 --- a/src/jalview/ws2/WebServiceWorkerI.java +++ b/src/jalview/ws2/WebServiceWorkerI.java @@ -5,18 +5,51 @@ import java.util.List; import jalview.ws2.utils.WSJobList; +/** + * {@link WebServiceWorkerI} interface is an extension of {@link PollableTaskI} + * that adds getter methods for fields that are specific for the web service + * tasks such as uid, sub-jobs and underlying web service client as well as a + * method to add listeners to the worker events. {@link WebServiceWorkerI} + * objects perform operations needed to start, poll and finalize jobs running on + * the server as well as store sub-jobs created in the process. They use their + * associated {@link WebServiceI} object to submit and poll the jobs and fetch + * and parse the result when it's ready. + * + * @author mmwarowny + * + */ public interface WebServiceWorkerI extends PollableTaskI -{ +{ + /** + * Get unique identifier of this worker. Identifier should be randomly + * generated on object creation and must remain unchanged. Unique id can be + * generated using {@link jalview.util.MathUtils#getUID}. + * + * @return worker unique id + */ long getUID(); + /** + * Get the sub-jobs created by the worker during job submission. + * + * @return sub-jobs + */ WSJobList getJobs(); + /** + * Gather and parse input data and submit one or more jobs to the web service + * using associated {@link WebServiceI} object. + */ void start() throws IOException; boolean poll() throws IOException; WebServiceI getWebService(); + /** + * Check if all sub-jobs finished execution and return whether this task has + * completed. + */ default boolean isDone() { if (getJobs().size() == 0) @@ -29,11 +62,14 @@ public interface WebServiceWorkerI extends PollableTaskI return true; } - /* - * Called by the executor when the worker transitions to the done state - * either normally or exceptionally. - */ void done(); - + + /** + * Add worker listeners to this worker that will be notified about any state + * changes to this worker. + * + * @param listener + * listener to add + */ public void addListener(WebServiceWorkerListener listener); } diff --git a/src/jalview/ws2/WebServiceWorkerListener.java b/src/jalview/ws2/WebServiceWorkerListener.java index 16ee7bd..74eb144 100644 --- a/src/jalview/ws2/WebServiceWorkerListener.java +++ b/src/jalview/ws2/WebServiceWorkerListener.java @@ -1,16 +1,72 @@ package jalview.ws2; +/** + * The listener interface for receiving signals from the + * {@link WebServiceWorkerI} about the state changes or new sub-jobs spawned. + * + * The {@link WebServiceWorkerListener} objects created from that interface are + * then registered with a worker objects using + * {@link WebServiceWorkerI#addListener} method. When an event occurs, a + * relevant method in the listener is invoked with the worker that emitted the + * signal as a first parameter and, optionally, followed by additional event + * details. + * + * @author mmwarowny + * + */ public interface WebServiceWorkerListener { + /** + * Called when the worker started successfully. + * + * @param source + * worker that emitted the signal + */ void workerStarted(WebServiceWorkerI source); - + + /** + * Called when the worker failed to start the jobs. + * + * @param source + * worker that emitted the signal + */ void workerNotStarted(WebServiceWorkerI source); - + + /** + * Called when the worker creates a new job + * + * @param source + * worker that emitted the signal + * @param job + * newly created job + */ void jobCreated(WebServiceWorkerI source, WSJob job); - + + /** + * Called when polling the job results in an exception. + * + * @param source + * worker that emitted the signal + * @param job + * polled job + * @param e + * exception that occurred + */ void pollException(WebServiceWorkerI source, WSJob job, Exception e); - + + /** + * Called when the polling has finished and the finalization process begun. + * + * @param source + * worker that emitted the signal + */ void workerCompleting(WebServiceWorkerI source); - + + /** + * Called when the worker completes its work. + * + * @param source + * worker that emitted the signal + */ void workerCompleted(WebServiceWorkerI source); } diff --git a/src/jalview/ws2/WebServiceWorkerListenersList.java b/src/jalview/ws2/WebServiceWorkerListenersList.java index a09c958..bce6d57 100644 --- a/src/jalview/ws2/WebServiceWorkerListenersList.java +++ b/src/jalview/ws2/WebServiceWorkerListenersList.java @@ -4,67 +4,136 @@ import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; import java.util.function.Consumer; +/** + * Utility class that manages a list of {@link WebServiceWorkerListener} and + * dispatches signals to them. An instance of this class can be used as a member + * field of the {@link WebServiceWorkerI} object to easily store listeners and + * delegate signals to them. Firing any signal with this object will invoke a + * corresponding method on all registered listeners in order they were + * registered. + * + * @author mmwarowny + * + */ public class WebServiceWorkerListenersList { private WebServiceWorkerI owner; + private List listeners = new CopyOnWriteArrayList<>(); - + + /** + * Constructs a listeners list object with the worker which will be given + * to the listeners as the source of the signals. + * + * @param worker the worker to be given as the source for signals + */ public WebServiceWorkerListenersList(WebServiceWorkerI worker) { this.owner = worker; } - + + /** + * Add listener to the listeners list. The listener will be notified of + * any signals triggered with this object. + * + * @param listener listener to add + */ public void addListener(WebServiceWorkerListener listener) { listeners.add(listener); } - + + /** + * Remove listener from the lsiteners list. The listener will no longer be + * notified of the emitted signals. + * + * @param listener listener to remove + */ public void removeListener(WebServiceWorkerListener listener) { listeners.remove(listener); } - + + /** + * Emit "worker started" signal to all listeners. + */ public void fireWorkerStarted() { for (var listener : listeners) listener.workerStarted(owner); } - + + /** + * Emit "worker not started" signal to all listeners. + */ public void fireWorkerNotStarted() { for (var listener : listeners) listener.workerNotStarted(owner); } - + + /** + * Emit "job created" signal to all listeners passing the job that has been + * created to them. + * + * @param job newly created job + */ public void fireJobCreated(WSJob job) { for (var listener : listeners) listener.jobCreated(owner, job); } - + + /** + * Emit "poll exception" signal to all listener when an exception occurred + * during job polling. The job which caused an exception as well as the exception + * are passed to all listeners. + * + * @param job polled job + * @param e exception that occurred + */ public void firePollException(WSJob job, Exception e) { for (var listener : listeners) listener.pollException(owner, job, e); } - + + /** + * Emit "worker completing" signal to all listeners when the worker starts + * collecting and parsing the results. + */ public void fireWorkerCompleting() { for (var listener : listeners) listener.workerCompleting(owner); } - + + /** + * Emit "worker completed" signal to all listeners indicating that the worker + * finished processing data and finalized the jobs. + */ public void fireWorkerCompleted() { for (var listener : listeners) listener.workerCompleted(owner); } + /** + * Get the list of registered listeners. The returned list should not be + * modified externally and its content may change when workers are added + * or removed from the list. + * @return + */ public List getListeners() { return listeners; } - + + /** + * Execute an operation for each listener in the listeners list. + * + * @param consumer listener object consumer + */ public void forEach(Consumer consumer) { for (var listener : listeners) diff --git a/src/jalview/ws2/gui/ProgressBarUpdater.java b/src/jalview/ws2/gui/ProgressBarUpdater.java index 24c71d7..89deb06 100644 --- a/src/jalview/ws2/gui/ProgressBarUpdater.java +++ b/src/jalview/ws2/gui/ProgressBarUpdater.java @@ -7,15 +7,21 @@ import jalview.gui.IProgressIndicator; import jalview.ws2.WSJob; import jalview.ws2.WSJobStatus; +/** + * Monitors annotation jobs' status and updates progress indicators accordingly. + * + * @author mmwarowny + * + */ public class ProgressBarUpdater implements PropertyChangeListener { private IProgressIndicator progressIndicator; - + public ProgressBarUpdater(IProgressIndicator progressIndicator) { this.progressIndicator = progressIndicator; } - + @Override public void propertyChange(PropertyChangeEvent evt) { diff --git a/src/jalview/ws2/operations/AlignmentOperation.java b/src/jalview/ws2/operations/AlignmentOperation.java index 1f0a602..ea8e529 100644 --- a/src/jalview/ws2/operations/AlignmentOperation.java +++ b/src/jalview/ws2/operations/AlignmentOperation.java @@ -59,6 +59,7 @@ import jalview.ws2.gui.AlignmentMenuBuilder; import jalview.ws2.utils.WSJobList; /** + * Implementation of the {@link Operation} for multiple sequence alignment jobs. * * @author mmwarowny * @@ -68,7 +69,6 @@ public class AlignmentOperation implements Operation private final WebServiceI service; private final ResultSupplier supplier; - public AlignmentOperation( WebServiceI service, @@ -83,7 +83,7 @@ public class AlignmentOperation implements Operation { return service.getName(); } - + @Override public String getDescription() { @@ -101,13 +101,13 @@ public class AlignmentOperation implements Operation { return service.getHostName(); } - + @Override public boolean hasParameters() { return service.hasParameters(); } - + @Override public ParamDatastoreI getParamStore() { @@ -137,7 +137,7 @@ public class AlignmentOperation implements Operation { return true; } - + @Override public boolean isAlignmentAnalysis() { @@ -156,13 +156,13 @@ public class AlignmentOperation implements Operation { return false; } - + @Override public boolean getFilterNonStandardSymbols() { return true; } - + @Override public boolean getNeedsAlignedSequences() { @@ -175,7 +175,6 @@ public class AlignmentOperation implements Operation return new AlignmentMenuBuilder(this); } - /** * Implementation of the web service worker performing multiple sequence * alignment. @@ -211,12 +210,12 @@ public class AlignmentOperation implements Operation private Map inputs = new LinkedHashMap<>(); private Map exceptionCount = new HashMap<>(); - + private final int MAX_RETRY = 5; public AlignmentWorker(AlignmentView msa, List args, - String alnTitle, boolean submitGaps, boolean preserveOrder, - AlignViewport viewport) + String alnTitle, boolean submitGaps, boolean preserveOrder, + AlignViewport viewport) { this.msa = msa; this.dataset = viewport.getAlignment().getDataset(); @@ -263,7 +262,7 @@ public class AlignmentOperation implements Operation { JobInput input = JobInput.create(conmsa[i], 2, submitGaps); WSJob job = new WSJob(service.getProviderName(), service.getName(), - service.getHostName()); + service.getHostName()); job.setJobNum(i); inputs.put(job.getUid(), input); jobs.add(job); @@ -300,7 +299,7 @@ public class AlignmentOperation implements Operation { job.setStatus(WSJobStatus.INVALID); job.setErrorLog( - MessageManager.getString("label.empty_alignment_job")); + MessageManager.getString("label.empty_alignment_job")); } } if (numValid > 0) @@ -331,29 +330,28 @@ public class AlignmentOperation implements Operation Cache.log.error(format("Polling job %s failed.", job), e); listeners.firePollException(job, e); int count = exceptionCount.getOrDefault(job.getUid(), - MAX_RETRY); + MAX_RETRY); if (--count <= 0) { job.setStatus(WSJobStatus.SERVER_ERROR); Cache.log.warn(format( - "Attempts limit exceeded. Droping job %s.", job)); + "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); + format("Out of memory when retrieving job %s", job), e); } Cache.log.debug( - format("Job %s status is %s", job, job.getStatus())); + format("Job %s status is %s", job, job.getStatus())); } done &= job.getStatus().isDone() || job.getStatus().isFailed(); } return done; } - @Override public void done() { @@ -365,7 +363,7 @@ public class AlignmentOperation implements Operation continue; try { - AlignmentI alignment = supplier.getResult(job, + AlignmentI alignment = supplier.getResult(job, dataset.getSequences(), viewport); if (alignment != null) { @@ -418,16 +416,16 @@ public class AlignmentOperation implements Operation width = Integer.max(width, emptySeq.getLength()); // pad shorter sequences with gaps String gapSeq = String.join("", - Collections.nCopies(width, Character.toString(gapChar))); + Collections.nCopies(width, Character.toString(gapChar))); List seqs = new ArrayList<>( - alnSeqs.size() + emptySeqs.size()); + alnSeqs.size() + emptySeqs.size()); seqs.addAll(alnSeqs); seqs.addAll(emptySeqs); for (var seq : seqs) { if (seq.getLength() < width) seq.setSequence(seq.getSequenceAsString() - + gapSeq.substring(seq.getLength())); + + gapSeq.substring(seq.getLength())); } SequenceI[] result = seqs.toArray(new SequenceI[0]); AlignmentOrder msaOrder = new AlignmentOrder(result); @@ -488,24 +486,23 @@ public class AlignmentOperation implements Operation } } } - + private Consumer resultConsumer; - + public void setResultConsumer(Consumer consumer) { this.resultConsumer = consumer; } - private WebServiceWorkerListenersList listeners = - new WebServiceWorkerListenersList(this); - + private WebServiceWorkerListenersList listeners = new WebServiceWorkerListenersList(this); + @Override public void addListener(WebServiceWorkerListener listener) { listeners.addListener(listener); } } - + public class AlignmentResult { AlignmentI aln; @@ -515,7 +512,7 @@ public class AlignmentOperation implements Operation HiddenColumns hidden; AlignmentResult(AlignmentI aln, List alorders, - HiddenColumns hidden) + HiddenColumns hidden) { this.aln = aln; this.alorders = alorders; @@ -548,8 +545,8 @@ public class AlignmentOperation implements Operation final Map sequenceNames; private JobInput(int numSequences, List inputSequences, - List emptySequences, - @SuppressWarnings("rawtypes") Map names) + List emptySequences, + @SuppressWarnings("rawtypes") Map names) { this.inputSequences = Collections.unmodifiableList(inputSequences); this.emptySequences = Collections.unmodifiableList(emptySequences); @@ -562,10 +559,10 @@ public class AlignmentOperation implements Operation } static JobInput create(SequenceI[] sequences, int minLength, - boolean submitGaps) + boolean submitGaps) { assert minLength >= 0 : MessageManager.getString( - "error.implementation_error_minlen_must_be_greater_zero"); + "error.implementation_error_minlen_must_be_greater_zero"); int numSeq = 0; for (SequenceI seq : sequences) { @@ -592,20 +589,20 @@ public class AlignmentOperation implements Operation if (!submitGaps) { seqString = AlignSeq.extractGaps( - jalview.util.Comparison.GapChars, seqString); + jalview.util.Comparison.GapChars, seqString); } inputSequences.add(new Sequence(newName, seqString)); } else { String seqString = ""; - if (seq.getEnd() >= seq.getStart()) // true if gaps only + if (seq.getEnd() >= seq.getStart()) // true if gaps only { seqString = seq.getSequenceAsString(); if (!submitGaps) { seqString = AlignSeq.extractGaps( - jalview.util.Comparison.GapChars, seqString); + jalview.util.Comparison.GapChars, seqString); } } emptySequences.add(new Sequence(newName, seqString)); diff --git a/src/jalview/ws2/operations/Operation.java b/src/jalview/ws2/operations/Operation.java index f02bb59..bd12041 100644 --- a/src/jalview/ws2/operations/Operation.java +++ b/src/jalview/ws2/operations/Operation.java @@ -3,38 +3,117 @@ package jalview.ws2.operations; import jalview.ws.params.ParamDatastoreI; import jalview.ws2.MenuEntryProviderI; +/** + * Operation represents an action which can be performed with a (web)service or + * calculator. Examples of operations are multiple sequence alignment or + * sequence annotation. There should be one Operation implementation for each + * operation that Jalview can perform on sequences or alignments. The concrete + * implementations may be further parameterized to alter the functionality (e.g. + * making the operation interactive) or restrict input data (e.g. limit to + * proteins only). + * + * @author mmwarowny + * + */ public interface Operation { + /** + * Get the name of the operation. Typically fetched from the server. + * + * @return operation name + */ public String getName(); - + + /** + * Get the description of the operation. Typically fetched from the server. + * + * @return operation description + */ public String getDescription(); + /** + * Get the name of the category that the operation falls into. Used to group + * the operations under the web services menu. + * + * @return category name + */ public String getTypeName(); + /** + * Get the hostname/url of the server which this operation is delegated to. + * Typically fetched from the accompanying web service instance. + * + * @return server url + */ public String getHostName(); - + + /** + * Check if the operation has user-customizable input parameters. + * + * @return if has parameters + */ public boolean hasParameters(); - + + /** + * Returns parameter datastore for this operations containing input parameters + * and available presets. + * + * @return parameter datastore of the operation + */ public ParamDatastoreI getParamStore(); + /** + * @return minimum accepted number of sequences + */ public int getMinSequences(); + /** + * @return maximum accepted number of sequences + */ public int getMaxSequences(); + /** + * @return whether gaps should be included + */ public boolean canSubmitGaps(); + /** + * @return whether works with protein sequences + */ public boolean isProteinOperation(); + /** + * @return whether works with nucleotide sequences + */ public boolean isNucleotideOperation(); + /** + * @return whether should be run interactively + */ public boolean isInteractive(); + /** + * Get the menu builder for this operation which will be used to construct the + * web services menu. The builder will be given the parent menu entry which it + * should attach menu items to and the current align frame. + * + * @return menu entry builder instance + */ public MenuEntryProviderI getMenuBuilder(); + /** + * @return whether this operation is alignment analysis + */ public boolean isAlignmentAnalysis(); - + + /** + * @return whether non-standatds symbols should be filtered out + */ public boolean getFilterNonStandardSymbols(); - + + /** + * @return whether it needs aligned sequences + */ public boolean getNeedsAlignedSequences(); }