package de.anycook.api.providers;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import de.anycook.db.mysql.DBDiscussion;
import de.anycook.messages.MessageSession;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.sql.SQLException;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import javax.ws.rs.container.AsyncResponse;
import javax.ws.rs.core.Response;
/**
* @author Jan Graßegger<jan@anycook.de>
*/
public enum DiscussionProvider {
INSTANCE;
private final Logger logger;
private final Cache<String, BlockingQueue<SuspendedDiscussion>> suspended;
DiscussionProvider() {
logger = LogManager.getLogger(getClass());
suspended = CacheBuilder.newBuilder()
.maximumSize(10000)
.expireAfterWrite(5, TimeUnit.MINUTES)
.build();
}
public void wakeUpSuspended(String recipeName) {
logger.debug("waking up suspended");
BlockingQueue<SuspendedDiscussion> queue = suspended.getIfPresent(recipeName);
if (queue == null) {
return;
}
try (DBDiscussion dbDiscussion = new DBDiscussion()) {
while (!queue.isEmpty()) {
LogManager.getLogger(MessageSession.class).debug("reading response");
try {
SuspendedDiscussion suspendedDiscussion = queue.take();
if (suspendedDiscussion.response.isSuspended()) {
suspendedDiscussion.response.resume(dbDiscussion.getDiscussion(recipeName,
suspendedDiscussion.lastId,
suspendedDiscussion.userId));
}
} catch (InterruptedException e) {
logger.warn(e, e);
}
}
} catch (SQLException e) {
logger.error(e, e);
}
suspended.put(recipeName, queue);
}
public void suspend(String recipeName, int userId, int lastId, AsyncResponse response) {
response.setTimeoutHandler(asyncResponse -> {
logger.info("reached timeout");
asyncResponse.resume(Response.ok().build());
});
response.setTimeout(5, TimeUnit.MINUTES);
logger.debug("supending " + recipeName);
try {
BlockingQueue<SuspendedDiscussion> queue =
suspended.get(recipeName, () -> new ArrayBlockingQueue<>(300));
queue.add(new SuspendedDiscussion(userId, lastId, response));
suspended.put(recipeName, queue);
} catch (ExecutionException e) {
logger.error(e, e);
}
}
private static class SuspendedDiscussion {
public final int userId;
public final int lastId;
public final AsyncResponse response;
public SuspendedDiscussion(int userId, int lastId, AsyncResponse response) {
this.userId = userId;
this.lastId = lastId;
this.response = response;
}
}
}