import jalview.ws2.WebServiceI;
import jalview.ws2.operations.Operation;
+/**
+ *
+ * @author mmwarowny
+ *
+ */
public class WebServicesMenuBuilder
{
@FunctionalInterface
var keysSet = new HashSet<>(oneshotOperations.keySet());
keysSet.addAll(interactiveOperations.keySet());
var keys = new ArrayList<>(keysSet);
- keys.sort(Comparator.<String>naturalOrder());
+ keys.sort(Comparator.<String> naturalOrder());
for (String opType : keys)
{
var submenu = new JMenu(opType);
}
private void addOneshotOperations(List<Operation> operations, JMenu submenu,
- AlignFrame frame)
+ AlignFrame frame)
{
operations = new ArrayList<>(operations);
operations.sort(Comparator
- .<Operation, String>comparing(o -> o.getHostName())
- .<String>thenComparing(o -> o.getName()));
+ .<Operation, String> comparing(o -> o.getHostName())
+ .<String> thenComparing(o -> o.getName()));
String lastHost = null;
for (final Operation op : operations)
{
groupedOperations.get(op.getName()).add(op);
}
var keys = new ArrayList<>(groupedOperations.keySet());
- keys.sort(Comparator.<String>naturalOrder());
+ keys.sort(Comparator.<String> naturalOrder());
for (String opName : keys)
{
var ops = groupedOperations.get(opName);
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 -> {
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);
}
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();
}
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);
}
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(() -> {
});
}
+ /**
+ * 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;
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);
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 <T>
+ * result type
+ */
@FunctionalInterface
public interface ResultSupplier<T>
{
jobId, creationTime);
}
+ /**
+ * Get the ordinal numer of the job.
+ *
+ * @return job number
+ */
public int getJobNum()
{
return jobNum;
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;
public static final int STATUS_UNKNOWN = -2;
+ /**
+ * Get the list of urls that this discoverer will use.
+ */
public List<String> getUrls();
+ /**
+ * Set the list of urls where this discoverer will search for services.
+ */
public void setUrls(List<String> 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<Operation> 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<WebServiceDiscoverer> 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<Operation> list);
+ List<Operation> list);
}
List<ServiceChangeListener> 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<Operation> list)
{
for (var listener : serviceListeners)
*/
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<SequenceI> sequences, List<ArgumentI> 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;
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;
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)
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);
}
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);
}
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<WebServiceWorkerListener> 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<WebServiceWorkerListener> getListeners()
{
return listeners;
}
-
+
+ /**
+ * Execute an operation for each listener in the listeners list.
+ *
+ * @param consumer listener object consumer
+ */
public void forEach(Consumer<WebServiceWorkerListener> consumer)
{
for (var listener : listeners)
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)
{
import jalview.ws2.utils.WSJobList;
/**
+ * Implementation of the {@link Operation} for multiple sequence alignment jobs.
*
* @author mmwarowny
*
private final WebServiceI service;
private final ResultSupplier<AlignmentI> supplier;
-
public AlignmentOperation(
WebServiceI service,
{
return service.getName();
}
-
+
@Override
public String getDescription()
{
{
return service.getHostName();
}
-
+
@Override
public boolean hasParameters()
{
return service.hasParameters();
}
-
+
@Override
public ParamDatastoreI getParamStore()
{
{
return true;
}
-
+
@Override
public boolean isAlignmentAnalysis()
{
{
return false;
}
-
+
@Override
public boolean getFilterNonStandardSymbols()
{
return true;
}
-
+
@Override
public boolean getNeedsAlignedSequences()
{
return new AlignmentMenuBuilder(this);
}
-
/**
* Implementation of the web service worker performing multiple sequence
* alignment.
private Map<Long, JobInput> inputs = new LinkedHashMap<>();
private Map<Long, Integer> exceptionCount = new HashMap<>();
-
+
private final int MAX_RETRY = 5;
public AlignmentWorker(AlignmentView msa, List<ArgumentI> 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();
{
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);
{
job.setStatus(WSJobStatus.INVALID);
job.setErrorLog(
- MessageManager.getString("label.empty_alignment_job"));
+ MessageManager.getString("label.empty_alignment_job"));
}
}
if (numValid > 0)
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()
{
continue;
try
{
- AlignmentI alignment = supplier.getResult(job,
+ AlignmentI alignment = supplier.getResult(job,
dataset.getSequences(), viewport);
if (alignment != null)
{
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<SequenceI> 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);
}
}
}
-
+
private Consumer<AlignmentResult> resultConsumer;
-
+
public void setResultConsumer(Consumer<AlignmentResult> 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;
HiddenColumns hidden;
AlignmentResult(AlignmentI aln, List<AlignmentOrder> alorders,
- HiddenColumns hidden)
+ HiddenColumns hidden)
{
this.aln = aln;
this.alorders = alorders;
final Map<String, ? extends Map> sequenceNames;
private JobInput(int numSequences, List<SequenceI> inputSequences,
- List<SequenceI> emptySequences,
- @SuppressWarnings("rawtypes") Map<String, ? extends Map> names)
+ List<SequenceI> emptySequences,
+ @SuppressWarnings("rawtypes") Map<String, ? extends Map> names)
{
this.inputSequences = Collections.unmodifiableList(inputSequences);
this.emptySequences = Collections.unmodifiableList(emptySequences);
}
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)
{
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));
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();
}