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; /** * 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(); /** * 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(() -> { 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); }); } /** * 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; 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(); /** * 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); } public void shutdown() { executor.shutdownNow(); } } class WebServiceThreadSupport implements PollableTaskListenerI { List 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); } }