package org.rakam.kume.service; import org.rakam.kume.transport.OperationContext; import org.rakam.kume.ServiceContext; import java.util.ArrayDeque; public abstract class PausableService<T extends Service> extends Service { private final ServiceContext<T> ctx; ArrayDeque<FutureRequest> objectQueue = new ArrayDeque(); ArrayDeque<Runnable> runnableQueue = new ArrayDeque(); private volatile boolean paused = false; public PausableService(ServiceContext<T> ctx) { this.ctx = ctx; } @Override public void handle(OperationContext ctx, Object object) { if(paused) { LOGGER.debug("Queued message {} for paused service {}", object, this); objectQueue.add(new FutureRequest(ctx, object)); }else { safelyHandle(ctx, object); } } public boolean addQueueIfPaused(Runnable run) { if(paused) { LOGGER.trace("Queued runnable {} for paused service {}", run, this); runnableQueue.add(run); return true; } return false; } public ServiceContext<T> getContext() { return ctx; } public boolean isPaused() { return paused; } public void safelyHandle(OperationContext ctx, Object object) { LOGGER.warn("Discarded message {} because the service doesn't implement handle(OperationContext, object)", object); } public synchronized void pause() { LOGGER.debug("Paused service {}", this); paused = true; } public synchronized void resume() { LOGGER.debug("Resumed service {}", this); objectQueue.forEach(x -> safelyHandle(x.context, x.request)); runnableQueue.forEach(x -> x.run()); paused = false; } public static class FutureRequest { OperationContext context; Object request; public FutureRequest(OperationContext context, Object request) { this.context = context; this.request = request; } } }