package de.jpaw.bonaparte.netty; import java.util.List; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.ByteToMessageDecoder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import de.jpaw.bonaparte.core.BonaPortable; import de.jpaw.bonaparte.core.ByteArrayParser; import de.jpaw.bonaparte.core.MessageParserException; public class BonaparteNettyDecoder extends ByteToMessageDecoder { private static final Logger LOGGER = LoggerFactory.getLogger(BonaparteNettyDecoder.class); private final ErrorForwarder errorForwarder; public BonaparteNettyDecoder(ErrorForwarder errorForwarder) { this.errorForwarder = errorForwarder; } public static byte [] getData(ByteBuf msg) { byte[] array; if (msg.readableBytes() <= 0 || msg.getByte(msg.readableBytes()-1) != '\n') { LOGGER.debug("Ignoring {} bytes of data - no NL at end of message", msg.readableBytes()); return null; // message not yet complete } if (msg.hasArray()) { if ((msg.arrayOffset() == 0) && (msg.readableBytes() == msg.capacity())) { // we have no offset and the length is the same as the capacity. Its safe to reuse // the array without copy it first array = msg.array(); msg.skipBytes(msg.readableBytes()); // void copying, as would be done via read() return array; } } // copy the ChannelBuffer to a byte array array = new byte[msg.readableBytes()]; msg.readBytes(array); return array; } @Override public void decode(ChannelHandlerContext ctx, ByteBuf msg, List<Object> out) throws Exception { byte[] array = getData(msg); if (array == null) return; // no data yet... LOGGER.debug("Received {} bytes of data", array.length); try { ByteArrayParser p = new ByteArrayParser(array, 0, -1); BonaPortable obj = p.readRecord(); LOGGER.debug("Successfully parsed data of class {}", obj.getClass()); out.add(obj); } catch (MessageParserException e) { // http://co-de-generation.blogspot.de/2012/09/slf4j-doesnt-log-exception-stacktrace.html LOGGER.error("Cannot parse " + array.length + " bytes of data: Exception {}", e); LOGGER.error("Message received is <{}>", array.length <= 200 ? new String(array) : new String(array).substring(0, 200)); if (errorForwarder == null) { throw e; } else { out.add(errorForwarder.createErrorObject(e.getErrorCode(), e.getMessage(), array)); } } } }