--- /dev/null
+package jalview.ws2;
+
+import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+
+import jalview.bin.Cache;
+
+public class PollingTaskExecutor
+{
+ private ScheduledExecutorService executor = Executors
+ .newSingleThreadScheduledExecutor();
+
+ public void submit(final PollableTaskI task)
+ {
+ executor.submit(() -> {
+ try
+ {
+ task.start();
+ wsThreadSupport.submitted(task);
+ } catch (Exception e)
+ {
+ Cache.log.error("Failed to submit web service jobs.", e);
+ wsThreadSupport.submissionFailed(task, e);
+ return;
+ }
+ executor.schedule(() -> poll(task), 1, TimeUnit.SECONDS);
+ });
+ }
+
+ private void poll(PollableTaskI task)
+ {
+ boolean done;
+ try
+ {
+ done = task.poll();
+ } catch (Exception e)
+ {
+ Cache.log.error("Failed to poll task.", e);
+ wsThreadSupport.pollFailed(task, e);
+ return;
+ }
+ if (!done)
+ {
+ executor.schedule(() -> poll(task), 1, TimeUnit.SECONDS);
+ }
+ else
+ {
+ task.done();
+ wsThreadSupport.done(task);
+ }
+ }
+
+ private WebServiceThreadSupport wsThreadSupport = new WebServiceThreadSupport();
+
+ public void addThreadListener(PollableTaskListenerI listener)
+ {
+ wsThreadSupport.addListener(listener);
+ }
+
+ public void removeThreadListener(PollableTaskListenerI listener)
+ {
+ wsThreadSupport.removeListener(listener);
+ }
+
+ public void shutdown()
+ {
+ executor.shutdownNow();
+ }
+
+}
+
+class WebServiceThreadSupport implements PollableTaskListenerI
+{
+ List<PollableTaskListenerI> listeners = new CopyOnWriteArrayList<>();
+
+ @Override
+ public void submitted(PollableTaskI task)
+ {
+ for (var listener : listeners)
+ listener.submitted(task);
+ }
+
+ @Override
+ public void submissionFailed(PollableTaskI task, Exception e)
+ {
+ for (var listener : listeners)
+ listener.submissionFailed(task, e);
+ }
+
+ @Override
+ public void pollFailed(PollableTaskI task, Exception e)
+ {
+ for (var listener : listeners)
+ listener.pollFailed(task, e);
+ }
+
+ @Override
+ public void cancelled(PollableTaskI task)
+ {
+ for (var listener : listeners)
+ listener.cancelled(task);
+ }
+
+ @Override
+ public void done(PollableTaskI task)
+ {
+ for (var listener : listeners)
+ listener.done(task);
+ }
+
+ public void addListener(PollableTaskListenerI listener)
+ {
+ if (!listeners.contains(listener))
+ {
+ listeners.add(listener);
+ }
+ }
+
+ public void removeListener(PollableTaskListenerI listener)
+ {
+ listeners.remove(listener);
+ }
+}