package com.intrbiz.bergamot.updater.handler;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import java.util.stream.Collectors;
import org.apache.log4j.Logger;
import com.intrbiz.Util;
import com.intrbiz.bergamot.data.BergamotDB;
import com.intrbiz.bergamot.model.message.api.error.APIError;
import com.intrbiz.bergamot.model.message.api.update.RegisterForUpdates;
import com.intrbiz.bergamot.model.message.api.update.RegisteredForUpdates;
import com.intrbiz.bergamot.model.message.api.update.UpdateEvent;
import com.intrbiz.bergamot.model.message.update.AlertUpdate;
import com.intrbiz.bergamot.model.message.update.CheckUpdate;
import com.intrbiz.bergamot.model.message.update.GroupUpdate;
import com.intrbiz.bergamot.model.message.update.LocationUpdate;
import com.intrbiz.bergamot.model.message.update.Update;
import com.intrbiz.bergamot.queue.UpdateQueue;
import com.intrbiz.bergamot.queue.key.UpdateKey;
import com.intrbiz.bergamot.queue.key.UpdateKey.UpdateType;
import com.intrbiz.bergamot.updater.context.ClientContext;
import com.intrbiz.queue.Consumer;
import com.intrbiz.queue.QueueException;
public class RegisterForUpdatesHandler extends RequestHandler<RegisterForUpdates>
{
private Logger logger = Logger.getLogger(RegisterForUpdatesHandler.class);
public RegisterForUpdatesHandler()
{
super(new Class<?>[] { RegisterForUpdates.class });
}
@Override
public void onRequest(ClientContext context, RegisterForUpdates request)
{
// setup the queue
if (context.var("updateConsumer") == null)
{
try
{
// the bindings
Set<UpdateKey> bindings = this.computeBindings(context, request);
logger.debug("Reigster for updates: " + bindings);
// setup the queue
UpdateQueue queue = context.var("updateQueue", UpdateQueue.open());
context.var("updateConsumer", queue.consumeUpdates((h, u) -> { this.sendUpdate(context, u); }, bindings));
// on close handler
context.onClose((ctx) -> {
Consumer<Update, UpdateKey> c = ctx.var("updateConsumer");
if (c != null) c.close();
UpdateQueue q = ctx.var("updateQueue");
if (q != null) q.close();
});
// done
context.send(new RegisteredForUpdates(request));
}
catch (QueueException e)
{
context.var("updateQueue", null);
context.var("updateConsumer", null);
logger.error("Failed to setup queue", e);
context.send(new APIError("Failed to setup queue"));
}
}
else
{
try
{
Set<UpdateKey> bindings = this.computeBindings(context, request);
logger.debug("Reigster for updates: " + bindings);
// update the bindings
Consumer<Update, UpdateKey> updateConsumer = context.var("updateConsumer");
for (UpdateKey binding : bindings)
{
logger.debug("Updating bindings, adding: " + binding);
updateConsumer.addBinding(binding);
}
context.send(new RegisteredForUpdates(request));
}
catch (QueueException e)
{
logger.error("Failed to update queue bindings", e);
context.send(new APIError("Failed to setup queue"));
}
}
}
private void sendUpdate(ClientContext context, Update update)
{
if (update instanceof CheckUpdate)
{
// only send the update if the user has permission over the check
if (context.getPrincipal().hasPermission("read", ((CheckUpdate) update).getCheck().getId()))
{
context.send(new UpdateEvent(update));
}
}
else if (update instanceof AlertUpdate)
{
if (context.getPrincipal().hasPermission("read", ((AlertUpdate) update).getAlert().getCheck().getId()))
{
context.send(new UpdateEvent(update));
}
}
else if (update instanceof GroupUpdate)
{
// we need to recompute the state of the group with respect to the given user
GroupUpdate groupUpdate = (GroupUpdate) update;
try (BergamotDB db = BergamotDB.connect())
{
groupUpdate.getGroup().setState(db.computeGroupStateForContact(groupUpdate.getGroup().getId(), context.getPrincipal().getId()).toMO(context.getPrincipal()));
}
context.send(new UpdateEvent(update));
}
else if (update instanceof LocationUpdate)
{
// we need to recompute the state of the group with respect to the given user
LocationUpdate locationUpdate = (LocationUpdate) update;
try (BergamotDB db = BergamotDB.connect())
{
locationUpdate.getLocation().setState(db.computeLocationStateForContact(locationUpdate.getLocation().getId(), context.getPrincipal().getId()).toMO(context.getPrincipal()));
}
context.send(new UpdateEvent(update));
}
}
private Set<UpdateKey> computeBindings(ClientContext context, RegisterForUpdates rfsn)
{
// the type of updates we are listening for
UpdateType type = UpdateType.valueOf(Util.coalesceEmpty(rfsn.getUpdateType(), "check").toUpperCase());
// wildcard ?
if ((rfsn.getIds() == null || rfsn.getIds().isEmpty()))
{
return new HashSet<UpdateKey>(Arrays.asList(new UpdateKey(type, context.getSite().getId())));
}
// compute the bindings
return rfsn.getIds().stream().map((id) -> new UpdateKey(type, context.getSite().getId(), id)).collect(Collectors.toSet());
}
}