package jalview.ws2;
-
public enum WSJobStatus
{
/** Job has invalid parameters and cannot be started. */
/** Job is running. */
RUNNING,
/** Job has finished with no errors. */
- FINISHED,
- BROKEN,
+ FINISHED, BROKEN,
/** Job has finished with errors. */
FAILED,
/** Job cannot be processed or completed due to server error. */
/** Status cannot be determined. */
UNKNOWN;
-
public boolean isSubmitted()
{
switch (this)
public interface WebServiceDiscoverer
{
public static final int STATUS_OK = 1;
+
public static final int STATUS_NO_SERVICES = 0;
+
public static final int STATUS_INVALID = -1;
+
public static final int STATUS_UNKNOWN = -2;
public List<String> getUrls();
public String getErrorMessages();
@FunctionalInterface
- static interface ServiceChangeListener {
+ static interface ServiceChangeListener
+ {
public void servicesChanged(WebServiceDiscoverer discoverer,
Collection<? extends WebServiceI> services);
}
List<ServiceChangeListener> serviceListeners = new CopyOnWriteArrayList<>();
- public default void addServiceChangeListener(ServiceChangeListener listener) {
+ public default void addServiceChangeListener(
+ ServiceChangeListener listener)
+ {
serviceListeners.add(listener);
}
- public default void removeServiceChangeListener(ServiceChangeListener listener) {
+ public default void removeServiceChangeListener(
+ ServiceChangeListener listener)
+ {
serviceListeners.remove(listener);
}
- default void fireServicesChanged(List<WebServiceI> services) {
- for (var listener: serviceListeners) {
+ default void fireServicesChanged(List<WebServiceI> services)
+ {
+ for (var listener : serviceListeners)
+ {
listener.servicesChanged(this, services);
}
}
public class WebServiceExecutor
{
- private ScheduledExecutorService executor =
- Executors.newSingleThreadScheduledExecutor();
+ private ScheduledExecutorService executor = Executors
+ .newSingleThreadScheduledExecutor();
public void submit(final WebServiceWorkerI worker)
{
executor.submit(() -> {
- try {
- worker.startJobs();
- wsThreadSupport.submitted(worker);
- }
- catch (Exception e) {
- Cache.log.error("Failed to submit web service jobs.", e);
- wsThreadSupport.submissionFailed(worker, e);
- return;
- }
- executor.schedule(() -> pollJobs(worker), 1, TimeUnit.SECONDS);
+ try
+ {
+ worker.startJobs();
+ wsThreadSupport.submitted(worker);
+ } catch (Exception e)
+ {
+ Cache.log.error("Failed to submit web service jobs.", e);
+ wsThreadSupport.submissionFailed(worker, e);
+ return;
}
- );
+ executor.schedule(() -> pollJobs(worker), 1, TimeUnit.SECONDS);
+ });
executor.schedule(() -> pollJobs(worker), 1, TimeUnit.SECONDS);
-}
-
+ }
- private void pollJobs(WebServiceWorkerI worker) {
- try {
+ private void pollJobs(WebServiceWorkerI worker)
+ {
+ try
+ {
worker.pollJobs();
- }
- catch (Exception e) {
+ } catch (Exception e)
+ {
Cache.log.error("Failed to poll web service jobs.", e);
- for (WSJob job : worker.getJobs()) {
+ for (WSJob job : worker.getJobs())
+ {
job.setStatus(WSJobStatus.SERVER_ERROR);
}
wsThreadSupport.pollFailed(worker, e);
return;
}
- if (!worker.isDone()) {
+ if (!worker.isDone())
+ {
executor.schedule(() -> pollJobs(worker), 1, TimeUnit.SECONDS);
}
- else {
+ else
+ {
worker.done();
wsThreadSupport.done(worker);
}
wsThreadSupport.removeListener(listener);
}
-
public void shutdown()
{
executor.shutdownNow();
}
-
-class WebServiceThreadSupport implements WebServiceThreadListenerI {
+class WebServiceThreadSupport implements WebServiceThreadListenerI
+{
List<WebServiceThreadListenerI> listeners = new CopyOnWriteArrayList<>();
@Override
public void submitted(WebServiceWorkerI thread)
{
- for (var listener : listeners) listener.submitted(thread);
+ for (var listener : listeners)
+ listener.submitted(thread);
}
@Override
public void submissionFailed(WebServiceWorkerI thread, Exception e)
{
- for (var listener : listeners) listener.submissionFailed(thread, e);
+ for (var listener : listeners)
+ listener.submissionFailed(thread, e);
}
@Override
- public void pollFailed(WebServiceWorkerI thread, Exception e) {
- for (var listener : listeners) listener.pollFailed(thread, e);
+ public void pollFailed(WebServiceWorkerI thread, Exception e)
+ {
+ for (var listener : listeners)
+ listener.pollFailed(thread, e);
}
@Override
public void cancelled(WebServiceWorkerI thread)
{
- for (var listener : listeners) listener.cancelled(thread);
+ for (var listener : listeners)
+ listener.cancelled(thread);
}
@Override
public void done(WebServiceWorkerI thread)
{
- for (var listener : listeners) listener.done(thread);
+ for (var listener : listeners)
+ listener.done(thread);
}
- public void addListener(WebServiceThreadListenerI listener) {
- if (!listeners.contains(listener)) {
+ public void addListener(WebServiceThreadListenerI listener)
+ {
+ if (!listeners.contains(listener))
+ {
listeners.add(listener);
}
}
- public void removeListener(WebServiceThreadListenerI listener) {
+ public void removeListener(WebServiceThreadListenerI listener)
+ {
listeners.remove(listener);
}
}
import jalview.ws2.operations.Operation;
/**
- * Provides information about the web service and sub-routines
- * to submit, track and cancel the jobs running on the server as well as
- * retrieve the results.
+ * Provides information about the web service and sub-routines to submit, track
+ * and cancel the jobs running on the server as well as retrieve the results.
* The instances should not depend on any other jalview components, especially
- * must be oblivious to the existence of any UI.
- * They are used by other classes such as WebServiceWorkers rather than
- * manipulate data themselves.
+ * must be oblivious to the existence of any UI. They are used by other classes
+ * such as WebServiceWorkers rather than manipulate data themselves.
*
* @author mmwarowny
*/
public interface WebServiceI
{
public String getHostName();
+
public String getProviderName();
+
public String getName();
+
public String getDescription();
+
public String getOperationType();
+
public List<Operation> getOperations();
+
public boolean hasParameters();
+
public ParamDatastoreI getParamStore();
public String submit(List<SequenceI> sequences, List<ArgumentI> args)
throws IOException;
- public void updateProgress(WSJob job)
- throws IOException;
+ public void updateProgress(WSJob job) throws IOException;
-// public <T> ResultSupplier<T> getResultSupplier(Class<T> type);
+ // public <T> ResultSupplier<T> getResultSupplier(Class<T> type);
public void cancel(WSJob job) throws IOException;
/**
- * Handle an exception that happened during job submission.
- * If the exception was handled property by this method, it
- * returns true. Otherwise, returns false indicating the exception
- * should be handled by the caller.
+ * Handle an exception that happened during job submission. If the exception
+ * was handled property by this method, it returns true. Otherwise, returns
+ * false indicating the exception should be handled by the caller.
*/
public boolean handleSubmissionError(WSJob job, Exception ex);
public class WebServiceInfoUpdater implements PropertyChangeListener
{
private final WebserviceInfo wsInfo;
+
private String outputHeader = "";
- public WebServiceInfoUpdater(WebserviceInfo wsInfo) {
+ public WebServiceInfoUpdater(WebserviceInfo wsInfo)
+ {
this.wsInfo = wsInfo;
}
- public String getOutputHeader() {
+ public String getOutputHeader()
+ {
return outputHeader;
}
- public void setOutputHeader(String header) {
+ public void setOutputHeader(String header)
+ {
this.outputHeader = header;
}
@Override
public void propertyChange(PropertyChangeEvent evt)
{
- switch (evt.getPropertyName()) {
+ switch (evt.getPropertyName())
+ {
case "status":
statusChanged(evt);
break;
}
}
- private void statusChanged(PropertyChangeEvent evt) {
+ private void statusChanged(PropertyChangeEvent evt)
+ {
WSJob job = (WSJob) evt.getSource();
WSJobStatus status = (WSJobStatus) evt.getNewValue();
int wsInfoStatus = 0;
- switch (status) {
+ switch (status)
+ {
case READY:
case SUBMITTED:
case QUEUED:
wsInfo.setStatus(job.getJobNum(), wsInfoStatus);
}
- private void logChanged(PropertyChangeEvent evt) {
+ private void logChanged(PropertyChangeEvent evt)
+ {
WSJob job = (WSJob) evt.getSource();
String oldLog = (String) evt.getOldValue();
String newLog = (String) evt.getNewValue();
- wsInfo.appendProgressText(job.getJobNum(), newLog.substring(oldLog.length()));
+ wsInfo.appendProgressText(job.getJobNum(),
+ newLog.substring(oldLog.length()));
}
- private void errorLogChanged(PropertyChangeEvent evt) {
+ private void errorLogChanged(PropertyChangeEvent evt)
+ {
WSJob job = (WSJob) evt.getSource();
String oldLog = (String) evt.getOldValue();
String newLog = (String) evt.getNewValue();
- wsInfo.appendProgressText(job.getJobNum(), newLog.substring(oldLog.length()));
+ wsInfo.appendProgressText(job.getJobNum(),
+ newLog.substring(oldLog.length()));
}
-
}
WebServiceI getWebService();
- default boolean isDone() {
+ default boolean isDone()
+ {
if (getJobs().size() == 0)
return false;
- for (WSJob job : getJobs()) {
+ for (WSJob job : getJobs())
+ {
if (!job.getStatus().isDone())
return false;
}
public interface Operation
{
public int getMinSequences();
+
public int getMaxSequences();
+
public boolean canSubmitGaps();
+
public boolean isProteinOperation();
- public boolean isNucleotideOperation();
+
+ public boolean isNucleotideOperation();
+
public MenuEntryProviderI getMenuBuilder();
}
}
@Override
- public List<String> getUrls() {
+ public List<String> getUrls()
+ {
String surls = Cache.getDefault(SLIVKA_HOST_URLS, DEFAULT_URL);
String urls[] = surls.split(",");
ArrayList<String> valid = new ArrayList<>(urls.length);
{
new URL(url);
valid.add(url);
- }
- catch (MalformedURLException e)
+ } catch (MalformedURLException e)
{
- Cache.log.warn("Problem whilst trying to make a URL from '" +
- Objects.toString(url, "<null>") + "'. " +
- "This was probably due to malformed comma-separated-list " +
- "in the " + SLIVKA_HOST_URLS + " entry of ${HOME}/.jalview_properties");
+ Cache.log.warn("Problem whilst trying to make a URL from '"
+ + Objects.toString(url, "<null>") + "'. "
+ + "This was probably due to malformed comma-separated-list "
+ + "in the " + SLIVKA_HOST_URLS
+ + " entry of ${HOME}/.jalview_properties");
Cache.log.debug("Exception occurred while reading url list", e);
}
}
}
@Override
- public void setUrls(List<String> wsUrls) {
+ public void setUrls(List<String> wsUrls)
+ {
if (wsUrls != null && !wsUrls.isEmpty())
{
Cache.setProperty(SLIVKA_HOST_URLS, String.join(",", wsUrls));
}
- else {
+ else
+ {
Cache.removeProperty(SLIVKA_HOST_URLS);
}
}
@Override
- public boolean testUrl(URL url) {
+ public boolean testUrl(URL url)
+ {
return getStatusForUrl(url.toString()) == STATUS_OK;
}
@Override
- public int getStatusForUrl(String url) {
+ public int getStatusForUrl(String url)
+ {
try
{
List<?> services = new SlivkaClient(url).getServices();
return services.isEmpty() ? STATUS_NO_SERVICES : STATUS_OK;
- }
- catch (IOException e)
+ } catch (IOException e)
{
- Cache.log.error("Slivka could not retrieve services list from " + url, e);
+ Cache.log.error("Slivka could not retrieve services list from " + url,
+ e);
return STATUS_INVALID;
}
}
- public List<WebServiceI> getServices() {
+ public List<WebServiceI> getServices()
+ {
return Collections.unmodifiableList(services);
}
- public boolean hasServices() {
+ public boolean hasServices()
+ {
return !isRunning() && services.size() > 0;
}
- public boolean isRunning() {
- for (Future<?> task : discoveryTasks) {
- if (!task.isDone()) {
+ public boolean isRunning()
+ {
+ for (Future<?> task : discoveryTasks)
+ {
+ if (!task.isDone())
+ {
return false;
}
}
return true;
}
- public boolean isDone() {
+ public boolean isDone()
+ {
return !isRunning() && discoveryTasks.size() > 0;
}
Cache.log.info("Reloading Slivka services");
fireServicesChanged(Collections.emptyList());
ArrayList<WebServiceI> allServices = new ArrayList<>();
- for (String url : getUrls()) {
+ for (String url : getUrls())
+ {
SlivkaClient client = new SlivkaClient(url);
List<SlivkaService> services;
- try {
+ try
+ {
services = client.getServices();
- } catch (IOException e) {
+ } catch (IOException e)
+ {
Cache.log.error("Unable to fetch services from " + url, e);
continue;
}
- for (SlivkaService service : services) {
- SlivkaWebService instance = new SlivkaWebService(client, service, service.getName());
+ for (SlivkaService service : services)
+ {
+ SlivkaWebService instance = new SlivkaWebService(client, service,
+ service.getName());
for (String classifier : service.classifiers)
{
String[] path = classifier.split("\\s*::\\s*");
&& path[1].toLowerCase().equals("analysis"))
{
Operation op = null;
- switch (path[path.length - 1].toLowerCase()) {
+ switch (path[path.length - 1].toLowerCase())
+ {
case "multiple sequence alignment":
op = new AlignmentOperation(instance, instance::getAlignment);
}
instance.addOperation(op);
}
}
- if (instance.operations.size() > 0) {
+ if (instance.operations.size() > 0)
+ {
allServices.add(instance);
}
}
}
@Override
- public String getErrorMessages() {
+ public String getErrorMessages()
+ {
return "";
}
public class SlivkaWebService implements WebServiceI
{
protected final SlivkaClient client;
+
protected final SlivkaService service;
+
protected SlivkaDatastore store = null;
+
protected final String operation;
+
protected final ArrayList<Operation> operations = new ArrayList<>();
+
protected int typeFlags = 0;
- protected static final EnumMap<Job.Status, WsJob.JobState> stateMap = new EnumMap<>(Job.Status.class);
+ protected static final EnumMap<Job.Status, WsJob.JobState> stateMap = new EnumMap<>(
+ Job.Status.class);
{
stateMap.put(Job.Status.PENDING, WsJob.JobState.QUEUED);
stateMap.put(Job.Status.REJECTED, WsJob.JobState.INVALID);
stateMap.put(Job.Status.ERROR, WsJob.JobState.SERVERERROR);
stateMap.put(Job.Status.UNKNOWN, WsJob.JobState.UNKNOWN);
}
- protected final Set<WsJob.JobState> failedStates = new HashSet<>(Arrays.asList(
- WsJob.JobState.INVALID, WsJob.JobState.BROKEN, WsJob.JobState.FAILED,
- WsJob.JobState.SERVERERROR, WsJob.JobState.CANCELLED
- ));
- public SlivkaWebService(SlivkaClient client, SlivkaService service, String operation) {
+ protected final Set<WsJob.JobState> failedStates = new HashSet<>(
+ Arrays.asList(WsJob.JobState.INVALID, WsJob.JobState.BROKEN,
+ WsJob.JobState.FAILED, WsJob.JobState.SERVERERROR,
+ WsJob.JobState.CANCELLED));
+
+ public SlivkaWebService(SlivkaClient client, SlivkaService service,
+ String operation)
+ {
this.client = client;
this.service = service;
this.operation = operation;
}
@Override
- public String getHostName() { return client.getUrl().toString(); }
+ public String getHostName()
+ {
+ return client.getUrl().toString();
+ }
@Override
- public String getProviderName() { return "slivka"; }
+ public String getProviderName()
+ {
+ return "slivka";
+ }
@Override
- public String getName() { return service.getName(); }
+ public String getName()
+ {
+ return service.getName();
+ }
@Override
- public String getDescription() { return service.getDescription(); }
+ public String getDescription()
+ {
+ return service.getDescription();
+ }
@Override
- public String getOperationType() { return operation; }
+ public String getOperationType()
+ {
+ return operation;
+ }
@Override
- public List<Operation> getOperations() {
+ public List<Operation> getOperations()
+ {
return operations;
}
- void addOperation(Operation operation) {
+ void addOperation(Operation operation)
+ {
operations.add(operation);
}
- void removeOperation(Operation operation) {
+ void removeOperation(Operation operation)
+ {
operations.remove(operation);
}
@Override
- public boolean hasParameters() {
+ public boolean hasParameters()
+ {
return getParamStore().getServiceParameters().size() > 0;
}
@Override
- public ParamDatastoreI getParamStore() {
- if (store == null) {
+ public ParamDatastoreI getParamStore()
+ {
+ if (store == null)
+ {
store = new SlivkaDatastore(service);
}
return store;
}
@Override
- public String submit(List<SequenceI> sequences, List<ArgumentI> args) throws IOException
+ public String submit(List<SequenceI> sequences, List<ArgumentI> args)
+ throws IOException
{
var request = new uk.ac.dundee.compbio.slivkaclient.JobRequest();
- for (Parameter param : service.getParameters()) {
- if (param instanceof Parameter.FileParameter) {
+ for (Parameter param : service.getParameters())
+ {
+ if (param instanceof Parameter.FileParameter)
+ {
// if finds a file input, gives it sequences stream
Parameter.FileParameter fileParam = (Parameter.FileParameter) param;
FileFormat format;
- switch (fileParam.getMediaType()) {
+ switch (fileParam.getMediaType())
+ {
case "application/pfam":
format = FileFormat.Pfam;
break;
format = FileFormat.Fasta;
break;
}
- InputStream stream = new ByteArrayInputStream(
- format.getWriter(null)
+ InputStream stream = new ByteArrayInputStream(format.getWriter(null)
.print(sequences.toArray(new SequenceI[0]), false)
.getBytes());
request.addFile(param.getId(), stream);
}
}
- if (args != null) {
- for (ArgumentI arg : args) {
+ if (args != null)
+ {
+ for (ArgumentI arg : args)
+ {
// multiple choice field names are name$number to avoid duplications
// the number is stripped here
String paramId = arg.getName().split("\\$", 2)[0];
Parameter param = service.getParameter(paramId);
- if (param instanceof Parameter.FlagParameter) {
+ if (param instanceof Parameter.FlagParameter)
+ {
if (arg.getValue() != null && !arg.getValue().isBlank())
request.addData(paramId, true);
else
}
@Override
- public void updateProgress(WSJob job)
- throws IOException
+ public void updateProgress(WSJob job) throws IOException
{
// TODO Auto-generated method stub
@Override
public boolean handleSubmissionError(WSJob job, Exception ex)
{
- if (ex instanceof ClientProtocolException) {
+ if (ex instanceof ClientProtocolException)
+ {
Cache.log.error("Job submission failed due to exception.", ex);
return true;
}
return false;
}
- public AlignmentI getAlignment(WSJob job) throws IOException {
+ public AlignmentI getAlignment(WSJob job) throws IOException
+ {
Collection<RemoteFile> files;
var slivkaJob = client.getJob(job.getJobId());
files = slivkaJob.getResults();
- for (RemoteFile f : files) {
- if (f.getMediaType().equals("application/clustal")) {
- return new FormatAdapter().readFile(
- f.getContentUrl().toString(), DataSourceType.URL, FileFormat.Clustal);
+ for (RemoteFile f : files)
+ {
+ if (f.getMediaType().equals("application/clustal"))
+ {
+ return new FormatAdapter().readFile(f.getContentUrl().toString(),
+ DataSourceType.URL, FileFormat.Clustal);
}
- else if (f.getMediaType().equals("application/fasta")) {
- return new FormatAdapter().readFile(
- f.getContentUrl().toString(), DataSourceType.URL, FileFormat.Fasta);
+ else if (f.getMediaType().equals("application/fasta"))
+ {
+ return new FormatAdapter().readFile(f.getContentUrl().toString(),
+ DataSourceType.URL, FileFormat.Fasta);
}
}
return null;
}
@Override
- public String toString() {
+ public String toString()
+ {
return String.format("SlivkaWebService[%s]", getName());
}
}