package service; import java.util.Collections; import java.util.HashSet; import java.util.Map; import java.util.Set; import com.google.common.collect.ImmutableList; import play.Logger; import service.EventTimeline.ForgottenEventException; import service.OrderedEvent; public class EventManagerImpl implements EventManager { private final EventTimeline<String, Event> history = new InMemoryEventTimeline<Event>(); private final Set<EventReceiver> receivers = Collections.synchronizedSet( new HashSet<EventReceiver>()); @Override public String getLastEventId() { return history.getLastEventId(); } @Override public Iterable<OrderedEvent> getSince(final String lastId) { final ImmutableList.Builder<OrderedEvent> b = ImmutableList.builder(); Map<String, Event> missed; try { missed = lastId == null ? history.getKnown() : history.getSince(lastId); } catch (ForgottenEventException e1) { // TODO Handle forgotten history return ImmutableList.of(outOfDateOrderedEvent()); } for (Map.Entry<String, Event> e : missed.entrySet()) { // Push event ID and event b.add(new OrderedEvent(e.getKey(), e.getValue())); } return b.build(); } @Override public void tell(final EventReceiverMessage message) { switch (message.type) { case ADD: Logger.debug("Adding event receiver to " + this); performCatchup(message.er, message.lastId); receivers.add(message.er); break; case REMOVE: Logger.debug("Removing event receiver from " + this); receivers.remove(message.er); break; } } @Override public void tell(final Event event) { history.record(event); Logger.debug(String.format("%s pushing event to %d receivers: %s", this, receivers.size(), event)); for (EventReceiver er : receivers) { // Push event ID and event er.push(new OrderedEvent(history.getLastEventId(), event)); } } protected void performCatchup( final EventReceiver er, final String lastId) { Logger.debug("Catching up from "+lastId); if (lastId == null) { er.push(outOfDateOrderedEvent()); er.end(); } else { try { final Map<String, Event> missed = history.getSince(lastId); for (Map.Entry<String, Event> e : missed.entrySet()) { Logger.debug(String.format( "%s pushing missed event %s to receiver: %s", this, e.getKey(), er)); // Push event ID and event er.push(new OrderedEvent(e.getKey(), e.getValue())); } } catch (ForgottenEventException e) { er.push(outOfDateOrderedEvent()); // Close the channel er.end(e); } } } protected OrderedEvent outOfDateOrderedEvent() { return new OrderedEvent(history.getLastEventId(), Event.outOfDate()); } @Override public String toString() { return "EM#"+System.identityHashCode(this); } }