package we.love.pluto.visualizer;
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.ServiceUnavailableException;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import org.glassfish.jersey.media.sse.EventOutput;
import org.glassfish.jersey.media.sse.OutboundEvent;
import org.glassfish.jersey.media.sse.SseBroadcaster;
import org.glassfish.jersey.media.sse.SseFeature;
import com.google.common.collect.Maps;
/**
* TODO M: Distributed map.
*
* @author Michal Gajdos
*/
@Path("space-object")
public class SpaceObjectResource {
private static final Map<String, AtomicInteger> occurrences = new ConcurrentHashMap<>();
private static final SseBroadcaster broadcaster = new SseBroadcaster();
@GET
@Path("events")
@Produces(SseFeature.SERVER_SENT_EVENTS)
public EventOutput events() {
final EventOutput eventOutput = new EventOutput();
if (!broadcaster.add(eventOutput)) {
// 503 -> 5s delayed client reconnect attempt.
throw new ServiceUnavailableException(5L);
}
try {
eventOutput.write(event());
} catch (final IOException ioe) {
// NO-OP.
}
return eventOutput;
}
@POST
@Path("of-the-moment")
public Response post(final String[] objects) {
// Increment counter.
for (String object : objects) {
if (!occurrences.containsKey(object)) {
occurrences.putIfAbsent(object, new AtomicInteger());
}
occurrences.get(object).incrementAndGet();
}
// Broadcast.
broadcaster.broadcast(event());
return Response.ok().build();
}
private OutboundEvent event() {
final Map<String, AtomicInteger> occurrences = SpaceObjectResource.occurrences;
return new OutboundEvent.Builder()
.mediaType(MediaType.APPLICATION_JSON_TYPE)
.data(Maps.transformValues(occurrences, AtomicInteger::intValue))
.build();
}
}