package camelinaction.goal; import java.util.Iterator; import java.util.List; import java.util.Random; import java.util.Timer; import java.util.TimerTask; import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.Collectors; import org.apache.camel.Endpoint; import org.apache.camel.Exchange; import org.apache.camel.Processor; import org.apache.camel.Suspendable; import org.apache.camel.impl.DefaultConsumer; import static java.lang.Thread.sleep; /** * The consumer can stream a live score updates and support suspend/resume * to stop the game clock as well. */ public class GoalConsumer extends DefaultConsumer implements Suspendable { // to use fast mode where each 5 second is a minute private boolean fastMode = true; private final List<String> goals; private final AtomicInteger gameTime = new AtomicInteger(-1); private final Timer timer = new Timer(); private TimerTask task; public GoalConsumer(Endpoint endpoint, Processor processor, List<String> goals) { super(endpoint, processor); this.goals = goals; } @Override protected void doStart() throws Exception { super.doStart(); log.info("Starting goal live stream"); if (task == null) { task = new GoalTask(); int period = fastMode ? 5 * 1000 : 60 * 1000; timer.scheduleAtFixedRate(task, 1000, period); } } @Override public void doResume() throws Exception { log.info("Resuming goal live stream"); // signal the clock is started Exchange exchange = getEndpoint().createExchange(); exchange.getIn().setHeader("action", "clock"); exchange.getIn().setBody(String.valueOf(gameTime.get())); getProcessor().process(exchange); } @Override protected void doSuspend() throws Exception { log.info("Suspending goal live stream"); // signal the clock is stopped Exchange exchange = getEndpoint().createExchange(); exchange.getIn().setHeader("action", "clock"); exchange.getIn().setBody("Stopped"); getProcessor().process(exchange); } @Override protected void doStop() throws Exception { log.info("Stopping goal live stream"); timer.cancel(); task = null; // signal the clock is stopped Exchange exchange = getEndpoint().createExchange(); exchange.getIn().setHeader("action", "clock"); exchange.getIn().setBody("Stopped"); getProcessor().process(exchange); super.doStop(); } /** * A {@link TimerTask} which runs every minute and routes messages to the vertx component * with updated game clock and goals. */ private class GoalTask extends TimerTask { @Override public void run() { if (!isRunAllowed() || isSuspended()) { // the route has been suspended when the user click the stop button return; } // start from 0 int min = gameTime.incrementAndGet(); // if the match is ended then there is no more goals if (min > 92) { return; } try { // publish game time Exchange exchange = getEndpoint().createExchange(); exchange.getIn().setHeader("action", "clock"); exchange.getIn().setBody(min +":00"); getProcessor().process(exchange); // stream all goals for the current game time List<String> newGoals = goals.stream().filter(next -> goalTime(next) == min).collect(Collectors.toList()); if (newGoals.isEmpty()) { exchange = getEndpoint().createExchange(); exchange.getIn().setHeader("action", "goal"); exchange.getIn().setBody("empty"); getProcessor().process(exchange); } else { Iterator<String> it = newGoals.iterator(); while (it.hasNext()) { exchange = getEndpoint().createExchange(); exchange.getIn().setHeader("action", "goal"); exchange.getIn().setBody(it.next()); getProcessor().process(exchange); if (it.hasNext()) { // there are more goals so wait a bit before next // delay between 8 - 12 sec for next goal int extra = fastMode ? 2000 : 8000 + new Random().nextInt(4000); sleep(extra); } }; } } catch (Exception e) { getExceptionHandler().handleException(e); } } } private static Integer goalTime(String line) { return Integer.valueOf(line.split(",")[1]); } }