package cassandra.protocol;
import cassandra.CassandraConnection;
import cassandra.CassandraException;
import cassandra.CassandraFuture;
import cassandra.CassandraFutureMap;
import cassandra.protocol.CassandraMessage.Event;
import cassandra.protocol.CassandraMessage.Request;
import cassandra.protocol.CassandraMessage.Response;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.CodecException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.nio.channels.ClosedChannelException;
import java.util.concurrent.ConcurrentMap;
import static io.netty.util.internal.PlatformDependent.newConcurrentHashMap;
@ChannelHandler.Sharable
public class CassandraMessageHandler extends SimpleChannelInboundHandler<CassandraMessage> {
private static final Logger logger = LoggerFactory.getLogger(CassandraMessageHandler.class);
private final CassandraFutureMap futureMap;
private final ConcurrentMap<Channel, CassandraConnection> registeredConnections;
public CassandraMessageHandler(CassandraFutureMap futureMap) {
this.futureMap = futureMap;
registeredConnections = newConcurrentHashMap();
}
public boolean register(Channel channel, CassandraConnection connection) {
return registeredConnections.putIfAbsent(channel, connection) == null;
}
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
futureMap.fail(ctx.channel(), new ClosedChannelException());
registeredConnections.remove(ctx.channel());
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
logger.error("{} uncaught exception thrown, {}", ctx.channel(), cause.getMessage(), cause);
if (cause instanceof CodecException) {
return;
}
ctx.close();
}
@Override
protected void channelRead0(ChannelHandlerContext ctx, CassandraMessage message) throws Exception {
if (message instanceof Request) {
logger.debug("{} received unexpected message, {}", ctx.channel(), message);
ctx.close();
return;
}
if (message instanceof Event) {
Event event = (Event)message;
CassandraConnection connection = registeredConnections.get(ctx.channel());
if (connection != null) {
connection.handleEvent(event);
} else {
logger.debug("{} received event with no connection registered, {}", ctx.channel(), event);
}
return;
}
CassandraFuture future = futureMap.removeFuture(ctx.channel(), message.getStreamId());
if (future != null) {
if (message instanceof CassandraMessage.Error) {
CassandraException exception = ((CassandraMessage.Error)message).exception;
future.setFailure(exception);
logger.debug("{} received error response, {}", ctx.channel(), exception.getMessage());
} else {
future.setSuccess((Response)message);
}
} else {
logger.debug("{} received response with no request registered, {}", ctx.channel(), message);
ctx.close();
}
}
}