/** {@inheritDoc} */
  @Override
  public long write(final SelectionKey key) throws IOException {
    final DatagramChannel channel = (DatagramChannel) key.channel();
    final MessageBufferConsumer<ByteBuffer> chnIn = getChannelInput();
    long n = 0;
    long k = chnIn.remaining();
    for (; k >= 0; k--) {
      final SocketAddress address;
      try {
        final long sequence = chnIn.acquire();
        try {
          final ByteBuffer msg = chnIn.get(sequence);
          sendBuffer.clear();
          codec.put(msg, sendBuffer);
          msg.clear();
          sendBuffer.flip();
          address = (SocketAddress) chnIn.attachment(sequence);
        } finally {
          chnIn.release(sequence);
        }
      } catch (final InterruptedException e) {
        throw new IOException(e);
      }

      limiter.send(sendBuffer.remaining());

      do {
        n += channel.send(sendBuffer, address);
      } while (sendBuffer.remaining() > 0);
    }
    if (chnIn.remaining() == 0) {
      disableWriter();
    }
    return n;
  }
 /** {@inheritDoc} */
 @Override
 protected void shutdown(final SettableCallbackFuture<Void> future, final Callable<Void> task) {
   try {
     codec.close();
     task.call();
     future.success(null);
   } catch (final Throwable t) {
     future.fail(t);
   }
 }
  /** {@inheritDoc} */
  @Override
  public long read(final SelectionKey key) throws IOException {
    final DatagramChannel channel = (DatagramChannel) key.channel();
    final MessageBufferProducer<ByteBuffer> chnOut = getChannelOutput();
    final int start = receiveBuffer.position();
    final SocketAddress source = channel.receive(receiveBuffer);
    if (source == null) {
      return 0;
    }
    final int n = receiveBuffer.position() - start;

    limiter.receive(n);

    receiveBuffer.flip();
    while (codec.hasNext(receiveBuffer)) {
      try {
        final long sequence = chnOut.acquire();
        try {
          final ByteBuffer buffer = chnOut.get(sequence);
          buffer.clear();
          codec.get(receiveBuffer, buffer);
          buffer.flip();
          chnOut.attach(sequence, source);
        } finally {
          chnOut.release(sequence);
        }
      } catch (final InterruptedException e) {
        throw new IOException(e);
      }
    }
    if (receiveBuffer.remaining() > 0) {
      receiveBuffer.compact();
    } else {
      receiveBuffer.clear();
    }
    return n;
  }
 UDPProcessor(
     @Nonnull final MessageCodec codec,
     @Nonnull final RateLimiter limiter,
     @Nonnull final MessageBufferProvider<ByteBuffer> provider) {
   super(provider);
   if (codec == null) {
     throw new NullPointerException("codec == null");
   }
   if (limiter == null) {
     throw new NullPointerException("limiter == null");
   }
   if (codec.getFrameLength() > MAX_DATAGRAM_PAYLOAD) {
     throw new IllegalArgumentException("codec.getFrameLength() > MAX_FRAME_LENGTH");
   }
   this.codec = codec;
   this.limiter = limiter;
   this.receiveBuffer = DUMMY_BUFFER; // will be replaced once processor is registered
   this.sendBuffer = DUMMY_BUFFER; // will be replaced once processor is registered
 }